home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-11-19 | 54.5 KB | 1,409 lines |
- Newsgroups: comp.sources.misc
- From: ram@eiffel.com (Raphael Manfredi)
- Subject: v33i100: mailagent - Rule Based Mail Filtering, Part08/17
- Message-ID: <1992Nov20.050610.14170@sparky.imd.sterling.com>
- X-Md4-Signature: df29022f0cc212b372fd291c70a57438
- Date: Fri, 20 Nov 1992 05:06:10 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: ram@eiffel.com (Raphael Manfredi)
- Posting-number: Volume 33, Issue 100
- Archive-name: mailagent/part08
- Environment: Perl, Sendmail, UNIX
-
- #! /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".
- # Contents: Copying agent/magent.SH agent/pl/analyze.pl
- # agent/test/filter/list.t
- # Wrapped by kent@sparky on Wed Nov 18 22:42:24 1992
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 8 (of 17)."'
- if test -f 'Copying' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Copying'\"
- else
- echo shar: Extracting \"'Copying'\" \(18090 characters\)
- sed "s/^X//" >'Copying' <<'END_OF_FILE'
- X
- X GNU GENERAL PUBLIC LICENSE
- X Version 2, June 1991
- X
- X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- X 675 Mass Ave, Cambridge, MA 02139, USA
- X
- X Everyone is permitted to copy and distribute verbatim copies
- X of this license document, but changing it is not allowed.
- X
- X Preamble
- X
- X The licenses for most software are designed to take away your
- Xfreedom to share and change it. By contrast, the GNU General Public
- XLicense is intended to guarantee your freedom to share and change free
- Xsoftware--to make sure the software is free for all its users. This
- XGeneral Public License applies to most of the Free Software
- XFoundation's software and to any other program whose authors commit to
- Xusing it. (Some other Free Software Foundation software is covered by
- Xthe GNU Library General Public License instead.) You can apply it to
- Xyour programs, too.
- X
- X When we speak of free software, we are referring to freedom, not
- Xprice. Our General Public Licenses are designed to make sure that you
- Xhave the freedom to distribute copies of free software (and charge for
- Xthis service if you wish), that you receive source code or can get it
- Xif you want it, that you can change the software or use pieces of it
- Xin new free programs; and that you know you can do these things.
- X
- X To protect your rights, we need to make restrictions that forbid
- Xanyone to deny you these rights or to ask you to surrender the rights.
- XThese restrictions translate to certain responsibilities for you if you
- Xdistribute copies of the software, or if you modify it.
- X
- X For example, if you distribute copies of such a program, whether
- Xgratis or for a fee, you must give the recipients all the rights that
- Xyou have. You must make sure that they, too, receive or can get the
- Xsource code. And you must show them these terms so they know their
- Xrights.
- X
- X We protect your rights with two steps: (1) copyright the software, and
- X(2) offer you this license which gives you legal permission to copy,
- Xdistribute and/or modify the software.
- X
- X Also, for each author's protection and ours, we want to make certain
- Xthat everyone understands that there is no warranty for this free
- Xsoftware. If the software is modified by someone else and passed on, we
- Xwant its recipients to know that what they have is not the original, so
- Xthat any problems introduced by others will not reflect on the original
- Xauthors' reputations.
- X
- X Finally, any free program is threatened constantly by software
- Xpatents. We wish to avoid the danger that redistributors of a free
- Xprogram will individually obtain patent licenses, in effect making the
- Xprogram proprietary. To prevent this, we have made it clear that any
- Xpatent must be licensed for everyone's free use or not licensed at all.
- X
- X The precise terms and conditions for copying, distribution and
- Xmodification follow.
- X
- X GNU GENERAL PUBLIC LICENSE
- X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- X
- X 0. This License applies to any program or other work which contains
- Xa notice placed by the copyright holder saying it may be distributed
- Xunder the terms of this General Public License. The "Program", below,
- Xrefers to any such program or work, and a "work based on the Program"
- Xmeans either the Program or any derivative work under copyright law:
- Xthat is to say, a work containing the Program or a portion of it,
- Xeither verbatim or with modifications and/or translated into another
- Xlanguage. (Hereinafter, translation is included without limitation in
- Xthe term "modification".) Each licensee is addressed as "you".
- X
- XActivities other than copying, distribution and modification are not
- Xcovered by this License; they are outside its scope. The act of
- Xrunning the Program is not restricted, and the output from the Program
- Xis covered only if its contents constitute a work based on the
- XProgram (independent of having been made by running the Program).
- XWhether that is true depends on what the Program does.
- X
- X 1. You may copy and distribute verbatim copies of the Program's
- Xsource code as you receive it, in any medium, provided that you
- Xconspicuously and appropriately publish on each copy an appropriate
- Xcopyright notice and disclaimer of warranty; keep intact all the
- Xnotices that refer to this License and to the absence of any warranty;
- Xand give any other recipients of the Program a copy of this License
- Xalong with the Program.
- X
- XYou may charge a fee for the physical act of transferring a copy, and
- Xyou may at your option offer warranty protection in exchange for a fee.
- X
- X 2. You may modify your copy or copies of the Program or any portion
- Xof it, thus forming a work based on the Program, and copy and
- Xdistribute such modifications or work under the terms of Section 1
- Xabove, provided that you also meet all of these conditions:
- X
- X a) You must cause the modified files to carry prominent notices
- X stating that you changed the files and the date of any change.
- X
- X b) You must cause any work that you distribute or publish, that in
- X whole or in part contains or is derived from the Program or any
- X part thereof, to be licensed as a whole at no charge to all third
- X parties under the terms of this License.
- X
- X c) If the modified program normally reads commands interactively
- X when run, you must cause it, when started running for such
- X interactive use in the most ordinary way, to print or display an
- X announcement including an appropriate copyright notice and a
- X notice that there is no warranty (or else, saying that you provide
- X a warranty) and that users may redistribute the program under
- X these conditions, and telling the user how to view a copy of this
- X License. (Exception: if the Program itself is interactive but
- X does not normally print such an announcement, your work based on
- X the Program is not required to print an announcement.)
- X
- XThese requirements apply to the modified work as a whole. If
- Xidentifiable sections of that work are not derived from the Program,
- Xand can be reasonably considered independent and separate works in
- Xthemselves, then this License, and its terms, do not apply to those
- Xsections when you distribute them as separate works. But when you
- Xdistribute the same sections as part of a whole which is a work based
- Xon the Program, the distribution of the whole must be on the terms of
- Xthis License, whose permissions for other licensees extend to the
- Xentire whole, and thus to each and every part regardless of who wrote it.
- X
- XThus, it is not the intent of this section to claim rights or contest
- Xyour rights to work written entirely by you; rather, the intent is to
- Xexercise the right to control the distribution of derivative or
- Xcollective works based on the Program.
- X
- XIn addition, mere aggregation of another work not based on the Program
- Xwith the Program (or with a work based on the Program) on a volume of
- Xa storage or distribution medium does not bring the other work under
- Xthe scope of this License.
- X
- X 3. You may copy and distribute the Program (or a work based on it,
- Xunder Section 2) in object code or executable form under the terms of
- XSections 1 and 2 above provided that you also do one of the following:
- X
- X a) Accompany it with the complete corresponding machine-readable
- X source code, which must be distributed under the terms of Sections
- X 1 and 2 above on a medium customarily used for software interchange; or,
- X
- X b) Accompany it with a written offer, valid for at least three
- X years, to give any third party, for a charge no more than your
- X cost of physically performing source distribution, a complete
- X machine-readable copy of the corresponding source code, to be
- X distributed under the terms of Sections 1 and 2 above on a medium
- X customarily used for software interchange; or,
- X
- X c) Accompany it with the information you received as to the offer
- X to distribute corresponding source code. (This alternative is
- X allowed only for noncommercial distribution and only if you
- X received the program in object code or executable form with such
- X an offer, in accord with Subsection b above.)
- X
- XThe source code for a work means the preferred form of the work for
- Xmaking modifications to it. For an executable work, complete source
- Xcode means all the source code for all modules it contains, plus any
- Xassociated interface definition files, plus the scripts used to
- Xcontrol compilation and installation of the executable. However, as a
- Xspecial exception, the source code distributed need not include
- Xanything that is normally distributed (in either source or binary
- Xform) with the major components (compiler, kernel, and so on) of the
- Xoperating system on which the executable runs, unless that component
- Xitself accompanies the executable.
- X
- XIf distribution of executable or object code is made by offering
- Xaccess to copy from a designated place, then offering equivalent
- Xaccess to copy the source code from the same place counts as
- Xdistribution of the source code, even though third parties are not
- Xcompelled to copy the source along with the object code.
- X
- X 4. You may not copy, modify, sublicense, or distribute the Program
- Xexcept as expressly provided under this License. Any attempt
- Xotherwise to copy, modify, sublicense or distribute the Program is
- Xvoid, and will automatically terminate your rights under this License.
- XHowever, parties who have received copies, or rights, from you under
- Xthis License will not have their licenses terminated so long as such
- Xparties remain in full compliance.
- X
- X 5. You are not required to accept this License, since you have not
- Xsigned it. However, nothing else grants you permission to modify or
- Xdistribute the Program or its derivative works. These actions are
- Xprohibited by law if you do not accept this License. Therefore, by
- Xmodifying or distributing the Program (or any work based on the
- XProgram), you indicate your acceptance of this License to do so, and
- Xall its terms and conditions for copying, distributing or modifying
- Xthe Program or works based on it.
- X
- X 6. Each time you redistribute the Program (or any work based on the
- XProgram), the recipient automatically receives a license from the
- Xoriginal licensor to copy, distribute or modify the Program subject to
- Xthese terms and conditions. You may not impose any further
- Xrestrictions on the recipients' exercise of the rights granted herein.
- XYou are not responsible for enforcing compliance by third parties to
- Xthis License.
- X
- X 7. If, as a consequence of a court judgment or allegation of patent
- Xinfringement or for any other reason (not limited to patent issues),
- Xconditions are imposed on you (whether by court order, agreement or
- Xotherwise) that contradict the conditions of this License, they do not
- Xexcuse you from the conditions of this License. If you cannot
- Xdistribute so as to satisfy simultaneously your obligations under this
- XLicense and any other pertinent obligations, then as a consequence you
- Xmay not distribute the Program at all. For example, if a patent
- Xlicense would not permit royalty-free redistribution of the Program by
- Xall those who receive copies directly or indirectly through you, then
- Xthe only way you could satisfy both it and this License would be to
- Xrefrain entirely from distribution of the Program.
- X
- XIf any portion of this section is held invalid or unenforceable under
- Xany particular circumstance, the balance of the section is intended to
- Xapply and the section as a whole is intended to apply in other
- Xcircumstances.
- X
- XIt is not the purpose of this section to induce you to infringe any
- Xpatents or other property right claims or to contest validity of any
- Xsuch claims; this section has the sole purpose of protecting the
- Xintegrity of the free software distribution system, which is
- Ximplemented by public license practices. Many people have made
- Xgenerous contributions to the wide range of software distributed
- Xthrough that system in reliance on consistent application of that
- Xsystem; it is up to the author/donor to decide if he or she is willing
- Xto distribute software through any other system and a licensee cannot
- Ximpose that choice.
- X
- XThis section is intended to make thoroughly clear what is believed to
- Xbe a consequence of the rest of this License.
- X
- X 8. If the distribution and/or use of the Program is restricted in
- Xcertain countries either by patents or by copyrighted interfaces, the
- Xoriginal copyright holder who places the Program under this License
- Xmay add an explicit geographical distribution limitation excluding
- Xthose countries, so that distribution is permitted only in or among
- Xcountries not thus excluded. In such case, this License incorporates
- Xthe limitation as if written in the body of this License.
- X
- X 9. The Free Software Foundation may publish revised and/or new versions
- Xof the General Public License from time to time. Such new versions will
- Xbe similar in spirit to the present version, but may differ in detail to
- Xaddress new problems or concerns.
- X
- XEach version is given a distinguishing version number. If the Program
- Xspecifies a version number of this License which applies to it and "any
- Xlater version", you have the option of following the terms and conditions
- Xeither of that version or of any later version published by the Free
- XSoftware Foundation. If the Program does not specify a version number of
- Xthis License, you may choose any version ever published by the Free Software
- XFoundation.
- X
- X 10. If you wish to incorporate parts of the Program into other free
- Xprograms whose distribution conditions are different, write to the author
- Xto ask for permission. For software which is copyrighted by the Free
- XSoftware Foundation, write to the Free Software Foundation; we sometimes
- Xmake exceptions for this. Our decision will be guided by the two goals
- Xof preserving the free status of all derivatives of our free software and
- Xof promoting the sharing and reuse of software generally.
- X
- X NO WARRANTY
- X
- X 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
- XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
- XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
- XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
- XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
- XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
- XREPAIR OR CORRECTION.
- X
- X 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
- XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
- XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
- XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
- XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- XPOSSIBILITY OF SUCH DAMAGES.
- X
- X END OF TERMS AND CONDITIONS
- X
- X Appendix: How to Apply These Terms to Your New Programs
- X
- X If you develop a new program, and you want it to be of the greatest
- Xpossible use to the public, the best way to achieve this is to make it
- Xfree software which everyone can redistribute and change under these terms.
- X
- X To do so, attach the following notices to the program. It is safest
- Xto attach them to the start of each source file to most effectively
- Xconvey the exclusion of warranty; and each file should have at least
- Xthe "copyright" line and a pointer to where the full notice is found.
- X
- X <one line to give the program's name and a brief idea of what it does.>
- X Copyright (C) 19yy <name of author>
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 2 of the License, or
- X (at your option) any later version.
- 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 GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- X
- XAlso add information on how to contact you by electronic and paper mail.
- X
- XIf the program is interactive, make it output a short notice like this
- Xwhen it starts in an interactive mode:
- X
- X Gnomovision version 69, Copyright (C) 19yy name of author
- X Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- X This is free software, and you are welcome to redistribute it
- X under certain conditions; type `show c' for details.
- X
- XThe hypothetical commands `show w' and `show c' should show the appropriate
- Xparts of the General Public License. Of course, the commands you use may
- Xbe called something other than `show w' and `show c'; they could even be
- Xmouse-clicks or menu items--whatever suits your program.
- X
- XYou should also get your employer (if you work as a programmer) or your
- Xschool, if any, to sign a "copyright disclaimer" for the program, if
- Xnecessary. Here is a sample; alter the names:
- X
- X Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- X `Gnomovision' (which makes passes at compilers) written by James Hacker.
- X
- X <signature of Ty Coon>, 1 April 1989
- X Ty Coon, President of Vice
- X
- XThis General Public License does not permit incorporating your program into
- Xproprietary programs. If your program is a subroutine library, you may
- Xconsider it more useful to permit linking proprietary applications with the
- Xlibrary. If this is what you want to do, use the GNU Library General
- XPublic License instead of this License.
- X
- END_OF_FILE
- if test 18090 -ne `wc -c <'Copying'`; then
- echo shar: \"'Copying'\" unpacked with wrong size!
- fi
- # end of 'Copying'
- fi
- if test -f 'agent/magent.SH' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/magent.SH'\"
- else
- echo shar: Extracting \"'agent/magent.SH'\" \(18483 characters\)
- sed "s/^X//" >'agent/magent.SH' <<'END_OF_FILE'
- Xcase $CONFIG in
- X'')
- X if test ! -f config.sh; then
- X ln ../config.sh . || \
- X ln ../../config.sh . || \
- X ln ../../../config.sh . || \
- X (echo "Can't find config.sh."; exit 1)
- X fi 2>/dev/null
- X . config.sh
- X ;;
- Xesac
- Xcase "$0" in
- X*/*) cd `expr X$0 : 'X\(.*\)/'` ;;
- Xesac
- Xecho "Extracting agent/magent (with variable substitutions)"
- X$spitshell >magent <<!GROK!THIS!
- X# feed this into perl
- X eval 'exec perl -S \$0 "\$@"'
- X if \$running_under_some_shell;
- X
- X# You'll need to set up a .forward file that feeds your mail to this script,
- X# via the filter. Mine looks like this:
- X# "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
- X
- X# $Id: magent.SH,v 2.9.1.2 92/08/26 12:41:27 ram Exp $
- X#
- X# Copyright (c) 1991, 1992, Raphael Manfredi
- X#
- X# You may redistribute only under the terms of the GNU General Public
- X# Licence as specified in the README file that comes with dist.
- X#
- X# $Log: magent.SH,v $
- X# Revision 2.9.1.2 92/08/26 12:41:27 ram
- X# patch8: better no-lock handling
- X# patch8: now maintains the notion of private library directory
- X# patch8: job number computation code moved to library
- X# patch8: added persisted variable handling
- X# patch8: added mailhook and interface functions with filtering actions
- X#
- X# Revision 2.9.1.1 92/08/02 15:53:40 ram
- X# patch2: added undocumented -TEST flag to skip queue processing
- X# patch2: eval_error now returns 1 if error was detected
- X#
- X# Revision 2.9 92/07/14 16:48:48 ram
- X# 3.0 beta baseline.
- X#
- X
- X# Perload ON
- X
- X# The following were determined by Configure
- X\$phostname = '$phostname'; # Command used to compute hostname
- X\$mydomain = '$mydomain'; # Our domain name
- X\$hiddennet = '$hiddennet'; # Hidden network (advertised host)
- X\$maildir = '$maildir'; # Directory where mail is spooled
- X\$mailfile = '$mailfile'; # File in which mail is stored
- X\$mversion = '$VERSION'; # Current version number
- X\$patchlevel = '$PATCHLEVEL'; # And patchlevel from patchlevel.h
- X\$lock_by_flock = '$lock_by_flock'; # Want to lock mailboxes with flock ?
- X\$flock_only = '$flock_only'; # Only use flock() and no .lock file
- X\$orgname = '$orgname'; # Our organization name
- X\$privlib = '$privlib'; # Private mailagent library
- X\$inews = '$inews';
- X!GROK!THIS!
- X
- X$spitshell >>magent <<'!NO!SUBS!'
- X
- X$prog_name = $0; # Who I am
- X$prog_name =~ s|^.*/(.*)|$1|; # Keep only base name
- X$has_option = 0; # True if invoked with options
- X$nolock = 0; # Do we need to get a lock file?
- X$config_file = '~/.mailagent'; # Default configuration file
- X$log_level = -1; # Changed by -L option
- X
- X# Calling the mailagent as 'mailqueue' lists the queue
- Xif ($prog_name eq 'mailqueue') {
- X ++$list_queue;
- X ++$has_option;
- X}
- X
- X# Parse options
- Xwhile ($ARGV[0] =~ /^-/) {
- X $_ = shift;
- X last if /--/;
- X if ($_ eq '-c') { # Specify alternate configuration file
- X ++$nolock; # Immediate processing wanted
- X $config_file = shift;
- X }
- X elsif ($_ eq '-d') { # Dump rules
- X ++$has_option; # Incompatible with other special options
- X ++$dump_rule;
- X }
- X elsif ($_ eq '-e') { # Rule supplied on command line
- X local($*) = 1;
- X $_ = shift;
- X s/\n/ /g;
- X push(@Linerules, $_);
- X ++$edited_rules; # Signals rules came from command line
- X ++$nolock; # Immediate processing wanted
- X }
- X elsif ($_ eq '-f') { # Take messages from UNIX mailbox
- X ++$nolock; # Immediate processing wanted
- X ++$mbox_mail;
- X $mbox_file = shift; # -f followed by file name
- X }
- X elsif ($_ eq '-h') { # Usage help
- X &usage;
- X }
- X elsif ($_ eq '-i') { # Interactive mode: log messages also on stderr
- X *add_log = *stderr_log;
- X }
- X elsif ($_ eq '-l') { # List queue
- X ++$has_option; # Incompatible with other special options
- X ++$list_queue;
- X ++$norule; # No need to compile rules
- X }
- X elsif ($_ eq '-o') { # Overwrite configuration variable
- X ++$nolock; # Immediate processing wanted
- X $over_config .= "\n" . shift;
- X }
- X elsif ($_ eq '-q') { # Process the queue
- X ++$has_option; # Incompatible with other special options
- X ++$run_queue;
- X }
- X elsif ($_ eq '-r') { # Specify alternate rule file
- X ++$nolock; # Immediate processing wanted
- X $rule_file = shift;
- X }
- X elsif (/^-s(\S*)/) { # Print statistics
- X ++$has_option; # Incompatible with other special options
- X ++$stats;
- X ++$norule; # No need to compile rules
- X $stats_opt = $1;
- X }
- X elsif ($_ eq '-t') { # Track rule matches on stdout
- X ++$track_all;
- X }
- X elsif ($_ eq '-L') { # Specify new logging level
- X $log_level = int(shift);
- X }
- X elsif ($_ eq '-V') { # Version number
- X print STDERR "$prog_name $mversion PL$patchlevel\n";
- X exit 0;
- X }
- X elsif ($_ eq '-TEST') { # Mailagent run via TEST (undocumented feature)
- X ++$test_mode;
- X }
- X else {
- X print STDERR "$prog_name: unknown option: $_\n";
- X &usage;
- X }
- X}
- X
- X++$nolock if $has_option; # No need to take a lock with special options
- X
- X# Only one option at a time (among those options which change our goal)
- Xif ($has_option > 1) {
- X print STDERR "$prog_name: at most one special option may be specified.\n";
- X exit 1;
- X}
- X
- X$file_name = shift; # File name to be processed (null if stdin)
- X$ENV{'IFS'}='' if $ENV{'IFS'}; # Shell separation field
- X&get_configuration; # Get a suitable configuration package (cf)
- Xselect(STDOUT); # Because the -t option writes on STDOUT,
- X$| = 1; # make sure it is flushed before we fork()
- X$agent_wait = "agent.wait"; # Waiting file for out-of-the-queue mails
- X$privlib = "$cf'home/../.." if $test_mode; # Tests ran from test/out
- X
- Xif ($orgname =~ m|^/|) { # Name of organization kept in file
- X unless (open(ORG, $orgname)) {
- X &add_log("ERROR cannot read $orgname") if $loglvl;
- X } else {
- X chop($orgname = <ORG>);
- X close ORG;
- X }
- X}
- X
- X$ENV{'HOME'} = $cf'home;
- X$ENV{'USER'} = $cf'user;
- X$ENV{'NAME'} = $cf'name;
- X$baselock = "$cf'spool/perl"; # This file does not exist
- X$lockext = ".lock"; # Extension used by lock routines
- X$lockfile = $baselock . $lockext;
- X
- Xumask(077); # Files we create are private ones
- X$jobnum = &jobnum; # Compute a job number
- X
- X# Allow only ONE mailagent at a time (resource consumming)
- Xdo checklock($baselock); # Make sure old locks do not remain
- Xunless (-f $lockfile) {
- X # Try to get the lock file (acting as a token). We do not need locking if
- X # we have been invoked with an option and that option is not -q.
- X if ($nolock && !$run_queue) {
- X &add_log("no need to get a lock") if $loglvl > 19;
- X } elsif (0 == &acs_rqst($baselock)) {
- X &add_log("got the right to process mail") if $loglvl > 19;
- X ++$locked;
- X } else {
- X &add_log("denied right to process mail") if $loglvl > 19;
- X }
- X}
- X
- Xif (!$locked && !$nolock) {
- X # Another mailagent is running somewhere
- X &queue_mail($file_name);
- X exit 0;
- X}
- X
- X# Initialize mail filtering and compile filter rule if necessary
- X&init_all;
- X&compile_rules unless $norule;
- X
- X# If rules are to be dumped, this is the only action
- Xif ($dump_rule) {
- X &dump_rules(*print_rule_number, *void_func);
- X unlink $lockfile if $locked;
- X exit 0;
- X}
- X
- X# Likewise, statistics dumping is the only option
- Xif ($stats) {
- X &report_stats($stats_opt);
- X unlink $lockfile if $locked;
- X exit 0;
- X}
- X
- X# Listing the queue is also the only performed action
- Xif ($list_queue) {
- X &list_queue;
- X unlink $lockfile if $locked;
- X exit 0;
- X}
- X
- X# Taking messages from mailbox file
- Xif ($mbox_mail) {
- X ++$run_queue if 0 == &mbox_mail($mbox_file);
- X unless ($run_queue) {
- X unlink $lockfile if $locked;
- X exit 1; # -f failed
- X }
- X &add_log("processing queued mails") if $loglvl > 15;
- X}
- X
- X# Suppress statistics when mailagent invoked manually (in not in test mode)
- X&no_stats if $nolock && !$test_mode;
- X
- X&read_stats; # Get statistics, so that we may update them in memory
- X
- Xif (!$run_queue) { # Do not enter here if -q
- X if (0 != &analyze_mail($file_name)) { # Analyze the mail
- X do add_log("ERROR while processing main message--queing it")
- X if ($loglvl > 0);
- X do queue_mail($file_name);
- X unlink $lockfile;
- X exit 0; # Do not continue
- X } else {
- X $file = $file_name; # Never corrupt $file_name
- X $file =~ s|.*/(.*)|$1|; # Keep only basename
- X $file = "<stdin>" if $file eq '';
- X do add_log("FILTERED [$file] $Header{'Length'} bytes") if $loglvl > 4;
- X }
- X}
- X
- Xunless ($test_mode) {
- X # Fork a child: we have to take care of the filter script which is waiting
- X # for us to finish processing of the delivered mail.
- X &fork_child() unless $run_queue;
- X
- X # From now on, we are in the child process... Don't sleep at all if logging
- X # level is greater that 11 or if $run_queue is true. Logging level of 12
- X # and higher are for debugging and should not be used on a permanent basis
- X # anyway.
- X
- X $sleep = 1; # Give others a chance to queue their mail
- X $sleep = 0 if $loglvl > 11 || $run_queue;
- X
- X while (&pqueue) { # Eventually process the queue
- X sleep 30 if $sleep; # Wait in case new mail arrives
- X }
- X} else {
- X &pqueue; # Process the queue once in test mode
- X}
- X
- X# End of mailagent processing
- X&write_stats; # Resynchronizes the statistics file
- X&contextual_operations; # Perform all the contextual operations
- X&add_log("mailagent exits") if $loglvl > 17;
- Xunlink $lockfile if $locked;
- Xexit 0;
- X
- X# Print usage and exit
- Xsub usage {
- X print STDERR <<EOF;
- XUsage: $prog_name [-dhilqtV] [-s{umary}] [-f file] [-e rules] [-c config]
- X [-L level] [-r file] [-o def] [mailfile]
- X -c : specify alternate configuration file.
- X -d : dump filter rules (special).
- X -e : enter rules to be applied.
- X -f : get messages from UNIX-style mailbox file.
- X -h : print this help message and exits.
- X -i : interactive usage -- print log messages on stderr.
- X -l : list message queue (special).
- X -L : force logging level.
- X -o : overwrite config file with supplied definition.
- X -q : process the queue (special).
- X -r : sepcify alternate rule file.
- X -s : report gathered statistics (special).
- X -t : track rules on stdout.
- X -V : print version number and exits.
- XEOF
- X exit 1;
- X}
- X
- X# Read configuration file and alter it with the values specified via -o.
- X# Then apply -r and -t by modifying suitable configuration parameters.
- Xsub get_configuration {
- X &read_config($config_file); # Read configuration file and set vars
- X &cf'parse($over_config); # Overwrite with command line options
- X $cf'rules = $rule_file if $rule_file; # -r overwrites rule file
- X $loglvl = $log_level if $log_level >= 0; # -L overwrites logging level
- X}
- X
- X#
- X# The filtering routines
- X#
- X
- X# Start-up initializations
- Xsub init_all {
- X do init_signals(); # Trap common signals
- X do init_constants(); # Constants definitions
- X do init_interpreter(); # Initialize tables %Priority, %Function, ...
- X do init_env(); # Initialize the %XENV array
- X do init_matcher(); # Initialize special matching functions
- X do init_pseudokey(); # Initialize the pseudo header keys for H table
- X do init_builtins(); # Initialize built-in commands like @RR
- X do init_filter(); # Initialize filter commands
- X do init_special(); # Initialize special user table %Special
- X}
- X
- X# Protect ourselves (trap common signals)
- Xsub init_signals {
- X $SIG{'HUP'} = 'emergency';
- X $SIG{'INT'} = 'emergency';
- X $SIG{'QUIT'} = 'emergency';
- X $SIG{'PIPE'} = 'emergency';
- X $SIG{'IO'} = 'emergency';
- X $SIG{'BUS'} = 'emergency';
- X $SIG{'ILL'} = 'emergency';
- X $SIG{'SEGV'} = 'emergency';
- X $SIG{'ALRM'} = 'emergency';
- X $SIG{'TERM'} = 'emergency';
- X}
- X
- X# Constants definitions
- Xsub init_constants {
- X require 'ctime.pl';
- X # Values for flock(), usually in <sys/file.h>
- X $LOCK_SH = 1; # Request a shared lock on file
- X $LOCK_EX = 2; # Request an exclusive lock
- X $LOCK_NB = 4; # Make a non-blocking lock request
- X $LOCK_UN = 8; # Unlock the file
- X
- X # Status used by filter
- X $FT_RESTART = 0; # Abort current action, restart from scratch
- X $FT_CONT = 1; # Continue execution
- X $FT_REJECT = 2; # Abort current action, continue filtering
- X $FT_ABORT = 3; # Abort filtering process
- X
- X # Shall we append or remove folder?
- X $FOLDER_APPEND = 0; # Append in folder
- X $FOLDER_REMOVE = 1; # Remove folder
- X
- X # Used by shell_command and children
- X $NO_INPUT = 0; # No input (stdin is closed)
- X $BODY_INPUT = 1; # Give body of mail as stdin
- X $MAIL_INPUT = 2; # Pipe the whole mail
- X $HEADER_INPUT = 3; # Pipe the header only
- X $NO_FEEDBACK = 0; # No feedback wanted
- X $FEEDBACK = 1; # Feed result of command back into %Header
- X
- X # The filter message
- X local($address) = &email_addr;
- X $FILTER =
- X "X-Filter: mailagent [version $mversion PL$patchlevel] for $address";
- X
- X # For header fields alteration
- X $HD_STRIP = 0; # Strip header fields
- X $HD_KEEP = 1; # Keep header fields
- X
- X # Faked leading From line (used for digest items, by SPLIT)
- X local($now) = &ctime(time);
- X chop($now);
- X $FAKE_FROM = "From mailagent " . $now;
- X}
- X
- X# Initializes environment. All the variables are initialized in XENV array
- X# The sole purpose of XENV is to be able to know what changes wrt the invoking
- X# environment when dumping the rules. It also avoid modifying the environment
- X# for our children.
- Xsub init_env {
- X foreach (keys(%ENV)) {
- X $XENV{$_} = $ENV{$_};
- X }
- X}
- X
- X# List of special header keys which do not represent a true header field.
- Xsub init_pseudokey {
- X %Pseudokey = (
- X 'Body', 1,
- X 'Head', 1,
- X 'All', 1
- X );
- X}
- X
- X#
- X# Miscellaneous utilities
- X#
- X
- X# Attempts a mailbox locking. The argument is the name of the file, the file
- X# descriptor is the global MBOX, opened for appending.
- Xsub mbox_lock {
- X local($file) = @_; # File name
- X unless ($flock_only) { # Lock with .lock
- X if (0 != &acs_rqst($file)) {
- X do add_log("WARNING could not lock $file") if $loglvl > 5;
- X }
- X }
- X # Make sure the file is still there and as not been removed while we were
- X # waiting for the lock (in which case our MBOX file descriptor would be
- X # useless: we would write in a ghost file!). This could happen when 'elm'
- X # (or other mail user agent) resynchronizes the mailbox.
- X close MBOX;
- X if (open(MBOX, ">>$file")) {
- X if ($lock_by_flock) {
- X unless (eval 'flock(MBOX, $LOCK_EX)') { # Ask for exclusive lock
- X do add_log("WARNING could not flock $file: $!") if $loglvl > 5;
- X }
- X }
- X } else {
- X do fatal("could not reopen $file");
- X }
- X seek(MBOX, 0, 2); # Someone may have appended something
- X}
- X
- X# Remove lock on mailbox
- Xsub mbox_unlock {
- X local($file) = @_; # File name
- X close MBOX; # Closing will remove flock lock
- X &free_file($file) unless $flock_only; # Remove the .lock
- X}
- X
- X# Computes the e-mail address of the user
- Xsub email_addr {
- X $cf'user . '@' . &domain_addr; # E-mail address in internet format
- X}
- X
- X# Domain name address for current host
- Xsub domain_addr {
- X local($_); # Our host name
- X $_ = $hiddennet if $hiddennet ne '';
- X if ($_ eq '') {
- X chop($_ = `$phostname`); # Must fork to get hostname, grr...
- X $_ .= $mydomain unless /\./; # We want something fully qualified
- X }
- X $_;
- X}
- X
- X# Compute the system mailbox file name
- Xsub mailbox_name {
- X # If ~/.mailagent provides us with a mail directory, use it and possibly
- X # override value computed by Configure.
- X $maildir = $cf'maildrop if $cf'maildrop ne '';
- X # If Configure gave a valid 'maildir', use it. Otherwise compute one now.
- X unless ($maildir ne '' && -d "$maildir") {
- X $maildir = "/usr/spool/mail"; # Default spooling area
- X -d "/usr/mail" && ($maildir = "/usr/mail");
- X -d "$maildir" || ($maildir = "$cf'home");
- X }
- X local($mbox) = $cf'user; # Default mailbox file name
- X $mbox = $cf'mailbox if $cf'mailbox ne ''; # Priority to config variable
- X $mailbox = "$maildir/$mbox"; # Full mailbox path
- X if (! -f "$mailbox" && ! -w "$maildir") {
- X # No mailbox already exists and we can't write in the spool directory.
- X # Use mailfile then, and if we can't write in the directory and the
- X # mail file does not exist either, use ~/mbox.$cf'user as mailbox.
- X $mailbox = $mailfile; # Determined by configure (%~ and %L form)
- X $mailbox =~ s/%~/$cf'home/go; # %~ stands for the user directory
- X $mailbox =~ s/%L/$cf'user/go; # %L stands for the user login name
- X $mailbox =~ m|(.*)/.*|; # Extract dirname
- X $mailbox = "$cf'home/mbox.$cf'user" unless (-f "mailbox" || -w "$1");
- X do add_log("WARNING using $mailbox for mailbox") if $loglvl > 5;
- X }
- X $mailbox;
- X}
- X
- X# Fork a new mailagent and update the pid in the perl.lock file. The parent
- X# then exits and the child continues. This enables the filter which invoked
- X# us to finally exit.
- Xsub fork_child {
- X local($pid) = fork;
- X if ($pid == -1) { # We cannot fork, exit.
- X do add_log("ERROR couldn't fork to process the queue") if $loglvl > 5;
- X unlink $lockfile if $locked;
- X exit 0;
- X } elsif ($pid == 0) { # The child process
- X # Update the pid in the perl.lock file, so that any process which will
- X # use the kill(pid, 0) feature to check whether we are alive or not will
- X # get a meaningful status.
- X if ($locked) {
- X chmod 0644, $lockfile;
- X open(LOCK, ">$lockfile"); # Ignore errors
- X chmod 0444, $lockfile; # Now it's open, so we may restore mode
- X print LOCK "$$\n"; # Write child's PID
- X close LOCK;
- X }
- X sleep(2); # Give filter time to clean up
- X } else { # Parent process
- X exit 0; # Exit without removing lock, of course
- X }
- X # Only the child comes here and returns
- X do add_log("mailagent continues") if $loglvl > 17;
- X}
- X
- X# Report any eval error and returns 1 if error detected.
- Xsub eval_error {
- X if ($@ ne '') {
- X $@ =~ s/ in file \(eval\) at line \d+//;
- X chop($@);
- X &add_log("ERROR $@") if $loglvl > 1;
- X }
- X $@ eq '' ? 0 : 1;
- X}
- X
- X!NO!SUBS!
- X$grep -v '^;#' pl/jobnum.pl >>magent
- X$grep -v '^;#' pl/read_conf.pl >>magent
- X$grep -v '^;#' pl/acs_rqst.pl >>magent
- X$grep -v '^;#' pl/free_file.pl >>magent
- X$grep -v '^;#' pl/add_log.pl >>magent
- X$grep -v '^;#' pl/checklock.pl >>magent
- X$grep -v '^;#' pl/lexical.pl >>magent
- X$grep -v '^;#' pl/parse.pl >>magent
- X$grep -v '^;#' pl/analyze.pl >>magent
- X$grep -v '^;#' pl/runcmd.pl >>magent
- X$grep -v '^;#' pl/filter.pl >>magent
- X$grep -v '^;#' pl/matching.pl >>magent
- X$grep -v '^;#' pl/locate.pl >>magent
- X$grep -v '^;#' pl/rfc822.pl >>magent
- X$grep -v '^;#' pl/macros.pl >>magent
- X$grep -v '^;#' pl/header.pl >>magent
- X$grep -v '^;#' pl/actions.pl >>magent
- X$grep -v '^;#' pl/stats.pl >>magent
- X$grep -v '^;#' pl/queue_mail.pl >>magent
- X$grep -v '^;#' pl/pqueue.pl >>magent
- X$grep -v '^;#' pl/builtins.pl >>magent
- X$grep -v '^;#' pl/rules.pl >>magent
- X$grep -v '^;#' pl/period.pl >>magent
- X$grep -v '^;#' pl/eval.pl >>magent
- X$grep -v '^;#' pl/dbr.pl >>magent
- X$grep -v '^;#' pl/history.pl >>magent
- X$grep -v '^;#' pl/once.pl >>magent
- X$grep -v '^;#' pl/makedir.pl >>magent
- X$grep -v '^;#' pl/emergency.pl >>magent
- X$grep -v '^;#' pl/listqueue.pl >>magent
- X$grep -v '^;#' pl/mbox.pl >>magent
- X$grep -v '^;#' pl/context.pl >>magent
- X$grep -v '^;#' pl/extern.pl >>magent
- X$grep -v '^;#' pl/mailhook.pl >>magent
- X$grep -v '^;#' pl/interface.pl >>magent
- X$grep -v '^;#' pl/getdate.pl >>magent
- Xchmod 755 magent
- X$eunicefix magent
- END_OF_FILE
- if test 18483 -ne `wc -c <'agent/magent.SH'`; then
- echo shar: \"'agent/magent.SH'\" unpacked with wrong size!
- fi
- chmod +x 'agent/magent.SH'
- # end of 'agent/magent.SH'
- fi
- if test -f 'agent/pl/analyze.pl' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/pl/analyze.pl'\"
- else
- echo shar: Extracting \"'agent/pl/analyze.pl'\" \(13269 characters\)
- sed "s/^X//" >'agent/pl/analyze.pl' <<'END_OF_FILE'
- X;# $Id: analyze.pl,v 2.9.1.4 92/11/01 15:45:26 ram Exp $
- X;#
- X;# Copyright (c) 1992, Raphael Manfredi
- X;#
- X;# You may redistribute only under the terms of the GNU General Public
- X;# Licence as specified in the README file that comes with dist.
- X;#
- X;# $Log: analyze.pl,v $
- X;# Revision 2.9.1.4 92/11/01 15:45:26 ram
- X;# patch11: added some blank lines for easier reading
- X;#
- X;# Revision 2.9.1.3 92/08/26 13:08:27 ram
- X;# patch8: parsing code moved to a separate library file
- X;#
- X;# Revision 2.9.1.2 92/08/02 16:08:39 ram
- X;# patch2: added support for negated selectors
- X;# patch2: header field names are now case-normalized (to or TO -> To)
- X;#
- X;# Revision 2.9.1.1 92/07/25 12:37:06 ram
- X;# patch1: did not correctly escape first From line within body
- X;#
- X;# Revision 2.9 92/07/14 16:49:36 ram
- X;# 3.0 beta baseline.
- X;#
- X;#
- X#
- X# Analyzing mail
- X#
- X
- X# Special users. Note that as login name matches are done in a case-insensitive
- X# manner, there is no need to upper-case any of the followings.
- Xsub init_special {
- X %Special = (
- X 'root', 1, # Super-user
- X 'uucp', 1, # Unix to Unix copy
- X 'daemon', 1, # Not a real user, hopefully
- X 'news', 1, # News daemon
- X 'postmaster', 1, # X-400 mailer-daemon name
- X 'newsmaster', 1, # My convention for news administrator--RAM
- X 'usenet', 1, # Aka newsmaster
- X 'mailer-daemon', 1, # Sendmail
- X 'nobody', 1 # Nobody we've heard of
- X );
- X}
- X
- X# Initialize global variables, before analyzing each mail
- Xsub init_global_state {
- X undef %Variable; # User-defined variables
- X}
- X
- X# This is the heart of the mail agent
- X# Scan the message in $file_name and apply the filtering rules
- Xsub analyze_mail {
- X local($file) = shift(@_); # Mail file to be parsed
- X local($mode); # Mode (optional)
- X local($wmode)= "INITIAL"; # Working mode (the mode we are in)
- X local($selector); # Selector (mandatory)
- X local($rulentry); # Entry in rule H table
- X local($pattern); # Pattern for selection, as written in rules
- X local($action); # Related action
- X local($last_selector); # Last used selector
- X local($rules); # A copy of the rules
- X local($matched); # Flag set to true if a rule is matched
- X local(%Matched); # Records the selectors which have been matched
- X local($header); # Header entry name to look for in Header table
- X local($status); # Status returned by xeqte
- X local($ever_matched) = 0; # Did we ever matched a single saving rule ?
- X local($ever_saved) = 0; # Did we ever saved a message ?
- X local($ever_seen) = 0; # Did we ever enter seen mode ?
- X local($vacation) = 1; # Vacation message allowed a priori
- X local(@Executed); # Records already executed rules
- X local($selist); # Key used to detect identical selector lists
- X local(%Inverted); # Records inverted '!' selectors which matched
- X
- X # First parse the mail and fill in the %Header table
- X
- X &init_global_state; # Initializes global variables
- X &parse_mail($file); # Parse the mail and fill-in H tables
- X return 0 unless defined $Header{'All'};
- X &reception if $loglvl > 8; # Log mail reception
- X &run_builtins; # Execute builtins, if any were found
- X
- X # Now analyze the mail. If there is already a X-Filter header, then the
- X # mail has already been processed. In that case, the default action is
- X # performed: leave it in the incomming mailbox with no further action.
- X # This should prevent nasty loops.
- X
- X do add_log ("analyzing mail") if $loglvl > 18;
- X $header = $Header{'X-Filter'}; # Mulitple occurences possible
- X if ($header ne '') { # Hmm... already filtered...
- X local(@filter) = split(/\n/, $header); # Look for each X-Filter
- X local($address) = &email_addr; # Our e-mail address
- X local($done) = 0; # Already processed ?
- X foreach (@filter) { # Maybe we'll find ourselves
- X if (/mailagent.*for (\S+)/) { # Mark left by us ?
- X $done = 1 if $1 eq $address; # Yes, we did that
- X $* = 1;
- X # Remove that X-Filter line, LEAVE will add one anyway
- X $Header{'Head'} =~ s/^X-Filter:\s*mailagent.*for $address\n//;
- X $* = 0;
- X last;
- X }
- X }
- X if ($done) { # We already processed that message
- X do add_log("NOTICE already filtered, entering seen mode")
- X if $loglvl > 5;
- X $wmode = '_SEEN_'; # This is a special mode
- X $ever_seen = 1; # This will prevent vacation messages
- X &s_seen; # Update statistics
- X }
- X }
- X
- X # The @Executed array records whether a specified action for a rule was
- X # executed. Loops are possible via the RESTART action, and as there is
- X # almost no way to exit from such a loop (there is one with FEED and RESYNC)
- X # I decided to prohibit them. Hence a given action is allowed to be executed
- X # only once during a mail analysis (modulo each possible working mode).
- X # For a rule number n, $Executed[n] is a collection of modes in which the
- X # rule was executed, comma separated.
- X
- X $Executed[$#Rules] = ''; # Pre-extend array
- X
- X # Order wrt the one in the rule file is guaranteed. I use a for construct
- X # with indexed access to be able to restart from the beginning upon
- X # execution of RESTART. This also helps filling in the @Executed array.
- X
- X local($i, $j); # Indexes within rule array
- X
- X rule: for ($i = 0; $i <= $#Rules; $i++) {
- X $j = $i + 1;
- X $_ = $Rules[$i];
- X
- X # The %Matched array records the boolean value associated with each
- X # possible selector. If two identical selector are found, the values
- X # are OR'ed (and we stop evaluating as soon as one is true). Otherwise,
- X # the values are AND'ed (for different selectors, but all are evaluated
- X # in case we later find another identical selectors -- no sort is done).
- X # The %Inverted which records '!' selector matches has all the above
- X # rules inverted according to De Morgan's Law.
- X
- X undef %Matched; # Reset matching patterns
- X undef %Inverted; # Reset negated patterns
- X $rules = $_; # Work on a copy
- X $rules =~ s/^(.*){// && ($mode = $1); # First word is the mode
- X $rules =~ s/\s*(.*)}// && ($action = $1); # Followed by action
- X $mode =~ s/\s*$//; # Remove trailing spaces
- X $rules =~ s/^\s+//; # Remove leading spaces
- X $last_selector = ""; # Last selector used
- X
- X # Make sure we are in the correct mode. The $mode variable holds a
- X # list of comma-separated modes. If the working mode is found in it
- X # then the rules apply. Otherwise, skip them.
- X
- X do add_log ("in mode '$wmode' for $mode") if $loglvl > 19;
- X $mode = "," . $mode . ",";
- X
- X # The special ALL mode matches anything but the other sepcial mode
- X # for already filtered messages.
- X
- X unless ($mode =~ /,ALL,/) {
- X next rule unless $mode =~ /,$wmode,/;
- X } else {
- X next rule if $wmode eq '_SEEN_' && $mode !~ /,_SEEN_,/;
- X }
- X
- X # Now loop over all the keys and apply the patterns in turn
- X
- X &reset_backref; # Reset backreferences
- X foreach $key (split(/ /, $rules)) {
- X $rulentry = $Rule{$key};
- X $rulentry =~ s/^\s*([^\/]*:)// && ($selector = $1);
- X $rulentry =~ s/^\s*//;
- X $pattern = $rulentry;
- X if ($last_selector ne $selector) { # Update last selector
- X $last_selector = $selector;
- X }
- X $selector =~ s/:$//; # Remove final ':' on selector
- X $* = 1; # There can be multi-line matching
- X do add_log ("selector '$selector', pattern '$pattern'")
- X if $loglvl > 19;
- X
- X # Identical (lists of) selectors are logically OR'ed. To make sure
- X # 'To Cc:' and 'Cc To:' are correctly OR'ed, the selector list is
- X # alphabetically sorted.
- X
- X $selist = join(',', sort split(' ', $selector));
- X
- X # Direct selectors and negated selectors (starting with a !) are
- X # kept separately, because the rules are dual:
- X # For normal selectors (kept in %Matched):
- X # - Identical are OR'ed
- X # - Different are AND'ed
- X # For inverted selectors (kept in %Inverted):
- X # - Identical are AND'ed
- X # - Different are OR'ed
- X # Multiple selectors like 'To Cc' are sorted according to the first
- X # selector on the list, i.e. 'To !Cc' is normal but '!To Cc' is
- X # inverted.
- X
- X if ($selector =~ /^!/) { # Inverted selector
- X # In order to guarantee an optimized AND, we first check that
- X # no previous failure has been reported for the current set of
- X # selectors.
- X unless (defined $Inverted{$selist} && !$Inverted{$selist}) {
- X $Inverted{$selist} = &match($selector, $pattern);
- X }
- X } else { # Normal selector
- X # Here it is the OR which is guaranteed to be optimized. Do
- X # not attempt the match if an identical selector already
- X # matched sucessfully.
- X unless ($Matched{$selist}) {
- X $Matched{$selist} = &match($selector, $pattern);
- X }
- X }
- X }
- X
- X # Both groups recorded in %Matched and %Inverted are globally AND'ed
- X # However, only one match is necessary within %Inverted whilst all
- X # must have matched within %Matched...
- X
- X $matched = 1; # Assume everything matched
- X foreach $key (keys %Matched) { # All entries must have matched
- X $matched = 0 unless $Matched{$key};
- X }
- X if ($matched) { # If %Matched failed, all failed!
- X foreach $key (keys %Inverted) { # Only one entry needs to match
- X $matched = 0 unless $Inverted{$key};
- X last if $matched;
- X }
- X }
- X
- X if ($matched) { # Execute action if pattern matched
- X # Make sure the rule has not already been executed in that mode
- X if ($Executed[$i] =~ /,$wmode,/) {
- X do add_log("NOTICE loop detected, rule $j, state $wmode")
- X if $loglvl > 5;
- X last rule; # Processing ends here
- X } else { # Rule was never executed
- X $Executed[$i] = ',' unless $Executed[$i];
- X $Executed[$i] .= "$wmode,";
- X }
- X $ever_matched = 1; # At least one match
- X &add_log("MATCH on rule #$j in mode $wmode") if $loglvl > 8;
- X &track_rule($j, $wmode) if $track_all;
- X &s_match($j, $wmode); # Record match for statistics
- X $status = do xeqte($action);
- X last rule if $status == $FT_CONT;
- X $ever_matched = 0; # No match if REJECT or RESTART
- X next rule if $status == $FT_REJECT;
- X $i = -1; # Restart analysis from the beginning ($FT_RESTART)
- X }
- X }
- X
- X # Deal with vacation mode. It applies only on mail not previously seen.
- X # The vacation mode must be turned on in the configuration file. The
- X # conditions for a vacation message to be sent are:
- X # - Message was directly sent to the user.
- X # - Message does not come from a special user like root.
- X # - Vacation message was not disabled via a VACATION command
- X
- X if (!$ever_seen && $cf'vacation =~ /on/i && $vacation) {
- X unless (&special_user) { # Not from special user and sent to me
- X # Send vacation message only once per address per period
- X &xeqte("ONCE (%r,vacation,$cf'vacperiod) MESSAGE $cf'vacfile");
- X &s_vacation; # Message received while in vacation
- X }
- X }
- X
- X # Default action if no rule ever matched
- X
- X unless ($ever_matched) {
- X do add_log("NOTICE no match, leaving in mailbox") if $loglvl > 5;
- X do xeqte("LEAVE"); # Default action anyway
- X &s_default; # One more application of default rule
- X } else {
- X unless ($ever_saved) {
- X do add_log("NOTICE not saved, leaving in mailbox") if $loglvl > 5;
- X do xeqte("LEAVE"); # Leave if message not saved
- X &s_saved; # Message saved by default rule
- X }
- X }
- X &s_filtered($Header{'Length'}); # Update statistics
- X 0; # Ok status
- X}
- X
- X# Return true if the mail was from a special user (root, uucp...) or if the
- X# mail was not directly mailed to the user (i.e. it comes from a distribution
- X# list or has bounced somewhere).
- Xsub special_user {
- X # Before sending the vacation message, we have to make sure the mail
- X # was sent to the user directly, through a 'To:' or a 'Cc:'. Otherwise,
- X # it must be from a mailing list or a 'Bcc:' and we don't want to
- X # send something back in that case.
- X local($matched) = do match_list("To", $cf'user);
- X $matched = do match_list("Cc", $cf'user) unless $matched;
- X unless ($matched) {
- X do add_log("mail was not directly sent to $cf'user") if $loglvl > 8;
- X return 1;
- X }
- X # If there is a Precedence: header set to either 'bulk' or 'junk', then
- X # we do not reply either.
- X local($prec) = $Header{'Precedence'};
- X if ($prec =~ /^bulk|junk/i) {
- X do add_log("mail was tagged with a '$prec' precedence") if $loglvl > 8;
- X return 1;
- X }
- X # Make sure the mail does not come from a "special" user, as listed in
- X # the %Special array (root, uucp...)
- X $matched = 0;
- X local($matched_login);
- X foreach $login (keys %Special) {
- X $matched = do match_single("From", $login);
- X $matched_login = $login if $matched;
- X last if $matched;
- X }
- X if ($matched) {
- X do add_log("mail was from special user $matched_login")
- X if $loglvl > 8;
- X return 1;
- X }
- X}
- X
- X# Log reception of mail (sender and subject fields). This is mainly intended
- X# for people like me who parse the logfile once in a while to do more
- X# statistics about mail reception. Hence the another distinction between
- X# original mails and answers.
- Xsub reception {
- X local($subject) = $Header{'Subject'};
- X local($sender) = $Header{'Sender'};
- X local($from) = $Header{'From'};
- X &add_log("FROM $from");
- X &add_log("VIA $sender")
- X if $sender ne '' && $sender ne (&parse_address($from))[0];
- X if ($subject ne '') {
- X if ($subject =~ s/^Re:\s*//) {
- X &add_log("REPLY $subject");
- X } else {
- X &add_log("ABOUT $subject");
- X }
- X }
- X print "-------- From $from\n" if $track_all;
- X}
- X
- X# Print match on STDOUT when -t option is used
- Xsub track_rule {
- X local($number, $mode) = @_;
- X print "*** Match on rule $number in mode $mode ***\n";
- X &print_rule($number);
- X}
- X
- END_OF_FILE
- if test 13269 -ne `wc -c <'agent/pl/analyze.pl'`; then
- echo shar: \"'agent/pl/analyze.pl'\" unpacked with wrong size!
- fi
- # end of 'agent/pl/analyze.pl'
- fi
- if test -f 'agent/test/filter/list.t' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'agent/test/filter/list.t'\"
- else
- echo shar: Extracting \"'agent/test/filter/list.t'\" \(1475 characters\)
- sed "s/^X//" >'agent/test/filter/list.t' <<'END_OF_FILE'
- X# This tests mathching on list selectors like To or Newsgroups.
- Xdo '../pl/filter.pl';
- X
- Xfor ($i = 1; $i <= 8; $i++) {
- X unlink "$user.$i";
- X}
- X
- X&add_header('X-Tag: list');
- X`$cmd`;
- X$? == 0 || print "1\n";
- X-f "$user.1" || print "2\n";
- Xunlink "$user.1";
- X
- X&replace_header('To: uunet!eiffel.com!max, other@max.com');
- X`$cmd`;
- X$? == 0 || print "3\n";
- X-f "$user.2" || print "4\n";
- Xunlink "$user.2";
- X
- X&replace_header('To: root@eiffel.com (Super User), max <other@max.com>');
- X`$cmd`;
- X$? == 0 || print "5\n";
- X-f "$user.3" || print "6\n";
- Xunlink "$user.3";
- X
- X# Following is illeaal in RFC-822: should be "root@eiffel.com" <maxime>
- X&replace_header('To: riot@eiffel.com (Riot Manager), root@eiffel.com <maxime>');
- X`$cmd`;
- X$? == 0 || print "7\n";
- X-f "$user.4" || print "8\n";
- Xunlink "$user.4";
- X
- X&replace_header('To: other, me, riotintin@eiffel.com, and, so, on');
- X`$cmd`;
- X$? == 0 || print "9\n";
- X-f "$user.5" || print "10\n";
- Xunlink "$user.5";
- X
- X&replace_header('To: other, me, chariot@eiffel.com, and, so, on');
- X`$cmd`;
- X$? == 0 || print "11\n";
- X-f "$user.6" || print "12\n";
- Xunlink "$user.6";
- X
- X&replace_header('To: other, me, abricot@eiffel.com, and, so, on');
- X&add_header('Newsgroups: comp.lang.perl, news.groups, news.lists');
- X`$cmd`;
- X$? == 0 || print "13\n";
- X-f "$user.7" || print "14\n";
- Xunlink "$user.7";
- X
- X&replace_header('Newsgroups: comp.lang.perl, news.groups, news.answers');
- X`$cmd`;
- X$? == 0 || print "15\n";
- X-f "$user.8" || print "16\n";
- Xunlink "$user.8";
- X
- Xunlink 'mail';
- Xprint "0\n";
- END_OF_FILE
- if test 1475 -ne `wc -c <'agent/test/filter/list.t'`; then
- echo shar: \"'agent/test/filter/list.t'\" unpacked with wrong size!
- fi
- # end of 'agent/test/filter/list.t'
- fi
- echo shar: End of archive 8 \(of 17\).
- cp /dev/null ark8isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 17 archives.
- 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...
-