home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume44
/
mailagent
/
patch14
< prev
next >
Wrap
Internet Message Format
|
1994-09-22
|
46KB
From: Raphael Manfredi <ram@acri.fr>
Newsgroups: comp.sources.misc
Subject: v44i088: mailagent - Flexible mail filtering and processing package, v3.0, Patch14
Date: 22 Sep 1994 12:13:09 -0500
Organization: Advanced Computer Research Institute, Lyon, France
Sender: kent@sparky.sterling.com
Approved: kent@sparky.sterling.com
Message-ID: <35sdv5$r5c@sparky.sterling.com>
X-Md4-Signature: e92b7f719734101e1dc4f203bab5ae54
Submitted-by: Raphael Manfredi <ram@acri.fr>
Posting-number: Volume 44, Issue 88
Archive-name: mailagent/patch14
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 #: 14
Priority: MEDIUM
Subject: patch #12, continued
Date: Thu Sep 22 17:04:34 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: 13
4c4
< #define PATCHLEVEL 13
---
> #define PATCHLEVEL 14
Index: agent/pl/eval.pl
Prereq: 3.0
*** agent/pl/eval.pl.old Thu Sep 22 16:43:09 1994
--- agent/pl/eval.pl Thu Sep 22 16:43:09 1994
***************
*** 1,4 ****
! ;# $Id: eval.pl,v 3.0 1993/11/29 13:48:42 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
--- 1,4 ----
! ;# $Id: eval.pl,v 3.0.1.1 1994/09/22 14:18:11 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
***************
*** 9,14 ****
--- 9,17 ----
;# of the source tree for mailagent 3.0.
;#
;# $Log: eval.pl,v $
+ ;# Revision 3.0.1.1 1994/09/22 14:18:11 ram
+ ;# patch12: replaced all deprecated 'do sub' calls with '&sub'
+ ;#
;# Revision 3.0 1993/11/29 13:48:42 ram
;# Baseline for mailagent 3.0 netwide release.
;#
***************
*** 19,26 ****
# Initialize the interpreter
sub init_interpreter {
! do set_priorities(); # Fill in %Priority
! do set_functions(); # Fill in %Function
$macro_T = "the Epoch"; # Default value for %T macro substitution
}
--- 22,29 ----
# Initialize the interpreter
sub init_interpreter {
! &set_priorities; # Fill in %Priority
! &set_functions; # Fill in %Function
$macro_T = "the Epoch"; # Default value for %T macro substitution
}
***************
*** 57,63 ****
# Print error messages -- asssumes $unit and $. correctly set.
sub error {
! do add_log("ERROR @_") if $loglvl > 1;
}
# Add a value on the stack, modified by all the monadic operators.
--- 60,66 ----
# Print error messages -- asssumes $unit and $. correctly set.
sub error {
! &add_log("ERROR @_") if $loglvl > 1;
}
# Add a value on the stack, modified by all the monadic operators.
***************
*** 81,89 ****
local($val2) = pop(@val); # Right value in algebraic notation
local($val1) = pop(@val); # Left value in algebraic notation
local($func) = $Function{$op}; # Function to be called
! do macros_subst(*val1); # Expand macros
! do macros_subst(*val2);
! push(@val, eval("do $func($val1, $val2)") ? 1: 0);
}
# Given an operator, either we add it in the stack @op, because its
--- 84,92 ----
local($val2) = pop(@val); # Right value in algebraic notation
local($val1) = pop(@val); # Left value in algebraic notation
local($func) = $Function{$op}; # Function to be called
! ¯os_subst(*val1); # Expand macros
! ¯os_subst(*val2);
! push(@val, eval("&$func($val1, $val2)") ? 1: 0);
}
# Given an operator, either we add it in the stack @op, because its
***************
*** 94,104 ****
sub update_stack {
local($op) = shift(@_); # Operator
if (!$Priority{$op}) {
! do error("illegal operator $op");
return;
} else {
if ($#val < 0) {
! do error("missing first operand for '$op' (diadic operator)");
return;
}
# Because of a bug in perl 4.0 PL19, I'm using a loop construct
--- 97,107 ----
sub update_stack {
local($op) = shift(@_); # Operator
if (!$Priority{$op}) {
! &error("illegal operator $op");
return;
} else {
if ($#val < 0) {
! &error("missing first operand for '$op' (diadic operator)");
return;
}
# Because of a bug in perl 4.0 PL19, I'm using a loop construct
***************
*** 107,113 ****
$Priority{$op[$#op]} > $Priority{$op} # Higher priority op
&& $#val > 0 # At least 2 values
) {
! do execute(); # Execute an higer priority stacked operation
}
push(@op, $op); # Everything at higher priority has been executed
}
--- 110,116 ----
$Priority{$op[$#op]} > $Priority{$op} # Higher priority op
&& $#val > 0 # At least 2 values
) {
! &execute; # Execute an higer priority stacked operation
}
push(@op, $op); # Everything at higher priority has been executed
}
***************
*** 127,169 ****
# A perl statement <<command>>
if (s/^<<//) {
if (s/^(.*)>>//) {
! do push_val((system
('perl','-e', "if ($1) {exit 0;} else {exit 1;}"
))? 0 : 1);
} else {
! do error("incomplete perl statement");
}
}
# A shell statement <command>
elsif (s/^<//) {
if (s/^(.*)>//) {
! do push_val((system
("if $1 >/dev/null 2>&1; then exit 0; else exit 1; fi"
))? 0 : 1);
} else {
! do error("incomplete shell statement");
}
}
# The '(' construct
elsif (s/^\(//) {
! do push_val(do eval_expr(*_));
# A final '\' indicates an end of line
! do error("missing final parenthesis") if !s/^\\//;
}
# Found a ')' or end of line
elsif (/^\)/ || /^$/) {
s/^\)/\\/; # Signals: left parenthesis found
$expr = $_; # Remove interpreted stuff
! do execute() while $#val > 0; # Executed stacked operations
while ($#op >= 0) {
$_ = pop(@op);
! do error("missing second operand for '$_' (diadic operator)");
}
return $val[0];
}
# Diadic operators
elsif (s/^(\|\||&&|>=|<=|>|<|==|!=|=|\/=)//) {
! do update_stack($1);
}
# Unary operator '!'
elsif (s/^!//) {
--- 130,172 ----
# A perl statement <<command>>
if (s/^<<//) {
if (s/^(.*)>>//) {
! &push_val((system
('perl','-e', "if ($1) {exit 0;} else {exit 1;}"
))? 0 : 1);
} else {
! &error("incomplete perl statement");
}
}
# A shell statement <command>
elsif (s/^<//) {
if (s/^(.*)>//) {
! &push_val((system
("if $1 >/dev/null 2>&1; then exit 0; else exit 1; fi"
))? 0 : 1);
} else {
! &error("incomplete shell statement");
}
}
# The '(' construct
elsif (s/^\(//) {
! &push_val(&eval_expr(*_));
# A final '\' indicates an end of line
! &error("missing final parenthesis") if !s/^\\//;
}
# Found a ')' or end of line
elsif (/^\)/ || /^$/) {
s/^\)/\\/; # Signals: left parenthesis found
$expr = $_; # Remove interpreted stuff
! &execute while $#val > 0; # Executed stacked operations
while ($#op >= 0) {
$_ = pop(@op);
! &error("missing second operand for '$_' (diadic operator)");
}
return $val[0];
}
# Diadic operators
elsif (s/^(\|\||&&|>=|<=|>|<|==|!=|=|\/=)//) {
! &update_stack($1);
}
# Unary operator '!'
elsif (s/^!//) {
***************
*** 171,177 ****
}
# Everything else is a value which stands for itself (atom)
elsif (s/^([\w'"%]+)//) {
! do push_val($1);
}
# Syntax error
else {
--- 174,180 ----
}
# Everything else is a value which stands for itself (atom)
elsif (s/^([\w'"%]+)//) {
! &push_val($1);
}
# Syntax error
else {
***************
*** 186,192 ****
local($val); # Value returned
local(*expr) = shift(@_); # Expression to be parsed
while ($expr) {
! $val = do eval_expr(*expr); # Expression will be modified
print "extra closing parenthesis ignored.\n" if $expr =~ s/^\\\)*//;
$expr = $val . $expr if $expr ne '';
}
--- 189,195 ----
local($val); # Value returned
local(*expr) = shift(@_); # Expression to be parsed
while ($expr) {
! $val = &eval_expr(*expr); # Expression will be modified
print "extra closing parenthesis ignored.\n" if $expr =~ s/^\\\)*//;
$expr = $val . $expr if $expr ne '';
}
Index: agent/edusers.SH
*** agent/edusers.SH.old Thu Sep 22 16:42:47 1994
--- agent/edusers.SH Thu Sep 22 16:42:47 1994
***************
*** 0 ****
--- 1,104 ----
+ case $CONFIG in
+ '')
+ if test -f config.sh; then TOP=.;
+ elif test -f ../config.sh; then TOP=..;
+ elif test -f ../../config.sh; then TOP=../..;
+ elif test -f ../../../config.sh; then TOP=../../..;
+ elif test -f ../../../../config.sh; then TOP=../../../..;
+ else
+ echo "Can't find config.sh."; exit 1
+ fi
+ . $TOP/config.sh
+ ;;
+ esac
+ case "$0" in
+ */*) cd `expr X$0 : 'X\(.*\)/'` ;;
+ esac
+ echo "Extracting agent/edusers (with variable substitutions)"
+ $spitshell >edusers <<!GROK!THIS!
+ $startperl
+ eval "exec perl -S \$0 \$*"
+ if \$running_under_some_shell;
+
+ # $Id: edusers.SH,v 3.0.1.1 1994/09/22 13:39:28 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: edusers.SH,v $
+ # Revision 3.0.1.1 1994/09/22 13:39:28 ram
+ # patch12: created
+ #
+
+ \$mversion = '$VERSION';
+ \$patchlevel = '$PATCHLEVEL';
+ \$defeditor = '$defeditor';
+ !GROK!THIS!
+ $spitshell >>edusers <<'!NO!SUBS!'
+
+ $userlist = "users";
+ $prog_name = $0; # Who I am
+ $prog_name =~ s|^.*/(.*)|$1|; # Keep only base name
+ $lockext = '.lock'; # Locking extension
+ *add_log = *stderr_log; # Ensure logs will go to stderr also
+
+ $EDITOR = $ENV{'EDITOR'} || $ENV{'VISUAL'} || $defeditor;
+
+ &read_config; # First, read configuration file (in ~/.mailagent)
+ &read_dist; # Read distributions
+ &catch_signals;
+
+ $system = shift; # Which system do we want
+ $version = shift; # Which version it is
+
+ # If no system is specified, try locating a '.package', then source it
+ # to get information...
+ if ($system eq '') {
+ die "$prog_name: you must specify a system name\n" unless &read_package;
+ $system = $pkg'package;
+ $version = $pkg'baserev;
+ }
+
+ # A single '-' or a missing version means "highest available" version.
+ $version = $Version{$system} if $version eq '-' || $version eq '';
+
+ # Full name of system for H table access
+ $pname = $system . "|" . $version;
+
+ die "$prog_name: no program called $system\n" unless $System{$system};
+ die "$prog_name: no package $system version $version\n"
+ unless $Program{$pname};
+
+ # Go to the system directory.
+ chdir "$Location{$pname}" ||
+ die "$prog_name: cannot go to $Location{$pname}\n";
+
+ -f $userlist || die "$prog_name: no $userlist file yet for $system $version.\n";
+
+ # Lock users file. That file should only be edited with the edusers script.
+ die "$prog_name: cannot lock $userlist.\n" if 0 != &acs_rqst($userlist);
+
+ system "$EDITOR $userlist";
+ warn "$prog_name: WARNING: edition failed...\n" if $?;
+ &free_file($userlist);
+
+ exit $?;
+
+ !NO!SUBS!
+ $grep -v '^;#' pl/fatal.pl >>edusers
+ $grep -v '^;#' pl/add_log.pl >>edusers
+ $grep -v '^;#' pl/read_conf.pl >>edusers
+ $grep -v '^;#' pl/distribs.pl >>edusers
+ $grep -v '^;#' pl/secure.pl >>edusers
+ $grep -v '^;#' pl/acs_rqst.pl >>edusers
+ $grep -v '^;#' pl/free_file.pl >>edusers
+ $grep -v '^;#' pl/checklock.pl >>edusers
+ $grep -v '^;#' pl/signals.pl >>edusers
+ $grep -v '^;#' pl/package.pl >>edusers
+ chmod 755 edusers
+ $eunicefix edusers
Index: agent/man/edusers.SH
*** agent/man/edusers.SH.old Thu Sep 22 16:42:56 1994
--- agent/man/edusers.SH Thu Sep 22 16:42:56 1994
***************
*** 0 ****
--- 1,106 ----
+ case $CONFIG in
+ '')
+ if test -f config.sh; then TOP=.;
+ elif test -f ../config.sh; then TOP=..;
+ elif test -f ../../config.sh; then TOP=../..;
+ elif test -f ../../../config.sh; then TOP=../../..;
+ elif test -f ../../../../config.sh; then TOP=../../../..;
+ else
+ echo "Can't find config.sh."; exit 1
+ fi
+ . $TOP/config.sh
+ ;;
+ esac
+ case "$0" in
+ */*) cd `expr X$0 : 'X\(.*\)/'` ;;
+ esac
+ echo "Extracting agent/man/edusers.$manext (with variable substitutions)"
+ $rm -f edusers.$manext
+ $spitshell >edusers.$manext <<!GROK!THIS!
+ .TH PACKAGE $manext
+ ''' @(#) Manual page for mailagent's edusers command
+ '''
+ ''' $Id: edusers.SH,v 3.0.1.1 1994/09/22 13:53:06 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: edusers.SH,v $
+ ''' Revision 3.0.1.1 1994/09/22 13:53:06 ram
+ ''' patch12: created
+ '''
+ '''
+ .de Ex \" Start of Example
+ .sp
+ .in +5
+ .nf
+ ..
+ .de Ef \" End of Example
+ .sp
+ .in -5
+ .fi
+ ..
+ .SH NAME
+ edusers \- edit users list created by package
+ .SH SYNOPSIS
+ \fBedusers\fR [\fIsystem\fR [\fIversion\fR]]
+ .SH DESCRIPTION
+ This command lets you safely edit the \fIusers\fR list created by the
+ .I package
+ command. It locks the file before launching the editor, hence protecting
+ against any concurrent update by some \fIpackage\fR command that could
+ arrive at the same time (by e-mail). The level of protection this locking
+ buys you depends on the locking policy you have configured in
+ your \fI~/.mailagent\fR.
+ .PP
+ If you are within a package source tree, all you need to say is
+ .Ex
+ edusers
+ .Ef
+ to edit the \fIusers\fR file for that package. In order for that particular
+ feature to work properly, the package must have been placed under dist control,
+ or at least the \fIpackinit\fR command from the dist package must have been
+ run.
+ .PP
+ Otherwise, you may specify
+ a system name, and optionally a version number if that is not enough to
+ disambiguate. Using '-' will get you the lattest version available.
+ .PP
+ In any case, there must be a proper setting of the \fIdistribs\fR file
+ to use this command. If that file is not accurate, the \fIpackage\fR
+ command will not be able to produce a \fIusers\fR file anyway.
+ .SH ENVIRONMENT
+ The editor is taken out of the EDITOR variable if defined, then from
+ the VISUAL variable, defaulting to
+ .I $defeditor
+ if none of the variables is set.
+ .SH FILES
+ .PD 0
+ .TP 20
+ ~/.mailagent
+ configuration file for mailagent.
+ .TP
+ Spool/distribs
+ distribution list, same file as the one used for mailpatch.
+ .TP
+ System/.package
+ file created by dist's packinit command to indicate
+ the root of the source tree for that package.
+ .TP
+ System/users
+ list of users of that system.
+ .TP
+ Log/agentlog
+ mailagent's log file.
+ .PD
+ .SH AUTHOR
+ Raphael Manfredi <ram@acri.fr>
+ .SH "SEE ALSO"
+ mailagent($manext), metaconfig($manext), package($manext), packinit($manext).
+ !GROK!THIS!
+ chmod 444 edusers.$manext
Index: agent/magent.SH
Prereq: 3.0.1.2
*** agent/magent.SH.old Thu Sep 22 16:42:54 1994
--- agent/magent.SH Thu Sep 22 16:42:54 1994
***************
*** 24,30 ****
# via the filter. Mine looks like this:
# "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
! # $Id: magent.SH,v 3.0.1.2 1994/07/01 14:54:29 ram Exp $
#
# Copyright (c) 1990-1993, Raphael Manfredi
#
--- 24,30 ----
# via the filter. Mine looks like this:
# "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"
! # $Id: magent.SH,v 3.0.1.3 1994/09/22 13:52:34 ram Exp $
#
# Copyright (c) 1990-1993, Raphael Manfredi
#
***************
*** 35,40 ****
--- 35,48 ----
# of the source tree for mailagent 3.0.
#
# $Log: magent.SH,v $
+ # Revision 3.0.1.3 1994/09/22 13:52:34 ram
+ # patch12: now performs &init_constants as soon as possible
+ # patch12: changed interface for &queue_mail to include first 2 letters
+ # patch12: context is loaded earlier to initialize callout queue
+ # patch12: added definition for $MAX_LINKS, $S_IWOTH, $S_IWGRP and &abs
+ # patch12: changed &email_addr to cache its result and not rely on $cf'user
+ # patch12: moved &init_signals to pl/signals.pl as &catch_signals
+ #
# Revision 3.0.1.2 1994/07/01 14:54:29 ram
# patch8: fixed leading From date format (spacing problem)
#
***************
*** 193,198 ****
--- 201,207 ----
$file_name = shift; # File name to be processed (null if stdin)
$ENV{'IFS'}='' if $ENV{'IFS'}; # Shell separation field
+ &init_constants; # Constants definitions
&get_configuration; # Get a suitable configuration package (cf)
select(STDOUT); # Because the -t option writes on STDOUT,
$| = 1; # make sure it is flushed before we fork()
***************
*** 237,249 ****
if (!$locked && !$nolock) {
# Another mailagent is running somewhere
! &queue_mail($file_name);
exit 0;
}
# Initialize mail filtering and compile filter rule if necessary
&init_all;
&compile_rules unless $norule;
# If rules are to be dumped, this is the only action
if ($dump_rule) {
--- 246,259 ----
if (!$locked && !$nolock) {
# Another mailagent is running somewhere
! &queue_mail($file_name, 'fm');
exit 0;
}
# Initialize mail filtering and compile filter rule if necessary
&init_all;
&compile_rules unless $norule;
+ &context'init; # Load context, initialize callout queue
# If rules are to be dumped, this is the only action
if ($dump_rule) {
***************
*** 286,292 ****
if (0 != &analyze_mail($file_name)) { # Analyze the mail
&add_log("ERROR while processing main message--queing it")
if ($loglvl > 0);
! &queue_mail($file_name);
unlink $lockfile;
exit 0; # Do not continue
} else {
--- 296,302 ----
if (0 != &analyze_mail($file_name)) { # Analyze the mail
&add_log("ERROR while processing main message--queing it")
if ($loglvl > 0);
! &queue_mail($file_name, 'fm');
unlink $lockfile;
exit 0; # Do not continue
} else {
***************
*** 364,371 ****
# Start-up initializations
sub init_all {
! &init_signals; # Trap common signals
! &init_constants; # Constants definitions
&init_interpreter; # Initialize tables %Priority, %Function, ...
&init_env; # Initialize the %XENV array
&init_matcher; # Initialize special matching functions
--- 374,380 ----
# Start-up initializations
sub init_all {
! &catch_signals; # Trap common signals
&init_interpreter; # Initialize tables %Priority, %Function, ...
&init_env; # Initialize the %XENV array
&init_matcher; # Initialize special matching functions
***************
*** 375,394 ****
&init_special; # Initialize special user table %Special
}
- # Protect ourselves (trap common signals)
- sub init_signals {
- $SIG{'HUP'} = 'emergency';
- $SIG{'INT'} = 'emergency';
- $SIG{'QUIT'} = 'emergency';
- $SIG{'PIPE'} = 'emergency';
- $SIG{'IO'} = 'emergency';
- $SIG{'BUS'} = 'emergency';
- $SIG{'ILL'} = 'emergency';
- $SIG{'SEGV'} = 'emergency';
- $SIG{'ALRM'} = 'emergency';
- $SIG{'TERM'} = 'emergency';
- }
-
# Constants definitions
sub init_constants {
require 'ctime.pl';
--- 384,389 ----
***************
*** 398,403 ****
--- 393,402 ----
$LOCK_NB = 4; # Make a non-blocking lock request
$LOCK_UN = 8; # Unlock the file
+ # Stat constants for file rights
+ $S_IWOTH = 02; # Writable by world (no .ph files here)
+ $S_IWGRP = 020; # Writable by group
+
# Status used by filter
$FT_RESTART = 0; # Abort current action, restart from scratch
$FT_CONT = 1; # Continue execution
***************
*** 432,437 ****
--- 431,439 ----
$now =~ s/\s(\d:\d\d:\d\d)\b/0$1/; # Add leading 0 if hour < 10
chop($now);
$FAKE_FROM = "From mailagent " . $now;
+
+ # Miscellaneous constants
+ $MAX_LINKS = 100; # Maximum number of symbolic link levels
}
# Initializes environment. All the variables are initialized in XENV array
***************
*** 493,500 ****
}
# Computes the e-mail address of the user
sub email_addr {
! $cf'user . '@' . &domain_addr; # E-mail address in internet format
}
# Domain name address for current host
--- 495,510 ----
}
# Computes the e-mail address of the user
+ # Can't rely on the value of $cf'user since config file may not have
+ # been parsed when this routine is first called.
sub email_addr {
! return $email_addr_cached if defined $email_addr_cached;
! local($user);
! ($user) = getpwuid($>);
! ($user) = getpwuid($<) unless $user;
! $user = 'nobody' unless $user;
! $email_addr_cached = $user . '@' . &domain_addr;
! return $email_addr_cached; # E-mail address in internet format
}
# Domain name address for current host
***************
*** 517,522 ****
--- 527,535 ----
$path; # Return possibly stripped path
}
+ # Compute absolute value -- on one line to avoid dataloading
+ sub abs { $_[0] > 0 ? $_[0] : -$_[0]; }
+
# Compute the system mailbox file name
sub mailbox_name {
# If ~/.mailagent provides us with a mail directory, use it and possibly
***************
*** 638,642 ****
--- 651,657 ----
$grep -v '^;#' pl/tilde.pl >>magent
$grep -v '^;#' pl/mh.pl >>magent
$grep -v '^;#' pl/umask.pl >>magent
+ $grep -v '^;#' pl/signals.pl >>magent
+ $grep -v '^;#' pl/callout.pl >>magent
chmod 755 magent
$eunicefix magent
Index: agent/pl/secure.pl
Prereq: 3.0
*** agent/pl/secure.pl.old Thu Sep 22 16:43:23 1994
--- agent/pl/secure.pl Thu Sep 22 16:43:23 1994
***************
*** 1,4 ****
! ;# $Id: secure.pl,v 3.0 1993/11/29 13:49:16 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
--- 1,4 ----
! ;# $Id: secure.pl,v 3.0.1.1 1994/09/22 14:38:04 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
***************
*** 9,14 ****
--- 9,17 ----
;# of the source tree for mailagent 3.0.
;#
;# $Log: secure.pl,v $
+ ;# Revision 3.0.1.1 1994/09/22 14:38:04 ram
+ ;# patch12: symbolic directories are now specially handled
+ ;#
;# Revision 3.0 1993/11/29 13:49:16 ram
;# Baseline for mailagent 3.0 netwide release.
;#
***************
*** 28,34 ****
return 0; # Unsecure file
}
local($ST_MODE) = 2 + $[; # Field st_mode from inode structure
- local($S_IWOTH) = 02; # Writable by world (no .ph files here)
unless (-O _) { # Reuse stat info from -e
&add_log("WARNING you do not own $type file $file") if $loglvl > 5;
return 0; # Unsecure file
--- 31,36 ----
***************
*** 38,49 ****
&add_log("WARNING $type file is world writable!") if $loglvl > 5;
return 0; # Unsecure file
}
return 1 unless $cf'secure =~ /on/i || $< == 0;
# Extra checks for secure mode (or if root user). We make sure the
# file is not writable by group and then we conduct the same secure tests
# on the directory itself
- local($S_IWGRP) = 020; # Writable by group
if ($st_mode & $S_IWGRP) {
&add_log("WARNING $type file is group writable!") if $loglvl > 5;
return 0; # Unsecure file
--- 40,51 ----
&add_log("WARNING $type file is world writable!") if $loglvl > 5;
return 0; # Unsecure file
}
+
return 1 unless $cf'secure =~ /on/i || $< == 0;
# Extra checks for secure mode (or if root user). We make sure the
# file is not writable by group and then we conduct the same secure tests
# on the directory itself
if ($st_mode & $S_IWGRP) {
&add_log("WARNING $type file is group writable!") if $loglvl > 5;
return 0; # Unsecure file
***************
*** 56,77 ****
return 0; # Unsecure directory, therefore unsecure file
}
$st_mode = (stat(_))[$ST_MODE];
! if ($st_mode & $S_IWOTH) {
! &add_log("WARNING directory of $type file is world writable!")
if $loglvl > 5;
return 0; # Unsecure directory
}
! if ($st_mode & $S_IWGRP) {
! &add_log("WARNING directory of $type file is group writable!")
if $loglvl > 5;
return 0; # Unsecure directory
}
! if (-l $dir) {
! &add_log("WARNING directory of $type file $file is a symbolic link")
if $loglvl > 5;
return 0; # Unsecure directory
}
!
! 1; # At last! File is secure...
}
--- 58,145 ----
return 0; # Unsecure directory, therefore unsecure file
}
$st_mode = (stat(_))[$ST_MODE];
! return 0 unless &check_st_mode($dir, 1);
!
! # If linkdirs is OFF, we do not check further when faced with a symbolic
! # link to a directory.
! if (-l $dir && $cf'linkdirs !~ /^off/i && !&symdir_secure($dir, $type)) {
! &add_log("WARNING directory of $type file $file is an unsecure symlink")
if $loglvl > 5;
return 0; # Unsecure directory
}
!
! 1; # At last! File is secure...
! }
!
! # Is a symbolic link to a directory secure?
! sub symdir_secure {
! local($dir, $type) = @_;
! if (&symdir_check($dir, 0)) {
! &add_log("symbolic directory $dir for $type file is secure")
! if $loglvl > 11;
! return 1;
! }
! 0; # Not secure
! }
!
! # A symbolic directory (that is a symlink pointing to a directory) is secure
! # if and only if:
! # - its target is a symlink that recursively proves to be secure.
! # - the target lies in a non world-writable directory
! # - the final directory at the end of the symlink chain is not world-writable
! # - less than $MAX_LINKS levels of indirection are needed to reach a real dir
! # Unfortunately, we cannot check for group writability here for the parent
! # target directory since the target might lie in a system directory which may
! # have a legitimate need to be read/write for root and wheel, for instance.
! # The routine returns 1 if the file is secure, 0 otherwise.
! sub symdir_check {
! local($dir, $level) = @_; # Directory, indirection level
! return 0 if $level++ > $MAX_LINKS;
! $dir = readlink($dir);
! unless (defined $dir) {
! &add_log("SYSERR readlink: $!") if $loglvl;
! return 0;
! }
! local($still_link) = -l _;
! unless (-d $dir || $still_link) {
! &add_log("ERROR inconsistency: $dir is a plain file?") if $loglvl;
! return 0; # Reached a plain file while following links to a dir!
! }
! unless (-d "$dir/..") {
! &add_log("ERROR inconsistency: $dir/.. is not a directory?") if $loglvl;
! return 0; # Reached a file hooked nowhere in the file system!
! }
! # Check parent directory
! local($ST_MODE) = 2 + $[; # Field st_mode from inode structure
! $st_mode = (stat(_))[$ST_MODE];
! return 0 unless &check_st_mode("$dir/..", 0);
! # Recurse if still a symbolic link
! if ($still_link) {
! return 0 unless &symdir_check($dir, $level);
! } else {
! $st_mode = (stat($dir))[$ST_MODE];
! return 0 unless &check_st_mode($dir, 1);
! }
! 1; # Ok, link is secure
! }
!
! # Returns true if mode in $st_mode does not include world or group writable
! # bits, false otherwise. This helps factorizing code used in both &file_secure
! # and &symdir_check. Set $both to true if both world/group checks are desirable,
! # false to get only world checks.
! sub check_st_mode {
! local($dir, $both) = @_;
! if ($st_mode & $S_IWOTH) {
! &add_log("WARNING directory of $type file $dir is world writable!")
if $loglvl > 5;
return 0; # Unsecure directory
}
! return 1 unless $both;
! if ($st_mode & $S_IWGRP) {
! &add_log("WARNING directory of $type file $dir is group writable!")
if $loglvl > 5;
return 0; # Unsecure directory
}
! 1;
}
Index: agent/pl/listqueue.pl
Prereq: 3.0.1.1
*** agent/pl/listqueue.pl.old Thu Sep 22 16:43:14 1994
--- agent/pl/listqueue.pl Thu Sep 22 16:43:15 1994
***************
*** 1,4 ****
! ;# $Id: listqueue.pl,v 3.0.1.1 1994/07/01 15:01:45 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
--- 1,4 ----
! ;# $Id: listqueue.pl,v 3.0.1.2 1994/09/22 14:26:00 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
***************
*** 9,14 ****
--- 9,18 ----
;# of the source tree for mailagent 3.0.
;#
;# $Log: listqueue.pl,v $
+ ;# Revision 3.0.1.2 1994/09/22 14:26:00 ram
+ ;# patch12: localized variables used by stat() and localtime()
+ ;# patch12: now knows about callout queue messages
+ ;#
;# Revision 3.0.1.1 1994/07/01 15:01:45 ram
;# patch8: now honours new queuehold and queuelost config variables
;#
***************
*** 26,32 ****
}
local(@dir) = readdir DIR; # Slurp the whole directory
closedir DIR;
! local(@files) = grep(s!^(q|f)m!$cf'queue/${1}m!, @dir);
undef @dir;
if (-f "$cf'queue/$agent_wait") {
if (open(WAITING, "$cf'queue/$agent_wait")) {
--- 30,36 ----
}
local(@dir) = readdir DIR; # Slurp the whole directory
closedir DIR;
! local(@files) = grep(s!^(q|f|c)m!$cf'queue/${1}m!, @dir);
undef @dir;
if (-f "$cf'queue/$agent_wait") {
if (open(WAITING, "$cf'queue/$agent_wait")) {
***************
*** 78,83 ****
--- 82,92 ----
.
local($n) = $#files + 1;
local($s) = $n > 1 ? 's' : '';
+ local($_);
+ local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks);
+ local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst);
+
print STDOUT " Mailagent Queue ($n request$s)\n";
foreach (@files) {
($directory, $file) = m|^(.*)/(.*)|;
***************
*** 110,121 ****
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
$status = '';
# If file has 'mbox.' as part of its name, then it is an emergency
# saving done by the mailagent. If it starts with 'logname', then it
# is an emergency saving done by the filter.
$file =~ s/^mbox\.// && ($status = 'Backup');
$file =~ s/^$cf'user\.// && ($status = 'Backup');
! if ($file =~ /^qm/ && (time - $mtime) < $cf'queuehold) {
# Queue mails starting with 'qm' have been queued by the filter
# program. To avoid race conditions, those mails are skipped for
# some time (cf to pqueue subroutine).
--- 119,144 ----
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks) = stat(_);
$status = '';
+
# If file has 'mbox.' as part of its name, then it is an emergency
# saving done by the mailagent. If it starts with 'logname', then it
# is an emergency saving done by the filter.
+
$file =~ s/^mbox\.// && ($status = 'Backup');
$file =~ s/^$cf'user\.// && ($status = 'Backup');
!
! # Check for callout queue file. If it is a 'cm' file, or it is not in
! # the queue and is recorded in the callout queue, then it is marked
! # as a callout file and the queue time printed will be the trigger
! # time.
!
! if (
! $file =~ /^cm/ ||
! ($directory ne $cf'queue && &callout'trigger($_))
! ) {
! $mtime = &callout'trigger($_); # May be called twice, that's ok.
! $status = 'Callout';
! } elsif ($file =~ /^qm/ && (time - $mtime) < $cf'queuehold) {
# Queue mails starting with 'qm' have been queued by the filter
# program. To avoid race conditions, those mails are skipped for
# some time (cf to pqueue subroutine).
***************
*** 124,136 ****
# Processing of mail allowed (mailagent -q would flush it)
$status = 'Deferred' unless $status;
}
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($mtime);
$queued = sprintf("%.2d/%.2d-%.2d:%.2d", ++$mon,$mday,$hour,$min);
! $queued = 'Now' if (time - $mtime) < 60;
$star = '';
$star = '*' if $directory ne $cf'queue; # Spot out-of-queue mails
! if ((time - $mtime) > $cf'queuelost) { # Also spot old mails
$star = '#';
$star = '@' if $directory ne $cf'queue;
}
--- 147,165 ----
# Processing of mail allowed (mailagent -q would flush it)
$status = 'Deferred' unless $status;
}
+
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($mtime);
$queued = sprintf("%.2d/%.2d-%.2d:%.2d", ++$mon,$mday,$hour,$min);
! $queued = 'Now' if &'abs(time - $mtime) < 60;
$star = '';
$star = '*' if $directory ne $cf'queue; # Spot out-of-queue mails
! if ($status ne 'Callout') {
! if ((time - $mtime) > $cf'queuelost) { # Also spot old mails
! $star = '#';
! $star = '@' if $directory ne $cf'queue;
! }
! } elsif (time > $mtime) { # Spot callouts that should have triggered
$star = '#';
$star = '@' if $directory ne $cf'queue;
}
Index: agent/pl/context.pl
Prereq: 3.0
*** agent/pl/context.pl.old Thu Sep 22 16:43:07 1994
--- agent/pl/context.pl Thu Sep 22 16:43:08 1994
***************
*** 1,4 ****
! ;# $Id: context.pl,v 3.0 1993/11/29 13:48:38 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
--- 1,4 ----
! ;# $Id: context.pl,v 3.0.1.1 1994/09/22 14:16:30 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
***************
*** 9,14 ****
--- 9,19 ----
;# of the source tree for mailagent 3.0.
;#
;# $Log: context.pl,v $
+ ;# Revision 3.0.1.1 1994/09/22 14:16:30 ram
+ ;# patch12: added access routines to detect context changes
+ ;# patch12: context is now written back to disk only when changed
+ ;# patch12: added callout queue knowledge
+ ;#
;# Revision 3.0 1993/11/29 13:48:38 ram
;# Baseline for mailagent 3.0 netwide release.
;#
***************
*** 25,32 ****
# Initialize context from context file
sub init {
&default; # Load a default context
! return unless -f $cf'context; # Finished if no saved context
! &load; # Load context, overwriting default context
&clean; # Remove uneeded entries from context
}
--- 30,37 ----
# Initialize context from context file
sub init {
&default; # Load a default context
! &load if -f $cf'context; # Load context, overwriting default context
! &callout'init; # Initialize callout queue
&clean; # Remove uneeded entries from context
}
***************
*** 59,74 ****
# Clean context, removing useless entries
sub clean {
! delete $Context{'last-clean'} unless $cf'autoclean =~ /^on/i;
}
! # Save a new context file
sub save {
require 'ctime.pl';
local($existed) = -f $cf'context;
&'acs_rqst($cf'context) if $existed; # Lock existing file
unless (open(CONTEXT, ">$cf'context")) {
&'add_log("ERROR cannot overwrite context file: $!") if $'loglvl > 1;
return;
}
&'add_log("saving context file $cf'context") if $'loglvl > 17;
--- 64,81 ----
# Clean context, removing useless entries
sub clean {
! &delete('last-clean') if $cf'autoclean !~ /^on/i && &get('last-clean');
}
! # Save a new context file, if it has changed since we read it.
sub save {
+ return unless $context_changed; # Do not save if no change
require 'ctime.pl';
local($existed) = -f $cf'context;
&'acs_rqst($cf'context) if $existed; # Lock existing file
unless (open(CONTEXT, ">$cf'context")) {
&'add_log("ERROR cannot overwrite context file: $!") if $'loglvl > 1;
+ &'free_file($cf'context) if $existed;
return;
}
&'add_log("saving context file $cf'context") if $'loglvl > 17;
***************
*** 86,91 ****
--- 93,127 ----
}
#
+ # Access features
+ #
+
+ # Add or set an entry in the context
+ sub set {
+ local($entry, $value) = @_;
+ $Context{$entry} = $value;
+ $context_changed++;
+ }
+
+ # Get a context entry value
+ sub get {
+ local($entry) = @_;
+ defined $Context{$entry} ? $Context{$entry} : undef;
+ }
+
+ # Delete an entry from context
+ sub delete {
+ local($entry) = @_;
+ unless (defined $Context{$entry}) {
+ &'add_log("WARNING attempting to delete inexistant $entry context")
+ if $'loglvl > 5;
+ return;
+ }
+ delete $Context{$entry};
+ $context_changed++;
+ }
+
+ #
# Context-dependant actions
#
***************
*** 96,107 ****
sub autoclean {
return unless $cf'autoclean =~ /^on/i;
local($period) = &'seconds_in_period($cf'cleanlaps);
! return if ($Context{'last-clean'} + $period) > time;
# Retry time reached -- start auto cleaning
&'add_log("autocleaning of dbr files") if $'loglvl > 8;
$period = &'seconds_in_period($cf'agemax);
&dbr'clean($period);
! $Context{'last-clean'} = time; # Update last cleaning time
}
#
--- 132,143 ----
sub autoclean {
return unless $cf'autoclean =~ /^on/i;
local($period) = &'seconds_in_period($cf'cleanlaps);
! return if (&get('last-clean') + $period) > time;
# Retry time reached -- start auto cleaning
&'add_log("autocleaning of dbr files") if $'loglvl > 8;
$period = &'seconds_in_period($cf'agemax);
&dbr'clean($period);
! &set('last-clean', time); # Update last cleaning time
}
#
***************
*** 112,119 ****
# the retry time was not reached. This routine is the main entry point in
# the package, and is the only one called from the outside world.
sub main'contextual_operations {
- &init; # Initialize context
&autoclean; # Clean dbr hash files
&save; # Save new context
}
--- 148,155 ----
# the retry time was not reached. This routine is the main entry point in
# the package, and is the only one called from the outside world.
sub main'contextual_operations {
&autoclean; # Clean dbr hash files
+ &callout'flush; # Flush the callout queue
&save; # Save new context
}
Index: agent/filter/parser.c
Prereq: 3.0.1.2
*** agent/filter/parser.c.old Thu Sep 22 16:42:53 1994
--- agent/filter/parser.c Thu Sep 22 16:42:53 1994
***************
*** 11,17 ****
*/
/*
! * $Id: parser.c,v 3.0.1.2 1994/07/01 14:53:57 ram Exp $
*
* Copyright (c) 1990-1993, Raphael Manfredi
*
--- 11,17 ----
*/
/*
! * $Id: parser.c,v 3.0.1.3 1994/09/22 13:47:21 ram Exp $
*
* Copyright (c) 1990-1993, Raphael Manfredi
*
***************
*** 22,27 ****
--- 22,30 ----
* of the source tree for mailagent 3.0.
*
* $Log: parser.c,v $
+ * Revision 3.0.1.3 1994/09/22 13:47:21 ram
+ * patch12: extended security checks to mimic those done by mailagent
+ *
* Revision 3.0.1.2 1994/07/01 14:53:57 ram
* patch8: new routine get_confval to get integer config variables
*
***************
*** 52,57 ****
--- 55,67 ----
#include <strings.h>
#endif
+ #ifdef I_SYS_PARAM
+ #include <sys/param.h>
+ #endif
+ #ifndef MAX_PATHLEN
+ #define MAX_PATHLEN 2048 /* Maximum path length allowed by kernel */
+ #endif
+
#ifndef HAS_GETHOSTNAME
#ifdef HAS_UNAME
#include <sys/utsname.h>
***************
*** 180,186 ****
* Returning from this routine implies that the security checks succeeded.
*/
! struct stat buf; /* Statistics buffer */
if (-1 == stat(file, &buf)) {
add_log(1, "SYSERR stat: %m (%e)");
--- 190,196 ----
* Returning from this routine implies that the security checks succeeded.
*/
! struct stat buf; /* Statistics buffer */
if (-1 == stat(file, &buf)) {
add_log(1, "SYSERR stat: %m (%e)");
***************
*** 195,204 ****
{
/* Check basic permissions on the specified file. It cannot be world
* writable and must be owned by the user. If the file specified does not
! * exist, no error is reported however.
*/
! struct stat buf; /* Statistics buffer */
if (-1 == stat(file, &buf))
return;
--- 205,220 ----
{
/* Check basic permissions on the specified file. It cannot be world
* writable and must be owned by the user. If the file specified does not
! * exist, no error is reported however. If the 'secure' option is set
! * to ON, or if we are running with superuser credentials, further checks
! * are performed on the directory containing the file.
*/
! struct stat buf; /* Statistics buffer */
! char parent[MAX_PATHLEN+1]; /* For parent directory */
! char *cfsecure; /* Config value for the 'secure' parameter */
! char *c; /* Last slash position in file name */
! int wants_secure = 0; /* Set to true for extra security checks */
if (-1 == stat(file, &buf))
return;
***************
*** 212,217 ****
--- 228,290 ----
if (buf.st_uid != geteuid())
fatal("file %s not owned by user!", file);
+
+ cfsecure = ht_value(&symtab, "secure"); /* Do we need extra security? */
+ if (
+ (cfsecure != (char *) 0 && /* Ok, secure is defined */
+ 0 == strcasecmp(cfsecure, "ON")) || /* And extra checks wanted */
+ geteuid() == ROOTID /* Running as superuser */
+ )
+ wants_secure = 1; /* Activate checks */
+
+ if (!wants_secure) {
+ add_log(12, "basic checks ok for file %s", file);
+ return;
+ }
+
+ /*
+ * Extra security checks for group writability and parent directory.
+ */
+
+ add_log(17, "performing additional checks on %s", file);
+
+ #ifndef S_IWGRP
+ #define S_IWGRP 00020 /* Write permissions for group */
+ #endif
+
+ if (buf.st_mode & S_IWGRP)
+ fatal("file %s is group writable!", file);
+
+ /*
+ * Ok, go on and check the parent directory...
+ */
+
+ if (*file != '/') { /* Path is not abosule, assume from home */
+ strcpy(parent, home); /* Prefill with home */
+ strcat(parent, "/");
+ } else
+ *parent = '\0'; /* Null string */
+ strcat(parent, file); /* Append file to get an absolute path */
+ if (c = rindex(parent, '/'))
+ *c = '\0'; /* Strip down last path component */
+
+ add_log(17, "checking directory %s", parent);
+
+ if (-1 == stat(parent, &buf)) {
+ add_log(1, "SYSERR stat: %m (%e)");
+ fatal("cannot stat directory %s", parent);
+ }
+
+ if (buf.st_mode & S_IWOTH)
+ fatal("directory %s is world writable!", parent);
+
+ if (buf.st_mode & S_IWGRP)
+ fatal("directory %s is group writable!", parent);
+
+ if (buf.st_uid != geteuid())
+ fatal("directory %s not owned by user!", parent);
+
+ add_log(12, "file %s seems to be secure", file);
}
public char *homedir()
Index: agent/pl/builtins.pl
Prereq: 3.0
*** agent/pl/builtins.pl.old Thu Sep 22 16:43:06 1994
--- agent/pl/builtins.pl Thu Sep 22 16:43:06 1994
***************
*** 1,4 ****
! ;# $Id: builtins.pl,v 3.0 1993/11/29 13:48:35 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
--- 1,4 ----
! ;# $Id: builtins.pl,v 3.0.1.1 1994/09/22 14:10:40 ram Exp $
;#
;# Copyright (c) 1990-1993, Raphael Manfredi
;#
***************
*** 9,14 ****
--- 9,18 ----
;# of the source tree for mailagent 3.0.
;#
;# $Log: builtins.pl,v $
+ ;# Revision 3.0.1.1 1994/09/22 14:10:40 ram
+ ;# patch12: added escapes in strings for perl5 support
+ ;# patch12: builtins are now looked for in &run_builtins
+ ;#
;# Revision 3.0 1993/11/29 13:48:35 ram
;# Baseline for mailagent 3.0 netwide release.
;#
***************
*** 92,103 ****
# The @RR command asks for a receipt
sub builtin_rr {
local($_) = @_;
! &add_log("found an @RR request to $_") if $loglvl > 18;
# @RR request honored only if not from special user and directed to us
unless (&special_user) {
push(@Builtcode, "&send_receipt('$_')");
} else {
! &add_log("ignoring @RR request to $_") if $loglvl > 4;
}
}
--- 96,107 ----
# The @RR command asks for a receipt
sub builtin_rr {
local($_) = @_;
! &add_log("found an \@RR request to $_") if $loglvl > 18;
# @RR request honored only if not from special user and directed to us
unless (&special_user) {
push(@Builtcode, "&send_receipt('$_')");
} else {
! &add_log("ignoring \@RR request to $_") if $loglvl > 4;
}
}
***************
*** 106,120 ****
local($_) = @_;
return if /[=\$^&*([{}`\\|;><?]/; # Invalid character found
$Userpath = $_;
! &add_log("found an @PATH request to $_") if $loglvl > 18;
}
# Execute stacked builtins
sub run_builtins {
return if $#Builtcode < 0; # No recorded builtins
foreach (@Builtcode) {
eval($_); # Execute stacked builtin
}
! @Builtcode = (); # Reset builtcode array
}
--- 110,136 ----
local($_) = @_;
return if /[=\$^&*([{}`\\|;><?]/; # Invalid character found
$Userpath = $_;
! &add_log("found an \@PATH request to $_") if $loglvl > 18;
}
# Execute stacked builtins
sub run_builtins {
+ undef @Builtcode;
+ # Lookup for builtins. Code moved out of &parse_mail.
+ foreach $line (split(/\n/, $Header{'Body'})) {
+ if ($line =~ s/^@(\w+)\s*//) { # A builtin command ?
+ local($subroutine) = $Builtin{$1};
+ &$subroutine($line) if $subroutine; # Record it if known
+ }
+ }
+ # End of original &parse_mail exerpt, beginning of original &run_builtins
+ # NOTE: since builtins are now looked for here and run from there directly,
+ # going through the burden of @Builtcode is not necessary. Will get fixed
+ # one day, possibly.
return if $#Builtcode < 0; # No recorded builtins
foreach (@Builtcode) {
eval($_); # Execute stacked builtin
}
! undef @Builtcode; # Reset builtcode array
}
*** End of Patch 14 ***
exit 0 # Just in case...