#!/usr/bin/perl
	eval 'exec perl -S $0 "$@"'
		if $running_under_some_shell;

#
# This perl program uses dynamic loading [generated by perload]
#

# You'll need to set up a .forward file that feeds your mail to this script,
# via the filter. Mine looks like this:
#   "|exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"

# $Id: magent.sh,v 3.0.1.17 2001/03/17 18:07:49 ram Exp ram $
#
#  Copyright (c) 1990-2006, 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: magent.sh,v $
# Revision 3.0.1.17  2001/03/17 18:07:49  ram
# patch72: mydomain and hiddennet now superseded by config vars
# patch72: changed email_addr() and domain_addr() to honour new config vars
#
# Revision 3.0.1.16  1999/01/13  18:08:48  ram
# patch64: changed agent_wait to AGENT_WAIT, now holding full path
#
# Revision 3.0.1.15  1997/09/15  15:05:06  ram
# patch57: call new pmail() routine to process main message
# patch57: fixed typo in -r usage
#
# Revision 3.0.1.14  1997/02/20  11:39:31  ram
# patch55: used  variable for no purpose
#
# Revision 3.0.1.13  1996/12/24  14:06:02  ram
# patch45: rule file path is now absolute, so caching can be safe
# patch45: changed queue processing/sleeping logic for better interactivity
# patch45: new stat constants, and updated usage line
#
# Revision 3.0.1.12  1995/09/15  13:54:28  ram
# patch43: rewrote mbox_lock routine to deal with new locksafe variable
# patch43: will now warn if configured to do flock() but can't actually
# patch43: can now be configured to do safe or allow partial mbox locking
#
# Revision 3.0.1.11  1995/08/31  16:26:54  ram
# patch42: forced numeric value when reading the Length header
#
# Revision 3.0.1.10  1995/08/07  16:12:03  ram
# patch37: now remove mailagent's lock as soon as possible before exiting
# patch37: added support for locking on filesystems with short filenames
#
# Revision 3.0.1.9  1995/03/21  12:54:50  ram
# patch35: added pl/cdir.pl to the list of appended files
#
# Revision 3.0.1.8  1995/02/16  14:24:42  ram
# patch32: new -I option for installation setup and checking
# patch32: usage message now sorts options by case type
#
# Revision 3.0.1.7  1995/02/03  17:57:16  ram
# patch30: also select hot piping on stderr to avoid problems on fork
#
# Revision 3.0.1.6  1995/01/03  17:56:52  ram
# patch24: new library files pl/rulenv.pl and pl/options.pl included
# patch24: no longer uses pl/umask.pl
#
# Revision 3.0.1.5  1994/10/29  17:40:14  ram
# patch20: added built-in biffing support
#
# Revision 3.0.1.4  1994/10/04  17:34:14  ram
# patch17: no longer report errors when orgname file is missing
# patch17: mailbox locking now uses customized mboxlock parameter
#
# 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 , ,  and &abs
# patch12: changed &email_addr to cache its result and not rely on '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)
#
# Revision 3.0.1.1  1994/01/26  09:27:56  ram
# patch5: new -F option to force procesing on filtered messages
#
# Revision 3.0  1993/11/29  13:48:22  ram
# Baseline for mailagent 3.0 netwide release.
#

# Perload ON

#
# The following were determined by Configure...
#

# Command used to compute hostname
$phostname = 'hostname';

# Our domain name
$mydomain = '.Unconfigured.Mailagent.Domain';

# Hidden network (advertised host)
$hiddennet = '';

# Directory where mail is spooled
$maildir = '/var/spool/mail';

# File in which mail is stored
$mailfile = '/var/spool/mail/%L';

# Current version number and patchlevel
$mversion = '3.1';
$patchlevel = '0';
$revision = '78';

# Want to lock mailboxes with flock ?
$lock_by_flock = '';

# Only use flock() and no .lock file
$flock_only = '';

# Our organization name
$orgname = '/etc/news/organization';

# Private mailagent library
$privlib = '/usr/share/mailagent';

# News posting program
$inews = 'inews';

# Mail sending program
$mailer = 'mail';

# Can we have filenames longer than 14 characters?
$long_filenames = 'define' eq 'define';

#
# End of configuration section.
#

$prog_name = $0;				# Who I am
$prog_name =~ s|^.*/(.*)|$1|;	# Keep only base name
$has_option = 0;				# True if invoked with options
$nolock = 0;					# Do we need to get a lock file?
$config_file = '~/.mailagent';	# Default configuration file
$log_level = -1;				# Changed by -L option

# Calling the mailagent as 'mailqueue' lists the queue
if ($prog_name eq 'mailqueue') {
	unshift(@ARGV, '-l');
}

# Parse options
while ($ARGV[0] =~ /^-/) {
	$_ = shift;
	last if /--/;
	if ($_ eq '-c') {		# Specify alternate configuration file
		++$nolock;			# Immediate processing wanted
		$config_file = shift;
	}
	elsif ($_ eq '-d') {	# Dump rules
		++$has_option;		# Incompatible with other special options
		++$dump_rule;
	}
	elsif ($_ eq '-e') {	# Rule supplied on command line
		$_ = shift;
		s/\n/ /g;
		push(@Linerules, $_);
		++$edited_rules;	# Signals rules came from command line
		++$nolock;			# Immediate processing wanted
	}
	elsif ($_ eq '-f') {	# Take messages from UNIX mailbox
		++$nolock;			# Immediate processing wanted
		++$mbox_mail;
		$mbox_file = shift;	# -f followed by file name
	}
	elsif ($_ eq '-h') {	# Usage help
		&usage;
	}
	elsif ($_ eq '-i') {	# Interactive mode: log messages also on stderr
		*add_log = *stderr_log;
	}
	elsif ($_ eq '-l') {	# List queue
		++$has_option;		# Incompatible with other special options
		++$list_queue;
		++$norule;			# No need to compile rules
	}
	elsif ($_ eq '-o') {	# Overwrite configuration variable
		++$nolock;			# Immediate processing wanted
		$over_config .= "\n" . shift;
	}
	elsif ($_ eq '-q') {	# Process the queue
		++$has_option;		# Incompatible with other special options
		++$run_queue;
	}
	elsif ($_ eq '-r') {	# Specify alternate rule file
		++$nolock;			# Immediate processing wanted
		$rule_file = shift;
		$rule_file = &cdir($rule_file);		# Make it an absolute path
	}
	elsif (/^-s(\S*)/) {	# Print statistics
		++$has_option;		# Incompatible with other special options
		++$stats;
		++$norule;			# No need to compile rules
		$stats_opt = $1;
	}
	elsif ($_ eq '-t') {	# Track rule matches on stdout
		++$track_all;
	}
	elsif ($_ eq '-F') {	# Force processing, even if already seen
		++$force_seen;
	}
	elsif ($_ eq '-I') {	# Install a suitable mailagent environment...
		++$has_option;		# That option must be the only one specified
		++$install_me;
	}
	elsif ($_ eq '-L') {	# Specify new logging level
		$log_level = int(shift);
	}
	elsif ($_ eq '-V') {	# Version number
		print STDERR "$prog_name $mversion-$revision\n";
		exit 0;
	}
	elsif ($_ eq '-U') {	# Do not allow UNIQUE to reject / abort
		++$disable_unique;
	}
	elsif ($_ eq '-TEST') {	# Mailagent run via TEST (undocumented feature)
		++$test_mode;
	}
	else {
		print STDERR "$prog_name: unknown option: $_\n";
		&usage;
	}
}

++$nolock if $has_option;		# No need to take a lock with special options

# Only one option at a time (among those options which change our goal)
if ($has_option > 1) {
	print STDERR "$prog_name: at most one special option may be specified.\n";
	exit 1;
}

exit(&cf'setup) if $install_me;	# Get a suitable configuration if -I

$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)
&patch_constants;				# Change some constants after config
select(STDERR); $| = 1;			# In case we get perl warnings...
select(STDOUT);					# and because the -t option writes on STDOUT,
$| = 1;							# make sure it is flushed before we fork().
$privlib = "$cf'home/../.." if $test_mode;	# Tests ran from test/out
$AGENT_WAIT = "$cf'spool/agent.wait";		# Waiting file for mails

$orgname = &tilda_expand($orgname);		# Perform run-time ~name substitution

if ($orgname =~ m|^/|) {		# Name of organization kept in file
	unless (open(ORG, $orgname)) {
		&add_log("ERROR cannot read $orgname: $!") if $loglvl && -f $orgname;
	} else {
		chop($orgname = <ORG>);
		close ORG;
	}
}

$ENV{'HOME'} = $cf'home;
$ENV{'USER'} = $cf'user;
$ENV{'NAME'} = $cf'name;
$baselock = "$cf'spool/perl";	# This file does not exist
$lockext = $long_filenames ? '.lock' : '!';	# Extension used by lock routines
$lockfile = $baselock . $lockext;

umask(077);						# Files we create are private ones
$jobnum = &jobnum;				# Compute a job number

# Allow only ONE mailagent at a time (resource consumming)
&checklock($baselock);			# Make sure old locks do not remain
unless (-f $lockfile) {
	# Try to get the lock file (acting as a token). We do not need locking if
	# we have been invoked with an option and that option is not -q.
	if ($nolock && !$run_queue) {
		&add_log("no need to get a lock") if $loglvl > 19;
	} elsif (0 == &acs_rqst($baselock)) {
		&add_log("got the right to process mail") if $loglvl > 19;
		++$locked;
	} else {
		&add_log("denied right to process mail") if $loglvl > 19;
	}
}

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) {
	&dump_rules(*print_rule_number, *void_func);
	unlink $lockfile if $locked;
	exit 0;
}

# Likewise, statistics dumping is the only option
if ($stats) {
	&report_stats($stats_opt);
	unlink $lockfile if $locked;
	exit 0;
}

# Listing the queue is also the only performed action
if ($list_queue) {
	&list_queue;
	unlink $lockfile if $locked;
	exit 0;
}

# Taking messages from mailbox file
if ($mbox_mail) {
	++$run_queue if 0 == &mbox_mail($mbox_file);
	unless ($run_queue) {
		unlink $lockfile if $locked;
		exit 1;		# -f failed
	}
	&add_log("processing queued mails") if $loglvl > 15;
}

# Suppress statistics when mailagent invoked manually (i.e. not in test mode)
&no_stats if $nolock && !$test_mode;

&read_stats;					# Load statistics into memory for fast update
&newcmd'load if $cf'newcmd;		# Load user-defined command definitions

#
# If -q is not specfied, we need to process the file which was given to us
# on the command line. We're calling pmail() to process it via locking,
# but unfortunately we can't allow pmail() to unlink the processed file,
# because it might be something the user wants to keep around...
# However, if we were invoked by the filter program, the processed mail
# will be unlinked later on. The trouble is the file was unlocked and
# there is a slight time window were the message could be processed again by
# another mailagent. If the 'queuehold' variable is reasonably set, such a
# message will be skipped anyway, so it's not that critical.
#

my $process_queue = 1;

if (!$run_queue) {				# Do not enter here if -q
	if (0 != &pmail($file_name, 0)) {
		&add_log("ERROR while processing main message--queing it") if $loglvl;
		&queue_mail($file_name, 'fm');
		unlink $lockfile;
		exit 0;					# Do not continue
	} 

	# If invoked from a tty and not in test mode, do not process queue
	$process_queue = 0 if -t STDOUT && !$test_mode; 
}

if ($process_queue) {
	unless ($test_mode) {
		# Fork a child: we have to take care of the filter script which is
		# waiting for us to finish processing of the delivered mail.
		&fork_child() unless $run_queue;

		# From now on, we are in the child process...
		# Don't sleep at all if logging level is greater that 11
		# or if $run_queue is true. Logging level of 12 and higher are
		# for debugging and should not be used on a permanent basis
		# anyway.

		$sleep = 1;					# Give others a chance to queue their mail
		$sleep = 0 if $loglvl > 11 || $run_queue;

		do {						# Eventually process the queue
			sleep 30 if $sleep;		# Wait in case new mail arrives
		} while (&pqueue);
	} else {
		&pqueue;					# Process the queue once in test mode
	}
}

# Mailagent is exiting. Remove lock file as early as possible to avoid a
# race condition: another mailagent could start up and decide another one
# is already processing mail, but since we're about to exit...
unlink $lockfile if $locked;
&add_log("mailagent exits") if $loglvl > 17;

# End of mailagent processing
&write_stats;					# Resynchronizes the statistics file
&compress'recompress;			# Compress some of the folders we delivered to
&contextual_operations;			# Perform all the contextual operations
exit 0;

sub main'usage { &auto_main'usage; }
sub auto_main'usage { &main'dataload; }

sub main'get_configuration { &auto_main'get_configuration; }
sub auto_main'get_configuration { &main'dataload; }

#
# The filtering routines
#

sub main'init_all { &auto_main'init_all; }
sub auto_main'init_all { &main'dataload; }

sub main'init_constants { &auto_main'init_constants; }
sub auto_main'init_constants { &main'dataload; }

sub main'patch_constants { &auto_main'patch_constants; }
sub auto_main'patch_constants { &main'dataload; }

sub main'init_env { &auto_main'init_env; }
sub auto_main'init_env { &main'dataload; }

sub main'init_pseudokey { &auto_main'init_pseudokey; }
sub auto_main'init_pseudokey { &main'dataload; }

#
# Miscellaneous utilities
#

sub main'mbox_lock { &auto_main'mbox_lock; }
sub auto_main'mbox_lock { &main'dataload; }

sub main'mbox_unlock { &auto_main'mbox_unlock; }
sub auto_main'mbox_unlock { &main'dataload; }

sub main'email_addr { &auto_main'email_addr; }
sub auto_main'email_addr { &main'dataload; }

sub main'domain_addr { &auto_main'domain_addr; }
sub auto_main'domain_addr { &main'dataload; }

sub main'tilda { &auto_main'tilda; }
sub auto_main'tilda { &main'dataload; }

# Compute absolute value -- on one line to avoid dataloading
sub abs { $_[0] > 0 ? $_[0] : -$_[0]; }

sub main'mailbox_name { &auto_main'mailbox_name; }
sub auto_main'mailbox_name { &main'dataload; }

sub main'fork_child { &auto_main'fork_child; }
sub auto_main'fork_child { &main'dataload; }

sub main'eval_error { &auto_main'eval_error; }
sub auto_main'eval_error { &main'dataload; }

sub main'jobnum { &auto_main'jobnum; }
sub auto_main'jobnum { &main'dataload; }

package cf;

# This package is responsible for keeping track of the configuration variables.

sub main'read_config { &auto_main'read_config; }
sub auto_main'read_config { &main'dataload; }

sub cf'parse { &auto_cf'parse; }
sub auto_cf'parse { &main'dataload; }

package main;

sub main'acs_rqst { &auto_main'acs_rqst; }
sub auto_main'acs_rqst { &main'dataload; }

sub main'acs_locktry { &auto_main'acs_locktry; }
sub auto_main'acs_locktry { &main'dataload; }

sub main'acs_lock { &auto_main'acs_lock; }
sub auto_main'acs_lock { &main'dataload; }

package lock;

sub lock'file { &auto_lock'file; }
sub auto_lock'file { &main'dataload; }

sub lock'base { &auto_lock'base; }
sub auto_lock'base { &main'dataload; }

sub lock'dir { &auto_lock'dir; }
sub auto_lock'dir { &main'dataload; }

package main;

sub main'free_file { &auto_main'free_file; }
sub auto_main'free_file { &main'dataload; }

sub main'add_log { &auto_main'add_log; }
sub auto_main'add_log { &main'dataload; }

sub main'stderr_log { &auto_main'stderr_log; }
sub auto_main'stderr_log { &main'dataload; }

sub main'stdout_log { &auto_main'stdout_log; }
sub auto_main'stdout_log { &main'dataload; }

#
# User-defined log files
#

package usrlog;

sub usrlog'new { &auto_usrlog'new; }
sub auto_usrlog'new { &main'dataload; }

sub usrlog'delete { &auto_usrlog'delete; }
sub auto_usrlog'delete { &main'dataload; }

sub main'usr_log { &auto_main'usr_log; }
sub auto_main'usr_log { &main'dataload; }

sub usrlog'write_log { &auto_usrlog'write_log; }
sub auto_usrlog'write_log { &main'dataload; }

package main;

sub main'checklock { &auto_main'checklock; }
sub auto_main'checklock { &main'dataload; }

#
# Lexical parsing of the rules
#

sub main'read_filerule { &auto_main'read_filerule; }
sub auto_main'read_filerule { &main'dataload; }

sub main'read_linerule { &auto_main'read_linerule; }
sub auto_main'read_linerule { &main'dataload; }

sub main'get_line { &auto_main'get_line; }
sub auto_main'get_line { &main'dataload; }

sub main'get_mode { &auto_main'get_mode; }
sub auto_main'get_mode { &main'dataload; }

sub main'get_selector { &auto_main'get_selector; }
sub auto_main'get_selector { &main'dataload; }

sub main'get_pattern { &auto_main'get_pattern; }
sub auto_main'get_pattern { &main'dataload; }

sub main'get_action { &auto_main'get_action; }
sub auto_main'get_action { &main'dataload; }

sub main'action_parse { &auto_main'action_parse; }
sub auto_main'action_parse { &main'dataload; }

#
# Parsing mail
#

sub main'parse_mail { &auto_main'parse_mail; }
sub auto_main'parse_mail { &main'dataload; }

sub main'header_parse { &auto_main'header_parse; }
sub auto_main'header_parse { &main'dataload; }

sub main'header_lines { &auto_main'header_lines; }
sub auto_main'header_lines { &main'dataload; }

sub main'header_update_size { &auto_main'header_update_size; }
sub auto_main'header_update_size { &main'dataload; }

sub main'body_check { &auto_main'body_check; }
sub auto_main'body_check { &main'dataload; }

sub main'body_recode_with { &auto_main'body_recode_with; }
sub auto_main'body_recode_with { &main'dataload; }

sub main'body_recode { &auto_main'body_recode; }
sub auto_main'body_recode { &main'dataload; }

sub main'body_recode_optimally { &auto_main'body_recode_optimally; }
sub auto_main'body_recode_optimally { &main'dataload; }

sub main'header_check_body_encoding { &auto_main'header_check_body_encoding; }
sub auto_main'header_check_body_encoding { &main'dataload; }

sub main'header_check { &auto_main'header_check; }
sub auto_main'header_check { &main'dataload; }

sub main'relay_list { &auto_main'relay_list; }
sub auto_main'relay_list { &main'dataload; }

sub main'header_append { &auto_main'header_append; }
sub auto_main'header_append { &main'dataload; }

sub main'header_prepend { &auto_main'header_prepend; }
sub auto_main'header_prepend { &main'dataload; }

sub main'best_body_encoding { &auto_main'best_body_encoding; }
sub auto_main'best_body_encoding { &main'dataload; }

#
# Analyzing mail
#

sub main'init_special { &auto_main'init_special; }
sub auto_main'init_special { &main'dataload; }

sub main'mail_logname { &auto_main'mail_logname; }
sub auto_main'mail_logname { &main'dataload; }

sub main'mail_logsize { &auto_main'mail_logsize; }
sub auto_main'mail_logsize { &main'dataload; }

sub main'analyze_mail { &auto_main'analyze_mail; }
sub auto_main'analyze_mail { &main'dataload; }

sub main'apply_rules { &auto_main'apply_rules; }
sub auto_main'apply_rules { &main'dataload; }

sub main'right_mode { &auto_main'right_mode; }
sub auto_main'right_mode { &main'dataload; }

sub main'special_user { &auto_main'special_user; }
sub auto_main'special_user { &main'dataload; }

sub main'fuzzy_domain { &auto_main'fuzzy_domain; }
sub auto_main'fuzzy_domain { &main'dataload; }

sub main'reception { &auto_main'reception; }
sub auto_main'reception { &main'dataload; }

sub main'track_rule { &auto_main'track_rule; }
sub auto_main'track_rule { &main'dataload; }


sub main'xeqte { &auto_main'xeqte; }
sub auto_main'xeqte { &main'dataload; }

sub main'run_command { &auto_main'run_command; }
sub auto_main'run_command { &main'dataload; }

sub main'init_filter { &auto_main'init_filter; }
sub auto_main'init_filter { &main'dataload; }

#
# Filter commands are run from here
#

sub main'run_process { &auto_main'run_process; }
sub auto_main'run_process { &main'dataload; }

sub main'run_server { &auto_main'run_server; }
sub auto_main'run_server { &main'dataload; }

sub main'run_leave { &auto_main'run_leave; }
sub auto_main'run_leave { &main'dataload; }

sub main'run_save { &auto_main'run_save; }
sub auto_main'run_save { &main'dataload; }

sub main'run_store { &auto_main'run_store; }
sub auto_main'run_store { &main'dataload; }

sub main'run_write { &auto_main'run_write; }
sub auto_main'run_write { &main'dataload; }

sub main'run_delete { &auto_main'run_delete; }
sub auto_main'run_delete { &main'dataload; }

sub main'run_macro { &auto_main'run_macro; }
sub auto_main'run_macro { &main'dataload; }

sub main'run_message { &auto_main'run_message; }
sub auto_main'run_message { &main'dataload; }

sub main'run_notify { &auto_main'run_notify; }
sub auto_main'run_notify { &main'dataload; }

sub main'run_reject { &auto_main'run_reject; }
sub auto_main'run_reject { &main'dataload; }

sub main'run_restart { &auto_main'run_restart; }
sub auto_main'run_restart { &main'dataload; }

sub main'run_abort { &auto_main'run_abort; }
sub auto_main'run_abort { &main'dataload; }

sub main'run_resync { &auto_main'run_resync; }
sub auto_main'run_resync { &main'dataload; }

sub main'run_begin { &auto_main'run_begin; }
sub auto_main'run_begin { &main'dataload; }

sub main'run_record { &auto_main'run_record; }
sub auto_main'run_record { &main'dataload; }

sub main'run_unique { &auto_main'run_unique; }
sub auto_main'run_unique { &main'dataload; }

sub main'run_forward { &auto_main'run_forward; }
sub auto_main'run_forward { &main'dataload; }

sub main'run_bounce { &auto_main'run_bounce; }
sub auto_main'run_bounce { &main'dataload; }

sub main'run_post { &auto_main'run_post; }
sub auto_main'run_post { &main'dataload; }

sub main'run_run { &auto_main'run_run; }
sub auto_main'run_run { &main'dataload; }

sub main'run_pipe { &auto_main'run_pipe; }
sub auto_main'run_pipe { &main'dataload; }

sub main'run_give { &auto_main'run_give; }
sub auto_main'run_give { &main'dataload; }

sub main'run_pass { &auto_main'run_pass; }
sub auto_main'run_pass { &main'dataload; }

sub main'run_feed { &auto_main'run_feed; }
sub auto_main'run_feed { &main'dataload; }

sub main'run_purify { &auto_main'run_purify; }
sub auto_main'run_purify { &main'dataload; }

sub main'run_back { &auto_main'run_back; }
sub auto_main'run_back { &main'dataload; }

sub main'run_on { &auto_main'run_on; }
sub auto_main'run_on { &main'dataload; }

sub main'run_once { &auto_main'run_once; }
sub auto_main'run_once { &main'dataload; }

sub main'run_select { &auto_main'run_select; }
sub auto_main'run_select { &main'dataload; }

sub main'run_nop { &auto_main'run_nop; }
sub auto_main'run_nop { &main'dataload; }

sub main'run_strip { &auto_main'run_strip; }
sub auto_main'run_strip { &main'dataload; }

sub main'run_keep { &auto_main'run_keep; }
sub auto_main'run_keep { &main'dataload; }

sub main'run_annotate { &auto_main'run_annotate; }
sub auto_main'run_annotate { &main'dataload; }

sub main'run_assign { &auto_main'run_assign; }
sub auto_main'run_assign { &main'dataload; }

sub main'run_tr { &auto_main'run_tr; }
sub auto_main'run_tr { &main'dataload; }

sub main'run_subst { &auto_main'run_subst; }
sub auto_main'run_subst { &main'dataload; }

sub main'run_split { &auto_main'run_split; }
sub auto_main'run_split { &main'dataload; }

sub main'run_vacation { &auto_main'run_vacation; }
sub auto_main'run_vacation { &main'dataload; }

sub main'run_queue { &auto_main'run_queue; }
sub auto_main'run_queue { &main'dataload; }

sub main'run_perl { &auto_main'run_perl; }
sub auto_main'run_perl { &main'dataload; }

sub main'run_require { &auto_main'run_require; }
sub auto_main'run_require { &main'dataload; }

sub main'run_apply { &auto_main'run_apply; }
sub auto_main'run_apply { &main'dataload; }

sub main'run_umask { &auto_main'run_umask; }
sub auto_main'run_umask { &main'dataload; }

sub main'run_after { &auto_main'run_after; }
sub auto_main'run_after { &main'dataload; }

sub main'run_do { &auto_main'run_do; }
sub auto_main'run_do { &main'dataload; }

sub main'run_beep { &auto_main'run_beep; }
sub auto_main'run_beep { &main'dataload; }

sub main'run_protect { &auto_main'run_protect; }
sub auto_main'run_protect { &main'dataload; }

sub main'run_biff { &auto_main'run_biff; }
sub auto_main'run_biff { &main'dataload; }

sub main'run_saving { &auto_main'run_saving; }
sub auto_main'run_saving { &main'dataload; }

sub main'alter_execution { &auto_main'alter_execution; }
sub auto_main'alter_execution { &main'dataload; }

sub main'save_message { &auto_main'save_message; }
sub auto_main'save_message { &main'dataload; }

#
# Matching functions
#

sub main'init_matcher { &auto_main'init_matcher; }
sub auto_main'init_matcher { &main'dataload; }

sub main'perl_pattern { &auto_main'perl_pattern; }
sub auto_main'perl_pattern { &main'dataload; }

sub main'make_pattern { &auto_main'make_pattern; }
sub auto_main'make_pattern { &main'dataload; }

sub main'match { &auto_main'match; }
sub auto_main'match { &main'dataload; }

sub main'apply_match { &auto_main'apply_match; }
sub auto_main'apply_match { &main'dataload; }

sub main'expr_selector_match { &auto_main'expr_selector_match; }
sub auto_main'expr_selector_match { &main'dataload; }

sub main'selector_match { &auto_main'selector_match; }
sub auto_main'selector_match { &main'dataload; }

# Pattern matching functions:
#	They are invoked as function($selector, $pattern, $range) and return true
#	if the pattern is found in the variable, according to some internal rules
#	which are different among the functions. For instance, match_single will
#	attempt a match with a login name or a regular pattern matching on the
#	whole variable if the pattern was not a single word.

sub main'match_single { &auto_main'match_single; }
sub auto_main'match_single { &main'dataload; }

sub main'match_list { &auto_main'match_list; }
sub auto_main'match_list { &main'dataload; }

sub main'match_var { &auto_main'match_var; }
sub auto_main'match_var { &main'dataload; }

#
# Backreference handling
#

sub main'reset_backref { &auto_main'reset_backref; }
sub auto_main'reset_backref { &main'dataload; }

sub main'update_backref { &auto_main'update_backref; }
sub auto_main'update_backref { &main'dataload; }

#
# Range interpolation
#

sub main'mrange { &auto_main'mrange; }
sub auto_main'mrange { &main'dataload; }

sub main'locate_file { &auto_main'locate_file; }
sub auto_main'locate_file { &main'dataload; }

sub main'locate_program { &auto_main'locate_program; }
sub auto_main'locate_program { &main'dataload; }


sub main'parse_address { &auto_main'parse_address; }
sub auto_main'parse_address { &main'dataload; }

sub main'login_name { &auto_main'login_name; }
sub auto_main'login_name { &main'dataload; }

sub main'last_name { &auto_main'last_name; }
sub auto_main'last_name { &main'dataload; }

sub main'internet_info { &auto_main'internet_info; }
sub auto_main'internet_info { &main'dataload; }

sub main'gen_message_id { &auto_main'gen_message_id; }
sub auto_main'gen_message_id { &main'dataload; }

#
# Macro handling (system)
#

sub main'macros_subst { &auto_main'macros_subst; }
sub auto_main'macros_subst { &main'dataload; }

package macro;

sub macro'info { &auto_macro'info; }
sub auto_macro'info { &main'dataload; }

sub macro'org { &auto_macro'org; }
sub auto_macro'org { &main'dataload; }

sub macro'domain { &auto_macro'domain; }
sub auto_macro'domain { &main'dataload; }

sub macro'internet { &auto_macro'internet; }
sub auto_macro'internet { &main'dataload; }

#
# Internal override feature
#

sub macro'overload { &auto_macro'overload; }
sub auto_macro'overload { &main'dataload; }

# Free routine defined by &overload
sub unload { undef &over }


package main;

package header;

# This package implements a header checker. To initialize it, call 'reset'.
# Then, call 'valid' with a header line and the function returns 0 if the
# line is not part of a header (which means all the lines seen since 'reset'
# are not part of a mail header). If the line may still be part of a header,
# returns 1. Finally, -1 is returned at the end of the header.

sub header'init { &auto_header'init; }
sub auto_header'init { &main'dataload; }

sub header'reset { &auto_header'reset; }
sub auto_header'reset { &main'dataload; }

sub header'valid { &auto_header'valid; }
sub auto_header'valid { &main'dataload; }

sub header'warning { &auto_header'warning; }
sub auto_header'warning { &main'dataload; }

sub header'clean { &auto_header'clean; }
sub auto_header'clean { &main'dataload; }

sub header'check { &auto_header'check; }
sub auto_header'check { &main'dataload; }

sub header'push { &auto_header'push; }
sub auto_header'push { &main'dataload; }

sub header'mta_date { &auto_header'mta_date; }
sub auto_header'mta_date { &main'dataload; }

sub header'normalize { &auto_header'normalize; }
sub auto_header'normalize { &main'dataload; }

sub header'msgid_cleanup { &auto_header'msgid_cleanup; }
sub auto_header'msgid_cleanup { &main'dataload; }

# Perload OFF

# Fixup one message ID by ensuring it has but one single "@" in it.
# Cannot be dataloaded since it is referenced from a regular expression
sub msgid_fix {
	my ($x, $fixupref) = @_;
	# Ensure at least one "@"
	unless ($x =~ /@/) {
		$$fixupref++;
		return $x . "\@faked-by-mailagent.local";
	}
	# Ensure only one "@"
	if ($x =~ tr/@/@/ > 1) {
		my ($leading, $trailing) = ($x =~ /(.*)@(.*)/);
		$leading =~ s/@/./g;
		$$fixupref++;
		return $leading . '@' . $trailing;
	}
	return $x;
}

# Perload ON

sub header'parsedate { &auto_header'parsedate; }
sub auto_header'parsedate { &main'dataload; }

sub header'format { &auto_header'format; }
sub auto_header'format { &main'dataload; }

sub header'news_fmt { &auto_header'news_fmt; }
sub auto_header'news_fmt { &main'dataload; }

sub main'header_found { &auto_main'header_found; }
sub auto_main'header_found { &main'dataload; }

package main;

#
# Implementation of filtering commands
#

sub main'leave { &auto_main'leave; }
sub auto_main'leave { &main'dataload; }

sub main'save { &auto_main'save; }
sub auto_main'save { &main'dataload; }

sub main'save_folder { &auto_main'save_folder; }
sub auto_main'save_folder { &main'dataload; }

sub main'save_hook { &auto_main'save_hook; }
sub auto_main'save_hook { &main'dataload; }

sub main'process { &auto_main'process; }
sub auto_main'process { &main'dataload; }

sub main'macro { &auto_main'macro; }
sub auto_main'macro { &main'dataload; }

sub main'message { &auto_main'message; }
sub auto_main'message { &main'dataload; }

sub main'notify { &auto_main'notify; }
sub auto_main'notify { &main'dataload; }

sub main'send_message { &auto_main'send_message; }
sub auto_main'send_message { &main'dataload; }

sub main'forward { &auto_main'forward; }
sub auto_main'forward { &main'dataload; }

sub main'bounce { &auto_main'bounce; }
sub auto_main'bounce { &main'dataload; }

sub main'post { &auto_main'post; }
sub auto_main'post { &main'dataload; }

sub main'apply { &auto_main'apply; }
sub auto_main'apply { &main'dataload; }

sub main'split { &auto_main'split; }
sub auto_main'split { &main'dataload; }

sub main'shell_command { &auto_main'shell_command; }
sub auto_main'shell_command { &main'dataload; }

sub main'popen_failed { &auto_main'popen_failed; }
sub auto_main'popen_failed { &main'dataload; }

sub main'alarm_clock { &auto_main'alarm_clock; }
sub auto_main'alarm_clock { &main'dataload; }

sub main'print_binary_mail { &auto_main'print_binary_mail; }
sub auto_main'print_binary_mail { &main'dataload; }

sub main'execute_command { &auto_main'execute_command; }
sub auto_main'execute_command { &main'dataload; }

sub main'handle_output { &auto_main'handle_output; }
sub auto_main'handle_output { &main'dataload; }

sub main'mail_back { &auto_main'mail_back; }
sub auto_main'mail_back { &main'dataload; }

sub main'feed_back { &auto_main'feed_back; }
sub auto_main'feed_back { &main'dataload; }

sub main'xeq_back { &auto_main'xeq_back; }
sub auto_main'xeq_back { &main'dataload; }

sub main'header_resync { &auto_main'header_resync; }
sub auto_main'header_resync { &main'dataload; }

sub main'alter_header { &auto_main'alter_header; }
sub auto_main'alter_header { &main'dataload; }

sub main'annotate_header { &auto_main'annotate_header; }
sub auto_main'annotate_header { &main'dataload; }


sub main'runop_on_field { &auto_main'runop_on_field; }
sub auto_main'runop_on_field { &main'dataload; }

sub main'alter_field { &auto_main'alter_field; }
sub auto_main'alter_field { &main'dataload; }

sub main'alter_value { &auto_main'alter_value; }
sub auto_main'alter_value { &main'dataload; }

sub main'perl { &auto_main'perl; }
sub auto_main'perl { &main'dataload; }

sub main'require { &auto_main'require; }
sub auto_main'require { &main'dataload; }

sub main'do { &auto_main'do; }
sub auto_main'do { &main'dataload; }

sub main'after { &auto_main'after; }
sub auto_main'after { &main'dataload; }

sub main'alter_flow { &auto_main'alter_flow; }
sub auto_main'alter_flow { &main'dataload; }

sub main'do_reject { &auto_main'do_reject; }
sub auto_main'do_reject { &main'dataload; }

sub main'do_restart { &auto_main'do_restart; }
sub auto_main'do_restart { &main'dataload; }

sub main'do_abort { &auto_main'do_abort; }
sub auto_main'do_abort { &main'dataload; }

sub main'complete_list { &auto_main'complete_list; }
sub auto_main'complete_list { &main'dataload; }

sub main'save_mail { &auto_main'save_mail; }
sub auto_main'save_mail { &main'dataload; }

sub main'empty_body { &auto_main'empty_body; }
sub auto_main'empty_body { &main'dataload; }

sub main'trace_dump { &auto_main'trace_dump; }
sub auto_main'trace_dump { &main'dataload; }

package stats;

$stats_wanted = 0;				# No statistics wanted by default
$new_record = 0;				# True when a new record is to be started
$start_date = 0;				# When statistics started
$suppressed = 0;				# Statistics suppressed by higher authority

# Suppress statistics. This function is called when options like -r or -e are
# used. Those usually specify one time rules and thus are not entitled to be
# recorded into the statistics.
sub main'no_stats { $suppressed = 1; }

sub main'read_stats { &auto_main'read_stats; }
sub auto_main'read_stats { &main'dataload; }

sub main'write_stats { &auto_main'write_stats; }
sub auto_main'write_stats { &main'dataload; }

sub stats'print_array { &auto_stats'print_array; }
sub auto_stats'print_array { &main'dataload; }

#
# Accounting routines
#

sub main's_filtered { &auto_main's_filtered; }
sub auto_main's_filtered { &main'dataload; }

sub main's_match { &auto_main's_match; }
sub auto_main's_match { &main'dataload; }

sub main's_default { &auto_main's_default; }
sub auto_main's_default { &main'dataload; }

sub main's_vacation { &auto_main's_vacation; }
sub auto_main's_vacation { &main'dataload; }

sub main's_saved { &auto_main's_saved; }
sub auto_main's_saved { &main'dataload; }

sub main's_seen { &auto_main's_seen; }
sub auto_main's_seen { &main'dataload; }

sub main's_action { &auto_main's_action; }
sub auto_main's_action { &main'dataload; }

sub main's_failed { &auto_main's_failed; }
sub auto_main's_failed { &main'dataload; }

sub main's_once { &auto_main's_once; }
sub auto_main's_once { &main'dataload; }

sub main's_noretry { &auto_main's_noretry; }
sub auto_main's_noretry { &main'dataload; }

#
# Low-level routines
#

sub stats'diff_rules { &auto_stats'diff_rules; }
sub auto_stats'diff_rules { &main'dataload; }

sub stats'fill_stats { &auto_stats'fill_stats; }
sub auto_stats'fill_stats { &main'dataload; }

#
# Reporting statistics
#

sub main'report_stats { &auto_main'report_stats; }
sub auto_main'report_stats { &main'dataload; }

sub stats'print_stats { &auto_stats'print_stats; }
sub auto_stats'print_stats { &main'dataload; }

sub stats'print_summary { &auto_stats'print_summary; }
sub auto_stats'print_summary { &main'dataload; }

sub stats'print_general { &auto_stats'print_general; }
sub auto_stats'print_general { &main'dataload; }

sub stats'print_commands { &auto_stats'print_commands; }
sub auto_stats'print_commands { &main'dataload; }

sub stats'uniform_rule { &auto_stats'uniform_rule; }
sub auto_stats'uniform_rule { &main'dataload; }

sub stats'print_rules_summary { &auto_stats'print_rules_summary; }
sub auto_stats'print_rules_summary { &main'dataload; }

#
# Hooks for rule dumping
#

sub stats'print_header { &auto_stats'print_header; }
sub auto_stats'print_header { &main'dataload; }

sub stats'rule_stats { &auto_stats'rule_stats; }
sub auto_stats'rule_stats { &main'dataload; }

package main;

sub main'qmail { &auto_main'qmail; }
sub auto_main'qmail { &main'dataload; }

sub main'queue_mail { &auto_main'queue_mail; }
sub auto_main'queue_mail { &main'dataload; }

sub main'waiting_mail { &auto_main'waiting_mail; }
sub auto_main'waiting_mail { &main'dataload; }

sub main'mv { &auto_main'mv; }
sub auto_main'mv { &main'dataload; }

sub main'same_device { &auto_main'same_device; }
sub auto_main'same_device { &main'dataload; }

sub main'pqueue { &auto_main'pqueue; }
sub auto_main'pqueue { &main'dataload; }

sub main'pmail { &auto_main'pmail; }
sub auto_main'pmail { &main'dataload; }

#
# Executing builtin commands
#

sub main'send_receipt { &auto_main'send_receipt; }
sub auto_main'send_receipt { &main'dataload; }

#
# Deal with builtins
#

sub main'init_builtins { &auto_main'init_builtins; }
sub auto_main'init_builtins { &main'dataload; }

# Whenever a builtin command is recognized (on the fly) while parsing the mail
# body, the corresponding builtin function is called with the remaining of the
# line given as argument (leading spaces removed).

sub main'builtin_rr { &auto_main'builtin_rr; }
sub auto_main'builtin_rr { &main'dataload; }

sub main'builtin_path { &auto_main'builtin_path; }
sub auto_main'builtin_path { &main'dataload; }

sub main'run_builtins { &auto_main'run_builtins; }
sub auto_main'run_builtins { &main'dataload; }

# Here are the data structures we use to store the compiled form of the rules:
#  @Rules has entries looking like "<$mode> {$action} $rulekeys..."
#  %Rule has entries looking like "$selector: $pattern"
# Each rule was saved in @Rules. The ruleskeys have the form H<num> where <num>
# is an increasing integer. They index the rules in %Rule.

sub main'compile_rules { &auto_main'compile_rules; }
sub auto_main'compile_rules { &main'dataload; }

sub main'default_rules { &auto_main'default_rules; }
sub auto_main'default_rules { &main'dataload; }

sub main'rule_cleanup { &auto_main'rule_cleanup; }
sub auto_main'rule_cleanup { &main'dataload; }

sub main'print_rule_number { &auto_main'print_rule_number; }
sub auto_main'print_rule_number { &main'dataload; }

sub main'void_func { &auto_main'void_func; }
sub auto_main'void_func { &main'dataload; }

sub main'exact_rule { &auto_main'exact_rule; }
sub auto_main'exact_rule { &main'dataload; }

sub nothing { }			 # Do nothing, really nothing

sub main'dump_rules { &auto_main'dump_rules; }
sub auto_main'dump_rules { &main'dataload; }

sub main'print_rule { &auto_main'print_rule; }
sub auto_main'print_rule { &main'dataload; }

#
# The following package added to hold all the new rule-specific functions
# added at version 3.0.
#

package rules;

sub rules'write_cache { &auto_rules'write_cache; }
sub auto_rules'write_cache { &main'dataload; }

sub rules'read_cache { &auto_rules'read_cache; }
sub auto_rules'read_cache { &main'dataload; }

sub rules'cache_ok { &auto_rules'cache_ok; }
sub auto_rules'cache_ok { &main'dataload; }

sub rules'write_fd { &auto_rules'write_fd; }
sub auto_rules'write_fd { &main'dataload; }

sub rules'writevar_fd { &auto_rules'writevar_fd; }
sub auto_rules'writevar_fd { &main'dataload; }

# Perload OFF
# (Used as a sort function, causes perl5 to dump core with native AUTOLOAD)

# Sorting for hash keys used by %Rule
sub hashkey {
	local($c) = $a =~ /^H(\d+)/;
	local($d) = $b =~ /^H(\d+)/;
	$c <=> $d;
}

# Perload ON

sub rules'alternate { &auto_rules'alternate; }
sub auto_rules'alternate { &main'dataload; }

package main;

sub main'seconds_in_period { &auto_main'seconds_in_period; }
sub auto_main'seconds_in_period { &main'dataload; }

sub main'relative_age { &auto_main'relative_age; }
sub auto_main'relative_age { &main'dataload; }

#
# The built-in expression interpreter
#

sub main'init_interpreter { &auto_main'init_interpreter; }
sub auto_main'init_interpreter { &main'dataload; }

sub main'set_priorities { &auto_main'set_priorities; }
sub auto_main'set_priorities { &main'dataload; }

sub main'set_functions { &auto_main'set_functions; }
sub auto_main'set_functions { &main'dataload; }

sub main'error { &auto_main'error; }
sub auto_main'error { &main'dataload; }

sub main'push_val { &auto_main'push_val; }
sub auto_main'push_val { &main'dataload; }

sub main'execute { &auto_main'execute; }
sub auto_main'execute { &main'dataload; }

sub main'update_stack { &auto_main'update_stack; }
sub auto_main'update_stack { &main'dataload; }

sub main'eval_expr { &auto_main'eval_expr; }
sub auto_main'eval_expr { &main'dataload; }

sub main'evaluate { &auto_main'evaluate; }
sub auto_main'evaluate { &main'dataload; }

#
# Boolean functions used by the interpreter. They all take two arguments
# and return 0 if false and 1 if true.
#

sub f_and { $_[0] && $_[1]; }		# Boolean AND
sub f_or { $_[0] || $_[1]; }		# Boolean OR
sub f_ge { $_[0] >= $_[1]; }		# Greater or equal
sub f_le { $_[0] <= $_[1]; }		# Lesser or equal
sub f_lt { $_[0] < $_[1]; }			# Lesser than
sub f_gt { $_[0] > $_[1]; }			# Greater than
sub f_eq { "$_[0]" eq "$_[1]"; }	# Equal
sub f_ne { "$_[0]" ne "$_[1]"; }	# Not equal
sub f_match { $_[0] =~ /$_[1]/; }	# Pattern matches
sub f_nomatch { $_[0] !~ /$_[1]/; }	# Pattern does not match

package dbr;

sub dbr'hash_path { &auto_dbr'hash_path; }
sub auto_dbr'hash_path { &main'dataload; }

sub dbr'info { &auto_dbr'info; }
sub auto_dbr'info { &main'dataload; }

sub dbr'match { &auto_dbr'match; }
sub auto_dbr'match { &main'dataload; }

sub dbr'update { &auto_dbr'update; }
sub auto_dbr'update { &main'dataload; }

sub dbr'delete { &auto_dbr'delete; }
sub auto_dbr'delete { &main'dataload; }

sub dbr'default { &auto_dbr'default; }
sub auto_dbr'default { &main'dataload; }

sub dbr'clean { &auto_dbr'clean; }
sub auto_dbr'clean { &main'dataload; }

sub dbr'recursive_clean { &auto_dbr'recursive_clean; }
sub auto_dbr'recursive_clean { &main'dataload; }

sub dbr'clean_file { &auto_dbr'clean_file; }
sub auto_dbr'clean_file { &main'dataload; }

package main;

sub main'history_tag { &auto_main'history_tag; }
sub auto_main'history_tag { &main'dataload; }

sub main'history_ignore { &auto_main'history_ignore; }
sub auto_main'history_ignore { &main'dataload; }

sub main'history_record { &auto_main'history_record; }
sub auto_main'history_record { &main'dataload; }

sub main'once_check { &auto_main'once_check; }
sub auto_main'once_check { &main'dataload; }

sub main'makedir { &auto_main'makedir; }
sub auto_main'makedir { &main'dataload; }

#
# Emergency situation routines
#

# Perload OFF
# (Better not be dynamically loaded as it is a signal handler)

# Emergency signal was caught
sub emergency {
	local($sig) = @_;			# First argument is signal name
	if ($has_option) {			# Mailagent was invoked "manually"
		&resync;				# Resynchronize waiting file if necessary
		&add_log("ERROR trapped SIG$sig") if $loglvl;
		exit 1;
	}
	&fatal("trapped SIG$sig");
}

# Perload ON

sub main'fatal { &auto_main'fatal; }
sub auto_main'fatal { &main'dataload; }

sub main'emergency_save { &auto_main'emergency_save; }
sub auto_main'emergency_save { &main'dataload; }

sub main'dump_mbox { &auto_main'dump_mbox; }
sub auto_main'dump_mbox { &main'dataload; }

sub main'write_waitkeys { &auto_main'write_waitkeys; }
sub auto_main'write_waitkeys { &main'dataload; }

sub main'resync { &auto_main'resync; }
sub auto_main'resync { &main'dataload; }

sub main'list_queue { &auto_main'list_queue; }
sub auto_main'list_queue { &main'dataload; }

package mbox;

sub main'mbox_mail { &auto_main'mbox_mail; }
sub auto_main'mbox_mail { &main'dataload; }

sub mbox'flush_blanks { &auto_mbox'flush_blanks; }
sub auto_mbox'flush_blanks { &main'dataload; }

sub mbox'flush_buffer { &auto_mbox'flush_buffer; }
sub auto_mbox'flush_buffer { &main'dataload; }

sub mbox'flush { &auto_mbox'flush; }
sub auto_mbox'flush { &main'dataload; }

package main;

package context;

#
# General handling
#

sub context'init { &auto_context'init; }
sub auto_context'init { &main'dataload; }

sub context'default { &auto_context'default; }
sub auto_context'default { &main'dataload; }

sub context'load { &auto_context'load; }
sub auto_context'load { &main'dataload; }

sub context'clean { &auto_context'clean; }
sub auto_context'clean { &main'dataload; }

sub context'save { &auto_context'save; }
sub auto_context'save { &main'dataload; }

#
# Access features
#

sub context'set { &auto_context'set; }
sub auto_context'set { &main'dataload; }

sub context'get { &auto_context'get; }
sub auto_context'get { &main'dataload; }

sub context'delete { &auto_context'delete; }
sub auto_context'delete { &main'dataload; }

#
# Context-dependant actions
#

sub context'autoclean { &auto_context'autoclean; }
sub auto_context'autoclean { &main'dataload; }

#
# Perform all contextual actions
#

sub main'contextual_operations { &auto_main'contextual_operations; }
sub auto_main'contextual_operations { &main'dataload; }

package main;

#
# Persitent variables handling
#

package extern;

sub extern'val { &auto_extern'val; }
sub auto_extern'val { &main'dataload; }

sub extern'set { &auto_extern'set; }
sub auto_extern'set { &main'dataload; }

sub extern'age { &auto_extern'age; }
sub auto_extern'age { &main'dataload; }

package main;

#
# Various hook utilities
# (name in package hook, compiled in package mailhook)
#

package mailhook;

sub hook'initvar { &auto_hook'initvar; }
sub auto_hook'initvar { &main'dataload; }

sub hook'run { &auto_hook'run; }
sub auto_hook'run { &main'dataload; }

package main;

#
# Perl interface with the filter actions
#

package mailhook;

sub abort		{ &interface'dispatch; }
sub annotate	{ &interface'dispatch; }
sub apply		{ &interface'dispatch; }
sub assign		{ &interface'dispatch; }
sub back		{ &interface'dispatch; }
sub beep		{ &interface'dispatch; }
sub begin		{ &interface'dispatch; }
sub biff		{ &interface'dispatch; }
sub bounce		{ &interface'dispatch; }
sub delete		{ &interface'dispatch; }
sub feed		{ &interface'dispatch; }
sub forward		{ &interface'dispatch; }
sub give		{ &interface'dispatch; }
sub keep		{ &interface'dispatch; }
sub leave		{ &interface'dispatch; }
sub macro		{ &interface'dispatch; }
sub message		{ &interface'dispatch; }
sub nop			{ &interface'dispatch; }
sub notify		{ &interface'dispatch; }
sub on			{ &interface'dispatch; }
sub once		{ &interface'dispatch; }
sub pass		{ &interface'dispatch; }
sub perl		{ &interface'dispatch; }
sub pipe		{ &interface'dispatch; }
sub post		{ &interface'dispatch; }
sub process		{ &interface'dispatch; }
sub protect		{ &interface'dispatch; }
sub purify		{ &interface'dispatch; }
sub queue		{ &interface'dispatch; }
sub record		{ &interface'dispatch; }
sub reject		{ &interface'dispatch; }
sub require		{ &interface'dispatch; }
sub restart		{ &interface'dispatch; }
sub resync		{ &interface'dispatch; }
sub run			{ &interface'dispatch; }
sub save		{ &interface'dispatch; }
sub select		{ &interface'dispatch; }
sub server		{ &interface'dispatch; }
sub split		{ &interface'dispatch; }
sub store		{ &interface'dispatch; }
sub strip		{ &interface'dispatch; }
sub subst		{ &interface'dispatch; }
sub tr			{ &interface'dispatch; }
sub umask		{ &interface'dispatch; }
sub unique		{ &interface'dispatch; }
sub vacation	{ &interface'dispatch; }
sub write		{ &interface'dispatch; }

# Perload OFF
# A perl filtering script should call &exit and not exit directly.
# (Cannot be data-loaded or it will corrupt $@ expected by &main'perl)
sub exit { 
	local($code) = @_;
	die "OK\n" unless $code;
	die "Exit $code\n";
}
# Perload ON

package interface;

# Perload OFF
# (Cannot be dynamically loaded as it uses the caller() function)

# The dispatch routine is really simple. We compute the name of our caller,
# prepend it to the argument and call run_command to actually run the command.
# Upon return, if we get anything but a continue status, we simply die with
# an 'OK' string, which will be a signal to the routine monitoring the execution
# that nothing wrong happened.
sub dispatch {
	local($args) = join(' ', @_);			# Arguments for the command
	local($name) = (caller(1))[3];			# Function which called us
	local($status);							# Continuation status
	$name =~ s/^\w+('|::)//;				# Strip leading package name
	&'add_log("calling '$name $args'") if $'loglvl > 18;
	$status = &'run_command("$name $args");	# Case does not matter

	# The status propagation is the only thing we have to deal with, as this
	# is handled within run_command. All other variables which are meaningful
	# for the filter are dynamically bound to function called before in the
	# stack, hence they are modified directly from within the perl script.

	die "Status $status\n" unless $status == $'FT_CONT;

	# Return the status held in $lastcmd, unless the command does not alter
	# the status significantly, in which case we return success. Note that
	# this is in fact a boolean success status, so 1 means success, whereas
	# $lastcmd records a failure status.

	$name =~ tr/a-z/A-Z/;					# Stored upper-cased
	$'Nostatus{$name} ? 1 : !$'lastcmd;		# Propagate status
}

# Perload ON

$in_perl = 0;					# Number of nested perl evaluations

sub interface'new { &auto_interface'new; }
sub auto_interface'new { &main'dataload; }

sub interface'reset { &auto_interface'reset; }
sub auto_interface'reset { &main'dataload; }

sub interface'valid { &auto_interface'valid; }
sub auto_interface'valid { &main'dataload; }

sub interface'add { &auto_interface'add; }
sub auto_interface'add { &main'dataload; }

package main;

package getdate;

# This package parses a date string and converts it into a number of seconds.
# I did minor editing on this code, mainly to remove all the YYDEBUG #if tests
# and to reformat some of the table. I also encapsulated all the initializations
# into init subroutines and reworked on the indentation of semantic actions.
# Oh yes, I also made some minor modifications in place (i.e. without running
# yacc again) to apply some small fixes Richard sent me via e-mail.
# Other than that, it's pretty verbatim--RAM.

sub getdate'yyinit { &auto_getdate'yyinit; }
sub auto_getdate'yyinit { &main'dataload; }

sub yyclearin { $yychar = -1; }
sub yyerrok { $yyerrflag = 0; }
sub YYERROR { ++$yynerrs; &yy_err_recover; }
sub getdate'yy_err_recover { &auto_getdate'yy_err_recover; }
sub auto_getdate'yy_err_recover { &main'dataload; }

sub getdate'yyparse { &auto_getdate'yyparse; }
sub auto_getdate'yyparse { &main'dataload; }

sub getdate'dateconv { &auto_getdate'dateconv; }
sub auto_getdate'dateconv { &main'dataload; }

sub getdate'dayconv { &auto_getdate'dayconv; }
sub auto_getdate'dayconv { &main'dataload; }

sub getdate'timeconv { &auto_getdate'timeconv; }
sub auto_getdate'timeconv { &main'dataload; }

sub getdate'monthadd { &auto_getdate'monthadd; }
sub auto_getdate'monthadd { &main'dataload; }

sub getdate'daylcorr { &auto_getdate'daylcorr; }
sub auto_getdate'daylcorr { &main'dataload; }

sub getdate'yylex { &auto_getdate'yylex; }
sub auto_getdate'yylex { &main'dataload; }
		
sub getdate'lookup_init { &auto_getdate'lookup_init; }
sub auto_getdate'lookup_init { &main'dataload; }

sub getdate'lookup { &auto_getdate'lookup; }
sub auto_getdate'lookup { &main'dataload; }

sub main'getdate { &auto_main'getdate; }
sub auto_main'getdate { &main'dataload; }

sub getdate'yyerror { &auto_getdate'yyerror; }
sub auto_getdate'yyerror { &main'dataload; }

package main;

sub main'include_file { &auto_main'include_file; }
sub auto_main'include_file { &main'dataload; }

sub main'plural { &auto_main'plural; }
sub auto_main'plural { &main'dataload; }

sub main'myhostname { &auto_main'myhostname; }
sub auto_main'myhostname { &main'dataload; }

sub main'hostname { &auto_main'hostname; }
sub auto_main'hostname { &main'dataload; }

#
# MMDF-style saving routines
#

package mmdf;

sub mmdf'save { &auto_mmdf'save; }
sub auto_mmdf'save { &main'dataload; }
	
sub mmdf'save_mmdf { &auto_mmdf'save_mmdf; }
sub auto_mmdf'save_mmdf { &main'dataload; }

sub mmdf'save_unix { &auto_mmdf'save_unix; }
sub auto_mmdf'save_unix { &main'dataload; }

sub mmdf'force_flushing { &auto_mmdf'force_flushing; }
sub auto_mmdf'force_flushing { &main'dataload; }

sub mmdf'is_mmdf { &auto_mmdf'is_mmdf; }
sub auto_mmdf'is_mmdf { &main'dataload; }

sub mmdf'chmod { &auto_mmdf'chmod; }
sub auto_mmdf'chmod { &main'dataload; }

package main;

#
# Folder compression
#

package compress;

sub compress'init { &auto_compress'init; }
sub auto_compress'init { &main'dataload; }

sub compress'uncompress { &auto_compress'uncompress; }
sub auto_compress'uncompress { &main'dataload; }

sub compress'compress { &auto_compress'compress; }
sub auto_compress'compress { &main'dataload; }

sub compress'recompress { &auto_compress'recompress; }
sub auto_compress'recompress { &main'dataload; }

sub compress'restore { &auto_compress'restore; }
sub auto_compress'restore { &main'dataload; }

sub compress'is_compressed { &auto_compress'is_compressed; }
sub auto_compress'is_compressed { &main'dataload; }

sub compress'add_compressor { &auto_compress'add_compressor; }
sub auto_compress'add_compressor { &main'dataload; }

package main;


package newcmd;

#
# User-defined commands
#

sub newcmd'load { &auto_newcmd'load; }
sub auto_newcmd'load { &main'dataload; }

sub newcmd'run { &auto_newcmd'run; }
sub auto_newcmd'run { &main'dataload; }

package main;

sub main'q { &auto_main'q; }
sub auto_main'q { &main'dataload; }

#
# Mailhook handling
#

package hook;

sub hook'init { &auto_hook'init; }
sub auto_hook'init { &main'dataload; }

sub hook'process { &auto_hook'process; }
sub auto_hook'process { &main'dataload; }

sub hook'type { &auto_hook'type; }
sub auto_hook'type { &main'dataload; }

#
# Hook functions
#

sub hook'unknown { &auto_hook'unknown; }
sub auto_hook'unknown { &main'dataload; }

sub hook'program { &auto_hook'program; }
sub auto_hook'program { &main'dataload; }

sub hook'rules { &auto_hook'rules; }
sub auto_hook'rules { &main'dataload; }

sub hook'perl { &auto_hook'perl; }
sub auto_hook'perl { &main'dataload; }

sub hook'audit { &auto_hook'audit; }
sub auto_hook'audit { &main'dataload; }

sub hook'deliver { &auto_hook'deliver; }
sub auto_hook'deliver { &main'dataload; }

sub hook'hooking { &auto_hook'hooking; }
sub auto_hook'hooking { &main'dataload; }

package main;

sub main'file_secure { &auto_main'file_secure; }
sub auto_main'file_secure { &main'dataload; }

sub main'symdir_secure { &auto_main'symdir_secure; }
sub auto_main'symdir_secure { &main'dataload; }

sub main'symfile_secure { &auto_main'symfile_secure; }
sub auto_main'symfile_secure { &main'dataload; }

sub main'symdir_check { &auto_main'symdir_check; }
sub auto_main'symdir_check { &main'dataload; }

sub main'symfile_check { &auto_main'symfile_check; }
sub auto_main'symfile_check { &main'dataload; }

sub main'check_st_mode { &auto_main'check_st_mode; }
sub auto_main'check_st_mode { &main'dataload; }

sub main'exec_secure { &auto_main'exec_secure; }
sub auto_main'exec_secure { &main'dataload; }

sub main'cdir { &auto_main'cdir; }
sub auto_main'cdir { &main'dataload; }

#
# Command server
#

package cmdserv;

$loaded = 0;			# Set to true when loading done

sub cmdserv'init { &auto_cmdserv'init; }
sub auto_cmdserv'init { &main'dataload; }

sub cmdserv'load { &auto_cmdserv'load; }
sub auto_cmdserv'load { &main'dataload; }

sub cmdserv'process { &auto_cmdserv'process; }
sub auto_cmdserv'process { &main'dataload; }

#
# Command execution
#

sub cmdserv'execute { &auto_cmdserv'execute; }
sub auto_cmdserv'execute { &main'dataload; }

sub cmdserv'dispatch { &auto_cmdserv'dispatch; }
sub auto_cmdserv'dispatch { &main'dataload; }

sub cmdserv'exec_shell { &auto_cmdserv'exec_shell; }
sub auto_cmdserv'exec_shell { &main'dataload; }

sub cmdserv'exec_perl { &auto_cmdserv'exec_perl; }
sub auto_cmdserv'exec_perl { &main'dataload; }

sub cmdserv'exec_help { &auto_cmdserv'exec_help; }
sub auto_cmdserv'exec_help { &main'dataload; }

#
# Builtins
#

sub cmdserv'run_approve { &auto_cmdserv'run_approve; }
sub auto_cmdserv'run_approve { &main'dataload; }

sub cmdserv'run_power { &auto_cmdserv'run_power; }
sub auto_cmdserv'run_power { &main'dataload; }

sub cmdserv'run_release { &auto_cmdserv'run_release; }
sub auto_cmdserv'run_release { &main'dataload; }

sub cmdserv'run_powers { &auto_cmdserv'run_powers; }
sub auto_cmdserv'run_powers { &main'dataload; }

sub cmdserv'run_password { &auto_cmdserv'run_password; }
sub auto_cmdserv'run_password { &main'dataload; }

sub cmdserv'run_passwd { &auto_cmdserv'run_passwd; }
sub auto_cmdserv'run_passwd { &main'dataload; }

sub cmdserv'change_password { &auto_cmdserv'change_password; }
sub auto_cmdserv'change_password { &main'dataload; }

sub cmdserv'run_user { &auto_cmdserv'run_user; }
sub auto_cmdserv'run_user { &main'dataload; }

sub cmdserv'run_newpower { &auto_cmdserv'run_newpower; }
sub auto_cmdserv'run_newpower { &main'dataload; }

sub cmdserv'newpower { &auto_cmdserv'newpower; }
sub auto_cmdserv'newpower { &main'dataload; }

sub cmdserv'run_delpower { &auto_cmdserv'run_delpower; }
sub auto_cmdserv'run_delpower { &main'dataload; }

sub cmdserv'delpower { &auto_cmdserv'delpower; }
sub auto_cmdserv'delpower { &main'dataload; }

sub cmdserv'run_setauth { &auto_cmdserv'run_setauth; }
sub auto_cmdserv'run_setauth { &main'dataload; }

sub cmdserv'run_addauth { &auto_cmdserv'run_addauth; }
sub auto_cmdserv'run_addauth { &main'dataload; }

sub cmdserv'run_remauth { &auto_cmdserv'run_remauth; }
sub auto_cmdserv'run_remauth { &main'dataload; }

sub cmdserv'run_getauth { &auto_cmdserv'run_getauth; }
sub auto_cmdserv'run_getauth { &main'dataload; }

sub cmdserv'run_set { &auto_cmdserv'run_set; }
sub auto_cmdserv'run_set { &main'dataload; }

#
# Utilities
#

sub cmdserv'user_prompt { &auto_cmdserv'user_prompt; }
sub auto_cmdserv'user_prompt { &main'dataload; }

sub cmdserv'include { &auto_cmdserv'include; }
sub auto_cmdserv'include { &main'dataload; }

sub cmdserv'finish { &auto_cmdserv'finish; }
sub auto_cmdserv'finish { &main'dataload; }

sub cmdserv'root { &auto_cmdserv'root; }
sub auto_cmdserv'root { &main'dataload; }

#
# Server modes
#

sub cmdserv'trusted { &auto_cmdserv'trusted; }
sub auto_cmdserv'trusted { &main'dataload; }

sub cmdserv'disable { &auto_cmdserv'disable; }
sub auto_cmdserv'disable { &main'dataload; }

sub cmdserv'servshell { &auto_cmdserv'servshell; }
sub auto_cmdserv'servshell { &main'dataload; }

#
# Environment for server commands
#

package cmdenv;

sub cmdenv'inituid { &auto_cmdenv'inituid; }
sub auto_cmdenv'inituid { &main'dataload; }

sub cmdenv'set_cmd { &auto_cmdenv'set_cmd; }
sub auto_cmdenv'set_cmd { &main'dataload; }

sub cmdenv'addpower { &auto_cmdenv'addpower; }
sub auto_cmdenv'addpower { &main'dataload; }

sub cmdenv'rempower { &auto_cmdenv'rempower; }
sub auto_cmdenv'rempower { &main'dataload; }

sub cmdenv'wipe_powers { &auto_cmdenv'wipe_powers; }
sub auto_cmdenv'wipe_powers { &main'dataload; }

sub cmdenv'haspower { &auto_cmdenv'haspower; }
sub auto_cmdenv'haspower { &main'dataload; }

package main;

#
# Power control
#

package power;

sub power'grant { &auto_power'grant; }
sub auto_power'grant { &main'dataload; }

sub power'authorized { &auto_power'authorized; }
sub auto_power'authorized { &main'dataload; }

sub power'valid { &auto_power'valid; }
sub auto_power'valid { &main'dataload; }

#
# Power aliases
#

sub power'authfile { &auto_power'authfile; }
sub auto_power'authfile { &main'dataload; }

sub power'set_auth { &auto_power'set_auth; }
sub auto_power'set_auth { &main'dataload; }

sub power'add_auth { &auto_power'add_auth; }
sub auto_power'add_auth { &main'dataload; }

sub power'rem_auth { &auto_power'rem_auth; }
sub auto_power'rem_auth { &main'dataload; }

sub power'used_alias { &auto_power'used_alias; }
sub auto_power'used_alias { &main'dataload; }

sub power'add_alias { &auto_power'add_alias; }
sub auto_power'add_alias { &main'dataload; }

sub power'del_alias { &auto_power'del_alias; }
sub auto_power'del_alias { &main'dataload; }

#
# Setting password information
#

sub power'set_passwd { &auto_power'set_passwd; }
sub auto_power'set_passwd { &main'dataload; }

sub power'getpwent { &auto_power'getpwent; }
sub auto_power'getpwent { &main'dataload; }

sub power'setpwent { &auto_power'setpwent; }
sub auto_power'setpwent { &main'dataload; }

sub power'rempwent { &auto_power'rempwent; }
sub auto_power'rempwent { &main'dataload; }

#
# Logging control
#

sub power'add_log { &auto_power'add_log; }
sub auto_power'add_log { &main'dataload; }

package main;

sub main'file_edit { &auto_main'file_edit; }
sub auto_main'file_edit { &main'dataload; }

#
# Load function into package
#

package dynload;

sub dynload'load { &auto_dynload'load; }
sub auto_dynload'load { &main'dataload; }

sub dynload'parse { &auto_dynload'parse; }
sub auto_dynload'parse { &main'dataload; }

sub dynload'do { &auto_dynload'do; }
sub auto_dynload'do { &main'dataload; }

package main;

sub main'gensym { &auto_main'gensym; }
sub auto_main'gensym { &main'dataload; }

#
# User-defined macros
#

package usrmac;

$init_done = 0;

sub usrmac'init { &auto_usrmac'init; }
sub auto_usrmac'init { &main'dataload; }

sub usrmac'push { &auto_usrmac'push; }
sub auto_usrmac'push { &main'dataload; }

sub usrmac'new { &auto_usrmac'new; }
sub auto_usrmac'new { &main'dataload; }

sub usrmac'pop { &auto_usrmac'pop; }
sub auto_usrmac'pop { &main'dataload; }

sub usrmac'delete { &auto_usrmac'delete; }
sub auto_usrmac'delete { &main'dataload; }

sub usrmac'save { &auto_usrmac'save; }
sub auto_usrmac'save { &main'dataload; }

sub usrmac'restore { &auto_usrmac'restore; }
sub auto_usrmac'restore { &main'dataload; }

#
# User-defined substitutions
#

sub macro'usr { &auto_macro'usr; }
sub auto_macro'usr { &main'dataload; }

#
# Type-dependant substitutions
#

sub usrmac'sub_scalar { &auto_usrmac'sub_scalar; }
sub auto_usrmac'sub_scalar { &main'dataload; }

sub usrmac'sub_expr { &auto_usrmac'sub_expr; }
sub auto_usrmac'sub_expr { &main'dataload; }

sub usrmac'sub_const { &auto_usrmac'sub_const; }
sub auto_usrmac'sub_const { &main'dataload; }

sub usrmac'sub_fn { &auto_usrmac'sub_fn; }
sub auto_usrmac'sub_fn { &main'dataload; }

sub usrmac'sub_prog { &auto_usrmac'sub_prog; }
sub auto_usrmac'sub_prog { &main'dataload; }

sub usrmac'sub_progc { &auto_usrmac'sub_progc; }
sub auto_usrmac'sub_progc { &main'dataload; }

#
# Value caching
#

sub usrmac'cache { &auto_usrmac'cache; }
sub auto_usrmac'cache { &main'dataload; }

package main;

sub main'tilda_expand { &auto_main'tilda_expand; }
sub auto_main'tilda_expand { &main'dataload; }

#
# MH-style saving routines
#

package mh;

sub mh'save { &auto_mh'save; }
sub auto_mh'save { &main'dataload; }
	
sub mh'savedir { &auto_mh'savedir; }
sub auto_mh'savedir { &main'dataload; }

sub mh'save_msg { &auto_mh'save_msg; }
sub auto_mh'save_msg { &main'dataload; }

#
# MH profile and sequence management.
#

sub mh'profile { &auto_mh'profile; }
sub auto_mh'profile { &main'dataload; }

sub mh'new_msg { &auto_mh'new_msg; }
sub auto_mh'new_msg { &main'dataload; }

sub mh'unseen { &auto_mh'unseen; }
sub auto_mh'unseen { &main'dataload; }

sub mh'seqadd { &auto_mh'seqadd; }
sub auto_mh'seqadd { &main'dataload; }

package main;

sub main'catch_signals { &auto_main'catch_signals; }
sub auto_main'catch_signals { &main'dataload; }

package callout;

#
# Callout queue handling
#

sub callout'init { &auto_callout'init; }
sub auto_callout'init { &main'dataload; }

sub callout'load { &auto_callout'load; }
sub auto_callout'load { &main'dataload; }

sub callout'queue { &auto_callout'queue; }
sub auto_callout'queue { &main'dataload; }

sub callout'trigger { &auto_callout'trigger; }
sub auto_callout'trigger { &main'dataload; }

sub callout'run { &auto_callout'run; }
sub auto_callout'run { &main'dataload; }

sub callout'flush { &auto_callout'flush; }
sub auto_callout'flush { &main'dataload; }

sub callout'save { &auto_callout'save; }
sub auto_callout'save { &main'dataload; }

#
# Spawning engine
#

sub callout'spawn { &auto_callout'spawn; }
sub auto_callout'spawn { &main'dataload; }

sub callout'spawn_agent { &auto_callout'spawn_agent; }
sub auto_callout'spawn_agent { &main'dataload; }

sub callout'spawn_cmd { &auto_callout'spawn_cmd; }
sub auto_callout'spawn_cmd { &main'dataload; }

sub callout'spawn_shell { &auto_callout'spawn_shell; }
sub auto_callout'spawn_shell { &main'dataload; }

package main;

package addr;

#
# Address stuff, mainly for mailing list maintainance (package command)
#

sub addr'valid { &auto_addr'valid; }
sub auto_addr'valid { &main'dataload; }

sub addr'simplify { &auto_addr'simplify; }
sub auto_addr'simplify { &main'dataload; }

sub addr'match { &auto_addr'match; }
sub auto_addr'match { &main'dataload; }

sub addr'close { &auto_addr'close; }
sub auto_addr'close { &main'dataload; }

package main;

#
# utmp file primitives
#

package utmp;

sub utmp'init { &auto_utmp'init; }
sub auto_utmp'init { &main'dataload; }

sub utmp'update { &auto_utmp'update; }
sub auto_utmp'update { &main'dataload; }

sub utmp'reload { &auto_utmp'reload; }
sub auto_utmp'reload { &main'dataload; }

sub utmp'ttys { &auto_utmp'ttys; }
sub auto_utmp'ttys { &main'dataload; }

package main;

#
# Local biff support
#

sub main'biff { &auto_main'biff; }
sub auto_main'biff { &main'dataload; }

package biff;

sub biff'notify { &auto_biff'notify; }
sub auto_biff'notify { &main'dataload; }

sub biff'custom { &auto_biff'custom; }
sub auto_biff'custom { &main'dataload; }

# Routine for %a substitution in biff templates
# Value of $env'beep is set by the BEEP command (default is 1).
sub beep { "\07" x $env'beep; }

sub biff'default { &auto_biff'default; }
sub auto_biff'default { &main'dataload; }

sub biff'all { &auto_biff'all; }
sub auto_biff'all { &main'dataload; }

sub biff'headers { &auto_biff'headers; }
sub auto_biff'headers { &main'dataload; }

sub biff'is_blank { &auto_biff'is_blank; }
sub auto_biff'is_blank { &main'dataload; }

sub biff'body { &auto_biff'body; }
sub auto_biff'body { &main'dataload; }

sub biff'trim { &auto_biff'trim; }
sub auto_biff'trim { &main'dataload; }

sub biff'mh { &auto_biff'mh; }
sub auto_biff'mh { &main'dataload; }

sub biff'format { &auto_biff'format; }
sub auto_biff'format { &main'dataload; }

# One-liner quoted-printable decoder
# MUST be on one line to not be dataloaded (would mess $1 in the regexp)
sub to_txt { my $l = shift; $l =~ s/=([\da-fA-F]{2})/pack('C', hex($1))/ge; $l }

sub biff'unquote_printable { &auto_biff'unquote_printable; }
sub auto_biff'unquote_printable { &main'dataload; }

sub biff'unmime { &auto_biff'unmime; }
sub auto_biff'unmime { &main'dataload; }

sub biff'skip_past { &auto_biff'skip_past; }
sub auto_biff'skip_past { &main'dataload; }

sub biff'parse_header { &auto_biff'parse_header; }
sub auto_biff'parse_header { &main'dataload; }

sub biff'strip_html { &auto_biff'strip_html; }
sub auto_biff'strip_html { &main'dataload; }

package main;

package env;

sub env'init { &auto_env'init; }
sub auto_env'init { &main'dataload; }

sub env'setup { &auto_env'setup; }
sub auto_env'setup { &main'dataload; }

sub env'local { &auto_env'local; }
sub auto_env'local { &main'dataload; }

sub env'unset { &auto_env'unset; }
sub auto_env'unset { &main'dataload; }

sub env'undef { &auto_env'undef; }
sub auto_env'undef { &main'dataload; }

sub env'restore { &auto_env'restore; }
sub auto_env'restore { &main'dataload; }

sub env'cleanup { &auto_env'cleanup; }
sub auto_env'cleanup { &main'dataload; }

package main;

package opt;

sub opt'get { &auto_opt'get; }
sub auto_opt'get { &main'dataload; }

sub opt'reset { &auto_opt'reset; }
sub auto_opt'reset { &main'dataload; }

sub opt'restore { &auto_opt'restore; }
sub auto_opt'restore { &main'dataload; }

sub opt'parse { &auto_opt'parse; }
sub auto_opt'parse { &main'dataload; }

package main;

#
# Configuration setup main entry point
#

package cf;

sub cf'setup { &auto_cf'setup; }
sub auto_cf'setup { &main'dataload; }

#
# Configuration setup routines
#

package cfset;

sub cfset'init { &auto_cfset'init; }
sub auto_cfset'init { &main'dataload; }

sub cfset'merge { &auto_cfset'merge; }
sub auto_cfset'merge { &main'dataload; }

sub cfset'check { &auto_cfset'check; }
sub auto_cfset'check { &main'dataload; }

sub cfset'read_setup { &auto_cfset'read_setup; }
sub auto_cfset'read_setup { &main'dataload; }

sub cfset'dflt { &auto_cfset'dflt; }
sub auto_cfset'dflt { &main'dataload; }

sub cfset'exists { &auto_cfset'exists; }
sub auto_cfset'exists { &main'dataload; }

sub cfset'create { &auto_cfset'create; }
sub auto_cfset'create { &main'dataload; }

sub cfset'prefix { &auto_cfset'prefix; }
sub auto_cfset'prefix { &main'dataload; }

sub cfset'path_check { &auto_cfset'path_check; }
sub auto_cfset'path_check { &main'dataload; }

sub cfset'default_path { &auto_cfset'default_path; }
sub auto_cfset'default_path { &main'dataload; }

sub cfset'contains { &auto_cfset'contains; }
sub auto_cfset'contains { &main'dataload; }

package main;

package base64;

#
# Simple base64 encoder/decoder.
#

sub base64'init { &auto_base64'init; }
sub auto_base64'init { &main'dataload; }

sub base64'reset { &auto_base64'reset; }
sub auto_base64'reset { &main'dataload; }

sub base64'decode { &auto_base64'decode; }
sub auto_base64'decode { &main'dataload; }

sub base64'encode { &auto_base64'encode; }
sub auto_base64'encode { &main'dataload; }

sub base64'output { &auto_base64'output; }
sub auto_base64'output { &main'dataload; }

sub base64'is_valid { &auto_base64'is_valid; }
sub auto_base64'is_valid { &main'dataload; }

sub base64'error_msg { &auto_base64'error_msg; }
sub auto_base64'error_msg { &main'dataload; }

package main;

package qp;

#
# Simple quoted-printable encoder/decoder.
#

sub qp'reset { &auto_qp'reset; }
sub auto_qp'reset { &main'dataload; }

sub qp'decode { &auto_qp'decode; }
sub auto_qp'decode { &main'dataload; }

sub qp'encode { &auto_qp'encode; }
sub auto_qp'encode { &main'dataload; }

sub qp'output { &auto_qp'output; }
sub auto_qp'output { &main'dataload; }

sub qp'is_valid { &auto_qp'is_valid; }
sub auto_qp'is_valid { &main'dataload; }

sub qp'error_msg { &auto_qp'error_msg; }
sub auto_qp'error_msg { &main'dataload; }

package main;

#
# termios primitives
#

package termios;

sub termios'init { &auto_termios'init; }
sub auto_termios'init { &main'dataload; }

sub termios'decompile { &auto_termios'decompile; }
sub auto_termios'decompile { &main'dataload; }

sub termios'size { &auto_termios'size; }
sub auto_termios'size { &main'dataload; }

package main;

# Load the calling function from DATA segment and call it. This function is
# called only once per routine to be loaded.
sub main'dataload {
	package perload;
	local($__packname__) = (caller(1))[3];
	$__packname__ =~ s/::/'/;
	local($__rpackname__) = $__packname__;
	local($__at__) = $@;
	$__rpackname__ =~ s/^auto_//;
	eval { load_from_data($__rpackname__, 0) };
	if ($@ eq "RETRY\n") {
		undef %Datapos;
		load_from_data($__rpackname__, 1);
	} else {
		die $@ if $@;
	}
	local($__fun__) = "$__rpackname__";
	$__fun__ =~ s/'/'load_/;
	eval "*$__packname__ = *$__fun__;";	# Change symbol table entry
	die $@ if $@;		# Should not happen
	$@ = $__at__;		# Restore value $@ had on entrance
	&$__fun__;			# Call newly loaded function
}

# Load function name given as argument, fatal error if not existent
sub perload'load_from_data {
	package perload;
	local ($name, $retried) = @_;
	local($pos) = $Datapos{$name};			# Offset within DATA
	# Avoid side effects by protecting special variables which will be changed
	# by the dataloading operation.
	local($., $_);
	$pos = &fetch_function_code($name, $retried) unless $pos;
	die "Function $name not found in data section.\n" unless $pos;
	die "Cannot seek to $pos into data section.\n"
		unless seek(main'DATA, $pos, 0);
	local($/) = "\n}";
	local($body) = scalar(<main'DATA>);
	local $loaded = $name;
	$loaded =~ s/^(.*?)'(.*)/sub ${1}'load_$2 {/;;
	unless ($body =~ /\n\}$/s && substr($body, 0, length $loaded) eq $loaded) {
		if ($retried) {
			die "End of file found while loading $name.\n"
				unless $body =~ /\n\}$/s;
			die "Offset table garbled or file changed whilst loading $name.\n";
		}
		die "RETRY\n";
	}
	local $@;
	eval $body;		# Load function into perl space
	chop($@) && die "$@, while parsing code of $_[0].\n";
}

# This function is called only once, and fills in the %Datapos array with
# the offset of each of the dataloaded routines held in the data section.
sub perload'fetch_function_code {
	package perload;
	local ($name, $retried) = @_;
	local($start) = 0;
	local($., $_);
	if ($retried) {
		my $date = scalar localtime;
		warn("$0 probably changed, reloading offset table on $date\n");
		close(main'DATA);
		open(main'DATA, $0) || die "Can't open $0 to reload offset table: $!\n";
		my $found = 0;
		while (<main'DATA>) {
			if (/^__END__\s$/) { $found++; last }
		}
		die "Unable to find __END__ token in $0\n" unless $found;
	}
	while (<main'DATA>) {			# First move to start of offset table
		next if /^#/;
		last if /^$/ && ++$start > 2;	# Skip two blank line after end token
	}
	$start = tell(main'DATA);		# Offsets in table are relative to here
	local($key, $value);
	while (<main'DATA>) {			# Load the offset table
		last if /^$/;				# Ends with a single blank line
		($key, $value) = split(' ');
		$Datapos{$key} = $value + $start;
	}
	$Datapos{$name};		# All that pain to get this offset...
}

#
# The perl compiler stops here.
#

__END__

#
# Beyond this point lie functions we may never compile.
#

#
# DO NOT CHANGE A IOTA BEYOND THIS COMMENT!
# The following table lists offsets of functions within the data section.
# Should modifications be needed, change original code and rerun perload
# with the -o option to regenerate a proper offset table.
#

	                     addr'close     496218
	                     addr'match     495474
	                  addr'simplify     494754
	                     addr'valid     494454
	                  base64'decode     541173
	                  base64'encode     542730
	               base64'error_msg     545045
	                    base64'init     538565
	                base64'is_valid     544919
	                  base64'output     544185
	                   base64'reset     540750
	                       biff'all     504317
	                      biff'body     505717
	                    biff'custom     501394
	                   biff'default     503869
	                    biff'format     513258
	                   biff'headers     504934
	                  biff'is_blank     505394
	                        biff'mh     512204
	                    biff'notify     499462
	              biff'parse_header     518123
	                 biff'skip_past     517798
	                biff'strip_html     518854
	                      biff'trim     508353
	                    biff'unmime     515075
	         biff'unquote_printable     514284
	                  callout'flush     490429
	                   callout'init     485620
	                   callout'load     486195
	                  callout'queue     487413
	                    callout'run     489055
	                   callout'save     490794
	                  callout'spawn     492231
	            callout'spawn_agent     493403
	              callout'spawn_cmd     493781
	            callout'spawn_shell     493938
	                callout'trigger     488573
	                       cf'parse      36780
	                       cf'setup     524958
	                    cfset'check     531336
	                 cfset'contains     538327
	                   cfset'create     534521
	             cfset'default_path     537780
	                     cfset'dflt     533459
	                   cfset'exists     533774
	                     cfset'init     526115
	                    cfset'merge     528183
	               cfset'path_check     536766
	                   cfset'prefix     536266
	               cfset'read_setup     532824
	                cmdenv'addpower     450873
	                cmdenv'haspower     451367
	                 cmdenv'inituid     449260
	                cmdenv'rempower     451033
	                 cmdenv'set_cmd     450325
	             cmdenv'wipe_powers     451194
	        cmdserv'change_password     435512
	               cmdserv'delpower     441443
	                cmdserv'disable     448552
	               cmdserv'dispatch     419944
	              cmdserv'exec_help     428205
	              cmdserv'exec_perl     426930
	             cmdserv'exec_shell     420824
	                cmdserv'execute     419471
	                 cmdserv'finish     447918
	                cmdserv'include     447327
	                   cmdserv'init     408762
	                   cmdserv'load     410896
	               cmdserv'newpower     438427
	                cmdserv'process     414178
	                   cmdserv'root     448115
	            cmdserv'run_addauth     443314
	            cmdserv'run_approve     430255
	           cmdserv'run_delpower     440757
	            cmdserv'run_getauth     444967
	           cmdserv'run_newpower     437839
	             cmdserv'run_passwd     434687
	           cmdserv'run_password     433818
	              cmdserv'run_power     430774
	             cmdserv'run_powers     432187
	            cmdserv'run_release     431624
	            cmdserv'run_remauth     444140
	                cmdserv'run_set     445663
	            cmdserv'run_setauth     442495
	               cmdserv'run_user     436426
	              cmdserv'servshell     448881
	                cmdserv'trusted     448255
	            cmdserv'user_prompt     446707
	        compress'add_compressor     387611
	              compress'compress     383864
	                  compress'init     379348
	         compress'is_compressed     386621
	            compress'recompress     385194
	               compress'restore     385368
	            compress'uncompress     381072
	              context'autoclean     343456
	                  context'clean     341542
	                context'default     340902
	                 context'delete     342911
	                    context'get     342761
	                   context'init     340617
	                   context'load     341048
	                   context'save     341724
	                    context'set     342611
	                      dbr'clean     316757
	                 dbr'clean_file     318013
	                    dbr'default     316272
	                     dbr'delete     316050
	                  dbr'hash_path     309826
	                       dbr'info     311248
	                      dbr'match     312515
	            dbr'recursive_clean     316996
	                     dbr'update     314103
	                     dynload'do     468649
	                   dynload'load     466178
	                  dynload'parse     467234
	                    env'cleanup     522317
	                       env'init     520066
	                      env'local     520887
	                    env'restore     521943
	                      env'setup     520441
	                      env'undef     521558
	                      env'unset     521331
	                     extern'age     344713
	                     extern'set     344528
	                     extern'val     344303
	               getdate'dateconv     361676
	                getdate'dayconv     362506
	               getdate'daylcorr     363726
	                 getdate'lookup     369746
	            getdate'lookup_init     365165
	               getdate'monthadd     363329
	               getdate'timeconv     362857
	         getdate'yy_err_recover     355245
	                getdate'yyerror     372814
	                 getdate'yyinit     348654
	                  getdate'yylex     363979
	                getdate'yyparse     355828
	                   header'check     172702
	                   header'clean     172106
	                  header'format     176253
	                    header'init     170094
	           header'msgid_cleanup     174946
	                header'mta_date     173589
	                header'news_fmt     177613
	               header'normalize     174665
	               header'parsedate     175756
	                    header'push     173193
	                   header'reset     170317
	                   header'valid     170633
	                 header'warning     171340
	                     hook'audit     395647
	                   hook'deliver     396398
	                   hook'hooking     397614
	                      hook'init     392434
	                   hook'initvar     345091
	                      hook'perl     394995
	                   hook'process     392854
	                   hook'program     394230
	                     hook'rules     394508
	                       hook'run     346105
	                      hook'type     393499
	                   hook'unknown     394081
	                  interface'add     348243
	                  interface'new     346620
	                interface'reset     346852
	                interface'valid     347842
	                      lock'base      44971
	                       lock'dir      45093
	                      lock'file      44484
	                   macro'domain     168858
	                     macro'info     168588
	                 macro'internet     169008
	                      macro'org     168741
	                 macro'overload     169654
	                      macro'usr     473415
	                  main'acs_lock      41962
	               main'acs_locktry      41160
	                  main'acs_rqst      40810
	              main'action_parse      56066
	                   main'add_log      46327
	                     main'after     242846
	               main'alarm_clock     219860
	           main'alter_execution     140695
	               main'alter_field     234485
	                main'alter_flow     244318
	              main'alter_header     230805
	               main'alter_value     236311
	              main'analyze_mail      88959
	           main'annotate_header     232613
	                     main'apply     210716
	               main'apply_match     145662
	               main'apply_rules      93443
	        main'best_body_encoding      86871
	                      main'biff     498921
	                main'body_check      67067
	               main'body_recode      70089
	     main'body_recode_optimally      71112
	          main'body_recode_with      68850
	                    main'bounce     200046
	              main'builtin_path     286559
	                main'builtin_rr     286158
	             main'catch_signals     485099
	                      main'cdir     408175
	             main'check_st_mode     405204
	                 main'checklock      49942
	             main'compile_rules     287668
	             main'complete_list     245510
	     main'contextual_operations     344090
	             main'default_rules     291742
	                        main'do     241558
	                  main'do_abort     245211
	                 main'do_reject     244817
	                main'do_restart     245013
	               main'domain_addr      31319
	                 main'dump_mbox     328438
	                main'dump_rules     292619
	                main'email_addr      30784
	            main'emergency_save     327719
	                main'empty_body     249654
	                     main'error     305704
	                main'eval_error      34606
	                 main'eval_expr     307682
	                  main'evaluate     309429
	                main'exact_rule     292501
	               main'exec_secure     405828
	                   main'execute     306251
	           main'execute_command     221359
	       main'expr_selector_match     148068
	                     main'fatal     325279
	                 main'feed_back     226044
	                 main'file_edit     459009
	               main'file_secure     398382
	                main'fork_child      33657
	                   main'forward     198294
	                 main'free_file      45360
	              main'fuzzy_domain     104105
	            main'gen_message_id     163920
	                    main'gensym     469917
	                main'get_action      55237
	         main'get_configuration      23712
	                  main'get_line      51244
	                  main'get_mode      52104
	               main'get_pattern      53342
	              main'get_selector      52594
	                   main'getdate     371401
	             main'handle_output     224375
	             main'header_append      86277
	              main'header_check      74288
	main'header_check_body_encoding      72182
	              main'header_found     178127
	              main'header_lines      65018
	              main'header_parse      63245
	            main'header_prepend      86512
	             main'header_resync     230370
	        main'header_update_size      65286
	            main'history_ignore     322868
	            main'history_record     323394
	               main'history_tag     319801
	                  main'hostname     375143
	              main'include_file     373263
	                  main'init_all      24063
	             main'init_builtins     285989
	            main'init_constants      24563
	                  main'init_env      27018
	               main'init_filter     110362
	          main'init_interpreter     304564
	              main'init_matcher     142224
	            main'init_pseudokey      27186
	              main'init_special      87795
	             main'internet_info     162811
	                    main'jobnum      34886
	                 main'last_name     162582
	                     main'leave     178713
	                main'list_queue     332960
	               main'locate_file     158677
	            main'locate_program     159571
	                main'login_name     161722
	                     main'macro     191907
	              main'macros_subst     164358
	                 main'mail_back     224698
	              main'mail_logname      88327
	              main'mail_logsize      88665
	              main'mailbox_name      32145
	              main'make_pattern     143422
	                   main'makedir     324729
	                     main'match     144499
	                main'match_list     153804
	              main'match_single     151488
	                 main'match_var     154765
	                 main'mbox_lock      28009
	                 main'mbox_mail     338607
	               main'mbox_unlock      30190
	                   main'message     193246
	                    main'mrange     157788
	                        main'mv     278043
	                main'myhostname     374929
	                    main'notify     193573
	                main'once_check     323609
	             main'parse_address     160671
	                main'parse_mail      58317
	           main'patch_constants      26565
	                      main'perl     237642
	              main'perl_pattern     142959
	                    main'plural     374465
	                     main'pmail     282887
	              main'popen_failed     219487
	                      main'post     201486
	                    main'pqueue     279983
	         main'print_binary_mail     220842
	                main'print_rule     296561
	         main'print_rule_number     292218
	                   main'process     184610
	                  main'push_val     305900
	                         main'q     392335
	                     main'qmail     270294
	                main'queue_mail     272027
	               main'read_config      35330
	             main'read_filerule      50787
	             main'read_linerule      50998
	                main'read_stats     250561
	                 main'reception     105004
	              main'relative_age     303928
	                main'relay_list      78999
	              main'report_stats     260282
	                   main'require     240555
	             main'reset_backref     156552
	                    main'resync     330753
	                main'right_mode     100600
	              main'rule_cleanup     292040
	                 main'run_abort     118097
	                 main'run_after     135532
	              main'run_annotate     129592
	                 main'run_apply     134615
	                main'run_assign     129917
	                  main'run_back     122862
	                  main'run_beep     136448
	                 main'run_begin     118548
	                  main'run_biff     137443
	                main'run_bounce     120406
	              main'run_builtins     286789
	               main'run_command     107554
	                main'run_delete     116430
	                    main'run_do     136088
	                  main'run_feed     122132
	               main'run_forward     120098
	                  main'run_give     121590
	                  main'run_keep     129336
	                 main'run_leave     114816
	                 main'run_macro     116616
	               main'run_message     116869
	                   main'run_nop     128706
	                main'run_notify     117217
	                    main'run_on     124076
	                  main'run_once     125693
	                  main'run_pass     121859
	                  main'run_perl     133887
	                  main'run_pipe     121268
	                  main'run_post     120706
	               main'run_process     114041
	               main'run_protect     136798
	                main'run_purify     122516
	                 main'run_queue     133469
	                main'run_record     118960
	                main'run_reject     117779
	               main'run_require     134194
	               main'run_restart     117938
	                main'run_resync     118253
	                   main'run_run     121002
	                  main'run_save     115238
	                main'run_saving     138437
	                main'run_select     127042
	                main'run_server     114303
	                 main'run_split     130990
	                 main'run_store     115391
	                 main'run_strip     129076
	                 main'run_subst     130839
	                    main'run_tr     130688
	                 main'run_umask     135053
	                main'run_unique     119566
	              main'run_vacation     132387
	                 main'run_write     116082
	            main'runop_on_field     233717
	                  main's_action     256501
	                 main's_default     255946
	                  main's_failed     256670
	                main's_filtered     255640
	                   main's_match     255793
	                 main's_noretry     257042
	                    main's_once     256879
	                   main's_saved     256243
	                    main's_seen     256376
	                main's_vacation     256095
	               main'same_device     279559
	                      main'save     179295
	               main'save_folder     181035
	                 main'save_hook     184339
	                 main'save_mail     246208
	              main'save_message     141492
	         main'seconds_in_period     302940
	            main'selector_match     150216
	              main'send_message     194419
	              main'send_receipt     284247
	             main'set_functions     305216
	            main'set_priorities     304994
	             main'shell_command     217764
	              main'special_user     101942
	                     main'split     211792
	                main'stderr_log      46682
	                main'stdout_log      47081
	              main'symdir_check     402534
	             main'symdir_secure     401148
	             main'symfile_check     403906
	            main'symfile_secure     401525
	                     main'tilda      31821
	              main'tilda_expand     476223
	                main'trace_dump     250074
	                main'track_rule     105910
	            main'update_backref     157015
	              main'update_stack     306956
	                     main'usage      22617
	                   main'usr_log      48064
	                 main'void_func     292385
	              main'waiting_mail     276816
	               main'write_stats     252771
	            main'write_waitkeys     329799
	                  main'xeq_back     229907
	                     main'xeqte     106357
	                     mbox'flush     340151
	              mbox'flush_blanks     339801
	              mbox'flush_buffer     339978
	                     mh'new_msg     480142
	                     mh'profile     479212
	                        mh'save     476587
	                    mh'save_msg     477531
	                     mh'savedir     477251
	                      mh'seqadd     483954
	                      mh'unseen     481929
	                     mmdf'chmod     378863
	            mmdf'force_flushing     377970
	                   mmdf'is_mmdf     378175
	                      mmdf'save     375517
	                 mmdf'save_mmdf     376012
	                 mmdf'save_unix     377083
	                    newcmd'load     388194
	                     newcmd'run     390348
	                        opt'get     522607
	                      opt'parse     524499
	                      opt'reset     523573
	                    opt'restore     523943
	                power'add_alias     455756
	                 power'add_auth     454793
	                  power'add_log     458716
	                 power'authfile     453800
	               power'authorized     452309
	                power'del_alias     456066
	                 power'getpwent     457281
	                    power'grant     451605
	                 power'rem_auth     455062
	                 power'rempwent     458205
	                 power'set_auth     454341
	               power'set_passwd     456442
	                 power'setpwent     457844
	               power'used_alias     455371
	                    power'valid     453204
	                      qp'decode     545756
	                      qp'encode     546450
	                   qp'error_msg     548023
	                    qp'is_valid     547905
	                      qp'output     547537
	                       qp'reset     545396
	                rules'alternate     301374
	                 rules'cache_ok     299501
	               rules'read_cache     298375
	              rules'write_cache     297137
	                 rules'write_fd     300158
	              rules'writevar_fd     300711
	               stats'diff_rules     257359
	               stats'fill_stats     259074
	              stats'print_array     255400
	           stats'print_commands     265378
	            stats'print_general     264243
	             stats'print_header     268330
	      stats'print_rules_summary     267474
	              stats'print_stats     262554
	            stats'print_summary     263634
	               stats'rule_stats     269223
	             stats'uniform_rule     267071
	              termios'decompile     548513
	                   termios'init     548156
	                   termios'size     548999
	                  usrlog'delete      47822
	                     usrlog'new      47369
	               usrlog'write_log      48390
	                   usrmac'cache     475916
	                  usrmac'delete     472187
	                    usrmac'init     470371
	                     usrmac'new     471360
	                     usrmac'pop     471797
	                    usrmac'push     470892
	                 usrmac'restore     472930
	                    usrmac'save     472623
	               usrmac'sub_const     474319
	                usrmac'sub_expr     474163
	                  usrmac'sub_fn     474648
	                usrmac'sub_prog     475039
	               usrmac'sub_progc     475531
	              usrmac'sub_scalar     474020
	                      utmp'init     496913
	                    utmp'reload     497765
	                      utmp'ttys     498465
	                    utmp'update     497458

#
# End of offset table and beginning of dataloading section.
#

# Print usage and exit
sub main'load_usage {
	package main;
	print STDERR <<EOF;
Usage: $prog_name [-dhilqtFIVU] [-s{umaryt}] [-f file] [-e rules] [-c config]
       [-L level] [-r file] [-o def] [mailfile]
  -c : specify alternate configuration file.
  -d : dump filter rules (special).
  -e : enter rules to be applied.
  -f : get messages from UNIX-style mailbox file.
  -h : print this help message and exits.
  -i : interactive usage -- print log messages on stderr.
  -l : list message queue (special).
  -o : overwrite config file with supplied definition.
  -q : process the queue (special).
  -r : specify alternate rule file.
  -s : report gathered statistics (special).
  -t : track rules on stdout.
  -F : force processing on already filtered messages.
  -I : install configuration and perform sanity checks.
  -L : force logging level.
  -V : print version number and exits.
  -U : prevent UNIQUE from rejecting an already processed Message-ID.
EOF
	exit 1;
}

# Read configuration file and alter it with the values specified via -o.
# Then apply -r and -t by modifying suitable configuration parameters.
sub main'load_get_configuration {
	package main;
	&read_config($config_file);		# Read configuration file and set vars
	&cf'parse($over_config);		# Overwrite with command line options
	$cf'rules = $rule_file if $rule_file;		# -r overwrites rule file
	$loglvl = $log_level if $log_level >= 0;	# -L overwrites logging level
}

# Start-up initializations
sub main'load_init_all {
	package main;
	&catch_signals;		# Trap common signals
	&init_interpreter;	# Initialize tables %Priority, %Function, ...
	&init_env;			# Initialize the %XENV array
	&init_matcher;		# Initialize special matching functions
	&init_pseudokey;	# Initialize the pseudo header keys for H table
	&init_builtins;		# Initialize built-in commands like @RR
	&init_filter;		# Initialize filter commands
	&init_special;		# Initialize special user table %Special
}

# Constants definitions
sub main'load_init_constants {
	package main;
	# Values for flock(), usually in <sys/file.h>
	$LOCK_SH = 1;				# Request a shared lock on file
	$LOCK_EX = 2;				# Request an exclusive lock
	$LOCK_NB = 4;				# Make a non-blocking lock request
	$LOCK_UN = 8;				# Unlock the file

	# Stat constants for file rights
	$S_IWOTH = 00002;			# Writable by world (no .ph files here)
	$S_IWGRP = 00020;			# Writable by group
	$S_ISUID = 04000;			# Set user ID on exec
	$S_ISGID = 02000;			# Set group ID on exec

	# Status used by filter
	$FT_RESTART = 0;			# Abort current action, restart from scratch
	$FT_CONT = 1;				# Continue execution
	$FT_REJECT = 2;				# Abort current action, continue filtering
	$FT_ABORT = 3;				# Abort filtering process

	# Shall we append or remove folder?
	$FOLDER_APPEND = 0;			# Append in folder
	$FOLDER_REMOVE = 1;			# Remove folder

	# Used by shell_command and children
	$NO_INPUT = 0;				# No input (stdin is closed)
	$BODY_INPUT = 1;			# Give body of mail as stdin
	$MAIL_INPUT = 2;			# Pipe the whole mail
	$HEADER_INPUT = 3;			# Pipe the header only
	$MAIL_INPUT_BINARY = 4;		# Whole mail in binary (no transfer encoding)
	$NO_FEEDBACK = 0;			# No feedback wanted
	$FEEDBACK = 1;				# Feed result of command back into %Header
	$FEEDBACK_ENCODING = 2;		# Same as $FEEDBACK, but probe body for encoding

	# The filter message
	local($address) = &email_addr;
	$FILTER =
		"X-Filter: mailagent [version $mversion-$revision] for $address";
	$MAILER =
		"X-Mailer: mailagent [version $mversion-$revision]";

	# For header fields alteration
	$HD_STRIP = 0;				# Strip header fields
	$HD_KEEP = 1;				# Keep header fields

	# Faked leading From line (used for digest items, by SPLIT)
	local($now) = scalar(localtime());
	$now =~ s/\s(\d:\d\d:\d\d)\b/0$1/;	# Add leading 0 if hour < 10
	$FAKE_FROM = "From mailagent " . $now;

	# Miscellaneous constants
	$MAX_LINKS = 100;			# Maximum number of symbolic link levels
}

# Change some constants after configuration file was parsed
sub main'load_patch_constants {
	package main;
	local($address) = &email_addr;	# Will prefer cf vars to hardwired ones
	$FILTER =
		"X-Filter: mailagent [version $mversion-$revision] for $address";
}

# Initializes environment. All the variables are initialized in XENV array
# The sole purpose of XENV is to be able to know what changes wrt the invoking
# environment when dumping the rules. It also avoid modifying the environment
# for our children.
sub main'load_init_env {
	package main;
	foreach (keys(%ENV)) {
		$XENV{$_} = $ENV{$_};
	}
}

# List of special header keys which do not represent a true header field.
sub main'load_init_pseudokey {
	package main;
	%Pseudokey = (
		'Body', 1,			# Body of message
		'Head', 1,			# Header of message
		'All', 1,			# Concatenation of Header, "\n", Body
		'=Body=', 1,		# Reference to body with decoded transfer encoding
	);
}

# Attempts a mailbox locking. The argument is the name of the file, the file
# descriptor is the global MBOX, opened for appending.
# Returns true if the lock was obtained, false if the lock could not be
# obtained but we wish to continue anyway, and undef if the lock was not
# obtained and locksafe is ON (i.e. the user does not wish to risk a delivery
# with no locking).
# If locksafe is set to PARTIAL, we only wish a lock to protect against
# another concurrent mailagent delivery, so any partial lock is ok (e.g. an
# flock() lock was obtained, but no .lock).
sub main'load_mbox_lock {
	package main;
	local($file) = @_;				# File name
	local($locked) = 0;				# Did we get at least one lock?
	local($error) = 0;				# Assume no error
	local($lastlock) = '';			# Last lock we successfully grabbed

	# Initial .lock locking (optionally reconfigured via mboxlock)
	# Done only when not configured to perform flock()-style locks.

	unless ($flock_only) {			# Lock with .lock
		if (0 != &acs_rqst($file, $cf'mboxlock)) {
			&add_log("WARNING could not lock $file") if $loglvl > 5;
			$error++;
		} else {
			$locked++;
			$lastlock = 'mbox .lock';
		}
	}

	# Make sure the file is still there and as not been removed while we were
	# waiting for the lock (in which case our MBOX file descriptor would be
	# useless: we would write in a ghost file!). This could happen when 'elm'
	# (or other mail user agent) resynchronizes the mailbox.

	close MBOX;
	unless (open(MBOX, ">>$file")) {
		&fatal("could not reopen $file");
	}

	# Perform flock()-style locking if configured to do so.

	if ($lock_by_flock) {
		local($ok) = 0;
		eval { $ok = flock(MBOX, $LOCK_EX) };	# flock() may be missing!
		if ($@ ne '' && $flock_only) {
			&add_log("WARNING flock() not available for locking")
				if $loglvl > 5;
			$error++;
		} elsif ($ok) {
			$locked++;
			$lastlock = 'flock';
		} else {
			&add_log("WARNING could not flock $file: $!") if $loglvl > 5;
			$error++;
		}
	}

	&add_log("WARNING was unable to get any lock on $file")
		if !$locked && $loglvl > 5;

	&add_log("NOTICE got an \"$lastlock\"-style lock on $file")
		if $error && $locked && $cf'locksafe !~ /^ON/i && $loglvl > 6;

	seek(MBOX, 0, 2);			# Someone may have appended something

	if ($cf'locksafe =~ /^ON/i && $error) {
		&mbox_unlock;
		return undef;			# No lock grabbed, can't deliver to folder
	} elsif ($cf'locksafe =~ /^PARTIAL/i) {
		return 1 if $locked;	# We got a partial locking, allow delivery
		return undef;			# No lock, can't deliver to that mbox
	} elsif ($error) {
		return 0;				# False but defined, meaning we may deliver!
	}

	return 1;	# Ok, we did lock that mailbox and we may deliver to it
}

# Remove lock on mailbox and return a failure status if closing failed
sub main'load_mbox_unlock {
	package main;
	local($file) = @_;				# File name
	local($status);					# Error status from close
	$status = close(MBOX);			# Closing will remove flock lock
	&free_file($file, $cf'mboxlock) unless $flock_only;	# Remove the lock
	$status ? 0 : 1;				# Return 0 for ok, 1 if close failed
}

# 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. This routine is also used
# to set a default value for $cf'email.
# Once $cf'email exists however, its value is used.
sub main'load_email_addr {
	package main;
	if (defined $cf'email) {
		my $mail = $cf'email;
		$mail .= '@' . &domain_addr unless $mail =~ /@/;
		return $mail;
	}
	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
# Use $cf'domain and $cf'hidenet when available.
sub main'load_domain_addr {
	package main;
	local($_);							# Our host name
	if (defined $cf'domain) {
		$_ = $cf'domain;
		if (lc($cf'hidenet) ne "on" || $_ eq '') {
			$_ = &hostname;
			$_ .= ".$cf::domain" unless /\./;
		}
	} else {
		$_ = $hiddennet if $hiddennet ne '';
		if ($_ eq '') {
			$_ = &hostname;					# Must fork to get hostname, grr...
			$_ .= $mydomain unless /\./;	# We want something fully qualified
		}
	}
	$_;
}

# Strip out leading path to home directory and replace it by a ~
sub main'load_tilda {
	package main;
	local($path) = @_;					# Path we wish to shorten
	local($home) = $cf'home;
	$home =~ s/(\W)/\\$1/g;				# Escape possible meta-characters
	$path =~ s/^$home/~/;				# Replace the home directory by ~
	$path;								# Return possibly stripped path
}

# Compute the system mailbox file name
sub main'load_mailbox_name {
	package main;
	# If ~/.mailagent provides us with a mail directory, use it and possibly
	# override value computed by Configure.
	$maildir = $cf'maildrop if $cf'maildrop ne '';
	# If Configure gave a valid 'maildir', use it. Otherwise compute one now.
	unless ($maildir ne '' && -d "$maildir") {
		$maildir = "/var/spool/mail";		# Default spooling area
		-d "$maildir" || ( -d "/usr/mail" && ($maildir = "/usr/mail"));
		-d "$maildir" || ($maildir = "$cf'home");
	}
	local($mbox) = $cf'user;					# Default mailbox file name
	$mbox = $cf'mailbox if $cf'mailbox ne '';	# Priority to config variable
	$mailbox = "$maildir/$mbox";				# Full mailbox path
	if (! -f "$mailbox" && ! -w "$maildir") {
		# No mailbox already exists and we can't write in the spool directory.
		# Use mailfile then, and if we can't write in the directory and the
		# mail file does not exist either, use ~/mbox.$cf'user as mailbox.
		$mailbox = $mailfile;		# Determined by configure (%~ and %L form)
		$mailbox =~ s/%~/$cf'home/go;	# %~ stands for the user directory
		$mailbox =~ s/%L/$cf'user/go;	# %L stands for the user login name
		$mailbox =~ m|(.*)/.*|;			# Extract dirname
		$mailbox = "$cf'home/mbox.$cf'user" unless (-f "mailbox" || -w "$1");
		&add_log("WARNING using $mailbox for mailbox") if $loglvl > 5;
	}
	$mailbox;
}

# Fork a new mailagent and update the pid in the perl.lock file. The parent
# then exits and the child continues. This enables the filter which invoked
# us to finally exit.
sub main'load_fork_child {
	package main;
	local($pid) = fork;
	if ($pid == -1) {				# We cannot fork, exit.
		&add_log("ERROR couldn't fork to process the queue") if $loglvl > 5;
		unlink $lockfile if $locked;
		exit 0;
	} elsif ($pid == 0) {			# The child process
		# Update the pid in the perl.lock file, so that any process which will
		# use the kill(pid, 0) feature to check whether we are alive or not will
		# get a meaningful status.
		if ($locked) {
			chmod 0644, $lockfile;
			open(LOCK, ">$lockfile");	# Ignore errors
			chmod 0444, $lockfile;		# Now it's open, so we may restore mode
			print LOCK "$$\n";			# Write child's PID
			close LOCK;
		}
		sleep(2);					# Give filter time to clean up
	} else {						# Parent process
		exit 0;						# Exit without removing lock, of course
	}
	# Only the child comes here and returns
	&add_log("mailagent continues") if $loglvl > 17;
}

# Report any eval error and returns 1 if error detected.
sub main'load_eval_error {
	package main;
	if ($@ ne '') {
		$@ =~ s/ in file \(eval\) at line \d+//;	# Older perls
		$@ =~ s/ at \(eval \d+\) line \d+\.//;		# Modern perl 5.x
		chop($@);
		&add_log("ERROR $@") if $loglvl > 1;
	}
	$@ eq '' ? 0 : 1;
}

# Computes a new job number
sub main'load_jobnum {
	package main;
	local($job);						# Computed job number
	if (0 != &acs_rqst($cf'seqfile)) {
		$job = "?";
	} else {
		local($njob);
		open(FILE, "$cf'seqfile");
		$njob = int(<FILE>);
		close FILE;
		$njob++;
		open(FILE, ">$cf'seqfile");
		print FILE "$njob\n";
		close FILE;
		$job = "$njob";
		&free_file("$cf'seqfile");
	}
	$job;		# Return job number to be used
}

# Read configuration file (usually in ~/.mailagent)
sub main'load_read_config {
	package cf;
	local($file) = @_;				# where config file is located
	local($_);
	$file = '~/.mailagent' unless $file;
	local($myhome) = $ENV{'HOME'};	# must be correctly set by filter
	$file =~ s/~/$myhome/;			# ~ substitution
	local($main'config) = $file;	# Save it: could be modified by config
	open(CONFIG, "$file") ||
		&'fatal("can't open config file $file");
	local($config) = ' ' x 2000;	# pre-extend to avoid realloc()
	$config = '';
	while (<CONFIG>) {
		next if /^[ \t]*#/;			# skip comments
		next if /^[ \t]*\n/;		# skip empy lines
		s/([^\\](\\\\)*)@/$1\\@/g;	# escape all un-escaped @ in string
		$config .= $_;
	}
	&parse($config) || &'fatal('bad configuration');
	close CONFIG;

	# Security checks, pending of those performed by the C filter. They are
	# somewhat necessary, even though the mailagent does not run setuid
	# (because anybody may activate the mailagent for any user by sending him
	# a mail, and world writable configuration files makes the task too easy
	# for a potential hacker). The tests are performed once the configuration
	# file has been parsed, so logging of fatal errors may occur.

	local($unsecure) = 0;

	$unsecure++ unless &'file_secure($'config, 'config');
	$unsecure++ unless &'file_secure($rules, 'rule');
	&'fatal("unsecure configuration!") if $unsecure;

	return unless -f "$rules";		# No rule file
}

# Parse config file held in variable and return 1 if ok, 0 for errors
sub cf'load_parse {
	package cf;
	local($config) = @_;
	return 1 unless defined $config;
	local($eval) = ' ' x 1000;		# Pre-extend
	local($myhome) = $ENV{'HOME'};	# must be correctly set by filter
	local($var, $value);
	local($_);
	$eval = '';
	foreach (split(/\n/, $config)) {
		if (/^[ \t]*([^ \t\n:\/]*)[ \t]*:[ \t]*([^#\n]*)/) {
			$var = $1;
			$value = $2;
			$value =~ s/\s*$//;						# remove trailing spaces
			$eval .= "\$$var = \"$value\";\n";
			$eval .= "\$$var =~ s|~|\$myhome|g;\n";	# ~ substitution
		}
	}
	eval $eval;			# evaluate configuration parameters within package

	if ($@ ne '') {				# Parsing error detected
		local($error) = $@;		# Logged error
		$error = (split(/\n/, $error))[0];		# Keep only first line
		# Dump error message on stderr, as well as faulty configuration file.
		# The original is restored out of the perl form to avoid surprise.
		$eval =~ s/^\$.* =~ s\|~\|.*\n//gm;		# Remove added ~ substitutions
		$eval =~ s/^\$//gm;						# Remove leading '$'
		$eval =~ s/ = "(.*)";/: $1/gm;			# Keep only variable value
		chop($eval);
		print STDERR <<EOM;
**** Syntax error in configuration:
$error

---- Begin of Faulty Configuration
$eval
---- End of Faulty Configuration

EOM
		&'add_log("syntax error in configuration: $error") if $'loglvl > 1;
		return 0;
	}

	# Define the mailagent parameters from those in config file
	$logfile = $logdir . "/$log";
	$seqfile = $spool . "/$seq";
	$hashdir = $spool . "/$hash";
	$main'loglvl = int($level);		# This one is visible in the main package
	$main'track_all = 1 if $track =~ /on/i;		# Option -t set by config
	$sendmail = $'mailer if $sendmail eq '';	# No sendmail program specified
	$sendnews = $'inews if $sendnews eq '';		# No news posting program
	$mailopt = '-odq -i' if $mailopt eq '' && $sendmail =~ /sendmail/;

	# Backward compatibility -- RAM, 25/04/94
	$fromesc = 'ON' unless defined $fromesc;	# If absent from ~/.mailagent
	$lockmax = 20 unless defined $lockmax;
	$lockdelay = 2 unless defined $lockdelay;
	$lockhold = 3600 unless defined $lockhold;
	$queuewait = 60 unless defined $queuewait;
	$queuehold = 1800 unless defined $queuehold;
	$queuelost = 86400 unless defined $queuelost;
	$runmax = 3600 unless defined $runmax;
	$umask = 077 unless defined $umask;
	$email = $user unless defined $email;
	$compspec = "$spool/compressors" unless defined $compspec;
	$comptag = 'gzip' unless defined $comptag;
	$locksafe = 'OFF' unless defined $locksafe;
	$execsafe = 'OFF' unless defined $execsafe;

	# For backward compatibility, we force a .lock locking on mailboxes.
	# For system ones (name = login), there's no problem because the lock
	# file is still under the 14 characters limit. If mail is saved in folders
	# whose name is longer, there might be problems though. There's little we
	# can do about it here, lest they choose an alternate locking name.
	# Note that mailagent's $lockext global variable setting depends on the
	# fact that the target system supports flexible filenames or not, so only
	# mailbox locking is a problem -- RAM, 18/07/95

	$mboxlock = '%f.lock' unless defined $mboxlock;

	# Backward compatibility -- RAM, 17/03/2001
	$domain = $main::hiddennet || $main::mydomain unless defined $domain;
	$hidenet = $main::hiddennet eq '' ? 'OFF' : 'ON' unless defined $hidenet;

	$umask = oct($umask) if $umask =~ /^0/;	 # Translate umask into decimal
	$domain =~ s/^\.*//;					 # Strip leading '.'

	# Update @INC perlib search path with the perlib variable. Paths not
	# starting by a '/' are supposed to be under the mailagent private lib
	# directory.

	local(%seen);		# Avoid dups in @INC (might be called more than once)

	foreach (@INC) { $seen{$_}++; }

	if (defined $perlib) {
		foreach (split(':', $perlib)) {
			s/^~/$home/;
			$_ = $'privlib . '/' . $_ unless m|^/|;
			push(@INC, $_) unless $seen{$_}++;
		}
	}

	1;		# Ok
}

#
# acs_rqst
#
# Attempt to lock $file, using $format as locking format (used to derive the
# name of the lock file from the filename).
#
# Returns 0 if locked, -1 otherwise.
#
sub main'load_acs_rqst {
	package main;
	local($file, $format) = @_;		# file to be locked, lock format
	return &acs_lock($file, $format, 0);
}

#
# acs_locktry
#
# Same as acs_rqst, but if the file is already locked by some other party, we
# do not wish to wait for the lock.
#
# Returns 1 if locked by someone else, 0 if locked by us, -1 otherwise.
sub main'load_acs_locktry {
	package main;
	local($file, $format) = @_;		# file to be locked, lock format
	return &acs_lock($file, $format, 1);
}

#
# acs_lock
#
# Asks for the exclusive access of a file. The config variable 'nfslock'
# determines whether the locking scheme has to be NFS-secure or not.
# The given parameter (let's say F) is the absolute path of the file we want
# to access. The routine checks for the presence of F.lock. If it exists, it
# sleeps 2 seconds and tries again. After 10 trys, it reports failure by
# returning -1. Otherwise, file F.lock is created and the pid of the current
# process is written. It is checked afterwards.
#
# When $try is true, we return 1 if the file is already locked. This is used
# to attempt locking only when the file is not otherwise locked.
#
sub main'load_acs_lock {
	package main;
	local($file, $format, $try) = @_;	# file to be locked, format, try only?
	local($max) = $cf'lockmax;		# max number of attempts
	local($delay) = $cf'lockdelay;	# seconds to wait between attempts
	local($mask);		# to save old umask
	local($stamp);		# string written in lock file
	&checklock($file, $format);		# avoid long-lasting locks
	if ($cf'nfslock =~ /on/i) {			# NFS-secure lock wanted
		$stamp = "$$" . &hostname;		# use PID and hostname
	} else {
		$stamp = "$$";					# use PID only (may spare a fork)
	}
	local($lockfile) = $file . $lockext;
	$lockfile = &lock'file($file, $format) if $format ne '';
	local($waited) = 0;					# amount of time spent sleeping
	local($lastwarn) = 0;				# last time we warned them...
	local($wmin, $wafter);				# busy lock warn limits

	if ($cf'lockwarn =~ /(\d+),\s*(\d+)/)	{ ($wmin, $wafter) = ($1, $2) }
	elsif ($cf'lockwarn =~ /(\d+)/)			{ ($wmin, $wafter) = ($1, $1) }
	else									{ ($wmin, $wafter) = (20, 300) }

	while ($max > 0) {
		$max--;
		if (-f $lockfile) {
			return 1 if $try;			# already locked
			next;
		}

		# Attempt to create lock
		$mask = umask(0333);			# no write permission
		if (open(FILE, ">$lockfile")) {
			print FILE "$stamp\n";		# write locking stamp
			close FILE;
			umask($mask);				# restore old umask
			# Check lock
			open(FILE, $lockfile);
			chop($_ = <FILE>);			# read contents
			close FILE;
			last if $_ eq $stamp;		# lock is ok
		} else {
			umask($mask);				# restore old umask
			return 1 if $try;			# already locked
			next;
		}
	} continue {
		sleep($delay);				# busy: wait
		$waited += $delay;
		# Warn them once after $wmin seconds and then every $wafter seconds
		if (
			(!$lastwarn && $waited > $wmin) ||
			($waited - $lastwarn) > $wafter
		) {
			local($waiting) = $lastwarn ? 'still waiting' : 'waiting';
			local($after) = $lastwarn ? 'after' : 'since';
			&add_log("WARNING $waiting for $file lock $after $waited seconds")
				if $loglvl > 3;
			$lastwarn = $waited;
		}
	}
	if ($max) {
		&add_log("NOTICE got $file lock after $waited seconds")
			if $lastwarn && $loglvl > 6;
		$result = 0;	# ok
	} else {
		$result = -1;	# could not lock
	}
	$result;			# return status
}

# Return the name of the lockfile, given the file name to lock and the custom
# string provided by the user. The following macros are substituted:
#	%D: the file dir name
#   %f: the file name (full path)
#   %F: the file base name (last path component)
#   %p: the process's pid
#   %%: a plain % character
sub lock'load_file {
	package lock;
	local($file, $_) = @_;
	s/%%/\01/g;				# Protect double percent signs
	s/%/\02/g;				# Protect against substitutions adding their own %
	s/\02f/$file/g;			# %f is the full path name
	s/\02D/&dir($file)/ge;	# %D is the dir name
	s/\02F/&base($file)/ge;	# %F is the base name
	s/\02p/$$/g;			# %p is the process's pid
	s/\02/%/g;				# All other % kept as-is
	s/\01/%/g;				# Restore escaped % signs
	$_;
}

# Return file basename (last path component)
sub lock'load_base {
	package lock;
	local($file) = @_;
	local($base) = $file =~ m|^.*/(.*)|;
	$base;
}

# Return dirname
sub lock'load_dir {
	package lock;
	local($file) = @_;
	local($dir) = $file =~ m|^(.*)/.*|;
	$dir;
}

# Remove the lock on a file. Returns 0 if ok, -1 otherwise
# Locking format is optional but when given must match the one used by
# the &acs_rqst() locking routine.
sub main'load_free_file {
	package main;
	local($file, $format) = @_;		# locked file, locking format
	local($stamp);					# string written in lock file

	if ($cf'nfslock =~ /on/i) {			# NFS-secure lock wanted
		$stamp = "$$" . &hostname;		# use PID and hostname
	} else {
		$stamp = "$$";					# use PID only (may spare a fork)
	}

	local($lockfile) = $file . $lockext;
	$lockfile = &lock'file($file, $format) if defined $format;

	if ( -f $lockfile) {
		# if lock exists, check for pid
		open(FILE, $lockfile);
		chop($_ = <FILE>);
		close FILE;
		if ($_ eq $stamp) {
			# pid (plus hostname eventually) is correct
			$result = 0;
			unlink $lockfile;
		} else {
			# pid is not correct (we did not get that lock)
			$result = -1;
		}
	} else {
		# no lock file
		$result = 0;
	}
	$result;	# return status
}

# Add an entry to logfile
# There is no need to lock logfile as print is sandwiched betweeen
# an open and a close (kernel will flush at the end of the file).
sub main'load_add_log {
	package main;
	# Indirection needed, so that we may remap add_log on stderr_log via a
	# type glob assignment.
	&usrlog'write_log($cf'logfile, $_[0], undef);
}

# When mailagent is used interactively, log messages are also printed on
# the standard error.
# NB: this function is not called directly, but via a type glob *add_log.
sub main'load_stderr_log {
	package main;
	print STDERR "$prog_name: $_[0]\n";
	&usrlog'write_log($cf'logfile, $_[0], undef);
}

# Routine used to emit logs when no logging has been configured yet.
# As soon as a valid configuration has been loaded, logs will also be
# duplicated into the logfile. Used solely by &cf'setup.
# NB: this function is not called directly, but via a type glob *add_log.
sub main'load_stdout_log {
	package main;
	print STDOUT "$prog_name: $_[0]\n";
	&usrlog'write_log($cf'logfile, $_[0], undef) if defined $cf'logfile;
}

# Record a new logfile by storing its pathname in the %Logpath hash table
# indexed by names and the carbon-copy flag in the %Cc table.
sub usrlog'load_new {
	package usrlog;
	local($name, $path, $cc) = @_;
	return if defined $Logpath{$name};	# Logfile already recorded
	return if $name eq 'default';		# Cannot redefined defaul log
	$path = "$cf'logdir/$path" unless $path =~ m|^/|;
	$Logpath{$name} = $path;			# Where logfile should be stored
	$Cc{$name} = $cc ? 1 : 0;			# Should we cc the default logfile?
	$Map{$path} = $name;				# Two-way hash table
}

# Delete user-defined logfile.
sub usrlog'load_delete {
	package usrlog;
	local($name) = @_;
	return unless defined $Logpath{$name};
	local($path) = $Logpath{$name};
	delete $Logpath{$name};
	delete $Cc{$name};
	delete $Map{$path};
}

# User-level logging main entry point
sub main'load_usr_log {
	package usrlog;
	local($name, $message) = @_;	# Logfile name and message to be logged
	local($file);
	$file = ($name eq 'default' || !defined $Logpath{$name}) ?
		$cf'logfile : $Logpath{$name};
	&write_log($file, $message, $Cc{$name});
}

# Log message into logfile, using jobnum to identify process.
sub usrlog'load_write_log {
	package usrlog;
	local($file, $msg, $cc) = @_;	# Logfile, message to be logged, cc flag
	local($date);
	local($log);

	return unless length $file;

	local ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
		localtime(time);
	$date = sprintf("%.2d/%.2d/%.2d %.2d:%.2d:%.2d",
		$year % 100,++$mon,$mday,$hour,$min,$sec);
	$log = $date . " $'prog_name\[$'jobnum\]: $msg\n";

	# If we cannot append to the logfile, first check whether it is the default
	# logfile or not. If it is not, then add a log entry to state the error in
	# the default log and then delete that user logname entry, assuming the
	# fault we get is of a permanent nature and not an NFS failure for instance.

	unless (open(LOGFILE, ">>$file")) {
		if ($file ne $cf'logfile) {
			local($name) = $Map{$file};	# Name under which it was registered
			&'add_log("ERROR cannot append to $name logfile $file: $!")
				if $'loglvl > 1;
			&'add_log("NOTICE removing logging to $file") if $'loglvl > 6;
			&delete($Map{$file});
			$cc = 1;				# Force logging to default file
		} else {					# We were already writing to default log
			return;					# Cannot log message at all
		}
	}

	print LOGFILE $log;
	close LOGFILE;

	# If $cc is set, a copy of the same log message (same time stamp guaranteed)
	# is made to the default logfile. If called with $file set to that default
	# logfile, $cc will be undef by construction.

	if ($cc) {
		open(LOGFILE, ">>$cf'logfile");
		print LOGFILE $log;
		close LOGFILE;
	}
}

# Make sure lock lasts for a reasonable time
sub main'load_checklock {
	package main;
	local($file, $format) = @_;				# Full path name, locking format
	local($lockfile) = $file . $lockext;	# Add lock extension
	$lockfile = &lock'file($file, $format) if defined $format;
	if (-f $lockfile) {
		# There is a lock file -- look for how long it's been there
		local($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
			$atime,$mtime,$ctime,$blksize,$blocks) = stat($lockfile);
		if ((time - $mtime) > $cf'lockhold) {
			# More than outdating time!! Something must have gone wrong
			unlink $lockfile;
			$file =~ s|.*/(.*)|$1|;	# Keep only basename
			&add_log("UNLOCKED $file (lock older than $cf'lockhold seconds)")
				if $loglvl > 5;
		}
	}
}

# The following subroutine is called whenever a new rule input is needed.
# It returns that new line or a null string if end of file has been reached.
sub main'load_read_filerule {
	package main;
	<RULES>;					# Read a new line from file
}

# The following subroutine is called in place of read_rule when rules are
# coming from the command line via @Linerules.
sub main'load_read_linerule {
	package main;
	$.++;						# One more line
	shift(@Linerules);			# Read a new line from array
}

# 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 main'load_get_line {
	package main;
	&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)
		last unless defined $_;	# end of file reached
		&add_log("READ <<$_>>") if $loglvl > 24;
		s/\n$//;				# don't use chop in case we read from array
		next if /^\s*#/;		# skip comments
		next if /^\s*$/;		# skip empty lines
		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 main'load_get_mode {
	package main;
	&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 main'load_get_selector {
	package main;
	&add_log("IN get_selector") if $loglvl > 24;
	local(*line) = shift(@_);	# edited in place
	local($_) = $line;			# make a copy of original
	local($selector) = "";
	s/^\s*,//;					# remove rule separator
	if (/^\s*\[\[/) {			# detected a script form
		$selector = 'script:';
	} else {
		s/^\s*([^\/,{\n]*(<[\d\s,-]+>)?\s*:)// && ($selector = $1);
	}
	$line = $_;					# eventually updates the line
	&add_log("OUT get_selector: $selector") if $loglvl > 24;
	$selector;
}

# A pattern if either a single word (with no white space) or something
# starting with a / and ending with an un-escaped / followed by some optional
# modifiers.
# Patterns may be preceded by a single '!' to negate the matching value.
sub main'load_get_pattern {
	package main;
	&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
	local($buffer) = "";			# the buffer used for parsing
	local($not) = '';				# shall boolean value be negated?
	local($script) = 0;				# true if pattern is a script
	s|^\s*||;						# remove leading spaces
	s/^!// && ($not = '!');			# A leading '!' inverts matching status
	if (s|^\[\[([^{]*)\]\]||) {		# pattern is a script
		$pattern = $1;				# get the whole script
		$script++;					# mark it as a script
	} elsif (s|^/||) {				# pattern starts with a /
		$pattern = "/";				# record the /
		while (s|([^/]*/)||) {		# while there is something before a /
			$buffer = $1;			# save what we've been reading
			$pattern .= $1;
			last unless $buffer =~ m|\\/$|;	# finished unless / is escaped
		}
		s/^(\w+)// && ($pattern .= $1);		# add optional modifiers
	} else {								# pattern does not start with a /
		s/([^\s,;{]*)// && ($pattern = $1);	# grab all until next delimiter
	}
	$line = $_;					# eventually updates the line
	$pattern =~ s/\s+$//;		# remove trailing spaces

	# In perl 4.0, we could write /^ram@acri\.fr/, but in perl 5.0, that
	# is not allowed since @ is now interpolated in patterns and strings.
	# In order to let them still write things that way, or escape the @
	# if they don't mind, we replace all un-escaped @ by escaped ones.

	$pattern =~ s/([^\\](\\\\)*)@/$1\\@/g unless $script;

	if ($not && !$pattern) {
		&add_log("ERROR discarding '!' not followed by pattern") if $loglvl;
	} 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 main'load_get_action {
	package main;
	&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
}

# Recursively parse the action string and return the parsed portion of the text
# with proper nesting wherever necessary. The string given as parameter is
# edited in place and the remaining is the unparsed part.
sub main'load_action_parse {
	package main;
	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.
		s/^(([^\\{}]|\\.)*\{)// && ($parsed .= $1);
		# Go to first un-escaped '}', with any '{' stopping scan.
		$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 '{'
			# interposes, the first match will return an empty string. In that
			# case, we continue if we are not at level #0. Otherwise we got the
			# whole action and may return now.
			$block = '';
			s/^(([^\\{}]|\\.)*\})// && ($block = $1);
			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;
}

# Parse the mail and fill-in the Header associative array. The special entries
# All, Body and Head respectively hold the whole message, the body and the
# header of the message.
sub main'load_parse_mail {
	package main;
	local($file_name) = shift(@_);	# Where mail is stored ("" for stdin)
	local($head_only) = shift(@_);	# Optional parameter: parse only header
	local($last_header) = "";		# Name of last header (for continuations)
	local($first_from) = "";		# The first From line in mails
	local($lines) = 0;				# Number of lines in the body
	local($length) = 0;				# Length of body, in bytes
	local($last_was_nl) = 1;		# True when last line was a '\n' (1 for EOH)
	local($fd) = STDIN;				# Where does the mail come from ?
	local($field, $value);			# Field and value for current line
	local($_);
	local($preext) = 0;
	local($added) = 0;
	local($curlen) = 0;
	undef %Header;					# Reset the whole structure holding message

	if ($file_name ne '') {			# Mail spooled in a file
		unless(open(MAIL, $file_name)) {
			&add_log("ERROR cannot open $file_name: $!");
			return;
		}
		$fd = MAIL;
		$preext = -s MAIL;
	}
	$Userpath = "";					# Reset path from possible previous @PATH 

	# Pre-extend 'All', 'Body' and 'Head'
	if ($preext <= 0) {
		$preext = 100_000;
		&add_log("preext uses fixed value ($preext)") if $loglvl > 19;
	} else {
		&add_log("preext uses file size ($preext)") if $loglvl > 19;
	}
	$preext += 500;					# Extra room for From --> >From, etc...

	$Header{'All'} = ' ' x $preext;
	$Header{'Body'} = ' ' x $preext;
	$Header{'Head'} = ' ' x 500;
	$Header{'All'} = '';
	$Header{'Body'} = '';
	$Header{'Head'} = '';

	&add_log ("parsing mail" . ($head_only ? " header" : "")) if $loglvl > 18;
	while (<$fd>) {
		$added += length($_);

		# If string extension goes beyond the pre-allocated space, re-extend
		# by a big amount instead of letting perl realloc space.
		if ($added > $preext) {
			$curlen = length($Header{'All'});
			&add_log ("extended after $curlen bytes") if $loglvl > 19;
			$Header{'All'} .= ' ' x $preext;
			substr($Header{'All'}, $curlen) = '';
			$curlen = length($Header{'Body'});
			$Header{'Body'} .= ' ' x $preext;
			substr($Header{'Body'}, $curlen) = '';
			$added = $added - $preext;
		}

		$Header{'All'} .= $_;
		if (1../^$/) {						# EOH is a blank line
			next if /^$/;					# Skip EOH marker
			chop;

			if (/^\s/) {					# It is a continuation line
				my $val = $_;
				$val =~ s/^\s+/ /;			# Swallow multiple spaces
				$Header{$last_header} .= $val if $last_header ne '';
				&add_log("WARNING bad continuation in header, line $.")
					if $last_header eq '' && $loglvl > 4;
			} elsif (($field, $value) = /^([!-9;-~\w-]+):\s*(.*)/) {
				# We found a new header field (i.e. it is not a continuation).
				# Guarantee only one From: header line. If multiple From: are
				# found, keep the last one.
				# Multiple headers like 'Received' are separated by a new-
				# line character. All headers end on a non new-line.
				# Case is normalized before recording, so apparently-to will
				# be recorded as Apparently-To but header is not changed.
				$last_header = &header'normalize($field);	# Normalize case
				if ($last_header eq 'From' && defined $Header{$last_header}) {
					$Header{$last_header} = $value;
					&add_log("WARNING duplicate From in header, line $.")
						if $loglvl > 4;
				} elsif ($Header{$last_header} ne '') {
					$Header{$last_header} .= "\n" . $value;
				} else {
					$Header{$last_header} .= $value;
				}
			} elsif (/^From\s+(\S+)/) {		# The very first From line
				$first_from = $1;
			} else {
				# Did not identify a header field nor a continuation
				# Maybe there was a wrong header split somewhere?
				# If we did not encounter a header yet, we're seeing garbage.
				if ($last_header eq '') {
					&add_log("ERROR ignoring header garbage, line $.: $_")
						if $loglvl > 1;
					next;					# Skip insertion to 'Head'
				} else {
					&add_log("WARNING ".
						"faking continuation for $last_header, line $."
					) if $loglvl > 4;
					$_ = " " . $_;			# Patch line for 'Head'
					$Header{$last_header} .= $_;
				}
			}

			$Header{'Head'} .= $_ . "\n";	# Record line in header

		} else {
			last if $head_only;		# Stop parsing if only header wanted
			$lines++;								# One more line in body
			$length += length($_);					# Update length of message
			# Protect potentially dangerous lines when asked to do so
			# From could normally be mis-interpreted only after a blank line,
			# but some "broken" User Agents also look for them everywhere...
			# That's where fromall must be set to ON to escape all of them.
			s/^From(\s)/>From$1/ if $last_was_nl && $cf'fromesc =~ /on/i;
			$last_was_nl = /^$/ || $cf'fromall =~ /on/i;
			$Header{'Body'} .= $_;
		}
	}
	close MAIL if $file_name ne '';
	&header_prepend("$FAKE_FROM\n") unless $first_from;
	&body_check unless $head_only;
	&header_check($first_from, $lines);	# Sanity checks
}

# Parse given header string into the supplied hash ref.
# Do that silently if told to do so via $silent.
# Returns: the value of the first From line, and fills %$href.
sub main'load_header_parse {
	package main;
	my ($headers, $href, $silent) = @_;
	# There is some code duplication with parse_mail() above
	local($first_from);						# First From line records sender
	local($last_header);					# Current normalized header field
	local($value);							# Value of current field
	my $missing_warned = 0;
	foreach (split(/\n/, $headers)) {
		if (/^\s/) {					# It is a continuation line
			s/^\s+/ /;					# Swallow multiple spaces
			$href->{$last_header} .= $_ if $last_header ne '';
		} elsif (/^([!-9;-~\w-]+):\s*(.*)/) {	# We found a new header
			$value = $2;				# Bug in perl 4.0 PL19
			$last_header = &header'normalize($1);
			$missing_warned = 0;
			# Multiple headers like 'Received' are separated by a new-
			# line character. All headers end on a non new-line.
			if ($href->{$last_header} ne '') {
				$href->{$last_header} .= "\n$value";
			} else {
				$href->{$last_header} .= $value;
			}
		} elsif (/^From\s+(\S+)/) {		# The very first From line
			$first_from = $1;
		} else {
			# Did not identify a header field nor a continuation
			# Maybe there was a wrong header split somewhere?
			if ($last_header eq '') {
				&add_log("ERROR ignoring leading header garbage: $_")
					if $loglvl > 1 && !$silent;
			} else {
				&add_log("ERROR missing continuation for $last_header: $_")
					if !$missing_warned && $loglvl > 1 && !$silent;
				$href->{$last_header} .= " " . $_;
				$missing_warned++;
			}
		}
	}
	return $first_from;
}

# Compute amount of lines listed in the header
# We do NOT use $Header{'Lines'} here since this is a filtering value which
# represents the number of lines in the *decoded* body, not the physical
# number of lines in the message which the Lines header in the message is
# supposed to represent.
sub main'load_header_lines {
	package main;
	my ($lines) = $Header{'Head'} =~ /^Lines:\s*(\d+)/im;
	return $lines;
}

# Set number of Lines in body and body Length to reflect reality
# If the headers were physically present in the message, they are
# updated as well.
sub main'load_header_update_size {
	package main;
	# Cannot trust %Header to indicate whether the headers were present
	# since we add these entries in any case...  Use a crude way to detect
	# presence then...
	my $had_lines = $Header{'Head'} =~ /^Lines:/im;
	my $had_length = $Header{'Head'} =~ /^Length:/im;

	my $lines = $Header{'Body'} =~ tr/\n/\n/;
	my $length = length($Header{'Body'});
	my $is_mime = exists $Header{'Mime-Version'};

	if ($had_lines && $lines != &header_lines) {
		alter_header("Lines", $HD_STRIP);
		header_append(header'format("Lines: $lines\n"));
	}

	# For filtering, use the *decoded* body!
	$Header{'Lines'} = ${$Header{'=Body='}} =~ tr/\n/\n/;
	$Header{'Length'} = length ${$Header{'=Body='}};

	if ($had_length) {
		alter_header("Length", $HD_STRIP);
		&add_log("NOTICE stripped non-RFC822 Length header") if $loglvl > 5;
	}

	if ($is_mime && exists $Header{'Content-Length'}) {
		my $clen = $Header{'Content-Length'};
		if ($clen != $length) {
			alter_header("Content-Length", $HD_STRIP);
			header_append(header'format("Content-Length: $length\n"));
			$Header{'Content-Length'} = $length;
			&add_log("NOTICE adjusted Content-Length from $clen to $length")
				if $loglvl > 5;
		}
	}

	if (!$is_mime && exists $Header{'Content-Length'}) {
		alter_header("Content-Length", $HD_STRIP);
		delete $Header{'Content-Length'};
		&add_log("NOTICE stripped Content-Length header in non-MIME message")
			if $loglvl > 5;
	}
}

# Check whether the body we got back has received a transfer encoding.
# If it has and we know about that transfer encoding, decode it.
# We make sure the "=Body=" header key is a reference to the decoded body:
# it is either a reference to $Header{'Body'} when we leave it as-is, or
# a reference to a newly allocated scalar.
sub main'load_body_check {
	package main;
	$Header{'=Body='} = \$Header{'Body'};
	my $encoding = lc($Header{'Content-Transfer-Encoding'});
	my %decode = map { $_ => 1 } qw(base64 quoted-printable);
	unless (exists $Header{'Mime-Version'}) {
		return unless length $encoding;
		if ($decode{$encoding}) {
			&add_log("WARNING ignoring $encoding body transfer encoding")
				if $loglvl > 3;
		} else {
			alter_header("Content-Transfer-Encoding", $HD_STRIP);
			delete $Header{'Content-Transfer-Encoding'};
			&add_log("NOTICE stripped $encoding encoding in non-MIME message")
				if $loglvl > 6;
		}
		return;
	}
	my %enc = map { $_ => 1 } qw(7bit 8bit binary base64 quoted-printable);
	$encoding =~ s/\s*;$//;		# Strip (wrong) spurious trailing separator
	if (length $encoding) {
		&'add_log("WARNING unknown content transfer encoding \"$encoding\"")
			if $'loglvl > 5 && !$enc{$encoding};
	}
	return unless $decode{$encoding};
	my @data = split(/\r?\n/, $Header{'Body'});
	my $error;
	my $output;
	if ($encoding eq "base64") {
		base64'reset(length $Header{'Body'});
		foreach my $d (@data) {
			base64'decode($d);
		}
		$error = base64'error_msg();
		$output = base64'output();
	} elsif ($encoding eq "quoted-printable") {
		qp'reset(length $Header{'Body'});
		foreach my $d (@data) {
			qp'decode($d);
		}
		$error = qp'error_msg();
		$output = qp'output();
	}
	if (length $error) {
		&'add_log("WARNING could not decode $encoding body: $error")
			if $'loglvl > 5;
	} else {
		if ($'loglvl > 9) {
			my $len = length $$output;
			&'add_log("decoded $encoding body into $len bytes");
		}
		$Header{'=Body='} = $output;		# Reference
	}
	&header_update_size;
}

# Force recoding of the body to a new encoding.
# The $Header{'Body'} variable is supposed to hold the decoded version.
sub main'load_body_recode_with {
	package main;
	my ($encoding) = @_;
	$Header{'=Body='} = \$Header{'Body'};	# The decoded version!
	my @data = split(/\r?\n/, $Header{'Body'});
	my $error;
	my $output;
	if ($encoding eq "base64") {
		base64'reset(length($Header{'Body'}) * 4/3);
		foreach my $d (@data) {
			base64'encode($d);
		}
		$error = base64'error_msg();
		$output = base64'output();
	} elsif ($encoding eq "quoted-printable") {
		qp'reset(length $Header{'Body'} * 1.1);
		foreach my $d (@data) {
			qp'encode($d);
		}
		$error = qp'error_msg();
		$output = qp'output();
	}
	if (length $error) {
		&'add_log("WARNING could not recode $encoding body: $error")
			if $'loglvl > 5;
	} else {
		if ($'loglvl > 9) {
			my $len = length $$output;
			&'add_log("recoded $encoding body into $len bytes") if $'loglvl > 7;
		}
		delete $Header{'Body'};		# $Header{'=Body='} ref still points to it
		$Header{'Body'} = $$output;	# Transfer-Encoded version of the body
		# The body changed, must update the "All" key...
		$Header{'All'} = $Header{'Head'} . "\n" . $Header{'Body'};
		&header_update_size;
	}
}

# When coming from a feeback routine such as PASS, we have a new body that
# maybe we need to recode to match the original encoding...
sub main'load_body_recode {
	package main;
	$Header{'=Body='} = \$Header{'Body'};	# The decoded version!
	my $encoding = lc($Header{'Content-Transfer-Encoding'});
	return unless length $encoding;
	unless (exists $Header{'Mime-Version'}) {
		&add_log("WARNING not recoding body in $encoding: no MIME header")
			if $loglvl > 3;
		alter_header("Content-Transfer-Encoding", $HD_STRIP);
		delete $Header{'Content-Transfer-Encoding'};
		return;
	}
	my %recode = map { $_ => 1 } qw(base64 quoted-printable);
	return unless $recode{$encoding};
	body_recode_with($encoding);
}

# When coming back from a FEED, check whether the content transfer encoding
# is suitable and replace it with the optimal one if not.
# Upon entry, we expect =Body= to point to the decoded versions and headers
# of the message to have been parsed in %Header (read: properly resync-ed).
# Both the header and the body of the message are updated if the encoding
# is changed.
# Return TRUE if body was recoded (implying caller should RESYNC the headers).
sub main'load_body_recode_optimally {
	package main;
	my $encoding = lc($Header{'Content-Transfer-Encoding'}) || "none";
	my $optimal = best_body_encoding($Header{'=Body='});
	my %encoded = map { $_ => 1 } qw(base64 quoted-printable);
	my $recoded = 0;
	if ($optimal ne $encoding) {
		&add_log("converting body encoded with $encoding to optimal $optimal")
			if $'loglvl > 7;
		if ($encoded{$optimal}) {
			$Header{'Body'} = ${$Header{'=Body='}};
			$Header{'=Body='} = \$Header{'Body'};	# The decoded version!
			body_recode_with($optimal);
		}
		alter_header("Content-Transfer-Encoding", $HD_STRIP);
		header_append(header'format("Content-Transfer-Encoding: $optimal\n"));
		$recoded = 1;
	}
	return $recoded;
}

# Whenever we got a new set of headers in $Header{'Head'} we need to ensure
# the new vision is consistent with the body encoding.  If they strip the
# Content-Transfer-Encoding header for instance, we have to use the old
# decoded version we had instead of the original body.
# If they add a Content-Transfer-Encoding header, we have to recode the body!
sub main'load_header_check_body_encoding {
	package main;
	my $plain = \$Header{'Body'} == $Header{'=Body='};	# No encoding
	if ($plain && $Header{'Head'} !~ /^Content-Transfer-Encoding:/mi) {
		# No encoding and no header indicating a transfer encodig...
		return;		# Nothing to change
	}
	my %new;
	header_parse($Header{'Head'}, \%new, 1);	# Silently parse new headers
	my $encoding = $Header{'Content-Transfer-Encoding'} || "none";
	my $new_encoding = lc($new{'Content-Transfer-Encoding'}) || "none";
	return if lc($encoding) eq $new_encoding;	# No change occurred

	&add_log(
		"WARNING body transfer encoding changed from $encoding to $new_encoding"
	) if $loglvl > 3;


	$Header{'Body'} = ${$Header{'=Body='}};		# Restore decoded version
	my %encode = map { $_ => 1 } qw(base64 quoted-printable);
	unless ($encode{$new_encoding}) {
		$Header{'=Body='} = \$Header{'Body'};
		return;
	}
	body_recode_with($new_encoding);			# Then re-encode it

	# At some point a RESYNC will be needed, caller will decide when it is
	# necessary to do it.
}

# Now do some sanity checks:
# - if there is no From: header, fill it in with the first From
# - if there is no To: but an Apparently-To:, copy it also as a To:
# - if an Envelope field was defined in the header, override it (sorry)
# - likewise for Relayed, which is the list of relaying hosts, first one first.
#
# We guarantee the following header entries (to select on in rules):
#   Envelope:     the actual sender of the message, empty if cannot compute
#   From:         the value of the From field
#   To:           to whom the mail was sent
#   Lines:        number of lines in the message (*decoded* version)
#   Length:       number of bytes in the message body (*decoded* version)
#   Relayed:      the list of relaying hosts deduced from Received: lines
#   Reply-To:     the address we may use to reply
#   Sender:       the value of the Sender field, same as From usually
#
# NB: When the $lines parameter is set, we parsed the whole message initially.
# When it is undef, we're resyncing, possibly after an external messaging of
# the message.
sub main'load_header_check {
	package main;
	local($first_from, $lines) = @_;	# First From line, number of lines
	unless (defined $Header{'From'}) {
		&add_log("WARNING no From: field, assuming $first_from") if $loglvl > 4;
		$Header{'From'} = $first_from;
		# Fake a From: header line unless prevented to do so. That way, when
		# saving in an MH or MMDF folder (where the leading From is stripped),
		# the user will still be able to identify the source of the message!
		if ($first_from && $cf'fromfake !~ /^off/i) {
			&add_log("NOTICE faking a From: header line") if $loglvl > 5;
			&header_append("From: $first_from\n");
		}
	}

	# There is usually one Apparently-To line per address. Remove all new lines
	# in the header line and replace them with ','. Likewise for To: and Cc:.
	# although it is far less likely to occur.
	foreach $field ('Apparently-To', 'To', 'Cc') {
		$Header{$field} =~ s/\n/,/gm;	# Remove new-lines
		$Header{$field} =~ s/,$/\n/m;	# Restore last new-line
	}

	# If no To: field, then maybe there is an Apparently-To: instead. If so,
	# make them identical. Otherwise, assume the mail was directed to the user.
	#
	# This changes the way filtering is done, so it's not always a good idea
	# to do it. Some people may want to explicitely check that there is no
	# To: line, but if we fake one, they'll never know. So check for tofake,
	# and if OFF, don't do anything.
	unless ($cf'tofake =~ /^off/i) {
		if (!$Header{'To'} && $Header{'Apparently-To'}) {
			$Header{'To'} = $Header{'Apparently-To'};
		}
		unless ($Header{'To'}) {
			&add_log("WARNING no To: field, assuming $cf'user") if $loglvl > 4;
			$Header{'To'} = $cf'user;
		}
	}

	# Update length information
	# No warning is emitted unless $lines was defined, indicating initial
	# parsing of the message we get.
	my $length = $Header{'Content-Length'};
	&header_update_size;		# Update number of lines and length...
	my $count = &header_lines;
	&add_log("NOTICE adjusted number of lines from $lines to $count")
		if $loglvl > 5 &&
			defined($lines) && defined($count) && $count != $lines;
	$count = $Header{'Content-Length'};
	&add_log("NOTICE adjusted Content-Length from $length to $count")
		if $loglvl > 5 && defined($lines) && $count != $length;

	# If there is no Reply-To: line, then take the address in From, if any.
	# Otherwise use the address found in the return-path
	if (!$Header{'Reply-To'}) {
		local($tmp) = (&parse_address($Header{'From'}))[0];
		$Header{'Reply-To'} = $tmp if $tmp ne '';
		$Header{'Reply-To'} = (&parse_address($Header{'Return-Path'}))[0]
			if $tmp eq '';
	}

	# Unless there is already a sender line, fake one using From field
	if (!$Header{'Sender'}) {
		$Header{'Sender'} = $first_from;
		$Header{'Sender'} = $Header{'From'} unless $first_from;
	}

	# Now override any Envelope header and grab it from the first From field
	# If such a field was defined in the message header, then sorry but it
	# was a mistake: RFC 822 doesn't define it, so it should have been
	# an X-Envelope instead.

	$Header{'Envelope'} = $first_from;

	# Finally, compute the list of relaying hosts. The first host which saw
	# this message comes first, the last one (normally the machine receiving
	# the mail) coming last.

	unless ($Header{'Relayed'} = &relay_list) {
		&add_log("NOTICE no valid Received: indication") if $loglvl > 6;
	}
}

# Compute the relaying hosts by looking at the Received: lines and parsing
# them to deduce which host saw and relayed the message. We parse things
# like this:
#
#	Received: from host1 (host2 [xx.yy.zz.tt]) by host3
#	Received: from host1 ([xx.yy.zz.tt]) by host3
#	Received: from ?host1? ([xx.yy.zz.tt]) by host3
#	Received: from host1 by host3
#	Received: from (host2 [xx.yy.zz.tt]) by host3
#	Received: from (host1) [xx.yy.zz.tt] by host3
#	Received: from host1 [xx.yy.zz.tt] by host3
#	Received: from host2 [xx.yy.zz.tt] (host1) by host3
#	Received: from (user@host1) by host3
#
# The host2, when present, is the reverse DNS mapping of the IP address.
# It can be different from host1 in case of local /etc/host aliasing for
# instance. This is used when present, otherwise we must trust host1.
# The host3 information is never used here. It is possible for host1 to
# be a simple IP address [xx.yy.zz.tt].
#
# The latest Received: line inserted in the header is the one added by
# the host receiving the message. For local messages, it may be the
# only line present. It is the only line for which host3 is used, since
# it is probable we can trust our local delivery mailer.
# 
# The returned comma-separated list is sorted to have the first relaying
# host come first (whilst Received headers are normally prepended, which
# yields a reverse host chain).
sub main'load_relay_list {
	package main;
	local(@received) = split(/\n/, $Header{'Received'});
	return '' unless @received;
	local(@hosts);					# List of relaying hosts
	local($host, $real);
	local($islast) = 1;				# First line we see is the "last" inserted
	local($received);				# Received line, verbatim
        # The regexp /\.X$/i where X is any of offical top level domains at
        # http://data.iana.org/TLD/tlds-alpha-by-domain.txt on 15 Aug 2006 plus the
        # extra domain "private".
        # The regexp is the translation into Perl syntax of the result of calling Emacs's `regexp-opt'
        # on the list of acceptable TLDs.
        local($tlds_rx) = qr'\.A(?:ERO|RPA|[C-GIL-OQ-UWXZ])|B(?:IZ|[ABD-JMNORSTVWYZ])|C(?:AT|O(?:M|OP)|[ACDF-IK-ORUVXYZ])|D[EJKMOZ]|E(?:DU|[CEGR-U])|F[IJKMOR]|G(?:OV|[ABD-ILMNP-UWY])|H[KMNRTU]|I(?:N(?:FO|T)|[DEL-OQ-T])|J(?:OBS|[EMOP])|K[EGHIMNRWYZ]|L[ABCIKR-VY]|M(?:IL|OBI|USEUM|[ACDGHK-Z])|N(?:AME|ET|[ACEFGILOPRUZ])|O(?:M|RG)|P(?:R(?:IVATE|O)|[AE-HK-NRSTWY])|QA|R[EOUW]|S[A-EG-ORTUVYZ]|T(?:RAVEL|[CDFGHJ-PRTVWZ])|U[AGKMSYZ]|V[ACEGINU]|W[FS]|Y[ETU]|Z[AMW]$'i;
	local($i);
	local($_);

	# All the known top-level domains as of 2006-08-15
	# with the addition of "loc", "localdomain" and "private".
	# See http://data.iana.org/TLD/tlds-alpha-by-domain.txt
	my $tlds_re = qr/
		a(?:ero|rpa|[c-gil-oq-uwxz])|
		b(?:iz|[abd-jmnorstvwyz])|
		c(?:at|o(?:m|op)|[acdf-ik-oruvxyz])|
		d[ejkmoz]|
		e(?:du|[cegr-u])|
		f[ijkmor]|
		g(?:ov|[abd-ilmnp-uwy])|
		h[kmnrtu]|
		i(?:n(?:fo|t)|[del-oq-t])|
		j(?:obs|[emop])|
		k[eghimnrwyz]|
		l(?:[abcikr-vy]|o(?:c|caldomain))|
		m(?:il|obi|useum|[acdghk-z])|
		n(?:ame|et|[acefgilopruz])|
		o(?:m|rg)|
		p(?:r(?:ivate|o)|[ae-hk-nrstwy])|
		qa|
		r[eouw]|
		s[a-eg-ortuvyz]|
		t(?:ravel|[cdfghj-prtvwz])|
		u[agkmsyz]|
		v[aceginu]|
		w[fs]|
		y[etu]|
		z[amw]
	/ix;

	for ($i = 0; $i < @received; $i++) {
		$received = $_ = $received[$i];

		# Handle first Received line (the last one added) specially.
		if ($islast) {
			if (
				/\bby\s+(\[\d+\.\d+\.\d+\.\d+\])/i	||
				/\bby\s+([\w-.]+)/i
			) {
				$host = $1;
				$host .= ".$cf::domain"
					if $host =~ /^\w/ && $host !~ /\.$tlds_re$/;
				push(@hosts, $host);
			} else {
				&add_log("WARNING no by in first Received: line '$received'")
					if $loglvl > 4;
			}
			$islast = 0;
		}

		next unless s/^\s*from\s+//i;
		next if s/^by\s+//i;		# Host name missing

		# Look for host1, which must be there somehow since we found a 'from'
		# Some sendmails like to add a leading 'login@' before the address,
		# so strip that out before being fancy...
		# The only case host1 was seen to be missing was when it is replaced
		# by an (host2 [ip]) specification instead.

		s/^\w+\@//;
		# [xx.yy.zz.tt]
		if (s/^(\[\d+\.\d+\.\d+\.\d+\])\s*//) {
			$host = $1;				# IP address [xx.yy.zz.tt]
		}
		# ?xx.yy.zz.tt? ( [XX.YY.ZZ.TT])
		elsif (s/^\?[\d\.]+\?\s*\(\s*(\[\d+\.\d+\.\d+\.\d+\])\s*\)\s*//) {
			$host = $1;
		}
		# foo.domain.com (optional)
		elsif (s/^([\w-.]+)(\(\S+\))?\s*//) {
			$host = $1;				# host name
		}
		# (user@foo.domain.com)
		elsif (s/^\(\w+\@([\w-.]+)\)\s*//) {
			$host = $1;				# host name
		}
		# (foo.domain.com) [xx.yy.zz.tt]
		#  foo.domain.com  [xx.yy.zz.tt]
		elsif (s/^\(?([\w-.]+)\)?\s*\[\d+\.\d+\.\d+\.\d+\]\s*//) {
			$host = $1;				# host name
		}
		# Unrecognized, but starting with a parenthesis, hinting for host2...
		elsif (m/^\(/) {
			$host = undef;			# host1 missing, but host2 should be there
		} else {
			&add_log("WARNING invalid from in Received: line '$received'")
				if $loglvl > 4;
			next;
		}

		# There may be an IP or reverse DNS mapping, which will be used to
		# supersede the current $host if found. Note that some (local) mailers
		# insert host as login@host, so we remove the login part.
		# Also handle things like (really foo.com) or (actually real.host), i.e
		# allow an adjective to qualify the real host name.
		#
		# Note: we don't anchor the match at the beginning of the string
		# since we want to parse the 'user@255.190.143.3' as in:
		#   from foo.net (HELO master.foo.org) (user@255.190.143.3) by bar.net
		# and it may not come first... Later on, we'll remove all remaining
		# leading unrecognized () information.
		#
		# The cryptic regexps below attempt to recognize things like:
		#    (user@foo.domain.com [xx.yy.zz.tt])
		#    (WORD user@foo.domain.com [xx.yy.zz.tt])

		$real = '';
		$real = $1 eq '' ? $2 : $1 if
			s/\(([\w-.@]*)?\s*(\[\d+\.\d+\.\d+\.\d+\])?\)\s*// ||
			s/\(\w+\s+([\w-.@]*)?\s*(\[\d+\.\d+\.\d+\.\d+\])?\)\s*//;
		$real =~ s/^.*\@//;
		$real = '' if $real =~ /^[\d.]+$/;		# A sendmail version number!

		# Supersede the host name computed in the previous parsing only
		# if the "real" host name we attempted to guess is an IP address
		# or looks like a fully qualified domain name.

		$host = $real if $real =~ /\.$tlds_re$/ || $real =~ /^\[[\d.]+\]$/;

		if ($host eq '') {
			&add_log("NOTICE no relaying origin in Received: line '$received'")
				if $loglvl > 6;
			next;
		}

		# If we have not recognized anything above, then we don't want to
		# handle anything between () that may follow the original host name.
		# There are just too many formats out there and we can't definitively
		# parse them all. There may even be multiple such occurrences like:
		#   from foo.net (HELO master.foo.org) (user@255.190.143.3) by bar.net
		# Just skip them.

		s/^\([^)]*\)\s+//g;

		# At this point, we should have a 'by ' string somewhere, or an EOS.
		# We're not checking the 'by' immediately (as in /^by/) because some
		# mailers like inserting comments such as 'with ESMTP' or 'via xyzt'.
		# Also, I have seen stange things like 'from xxx from xxx by yyy'.
		#
		# Otherwise we have an unknown Received line format.
		# This is not as bad as not being able to deduce host1 or host2.
		# The full line is logged, so that we may improve our fuzzy matching
		# policy.
		#
		# Note: the lack of 'by' is only allowed for the first Received line
		# stacked, i.e. the last one we parse here...

		unless (/\s*by\s+/i || /^\s*$/ || $i == $#received) {
			&add_log("weird Received: line '$received'") if $loglvl > 8;
		}

		# Validate the host. It must be either an internet [xx.yy.zz.tt] form,
		# or a domain name. This also skips things like 'localhost'.  We
		# also accept pure xx.yy.zz.tt (i.e. without surrounding brackets)

		unless (
			$host =~ /^\[[\d.]+\]$/							||
			$host =~ /^[\w-.]+\.$tlds_re$/					||
			$host =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
		) {
			next if $host =~ /^[\w-]+$/;	# No message for unqualified hosts
			&add_log("ignoring bad host $host in Received: line '$received'")
				if $loglvl > 6;
			next;
		}

		push(@hosts, $host);
	}

	# Remove duplicate consecutive hosts in the list, since this is probably
	# an internal relaying (where we don't have real names but only aliases,
	# otherwise the message would have looped forever!) and does not bring
	# us much.

	local($last, $dup);
	local(@unique) = grep(($dup = $last ne $_, $last = $_, $dup), @hosts);

	return join(', ', reverse @unique);
}

# Append given field to the header structure, updating the whole mail
# text at the same time, hence keeping the %Header table.
# The argument must be a valid formatted RFC-822 mail header field.
sub main'load_header_append {
	package main;
	local($hline) = @_;
	$Header{'Head'} .= $hline;
	$Header{'All'} = $Header{'Head'} . "\n" . $Header{'Body'};
}

# Prepend given field to the whole mail, updating %Header fields accordingly.
sub main'load_header_prepend {
	package main;
	local($hline) = @_;
	$Header{'Head'} = $hline . $Header{'Head'};
	$Header{'All'} = $hline . $Header{'All'};
}

# Scan the supplied scalar reference (containing a mail body without any
# content transfer encoding) and determine what is the proper encoding
# for that body: "7bit", "quoted-printable" or "base64".
sub main'load_best_body_encoding {
	package main;
	my ($body) = @_;
	my $size = 0;
	my $largest_line = 0;
	my $qp_escaped = 0;
	my $non_7bit = 0;

	foreach my $l (split(/\r?\n/, $$body)) {
		my $len = length($l);
		$size += $len;
		$largest_line = $len if $largest_line < $len;
		$non_7bit += $l =~ tr/[\x80-\xff]/[\x80-\xff]/;
		$non_7bit += $l =~ tr/[\x0]/[\x0]/;	# NUL never allowed in "7bit"
		$l =~ s/([^ \t\n!"#\$%&'()*+,\-.\/0-9:;<>?\@A-Z[\\\]^_`a-z{|}~])//g;
		$qp_escaped = $len - length($l);
	}

	return "7bit" if $largest_line <= 998 && $non_7bit == 0;

	my $size_qp = $size + 2 * $qp_escaped;
	my $size_base64 = $size * 4 / 3;

	return "base64" if $size_base64 <= $size_qp;
	return "quoted-printable" if $qp_escaped * 8 < $size;	# Less than 1/8th
	return "base64";
}

# Special users. Note that as login name matches are done in a case-insensitive
# manner, there is no need to upper-case any of the followings.
sub main'load_init_special {
	package main;
	%Special = (
		'root', 1,				# Super-user
		'uucp', 1,				# Unix to Unix copy
		'daemon', 1,			# Not a real user, hopefully
		'news', 1,				# News daemon
		'postmaster', 1,		# X-400 mailer-daemon name
		'newsmaster', 1,		# My convention for news administrator--RAM
		'usenet', 1,			# Aka newsmaster
		'mailer-daemon', 1,		# Sendmail
		'mailer-agent', 1,		# NeXT mailer
		'nobody', 1				# Nobody we've heard of
	);
}

# Compute shorthand file name for logging based on the processed file
sub main'load_mail_logname {
	package main;
	my ($file) = @_;
	my ($mfile) = $file =~ m|.*/(.*)|;	# Basename of mail file
	$mfile = $file unless $mfile;		# There was no / in name
	$mfile = '<stdin>' unless $mfile;	# No $file_name if from STDIN
	return $mfile;
}

# Compute file size for logging, if possible (i.e. not reading from STDIN)
sub main'load_mail_logsize {
	package main;
	my ($file) = @_;
	return "" unless length $file;
	my $msize = (stat($file))[7];
	my $size = "";
	my $s = $msize == 1 ? "" : "s";
	$size = " $msize byte$s" if defined $msize;
	return $size;
}

# Parse mail message and apply the filtering rules on it
sub main'load_analyze_mail {
	package main;
	local($file) = shift(@_);	# Mail file to be parsed
	local($mode) = 'INITIAL';	# Initial working mode
	local($wmode) = $mode;		# Needed for statistics routines
	local(%Variable);			# User-defined variables, visible through APPLY

	# Set-up proper environment. Dynamic scoping is used on those variables
	# for the APPLY command (see the &apply function). Note that the $wmode
	# variable is passed to &apply_rules but is local to that function,
	# meaning there is no feedback of the working mode when using APPLY.
	# However, the variables listed below may be probed upon return since they
	# are external to &apply_rules.
	local($ever_matched) = 0;	# Did we ever matched a single saving rule ?
	local($ever_saved) = 0;		# Did we ever saved a message ?
	local($folder_saved) = '';	# Last folder we saved into (full path)

	# Other local variables used only in this function
	local($ever_seen) = 0;		# Did we ever enter seen mode ?
	local($header);				# Header entry name to look for in Header table

	# Reset environment and umask before each new mail processing
	&env'setup;
	umask($env'umask);

	# Log start of processing
	my $mfile = mail_logname($file);
	my $msize = mail_logsize($file);
	add_log("-- HANDLING [$mfile]$msize --") if $loglvl > 8;

	# Parse the mail message in file
	&parse_mail($file);			# Parse the mail and fill-in H tables
	return 1 unless defined $Header{'All'};		# Mail not parsed correctly
	&reception if $loglvl > 8;	# Log mail reception
	&run_builtins;				# Execute builtins, if any

	# Now analyze the mail. If there is already a X-Filter header, then the
	# mail has already been processed. In that case, the default action is
	# performed: leave it in the incomming mailbox with no further action.
	# This should prevent nasty loops.

	&add_log ("analyzing mail") if $loglvl > 18;
	$header = $Header{'X-Filter'};				# Mulitple occurences possible
	if ($header ne '') {						# Hmm... already filtered...
		local(@filter) = split(/\n/, $header);	# Look for each X-Filter
		local($address) = &email_addr;			# Our e-mail address
		local($done) = 0;						# Already processed ?
		local($_);
		foreach (@filter) {						# Maybe we'll find ourselves
			if (/mailagent.*for (\S+)/) {		# Mark left by us ?
				$done = 1 if $1 eq $address;	# Yes, we did that
				# Remove that X-Filter line, LEAVE will add one anyway
				$Header{'Head'} =~ s/^X-Filter:\s*mailagent.*for $address\n//m;
				last;
			}
		}
		if ($done) {			# We already processed that message
			if ($force_seen) {	# They used the -F option
				&add_log("NOTICE already filtered, processing anyway")
					if $loglvl > 5;
			} else {
				&add_log("NOTICE already filtered, entering seen mode")
					if $loglvl > 5;
				$mode = '_SEEN_';	# This is a special mode
			}
			$ever_seen = 1;		# This will prevent vacation messages
			&s_seen;			# Update statistics
		}
	}

	local($lastcmd) = 0;		# Failure status from last command
	&apply_rules($mode, 1);		# Now apply the filtering rules on it.

	# Deal with vacation mode. It applies only on mail not previously seen.
	# The vacation mode must be turned on in the configuration file. The
	# conditions for a vacation message to be sent are:
	#   - Message was directly sent to the user.
	#   - Message does not come from a special user like root.
	#   - Vacation message was not disabled via a VACATION command
	# Note that we use the environment set-up by the last rule we processed.

	if (!$ever_seen && $cf'vacation =~ /on/i && $env'vacation) {
		unless (&special_user) {	# Not from special user and sent to me
			# Send vacation message only once per address per period
			&xeqte("ONCE (%r,vacation,$env'vacperiod) MESSAGE $env'vacfile");
			&s_vacation;		# Message received while in vacation
		}
	}

	# Default action if no rule ever matched. Statistics routines will use
	# our own local $wmode variable.

	unless ($ever_matched) {
		&add_log("NOTICE no match, leaving in mailbox") if $loglvl > 5;
		&xeqte("LEAVE");			# Default action anyway
		&s_default;					# One more application of default rule
	} else {
		unless ($ever_saved) {
			&add_log("NOTICE not saved, leaving in mailbox") if $loglvl > 5;
			&xeqte("LEAVE");		# Leave if message not saved
			&s_saved;				# Message saved by default rule
		}
	}
	&s_filtered($Header{'Length'});		# Update statistics

	&env'cleanup;						# Clean-up the environment
	0;									# Ok status
}

# This is the heart of the mail agent -- Apply the filtering rules
sub main'load_apply_rules {
	package main;
	local($wmode, $stats)= @_;	# Working mode (the mode we start in)
	local($mode);				# Mode (optional)
	local($selector);			# Selector (mandatory)
	local($range);				# Range for selection (optional)
	local($rulentry);			# Entry in rule H table
	local($pattern);			# Pattern for selection, as written in rules
	local($action);				# Related action
	local($last_selector);		# Last used selector
	local($rules);				# A copy of the rules
	local($matched);			# Flag set to true if a rule is matched
	local(%Matched);			# Records the selectors which have been matched
	local($status);				# Status returned by xeqte
	local(@Executed);			# Records already executed rules
	local($selist);				# Key used to detect identical selector lists
	local(%Inverted);			# Records inverted '!' selectors which matched

	# The @Executed array records whether a specified action for a rule was
	# executed. Loops are possible via the RESTART action, and as there is
	# almost no way to exit from such a loop (there is one with FEED and RESYNC)
	# I decided to prohibit them. Hence a given action is allowed to be executed
	# only once during a mail analysis (modulo each possible working mode).
	# For a rule number n, $Executed[n] is a collection of modes in which the
	# rule was executed, comma separated.

	$Executed[$#Rules] = '';		# Pre-extend array

	# Order wrt the one in the rule file is guaranteed. I use a for construct
	# with indexed access to be able to restart from the beginning upon
	# execution of RESTART. This also helps filling in the @Executed array.

	local($i, $j);			# Indices within rule array

	rule: for ($i = 0; $i <= $#Rules; $i++) {
		$j = $i + 1;
		$_ = $Rules[$i];

		# The %Matched array records the boolean value associated with each
		# possible selector. If two identical selector are found, the values
		# are OR'ed (and we stop evaluating as soon as one is true). Otherwise,
		# the values are AND'ed (for different selectors, but all are evaluated
		# in case we later find another identical selectors -- no sort is done).
		# The %Inverted which records '!' selector matches has all the above
		# rules inverted according to De Morgan's Law.

		undef %Matched;							# Reset matching patterns
		undef %Inverted;						# Reset negated patterns
		$rules = $_;							# Work on a copy
		$rules =~ s/^([^{]*)\{// && ($mode = $1);	# First word is the mode
		$rules =~ s/\s*(.*)\}// && ($action = $1);	# Followed by action }
		$mode =~ s/\s*$//;							# Remove trailing spaces
		$rules =~ s/^\s+//;						# Remove leading spaces
		$last_selector = "";					# Last selector used

		# Make sure we are in the correct mode. The $mode variable holds a
		# list of comma-separated modes. If the working mode is found in it
		# then the rules apply. Otherwise, skip them.

		next rule unless &right_mode;		# Skip rule if not in right mode

		# Now loop over all the keys and apply the patterns in turn

		&reset_backref;						# Reset backreferences
		foreach $key (split(/ /, $rules)) {
			$rulentry = $Rule{$key};
			$rulentry =~ s/^\s*([^\/]*:)// && ($selector = $1);
			$rulentry =~ s/^\s*//;
			$pattern = $rulentry;
			if ($last_selector ne $selector) {	# Update last selector
				$last_selector = $selector;
			}
			$selector =~ s/:$//;			# Remove final ':' on selector
			$range = '<1,->';				# Default range
			$selector =~ s/\s*(<[\d\s,-]+>)$// && ($range = $1);

			&add_log ("selector '$selector' on '$range', pattern '$pattern'")
				if $loglvl > 19;

			# Identical (lists of) selectors are logically OR'ed. To make sure
			# 'To Cc:' and 'Cc To:' are correctly OR'ed, the selector list is
			# alphabetically sorted.

			$selist = join(',', sort split(' ', $selector));

			# Direct selectors and negated selectors (starting with a !) are
			# kept separately, because the rules are dual:
			# For normal selectors (kept in %Matched):
			#  - Identical are OR'ed
			#  - Different are AND'ed
			# For inverted selectors (kept in %Inverted):
			#  - Identical are AND'ed
			#  - Different are OR'ed
			# Multiple selectors like 'To Cc' are sorted according to the first
			# selector on the list, i.e. 'To !Cc' is normal but '!To Cc' is
			# inverted.

			if ($selector =~ /^!/) {		# Inverted selector
				# In order to guarantee an optimized AND, we first check that
				# no previous failure has been reported for the current set of
				# selectors.
				unless (defined $Inverted{$selist} && !$Inverted{$selist}) {
					$Inverted{$selist} = &match($selector, $pattern, $range);
				}
			} else {						# Normal selector
				# Here it is the OR which is guaranteed to be optimized. Do
				# not attempt the match if an identical selector already
				# matched sucessfully.
				unless (defined $Matched{$selist} && $Matched{$selist}) {
					$Matched{$selist} = &match($selector, $pattern, $range);
				}
			}
		}

		# Both groups recorded in %Matched and %Inverted are globally AND'ed
		# However, only one match is necessary within %Inverted whilst all
		# must have matched within %Matched...

		$matched = 1;						# Assume everything matched
		foreach $key (keys %Matched) {		# All entries must have matched
			$matched = $Matched{$key} ? 1 : 0;
			&add_log("rule #$j: direct $key " . ($matched ? 'ok' : 'failed'))
				if $loglvl > 19;
			last unless $matched;
		}
		if ($matched) {						# If %Matched failed, all failed!
			foreach $key (keys %Inverted) {	# Only one entry needs to match
				$matched = $Inverted{$key} ? 1 : 0;
				&add_log("rule #$j: neg $key " . ($matched ? 'ok' : 'failed'))
					if $loglvl > 19;
				last if $matched;
			}
		}

		&add_log("matching summary rule #$j: " . ($matched ? 'ok' : 'failed'))
			if $loglvl > 17;

		if ($matched) {						# Execute action if pattern matched
			# Make sure the rule has not already been executed in that mode
			if ($Executed[$i] =~ /,$wmode,/) {
				&add_log("NOTICE loop detected, rule $j, state $wmode")
					if $loglvl > 5;
				last rule;					# Processing ends here
			} else {						# Rule was never executed
				$Executed[$i] = ',' unless $Executed[$i];
				$Executed[$i] .= "$wmode,";
			}
			$ever_matched = 1;				# At least one match
			&add_log("MATCH on rule #$j in mode $wmode") if $loglvl > 8;
			&track_rule($j, $wmode) if $track_all;
			&s_match($j, $wmode) if $stats;	# Record match for statistics

			# By issuing an &env'restore, we make sure any local variable
			# setting done in other rules is not seen by the actions we are
			# about to execute. However, should the action be the last one
			# to be performed, its settings will remain for later perusal
			# by our caller (vacation messages come to mind).

			&env'restore;				# Restore vars set in previous rules
			$status = &xeqte($action);	# Execute actions

			last rule if $status == $FT_CONT;
			$ever_matched = 0;				# No match if REJECT or RESTART
			next rule if $status == $FT_REJECT;
			$i = -1;		# Restart analysis from the beginning ($FT_RESTART)
		}
	}
	($ever_saved, $ever_matched);
}

# Return true if the modes currently specified by the rule (held in $mode)
# are selected by the current mode (in $wmode), meaning the rule has to
# be applied.
sub main'load_right_mode {
	package main;
	local($list) = "," . $mode . ",";
	&add_log("in mode '$wmode' for $mode") if $loglvl > 19;

	# If mode is negated, skip the rule, whatever other selectors may
	# indicate. Thus <ALL, !INITIAL> will not be taken into account if
	# mode is INITIAL, despite the leading ALL. They can be seen as further
	# requirements or restrictions applied to the mode list (like in the
	# sentence "all the listed modes *but* the one negated").

	return 0 if $list =~ /!ALL/;		# !ALL cannot match, ever
	return 0 if $list =~ /,!$wmode,/;	# Negated modes logically and'ed

	# Now strip out all negated modes, and if the resulting string is
	# empty, force a match...

	1 while $list =~ s/,![^,]*,/,/;		# Strip out negated modes
	$list = ',ALL,' if $list eq ',';	# Emtpy list, force a match

	# The special ALL mode matches anything but the other sepcial mode for
	# already filtered messages. Otherwise, direct mode (i.e. non-negated)
	# are logically or'ed.

	if ($list =~ /,ALL,/) {
		return 0 if $wmode eq '_SEEN_' && $list !~ /,_SEEN_,/;
	} else {
		return 0 unless $list =~ /,$wmode,/;
	}

	1;	# Ok, rule can be applied
}

# Return true if the mail was from a special user (root, uucp...) or if the
# mail was not directly mailed to the user (i.e. it comes from a distribution
# list or has bounced somewhere).
sub main'load_special_user {
	package main;
	# Before sending the vacation message, we have to make sure the mail
	# was sent to the user directly, through a 'To:' or a 'Cc:'. Otherwise,
	# it must be from a mailing list or a 'Bcc:' and we don't want to
	# send something back in that case.

	local($matched) = &match_list("To", $cf'user);
	$matched = &match_list("Cc", $cf'user) unless $matched;

	# Try alternate login names, in case they used a company-wide alias like
	# First.Last or simply a plain sendmail alias.

	if (!$matched && $cf'tome ne '') {
		foreach $addr (split(/\s*,\s*/, $cf'tome)) {
			$matched = &match_list('To', $addr);
			$matched = &match_list('Cc', $addr) unless $matched;
			if ($matched) {
				&add_log("mail was sent to alternate $addr") if $loglvl > 8;
				last;
			} else {
				&add_log("mail wasn't sent to alternate $addr") if $loglvl > 12;
			}
		}
	}

	unless ($matched) {
		&add_log("mail was not directly sent to $cf'user") if $loglvl > 8;
		return 1;
	}

	# If there is a Precedence: header set to either 'bulk', 'list' or 'junk',
	# then we do not reply either.
	local($prec) = $Header{'Precedence'};
	if ($prec =~ /^bulk|junk|list/i) {
		&add_log("mail was tagged with a '$prec' precedence") if $loglvl > 8;
		return 1;
	}
	# If there is an RFC-886 Illegal-Object or Illegal-Field header, do not
	# trust the whole header integrity, and therefore do not reply.
	if ($Header{'Illegal-Object'} ne '' || $Header{'Illegal-Field'} ne '') {
		&add_log("mail was received with header errors") if $loglvl > 8;
		return 1;
	}
	# Make sure the mail does not come from a "special" user, as listed in
	# the %Special array (root, uucp...)
	$matched = 0;
	local($matched_login);
	foreach $login (keys %Special) {
		$matched = &match_single("From", $login);
		$matched_login = $login if $matched;
		last if $matched;
	}
	if ($matched) {
		&add_log("mail was from special user $matched_login")
			if $loglvl > 8;
		return 1;
	}
	0;	# Not from special user!
}

# Compare a machine and an e-mail address and return true if the domain
# for that address matches the domain of the machine. We allow an extra
# level of "domain indirection".
sub main'load_fuzzy_domain {
	package main;
	local($first, $fhost) = @_;
	$fhost =~ s/^\S+@([\w-.]+)/$1/;					# Keep hostname part
	$fhost =~ tr/A-Z/a-z/;							# perl4 misses lc()
	$first =~ tr/A-Z/a-z/;
	local(@fhost) = split(/\./, $fhost);
	local(@first) = split(/\./, $first);
	if (@fhost > @first) {
		shift(@fhost);					# Allow extra machine name
	} elsif (@first > @fhost) {
		shift(@first);
	} elsif (@fhost >= 3) {				# Has at least machine.domain.top
		shift(@first);					# Allow server1.domain.top to match
		shift(@fhost);					# server2.domain.top
	}
	$fhost = join('.', @fhost);
	$first = join('.', @first);
	return $fhost eq $first;
}

# Log reception of mail (sender and subject fields). This is mainly intended
# for people like me who parse the logfile once in a while to do more 
# statistics about mail reception. Hence the other distinction between
# original mails and answers.
sub main'load_reception {
	package main;
	local($subject) = $Header{'Subject'};
	local($sender) = $Header{'Sender'};
	local($from) = $Header{'From'};
	&add_log("FROM $from");
	local($faddr) = (&parse_address($from))[0];		# From address
	local($saddr) = '';

	if ($sender ne '') {
		$saddr = (&parse_address($sender))[0];
		&add_log("VIA $sender") if $saddr ne $faddr;
	}

	# Trace relaying hosts as well if the first host is unrelated to sender
	local($relayed) = $Header{'Relayed'};
	local($first) = (split(/,\s+/, $relayed))[0];	# First relaying host
	&add_log("RELAYED $relayed") if $relayed ne '' &&
		!(&fuzzy_domain($first, $saddr) || &fuzzy_domain($first, $faddr));

	if ($subject ne '') {
		if ($subject =~ s/^Re:\s*//) {
			&add_log("REPLY $subject");
		} else {
			&add_log("ABOUT $subject");
		}
	}
	print "-------- From $from\n" if $track_all;
}

# Print match on STDOUT when -t option is used
sub main'load_track_rule {
	package main;
	local($number, $mode) = @_;
	print "*** Match on rule $number in mode $mode ***\n";
	&print_rule($number);
}

# Split the commands and execute them. This function is the main entry point
# for nesting level (e.g. execution of commands from BACK are driven by xeqte).
# We wish to keep track of the execution status of the last command, as does
# the shell with its $? variable. This is done by $lastcmd.
sub main'load_xeqte {
	package main;
	local($line) = shift(@_);		# Commands to execute
	local(@cmd);					# The commands to be ran
	local($status) = $FT_CONT;		# Status returned by run_command
	local($_);

	# Normally, a ';' separates each action. However, an escaped one as in \;
	# must not be taken into account. We also need to escape a single \, in
	# case we want a \ followed by a ; grr...
	$line =~ s/\\\\/\02/g;			# \\ -> ^B
	$line =~ s/\\;/\01/g;			# \; -> ^A
	@cmd = split(/;/, $line);		# Put all commands in an array
	foreach (@cmd) {				# Now restore orginal escaped sequences
		s/\01/;/g;					# ^A -> ;
		s/\02/\\/g;					# ^B -> \
	}

	# Now run each command in turn
	foreach $cmd (@cmd) {
		$status = &run_command($cmd);
		last unless $status == $FT_CONT;
	}

	# Remap $FT_ABORT on $FT_CONT. In effect, we just skipped the remaining
	# commands on the line and act as if they had been executed. This indeed
	# achieves the ABORT command.
	$status = $FT_CONT if $status == $FT_ABORT;
	$status;
}

# Executes a filter command and return continuing status:
#  FT_CONT to continue
#  FT_REJECT if a reject was found
#  FT_RESTART if a restart was found
#  FT_ABORT if an abort was found
sub main'load_run_command {
	package main;
	local($cmd) = @_;				# Command to be run (passed to subroutines)
	local($cmd_name);				# Command name
	local($cont) = $FT_CONT;		# Continue by default
	local($mfile) = mail_logname($file_name);
	&macros_subst(*cmd);			# Macros substitutions
	$cmd =~ s/^\s*//;				# Remove leading spaces
	$cmd =~ s/\s*$//;				# And trailing ones
	return $cont unless $cmd;		# Ignore null instructions
	($cmd_name) = $cmd =~ /^(\w+)/;
	$cmd_name =~ tr/a-z/A-Z/;		# In uppercase from now on
	# In the special mode _SEEN_, only a restricted set of action are allowed
	if ($wmode eq '_SEEN_') {
		if ($Rfilter{$cmd_name}) {
			&add_log("WARNING command $cmd_name not allowed") if $loglvl > 5;
			return $cont;
		}
	}
	&add_log("XEQ ($cmd)") if $loglvl > 10;
	print ">> $cmd\n" if $track_all;		# Option -t
	local($routine) = $Filter{$cmd_name};

	# Unknown commands default to LEAVE if no save have ever been done.
	# Otherwise, they are simply ignored.
	unless ($routine) {
		local($what) = 'defaults to LEAVE';
		$what = 'ignored' if $ever_saved;
		&add_log("ERROR unknown command $cmd_name ($what)")
			if $loglvl > 1;
		$routine = $Filter{'LEAVE'};		# Default action
		return $cont if $ever_saved;		# Command ignored
	}

	# Argument parsing within package opt, defining $opt'sw_i if -i for
	# instance. We first reset previous instances from a former command,
	# then parse it for arguments (if any specified in %Option), updating
	# the command string as needed to remove the options as they are found.
	local($opt) = $Option{$cmd_name};
	local($cms) = $cmd;
	if ($opt) {
		&opt'reset;
		$cms = &opt'parse($cmd, $opt);
	}

	# Call routine to handle the action, passing it a string containing
	# the command arguments, as adjusted by a possible option parsing.
	$cms =~ s/^\w+\s*//;						# Comamnd name stripped
	local($failed) = eval("&$routine(\$cms)");	# Eval traps all fatal errors
	$failed = 1 if &eval_error;					# Make sure eval worked

	&opt'restore if $opt;		# Restore options, in case of recursion

	# If command does not belong to the set of those who do not modify the
	# last execution status recorded, then update $lastcmd with the failure
	# status.
	$lastcmd = $failed unless $Nostatus{$cmd_name};

	# Update statistics
	unless ($failed) {
		&s_action($cmd_name, $wmode);
	} else {
		&s_failed($cmd_name, $wmode);
	}
	$cont;				# Continue status
}

# Each filter command is handled by a specific function. The Filter array
# maps an action name to a subroutine, while the Rfilter array lists the
# authorized actions in the special mode _SEEN_ (used when a mail already
# filtered is processed).
# The %Nostatus array records the commands which do not modify the execution
# status recorded by the last command. Typically, those are commands which can
# never fail.
sub main'load_init_filter {
	package main;
	%Filter = (
		'ABORT', 'run_abort',		# Aborts application of filtering rules
		'AFTER', 'run_after',		# Records callout action
		'ANNOTATE', 'run_annotate',	# Add new field into header
		'APPLY', 'run_apply',		# Apply alternate rule file on message
		'ASSIGN', 'run_assign',		# Assign value to variable
		'BACK', 'run_back',			# Eval feedback
		'BEEP', 'run_beep',			# Change value of %b escape when biffing
		'BEGIN', 'run_begin',		# Enter in a new state
		'BIFF', 'run_biff',			# Turn biffing on/off dynamically
		'BOUNCE', 'run_bounce',		# Bounce message
		'DO', 'run_do',				# Call perl routine directly
		'DELETE', 'run_delete',		# Throw mail away, explicitely
		'FEED', 'run_feed',			# Feed back mail through program
		'FORWARD', 'run_forward',	# Forward mail
		'GIVE', 'run_give',			# Give body to command
		'KEEP', 'run_keep',			# Keep only the listed header fields
		'LEAVE', 'run_leave',		# Saving in incomming mailbox
		'MACRO', 'run_macro',		# Define a user macro
		'MESSAGE', 'run_message',	# Send a vacation-like file
		'NOP', 'run_nop',			# No operation
		'NOTIFY', 'run_notify',		# Notify reception of message
		'ON', 'run_on',				# On day control
		'ONCE', 'run_once',			# Once control
		'PASS', 'run_pass',			# Pass body to program with feedback
		'PERL', 'run_perl',			# Perform actions from within a perl script
		'PIPE', 'run_pipe',			# Pipe message to specified command
		'POST', 'run_post',			# Post mail to the net
		'PROCESS', 'run_process',	# Mailagent processing
		'PROTECT', 'run_protect',	# Change default folder protection mode
		'PURIFY', 'run_purify',		# Purify header through a program
		'QUEUE', 'run_queue',		# Queue mail
		'RECORD', 'run_record',		# Record message in history
		'REJECT', 'run_reject',		# Reject
		'REQUIRE', 'run_require',	# Load perl code
		'RESTART', 'run_restart',	# Restart
		'RESYNC', 'run_resync',		# Resynchronizes the header
		'RUN', 'run_run',			# Run specified program
		'SAVE', 'run_save',			# Save in a folder
		'SELECT', 'run_select',		# Time selection control
		'SERVER', 'run_server',		# Server processing
		'SPLIT', 'run_split',		# Split digest message
		'STORE', 'run_store',		# Save and leave copy in mailbox
		'STRIP', 'run_strip',		# Strip some header lines
		'SUBST', 'run_subst',		# Substitution on variable
		'TR', 'run_tr',				# Translation on variable
		'UMASK', 'run_umask',		# Set new umask
		'UNIQUE', 'run_unique',		# Delete message if already in history
		'VACATION', 'run_vacation',	# Allow or forbid vacation messages
		'WRITE', 'run_write',		# Write mail in folder
	);
	# Option string for &opt'get parsing (syntax similar to getopt)
	%Option = (
		'ABORT',	'ft',
		'AFTER',	'acns',
		'ANNOTATE',	'du',
		'BEEP',		'l',
		'BEGIN',	'ft',
		'BIFF',		'l',
		'FEED',		'be',
		'MACRO',	'rdp',
		'NOP',		'tf',
		'PIPE',		'b',
		'POST',		'lb',
		'PROTECT',	'lu',
		'RECORD',	'acr',
		'REJECT',	'ft',
		'RESTART',	'ft',
		'SERVER',	'd:t',
		'SPLIT',	'adeiw',
		'UMASK',	'l',
		'UNIQUE',	'acr',
		'VACATION',	'l',
	);
	# Restricted filter actions: the commands listed below cannot be
	# executed in the special seen mode (in order to avoid loops).
	%Rfilter = (
		'BACK', 1,
		'BOUNCE', 1,
		'DO', 1,
		'FEED', 1,
		'FORWARD', 1,
		'GIVE', 1,
		'NOTIFY', 1,
		'PASS', 1,
		'PIPE', 1,
		'POST', 1,
		'PURIFY', 1,
		'QUEUE', 1,
		'RUN', 1,
	);
	# The following commands do not modify the last status recorded.
	%Nostatus = (
		'ABORT', 1,
		'ASSIGN', 1,
		'BEEP', 1,
		'BIFF', 1,
		'BEGIN', 1,
		'KEEP', 1,
		'MACRO', 1,
		'PROTECT', 1,
		'REJECT', 1,
		'RESTART', 1,
		'RESYNC', 1,
		'STRIP', 1,
		'UMASK', 1,
		'VACATION', 1,
	);
}

# Run the PROCESS command
sub main'load_run_process {
	package main;
	if (0 != &process) {
		&add_log("ERROR while processing [$mfile]--queing it") if $loglvl;
		&queue_mail($file_name, 'fm');
		return 1;
	}
	&add_log("PROCESSED [$mfile]") if $loglvl > 8;
	0;
}

# Run the SERVER command
sub main'load_run_server {
	package main;
	&cmdenv'inituid;				# Initialize server session environment
	&cmdserv'trusted if $opt'sw_t;	# Server runs in trusted mode
	&cmdserv'disable($opt'sw_d) if $opt'sw_d;	# Disable commands for this run
	local(@body) = split(/\n/, $Header{'Body'});
	local($failed) = &cmdserv'process(*body);
	unless ($failed) {
		&add_log("SERVED [$mfile]") if $loglvl > 8;
	} else {
		&add_log("ERROR unable to serve [$mfile]--discarded") if $loglvl;
	}
	$failed;
}

# Run the LEAVE command
sub main'load_run_leave {
	package main;
	local($mbox, $failed) = &leave;
	unless ($failed) {
		&add_log("LEFT [$mfile] in mailbox") if $loglvl > 2;
	}
	# Even if it failed, mark it as saved anyway, as the default action would
	# be a saving in mailbox and there is little chance another attempt would
	# succeed while this one failed.
	$ever_saved = 1;		# At least we tried to save it
	$failed;
}

# Run the SAVE command
sub main'load_run_save {
	package main;
	local($folder) = @_;	# Folder where message should be saved
	&save_message($folder);
}

# Run the STORE command
sub main'load_run_store {
	package main;
	local($folder) = @_;	# Folder where message should be saved
	local($mbox, $failed, $log_message) = &run_saving($folder, $FOLDER_APPEND);
	unless ($failed) {
		$ever_saved = 1;			# We were able to save it
		($mbox, $failed) = &leave;
		unless ($failed) {
			&add_log("STORED [$mfile] in $log_message") if $loglvl > 2;
		} else {
			&add_log("WARNING only SAVED [$mfile] in $log_message")
				if $loglvl > 1;
			return 1;
		}
	} else {
		($mbox, $failed) = &leave;
		unless ($failed) {
			$ever_saved = 1;			# We were able to save it
			&add_log("WARNING only LEFT [$mfile] in mailbox")
				if $loglvl > 1;
		}
	}
	$failed;
}

# Run the WRITE command
sub main'load_run_write {
	package main;
	local($folder) = @_;	# Folder where message should be saved
	local($mbox, $failed, $log_message) = &run_saving($folder, $FOLDER_REMOVE);
	unless ($failed) {
		&add_log("WROTE [$mfile] in $log_message") if $loglvl > 2;
		$ever_saved = 1;			# We were able to save it
	}
	$failed;
}

# Run the DELETE command
sub main'load_run_delete {
	package main;
	&add_log("DELETED [$mfile]") if $loglvl > 2;
	$ever_saved = 1;		# User chose to discard it, it counts as a save
	0;
}

# Run the MACRO command
sub main'load_run_macro {
	package main;
	local($args) = @_;		# Get command arguments
	local($name, $action) = &macro($args);	# Perform the command
	&add_log("MACRO [$mfile] $name $action") if $loglvl > 7;
	0;	# Never fails
}

# Run the MESSAGE command
sub main'load_run_message {
	package main;
	local($msg) = @_;		# Vacation message location
	$msg =~ s/~/$cf'home/g;					# ~ substitution
	local($failed) = &message($msg);
	unless ($failed) {
		$msg = &tilda($msg);				# Replace the home directory by ~
		&add_log("MESSAGE $msg for [$mfile]") if $loglvl > 2;
	}
	$failed;
}

# Run the NOTIFY command
sub main'load_run_notify {
	package main;
	local($args) = @_;
	local(@args) = split(' ', $args);
	local($msg) = shift(@args);				# First argument is message text
	$msg =~ s/~/$cf'home/g;					# ~ substitution
	local($address) = join(' ', @args);		# Address list
	$address = $cf'email if $address eq '';	# No address, defaults to user
	local($failed) = &notify($msg, $address);
	unless ($failed) {
		$msg = &tilda($msg);				# Replace the home directory by ~
		&add_log("NOTIFIED $msg [$mfile] to $address") if $loglvl > 2;
	}
	$failed;
}

# Run the REJECT command
sub main'load_run_reject {
	package main;
	local(*perform) = *do_reject;
	&alter_flow;		# Change control flow by calling &perform
}

# Run the RESTART command
sub main'load_run_restart {
	package main;
	local(*perform) = *do_restart;
	&alter_flow;		# Change control flow by calling &perform
}

# Run the ABORT command
sub main'load_run_abort {
	package main;
	local(*perform) = *do_abort;
	&alter_flow;		# Change control flow by calling &perform
}

# Run the RESYNC command
sub main'load_run_resync {
	package main;
	# Headers pertaining to body encoding could have changed.
	&header_check_body_encoding;	# Check and recode if possible
	&header_resync;					# Resynchronize the %Header array
	&add_log("RESYNCED [$mfile]") if $loglvl > 4;
	0;
}

# Run the BEGIN command
sub main'load_run_begin {
	package main;
	local($newstate) = @_;		# New state wanted
	return 0 if $opt'sw_t && $lastcmd;		# -t means change only if true
	return 0 if $opt'sw_f && !$lastcmd;		# -f means change only if false
	$newstate = 'INITIAL' unless $newstate;
	$wmode = $newstate;			# $wmode comes from analyze_mail
	&add_log("BEGUN [$mfile] state $newstate") if $loglvl > 4;
	0;
}

# Run the RECORD command
sub main'load_run_record {
	package main;
	local($mode) = @_;
	local($tags);
	$mode =~ s|^(\w*)\s*\(([^()]*)\).*|$1| && ($tags = $2);
	local($failed) = 0;
	if (&history_tag($tags)) {	# Message already seen
		if ($mode eq '') {
			&add_log("NOTICE entering seen mode")
				if $loglvl > 5 && $wmode ne '_SEEN_';
			# Enter special mode ($wmode from analyze_mail)
			$wmode = '_SEEN_';
		}
		&alter_execution('x', $mode);
		$failed = 1;			# Make sure it "fails"
	}
	local($tagmsg) = $tags ne '' ? " ($tags)" : '';
	&add_log("RECORDED [$mfile]" . $tagmsg) if $loglvl > 4;
	$failed;
}

# Run the UNIQUE command
sub main'load_run_unique {
	package main;
	local($mode) = @_;
	local($tags);
	$mode =~ s|^(\w*)\s*\(([^()]*)\).*|$1| && ($tags = $2);
	local($failed) = 0;
	if (&history_tag($tags)) {	# Message already seen
		&add_log("NOTICE message tagged as saved") if $loglvl > 5;
		$ever_saved = 1;		# In effect, runs a DELETE
		&alter_execution('x', $mode);
		$failed = 1;			# Make sure it "fails"
	}
	local($tagmsg) = $tags ne '' ? " ($tags)" : '';
	&add_log("UNIQUE [$mfile]" . $tagmsg) if $loglvl > 4;
	$failed;
}

# Run the FORWARD command
sub main'load_run_forward {
	package main;
	local($addresses) = @_;		# Address(es)
	local($failed) = &forward($addresses);
	unless ($failed) {
		&add_log("FORWARDED [$mfile] to $addresses") if $loglvl > 2;
		$ever_saved = 1;		# Forwarding succeeded, counts as a save
	}
	$failed;
}

# Run the BOUNCE command
sub main'load_run_bounce {
	package main;
	local($addresses) = @_;		# Address(es)
	local($failed) = &bounce($addresses);
	unless ($failed) {
		&add_log("BOUNCED [$mfile] to $addresses") if $loglvl > 2;
		$ever_saved = 1;		# Bouncing succeeded, counts as a save
	}
	$failed;
}

# Run the POST command
sub main'load_run_post {
	package main;
	local($newsgroups) = @_;	# Newsgroup(s)
	local($failed) = &post($newsgroups);
	unless ($failed) {
		&add_log("POSTED [$mfile] to $newsgroups") if $loglvl > 2;
		$ever_saved = 1;		# Posting succeeded, counts as a save
	}
	$failed;
}

# Run the RUN command
sub main'load_run_run {
	package main;
	local($program) = @_;		# Program to run
	local($failed) = &shell_command($program, $NO_INPUT, $NO_FEEDBACK);
	unless ($failed) {
		&add_log("RAN '$program' for [$mfile]") if $loglvl > 4;
	}
	$failed;
}

# Run the PIPE command
sub main'load_run_pipe {
	package main;
	local($program) = @_;		# Program to run
	my $mail = $opt'sw_b ? $MAIL_INPUT_BINARY : $MAIL_INPUT;
	local($failed) = &shell_command($program, $mail, $NO_FEEDBACK);
	unless ($failed) {
		&add_log("PIPED [$mfile] to '$program'") if $loglvl > 4;
	}
	$failed;
}

# Run the GIVE command
sub main'load_run_give {
	package main;
	local($program) = @_;		# Program to run
	local($failed) = &shell_command($program, $BODY_INPUT, $NO_FEEDBACK);
	unless ($failed) {
		&add_log("GAVE [$mfile] to '$program'") if $loglvl > 4;
	}
	$failed;
}

# Run the PASS command
sub main'load_run_pass {
	package main;
	local($program) = @_;		# Program to run
	local($failed) = &shell_command($program, $BODY_INPUT, $FEEDBACK);
	unless ($failed) {
		&add_log("PASSED [$mfile] through '$program'") if $loglvl > 4;
	}
	$failed;
}

# Run the FEED command
sub main'load_run_feed {
	package main;
	local($program) = @_;		# Program to run
	my $mail = $opt'sw_b ? $MAIL_INPUT_BINARY : $MAIL_INPUT;
	my $feedback = $opt'sw_e ? $FEEDBACK_ENCODING : $FEEDBACK;
	local($failed) = &shell_command($program, $mail, $feedback);
	unless ($failed) {
		&add_log("FED [$mfile] through '$program'") if $loglvl > 4;
	}
	$failed;
}

# Run the PURIFY command
sub main'load_run_purify {
	package main;
	local($program) = @_;		# Program to run
	local($failed) = &shell_command($program, $HEADER_INPUT, $FEEDBACK);
	unless ($failed) {
		&add_log("PURIFIED [$mfile] through '$program'") if $loglvl > 4;
	}
	$failed;
}

# Run the BACK command
# Manipulates dynamically bound variable $cont (output from xeqte)
sub main'load_run_back {
	package main;
	local($command) = @_;
	# The BACK command is handled recursively. The local variable $Back will be
	# set by xeq_back() if any feedback is to ever occur. This routine will be
	# transparently called instead of the usual handle_output() because of the
	# dynamic aliasing done here.
	local($Back) = '';					# BACK may be nested
	local(*handle_output) = *xeq_back;	# Any output to be put in $Back
	local($failed) = 0;
	$command =~ s/%/%%/g;				# Protect against 2nd macro substitution
	# Calling run_command will position $lastcmd to be the return status of
	# the last meaningful command executed. However, we reset $lastcmd before
	# diving into the execution.
	$lastcmd = 0;						# Assume everything went fine
	&run_command($command);				# Run command (ignore return value)
	if ($Back ne '') {
		&add_log("got '$Back' back") if $loglvl > 11;
		$cont = &xeqte($Back);			# Get continuation status back
		$@ = '';						# Avoid cascade of (same) error report
		&add_log("BACK from '$command'") if $loglvl > 4;
	} else {
		&add_log("WARNING got nothing out of '$command'") if $loglvl > 5;
	}
	$lastcmd;			# Propage error status we got from the $command
}

# Run the ON command
sub main'load_run_on {
	package main;
	local($_) = $cmd;					# The whole command line
	local(@days) = split(' ', 'Sun Mon Tue Wed Thu Fri Sat');
	local(%days);
	local($daynum) = 0;
	foreach $day (@days) {				# Initialize Sun => 0, Mon => 1, etc...
		$days{$day} = $daynum++;
	}
	local(@on);							# List of specified days
	local(%on);							# Hash '0' (for sunday) => 1 if selected
	if (s/^ON\s*\(([^\)]*)\)//) {		# List of days, like (Mon Tue)
		@on = split(/,?\s+/, $1);		# Allow (Mon Thu) and (Mon, Thu)
		local($non);
		foreach $on (@on) {
			$non = $on;					# New $on will be canonicalized
			$non =~ s/^(...).*/\u\L$1/;	# Keep only first 3 letters
			unless (defined $days{$non}) {
				&add_log("WARNING ignoring bad day $on in ON (@on)")
					if $loglvl > 5;
				next;
			}
			$on{$days{$non}}++;			# E.g sets $on{1} for Mon
		}
		&add_log("on (@on)") if $loglvl > 18;
	} else {
		&add_log("ERROR bad ON syntax (did not parse right)") if $loglvl > 1;
		return 1;
	}

	# Calling run_command will set $lastcmd to the status of the command. In
	# case we are running a command which does not alter this status, assume
	# everything is fine.

	$lastcmd = 0;						# Assume command will run correctly
	s/^\s*//;							# Remove leading spaces

	local($wday) = (localtime(time))[6];

	if (defined $on{$wday}) {
		&add_log("ON (@on) $_") if $loglvl > 7;
		s/%/%%/g;						# Protect against 2nd macro substitution
		$cont = &run_command($_);		# Run command and update control flow
	} else {
		&add_log("not a good day for $_") if $loglvl > 12;
	}

	$lastcmd;							# Propagates execution status
}

# Run the ONCE command
sub main'load_run_once {
	package main;
	local($_) = $cmd;					# The whole command line
	local($hname);						# Hash name (e-mail address)
	local($tag);						# Tag associated with command
	local($raw_period);					# The period, as written
	if (s/^ONCE\s*\(([^,\)]*),\s*([^,;\)]*),\s*(\w+)\s*\)//) {
		($hname, $tag, $raw_period) = ($1, $2, $3);
		&add_log("tag is ($hname, $tag, $raw_period)") if $loglvl > 18;
	} else {
		&add_log("ERROR bad once syntax (invalid tag)") if $loglvl > 1;
		return 1;
	}
	s/^\s*//;							# Remove leading spaces
	local($period) = &seconds_in_period($raw_period);
	&add_log("period is $raw_period = $period seconds") if $loglvl > 18;

	# Calling run_command will set $lastcmd to the status of the command. In
	# case we are running a command which does not alter this status, assume
	# everything is fine.
	$lastcmd = 0;						# Assume command will run correctly

	if (&once_check($hname, $tag, $period)) {
		&add_log("ONCE ($hname, $tag, $raw_period) $_") if $loglvl > 7;
		&s_once($cmd_name, $wmode, $tag);
		s/%/%%/g;						# Protect against 2nd macro substitution
		$cont = &run_command($_);		# Run it, update continuation status
	} else {
		&add_log("retry time not reached for $_") if $loglvl > 12;
		&s_noretry($cmd_name, $wmode, $tag);
	}

	$lastcmd;							# Propagates execution status
}

# Run the SELECT command
sub main'load_run_select {
	package main;
	local($_) = $cmd;					# The whole command line
	local($start, $end);				# Date strings for start and end
	if (s/^SELECT\s*\(([^.\)]*)\.\.\s*([^\)]*)\)//) {
		($start, $end) = ($1, $2);
		$start =~ s/\s*$//;				# Remove trailing spaces
		$end =~ s/\s*$//;
		&add_log("time is ($start .. $end)") if $loglvl > 18;
	} else {
		&add_log("ERROR bad select syntax (invalid time)") if $loglvl > 1;
		return 1;
	}
	local($now) = time;					# Current time
	local($sec_start, $sec_end);		# Start and end converted in seconds
	$sec_start = &getdate($start, $now);
	if ($sec_start == -1) {
		&add_log("ERROR in SELECT: 1st time '$start'") if $loglvl > 1;
		return 1;
	}
	$sec_end = &getdate($end, $now);
	if ($sec_end == -1) {
		&add_log("ERROR in SELECT: 2nd time '$end'") if $loglvl > 1;
		return 1;
	}
	if ($sec_start > $sec_end) {
		&add_log("WARNING time selection always impossible?") if $loglvl > 1;
		return 0;
	}

	# Calling run_command will set $lastcmd to the status of the command. In
	# case we are running a command which does not alter this status, assume
	# everything is fine.
	$lastcmd = 0;						# Assume command will run correctly

	&add_log("SELECT ($sec_start, $sec_end) at $now") if $loglvl > 11;

	s/^\s*//;							# Remove leading spaces
	if ($now >= $sec_start && $now <= $sec_end) {
		&add_log("SELECT ($start .. $end) $_") if $loglvl > 7;
		s/%/%%/g;						# Protect against 2nd macro substitution
		$cont = &run_command($_);		# Run command and update control flow
	} else {
		&add_log("time period not good for $_") if $loglvl > 12;
	}

	$lastcmd;							# Propagates execution status
}

# Run the NOP command
sub main'load_run_nop {
	package main;
	local($what) = $opt'sw_f ? 'failure' : ($opt'sw_t ? 'success' : '');
	local($force) = $what ? " forcing $what" : '';
	&add_log("NOP [$mfile]$force") if $loglvl > 7;
	return 1 if $opt'sw_f;		# -f forces failure
	return 0 if $opt'sw_t;		# -t forces failure
	$lastcmd;					# Propagates curremt exec status
}

# Run the STRIP command
sub main'load_run_strip {
	package main;
	local($headers) = @_;		# Headers to remove
	&alter_header($headers, $HD_STRIP);
	$headers = join(', ', split(/\s/, $headers));
	&add_log("STRIPPED $headers from [$mfile]") if $loglvl > 7;
	0;
}

# Run the KEEP command
sub main'load_run_keep {
	package main;
	local($headers) = @_;		# Headers to keep
	&alter_header($headers, $HD_KEEP);
	$headers = join(', ', split(/\s/, $headers));
	&add_log("KEPT $headers from [$mfile]") if $loglvl > 7;
	0;
}

# Run the ANNOTATE command
sub main'load_run_annotate {
	package main;
	local($field, $value) = $cms =~ m|([\w\-]+):?\s*(.*)|;
	local($failed) = &annotate_header($field, $value);
	unless ($failed) {
		local($msg) = $opt'sw_d ? ' (no date)' : '';
		&add_log("ANNOTATED [$mfile] with $field$msg") if $loglvl > 7;
	}
	$failed;
}

# Run the ASSIGN command
sub main'load_run_assign {
	package main;
	local($var, $value) = $cms =~ m|^(:?\w+)\s+(.*)|;
	local($eval);						# Evaluated value for expression
	local($@);
	# An expression may be provided as a value. If the whole value is enclosed
	# within simple quotes, then those are stripped and no evaluation is made.
	unless ($value =~ s/^'(.*)'$/$1/) {
		eval "\$eval = $value";			# Maybe value is an expression?
		if ($@) {
			chop($@);
			&add_log("WARNINIG can't evaluate '$value': $@");
		} else {
			$value = $eval;
		}
	}
	if ($var =~ s/^://) {
		&extern'set($var, $value);		# Persistent variable is set
	} else {
		$Variable{$var} = $value;		# User defined variable is set
	}
	&add_log("ASSIGNED '$value' to '$var' [$mfile]") if $loglvl > 7;
	0;
}

# Run the TR command
sub main'load_run_tr {
	package main;
	local($variable, $tr) = $cms =~ m|^(\S+)\s+(.*)|;
	&alter_value($variable, "tr$tr");
}

# Run the SUBST command
sub main'load_run_subst {
	package main;
	local($variable, $s) = $cms =~ m|^(\S+)\s+(.*)|;
	&alter_value($variable, "s$s");
}

# Run the SPLIT command
sub main'load_run_split {
	package main;
	local($folder) = @_;			# Folder where split occurs
	local($failed) = &split($folder);
	if (0 == $failed % 2) {			# Message was in digest format
		if ($failed & 0x4) {
			&add_log("SPLIT [$mfile] in mailagent's queue") if $loglvl > 2;
		} else {
			&add_log("SPLIT [$mfile] in $folder") if $loglvl > 2;
		}
		# If digest was not in RFC-934 style, there is a chance the split
		# was not correctly performed. To avoid any accidental loss of
		# information, the original digest message is also saved if SPLIT
		# had a folder argument, or it is not tagged saved.
		if ($failed & 0x8) {		# Digest was not RFC-934 compliant
			&add_log("NOTICE [$mfile] not RFC-934 compliant") if $loglvl > 6;
			if ($folder ne '') {
				&add_log("NOTICE saving original [$mfile] in $folder")
					if $loglvl > 6;
				&save_message($folder);
			} else {
				&add_log("NOTICE [$mfile] not tagged as saved")
					if $loglvl > 6 && ($failed & 0x2);
			}
		} else {
			$ever_saved = 1 if $failed & 0x2;	# Split -i succeeded
		}
		$failed = 0;
	}
	# If message was not in digest format and a folder was specified, save
	# message in that folder.
	if ($failed < 0 && $folder ne '') {
		&add_log("NOTICE [$mfile] not in digest format") if $loglvl > 6;
		$failed = &save_message($folder);
	}
	$failed ? 1 : 0;	# Failure status from split can be negative
}

# Run the VACATION command
sub main'load_run_vacation {
	package main;
	return 0 unless $cf'vacation =~ /on/i;	# Ignore if vacation mode off
	local($mode, $period) = $cms =~ m|^(\S+)(\s+\S+)?|;
	local($l) = $opt'sw_l ? ' locally' : '';
	local($allowed) = ($mode =~ /off/i) ? 0 : 1;
	&env'local('vacation', $allowed) if $opt'sw_l;
	$env'vacation = $allowed;			# Won't hurt given the above local call
	if ($allowed && $mode !~ /^on$/i) {	# New vacation path given
		if ($cf'vacfixed =~ /on/i) {	# Not allowed if vacfixed is ON
			&add_log("WARNING no message change allowed by 'vacfixed'")
				if $loglvl > 5;
		} else {
			$mode =~ s/^~/$cf'home/;		# ~ substitution
			&env'local('vacfile', $mode) if $opt'sw_l;
			$env'vacfile = $mode;
			&add_log("vacation message in file $mode$l") if $loglvl > 7;
		}
	}
	if ($allowed && $period) {
		&env'local('vacperiod', $period) if $opt'sw_l;
		$env'vacperiod = $period;
		&add_log("vacation period is now $period$l") if $loglvl > 7;
	}
	$mode = $env'vacation ? 'on' : 'off';
	&add_log("vacation message turned $mode$l") if $loglvl > 7;
	0;
}

# Run the QUEUE command
sub main'load_run_queue {
	package main;
	# Mail is saved as a 'qm' file, to avoid endless loops when mailagent
	# processes the queue. This means the mail will be deferred for at
	# least half an hour.
	local($name) = &queue_mail('', 'qm');	# No file name, mail in %Header
	$ever_saved = 1 if defined $name;		# Queuing counts as saving
	defined $name ? 0 : 1;					# Failed if $name is undef
}

# Run the PERL command
sub main'load_run_perl {
	package main;
	local($script) = @_;	# Script to be loaded
	local($failed) = &perl($script);
	unless ($failed) {
		$script = &tilda($script);			# Replace the home directory by ~
		&add_log("PERLED [$mfile] through $script") if $loglvl > 7;
	}
	$failed;
}

# Run the REQUIRE command
sub main'load_run_require {
	package main;
	local($file, $package) = $cms =~ m|^(\S+)\s*(.*)|;
	local($failed) = &require($file, $package);
	unless ($failed) {
		$file = &tilda($file);		# Replace the home directory by ~
		local($inpack) = $file;		# Loaded in a package?
		$inpack .= " in package $package" if $package ne '';
		&add_log("REQUIRED [$mfile] $inpack") if $loglvl > 7;
	}
	$failed;
}

# Run the APPLY command
sub main'load_run_apply {
	package main;
	local($rulefile) = @_;	# Rule file to be applied
	local($failed, $saved) = &apply($rulefile);
	unless ($failed) {
		$rulefile = &tilda($rulefile);		# Replace the home directory by ~
		&add_log("APPLIED [$mfile] rules $rulefile") if $loglvl > 7;
	}
	$ever_saved = 1 if $saved;		# Mark mail as saved if appropriate
	$saved ? $failed : 1;			# Force failure if never saved
}

# Run the UMASK command
sub main'load_run_umask {
	package main;
	local($mask) = @_;
	$mask = oct($mask) if $mask =~ /^0/;
	&env'local('umask', $mask) if $opt'sw_l;	# Restored when leaving rule
	$env'umask = $mask;		# Permanent change, unless changed locally already
	umask($env'umask);
	local($omask) = sprintf("0%o", $mask);	# Octal string, for logging
	local($local) = $opt'sw_l ? ' locally' : '';
	&add_log("UMASK [$mfile] set to ${omask}$local") if $loglvl > 7;
	0;	# Ok
}

# Run the AFTER command
sub main'load_run_after {
	package main;
	local($time, $action) = $cms =~ m|^\((.*)\)(.*)|;
	local($failed, $queued) = &after($time, $action);
	unless ($failed) {
		local(@msg);
		push(@msg, 'shell') if $opt'sw_s;
		push(@msg, 'command') if $opt'sw_c;
		push(@msg, 'no input') if $opt'sw_n;
		push(@msg, 'agent') if $opt'sw_a || 0 == @msg;
		local($type) = join(', ', @msg);
		local($qmsg) = $queued ne '-' ? "-> $queued" : '';
		&add_log("AFTER [$mfile$qmsg] $time {$action} ($type)") if $loglvl > 3;
	}
	$failed;	# Failure status
}

# Run the DO command
sub main'load_run_do {
	package main;
	local($what, $args) = $cms =~ m|^([^()\s]*)(.*)|;
	local($something, $routine) = $what =~ m|^([^:]*):(.*)|;
	$routine = $what if $something eq '';
	local($failed) = &do($something, $routine, $args);
	&add_log("DONE [$mfile] $routine$args") if $loglvl > 7 && !$failed;
	$failed;	# Failure status
}

# Run the BEEP command
sub main'load_run_beep {
	package main;
	local($beep) = @_;
	&env'local('beep', $beep) if $opt'sw_l;	# Restored when leaving rule
	$env'beep = $beep;		# Permanent change, unless changed locally already
	local($local) = $opt'sw_l ? ' locally' : '';
	&add_log("BEEP [$mfile] set to ${beep}$local") if $loglvl > 7;
	0;	# Ok
}

# Run the PROTECT command
sub main'load_run_protect {
	package main;
	local($mode) = @_;
	local($local) = $opt'sw_l ? ' locally' : '';
	if ($opt'sw_u) {
		&env'undef('protect');
		&env'unset('protect') unless $opt'sw_l;
		&add_log("PROTECT [$mfile] reset to default$local") if $loglvl > 7;
		return 0;	# Ok
	}
	$mode = oct($mode) if $mode =~ /^0/;
	&env'local('protect', $mode) if $opt'sw_l;	# Restored when leaving rule
	$env'protect = $mode;	# Permanent change, unless changed locally already
	local($omode) = sprintf("0%o", $mode);	# Octal string, for logging
	&add_log("PROTECT [$mfile] mode set to ${omode}$local") if $loglvl > 7;
	0;	# Ok
}

# Run the BIFF command
sub main'load_run_biff {
	package main;
	local($mode) = $cms =~ m|^(\S+)|;
	local($l) = $opt'sw_l ? ' locally' : '';
	local($allowed) = ($mode =~ /off/i) ? 0 : 1;	# New boolean setting
	local($was) = ($env'biff =~ /off/i) ? 0 : 1;	# Old boolean setting
	local($setting) = $allowed ? 'ON' : 'OFF';
	&env'local('biff', $setting) if $opt'sw_l;
	$env'biff = $setting;				# Won't hurt given the above local call
	if ($allowed && $mode !~ /^on$/i) {	# New biff template format path given
		$mode =~ s/^~/$cf'home/;		# ~ substitution
		&env'local('biffmsg', $mode) if $opt'sw_l;
		$env'biffmsg = $mode;
		&add_log("biff template in file $mode$l") if $loglvl > 7;
	}
	&add_log("biffing turned $setting$l") if $loglvl > 7 && $was != $allowed;
	0;
}

# For SAVE, STORE or WRITE, the job is the same
# If the name is not an absolute path, the folder directory is taken
# in the "maildir" environment variable. If none, defaults to ~/Mail.
# A folder whose name begins with a '+' is taken as an MH folder.
sub main'load_run_saving {
	package main;
	local($folder, $remove) = @_;				# Shall we remove folder first?
	local($folddir) = $XENV{'maildir'};			# Folder directory location
	unless ($folder =~ /^\+/) {					# Not an MH folder
		$folder = "~/mbox" unless $folder;		# No folder -> save in mbox
		$folder =~ s/~/$cf'home/g;				# ~ substitution
		$folddir =~ s/~/$cf'home/g;				# ~ substitution
		$folddir = "$cf'home/Mail" unless $folddir;	# Default folders in ~/Mail
		$folder = "$folddir/$folder" unless $folder =~ m|^/|;
		local($dir) = $folder =~ m|(.*)/.*|;	# Get directory name
		unless (-d "$dir") {
			&makedir($dir);
			unless (-d "$dir") {
				&add_log("ERROR couldn't create directory $dir")
					if $loglvl > 0;
			} else {
				&add_log("created directory $dir") if $loglvl > 7;
			}
		}
	}
	# Cannot use WRITE with an MH folder, it behaves like a SAVE. Same thing
	# when attempting to save in a directory...
	if ($remove == $FOLDER_REMOVE && $folder !~ /^\+/) {
		# Folder has to be removed before writting into it. However, if it
		# is write protected, do not unlink it (save will fail later on anyway).
		# Note that this makes it a candidate for hooks via WRITE, if the
		# folder has its 'x' bit set with its 'w' bit cleared. This is an
		# undocumented feature however (WRITE is not supposed to trigger hooks).
		unlink "$folder" if -f "$folder" && -w _;
	}
	local($mbox, $failed) = &save($folder);
	local($log_message);				# Log message to be issued
	unless ($failed) {
		local($file) = $folder;			# Work on a copy to detect leading dir
		$folddir =~ s/(\W)/\\$1/g;		# Escape possible meta-characters
		$file =~ s|^$folddir/||;		# Preceded by folder directory?
		if ($file =~ s/^\+//) {
			$log_message = "MH folder $file";
		} elsif ($file ne $folder) {
			$log_message = "folder $file";
		} else {
			$log_message = &tilda($folder);	# Replace the home directory by ~
		}
	}

	# Return the status of the save command and a part of the logging message
	# to be issued. That way, we get a nice contextual log.
	($mbox, $failed, $log_message);
}

# Perform the appropriate continuation status, depending on the option:
# When 'x' is given as the option string, then the current options in the
# opt package are used instead of -c, -r or -a.
sub main'load_alter_execution {
	package main;
	local($option, $mode) = @_;	# Option, mode we have to change to
	if ($mode ne '') {
		&add_log("entering new state $mode") if $loglvl > 6 && $wmode ne $mode;
		$wmode = $mode;
	}
	if ($option eq 'x') {		# Backward compatibility at 3.0 PL24
		$option = '-c' if $opt'sw_c;
		$option = '-a' if $opt'sw_a;
		$option = '-r' if $opt'sw_r;
		$option = '' if $option eq 'x';
	}
	&add_log("altering execution in mode '$wmode', option '$option'")
		if $loglvl > 18;
	if ($option eq '-c') {		# Continue execution
		0;
	} elsif ($option eq '-r') {	# Asks for RESTART
		&do_restart;
	} elsif ($option eq '-a') {	# Asks for ABORT
		&do_abort;
	} else {					# Default is to REJECT
		&do_reject;
	}
	# Propagate return status.
}

# Save message in specified folder
sub main'load_save_message {
	package main;
	local($folder) = @_;
	local($mbox, $failed, $log_message) = &run_saving($folder, $FOLDER_APPEND);
	unless ($failed) {
		&add_log("SAVED [$mfile] in $log_message") if $loglvl > 2;
		$ever_saved = 1;			# We were able to save it
	}
	$failed;
}

# List of special header selector, for which a pattern without / is to be
# taken as an equality with the login name of the address. If there are some
# metacharacters, then a match will be attempted on that name. For each of
# those special headers, we record the name of the subroutine to be called.
# If a matching function is not specified, the default is 'match_var'.
# The %Amatcher gives the name of the fields which contains an address.
sub main'load_init_matcher {
	package main;
	%Matcher = (
		'Envelope',			'match_single',
		'From',				'match_single',
		'To',				'match_list',
		'Cc',				'match_list',
		'Apparently-To',	'match_list',
		'Newsgroups',		'match_list',
		'Sender',			'match_single',
		'Resent-From',		'match_single',
		'Resent-To',		'match_list',
		'Resent-Cc',		'match_list',
		'Resent-Sender',	'match_single',
		'Reply-To',			'match_single',
		'Relayed',			'match_list',
	);
	%Amatcher = (
		'From',				1,
		'Envelope',			1,
		'To',				1,
		'Cc',				1,
		'Apparently-To',	1,
		'Sender',			1,
		'Resent-From',		1,
		'Resent-To',		1,
		'Resent-Cc',		1,
		'Resent-Sender',	1,
		'Reply-To',			1,
	);
}

# Transform a shell-style pattern into a perl pattern
sub main'load_perl_pattern {
	package main;
	local($_) = @_;		# The shell pattern
	s/\./\\./g;			# Escape .
	s/\*/.*/g;			# Transform * into .*
	s/\?/./g;			# Transform ? into .
	$_;					# Perl pattern
}

# Take a pattern as written in the rule file and make it suitable for
# pattern matching as understood by perl. Unless the pattern starts with a
# leading / or is of the form m||, it is enclosed within slashes.
# We also enclose the whole pattern within ().
sub main'load_make_pattern {
	package main;
	local($_) = shift(@_);
	# The whole pattern is inserted within () to make at least one
	# backreference. Otherwise, the following could happen:
	#    $_ = '1 for you';
	#    @matched = /^\d/;
	#    @matched = /^(\d)/;
	# In both cases, the @matched array is set to ('1'), with no way to
	# determine whether it is due to a backreference (2nd case) or a sucessful
	# match. Knowing we have at least one bracketed reference is enough to
	# disambiguate.
	if (/^m(\W)(.*)\1(\w*)$/) {
		$_ = "m$1($2)$1$3";
	} elsif (m|^/(.*)/(\w*)$|) {
		$_ = "/($1)/$2";
	} else {
		# Pattern does not start with a / or is not of the form m|xxx|
		$_ = &perl_pattern($_);		# Simple words specified via shell patterns
		$_ = "/^($_)\$/";			# Anchor pattern
	}
	$_;						# Pattern suitable for eval'ed matching
}

# ### Main matching entry point ###
# ### (called from &apply_rules in pl/analyze.pl)
# Attempt a match of a set of pattern, for each possible selector. The selector
# string given can contain multiple selectors separated by white spaces.
sub main'load_match {
	package main;
	local($selector) = shift(@_);	# The selector on which pattern applies
	local($pattern) = shift(@_);	# The pattern or script to apply
	local($range) = shift(@_);		# The range on which pattern applies
	local($matched) = 0;			# Matching status returned
	# If the pattern is held within double quotes, it is assumed to be the name
	# of a file from which patterns may be found (one per line, shell comments
	# being ignored).
	if ($pattern !~ /^"/) {
		$matched = &apply_match($selector, $pattern, $range);
	} else {
		# Load patterns from file whose name is given between "quotes"
		# All un-escaped @ in patterns are escaped for perl5.
		local(@filepat) = &include_file($pattern, 'pattern');
		grep(s/([^\\](\\\\)*)@/$1\\@/g && undef, @filepat);
		# Now do the match for all the patterns. Stop as soon as one matches.
		foreach (@filepat) {
			$matched = &apply_match($selector, $_, $range);
			last if $matched;
		}
	}
	$matched ? 1 : 0;		# Return matching status (guaranteed numeric)
}

# Attempt a pattern match on a set of selectors, and set the special macro %&
# to the name of the regexp-specified fields which matched.
sub main'load_apply_match {
	package main;
	local($selector) = shift(@_);	# The selector on which pattern applies
	local($pattern) = shift(@_);	# The pattern or script to apply
	local($range) = shift(@_);		# The range on which pattern applies
	local($matched) = 0;			# True when a matching occurred
	local($inverted) = 0;			# True whenever all '!' match succeeded
	local($invert) = 1;				# Set to false whenever a '!' match fails
	local($match);					# Matching status reported
	local($not) = '';				# Shall we negate matching status?
	if ($selector eq 'script') {	# Pseudo header selector
		$matched = &evaluate(*pattern);
	} else {						# True header selector

		# There can be multiple selectors separated by white spaces. As soon as
		# one of them matches, we stop and return true. A selector may contain
		# metacharacters, in which case a regular pattern matching is attempted
		# on the true *header* fields (i.e. we skip the pseudo keys like Body,
		# Head, etc..). For instance, Return.* would attempt a match on the
		# field Return-Receipt-To:, if present. The special macro %& is set
		# to the list of all the fields on which the match succeeded
		# (alphabetically sorted).

		foreach $select (split(/ /, $selector)) {
			$not = '';
			$select =~ s/^!// && ($not = '!');
			# Allowed metacharacters are listed here (no braces wanted)
			if ($select =~ /\.|\*|\[|\]|\||\\|\^|\?|\+|\(|\)/) {
				$match = &expr_selector_match($select, $pattern, $range);
			} else {
				$match = &selector_match($select, $pattern, $range);
			}
			if ($not) {								# Negated test
				$invert = !$match if $invert;		# '!' tests AND'ed
				$inverted = $invert;				# Meaningful from now on
			} else {
				$matched = $match;					# Normal tests OR'ed
			}
			last if $matched;		# Stop when matching status known
		}
	}
	$matched = $matched || $inverted;
	if ($loglvl > 19) {
		local($logmsg) = "applied '$pattern' on '$selector' ($range) was ";
		$logmsg .= $matched ? "true" : "false";
		&add_log($logmsg);
	}
	$matched;						# Return matching status
}

# Attempt a pattern match on a set of selectors, and set the special macro %&
# to the name of the field which matched. If there is more than one such
# selector, values are separated using comas. If selector is preceded by a '!',
# then the matching status is negated and *all* the tested fields are recorded
# within %& when the returned status is 'true'.
sub main'load_expr_selector_match {
	package main;
	local($selector) = shift(@_);	# The selector on which pattern applies
	local($pattern) = shift(@_);	# The pattern or script to apply
	local($range) = shift(@_);		# The range on which pattern applies
	local($matched) = 0;			# True when a matching occurred
	local(@keys) = sort keys %Header;
	local($match);					# Local matching status
	local($not) = '';				# Shall boolean value be negated?
	local($orig_ampersand) = $macro_ampersand;	# Save %&
	$selector =~ s/^!// && ($not = '!');
	&add_log("field '$selector' has metacharacters") if $loglvl > 18;
	field: foreach $key (@keys) {
		next if $Pseudokey{$key};		# Skip Body, All...
		&add_log("'$select' tried on '$key'") if $loglvl > 19;
		next unless eval '$key =~ /' . $select . '/';
		$match = &selector_match($key, $pattern, $range);
		$matched = 1 if $match;			# Only one match needed
		# Record matching field for futher reference if a match occurred and
		# the selector does not start with a '!'. Record all the tested fields
		# if's starting with a '!' (because that's what is interesting in that
		# case). In that last case, the original macro will be restored if any
		# match occurs.
		if ($not || $match) {
			$macro_ampersand .= ',' if $macro_ampersand;
			$macro_ampersand =~ s/;,$/;/;
			$macro_ampersand .= $key;
		}
		if ($match) {
			&add_log("obtained match with '$key' field")
				if $loglvl > 18;
			next field;				# Try all the matching selectors
		}
		&add_log("no match with '$key' field") if $loglvl > 18;
	}
	$macro_ampersand .= ';';		# Set terminated with a ';'
	# No need to negate status if selector was preceded by a '!': this will
	# be done by apply match.
	$macro_ampersand = $orig_ampersand if $not && $matched;	# Restore %&
	&add_log("matching status for '$selector' ($range) is '$matched'")
		if $loglvl > 18;
	$matched;						# Return matching status
}

# Attempt a match of a pattern against a selector, return boolean status.
# If pattern is preceded by a '!', the boolean status is negated.
# If the 'rulemac' configuration variable is set to ON, a macro substitution
# is performed on the search pattern.
sub main'load_selector_match {
	package main;
	local($selector) = shift(@_);	# The selector on which pattern applies
	local($pattern) = shift(@_);	# The pattern to apply
	local($range) = shift(@_);		# The range on which pattern applies
	local($matcher);				# Subroutine used to do the match
	local($matched);				# Record matching status
	local($not) = '';				# Shall we apply NOT on matching result?
	$selector = &header'normalize($selector);	# Normalize case
	$matcher = $Matcher{$selector};
	$matcher = 'match_var' unless $matcher;
	$pattern =~ s/^!// && ($not = '!');
	&macros_subst(*pattern) if $cf'rulemac =~ /on/i;	# Macro substitution
	$matched = &$matcher($selector, $pattern, $range);
	$matched = !$matched if $not;	# Revert matching status if ! pattern
	if ($loglvl > 19) {
		local($logmsg) = "matching '$not$pattern' on '$selector' ($range) was ";
		$logmsg .= $matched ? "true" : "false";
		&add_log($logmsg);
	}
	$matched;				# Return matching status
}

# Matching is done in a header which only contains an internet address. The
# $range parameter is ignored (does not make any sense here). An optional 4th
# parameter may be supplied to specify the matching buffer. If absent, the
# corresponding header line is used -- this feature is used by &match_list.
sub main'load_match_single {
	package main;
	local($selector, $pattern, $range, $buffer) = @_;
	local($login) = 0;				# Set to true when attempting login match
	local(@matched);
	unless (defined $buffer) {		# No buffer for matching was supplied
		$buffer = $Header{$selector};
	}
	#
	# If we attempt a match on a field holding e-mail addresses and the pattern
	# is anchored at the beginning with a /^, then we only keep the address
	# part and remove the comment if any.
	#
	# If the field holds a full e-mail address and only that, we automatically
	# select the address part of the field for matching. -- RAM, 17/03/2001
	#
	# Otherwise, the field is left alone.
	#
	# If the pattern is only a single name, we extract the login name for
	# matching purposes...
	#
	if ($Amatcher{$selector}) {					# Field holds an e-mail address
		if (
			$pattern =~ m|^/\^| ||
			$pattern =~ m|^[-\w.*?]+(\\\@[-\w.*?]+)?\s*$|
		) {
			$buffer = (&parse_address($buffer))[0];
			&add_log("matching buffer reduced to '$buffer'") if $loglvl > 18;
		}
		if ($pattern =~ m|^[-\w.*?]+\s*$|) {	# Single name may have - or .
			$buffer = &login_name($buffer);		# Match done only on login name
			$pattern =~ tr/A-Z/a-z/;	# Cannonicalize name to lower case
		}
		$login = 1 unless $pattern =~ m|^/|;	# Ask for case-insensitive match
	}
	$buffer =~ s/^\s+//;				# Remove leading spaces
	$buffer =~ s/\s+$//;				# And trailing ones
	$pattern = &make_pattern($pattern);
	$pattern .= "i" if $login;			# Login matches are case-insensitive
	@matched = eval '($buffer =~ ' . $pattern . ');';
	# If buffer is empty, we have to recheck the pattern in a non array context
	# to see if there is a match. Otherwise, /(.*)/ does not seem to match an
	# empty string as it returns an empty string in $matched[0]...
	$matched[0] = eval '$buffer =~ ' . $pattern if $buffer eq '';
	&eval_error;						# Make sure eval worked
	&update_backref(*matched);			# Record non-null backreferences
	$matched[0];						# Return matching status
}

# Matching is done on a header field which may contains multiple addresses
# This will not work if there is a ',' in the comment part of the addresses,
# but I never saw that and I don't want to write complex code for that--RAM.
# If a range is specified, then only the items specified by the range are
# actually used.
sub main'load_match_list {
	package main;
	local($selector, $pattern, $range) = @_;
	local($_) = $Header{$selector};	# Work on a copy of the line
	tr/\n/ /;						# Make one big happy line
	local(@list) = split(/,/);		# List of addresses
	local($min, $max) = &mrange($range, scalar(@list));
	return 0 unless $min;			# No matching possible if null range
	local($buffer);					# Buffer on which pattern matching is done
	local($matched) = 0;			# Set to true when matching has occurred
	@list = @list[$min - 1 .. ($max > $#list ? $#list : $max - 1)]
		if $min != 1 || $max != 9_999_999;
	foreach $buffer (@list) {
		# Call match_single to perform the actual match and supply the matching
		# buffer as the last argument. Note that since range does not make
		# any sense for single matches, undef is passed on instead.
		$matched = &match_single($selector, $pattern, undef, $buffer);
		last if $matched;
	}
	$matched;
}

# Look for a pattern in a multi-line context
sub main'load_match_var {
	package main;
	local($selector, $pattern, $range) = @_;
	local($lines) = 0;					# Number of lines in matching buffer
	my $target = \$Header{$selector};
	# Need to special-case Body to use the *decoded* version
	$target = $Header{'=Body='} if $selector eq 'Body';
	if ($range ne '<1,->') {			# Optimize: count lines only if needed
		$lines = $$target =~ tr/\n/\n/;
	}
	local($min, $max) = &mrange($range, $lines);
	return 0 unless $min;				# No matching possible if null range
	my $buffer;							# Buffer on which matching is attempted
	local(@buffer);						# Same, whith range line selected
	local(@matched);
	$pattern = &make_pattern($pattern);
	# Optimize, since range selection is the exception and not the rule.
	# Most likely, we use the default selection, i.e. we take everything...
	if ($min != 1 || $max != 9_999_999) {
		@buffer = split(/\n/, $$target);
		@buffer = @buffer[$min - 1 .. ($max > $#buffer ? $#buffer : $max - 1)];
		$buffer = join("\n", @buffer);		# Keep only selected lines
		undef @buffer;						# May be big, so free ASAP
		$target = \$buffer;
	}
	# Ensure multi-line matching by adding trailing "m" option to pattern
	@matched = eval '($$target =~ ' . $pattern . 'm);';
	# If buffer is empty, we have to recheck the pattern in a non array context
	# to see if there is a match. Otherwise, /(.*)/ does not seem to match an
	# empty string as it returns an empty string in $matched[0]...
	$matched[0] = eval '$$target =~ ' . $pattern . 'm' unless length $$target;
	&eval_error;						# Make sure eval worked
	&update_backref(*matched);			# Record non-null backreferences
	$matched[0];						# Return matching status
}

# Reseet the backreferences at the beginning of each rule match attempt
# The backreferences include %& and %1 .. %99.
sub main'load_reset_backref {
	package main;
	$macro_ampersand = '';			# List of matched generic selector
	@Backref = ();					# Stores backreferences provided by perl
}

# Update the backward reference array. There is a maximum of 99 backreferences
# per filter rule. The argument list is an array of all the backreferences
# found in the pattern matching, but the first item has to be skipped: it is
# the whole matching string -- see comment on make_pattern().
sub main'load_update_backref {
	package main;
	local(*array) = @_;				# Array holding $1 .. $9, $10 ..
	local($i, $val);
	for ($i = 1; $i < @array; $i++) {
		$val = $array[$i];
		push(@Backref, $val);		# Stack backreference for later perusal
		&add_log("stacked '$val' as backreference") if $loglvl > 18;
	}
}

# Return minimum and maximum for range value. A range is specified as <min,max>
# but '-' may be used as min for 1 and max as a symbolic constant for the
# maximum value. An arbitrarily large number is returned in that case. If a
# negative value is used, it is added to the number of items and rounded towards
# 1 if still negative. That way, it is possible to request the last 10 items.
# As a special case, <3> stands for <3,3> and thus <-> means everything.
sub main'load_mrange {
	package main;
	local($range, $items) = @_;
	local($min, $max) = (1, 9_999_999);
	local($rmin, $rmax);
	$rmin = $rmax = $1 if $range =~ /<\s*([\d-]+)\s*>/;
	($rmin, $rmax) = $range =~ /<\s*([\d-]*)\s*,\s*([\d-]*)\s*>/
		unless defined $rmin;
	$rmin = $min if $rmin eq '' || $rmin eq '-';
	$rmax = $max if $rmax eq '' || $rmax eq '-';
	$rmin = $rmin + $items + 1 if $rmin < 0;
	$rmax = $rmax + $items + 1 if $rmax < 0;
	$rmin = 1 if $rmin < 0;
	$rmax = 1 if $rmax < 0;
	($rmin, $rmax) = (0, 0) if $rmin > $rmax;	# Null range if min > max
	return ($rmin, $rmax);
}

# If the file name does not start with a '/', then it is assumed to be found
# in the mailfilter directory if defined, maildir otherwise, and the home
# directory finally. The function returns the full path of the file derived
# from those rules but does not actually check whether file exists or not.
sub main'load_locate_file {
	package main;
	local($filename) = @_;			# File we are trying to locate
	$filename =~ s/~/$cf'home/g;	# ~ substitution
	unless ($filename =~ m|^/|) {	# Do nothing if already a full path
		if (defined($XENV{'mailfilter'}) && $XENV{'mailfilter'} ne '') {
			$filename = $XENV{'mailfilter'} . "/$filename";
		} elsif (defined($XENV{'maildir'}) && $XENV{'maildir'} ne '') {
			$filename = $XENV{'maildir'} . "/$filename";
		} else {
			$filename = $cf'home . "/$filename";
		}
	}
	$filename =~ s/~/$cf'home/g;	# ~ substitution
	$filename;
}

# Locate specified program from command line by looking through the PATH
# like the shell would. Return the first matching program path or the program
# name if not found. Caller can check for the presence of '/' in the returned
# value to determine whether we succeeded. A leading ~ is replaced by the
# user's home directory.
sub main'load_locate_program {
	package main;
	local($_) = @_;
	undef while s/^\s*[<>]\s*\S+//;	# Strip leading >&1 or >file directives
	local($name) = /^\s*(\S+)/;
	$name =~ s/~/$cf'home/g;		# ~ substitution
	return $name if $name =~ m|/|;	# Absolute or relative path, no search

	foreach $dir (split(/:/, $ENV{'PATH'})) {
		$dir = '.' if $dir eq '';
		return "$dir/$name" if -x "$dir/$name";
	}

	return $name;		# Not found, return plain name
}

# Parse an address and returns (internet, comment)
# Examples:
#    ram@eiffel.com (Raphael Manfredi)  -> (ram@eiffel.com, Raphael Manfredi)
#    Raphael Manfredi <ram@eiffel.com>  -> (ram@eiffel.com, Raphael Manfredi)
# Note that we try to parse malformed RFC822 addresses to the best we can, by
# giving priority to anything between <> for correct e-mail address detection.
# Common errors include having a '<>' construct as part of the comment attached
# to the address as "name <surname> lastname", but this can only be followed
# by a <> address and the regexp is built so that it will skip the first <>
# and match only the last one on the line.
sub main'load_parse_address {
	package main;
	local($_) = shift(@_);		# The address to be parsed
	local($comment);
	local($internet);
	if (/^\s*(.*?)\s*<(\S+)>[^()]*$/) {		# comment <address>
		$comment = $1;
		$internet = $2;
		$comment =~ s/^"(.*)"/$1/;			# "comment" -> comment
		($internet, $comment);
	} elsif (/^\s*([^()]+?)\s*\((.*)\)/) {	# address (comment) 
		$comment = $2;
		$internet = $1;
		# Construct '<address> (comment)' is invalid but... priority to <>
		# This will also take care of "comment" <address> (other-comment)
		$internet =~ /<(\S+)>/ && ($internet = $1);
		($internet, $comment);
	} elsif (/^\s*<(\S+)>\s*(.*)/) {		# <address> ...garbage...
		($1, $2);
	} elsif (/^\s*\((.*)\)\s*<?(.*)>?/) {	# (comment) [address or <address>]
		($2, $1);
	} else {								# plain address, grab first word
		/^\s*(\S+)\s*(.*)/;
		($1, $2);
	}
}

# Parses an internet address and returns the login name of the sender. When
# facing an RFC 822 group addressing (like To: group:;), it returns the group
# name when mailbox is not specified.
sub main'load_login_name {
	package main;
	local($_) = shift(@_);				# The internet address
	if (/^(\S+):(\S*);/) {				# rfc-822-group:mailbox;
		if ($2 eq '') {
			&last_name($1);				# empty mailbox name, use phrase
		} else {
			&login_name($2);			# mailbox name
		}
	} elsif (s/^@\S+://) {				# @domain:user@other
		&login_name($_);				# parse user@other
	} elsif (s/^"(\S+)"@\S+/$1/) {		# "user@domain"@other
		&login_name($_);				# parse user@domain
	} elsif (s/^(\S+)@\S+/$1/) {		# user@domain.name
		&login_name($_);				# parse user
	} elsif (s/^(\S+)%\S+/$1/) {		# user%domain.name
		&login_name($_);				# parse user
	} elsif (s/^\S+!(\S+)/$1/) {		# ...!backbone!user
		&last_name($_);					# user can only be a simple name
	} else {							# everything else must be a single name
		&last_name($_);					# keep only last name
	}
}

# Lower-case name only
sub main'load_last_name {
	package main;
	local($_) = shift(@_);			# The sender's login name
	tr/A-Z/a-z/;					# And lowercase it
	$_;
}

# Parse an e-mail address and return a three element array:
#   ($host, $domain, $country)
sub main'load_internet_info {
	package main;
	local($_) = shift(@_);				# The internet address
	local($login) = &login_name($_);	# Get the address login name
	local($internet);					# The internet part of the address
	# Try with uucp form first, to detect things like eiffel!ram@inria.fr
	# We use the login name to anchor the last '!' or the first '@' or '%'
	($internet) = /([^!]*)!$login/i;
	($internet) = /$login[@%]([\w.-]*)/i unless $internet;
	$internet = &myhostname . ".$cf::domain" unless $internet;
	$internet =~ tr/A-Z/a-z/;				# Always lower-cased
	local(@parts) = split(/\./, $internet);	# Break on dots
	if (@parts == 1) {						# Only a host name
		# Maybe this is a local address, maybe this is a uucp name. Assume that
		# it is local if there is an '@' sign, as in 'ram@lyon'. Otherwise, it
		# is a uucp name, as in 'eiffel!ram'.
		push(@parts, 'uucp') if /!$login/;	# UUCP name
		push(@parts, split(/\./, $cf::domain)) if @parts == 1;
	}
	unshift(@parts, '') if @parts == 2;		# No host name
	@parts[($#parts - 2) .. $#parts];		# ($host, $domain, $country)
}

# Generate a unique message ID
sub main'load_gen_message_id {
	package main;
	my $now = time;
	my @alphabet = ('a' .. 'z', '0' .. '9', 'A' .. 'Z');
	my $randword = '';
	for (my $i = 0; $i < 10; $i++) {
		$randword .= $alphabet[rand @alphabet];
	}
	my $domain = &domain_addr;				# Local domain where we run
	my $id = "<mailagent-$now-$randword\@$domain>";
	&header'msgid_cleanup(\$id);			# Clean up: domain wrongly set?
	return $id;
}

# Macros substitutions (in-place)
sub main'load_macros_subst {
	package main;
	local(*str) = shift(@_);			# The string
	local($_) = $str;					# Work on a copy
	return $_ unless /%/;				# Return immediately if no macros

	local($sender);							# The from field
	local(@from);							# The rfc-822 parsed from line
	$sender = $Header{'From'};				# Header-derived From address
	@from = &parse_address($sender);		# Get (address, comment)
	local($login) = &login_name($from[0]);	# Keep only login name
	local($fullname) = $from[1];			# The comment part of address
	$fullname = $login unless $fullname;	# Use login name if no comment part
	local($reply_to) = $Header{'Reply-To'}; # Return path derived
	local($subject) = $Header{'Subject'};	# Original subject header
	$subject =~ s/^\s*Re:\s*(.*)/$1/;		# Strip off leading Re:
	$subject = "<empty subject>" unless $subject;
	$reply_to = (&parse_address($reply_to))[0];	# Keep only e-mail address

	# Time computations
	local($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
			localtime(time);
	$mon = sprintf("%.2d", $mon + 1);
	$mday = sprintf("%.2d", $mday);
	local($timenow) = sprintf("%.2d:%.2d", $hour, $min);
	$hour = sprintf("%.2d", $hour);
	$year += 1900;

	# The following dummy block is here only to force perl interpreting
	# the $ variables in the substitutions correctly...
	if (0) {
		$Header{'a'} = 'a';
		$Variable{'a'} = 'a';
		$Backref[0] = 0;
	}

	s/%%/\01/g;							# Protect double percent signs
	s/%/\02!/g;							# Make sure substitutions do not add %

	&macro'over if defined &macro'over;	# Allow for internal override

	# In the following, substitutions marked as "workaround for perl 5.0 bug"
	# are fixing the fact that $1 will get clobbered if the routine used in
	# the substitution part is dataloaded.

	s/\02!A/&macro'internet/eg;			# Main internet address of sender
	s/\02!d/$mday/g;					# Day of the month (01-31)
	s/\02!C/&domain_addr/eg;			# CPU name, fully qualified with domain
	s/\02!D/$wday/g;					# Day of the week (0-6)
	s/\02!e/$cf'email/go;				# The user's email address
	s/\02!f/$Header{'From'}/g;			# The "From:" line
	s/\02!h/$hour/g;					# Hour of the day (00-23)
	s/\02!H/&myhostname/eg;				# Hostname on which mailagent runs
	s/\02!i/$Header{'Message-Id'}/g;	# Message-Id (null string if none)
	s/\02!I/&macro'domain/eg;			# Internet domain name of sender
	s/\02!l/$Header{'Lines'}/g;			# Number if lines in message
	s/\02!L/$Header{'Length'}/g;		# Length of message, in bytes
	s/\02!m/$mon/g;						# Month of the year
	s/\02!n/$login/g;					# Lower-cased login name of sender
	s/\02!N/$fullname/g;				# Full name of sender (login if none)
	s/\02!o/$orgname/g;					# Organization name
	s/\02!O/&macro'org/eg;				# Organization part of sender's address
	s/\02!r/$reply_to/g;				# Return path of message
	s/\02!R/$subject/g;					# Subject with leading Re: suppressed
	s/\02!s/$Header{'Subject'}/g;		# Subject of message
	s/\02!S/Re: $Header{'Subject'}/g;	# Re: subject of original message
	s/\02!t/$timenow/g;					# Current time HH:MM
	s/\02!T/$macro_T/g;					# Time of last modification on file
	s/\02!u/$cf'user/go;				# User login name (does not change)
	s/\02!U/$cf'name/go;				# User's name (does not change)
	s/\02!y/$year % 100/eg;				# Year (last two digits)
	s/\02!Y/$year/g;					# Year (yyyy format)
	s/\02!_/ /g;						# A white space
	s/\02!~//g;							# A null character
	s/\02!&/$macro_ampersand/g;			# List of matched generic selectors
	s/\02!(\d\d?)/$Backref[$1 - 1]/g;	# A pattern matching backreference
	s/\02!#:(\w+)/local($x) = $1; &extern'val($x)/eg;
		# A persistent user-defined variable (workaround for perl 5.0 PL0 bug)
	s/\02!#(\w+)/$Variable{$1}/g;		# A user-defined variable
	s/\02!\[([\w-]+)\]/$Header{$1}/g;	# The %[Field] macro
	s/\02!=(\w+)/"\$cf'$1"/gee;			# The %=config_var variable
	s/\02!-([^\s(])/local($x) = $1; &macro'usr($x)/ge;
		# A %-x single letter user macro (workaround for perl 5.0 PL0 bug)
	s/\02!-\(([^\s)]+)\)/local($x) = $1; &macro'usr($x)/ge;
		# A %-(complex) user-defined macro (workaround for perl 5.0 PL0 bug)

	s/\02!/%/g;							# Any remaining percent is kept
	s/\01/%/g;							# A double percent expands to %
	$str = $_;							# Update string in-place
}

# Return the internet information of the From address
sub macro'load_info {
	package macro;
	local($addr) = (&'parse_address($'Header{'From'}))[0];
	&'internet_info($addr);
}

# Return the organization name
sub macro'load_org {
	package macro;
	local($host, $domain, $country) = &info;
	$domain;
}

# Return the domain name
sub macro'load_domain {
	package macro;
	local($host, $domain, $country) = &info;
	$domain .'.'. $country;
}

# Return the qualified internet address
sub macro'load_internet {
	package macro;
	local($host, $domain, $country) = &info;
	$host ne '' ? $host .'.'. $domain .'.'. $country : $domain .'.'. $country;
}

# Record a new set of macros within the &over routine. Macros are defined
# using a low-level (ok, perl) description, but hey! this is an internal
# feature not intended to be used by others. The argument is a single string
# formatted this way:
#   <l> <value> <mod>
# where <l> is a single letter or group of letters, <value> is what will be
# substituted when the macro is seen, and <mod> are the perl modifiers that
# should be added at the end of the substitute perl statement.
sub macro'load_overload {
	package macro;
	local($macros) = @_;
	local(@macs) = split(/\n/, $macros);
	local($_);
	local($fn);					# Where the &over routine is built
	local($l, $value, $mod);
	$fn = "sub over {\n";
	foreach (@macs) {
		($l, $value, $mod) = split;
		$fn .= 's/\02!'.$l.'/'.$value."/g$mod;\n";
	}
	$fn .= "}\n";
	undef &over if defined &over;
	eval $fn;
	&'add_log("ERROR in &macro'overload: $@") if chop($@) && $'loglvl;
}

sub header'load_init {
	package header;
	# Main header fields which should be looked at when parsing a mail header
	%Mailheader = (
		'From', 1,
		'To', 1,
		'Subject', 1,
		'Date', 1,
	);
}

# Reset header checking status
sub header'load_reset {
	package header;
	&init unless $init_done++;		# Initialize private data
	$last_was_header = 0;			# Previous line was not a header
	$maybe = 0;						# Do we have a valid part of header?
	$line = 0;						# Count number of lines in header
}

# Is the current line still part of a valid header ?
sub header'load_valid {
	package header;
	local($_) = @_;
	return 1 if $last_was_header && /^\s/;	# Continuation line
	return -1 if /^$/;						# End of header
	$last_was_header = /^([\w\-]+):/ ? 1 : 0;
	# Activate $maybe when essential parts of a valid mail header are found
	# Any client can check 'maybe' to see if what has been parsed so far would
	# be a valid RFC-822 header, even though syntactically correct.
	$maybe |= $Mailheader{$1} if $last_was_header;
	$last_was_header = /^From\s+\S+/
		unless $last_was_header || $line;	# First line may be special
	++$line;								# One more line
	$last_was_header;						# Are we still inside header?
}

# Produce a warning header field about a specific item
sub header'load_warning {
	package header;
	local($field, $added) = @_;
	local($warning);
	local(@field) = split(' ', $field);
	$warning = 'X-Filter-Note: ';
	if ($added && @field == 1) {
		$warning .= "Header $field added at ";
	} elsif ($added && @field > 1) {
		$field = join(', ', @field);
		$field =~ s/^(.*), (.*)/$1 and $2/;
		$warning .= "Headers $field added at ";
	} else {
		$warning .= "Parsing error in original previous line at ";
	}
	$warning .= &main'domain_addr;
	$warning;
}

# Make sure header contains vital fields. The header is held in an array, on
# a line basis with final new-line chopped. The array is modified in place,
# setting defaults from the %Header array (if defined, which is the case for
# digests mails) or using local defaults.
sub header'load_clean {
	package header;
	local(*array) = @_;					# Array holding the header
	local($added) = '';					# Added fields

	$added .= &check(*array, 'From', $cf'user, 1);
	$added .= &check(*array, 'To', $cf'user, 1);
	$added .= &check(*array, 'Date', &mta_date(), 0);
	$added .= &check(*array, 'Subject', '<none>', 1);

	&push(*array, &warning($added, 1)) if $added ne '';
}

# Check presence of specific field and use value of %Header as a default if
# available and if '$use_header' is set, otherwise use the provided value.
# Return added field or a null string if nothing is done.
sub header'load_check {
	package header;
	local(*array, $field, $default, $use_header) = @_;
	local($faked);						# Faked value to be used
	if ($use_header) {
		$faked = (defined $'Header{$field}) ? $'Header{$field} : $default;
	} else {
		$faked = $default;
	}

	# Try to locate field in header
	local($_);
	foreach (@array) {
		return '' if /^$field:/;
	}

	&push(*array, "$field: $faked");
	$field . ' ';
}

# Push header line at the end of the array, without assuming any final EOH line
sub header'load_push {
	package header;
	local(*array, $line) = @_;
	local($last) = pop(@array);
	push(@array, $last) if $last ne '';	# There was no EOH
	push(@array, $line);				# Insert header line
	push(@array, '') if $last eq '';	# Restore EOH
}

# Compute a valid date field suitable for mail header:
#    Mon,  8 Jan 2001 05:14:00 +0100
# If optional $time arg is missing, use current time.
sub header'load_mta_date {
	package header;
	my ($time) = @_;
	$time = time unless defined $time;
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time);
	my ($gmmin, $gmhour, $gmyday) = (gmtime($time))[1,2,7];
	my @days   = qw(Sun Mon Tue Wed Thu Fri Sat);
	my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);

	# Compute delta in minutes between local time and GMT
	$yday = -1 if $gmyday == 0 && $yday >= 364;
	$gmyday = -1 if $yday == 0 && $gmyday >= 364;
	$gmhour += 24 if $gmyday > $yday;
	my $dhour = ($gmyday < $yday) ? $hour + 24 : $hour;
	my $dmin = ($dhour * 60 + $min) - ($gmhour * 60 + $gmmin);

	# Must convert delta into +/-HHMM format
	my $d = 100 * int($dmin / 60) + (abs($dmin) % 60) * ($dmin > 0 ? 1 : -1);

	sprintf "%s, %2d %s %4d %02d:%02d:%02d %+05d",
		$days[$wday], $mday, $months[$mon], 1900+$year, $hour, $min, $sec, $d;
}

# Normalizes header: every first letter is uppercase, the remaining of the
# word being lowercased, as in This-Is-A-Normalized-Header. Note that RFC-822
# does not impose such a formatting.
sub header'load_normalize {
	package header;
	local($field_name) = @_;			# Header to be normalized
	$field_name =~ s/(\w+)/\u\L$1/g;
	$field_name;						# Return header name with proper case
}

# Clean-up message ID string passed as reference.
# Returns true if string was changed.
sub header'load_msgid_cleanup {
	package header;
	my $mref = shift;
	local $_ = $$mref;
	my $fixup = 0;

	# Regexps are written to work on both a single <id> as found in Message-ID
	# lines, and on a space-separated list as found in References lines.

	s/>\s+</>\01</g;			# Protect spaces between IDs for References
	$fixup++ if s/\s/-/g;		# No spaces
	$fixup++ if s/_/-/g;		# No _ in names
	$fixup++ if s|/|-|g;		# No / in names
	$fixup++ if s/[(){}]//g;	# No () nor {} in names and ID
	$fixup++ if s/\.+>/>/g;		# No trailing dot(s)
	$fixup++ if s/\.\.+/./g;	# No consecutive dots
	s/<([^>]*?)>/'<' . &header'msgid_fix($1, \$fixup) . '>'/ge;
	s/>\01</> </g;				# Restore spaces between IDs
	$$mref = $_ if $fixup;
	return $fixup;
}

# Parse date from header and return its timestamp (seconds since the Epoch)
sub header'load_parsedate {
	package header;
	my ($str) = @_;

	# Look for +/-HHMM adjustment wrt GMT time
	my ($sign, $hh_d, $mm_d) = $str =~ /\s([-+])(\d\d)(\d\d)\b/;
	my $dt = 0;
	$dt = (($sign eq '+') ? +1 : -1) * ($hh_d * 60 + $mm_d) if $sign ne '';

	# Parse date to compute timestamp since Jan 1, 1970 GMT.
	return main::getdate($str, time, -$dt);
}

# Format header field to fit into 78 columns, each continuation line being
# indented by 8 chars. Returns the new formatted header string.
sub header'load_format {
	package header;
	local($field) = @_;			# Field to be formatted
	local($tmp);				# Buffer for temporary formatting
	local($new) = '';			# Constructed formatted header
	local($kept);				# Length of current line
	local($len) = 78;			# Amount of characters kept
	local($cont) = ' ' x 8;		# Continuation lines starts with 8 spaces
	# Format header field, separating lines on ',' or space.
	while (length($field) > $len) {
		$tmp = substr($field, 0, $len);		# Keep first $len chars
		$tmp =~ s/^(.*)([,\s]).*/$1$2/;		# Cut at last space or ,
		$kept = length($tmp);				# Amount of chars we kept
		$tmp =~ s/\s+$//;					# Remove trailing spaces
		$tmp =~ s/^\s+//;					# Remove leading spaces
		$new .= $cont if $new;				# Continuation starts with 8 spaces
		$len = 70;							# Account continuation for next line
		$new .= "$tmp\n";
		$field = substr($field, $kept, length $field);
	}
	unless ($field =~ /^\s+$/) {			# Not only spaces
		$new .= $cont if $new;				# Add 8 chars if continuation
		$new .= $field;						# Remaining information on one line
	}
	return $new;
}

# Same as format() but with extra magic for news articles: we must never
# emit a continuation right after a header, there must be a single space
# after the field name.
# Also, this routine must work when called to format a continuation (field
# stating with spaces).
sub header'load_news_fmt {
	package header;
	my ($field) = @_;			# Field to be formatted
	my $continuation = 0;
	$continuation++ if $field =~ s/^\s+//;
	my $res = &format($field);
	if ($continuation) {
		$res = (' ' x 8) . $res;	# Can be larger than 80 chars, but it's OK
	} else {
		$res =~ s/^([\w-]+):(\S)/$1: $2/s || $res =~ s/^([\w-]+):\n/$1: \n/s;
	}
	return $res;
}

# Scan the head of a file and try to determine whether there is a mail
# header at the beginning or not. Return true if a header was found.
sub main'load_header_found {
	package header;
	local($file) = @_;
	local($correct) = 1;				# Were all the lines from top correct ?
	local($_);
	open(FILE, $file) || return 0;		# Don't care to report error
	&reset;								# Initialize header checker
	while (<FILE>) {					# While still in a possible header
		last if /^$/;					# Exit if end of header reached
		$correct = &valid($_);			# Check line validity
		last unless $correct;			# No, not a valid header
	}
	close FILE;
	$correct;
}

# The "LEAVE" command
# Leave a copy of the message in the mailbox. Returns (mbox, failed_status)
sub main'load_leave {
	package main;
	local($mailbox) = &mailbox_name;	# Incomming mailbox filename
	&add_log("starting LEAVE") if $loglvl > 15;
	&save($mailbox);					# Propagate return status
}

# The "SAVE" command
# Save a message in a folder. Returns (mbox, failed_status). If the folder
# already exists and has the 'x' bit set, then is is understood as an external
# hook and mailhook is invoked. If the folder name begins with '+', it is
# handled as an MH folder. If the folder is actually a directory, then message
# is saved in an individual file, much like an MH folder.
sub main'load_save {
	package main;
	local($mailbox) = @_;			# Where mail should be saved
	local($failed) = 0;				# Printing status
	if ($mailbox eq '') {			# Empty mailbox (e.g. SAVE %1 with no match)
		$mailbox = &mailbox_name;
		&add_log("WARNING empty folder name, using $mailbox") if $loglvl > 5;
	}
	local($biffing) = $env'biff =~ /ON/i;	# Whether we should biff or not
	local($type) = 'file';					# Folder type, for biffing macros
	&add_log("starting SAVE $mailbox") if $loglvl > 15;
	if ($mailbox =~ s/^\+//) {		# MH folder?
		$type = 'MH';
		$failed = &mh'save($mailbox);
	} elsif (-d $mailbox) {			# A directory hook
		$failed = &mh'savedir($mailbox);
		$type = 'dir';
	} elsif (-x $mailbox) {			# Folder hook
		$failed = &save_hook;		# Deliver to program
		$biffing = 0;				# No biffing for hooks
	} else {						# Saving to a normal folder
		# Uncompress folders if necessary. The restore routine will perform
		# the necessary checks and return immediately if no compression is
		# wanted for that particular folder. However, we can avoid the overhead
		# of calling this routine (and loading it when using dataloading) if
		# the 'compress' configuration parameter is missing.
		&compress'restore($mailbox) if $cf'compress;
		$failed = &save_folder($mailbox);
	}
	&add_log("ERROR could not save mail in $mailbox") if $failed && $loglvl;
	&emergency_save if $failed;

	# At this point, folder_saved has been updated to the path of the folder
	# where message has been saved, unless it was a hook but in that case we
	# do not biff anyway.
	&biff($folder_saved, $type) if $biffing && !$failed;

	($mailbox, $failed);			# Where save was made and failure status
}

# Called by &save when folder is a regular one (i.e. not a hook).
sub main'load_save_folder {
	package main;
	local($mailbox) = @_;			# Where mail should be saved
	local($amount);					# Amount of bytes written
	local($failed);
	# Explicitely check for writable mailbox. I've seen an NFS between a SUN
	# and a file on DEC OSF/1 accept appending while file was read-only...
	# We may only perform the open if the file does not exist or is writable.
	local($exist) = -e $mailbox;	# Run chmod if PROTECT used and created
	local($mayopen) = !$exist || -w _;
	if ($mayopen && open(MBOX, ">>$mailbox")) {

		local($ret) = &mbox_lock($mailbox);	# Lock mailbox, get exclusive access
		return 1 unless defined $ret;		# Unable to lock, fail miserably
		local($size) = -s $mailbox;			# Initial mailbox size

		# It's still possible we did not get any lock on the mailbox, or just
		# a partial lock, but the user did tell us that was ok, via the
		# 'locksafe' variable setting. Simply emit a notice that we're
		# delivering without locking.

		&add_log("NOTICE saving to non-locked $mailbox")
			if !$ret && $loglvl > 6;

		# If MMDF-style mailboxes are allowed, then the saving routine will
		# try to determine what kind of folder it is delivering to and choose
		# the right format. Otherwise, standard Unix format is assumed.

		if ($cf'mmdf =~ /on/i) {	# MMDF-style allowed
			# Save to mailbox, selecting the right format (UNIX vs MMDF)
			($failed, $amount) = &mmdf'save(*MBOX, $mailbox);
		} else {
			# Save to UNIX folder
			($failed, $amount) = &mmdf'save_unix(*MBOX);
		}

		# Because we might write over NFS, and because we might have had to
		# force fate to get a lock, it is wise to make sure the folder has the
		# right size, which would tend to indicate the mail made it to the
		# buffer cache, if not to the disk itself.
		local($should) = $size + $amount;	# Computed new size for mailbox
		local($new_size) = -s $mailbox;		# Last write was flushed to disk
		&add_log("ERROR $mailbox has $new_size bytes (should have $should)")
			if $new_size != $should && $loglvl;
		$failed = 1 if $new_size != $should;

		# Finally, release the lock on the mailbox and close the file. If the
		# closing operation fails for whatever reason, the routine will return
		# a 1, so $failed will be set. Of course, "normally" it should not
		# fail at that point, since the mail was previously flushed.
		$failed |= &mbox_unlock($mailbox);	# Will close file

		# Now adjust permissions on the file, if created and PROTECT was used.
		&mmdf'chmod($env'protect, $mailbox) if !$exist && defined $env'protect;

	} else {
		local($msg) = $mayopen ? "$!" : 'Permission denied';
		&add_log("SYSERR open: $msg") if $loglvl;
		if (-f "$mailbox") {
			&add_log("ERROR cannot append to $mailbox") if $loglvl;
		} else {
			&add_log("ERROR cannot create $mailbox") if $loglvl;
		}
		$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 main'load_save_hook {
	package main;
	local($failed) = &hook'process($mailbox);
	&add_log("HOOKED [$mfile]") if !$failed && $loglvl > 2;
	$failed;				# Propagate failure status
}

# The "PROCESS" command
# The body of the message is expected to be in $Header{'Body'}
sub main'load_process {
	package main;
	local($subj) =			$Header{'Subject'};
	local($msg_id) =		$Header{'Message-Id'};
	local($sender) =		$Header{'Reply-To'};
	local($to) =			$Header{'To'};
	local($bad) = "";		# No bad commands
	local($pack) = "auto";	# Default packing mode for sending files
	local($ncmd) = 0;		# Number of valid commands we have found
	local($dest) = "";		# Destination (where to send answers)
	local(@cmd);			# Array of all commands
	local(%packmode);		# Records pack mode for each command
	local($error) = 0;		# Error report code
	local(@body);			# Body of message

	&add_log("starting PROCESS") if $loglvl > 15;

	# If no @PATH directive was found, use $sender as a return path
	$dest = $Userpath;				# Set by an @PATH
	$dest = $sender unless $dest;
	# Remove the <> if any (e.g. path derived from Return-Path)
	$dest = (&parse_address($dest))[0];

	# Debugging purposes
	&add_log("\@PATH was '$Userpath' and sender was '$sender'")
		if $loglvl > 18;
	&add_log("computed destination: $dest") if $loglvl > 15;

	# Make sure address is not hostile. Since a transcript is sent to the
	# sender computed in $dest, we cannot inform the user if the address
	# turns out to be really hostile.

	unless (&addr'valid($dest)) {
		&add_log("ERROR $dest is an hostile sender address") if $loglvl > 1;
		&add_log("NOTICE discarding whole command mail") if $loglvl > 6;
		return 0;	# An error would requeue message
	}

	# Copy body of message in an array, one line per entry
	@body = split(/\n/, $Header{'Body'});

	# The command file contains the authorized commands
	if ($#command < 0) {			# Command file not processed yet
		open(COMMAND, "$cf'comfile") || &fatal("No command file!");
		while (<COMMAND>) {
			chop;
			$command{$_} = 1;
		}
		close(COMMAND);
	}

	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/;
			s/^help/mailhelp/i;
			# Now fetch command's name (first symbol)
			if (/^([^ \t]+)[ \t]/) {
				$first = $1;
			} else {
				$first = $_;
			}
			if (!$command{$first}) {	# if un-authorized cmd
				s/^/unknown cmd: /;		# needs a space after ":"
				$bad .= $_ . "\n";
				next line;
			}
			$packmode{$_} = $pack;		# packing mode for this command
			push(@cmd, $_);				# record command
		}
	}

	# ************* Check with authoritative file ****************

	# Do not continue if an error occurred, in which case the mail will remain
	# in the queue and will be processed later on.
	return $error if $error || $dest eq '';

	# Now we are sure the mail we proceed is for us
	$sender = "<someone>" if $sender eq '';
	$ncmd = $#cmd + 1;
	if ($ncmd > 1) {
		&add_log("$ncmd commands for $sender") if $loglvl > 11;
	} elsif ($ncmd == 1) {
		&add_log("1 command for $sender") if $loglvl > 11;
	} else {
		&add_log("no command for $sender") if $loglvl > 11;
	}
	foreach $fullcmd (@cmd) {
		$cmdfile = "/tmp/mess.cmd$$";
		open(CMD,">$cmdfile");
		# For our children
		print CMD "jobnum=$jobnum export jobnum\n";
		print CMD "fullcmd=\"$fullcmd\" export fullcmd\n";
		print CMD "pack=\"$packmode{$fullcmd}\" export pack\n";
		print CMD "path=\"$dest\" export path\n";
		print CMD "sender=\"$sender\" export sender\n";
		print CMD "set -x\n";
		print CMD "$fullcmd\n";
		close CMD;
		$fullcmd =~ /^[ \t]*(\w+)/;		# extract first word
		$cmdname = $1;		# this is the command name
		$trace = "$cf'tmpdir/trace.cmd$$";

		# For HPUX-10.x, grrr... have to use our own shell otherwise that
		# silly posix /bin/sh dumps core when fed the $cmdfile we built above.
		local($shell) = &cmdserv'servshell;

		$pid = fork;						# We fork here
		$pid = -1 unless defined $pid;

		if ($pid == 0) {
			open(STDOUT, ">$trace");		# Where output goes
			open(STDERR, ">&STDOUT");		# Make it follow pipe
			exec $shell, "$cmdfile";		# Don't use sh -c
		} elsif ($pid == -1) {
			# Set the error report code, and the mail will remain in queue
			# for later processing. Any @RR in the message will be re-executed
			# but it is not really important. In fact, this is going to be
			# a feature, not a bug--RAM.
			$error = 1;
			&add_log("ERROR cannot fork: $!") if $loglvl > 0;
			unless (open(MAILER,"|$cf'sendmail $cf'mailopt $dest $cf'email")) {
				&add_log("SYSERR fork: $!") if $loglvl;
				&add_log("ERROR cannot launch $cf'sendmail") if $loglvl;
			}
			print MAILER <<EOM;
To: $dest
Subject: $cmdname not executed
$MAILER

Your command was: $fullcmd

It was not executed because I could not fork. Sigh !
(Kernel report: $!)

The command has been left in a queue and will be processed again
as soon as possible, so it is useless to resend it.

-- mailagent speaking for $cf'user
EOM
			close MAILER;
			if ($?) {
				&add_log("ERROR cannot report failure") if $loglvl;
			}
			return $error;		# Abort processing now--mail remains in queue
		} else {
			wait();
			if ($?) {
				unless (
					open(MAILER,"|$cf'sendmail $cf'mailopt $dest $cf'email")
				) {
					&add_log("SYSERR fork: $!") if $loglvl;
					&add_log("ERROR cannot launch $cf'sendmail") if $loglvl;
				}
				print MAILER <<EOM;
To: $dest
Subject: $cmdname returned a non-zero status
$MAILER

Your command was: $fullcmd
It produced the following output and failed:

EOM
				if (open(TRACE, $trace)) {
					while (<TRACE>) {
						print MAILER;
					}
					close TRACE;
				} else {
					print MAILER "** SORRY - NOT AVAILABLE **\n";
					&add_log("ERROR cannot dump trace") if $loglvl;
				}
				print MAILER "\n-- mailagent speaking for $cf'user\n";
				close MAILER;
				if ($?) {
					&add_log("ERROR cannot report failure") if $loglvl;
					&trace_dump($trace, "failed $fullcmd");
				}
				&add_log("FAILED $fullcmd") if $loglvl > 1;
			} else {
				&add_log("OK $fullcmd") if $loglvl > 5;
			}
		}
		unlink $cmdfile, $trace;
	}

	if ($bad) {
		unless (open(MAILER,"|$cf'sendmail $cf'mailopt $dest $cf'email")) {
			&add_log("SYSERR fork: $!") if $loglvl;
			&add_log("ERROR cannot launch $cf'sendmail") if $loglvl;
		}
		chop($bad);			# Remove trailing new-line
		# For unknown reasons, perl 4.0 PL36 chokes here when a here-document
		# syntax is used. Although it compiles fine, no output seems to be
		# sent on the MAILER descriptor. Use a string then... That's funny
		# though becase here-document syntax is used elsewhere without problems.
		print MAILER
"To: $dest
Subject: the following commands were not executed
$MAILER

$bad

If $cf'name can figure out what you wanted, he may do it anyway.

-- mailagent speaking for $cf'user
";
		close MAILER;
		if ($?) {
			&add_log("ERROR unable to mail back bad commands from $sender")
				if $loglvl;
		}
		&add_log("bad commands from $sender") if $loglvl > 5;
	}

	&add_log("all done for $sender") if $loglvl > 11;
	$error;		# Return error report (0 for ok)
}

# The "MACRO" command
sub main'load_macro {
	package main;
	local($args) = @_;				# name = (value, type)
	local($replace) = $opt'sw_r;	# Replace existing macro
	local($delete) = $opt'sw_d;		# Delete macro
	local($pop) = $opt'sw_p;		# Pop macro
	local($name);					# Macro's name
	if ($delete || $pop) {			# Macro is to be deleted or popped
		($name) = $args =~ /(\S+)/;	# Get first "word"
		&usrmac'pop($name) if $pop;	# Pop last value, delete if last
		&usrmac'delete($name) if $delete;
		return ($name, $pop ? 'popped' : 'deleted');	# Propagate action
	}
	# There are two formats for the macro command. The first format uses the
	# 'name = (val, type)' template and can be used to specify any kind of
	# macro (see usrmac.pl). The other form is name ..., where ... is any
	# kind of string --including spaces-- which will be used as a SCALAR
	# value. Of course, that string cannot take the '= (val, type)' format.
	local($val);					# Macro's value
	local($type) = 'SCALAR';		# Assume scalar type
	if ($args =~ /(\S+)\s*=\s*\(\s*(.*),\s*(\w+)\s*\)\s*/) {
		($name, $val, $type) = ($1, $2, $3);
	} else {
		($name, $val) = $args =~ /(\S+)\s+(.*)/;	# SCALAR typ                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               