home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-02 | 55.7 KB | 1,428 lines |
- Newsgroups: comp.sources.misc
- From: Raphael Manfredi <ram@acri.fr>
- Subject: v41i001: mailagent - Flexible mail filtering and processing package, v3.0, Part01/26
- Message-ID: <csm-v41i001=mailagent.073303@sparky.Sterling.COM>
- X-Md4-Signature: 104b515e8cb1c79995e2798cf7c1ac51
- Sender: kent@sparky.sterling.com (Kent Landfield)
- Organization: Advanced Computer Research Institute, Lyon, France.
- Date: Thu, 2 Dec 1993 13:33:32 GMT
- Approved: kent@sparky.sterling.com
-
- Submitted-by: Raphael Manfredi <ram@acri.fr>
- Posting-number: Volume 41, Issue 1
- Archive-name: mailagent/part01
- Environment: UNIX, Perl
- Supersedes: mailagent: Volume 33, Issue 93-109
-
- This is a mailagent program, and it will take care of all your incoming
- mail by applying a set of rules and trying to figure out what to do with
- it. A message can be saved in a folder, left in the main mailbox, posted
- to a newsgroup, forwarded to other people, split if it is a digest,
- etc... You may even delete all those mails you do not wish to see, ever.
-
- Mailagent is easily extensible if you speak perl fluently enough and have
- the courage to dive into the manual page. It also provides you with all
- the tools to turn it into a mail server, which can be remotely managed.
-
- Here is a summary of the changes that occurred since mailagent 2.9 PL19:
-
- . Mailhook disappears. Folder hooks are now handled without the need for an
- extra process.
-
- . NOTIFY now takes its FIRST argument to indicate the message file,
- instead of its LAST as in the 2.9 release. This change in order to make
- it compatible with MESSAGE.
-
- . Mailagent secure configuration checks. Impossible to use mailagent if the
- ~/.mailagent file or the rule file are not correctly protected.
-
- . Dynamic loading interface (dynload.pl) available for perl commands.
-
- . Added a generic command server. Mailagent provides the server engine and
- users write their own commands, with special provision for perl scripts
- which can be directly loaded and executed within mailagent itself.
-
- . User-defined macro support %-(x) and perl interface.
-
- . New APPLY, REQUIRE, SERVER, MACRO commands.
-
- . Support for rule caching. This avoids recompiling large rule files at every
- mailagent run, but speed has never never been a main concern in this program
- anyway.
-
- . Negated mode support <!MODE>. Rule is not executed if in the specified
- negated mode. This supersedes normal modes, i.e. <MODE, !MODE> is never
- executed.
-
- . Can now configure sendmail process and inews, with options, from ~/.mailagent.
- If your sendmail behaves strangely or want to have interactive delivery
- instead of queuing, this is the place to look at.
-
- . New usr_log facility, enabling user-defined logfiles. Available for your
- own commands and used internally by mailagent.
-
- . Saving operations now check on the size of the produced folder for NFS.
-
- . Can now access ~/.mailagent config params via %=var
-
- . Fixed bug in agent queue parsing. This happened mainly on SUN systems, and
- was apparently a perl fileglob bug (or is it a /bin/csh bug?). Anyway, I
- now use readdir() to access the queue, which suppresses forking of an extra
- process.
-
- . Improved RFC822 address parsing. Now understands group names as login names.
-
- . Output for mailagent -d formatted differently.
-
- . Selector range Body <1,4>: available. This example selects body lines 1 to
- 4 (inclusive) for matching.
-
- . Can now deliver to MH folders (without the need for an extra process). Use
- 'SAVE +foo' to deliver to the MH folder foo. Unseen sequences specified in
- your ~/.mh_profile are correctly updated.
-
- . Minimal support for directory hooks (only behaves like MH folders currently).
-
- . New @SH package command for dist-3.0 MailAuthor.U support. That metaconfig
- units sends a mail in specific format to record users of some package, and
- the package command is there to automate the process.
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: PACKNOTES README PACKLIST agent/ agent/examples/
- # agent/files/ agent/files/help agent/files/server agent/filter/
- # agent/man/ agent/pl/ agent/pl/stats.pl agent/test/
- # agent/test/basic/ agent/test/cmd/ agent/test/filter/
- # agent/test/misc/ agent/test/option/ agent/test/pl/ bin/ misc/
- # misc/shell/ misc/unkit/
- # Wrapped by ram@soft208 on Mon Nov 29 16:49:54 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 1 (of 26)."'
- if test -f 'PACKNOTES' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'PACKNOTES'\"
- else
- echo shar: Extracting \"'PACKNOTES'\" \(389 characters\)
- sed "s/^X//" >'PACKNOTES' <<'END_OF_FILE'
- X
- X# "Configure" was split into 2 parts; to create it, do
- X cat Configure.0[1-9] >Configure
- X chmod +x Configure
- X
- X# "agent/man/mailagent.SH" was split into 4 parts; to create it, do
- X cat agent/man/mailagent.SH.0[1-9] >agent/man/mailagent.SH
- X chmod +x agent/man/mailagent.SH
- X
- X# "agent/pl/actions.pl" was split into 2 parts; to create it, do
- X cat agent/pl/actions.pl.0[1-9] >agent/pl/actions.pl
- END_OF_FILE
- if test 389 -ne `wc -c <'PACKNOTES'`; then
- echo shar: \"'PACKNOTES'\" unpacked with wrong size!
- fi
- # end of 'PACKNOTES'
- fi
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(6197 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- X mailagent 3.0
- X
- X Copyright (c) 1990-1993, Raphael Manfredi
- X
- X------------------------------------------------------------------------
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the Artistic License, a copy of which can be
- X found with this package.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X Artistic License for more details.
- X------------------------------------------------------------------------
- X
- XPlease read all the directions below before you proceed any further, and
- Xthen follow them carefully.
- X
- XAfter you have unpacked your kit, you should have all the files listed
- Xin MANIFEST.
- X========================================================================
- X
- XThis is a mailagent program, and it will take care of all your incoming
- Xmail by applying a set of rules and trying to figure out what to do with
- Xit. A message can be saved in a folder, left in the main mailbox, posted
- Xto a newsgroup, forwarded to other people, split if it is a digest,
- Xetc... You may even delete all those mails you do not wish to see, ever.
- X
- XFiltering rules are specified using lex-style rules, i.e. they have
- Xa set of patterns in the left hand-side (lhs) and a set of actions within
- X{} braces on the right hand-side (rhs). Pattern on the lhs are applied
- Xin sequence until one match occurs, at which time the rhs is executed.
- XNormally the first match stops the processing, but that may be changed.
- X
- XAs in lex, the filtering automaton supports the notion of modes, each
- Xrule belonging to a set of modes and being applied only when the current
- Xworking mode matches one of the modes associated with the rule.
- X
- XIf you do not install any filtering rules, then some default hardwired
- Xrules apply. Those simply leave all the messages in your mailbox, but
- Xprocess mails whose Subject line is Command (@SH hooks). You may
- Xoverride this default behavior by writing your own set of rules,
- Xand maybe disable this processing entirely.
- X
- XI have included in the subdirectory 'examples' a set of files which are
- Xpart of my own mail environment, in the hope that they will be useful.
- XIn particular, there is a heavily documented rule file, which is a copy
- Xof the one I am currently using, comments excepted...
- X
- X(This paragraph only matters if you decide to use the PROCESS command.)
- XThe mailhelp, maillist, mailpatch and maillist programs are *old* and
- Xwould need some clean up. They require you to have the kit program
- Xand cshar; those two programs have been posted to comp.sources.unix.
- XYou may want to retrieve them via my mailagent if you can't find them.
- X
- XAny feedback on this program will be appreciated. However, please make
- Xsure to introduce the word 'mailagent' in the subject of your message,
- Xso that the new rule I am about to add to my ~/.rules may correctly
- Xredirect your message into a high priority folder :-)
- X
- X
- XThere is a mailing list hosted in Japan and set up by Shigeya Suzuki
- X<shigeya@foretune.co.jp>, for discussion about the mailagent package as
- Xa whole. It's a good place to ask questions (or answer them) and to
- Xsend your patches. I will post official patches to the net, as well
- Xas to the agent-users list.
- X
- XTo send a mail to the list, address it to <agent-users@foretune.co.jp>.
- XTo subscribe, send a mail to <majordomo@foretune.co.jp>. If you don't
- Xknow how to use majordomo, the syntax of the subscribe command is:
- X
- X subscribe agent-users [address]
- X
- Xwhere the address part is optional. You may unsubscribe automatically
- Xat any time by sending:
- X
- X unsubscribe agent-users
- X
- XIf you have a problem with this version of mailagent, it is recommended
- Xthat you subscribe to the list, then send a description of your problem to
- Xit. If you send mail to me personally, I may not be able to answer in a
- Xtimely fashion.
- X
- XThis mailing list has low traffic (a few articles per week, typically),
- Xand it is expected to remain so, with a high signal/noise ratio.
- X
- XNotes:
- X Raphael Manfredi <ram@acri.fr>
- X Lyon, France, December 1st 1993
- X
- X========================================================================
- X
- XINSTALLATION
- X
- X1) Run Configure. This will figure out various things about your
- Xsystem. After it has completed, it will produce config.h and config.sh.
- X
- XYou might possibly have to trim # comments from the front of Configure
- Xif your shell doesn't handle them, but all other comments will be taken
- Xcare of.
- X
- X2) Run make.
- X
- X3) If make succeeded, you may wish to do "make install install.man". Be
- Xsure your rights are correct (if you install manual pages, you may need
- Xsuper-user privileges). By not running "make install.man", you avoid the
- Xinstallation of the manual pages.
- X
- X4) Read the manual entry before running.
- X
- X5) IMPORTANT! Communicate any problem and suggested patches to me,
- Xram@acri.fr (Raphael Manfredi), so we can keep this distribution in
- Xsync. If you have a problem, there will be someone else who had it or
- Xwill have it too...
- X
- XIf possible, send me patches such that the patch program will apply
- Xthem. Context diffs are the best, then normal diffs. Do not send ed
- Xscripts, I have probably changed my copy since the version you got.
- X
- X6) After everything is installed, you can do make clobber. This will
- Xclean up everything and let you re-distribute this kit, without
- Xcarrying useless files. You should keep this distribution intact, so
- Xthat future patches will be applyable.
- X
- X7) I have an automatic patch sender. Send me the following mail:
- X
- X Subject: Command
- X @SH mailhelp PATH
- X
- Xand you'll get instructions (PATH stands for YOUR e-mail address, either
- Xin INTERNET or in bang notation). I would recommend you to get all the
- Xissued patches before you start making some modifications on this
- Xpackage.
- X
- X8) If you wish to de-install the package, you may run "make deinstall".
- XA separate "make deinstall.man" will remove the manual pages. Be sure
- Xthe makefiles are correctly set before running any deinstall target.
- XOn USG systems, some executable have a chance to remain despite the
- Xdeinstall (text file busy...).
- X
- X Raphael Manfredi <ram@acri.fr>
- X
- END_OF_FILE
- if test 6197 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'PACKLIST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'PACKLIST'\"
- else
- echo shar: Extracting \"'PACKLIST'\" \(16462 characters\)
- sed "s/^X//" >'PACKLIST' <<'END_OF_FILE'
- X File Name Archive # Description
- X----------------------------------------------------------
- XPACKNOTES 1 Warnings about long lines, etc
- XREADME 1 Basic instructions
- XMANIFEST 12 This list of files
- XArtistic 18 The Artistic Licence
- XChanges 20 User-visible changes between 2.9 and 3.0
- XConfigure.01 6 Portability tool (part 1)
- XConfigure.02 7 Portability tool (part 2)
- XCredits 17 Traditional "thank you" list
- XJmakefile 22 Description of the main Makefile
- XMakefile.SH 18 A makefile to run subsidiary makefiles
- XPACKLIST 1 This shipping list
- Xagent/ 1 Where mailagent support files are located
- Xagent/Jmakefile 22 High level description of Makefile
- Xagent/Makefile.SH 16 Makefile which builds and installs mailagent
- Xagent/README 25 Welcome to mailagent
- Xagent/examples/ 1 A set of files from my own environment
- Xagent/examples/README 23 Explains what the examples are
- Xagent/examples/daemon 25 Rules for "vacation" emulation
- Xagent/examples/mailfolders 25 A copy of my ~/.mailfolders
- Xagent/examples/mchk 24 Checks for new mail
- Xagent/examples/mhinc 25 Call the MH inc command to incorporate new mail
- Xagent/examples/nocmds 25 Message you currently get if you send me a command
- Xagent/examples/profile 23 What I added to my onw ~/.profile
- Xagent/examples/rules 15 The rules I am currently using
- Xagent/examples/vacation 25 A sample vacation message
- Xagent/files/ 1 Mailagent's configuration files
- Xagent/files/Jmakefile 25 High level description for Makefile
- Xagent/files/Makefile.SH 18 Makefile for subsidiary files
- Xagent/files/README 23 Notes about files found in this directory
- Xagent/files/agenthelp 17 Help file used by mailhelp
- Xagent/files/chkagent.sh 20 Cron script to spot problems in the mailagent system
- Xagent/files/commands 25 Allowed commands for mailagent
- Xagent/files/distribs 25 Example of distribution list
- Xagent/files/filter.sh 16 Shell script version of the mail filter
- Xagent/files/help 1 Directory holding SERVER help files
- Xagent/files/help/Jmakefile 24 Generic makefile for help directory
- Xagent/files/help/Makefile.SH 19 Generated makefile
- Xagent/files/help/README 25 States what this directory is about
- Xagent/files/help/addauth.SH 22 Help file for addauth
- Xagent/files/help/approve.SH 22 Help file for approve
- Xagent/files/help/delpower.SH 22 Help file for delpower
- Xagent/files/help/end.SH 22 Help file for end
- Xagent/files/help/getauth.SH 22 Help file for getauth
- Xagent/files/help/help.SH 23 Help file for help
- Xagent/files/help/newpower.SH 21 Help file for newpower
- Xagent/files/help/passwd.SH 23 Help file for passwd
- Xagent/files/help/password.SH 22 Help file for password
- Xagent/files/help/power.SH 22 Help file for power
- Xagent/files/help/release.SH 21 Help file for release
- Xagent/files/help/remauth.SH 22 Help file for remauth
- Xagent/files/help/set.SH 23 Help file for set
- Xagent/files/help/setauth.SH 22 Help file for setauth
- Xagent/files/help/user.SH 21 Help file for user
- Xagent/files/mailagent.cf 19 Example of configuration file
- Xagent/files/passwd 25 An example for power password file
- Xagent/files/proglist 3 Example of description file
- Xagent/files/server 1 An example for server command file
- Xagent/filter/ 1 The C version of the mail filter
- Xagent/filter/Jmakefile 24 Generic makefile template
- Xagent/filter/Makefile.SH 18 Makefile for C filter
- Xagent/filter/README 4 Introduction to filter
- Xagent/filter/environ.c 17 Environment management routines
- Xagent/filter/environ.h 22 Declarations for environment management routines
- Xagent/filter/hash.c 8 Symbol table handling
- Xagent/filter/hash.h 21 Declarations for symbol table
- Xagent/filter/io.c 11 I/O routines
- Xagent/filter/io.h 24 Header for I/O routines
- Xagent/filter/lock.c 18 File locking
- Xagent/filter/lock.h 24 Declarations for file locking routines
- Xagent/filter/logfile.c 18 Logging facilities
- Xagent/filter/logfile.h 22 Header for logging routines
- Xagent/filter/main.c 19 The main entry point for filter
- Xagent/filter/misc.c 23 Miscellaneous routines
- Xagent/filter/msg.c 21 Handles fatal messages
- Xagent/filter/msg.h 25 Declarations for user messages
- Xagent/filter/parser.c 11 Parse the config file with variable substitutions
- Xagent/filter/parser.h 23 About config file parsing
- Xagent/filter/portable.h 22 Portable declarations
- Xagent/filter/sysexits.h 23 Standard exit codes
- Xagent/filter/user.c 21 To get login name from user
- Xagent/magent.SH 10 The main processor
- Xagent/maildist.SH 13 Mails a whole distribution
- Xagent/mailhelp.SH 21 Mails some help
- Xagent/maillist.SH 15 Mails a list of available distributions
- Xagent/mailpatch.SH 14 Mails patches for a given distribution
- Xagent/man/ 1 Manual pages for mailagent
- Xagent/man/Jmakefile 25 Makefile description for jmake
- Xagent/man/Makefile.SH 19 Makefile for manual pages extraction
- Xagent/man/mailagent.SH.01 4 Produces a manual page for mailagent (part 1)
- Xagent/man/mailagent.SH.02 2 Produces a manual page for mailagent (part 2)
- Xagent/man/mailagent.SH.03 3 Produces a manual page for mailagent (part 3)
- Xagent/man/mailagent.SH.04 13 Produces a manual page for mailagent (part 4)
- Xagent/man/maildist.SH 24 Produces a manual page for maildist
- Xagent/man/mailhelp.SH 18 Produces a manual page for mailhelp
- Xagent/man/maillist.SH 24 Produces a manual page for maillist
- Xagent/man/mailpatch.SH 24 Produces a manual page for mailpatch
- Xagent/man/package.SH 20 Produces a manual page for package
- Xagent/package.SH 15 Records users of a PD package (cf dist-3.0)
- Xagent/pl/ 1 Perl files used by mailagent scripts
- Xagent/pl/acs_rqst.pl 20 Perl library to ask for private file access
- Xagent/pl/actions.pl.01 5 Implementation of mailagent's actions (part 1)
- Xagent/pl/actions.pl.02 25 Implementation of mailagent's actions (part 2)
- Xagent/pl/add_log.pl 7 Perl library to add logs to logfile
- Xagent/pl/analyze.pl 12 Perl library analyzing the incoming mail
- Xagent/pl/builtins.pl 19 Perl library dealing with builtins
- Xagent/pl/checklock.pl 23 Perl library to check for long lasting locks
- Xagent/pl/cmdserv.pl 8 Implements generic mail server
- Xagent/pl/compress.pl 16 Folder compression library
- Xagent/pl/context.pl 20 Mailagent context file handling
- Xagent/pl/dbr.pl 10 Internal database management
- Xagent/pl/distribs.pl 20 Perl library to scan the distribs file
- Xagent/pl/dynload.pl 20 Dynamically loads perl code into mailagent
- Xagent/pl/emergency.pl 18 Perl library dealing with emergencies
- Xagent/pl/eval.pl 18 A little expression interpreter
- Xagent/pl/extern.pl 23 Perl library to handle persistent variables
- Xagent/pl/fatal.pl 25 Perl library to deal with fatal errors
- Xagent/pl/file_edit.pl 15 File edition with extensive error checking
- Xagent/pl/filter.pl 9 Running the filtering commands
- Xagent/pl/free_file.pl 23 Perl library to free file access
- Xagent/pl/gensym.pl 25 Dynamic symbol generator
- Xagent/pl/getdate.pl 9 Richard Ohnemus's getdate package
- Xagent/pl/header.pl 17 Header-related routines
- Xagent/pl/history.pl 20 Perl library to implement history mechanism
- Xagent/pl/hook.pl 16 Mail hook wrapping functions
- Xagent/pl/hostname.pl 24 Perl library to compute hostname
- Xagent/pl/include.pl 21 Processing of "include file" requests
- Xagent/pl/interface.pl 12 Perl interface with filter commands
- Xagent/pl/jobnum.pl 24 Perl library to compute a job number
- Xagent/pl/lexical.pl 17 Perl library for lexical analysis
- Xagent/pl/listqueue.pl 13 Perl library to list the queue
- Xagent/pl/locate.pl 23 Perl library to locate loaded patterns/addresses
- Xagent/pl/macros.pl 16 Perl library for macros expansion
- Xagent/pl/mailhook.pl 21 Initializing and running hooks
- Xagent/pl/makedir.pl 24 Perl library for making a directory
- Xagent/pl/matching.pl 11 Matching routines used by filter
- Xagent/pl/mbox.pl 20 Getting mails from a mailbox file
- Xagent/pl/mh.pl 15 Handles MH-style folder delivery
- Xagent/pl/mmdf.pl 19 MMDF-style mailbox handling
- Xagent/pl/newcmd.pl 17 Filter command extension driver
- Xagent/pl/once.pl 21 Dealing with once commands
- Xagent/pl/parse.pl 16 Perl library to parse a mail message
- Xagent/pl/period.pl 22 Perl library to compute periods
- Xagent/pl/plsave.pl 14 Perl library to handle the plsave cache file
- Xagent/pl/plural.pl 24 Perl library to pluralize words
- Xagent/pl/power.pl 15 Power management for mail server
- Xagent/pl/pqueue.pl 20 Processing the queued mails
- Xagent/pl/q.pl 25 Quote removal function
- Xagent/pl/queue_mail.pl 14 Queuing mails
- Xagent/pl/rangeargs.pl 23 Perl library to expand a list of patches
- Xagent/pl/read_conf.pl 19 Perl library to read configuration file
- Xagent/pl/rfc822.pl 19 Perl library to parse RFC822 addresses
- Xagent/pl/rules.pl 12 Compiles the filtering rules
- Xagent/pl/runcmd.pl 13 Filter commands ran from here
- Xagent/pl/secure.pl 20 Make sure a file is "secure" and can be trusted
- Xagent/pl/sendfile.pl 14 Perl library to send files in shar / kit mode
- Xagent/pl/stats.pl 1 Mailagent's statistics recording and printing
- Xagent/pl/tilde.pl 25 Perl library to perform ~name expansion
- Xagent/pl/unpack.pl 2 Perl library to unpack archive files
- Xagent/pl/usrmac.pl 14 User-defined macros
- Xagent/test/ 1 Regression test suite
- Xagent/test/Jmakefile 23 Generic makefile for test suite
- Xagent/test/Makefile.SH 17 Makefile for test suite
- Xagent/test/README 20 About the regression tests
- Xagent/test/TEST 19 Runs the full test suite
- Xagent/test/actions 17 Rule file for cmd tests
- Xagent/test/basic/ 1 Basic tests
- Xagent/test/basic/config.t 20 Main test initialization and sanity checks
- Xagent/test/basic/filter.t 21 Make sure C filter works
- Xagent/test/basic/mailagent.t 9 Make sure mailagent basically works
- Xagent/test/cmd/ 1 Tests of mailagent's filtering commands
- Xagent/test/cmd/abort.t 25 Test ABORT command
- Xagent/test/cmd/annotate.t 24 Test ANNOTATE command
- Xagent/test/cmd/apply.t 22 Test APPLY command
- Xagent/test/cmd/assign.t 24 Test ASSIGN command
- Xagent/test/cmd/back.t 24 Test BACK command
- Xagent/test/cmd/begin.t 24 Test BEGIN command
- Xagent/test/cmd/bounce.t 23 Test BOUNCE command
- Xagent/test/cmd/delete.t 25 Test DELETE command
- Xagent/test/cmd/feed.t 25 Test FEED command
- Xagent/test/cmd/forward.t 22 Test FORWARD command
- Xagent/test/cmd/give.t 24 Test GIVE command
- Xagent/test/cmd/keep.t 21 Test KEEP command
- Xagent/test/cmd/leave.t 22 Test LEAVE command
- Xagent/test/cmd/macro.t 25 Test MACRO command
- Xagent/test/cmd/message.t 23 Test MESSAGE command
- Xagent/test/cmd/nop.t 25 Test NOP command
- Xagent/test/cmd/notify.t 22 Test NOTIFY command
- Xagent/test/cmd/once.t 21 Test ONCE command
- Xagent/test/cmd/pass.t 24 Test PASS command
- Xagent/test/cmd/perl.t 23 Test PERL command
- Xagent/test/cmd/pipe.t 24 Test PIPE command
- Xagent/test/cmd/post.t 23 Test POST command
- Xagent/test/cmd/process.t 25 Test PROCESS command
- Xagent/test/cmd/purify.t 24 Test PURIFY command
- Xagent/test/cmd/queue.t 25 Test QUEUE command
- Xagent/test/cmd/record.t 21 Test RECORD command
- Xagent/test/cmd/reject.t 24 Test REJECT command
- Xagent/test/cmd/require.t 24 Test REQUIRE command
- Xagent/test/cmd/restart.t 24 Test RESTART command
- Xagent/test/cmd/resync.t 25 Test RESYNC command
- Xagent/test/cmd/run.t 25 Test RUN command
- Xagent/test/cmd/save.t 22 Test SAVE command
- Xagent/test/cmd/select.t 24 Test SELECT command
- Xagent/test/cmd/server.t 25 Test SERVER command
- Xagent/test/cmd/split.t 16 Test SPLIT command
- Xagent/test/cmd/store.t 21 Test STORE command
- Xagent/test/cmd/strip.t 21 Test STRIP command
- Xagent/test/cmd/subst.t 25 Test SUBST command
- Xagent/test/cmd/tr.t 25 Test TR command
- Xagent/test/cmd/unique.t 21 Test UNIQUE command
- Xagent/test/cmd/unknown.t 24 Make sure unknown command defaults correctly
- Xagent/test/cmd/vacation.t 22 Test VACATION command
- Xagent/test/cmd/write.t 21 Test WRITE command
- Xagent/test/filter/ 1 Testing the filtering capabilities
- Xagent/test/filter/backref.t 23 Check backreferences
- Xagent/test/filter/case.t 24 Normalized header case tests
- Xagent/test/filter/default.t 23 Check default behaviour when mail not saved
- Xagent/test/filter/escape.t 25 Escape sequences within actions
- Xagent/test/filter/group.t 24 Selector combination tests
- Xagent/test/filter/hook.t 20 Ensure hooks are correctly invoked
- Xagent/test/filter/list.t 5 Check matching on lists like To and Newsgroups
- Xagent/test/filter/loop.t 24 Check loop detection
- Xagent/test/filter/mode.t 24 Make sure mode selection logic works
- Xagent/test/filter/multiple.t 23 Check multiple selectors
- Xagent/test/filter/not.t 23 Negated pattern tests
- Xagent/test/filter/pattern.t 24 Check patterns specification and loading
- Xagent/test/filter/range.t 22 Selector range tests
- Xagent/test/filter/status.t 24 Action status updating tests
- Xagent/test/level 19 Default logging level for tests
- Xagent/test/mail 22 The mail used by testing routines
- Xagent/test/misc/ 1 Directory for miscellaneous tests
- Xagent/test/misc/compress.t 6 Folder compression checks
- Xagent/test/misc/mh.t 21 MH-style folder checks
- Xagent/test/misc/mmdf.t 23 MMDF-style mailbox checks
- Xagent/test/misc/newcmd.t 21 Filter command extension tests
- Xagent/test/misc/usrmac.t 20 User-defined macros checks
- Xagent/test/option/ 1 Tests the options to the mailagent program
- Xagent/test/option/L.t 25 Test -L option
- Xagent/test/option/V.t 25 Test -V option
- Xagent/test/option/c.t 24 Test -c option
- Xagent/test/option/d.t 23 Test -d option
- Xagent/test/option/e.t 22 Test -e option
- Xagent/test/option/f.t 22 Test -f option
- Xagent/test/option/h.t 25 Test -h option
- Xagent/test/option/i.t 24 Test -i option
- Xagent/test/option/l.t 22 Test -l option
- Xagent/test/option/o.t 25 Test -o option
- Xagent/test/option/q.t 23 Test -q option
- Xagent/test/option/r.t 25 Test -r option
- Xagent/test/option/s.t 21 Test -s option
- Xagent/test/option/t.t 23 Test -t option
- Xagent/test/option/what.t 25 Ensure good behaviour with unknown option
- Xagent/test/pl/ 1 Perl libraries for the regression test suite
- Xagent/test/pl/cmd.pl 24 Initializes command paths
- Xagent/test/pl/filter.pl 24 Set up environment for filter tests
- Xagent/test/pl/init.pl 25 Variable initializations
- Xagent/test/pl/logfile.pl 23 Logging file checking
- Xagent/test/pl/mail.pl 23 Modifies mail components
- Xagent/test/pl/misc.pl 25 Set up for miscellaneous tests
- Xagent/test/pl/mta.pl 25 Trivial MTA and NTA for tests
- Xagent/test/rules 19 Rules used by filtering tests
- Xbin/ 1 Directory for uninstalled binaries
- Xbin/perload 10 The dataloading/autoloading perl translator
- Xconfig_h.SH 13 Produces config.h
- Xconfmagic.h 25 Magic symbol remapping
- Xinstall.SH 19 Installation script
- Xmisc/ 1 Miscellaneous server commands
- Xmisc/README 15 Introduction to the misc directory
- Xmisc/shell/ 1 Command to run arbitrary shell commands
- Xmisc/shell/README 25 Warning, should be read carefully
- Xmisc/shell/server.cf 16 Configuration of this server command
- Xmisc/shell/shell 23 The shell command itself
- Xmisc/unkit/ 1 Command to automatically unkit messages
- Xmisc/unkit/README 25 Some notes about the UNKIT command
- Xmisc/unkit/kitok.msg 10 An example of message to be sent when kit received
- Xmisc/unkit/mailagent.cf 25 Template for inclusion into your ~/.mailagent
- Xmisc/unkit/newcmd.cf 26 Configuration of the new command
- Xmisc/unkit/rules 21 Rules to be added to handle kit messages
- Xmisc/unkit/unkit.pl 14 Implementation of the user-defined UNKIT command
- Xpatchlevel.h 8 Current version number and patch level
- END_OF_FILE
- if test 16462 -ne `wc -c <'PACKLIST'`; then
- echo shar: \"'PACKLIST'\" unpacked with wrong size!
- fi
- # end of 'PACKLIST'
- fi
- if test ! -d 'agent' ; then
- echo shar: Creating directory \"'agent'\"
- mkdir 'agent'
- fi
- if test ! -d 'agent/examples' ; then
- echo shar: Creating directory \"'agent/examples'\"
- mkdir 'agent/examples'
- fi
- if test ! -d 'agent/files' ; then
- echo shar: Creating directory \"'agent/files'\"
- mkdir 'agent/files'
- fi
- if test ! -d 'agent/files/help' ; then
- echo shar: Creating directory \"'agent/files/help'\"
- mkdir 'agent/files/help'
- fi
- if test -f 'agent/files/server' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/files/server'\"
- else
- echo shar: Extracting \"'agent/files/server'\" \(263 characters\)
- sed "s/^X//" >'agent/files/server' <<'END_OF_FILE'
- X# Commands allowed by the server (file formatted with tabstops=4)
- X
- X# command name
- X# type (shell/perl/end/help)
- X# concealed arguments
- X# collect data
- X# file name
- X# [function name (perl) / options (shell)]
- X
- Xend end - - -
- Xhelp help - - -
- END_OF_FILE
- if test 263 -ne `wc -c <'agent/files/server'`; then
- echo shar: \"'agent/files/server'\" unpacked with wrong size!
- fi
- # end of 'agent/files/server'
- fi
- if test ! -d 'agent/filter' ; then
- echo shar: Creating directory \"'agent/filter'\"
- mkdir 'agent/filter'
- fi
- if test ! -d 'agent/man' ; then
- echo shar: Creating directory \"'agent/man'\"
- mkdir 'agent/man'
- fi
- if test ! -d 'agent/pl' ; then
- echo shar: Creating directory \"'agent/pl'\"
- mkdir 'agent/pl'
- fi
- if test -f 'agent/pl/stats.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/pl/stats.pl'\"
- else
- echo shar: Extracting \"'agent/pl/stats.pl'\" \(23279 characters\)
- sed "s/^X//" >'agent/pl/stats.pl' <<'END_OF_FILE'
- X;# $Id: stats.pl,v 3.0 1993/11/29 13:49:17 ram Exp ram $
- X;#
- X;# Copyright (c) 1990-1993, Raphael Manfredi
- X;#
- X;# You may redistribute only under the terms of the Artistic License,
- X;# as specified in the README file that comes with the distribution.
- X;# You may reuse parts of this distribution only within the terms of
- X;# that same Artistic License; a copy of which may be found at the root
- X;# of the source tree for mailagent 3.0.
- X;#
- X;# $Log: stats.pl,v $
- X;# Revision 3.0 1993/11/29 13:49:17 ram
- X;# Baseline for mailagent 3.0 netwide release.
- X;#
- X;#
- X;# Handle the mailagent statistics file. This file is known as the statfile
- X;# in the configuration file (typically mailagent.st in the spool directory).
- X;# This file contains a summary of the action taken by the mailagent. The very
- X;# first line contains: mailstat: <timestamp> which is the date the statistics
- X;# started.
- X;#
- X;# The following format is used for each records:
- X;#
- X;# <timestamp> 0 0
- X;# <# of mails processed> <# commands run> <# of failures> <# of bytes>
- X;# <rule number> <mode> <number of matches>
- X;# "default" <number of matches>
- X;# "vacation" <number of vaction messages sent>
- X;# "seen" <number of messages already seen>
- X;# "saved" <number of messages saved by default>
- X;# <command name> <mode> <number of execution>
- X;# !<command name> <mode> <number of failures>
- X;# @<command name> <mode> <tag> <number of execution>
- X;# %@<command name> <mode> <tag> <number of non-executed commands>
- X;# --------
- X;# <output of rule dumping>
- X;# ++++++++
- X;#
- X;# The leading timestamp records the stamp on the rule file, followed by two
- X;# zeros (currently unused locations, reserved for future use, as they say).
- X;#
- X;# The number of mails processed is only stored to check the consistency of the
- X;# statistics file. Likewise, the number of commands run and the number of
- X;# failed commands are used to check the logging accuracy.
- X;#
- X;# Lines starting with a number indicate a match for a particular rule, in
- X;# a given mode. The "default", "vacation" and "seen" lines record the activity
- X;# of the default action, the vacation mode or the messages already processed
- X;# which come back.
- X;#
- X;# Commands are also logged. They are always spelled upper-cased. If the line
- X;# starts with a '!', it indicates a failure. If the character '@' is found
- X;# before the command name, it indicates a ONCE command. The tag part of the
- X;# identification is logged, but not the name (which is likely to be an e-mail
- X;# address anyway, whereas the tag identifies the command itself). The lines
- X;# starting with '%' also give the number of ONCE commands which were not
- X;# executed because the retry time was not reached.
- X;#
- X;# Below the dashed line, all the rules are dumped in order, and are separated
- X;# by a blank line. These are the rules listed in the rule file and they are
- X;# given for information purposes only, when reporting statistics. It ends with
- X;# a plus line.
- X;#
- X;# Whenever the rule file is updated, another record is started after having
- X;# been diffing the rules we have parsed with the rules dumped in the statistics
- X;# file.
- X;#
- X;# In order to improve performances, the statistics file is cached in memory.
- X;# Only the last record is read, up to the dashed-line. The data structures
- X;# used are:
- X;#
- X;# @stats'Top: the top seven fields of the record:
- X;# (time, 0, 0, processed, run, failed, bytes)
- X;# %stats'Rule: indexed by <N>+mode, the number of matches
- X;# %stats'Special: indexed by "default", "vacation", "saved" or "seen"
- X;# %stats'Command: indexed by name+mode, the total number of runs
- X;# this accounts for ONCE commands as well.
- X;# %stats'FCommand: indexed by name+mode, the number of failures
- X;# this accounts for ONCE commands as well.
- X;# %stats'Once: indexed by name+mode+tag, the number of succesful runs
- X;# %stats'ROnce: indexed by name+mode+tag, number of non-executed comands
- X;#
- Xpackage stats;
- X
- X$stats_wanted = 0; # No statistics wanted by default
- X$new_record = 0; # True when a new record is to be started
- X$start_date = 0; # When statistics started
- X$suppressed = 0; # Statistics suppressed by higher authority
- X
- X# Suppress statistics. This function is called when options like -r or -e are
- X# used. Those usually specify one time rules and thus are not entitled to be
- X# recorded into the statistics.
- Xsub main'no_stats { $suppressed = 1; }
- X
- X# Read the statistics file and fill in the hash tables
- Xsub main'read_stats {
- X local($statfile) = $cf'statfile; # Extract value from config package
- X local($loglvl) = $main'loglvl;
- X local($_, $.);
- X $stats_wanted = 1 if ($statfile ne '' && -f $statfile);
- X $stats_wanted = 0 if $suppressed;
- X return unless $stats_wanted;
- X # Do not come here unless statistics are really wanted
- X unless (open(STATS, "$statfile")) {
- X &'add_log("ERROR could not open statistics file $statfile: $!")
- X if $loglvl > 0;
- X $stats_wanted = 0; # Cannot keep track of statistics
- X return;
- X }
- X local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime, $mtime,
- X $ctime,$blksize,$blocks) = stat($cf'rules);
- X # A null size means we have to start over again
- X unless (-s $statfile) {
- X &'add_log("starting new statistics") if $loglvl > 6;
- X $start_date = time;
- X close STATS;
- X @Top = ($mtime, 0, 0, 0, 0, 0, 0);
- X return;
- X }
- X $_ = <STATS>;
- X unless (/^mailstat: (\d+)/) {
- X &'add_log("ERROR corrupted statistics file $statfile") if $loglvl;
- X close STATS;
- X $stats_wanted = 0;
- X return;
- X } else {
- X $start_date = $1;
- X }
- X # The first record is always the active one. Check the timestamp. If the
- X # rule file has changed, check the sums.
- X $_ = <STATS>;
- X local($timestamp, $unused_1, $unused_2) = split(' ', $_);
- X if ($main'edited_rules || $mtime > $timestamp) { # File was modified?
- X # Reset timestamp for next time if rule come from a file.
- X $timestamp = $mtime;
- X $timestamp = 0 if $main'edited_rules;
- X &'add_log("rule file may have changed") if $loglvl > 18;
- X $new_record = &diff_rules($statfile); # Run the full diff then
- X if ($new_record) {
- X &'add_log("rule file has changed") if $loglvl > 6;
- X @Top = ($mtime, 0, 0, 0, 0, 0, 0);
- X close STATS;
- X $start_date = time;
- X return;
- X }
- X &'add_log("rule file has not changed") if $loglvl > 6;
- X }
- X # Read second line and build the @Top array
- X $_ = <STATS>;
- X local($processed, $run, $failed, $bytes) = split(' ', $_);
- X @Top =
- X ($timestamp, $unused_1, $unused_2, $processed, $run, $failed, $bytes);
- X local($valid) = 0; # Set to true when a valid record was found
- X &fill_stats; # Fill in data structures
- X close STATS;
- X &'add_log('statistics initialized and loaded') if $loglvl > 18;
- X}
- X
- X# Write the statistics file
- Xsub main'write_stats {
- X local($statfile) = $cf'statfile; # Extract value from config package
- X local($loglvl) = $main'loglvl;
- X return unless $stats_wanted;
- X local($oldstat) = -f $statfile;
- X if ($oldstat) {
- X unlink("$statfile.b") if -f "$statfile.b";
- X unless (rename($statfile, "$statfile.b")) {
- X &'add_log("ERROR cannot rename $statfile as $statfile.b: $!")
- X if $loglvl;
- X return;
- X }
- X }
- X unless (open(STATS, ">$statfile")) {
- X &'add_log("ERROR cannot create $statfile: $!") if $loglvl;
- X return;
- X }
- X # If a new record is to be created, do it at the top of the file, then
- X # append the old statistics file at the end of it. Otherwise, the first
- X # record of the old statistics file is removed and the remaining is
- X # appended.
- X print STATS "mailstat: $start_date\n"; # Magic line
- X print STATS join(' ', @Top[0..2]), "\n";
- X print STATS join(' ', @Top[3..$#Top]), "\n";
- X &print_array(*Rule, ""); # Print rule matches statistics
- X &print_array(*Special, ""); # Print special stats
- X &print_array(*Command, ""); # Print actions executions
- X &print_array(*FCommand, "!"); # Print failed actions
- X &print_array(*Once, "@"); # Print once commands done
- X &print_array(*ROncem, "%@"); # Print once commands not retried
- X print STATS "------\n";
- X &rules'write_fd("stats'STATS"); # Append internal form of rules
- X # If there was no previous statistics file, it's done!
- X unless ($oldstat) {
- X close STATS;
- X return;
- X }
- X unless (open(OLD, "$statfile.b")) {
- X &'add_log("ERROR cannot open old statistics file") if $loglvl;
- X close STATS;
- X return;
- X }
- X # If no new record was created, we have to skip the first record of the old
- X # statistics file before appending.
- X unless ($new_record) {
- X while (<OLD>) {
- X last if /^\+\+\+\+\+\+/;
- X }
- X }
- X # It's fine to only check the return status of print right now. If there is
- X # not enough space on the device, we won't be able to append the whole
- X # backup file, but then we have to discard previously saved statistics
- X # anyway...
- X # Note: 'print STATS <OLD>' would cause an excessive memory consumption
- X # given that a statistics file can be several hundred Kbytes long.
- X local($status) = 1; # Printing status
- X while (<OLD>) {
- X $status &= (print STATS); # Status remains to 1 while successful
- X }
- X close OLD;
- X close STATS;
- X if ($status) { # Print ran ok
- X unlink("$statfile.b");
- X } else { # Print failed
- X &'add_log("ERROR could not update statistics: $!") if $loglvl;
- X unless (rename("$statfile.b", $statfile)) {
- X &'add_log("ERROR could not restore old statistics file: $!")
- X if $loglvl;
- X }
- X }
- X}
- X
- X# Print the hash table array in STATS file
- Xsub print_array {
- X local(*name, $leader) = @_;
- X local(@keys);
- X foreach (sort keys %name) {
- X @keys = split(/:/);
- X print STATS $leader . join(' ', @keys) . ' ' . $name{$_}, "\n";
- X }
- X}
- X
- X#
- X# Accounting routines
- X#
- X
- X# Record a mail processing
- Xsub main's_filtered {
- X return unless $stats_wanted;
- X local($length) = @_;
- X $Top[3]++;
- X $Top[6] += $length;
- X}
- X
- X# Record a rule match
- Xsub main's_match {
- X return unless $stats_wanted;
- X local($number, $mode) = @_;
- X $Rule{"$number:$mode"}++;
- X}
- X
- X# Record a default rule
- Xsub main's_default {
- X return unless $stats_wanted;
- X $Special{'default'}++;
- X}
- X
- X# Record a vacation message sent in vacation mode
- Xsub main's_vacation {
- X return unless $stats_wanted;
- X $Special{'vacation'}++;
- X}
- X
- X# Record a message saved by the default action
- Xsub main's_saved {
- X return unless $stats_wanted;
- X $Special{'saved'}++;
- X}
- X
- X# Record an already processed message
- Xsub main's_seen {
- X return unless $stats_wanted;
- X $Special{'seen'}++;
- X}
- X
- X# Record a successful execution
- Xsub main's_action {
- X return unless $stats_wanted;
- X local($name, $mode) = @_;
- X $Command{"$name:$mode"}++;
- X $Top[4]++;
- X}
- X
- X# Record a failed execution
- Xsub main's_failed {
- X return unless $stats_wanted;
- X local($name, $mode) = @_;
- X $Command{"$name:$mode"}++;
- X $FCommand{"$name:$mode"}++;
- X $Top[4]++;
- X $Top[5]++;
- X}
- X
- X# Record a successful once
- Xsub main's_once {
- X return unless $stats_wanted;
- X local($name, $mode, $tag) = @_;
- X $Once{"$name:$mode:$tag"}++;
- X}
- X
- X# Record a non-retried once
- Xsub main's_noretry {
- X return unless $stats_wanted;
- X local($name, $mode, $tag) = @_;
- X $ROnce{"$name:$mode:$tag"}++;
- X}
- X
- X#
- X# Low-level routines
- X#
- X
- X# Establish a difference between the rules we have in memory and the rules
- X# that has been dumped at the end of the active record. Return the difference
- X# status, true or false.
- Xsub diff_rules {
- X local($file) = @_; # Statistics file where dump is stored
- X local(*loglvl) = *main'loglvl;
- X local($_, $.);
- X open(FILE, "$file") || return 1; # Changed if we cannot re-open file
- X # Go past the first dashed line, where the dumped rules begin
- X while (<FILE>) {
- X last if /^------/;
- X }
- X # The difference is done on the internal representation of the rules,
- X # which gives us a uniform and easy way to make sure the rules did not
- X # change.
- X local(*Rules) = *main'Rules; # The @Rules array
- X local($i) = 0; # Index in the rules
- X while (<FILE>) {
- X last if /^\+\+\+\+\+\+/; # End of dumped rules
- X last if $i > $#Rules;
- X chop;
- X last unless $_ eq $Rules[$i]; # Compare rule with internal form
- X $i++; # Index in the @Rules array
- X }
- X if ($i <= $#Rules) { # If one rule did not match
- X close FILE;
- X ++$i;
- X &'add_log("rule $i did not match") if $loglvl > 11;
- X return 1; # Rule file has changed
- X }
- X # Now check the hash table entries
- X local(*Rule) = *main'Rule; # The %Rule array
- X local(@keys) =
- X sort rules'hashkey keys(%Rule); # Sorted keys H0, H1, etc...
- X $i = 0; # Reset index
- X while (<FILE>) { # Swallow blank line
- X last if /^\+\+\+\+\+\+/; # End of dumped rules
- X last if $i > $#keys;
- X chop;
- X last unless $_ eq $Rule{$keys[$i]};
- X $i++; # Index in @keys
- X }
- X if ($i <= $#keys) { # Changed if one rule did not match
- X close FILE;
- X ++$i;
- X &'add_log("hrule $i did not match") if $loglvl > 11;
- X return 1; # Rule file has changed
- X }
- X close FILE;
- X return 1 unless /^\+\+\+\+\+\+/; # More rules to come
- X 0; # Rule file did not change
- X}
- X
- X# Read pre-opened STATS file descriptor and fill in the statistics arrays
- Xsub fill_stats {
- X while (<STATS>) {
- X last if /^------/; # Reached end of statistics
- X if (/^(\d+)\s+(\w+)\s+(\d+)/) { # <rule> <mode> <# match>
- X $Rule{"$1:$2"} = int($3);
- X } elsif (/^([a-z]+)\s+(\d+)/) { # <special> <# match>
- X $Special{$1} = $2; # first token is the key
- X } elsif (/^([A-Z]+)\s+(\w+)\s+(\d+)/) { # <cmd> <mode> <# succes>
- X $Command{"$1:$2"} = int($3);
- X } elsif (/^!([A-Z]+)\s+(\w+)\s+(\d+)/) { # <cmd> <mode> <# fail>
- X $FCommand{"$1:$2"} = int($3);
- X } elsif (/^@([A-Z]+)\s+(\w+)\s+(\S+)\s+(\d+)/) { # Once run
- X $Once{"$1:$2:$3"} = int($4);
- X } elsif (/^%@([A-Z]+)\s+(\w+)\s+(\S+)\s+(\d+)/) { # Once not retried
- X $ROnce{"$1:$2:$3"} = int($4);
- X } else {
- X &'add_log("ERROR corrupted line $. in statistics file") if $loglvl;
- X &'add_log("ERROR line $. was: $_") if $loglvl > 1;
- X }
- X }
- X}
- X
- X#
- X# Reporting statistics
- X#
- X
- X# Dump the statistics on the standard output.
- X# Here are the possible options:
- X# u: print only used rules
- X# m: merge all the statistics at the end
- X# a: all mode reported
- X# r: rule-based statistics, on a per-state basis
- X# y: USELESS if -m, but kept for nice mnemonic
- Xsub main'report_stats {
- X require 'ctime.pl';
- X local($option) = @_; # Options from command line
- X local($opt_u) = $option =~ /u/; # Only used rules
- X local($opt_m) = $option =~ /m/; # Merge all statistics at the end
- X local($opt_a) = $option =~ /a/; # Print mode-related statistics
- X local($opt_r) = $option =~ /r/; # Print rule-based statistics
- X local($opt_y) = $option =~ /y/; # Yield rule-based summary
- X local($statfile) = $cf'statfile;
- X local(*loglvl) = *main'loglvl;
- X local($_, $.);
- X select(STDOUT);
- X unless ($statfile ne '' && -f "$statfile") {
- X print "No statistics available.\n";
- X return;
- X }
- X unless (open(STATS, "$statfile")) {
- X print "Can't open $statfile: $!\n";
- X return;
- X }
- X unless (-s $statfile) {
- X print "Statistics file is empty.\n";
- X close STATS;
- X return;
- X }
- X local($lasttime) = time; # End of last dumped period
- X local($start) = $lasttime; # Save current time
- X local($amount); # Number of mails processed
- X local($bytes); # Bytes processed
- X local($actions); # Number of actions
- X local($failures); # Failures reported
- X local(%Cmds); # Execution / action
- X local(%FCmds); # Failures / action
- X local(%Spec); # Summary of special actions
- X local(%Mrule); # For merged rules statistics
- X local($in_summary); # True when in summary
- X 1 while &print_stats; # Print statistics for each record
- X close STATS;
- X if ($opt_m) {
- X $in_summary = 1; # Signal in summary part
- X $Top[3] = $amount; # Number of mails processed
- X $Top[4] = $actions; # Number of mails processed
- X $Top[5] = $failures; # Failures reported
- X $Top[6] = $bytes; # Bytes processed
- X $current_time = $lasttime;
- X $lasttime = $start;
- X local(*Special) = *Spec; # Alias %Spec into %Special
- X &print_general("Summary");
- X local(*Command) = *Cmds; # Alias %Cmds into %Command
- X local(*FCommand) = *FCmds; # Alias %FCmds into %FCommand
- X &print_commands; # Commands summary
- X &print_rules_summary; # Print rules summary
- X }
- X}
- X
- X# Print statistics for one record. This subroutine exectues in the context
- X# built by report_stats. I heavily used dynamic scope hereafter to avoid code
- X# duplication.
- Xsub print_stats {
- X return 0 if eof(STATS);
- X $_ = <STATS>;
- X unless (/^mailstat: (\d+)/) {
- X print "Statistics file is corrupted, line $.\n";
- X return 0;
- X }
- X local($current_time) = $1;
- X # Build a valid context for data structures fill-in
- X local(@Top, %Rule, %Special, %Command, %FCommand, %Once, %ROnce);
- X # The two first line are the @Top array
- X $_ = <STATS>;
- X $_ .= <STATS>;
- X chop;
- X @Top = split(/\s+/);
- X &fill_stats; # Fill in local data structures
- X &print_summary; # Print local summary
- X # Now build a valid context for rule dumping
- X local(@main'Rules, %main'Rule);
- X local($i) = 0; # Force numeric context
- X local($hash); # True when entering %Rule section
- X while (<STATS>) {
- X last if /^\+\+\+\+\+\+/;
- X chop;
- X if (/^$/) {
- X $hash = 1; # Separator between @Rules and %Rule
- X next;
- X }
- X unless ($hash) {
- X push(@main'Rules, $_);
- X } else {
- X $main'Rule{"H$i"} = $_;
- X $i++;
- X }
- X }
- X &main'dump_rules(*print_header, *rule_stats);
- X print '=' x 79, "\n";
- X $lasttime = $current_time;
- X}
- X
- X# Print a summary from a given record
- Xsub print_summary {
- X &print_general("Statistics");
- X &print_commands; # Commands summary
- X $amount += $Top[3]; # Number of mails processed
- X $bytes += $Top[6]; # Bytes processed
- X $actions += $Top[4]; # Actions exectuted
- X $failures += $Top[5]; # Failures reported
- X foreach (keys %Special) { # Special statistics
- X $Spec{$_} += $Special{$_};
- X }
- X foreach (keys %Command) { # Commands ececuted
- X $Cmds{$_} += $Command{$_};
- X }
- X foreach (keys %FCommand) { # Failed commands
- X $FCmds{$_} += $FCommand{$_};
- X }
- X}
- X
- X# Print general informations, as found in @Top.
- Xsub print_general {
- X local($what) = @_;
- X local($last) = &'ctime($lasttime);
- X local($now) = &'ctime($current_time);
- X local($n, $s);
- X chop $now;
- X chop $last;
- X # Header of statistics
- X print "$what from $now to $last:\n";
- X print '~' x 79, "\n";
- X print "Processed $Top[3] mail";
- X print "s" unless $Top[3] == 1;
- X print " for a total of $Top[6] bytes";
- X $n = $Special{'seen'};
- X $s = $n == 1 ? '' : 's';
- X print " ($n mail$s already seen)" if $n;
- X print ".\n";
- X print "Executed $Top[4] action";
- X print "s" unless $Top[4] == 1;
- X local($failed) = $Top[5];
- X unless ($failed) {
- X print " with no failure.\n";
- X } else {
- X print ", $failed of which failed.\n";
- X }
- X $n = $Special{'default'};
- X $s = $n == 1 ? '' : 's';
- X print "The default rule was applied $n time$s";
- X $n = $Special{'saved'};
- X $s = $n == 1 ? '' : 's';
- X local($was) = $n == 1 ? 'was' : 'were';
- X print " and $n message$s $was implicitely saved" if $n;
- X print ".\n";
- X $n = $Special{'vacation'};
- X $s = $n == 1 ? '' : 's';
- X print "Received $n message$s in vacation mode with no rule match.\n" if $n;
- X}
- X
- X# Print the commands executed, as found in %Command and @Top.
- Xsub print_commands {
- X print '~' x 79, "\n";
- X local($cmd, $mode);
- X local(%states, %fstates);
- X local(%cmds, %fcmds);
- X local(@kstates, @fkstates);
- X local($n, $s);
- X foreach (keys %Command) {
- X ($cmd, $mode) = /^(\w+):(\w+)/;
- X $n = $Command{$_};
- X $cmds{$cmd} += $n;
- X $states{"$cmd:$mode"} += $n;
- X }
- X foreach (keys %FCommand) {
- X ($cmd, $mode) = /^(\w+):(\w+)/;
- X $n = $FCommand{$_};
- X $fcmds{$cmd} += $n;
- X $fstates{"$cmd:$mode"} += $n;
- X }
- X local($total) = $Top[4];
- X local($percentage);
- X local($cmd_total);
- X foreach $key (sort keys %cmds) {
- X @kstates = sort grep(/^$key:/, keys %states);
- X $cmd_total = $n = $cmds{$key};
- X $s = $n == 1 ? '' : 's';
- X $percentage = '0.00';
- X $percentage = sprintf("%.2f", ($n / $total) * 100) if $total;
- X print "$key run $n time$s ($percentage %)";
- X if (@kstates == 1) {
- X ($mode) = $kstates[0] =~ /^\w+:(\w+)/;
- X print " in state $mode";
- X } else {
- X $n = @kstates;
- X print " in $n states";
- X }
- X if (defined($fcmds{$key}) && ($n = $fcmds{$key})) {
- X $s = $n == 1 ? '' : 's';
- X $percentage = sprintf("%.2f", ($n / $cmd_total) * 100);
- X print " and failed $n time$s ($percentage %)";
- X }
- X if (@kstates == 1 || !$opt_a) {
- X print ".\n";
- X } else {
- X print ":\n";
- X @fkstates = sort grep(/^$key:/, keys %states);
- X foreach (@kstates) {
- X ($mode) = /^\w+:(\w+)/;
- X $n = $states{$_};
- X $s = $n == 1 ? '' : 's';
- X $percentage = sprintf("%.2f", ($n / $cmd_total) * 100);
- X print " state $mode: $n time$s ($percentage %)";
- X $n = $fstates{$_};
- X $s = $n == 1 ? '' : 's';
- X print ", $n failure$s" if $n;
- X print ".\n";
- X }
- X }
- X }
- X}
- X
- X# Return a uniform representation of a rule (suitable for usage merging)
- Xsub uniform_rule {
- X local($rulenum) = @_;
- X local($text) = $main'Rules[$rulenum - 1];
- X $text =~ s/^(.*}\s+)//; # Get mode and action
- X local($rule) = $1;
- X local(@keys) = split(' ', $text); # H keys for selection / patterns
- X foreach (@keys) {
- X $rule .= "\n" . $main'Rule{$_}; # Add selectors and patterns
- X }
- X $rule;
- X}
- X
- X# Print a summary of merged rules as found in %Mrule
- Xsub print_rules_summary {
- X return unless $opt_y;
- X local(@main'Rules); # The main rules array
- X local(%main'Rule); # The H table for selectors and patterns
- X local($counter) = 0; # Counter for H key computation
- X local($rulenum) = 0; # Rule number
- X local(%Rule); # The local rule statistics array
- X local(@components); # Rule components
- X local($rule); # Constructed rule
- X foreach (keys %Mrule) {
- X s/^(\w+)://; # Get applied state
- X $state = $1;
- X @components = split(/\n/);
- X $rule = shift(@components);
- X foreach (@components) {
- X $rule .= " H$counter";
- X $main'Rule{"H$counter"} = $_;
- X $counter++;
- X }
- X push(@main'Rules, $rule);
- X $rulenum++;
- X $Rule{"$rulenum:$state"} += $Mrule{"$state:$_"};
- X }
- X &main'dump_rules(*print_header, *rule_stats);
- X}
- X
- X#
- X# Hooks for rule dumping
- X#
- X
- X# Print the rule number and the number of applications
- Xsub print_header {
- X local($rulenum) = @_;
- X local($total_matches) = 0;
- X local(@keys) = grep(/^$rulenum:/, keys %Rule);
- X local($state);
- X local($matches);
- X # Add up the usage of rules, whatever the matching state was
- X foreach (@keys) {
- X $matches = $Rule{$_};
- X $total_matches += $matches;
- X if ($opt_y && !$in_summary) {
- X ($state) = /^\d+:(.*)/;
- X $_ = $state . ":" . &uniform_rule($rulenum);
- X $Mrule{$_} += $matches;
- X }
- X }
- X return 0 if ($opt_u && $total_matches == 0);
- X return 0 unless $opt_r;
- X local($total) = $Top[3];
- X $total = 1 unless $total;
- X local($percentage) = sprintf("%.2f", ($total_matches / $total) * 100);
- X $percentage = '0' if $total_matches == 0;
- X local($s) = $total_matches == 1 ? '' : 's';
- X print '-' x 79, "\n";
- X print "Rule #$rulenum, applied $total_matches time$s ($percentage %).\n";
- X}
- X
- X# Print the rule applications, on a per-state basis
- Xsub rule_stats {
- X return unless $opt_r;
- X local($rulenum) = @_;
- X local($mode) = $main'Rules[$rulenum - 1] =~ /^(.*)\s+{/;
- X return unless $mode =~ /,/ || $mode eq 'ALL' || $mode =~ /!/;
- X
- X # If there is only one mode <ALL>, more than one mode, or at least
- X # a negated mode, then we have a priori more than one possible mode
- X # that can lead to the execution of the rule. So dump them.
- X
- X local(@keys) = grep(/^$rulenum:/, keys %Rule);
- X local(%states);
- X local($s, $total);
- X foreach (@keys) {
- X /^\d+:(.+)/;
- X $states{$1}++;
- X }
- X @keys = keys %states;
- X return unless $opt_a;
- X if (@keys == 1) {
- X print "Applied only in state $keys[0].\n";
- X } else {
- X foreach (@keys) {
- X $total = $states{$_};
- X $s = $total == 1 ? '' : 's';
- X print "State $_: $total time$s.\n";
- X }
- X }
- X}
- X
- Xpackage main;
- X
- END_OF_FILE
- if test 23279 -ne `wc -c <'agent/pl/stats.pl'`; then
- echo shar: \"'agent/pl/stats.pl'\" unpacked with wrong size!
- fi
- # end of 'agent/pl/stats.pl'
- fi
- if test ! -d 'agent/test' ; then
- echo shar: Creating directory \"'agent/test'\"
- mkdir 'agent/test'
- fi
- if test ! -d 'agent/test/basic' ; then
- echo shar: Creating directory \"'agent/test/basic'\"
- mkdir 'agent/test/basic'
- fi
- if test ! -d 'agent/test/cmd' ; then
- echo shar: Creating directory \"'agent/test/cmd'\"
- mkdir 'agent/test/cmd'
- fi
- if test ! -d 'agent/test/filter' ; then
- echo shar: Creating directory \"'agent/test/filter'\"
- mkdir 'agent/test/filter'
- fi
- if test ! -d 'agent/test/misc' ; then
- echo shar: Creating directory \"'agent/test/misc'\"
- mkdir 'agent/test/misc'
- fi
- if test ! -d 'agent/test/option' ; then
- echo shar: Creating directory \"'agent/test/option'\"
- mkdir 'agent/test/option'
- fi
- if test ! -d 'agent/test/pl' ; then
- echo shar: Creating directory \"'agent/test/pl'\"
- mkdir 'agent/test/pl'
- fi
- if test ! -d 'bin' ; then
- echo shar: Creating directory \"'bin'\"
- mkdir 'bin'
- fi
- if test ! -d 'misc' ; then
- echo shar: Creating directory \"'misc'\"
- mkdir 'misc'
- fi
- if test ! -d 'misc/shell' ; then
- echo shar: Creating directory \"'misc/shell'\"
- mkdir 'misc/shell'
- fi
- if test ! -d 'misc/unkit' ; then
- echo shar: Creating directory \"'misc/unkit'\"
- mkdir 'misc/unkit'
- fi
- echo shar: End of archive 1 \(of 26\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 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 26 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 26 archives.
- echo "Now run 'sh PACKNOTES', then read README and type Configure.'"
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
-
- exit 0 # Just in case...
-