home *** CD-ROM | disk | FTP | other *** search
- From: Raphael Manfredi <ram@acri.fr>
- Newsgroups: comp.sources.misc
- Subject: v44i087: mailagent - Flexible mail filtering and processing package, v3.0, Patch13
- Date: 22 Sep 1994 12:12:49 -0500
- Organization: Advanced Computer Research Institute, Lyon, France
- Sender: kent@sparky.sterling.com
- Approved: kent@sparky.sterling.com
- Message-ID: <35sduh$r4q@sparky.sterling.com>
- X-Md4-Signature: 54a601f5e0d0ff502086866c67008bb6
-
- Submitted-by: Raphael Manfredi <ram@acri.fr>
- Posting-number: Volume 44, Issue 87
- Archive-name: mailagent/patch13
- Environment: UNIX, Perl
- Patch-To: mailagent: Volume 41, Issue 1-26
-
- [The latest patch for mailagent version 3.0 is #16.]
-
- System: mailagent version 3.0
- Patch #: 13
- Priority: MEDIUM
- Subject: patch #12, continued
- Date: Thu Sep 22 17:04:30 MET DST 1994
- From: Raphael Manfredi <ram@acri.fr>
-
- Description:
- See patch #12.
-
-
- Fix: From rn, say "| patch -p -N -d DIR", where DIR is your mailagent source
- directory. Outside of rn, say "cd DIR; patch -p -N <thisarticle".
- If you don't have the patch program, apply the following by hand,
- or get patch (version 2.0, latest patchlevel).
-
- After patching:
- *** DO NOTHING--INSTALL ALL PATCHES UP THROUGH #16 FIRST ***
-
- If patch indicates that patchlevel is the wrong version, you may need
- to apply one or more previous patches, or the patch may already
- have been applied. See the patchlevel.h file to find out what has or
- has not been applied. In any event, don't continue with the patch.
-
- If you are missing previous patches they can be obtained from me:
-
- Raphael Manfredi <ram@acri.fr>
-
- If you send a mail message of the following form it will greatly speed
- processing:
-
- Subject: Command
- @SH mailpatch PATH mailagent 3.0 LIST
- ^ note the c
-
- where PATH is a return path FROM ME TO YOU either in Internet notation,
- or in bang notation from some well-known host, and LIST is the number
- of one or more patches you need, separated by spaces, commas, and/or
- hyphens. Saying 35- says everything from 35 to the end.
-
- To get some more detailed instructions, send me the following mail:
-
- Subject: Command
- @SH mailhelp PATH
-
-
- Index: patchlevel.h
- Prereq: 12
- 4c4
- < #define PATCHLEVEL 12
- ---
- > #define PATCHLEVEL 13
-
- Index: agent/pl/callout.pl
- *** agent/pl/callout.pl.old Thu Sep 22 16:43:06 1994
- --- agent/pl/callout.pl Thu Sep 22 16:43:06 1994
- ***************
- *** 0 ****
- --- 1,286 ----
- + ;# $Id: callout.pl,v 3.0.1.1 1994/09/22 14:13:07 ram Exp $
- + ;#
- + ;# Copyright (c) 1990-1993, Raphael Manfredi
- + ;#
- + ;# You may redistribute only under the terms of the Artistic License,
- + ;# as specified in the README file that comes with the distribution.
- + ;# You may reuse parts of this distribution only within the terms of
- + ;# that same Artistic License; a copy of which may be found at the root
- + ;# of the source tree for mailagent 3.0.
- + ;#
- + ;# $Log: callout.pl,v $
- + ;# Revision 3.0.1.1 1994/09/22 14:13:07 ram
- + ;# patch12: created
- + ;#
- + ;#
- + ;# This package implements a callout queue for a limited "at" support in
- + ;# mailagent commands. Since items in the callout queue can only be dispatched
- + ;# by another call to the mailagent command, execution at an exact time cannot
- + ;# be guaranteed; instead we say the action will be launched "after" a certain
- + ;# date.
- + ;#
- + ;# It is quite admissible, however, to schedule a periodic cron job launching
- + ;# a 'mailagent -q' command to actually force processing of the queue and also
- + ;# of the callout queue, as a side effect... This is up to you, the user, to
- + ;# ensure that, depending on the required accuracy for your AFTER commands.
- + ;#
- + ;# The callout queue is handled as a sorted list with a single text file:
- + ;#
- + ;# <timestamp> <type> <filename> <command>
- + ;#
- + ;# where:
- + ;# - timestamp is the time in seconds elapsed since the Epoch, after which
- + ;# the job should be launched.
- + ;# - type is either 'agent' or 'shell' depending on whether the command is
- + ;# a shell command or a mailagent filtering command (which can be a possible
- + ;# mailagent call back to a perl routine via DO).
- + ;# - command is the command to be run. Everything up to the new line.
- + ;#
- + ;# When loaded in memory, the callout queue is held in three hash tables:
- + ;# %Calltype: associates a timestamp to a list of ^@-separated types
- + ;# %Callout: associates a timestamp to a list of ^@-separated actions
- + ;# %Callfile: associates a timestamp with a list of file names
- + ;# This separation by means of ^@ is necessary since more than one event may
- + ;# be associated to a single point in time.
- + ;#
- + package callout;
- +
- + #
- + # Callout queue handling
- + #
- +
- + # Init constants -- must be called after mailagent context was loaded
- + sub init {
- + $AGENT = 'agent'; # Action is a mailagent command
- + $SHELL = 'shell'; # Action is a standalone shell command
- + $CMD = 'cmd'; # Action is a shell command on a mail message
- + $first_callout = &context'get('next-callout'); # undef if not there
- + $callout_changed = 0; # Records changes in callout queue
- + }
- +
- + # Load callout queue file into memory. Before exiting, mailagent will flush
- + # it again to the disk if it has been modified in some way. It is not an error
- + # for the file not to exist: it means the callout queue has been emptied.
- + sub load {
- + unless (open(CALLOUT, $cf'callout)) {
- + &'add_log("WARNING unable to open callout queue file: $!")
- + if -f $cf'callout && $'loglvl > 5;
- + return;
- + }
- + &'add_log("loading mailagent callout queue") if $'loglvl > 15;
- + local($_, $.);
- + while (<CALLOUT>) {
- + next if /^\s*#/;
- + if (/^(\d+)\s+(\w+)\s+(\S+)\s+(.*)/) {
- + $Calltype{$1} .= "$2\0";
- + $Callfile{$1} .= "$3\0";
- + $Callout{$1} .= "$4\0";
- + next;
- + }
- + &'add_log("WARNING callout queue corrupted, line $.") if $'loglvl > 5;
- + last;
- + }
- + close CALLOUT;
- + return unless defined %Callout; # Nothing loaded, empty file...
- +
- + local($next_callout) = (sort keys %Callout)[0];
- + if ($next_callout != $first_callout) {
- + &'add_log(
- + "NOTICE next-callout is $first_callout, should be $next_callout"
- + ) if $'loglvl > 6;
- + &'add_log("WARNING inconsistency in mailagent context (next-callout)")
- + if $'loglvl > 5;
- + }
- + $first_callout = $next_callout; # Trust callout queue over context
- + }
- +
- + # Enqueue a new job to be performed after a certain time. If the job is to be
- + # launched before the first one in the queue, the next-callout value in the
- + # mailagent context is updated.
- + # Return the queued file name, or '-' if none, undef on errors.
- + sub queue {
- + local($time, $action, $type, $no_input) = @_;
- + $callout_changed++;
- + &load unless defined %Callout;
- + local($qname) = '-'; # File not queued by default
- + if ($type ne $SHELL && !$no_input) {
- + # 'agent' or 'cmd' callouts have input by default, unless $no_input
- + # is specified in the arguments.
- + local(@mail); # Temporary mail storage
- + @mail = split(/\n/, $'Header{'All'});
- + $qname = &'qmail(*mail, 'cm');
- + unless (defined $qname) {
- + &'add_log("ERROR cannot record $type callout $action for $time")
- + if $'loglvl > 1;
- + return undef;
- + }
- + }
- + $Callfile{$time} .= "$qname\0"; # Add queue name to the list
- + $Calltype{$time} .= "$type\0"; # Add type to the list
- + $Callout{$time} .= "$action\0"; # Add action at this time stamp
- + $first_callout = $time if $time < $first_callout;
- + return $qname;
- + }
- +
- + # Return trigger time for a callout, based on its file name. This is primarily
- + # used to list the callout queue. If no callout is found, returns 0.
- + sub trigger {
- + local($file) = @_;
- + local($directory, $base) = $file =~ m|(.*)/(.*)|;
- + $file = $directory eq $cf'queue ? $base : $file;
- + &load unless defined %Callout;
- + local($time, $files);
- + foreach $time (keys %Callfile) {
- + $files = $Callfile{$time};
- + next unless "\0$files" =~ /\0$file\0/;
- + return $time;
- + }
- + return 0;
- + }
- +
- + # Run the queue, by poping off the first set in the queue, and executing
- + # it. If by that time another timeout expires, loop again.
- + sub run {
- + &'add_log("running callout queue") if $'loglvl > 15;
- + $callout_changed++;
- + &load unless defined %Callout;
- + local(@type, @action, @file);
- + local($type, $action, $file);
- + do {
- + chop($type = $Calltype{$first_callout}); # Remove trailing \0
- + chop($action = $Callout{$first_callout});
- + chop($file = $Callfile{$first_callout});
- + @type = split(/\0/, $type);
- + @action = split(/\0/, $action);
- + @file = split(/\0/, $file);
- + while ($type = shift(@type)) {
- + $action = shift(@action);
- + $file = shift(@file);
- + &spawn($type, $file, $action); # Spawn callout action
- + }
- + delete $Calltype{$first_callout};
- + delete $Callout{$first_callout};
- + delete $Callfile{$first_callout};
- + $first_callout = (sort keys %Callout)[0];
- + } while (time >= $first_callout);
- + }
- +
- + # Flush the callout queue to the disk. This operation launches the commands
- + # that have expired, then rewrites a new callout queue file to the disk if
- + # required. When all the jobs from the queue have been run, the callout file
- + # is removed and the next-callout value is deleted from the context.
- + # NOTE: this is called by &main'contextual_operations in pl/context.pl, before
- + # the new mailagent context is actually saved to the disk. Therefore, we are
- + # able to update next-callout for the next mailagent run.
- + sub flush {
- + return unless defined $first_callout;
- + &run if time >= $first_callout; # Run queue if time reached
- + return unless $callout_changed; # Done if no change since &init
- + &save;
- + &context'set('next-callout', $first_callout);
- + }
- +
- + # Save the callout queue on disk. If the %Callout table is empty, the
- + # callout file is removed.
- + sub save {
- + local($count) = scalar(keys %Callout);
- + unless ($count) {
- + &'add_log("removing mailagent callout queue") if $'loglvl > 15;
- + unlink($cf'callout);
- + return;
- + }
- + &'add_log("saving $count entries in callout queue") if $'loglvl > 15;
- +
- + local($existed) = -f $cf'callout;
- + &'acs_rqst($cf'callout) if $existed; # Lock existing file
- +
- + unless (open(CALLOUT, ">$cf'callout")) {
- + &'add_log("ERROR cannot overwrite callout queue $cf'callout: $!")
- + if $'loglvl > 1;
- + &'free_file($cf'callout) if $existed;
- + return;
- + }
- +
- + require 'ctime.pl';
- + print CALLOUT "# Mailagent callout queue, last updated " . &'ctime(time);
- +
- + local(@type, @action, @file);
- + local($type, $action, $file);
- +
- + # De-compile callout data structure back into a human-readable table
- + foreach $time (sort keys %Callout) {
- + chop($type = $Calltype{$time}); # Remove trailing \0
- + chop($action = $Callout{$time});
- + chop($file = $Callfile{$time});
- + @type = split(/\0/, $type); # Type and action lists per time
- + @action = split(/\0/, $action);
- + @file = split(/\0/, $file);
- + while ($type = shift(@type)) {
- + $action = shift(@action);
- + $file = shift(@file);
- + print CALLOUT "$time\t$type\t$file\t$action\n";
- + }
- + }
- +
- + close CALLOUT;
- + &'free_file($cf'callout) if $existed;
- + }
- +
- + #
- + # Spawning engine
- + #
- +
- + # Spawn callout action given its type, and the mail file on which the action
- + # takes place. If the file name is '-', then no input, but only for shell
- + # commands.
- + sub spawn {
- + local($type, $action, $file) = @_;
- + local($sub) = 'spawn_' . $type;
- + local($file_name) = $file; # Where mail is held (within queue usually)
- + local(%Header); # Where filtering information is stored
- + # File name is absolute if not within mailagent's queue, otherwise it
- + # is only a relative path name, as returned by &qmail. Shell commands
- + # specify '-', meaning no input is to be taken.
- + $file_name = $cf'queue . '/' . $file_name unless $file_name =~ m|^/|;
- + if (defined &$sub) {
- + &'add_log("setting up mailagent data structures for $file")
- + if $'loglvl > 15;
- + &'parse_mail($file_name) if $file ne '-'; # Fill in %Header
- + &'add_log("spawning callout $type type on $file: $action")
- + if $'loglvl > 15;
- + local($failed);
- + $failed = &$sub($action); # Invoke call-out action
- + $failed = 'FAILED' if $failed;
- + &'add_log("${failed}CALLOUT ($type) [$file] $action") if $'loglvl > 7;
- + } else {
- + &'add_log("ERROR unknown callout type $type -- skipping $action")
- + if $'loglvl;
- + }
- + unlink $file_name unless $file eq '-';
- + }
- +
- + # Spawn filtering command
- + sub spawn_agent {
- + local($action) = @_;
- + local($mode) = '_CALLOUT_'; # Initial working mode
- + local($wmode) = $mode; # Needed for statistics routines
- + umask($cf'umask); # Reset default umask
- + &'xeqte($action); # Run action
- + umask($cf'umask); # Reset umask anyway
- + return 0;
- + }
- +
- + # Spawn command-on-mail, i.e. shell command with mail on stdin
- + sub spawn_cmd {
- + local($action) = @_;
- + return &'shell_command($action, $'MAIL_INPUT, $'NO_FEEDBACK);
- + }
- +
- + # Spawn shell command
- + sub spawn_shell {
- + local($action) = @_;
- + return &'shell_command($action, $'NO_INPUT, $'NO_FEEDBACK);
- + }
- +
- + package main;
- +
-
- Index: agent/pl/actions.pl
- Prereq: 3.0.1.3
- *** agent/pl/actions.pl.old Thu Sep 22 16:43:02 1994
- --- agent/pl/actions.pl Thu Sep 22 16:43:03 1994
- ***************
- *** 1,4 ****
- ! ;# $Id: actions.pl,v 3.0.1.3 1994/07/01 14:57:49 ram Exp $
- ;#
- ;# Copyright (c) 1990-1993, Raphael Manfredi
- ;#
- --- 1,4 ----
- ! ;# $Id: actions.pl,v 3.0.1.4 1994/09/22 14:07:26 ram Exp $
- ;#
- ;# Copyright (c) 1990-1993, Raphael Manfredi
- ;#
- ***************
- *** 9,14 ****
- --- 9,21 ----
- ;# of the source tree for mailagent 3.0.
- ;#
- ;# $Log: actions.pl,v $
- + ;# Revision 3.0.1.4 1994/09/22 14:07:26 ram
- + ;# patch12: now updates new variable folder_saved with folder path
- + ;# patch12: added various escapes in strings for perl5 support
- + ;# patch12: create ~/agent.trace if unable to mail command trace back
- + ;# patch12: interface change for &qmail allows for better log messages
- + ;# patch12: implements new AFTER and DO filtering commands
- + ;#
- ;# Revision 3.0.1.3 1994/07/01 14:57:49 ram
- ;# patch8: timeout for RUN commands now defined by runmax config variable
- ;# patch8: now systematically escape leading From if fromall is ON
- ***************
- *** 116,125 ****
- }
- $failed = 1;
- }
- ! $failed; # Propagate failure status
- }
-
- # Called by &save when folder is a hook.
- # Return command failure status.
- sub save_hook {
- local($failed) = &hook'process($mailbox);
- --- 123,137 ----
- }
- $failed = 1;
- }
- ! $folder_saved = $mailbox; # Keep track of last folder we save into
- ! $failed; # Propagate failure status
- }
-
- # Called by &save when folder is a hook.
- + # Note that as opposed to other folder saving routines, we do not update the
- + # $folder_saved variable when saving into a hook. This is because the hook
- + # might be another set of filtering rules or a perl escape taking care of its
- + # own saving, in which case we do not want to corrupt the saved location.
- # Return command failure status.
- sub save_hook {
- local($failed) = &hook'process($mailbox);
- ***************
- *** 152,158 ****
- $dest =~ /<(.*)>/ && ($dest = $1);
-
- # Debugging purposes
- ! &add_log("@PATH was '$Userpath' and sender was '$sender'") if $loglvl > 18;
- &add_log("computed destination: $dest") if $loglvl > 15;
-
- # Copy body of message in an array, one line per entry
- --- 164,171 ----
- $dest =~ /<(.*)>/ && ($dest = $1);
-
- # Debugging purposes
- ! &add_log("\@PATH was '$Userpath' and sender was '$sender'")
- ! if $loglvl > 18;
- &add_log("computed destination: $dest") if $loglvl > 15;
-
- # Copy body of message in an array, one line per entry
- ***************
- *** 170,191 ****
-
- line: foreach (@body) {
- # Built-in commands
- ! if (/^@PACK\s*(.*)/) { # Pack mode
- $pack = $1 if $1 ne '';
- $pack = "" if ($pack =~ /[=$^&*([{}`\\|;><?]/);
- }
- ! s/^[ \t]@SH/@SH/; # allow one blank only
- ! if (/^@SH/) {
- s/\\!/!/g; # if uucp address, un-escape `!'
- if (/[=\$^&*([{}`\\|;><?]/) {
- ! s/^@SH/bad command:/; # space after ":" will be added
- $bad .= $_ . "\n";
- next line;
- }
- # Some useful substitutions
- ! s/@SH[ \t]*//; # Allow leading blanks
- s/ PATH/ $dest/; # PATH is a macro
- ! s/^mial(\w*)/mail\1/; # Common mis-spellings
- s/^mailpath/mailpatch/;
- s/^mailist/maillist/;
- # Now fetch command's name (first symbol)
- --- 183,204 ----
-
- line: foreach (@body) {
- # Built-in commands
- ! if (/^\@PACK\s*(.*)/) { # Pack mode
- $pack = $1 if $1 ne '';
- $pack = "" if ($pack =~ /[=$^&*([{}`\\|;><?]/);
- }
- ! s/^[ \t]\@SH/\@SH/; # allow one blank only
- ! if (/^\@SH/) {
- s/\\!/!/g; # if uucp address, un-escape `!'
- if (/[=\$^&*([{}`\\|;><?]/) {
- ! s/^\@SH/bad command:/; # space after ":" will be added
- $bad .= $_ . "\n";
- next line;
- }
- # Some useful substitutions
- ! s/\@SH[ \t]*//; # Allow leading blanks
- s/ PATH/ $dest/; # PATH is a macro
- ! s/^mial(\w*)/mail$1/; # Common mis-spellings
- s/^mailpath/mailpatch/;
- s/^mailist/maillist/;
- # Now fetch command's name (first symbol)
- ***************
- *** 282,288 ****
- It produced the following output and failed:
-
- EOM
- ! if (open(TRACE, "$trace")) {
- while (<TRACE>) {
- print MAILER;
- }
- --- 295,301 ----
- It produced the following output and failed:
-
- EOM
- ! if (open(TRACE, $trace)) {
- while (<TRACE>) {
- print MAILER;
- }
- ***************
- *** 295,300 ****
- --- 308,324 ----
- close MAILER;
- if ($?) {
- &add_log("ERROR cannot report failure") if $loglvl;
- + # Dump trace in ~/agent.trace
- + local($ok) = 1;
- + open(DUMP, ">>$cf'home/agent.trace") || ($ok = 0);
- + print DUMP "--- Trace for failed $fullcmd ---\n";
- + print DUMP "--- (was unable to mail it back) ---\n";
- + open(TRACE, $trace) || ($ok = 0);
- + while (<TRACE>) { print DUMP; }
- + print DUMP "--- End of trace for $fullcmd ---\n";
- + close DUMP;
- + &add_log("DUMPED trace in ~/agent.trace")
- + if $ok && $loglvl > 2;
- }
- &add_log("FAILED $fullcmd") if $loglvl > 1;
- } else {
- ***************
- *** 1299,1304 ****
- --- 1323,1397 ----
- 0; # Success
- }
-
- + # The "DO" command
- + # The routine name can be one of pack'routine, COMMAND:pack'routine or
- + # /some/path:pack'routine. The following parsing duplicates the one done
- + # in &dynload'do, so beware, should the interface change.
- + sub do {
- + local($something, $routine, $args) = @_;
- + $routine = $what if $something eq '';
- + unless (&dynload'do($what)) {
- + local($under);
- + $under = " under $something" if $something ne '';
- + &add_log("ERROR couldn't locate routine $routine$under") if $loglvl > 1;
- + return 1; # Failed
- + }
- + $args = '()' unless $args;
- + &add_log("calling routine $routine$args") if $loglvl > 15;
- + eval "package main; &$routine$args;";
- +
- + # I want to allow people to call mailhook commands from a DO routine call.
- + # However, commands modifying the filtering control flow are performing a
- + # die() with 'Status x' as the error message where 'x' defines the new
- + # continuation value for run_command. This is trapped specially here.
- + # Note however that convenience variables typically set for PERL escapes
- + # are not available via a DO.
- +
- + if (chop($@)) {
- + local($_) = $@;
- + $@ = ''; # Avoid cascades: we're within an eval already
- + if (/^Status (\d+)$/) { # Filter automaton continuation status
- + $cont = $1; # Propagate status ($cont from &run_command)
- + &add_log("NOTICE $routine shifted automaton to status $cont")
- + if $loglvl > 1;
- + } else {
- + &add_log("ERROR cannot call $routine$args: $_") if $loglvl > 1;
- + return 1;
- + }
- + }
- + 0; # Success
- + }
- +
- + # The "AFTER" command
- + sub after {
- + local($time, $action, $type) = @_;
- + local($no_input) = $type =~ /n/;
- + local($agent_cmd) = $type =~ /a/ || $type eq '';
- + local($shell_cmd) = $type =~ /s/;
- + local($cmd_cmd) = $type =~ /c/;
- + local($now) = time; # Current time
- + local($start); # Action's starting time
- + $start = &getdate($time, $now);
- + if ($start == -1) {
- + &add_log("ERROR in AFTER: time '$time' is incorrect") if $loglvl > 1;
- + return (1,undef);
- + }
- + if ($start < $now) {
- + &add_log("NOTICE time '$time' ($start) is before now ($now)")
- + if $loglvl > 5;
- + &add_log("ERROR in AFTER: command should have run already!")
- + if $loglvl > 1;
- + return (1,undef);
- + }
- + local($atype) = $agent_cmd ? $callout'AGENT :
- + ($shell_cmd ? $callout'SHELL : $callout'CMD);
- + local($qfile) = &callout'queue($start, $action, $atype, $no_input);
- + unless (defined $qfile) {
- + &add_log("ERROR in AFTER: cannot queue action $action") if $loglvl > 1;
- + return (1,undef);
- + }
- + (0, $qfile); # Success
- + }
-
- # Modify control flow within automaton by calling a non-existant function
- # &perform, which has been dynamically bound to one of the do_* functions.
- ***************
- *** 1393,1400 ****
- }
- # Now @array holds the whole digest item
- if ($folder =~ /^\s*$/) { # No folder means we have to queue message
- ! $failed = &qmail(*array);
- ! $log_message = 'mailagent\'s queue';
- foreach (@array) {
- $length += length($_) + 1; # No trailing new-lines
- }
- --- 1486,1494 ----
- }
- # Now @array holds the whole digest item
- if ($folder =~ /^\s*$/) { # No folder means we have to queue message
- ! local($name) = &qmail(*array);
- ! $failed = defined $name ? 0 : 1;
- ! $log_message = $name =~ m|/| ? "file [$name]" : "queue [$name]";
- foreach (@array) {
- $length += length($_) + 1; # No trailing new-lines
- }
-
- Index: agent/pl/lexical.pl
- Prereq: 3.0
- *** agent/pl/lexical.pl.old Thu Sep 22 16:43:14 1994
- --- agent/pl/lexical.pl Thu Sep 22 16:43:14 1994
- ***************
- *** 1,4 ****
- ! ;# $Id: lexical.pl,v 3.0 1993/11/29 13:48:55 ram Exp $
- ;#
- ;# Copyright (c) 1990-1993, Raphael Manfredi
- ;#
- --- 1,4 ----
- ! ;# $Id: lexical.pl,v 3.0.1.1 1994/09/22 14:24:44 ram Exp $
- ;#
- ;# Copyright (c) 1990-1993, Raphael Manfredi
- ;#
- ***************
- *** 9,14 ****
- --- 9,18 ----
- ;# of the source tree for mailagent 3.0.
- ;#
- ;# $Log: lexical.pl,v $
- + ;# Revision 3.0.1.1 1994/09/22 14:24:44 ram
- + ;# patch12: added logging at level 25 to debug lexer
- + ;# patch12: better mismatched braces handling
- + ;#
- ;# Revision 3.0 1993/11/29 13:48:55 ram
- ;# Baseline for mailagent 3.0 netwide release.
- ;#
- ***************
- *** 33,42 ****
- --- 37,48 ----
- # Assemble a whole rule in one line and return it. The end of a line is
- # marked by a ';' at the end of an input line.
- sub get_line {
- + &add_log("IN get_line") if $loglvl > 24;
- local($result) = ""; # what will be returned
- local($in_braces) = 0; # are we inside braces ?
- for (;;) {
- $_ = &read_rule; # new rule line (pseudo from compile_rules)
- + &add_log("READ <<$_>>") if $loglvl > 24;
- last if $_ eq ''; # end of file reached
- s/\n$//; # don't use chop in case we read from array
- next if /^\s*#/; # skip comments
- ***************
- *** 44,72 ****
- s/\s\s+/ /; # reduce white spaces
- $result .= $_;
- # Very simple braces handling
- ! /.*{/ && ($in_braces = 1);
- ! if ($in_braces) {
- ! /.*}/ && ($in_braces = 0);
- ! }
- ! last if !$in_braces && /;\s*$/;
- }
- $result;
- }
-
- # Get optional mode (e.g. <TEST>) at the beginning of the line and return
- # it, or ALL if none was present. A mode can be negated by pre-pending a '!'.
- sub get_mode {
- local(*line) = shift(@_); # edited in place
- local($_) = $line; # make a copy of original
- local($mode) = "ALL"; # default mode
- s/^\s*<([\s\w,!]+)>// && ($mode = $1);
- $mode =~ s/\s//g; # no spaces in returned mode
- $line = $_; # eventually updates the line
- $mode;
- }
-
- # A selector is either a script or a list of header fields ending with a ':'.
- sub get_selector {
- local(*line) = shift(@_); # edited in place
- local($_) = $line; # make a copy of original
- local($selector) = "";
- --- 50,79 ----
- s/\s\s+/ /; # reduce white spaces
- $result .= $_;
- # Very simple braces handling
- ! $in_braces += tr/{/{/ - tr/}/}/;
- ! last if $in_braces <= 0 && /;\s*$/;
- }
- + &add_log("OUT get_line: $result") if $loglvl > 24;
- $result;
- }
-
- # Get optional mode (e.g. <TEST>) at the beginning of the line and return
- # it, or ALL if none was present. A mode can be negated by pre-pending a '!'.
- sub get_mode {
- + &add_log("IN get_mode") if $loglvl > 24;
- local(*line) = shift(@_); # edited in place
- local($_) = $line; # make a copy of original
- local($mode) = "ALL"; # default mode
- s/^\s*<([\s\w,!]+)>// && ($mode = $1);
- $mode =~ s/\s//g; # no spaces in returned mode
- $line = $_; # eventually updates the line
- + &add_log("OUT get_mode: $mode") if $loglvl > 24;
- $mode;
- }
-
- # A selector is either a script or a list of header fields ending with a ':'.
- sub get_selector {
- + &add_log("IN get_selector") if $loglvl > 24;
- local(*line) = shift(@_); # edited in place
- local($_) = $line; # make a copy of original
- local($selector) = "";
- ***************
- *** 77,82 ****
- --- 84,90 ----
- s/^\s*([^\/,{\n]*(<[\d\s,-]+>)?\s*:)// && ($selector = $1);
- }
- $line = $_; # eventually updates the line
- + &add_log("OUT get_selector: $selector") if $loglvl > 24;
- $selector;
- }
-
- ***************
- *** 85,90 ****
- --- 93,99 ----
- # modifiers.
- # Patterns may be preceded by a single '!' to negate the matching value.
- sub get_pattern {
- + &add_log("IN get_pattern") if $loglvl > 24;
- local(*line) = shift(@_); # edited in place
- local($_) = $line; # make a copy of original
- local($pattern) = ""; # the recognized pattern
- ***************
- *** 112,131 ****
- } else {
- $pattern = $not . $pattern;
- }
- $pattern;
- }
-
- # Extract the action part from the line (by editing it in place) and return
- # the first action encountered. Nesting of {...} blocks may occur.
- sub get_action {
- local(*line) = shift(@_); # edited in place
- local($_) = $line; # make a copy of original
- ! return '' unless s/^\s*\{/{/;
- local($action) = &action_parse(*_, 0);
- &add_log("ERROR no action, discarding '$_'") if $loglvl && $action eq '';
- $line = $_; # eventually update the line
- $action =~ s/^\{\s*//; # remove leading and trailing braces
- $action =~ s/\s*\}$//;
- $action; # return new action block
- }
-
- --- 121,146 ----
- } else {
- $pattern = $not . $pattern;
- }
- + &add_log("OUT get_pattern: $pattern") if $loglvl > 24;
- $pattern;
- }
-
- # Extract the action part from the line (by editing it in place) and return
- # the first action encountered. Nesting of {...} blocks may occur.
- sub get_action {
- + &add_log("IN get_action") if $loglvl > 24;
- local(*line) = shift(@_); # edited in place
- local($_) = $line; # make a copy of original
- ! unless (s/^\s*\{/{/) {
- ! &add_log("OUT get_action (none)") if $loglvl > 24;
- ! return '';
- ! }
- local($action) = &action_parse(*_, 0);
- &add_log("ERROR no action, discarding '$_'") if $loglvl && $action eq '';
- $line = $_; # eventually update the line
- $action =~ s/^\{\s*//; # remove leading and trailing braces
- $action =~ s/\s*\}$//;
- + &add_log("OUT get_action: $action") if $loglvl > 24;
- $action; # return new action block
- }
-
- ***************
- *** 135,143 ****
- --- 150,160 ----
- sub action_parse {
- local(*_) = shift(@_); # edited in place
- local($level) = shift(@_); # recursion level
- + &add_log("IN action_parse $level: $_") if $loglvl > 24;
- local($parsed) = ''; # the part we parsed so far
- local($block); # block recognized
- local($follow); # recursion string returned
- +
- for (;;) {
- # Go to first un-escaped '{', if possible and save leading string
- # up-to first '{'. Note that any '}' immediately stops scanning.
- ***************
- *** 146,160 ****
- $block = '';
- s/^(([^\\{}]|\\.)*\})// && ($block = $1);
- $parsed .= $block; # block may be empty, or has trailing '}'
- if ($parsed =~ s/\{$//) { # recursion if '{' found
- $follow = &action_parse(*_, $level + 1);
- # If a null string is returned, then no matching '}' was found
- &add_log("WARNING no closing brace (added for you)")
- if $follow eq '' && $loglvl > 5;
- $parsed .= '{' . $follow . '}';
- ! } elsif (s/^\}//) { # reached end of a block
- &add_log("WARNING extra closing brace ignored")
- if $level == 0 && $loglvl > 5;
- return $parsed;
- } else {
- # Get the whole string until the next '}' and return. If a '{'
- --- 163,179 ----
- $block = '';
- s/^(([^\\{}]|\\.)*\})// && ($block = $1);
- $parsed .= $block; # block may be empty, or has trailing '}'
- + &add_log("action_parse $level: $parsed") if $loglvl > 24;
- if ($parsed =~ s/\{$//) { # recursion if '{' found
- $follow = &action_parse(*_, $level + 1);
- # If a null string is returned, then no matching '}' was found
- &add_log("WARNING no closing brace (added for you)")
- if $follow eq '' && $loglvl > 5;
- $parsed .= '{' . $follow . '}';
- ! } elsif (s/^\}//) { # reached end of a block
- &add_log("WARNING extra closing brace ignored")
- if $level == 0 && $loglvl > 5;
- + &add_log("OUT action_parse $level: $parsed") if $loglvl > 24;
- return $parsed;
- } else {
- # Get the whole string until the next '}' and return. If a '{'
- ***************
- *** 166,176 ****
- --- 185,201 ----
- if ($block eq '' && $level) { # Advance until '{'
- s/^(([^\\}]|\\.)*\{)// && ($block = $1);
- $parsed .= $block;
- + last if $block eq ''; # Reached the end... prematurely!
- next;
- }
- $block =~ s/\}//;
- + &add_log("OUT action_parse $level: $parsed$block") if $loglvl > 24;
- return $parsed . $block;
- }
- }
- +
- + &add_log("WARNING mismatched braces in rule file") if $loglvl > 5;
- + &add_log("OUT action_parse $level: $parsed <EOF>") if $loglvl > 24;
- + return $parsed;
- }
-
-
- Index: agent/pl/queue_mail.pl
- Prereq: 3.0
- *** agent/pl/queue_mail.pl.old Thu Sep 22 16:43:20 1994
- --- agent/pl/queue_mail.pl Thu Sep 22 16:43:20 1994
- ***************
- *** 1,4 ****
- ! ;# $Id: queue_mail.pl,v 3.0 1993/11/29 13:49:11 ram Exp $
- ;#
- ;# Copyright (c) 1990-1993, Raphael Manfredi
- ;#
- --- 1,4 ----
- ! ;# $Id: queue_mail.pl,v 3.0.1.1 1994/09/22 14:34:16 ram Exp $
- ;#
- ;# Copyright (c) 1990-1993, Raphael Manfredi
- ;#
- ***************
- *** 9,14 ****
- --- 9,17 ----
- ;# of the source tree for mailagent 3.0.
- ;#
- ;# $Log: queue_mail.pl,v $
- + ;# Revision 3.0.1.1 1994/09/22 14:34:16 ram
- + ;# patch12: changed interface of &qmail and &queue_mail for wider usage
- + ;#
- ;# Revision 3.0 1993/11/29 13:49:11 ram
- ;# Baseline for mailagent 3.0 netwide release.
- ;#
- ***************
- *** 16,29 ****
- ;# Queue a mail file. Needs add_log(). Calls fatal() in emergency situations.
- ;# Requires a parsed config file.
- ;#
- ! # Queue mail in a 'fm' file. The mail is held in memory. It returns 0 if the
- ! # mail was queued, 1 otherwise.
- sub qmail {
- ! local(*array) = @_; # In which array mail is located.
- local($queue_file); # Where we attempt to save the mail
- local($failed) = 0; # Be positive and look forward :-)
- ! $queue_file = "$cf'queue/Tqm$$";
- ! $queue_file = "$cf'queue/Tqmb$$" if -f "$queue_file"; # Paranoid
- unless (open(QUEUE, ">$queue_file")) {
- &add_log("ERROR unable to create $queue_file: $!") if $loglvl > 1;
- return 1; # Failed
- --- 19,35 ----
- ;# Queue a mail file. Needs add_log(). Calls fatal() in emergency situations.
- ;# Requires a parsed config file.
- ;#
- ! # Queue mail in a 'fm' file (or whatever is specified for type). The mail is
- ! # held in memory, within an array passed via a type-glob.
- ! # Returns the name of queued file if success, undef if failed. File name will
- ! # be absolute only when queued outside of the regular queue.
- sub qmail {
- ! local(*array, $type) = @_; # In which array mail is located.
- local($queue_file); # Where we attempt to save the mail
- local($failed) = 0; # Be positive and look forward :-)
- ! local($name); # Name of queued file
- ! $queue_file = "$cf'queue/Mqm$$";
- ! $queue_file = "$cf'queue/Mqmb$$" if -f "$queue_file"; # Paranoid
- unless (open(QUEUE, ">$queue_file")) {
- &add_log("ERROR unable to create $queue_file: $!") if $loglvl > 1;
- return 1; # Failed
- ***************
- *** 43,79 ****
- }
- close QUEUE;
- unlink "$queue_file" if $failed;
- ! $failed = &queue_mail($queue_file) unless $failed;
- ! $failed; # 0 means success
- }
-
- ! # Queue mail in a 'fm' file. The mail is supposed to be either on disk or
- ! # is expected from standard input. Returns 0 for success, 1 if failed.
- # In case mail comes from stdin, may not return at all but raise a fatal error.
- sub queue_mail {
- local($file_name) = shift(@_); # Where mail to-be-queued is
- ! local($deferred) = shift(@_); # True when 'qm' mail wanted instead
- local($dirname); # Directory name of processed file
- local($tmp_queue); # Tempoorary storing of queued file
- local($queue_file); # Final name of queue file
- local($ok) = 1; # Print status
- local($_);
- ! &add_log("queuing mail for delayed processing") if $loglvl > 18;
- chdir $cf'queue || &fatal("cannot chdir to $cf'queue");
-
- # The following ensures unique queue mails. As the mailagent itself may
- # queue intensively throughout the SPLIT command, a queue counter is kept
- # and is incremented each time a mail is successfully queued.
- ! local($base) = $deferred ? 'qm' : 'fm';
- ! $queue_file = "$base$$"; # 'fm' stands for Full Mail
- ! $queue_file = "$base$$x" . $queue_count if -f "$queue_file";
- $queue_file = "${queue_file}x" if -f "$queue_file"; # Paranoid
- ++$queue_count; # Counts amount of queued mails
- &add_log("queue file is $queue_file") if $loglvl > 19;
-
- # Do not write directly in the fm file, otherwise the main
- # mailagent process could start its processing on it...
- ! $tmp_queue = "Tfm$$";
- local($sender) = "<someone>"; # Attempt to report the sender of message
- if ($file_name) { # Mail is already on file system
- # Mail already in a file
- --- 49,103 ----
- }
- close QUEUE;
- unlink "$queue_file" if $failed;
- ! unless ($failed) {
- ! $type = 'fm' unless defined $type; # Defaults to a 'fm' file
- ! $name = &queue_mail($queue_file, $type);
- ! $failed = defined $name ? 0 : 1;
- ! }
- ! $failed ? undef : $name; # File path name, undef if failed
- }
-
- ! # Queue mail in a queue file. There are three types of queued mails:
- ! # . qm: messages whose handling will be delayed by at most cf'queuehold secs
- ! # . fm: messages queued for immediate processing by next 'mailagent -q'
- ! # . cm: callout queue messages, meant for input by callout command
- ! # The mail is supposed to be either on disk or is expected from standard input.
- # In case mail comes from stdin, may not return at all but raise a fatal error.
- + # Returns the name of queued file if success, undef if failed. File name will
- + # be absolute only when queued outside of the regular queue.
- sub queue_mail {
- local($file_name) = shift(@_); # Where mail to-be-queued is
- ! local($type) = shift(@_); # Type of mail message, must be known
- local($dirname); # Directory name of processed file
- local($tmp_queue); # Tempoorary storing of queued file
- local($queue_file); # Final name of queue file
- local($ok) = 1; # Print status
- local($_);
- ! &add_log("queuing mail ($type) for delayed processing") if $loglvl > 18;
- chdir $cf'queue || &fatal("cannot chdir to $cf'queue");
-
- + local(%known_type) = ( # Known queue message types
- + 'qm', 1,
- + 'fm', 1,
- + 'cm', 1,
- + );
- + unless ($known_type{$type}) {
- + &add_log("ERROR unknown type $type, defaulting to qm") if $loglvl > 1;
- + $type = 'qm';
- + }
- +
- # The following ensures unique queue mails. As the mailagent itself may
- # queue intensively throughout the SPLIT command, a queue counter is kept
- # and is incremented each time a mail is successfully queued.
- ! $queue_file = "$type$$"; # Append PID for uniqueness
- ! $queue_file = "$type$$x" . $queue_count if -f "$queue_file";
- $queue_file = "${queue_file}x" if -f "$queue_file"; # Paranoid
- ++$queue_count; # Counts amount of queued mails
- &add_log("queue file is $queue_file") if $loglvl > 19;
-
- # Do not write directly in the fm file, otherwise the main
- # mailagent process could start its processing on it...
- ! $tmp_queue = "T$type$$";
- local($sender) = "<someone>"; # Attempt to report the sender of message
- if ($file_name) { # Mail is already on file system
- # Mail already in a file
- ***************
- *** 141,148 ****
- # in the queue directory. This file contains the names of the mails
- # stored outside of the mailagent's queue and waiting to be processed.
- $ok = &waiting_mail($tmp_queue);
- ! return 1 unless $ok; # Queuing failed if not ok
- ! return 0;
- }
-
- # We succeeded in writing the temporary queue mail. Now rename it so that
- --- 165,172 ----
- # in the queue directory. This file contains the names of the mails
- # stored outside of the mailagent's queue and waiting to be processed.
- $ok = &waiting_mail($tmp_queue);
- ! return undef unless $ok; # Queuing failed if not ok
- ! return $tmp_queue;
- }
-
- # We succeeded in writing the temporary queue mail. Now rename it so that
- ***************
- *** 155,163 ****
- } else {
- &add_log("ERROR cannot rename $tmp_queue to $queue_file") if $loglvl;
- $ok = &waiting_mail($tmp_queue);
- }
- ! return 1 unless $ok; # Queuing failed if not ok
- ! 0;
- }
-
- # Adds mail into the agent.wait file, if possible. This file records all the
- --- 179,188 ----
- } else {
- &add_log("ERROR cannot rename $tmp_queue to $queue_file") if $loglvl;
- $ok = &waiting_mail($tmp_queue);
- + $queue_file = $tmp_queue;
- }
- ! return undef unless $ok; # Queuing failed if not ok
- ! $queue_file; # Return file name for success
- }
-
- # Adds mail into the agent.wait file, if possible. This file records all the
-
- Index: agent/man/mailagent.SH
- Prereq: 3.0.1.4
- *** agent/man/mailagent.SH.old Thu Sep 22 16:42:58 1994
- --- agent/man/mailagent.SH Thu Sep 22 16:42:59 1994
- ***************
- *** 20,26 ****
- .TH MAILAGENT $manext "Version $VERSION PL$PATCHLEVEL"
- ''' @(#) Manual page for mailagent's filter -- (c) ram February 1991
- '''
- ! ''' $Id: mailagent.SH,v 3.0.1.4 1994/07/01 14:56:20 ram Exp $
- '''
- ''' Copyright (c) 1990-1993, Raphael Manfredi
- '''
- --- 20,26 ----
- .TH MAILAGENT $manext "Version $VERSION PL$PATCHLEVEL"
- ''' @(#) Manual page for mailagent's filter -- (c) ram February 1991
- '''
- ! ''' $Id: mailagent.SH,v 3.0.1.5 1994/09/22 13:57:09 ram Exp $
- '''
- ''' Copyright (c) 1990-1993, Raphael Manfredi
- '''
- ***************
- *** 31,36 ****
- --- 31,42 ----
- ''' of the source tree for mailagent 3.0.
- '''
- ''' $Log: mailagent.SH,v $
- + ''' Revision 3.0.1.5 1994/09/22 13:57:09 ram
- + ''' patch12: documents new config parameters callout and linkdirs
- + ''' patch12: new filtering actions AFTER and DO
- + ''' patch12: variable msgpath is now defined within a PERL escape
- + ''' patch12: mention that PERL escape variables are available to new commands
- + '''
- ''' Revision 3.0.1.4 1994/07/01 14:56:20 ram
- ''' patch8: documents new eleven configuration variables
- ''' patch8: sub-section on timeouts has been expanded
- ***************
- *** 204,209 ****
- --- 210,220 ----
- (suggested: OFF, unless you use ONCE, UNIQUE or RECORD commands, or activate
- the vacation mode.)
- .TP
- + .I callout
- + The name of the callout queue file where batched jobs are kept. This
- + parameter must be defined when using the AFTER command.
- + (suggested: $spool/callout)
- + .TP
- .I cleanlaps
- Cleaning period for database entries. The value of the last clean up is saved
- into the context file. This is optional, but needed if \fIautoclean\fR is on.
- ***************
- *** 266,277 ****
- .I level
- Log level, see below for a definition of available levels (suggested: 9).
- .TP
- .I lockdekay
- The delay in seconds between two locking attempts. (optional, defaults to: 2).
- .TP
- .I lockhold
- The maximum delay in seconds for holding a lock. After that time, the lock
- ! will be broken. (optional, defaults to: 3600)
- .TP
- .I lockmax
- Maximum number of locking attempts before giving up. (optional,
- --- 277,296 ----
- .I level
- Log level, see below for a definition of available levels (suggested: 9).
- .TP
- + .I linkdirs
- + When set to ON, carefully checks symbolic links to directories when performing
- + security checks on sensitive files. This will (recursively) check for each
- + symbolic link level that the target directory is not world writable or group
- + writable and that the parent directory of each target link is not world
- + writable. If the \fIsecure\fR option is OFF, this parameter is ignored.
- + (optional, defaults to: ON, suggested: ON when secure is also ON).
- + .TP
- .I lockdekay
- The delay in seconds between two locking attempts. (optional, defaults to: 2).
- .TP
- .I lockhold
- The maximum delay in seconds for holding a lock. After that time, the lock
- ! will be broken. (optional, defaults to: 3600).
- .TP
- .I lockmax
- Maximum number of locking attempts before giving up. (optional,
- ***************
- *** 1362,1367 ****
- --- 1381,1404 ----
- Abort application of filtering rules immediately. See REJECT for the meaning
- of the optional parameters. (Does not modify existing status)
- .TP
- + AFTER [-sanc] \fI(time) action\fR
- + Records a callback for after the specified \fItime\fR, where \fIaction\fR will
- + be performed. By default, a mailagent filtering action is assumed (\fB\-a\fR
- + option), on the current mail message. A shell command (\fB\-c\fR) may be
- + given instead, receiving the current mail message as standard input. Finally,
- + a plain shell command may be run (with no input) using the \fB\-s\fR option.
- + The option \fB-n\fR may be used when the current mail message does not need
- + to be kept for input. For instance:
- + .Ex
- + AFTER \fB-an\fR (1 day) DO ~/process:proc'run(%u)
- + .Ef
- + would call \fIproc'run\fR defined in the \fI~/process\fR file in one day
- + from now, without giving any input (the action here does not require any).
- + Note that the command is not called \fIAT\fR because the call will only
- + be performed at the next mailagent invocation after the specified time has
- + elapsed. Dates are specified using the same format as in SELECT.
- + (Fails if the action cannot be recorded in the callout queue).
- + .TP
- ANNOTATE [-d] \fIfield value\fR
- Annotate message by adding \fIfield\fR into the mail header, with the
- supplied \fIvalue\fR. This is like the MH command \fIanno\fR, but the
- ***************
- *** 1422,1427 ****
- --- 1459,1482 ----
- for pattern loading.
- (Fails if mail cannot be resent)
- .TP
- + DO \fIroutine\fR [\fI(arg1, arg2, ... , argn)\fR]
- + Calls the perl \fIroutine\fR, with the supplied arguments if any. This is a
- + very low level hook into \fImailagent's\fR internal. The routine can be
- + specified by itself (\fIpackage'name\fR, \fIpackage\fR being \fImain\fR by
- + default), or identified by a leading \fItag\fR, followed by a ':', then the
- + routine name as before. The \fItag\fR can be a path to a file where the routine
- + is defined, or a command name (for user-defined commands which are loaded
- + dynamically). For instance
- + .Ex
- + DO UNKIT:newcmd'unkit('true')
- + .Ef
- + would lookup
- + the user-defined \fIUNKIT\fR command, load the file where it is defined (in the
- + \fInewcmd\fR package), then call the routine with \fI'true'\fR as argument.
- + The \fIpackage\fR specified determines where the loading is done, so be sure
- + it is consistent with the definition in the file where the routine is defined.
- + (Fails if the routine cannot be located and executed)
- + .TP
- DELETE
- Delete the current message. Actually, this does not do anything, it just marks
- the mail as saved. If no further action involving saving is done, then the
- ***************
- *** 1850,1855 ****
- --- 1905,1915 ----
- This table, indexed by field name, returns the raw content on the
- corresponding header line. See below.
- .TP
- + .I \$msgpath
- + The full path name of the folder (or message within an MH folder) where
- + the last saving operation has occurred. This is intended to be used if
- + you wish to construct your own mail reception notification.
- + .TP
- .I \$login
- The login name of the address on the From: line.
- .TP
- ***************
- *** 2771,2776 ****
- --- 2831,2841 ----
- saving operation has been completed. If at the end of the filtering, this
- variable is still \fB0\fR, then the default LEAVE will be executed.
- .TP
- + .I \$folder_saved
- + The value of that variable governs the \fI\$msgpath\fR convenience variable
- + set for PERL escapes. It is updated whenever a message is written to a file,
- + to hold the path of the written file.
- + .TP
- .I \$vacation
- This is a boolean, which when \fIset\fR to \fB1\fR will allow vacation messages.
- It is mainly used by the VACATION command, but if you wish to re-implement that
- ***************
- *** 2795,2800 ****
- --- 2860,2869 ----
- This records the current state of the filter automaton (working mode), in a
- literal string form, typically modified by the BEGIN command or as a side
- effect, as in REJECT for instance.
- + .PP
- + All the special variables set-up for PERL escapes are also installed within
- + the \fInewcmd\fR package. Those are \fI\$login\fR, \fI%header\fR, etc... You
- + may peruse them at will.
- .PP
- Other variables you might have a need for are configuration parameters, held
- in the \fI~/.mailagent\fR configuration file. Well, the rule is simple. The
-
- Index: agent/test/cmd/after.t
- *** agent/test/cmd/after.t.old Thu Sep 22 16:43:28 1994
- --- agent/test/cmd/after.t Thu Sep 22 16:43:28 1994
- ***************
- *** 0 ****
- --- 1,18 ----
- + # The AFTER command
- +
- + # $Id: after.t,v 3.0.1.1 1994/09/22 14:40:57 ram Exp $
- + #
- + # Copyright (c) 1990-1993, Raphael Manfredi
- + #
- + # You may redistribute only under the terms of the Artistic License,
- + # as specified in the README file that comes with the distribution.
- + # You may reuse parts of this distribution only within the terms of
- + # that same Artistic License; a copy of which may be found at the root
- + # of the source tree for mailagent 3.0.
- + #
- + # $Log: after.t,v $
- + # Revision 3.0.1.1 1994/09/22 14:40:57 ram
- + # patch12: created
- + #
- +
- + print "-1\n"; # Automatic testing difficult
-
- *** End of Patch 13 ***
-
- exit 0 # Just in case...
-