Provided by: mailagent_3.1-81-4_amd64 bug

NAME

       mailagent - an automatic mail-processing tool

SYNOPSIS

       mailagent  [  -dhilqtFIVU  ]  [  -s{umaryt}  ]  [ -f file ] [ -e rule ] [ -c config ] [ -L
       loglevel ] [ -r rulefile ] [ -o override ] [ mailfile ]

DESCRIPTION

       Mailagent allows you to process your mail automatically. Given a set  of  lex-like  rules,
       you are able to fill mails to specific folders, forward messages to a third person, pipe a
       message to a command or even post the message to a  newsgroup.  It  is  also  possible  to
       process  messages containing some commands.  The mailagent is not usually invoked manually
       but is rather called via the filter program, which is in turn invoked by  sendmail.   That
       means  you  must have sendmail on your system to use this.  You also must have perl to run
       the mailagent scripts.

       There is a set of options which may be used when you  invoke  mailagent  yourself.  Please
       refer  to the OPTIONS section for a complete description. You may use the -h option to get
       a cryptic usage reminder.

   Product Overview
       Mailagent has actually four distinct set of features, which can be used simultaneously  or
       one at a time. This involves:

       •    An  @SH  command  processor,  to remain compatible with the first implementation.  In
            this simplest usage, all the mail messages are left in your mailbox (or the catch all
            folder  required  on Debian systems: Please see /usr/share/doc/mailagent/SECURITY for
            details), with special processing  raised  on  messages  whose  subject  is  Command.
            Please  refer to the section entitled USING THE DEFAULT RULES if you wish to use this
            feature.

       •    A complete mail filter, which helps you sort  your  mail  based  on  various  sorting
            criteria  and  actions.  Filtering  is  specified  in  a rule file and supersedes the
            default Command mail processing (which may be turned on again by  explicitly  setting
            up  a  rule  for  it).  This  should be the most common use of mailagent and is fully
            documented under the section entitled USING THE FILTER.   You  may  deliver  mail  to
            plain Unix-style folders but also to MMDF and MH ones.

       •    A  replacement  for  the  vacation program, which will automatically answer your mail
            while you are not there. You only need to supply a message to be sent  back  and  the
            frequency  at which this will occur. Some simple macro substitutions allow you to re-
            use some parts of the mail header into your vacation message, for a more personalized
            reply. See the VACATION MODE section for more details.

       •    A  generic  mail  server, which will let you implement a real mail server without the
            hassle of the lower-level concerns like error recovery, logging or  command  parsing.
            The  full documentation can be found in the section GENERIC MAIL SERVER at the end of
            this manual page.

       It is possible to extend the mailagent filtering commands by implementing them in perl and
       then  having  them  automagically  loaded  when  used. Those extended commands will behave
       exactly like built in ones, as documented in the EXTENDING FILTERING COMMANDS section.

   Learning From Examples
       It is  quite  possible  that  you  will  find  this  manual  page  too  complex  for  you.
       Unfortunately, it is not really meant to be a tutorial but rather a reference material. If
       you wish, you may start by looking at the examples held in the  distribution  source  tree
       under  agent/examples.  This  directory  contains  two examples of rule files (look at the
       README file first) and are verbosely commented.

GETTING STARTED

       First, you need to install a minimum configuration and see  how  it  works.  It  would  be
       useless  to  fully  install  the  program  and  then  discover  that  it  does not work as
       advertised...

       To start the installation, you have to set up  a  ~/.mailagent  file  which  is  the  main
       configuration file, and choose the right filter program.

   Choosing The Filter Program
       The  distribution  comes  with two filter programs. One written in shell and one in C. The
       shell version might be the one to use if you can  receive  your  mail  on  many  different
       platforms  where  your  home  directory  is  NFS-mounted  (i.e.   shared  among  all those
       platforms). The C version is safer and much faster, but you need to install it to a  fixed
       location.

       On  some platforms, sendmail does not correctly reset its UID when processing mails in its
       own queue. In that case, you need to get a private copy of the C filter program  and  make
       it  setuid  to  yourself.  The filter will then correctly reset its UID if invoked with an
       effective UID different from yours (it may also require the setgid bit  to  reset  GID  as
       well).   If  this  is  indeed  the  case  on  your  system,  make  sure  you  use the path
       configuration variable to set a proper PATH, as the filter will spawn a perl process  with
       the '-S' option, looking for a mailagent script.

       Even if you do not need to get a setuid copy of the filter program, it is wise to set up a
       proper path: someone might break into your account by putting a mailagent Trojan horse  in
       the  appropriate  location.  Also  make  sure  the  mailagent program is protected against
       writing, as well as the directory which holds it, or  someone  might  substitute  his  own
       version  of the script and break security. I believe the setuid filter program to be safe,
       but overlooking is always possible so please report any security hole to me.

       The filter script can be found in the Lib/mailagent directory. It needs some tailoring  so
       you  should copy it into your home directory and edit it to suit your needs. Comments held
       in it should be self explanatory. There is only a small section at the head of the  script
       which  needs  to  be edited.  You'll have to delete shell comments in the filter script by
       yourself if your shell cannot deal with them.

       As of version 3.0 PL44, I advise you to prefer the C version if you  are  concerned  about
       security. If you are in a position where multiple architectures can process your .forward,
       then a shell wrapper selecting the proper executable based on  the  architecture  will  be
       required.

   Configuring Mailagent
       If  mailagent  is  in your path, you may automatically configure a default installation by
       running:

                 mailagent -I

       which will create a ~/.mailagent file from an existing template, customize some  important
       variables for your site, and make some basic sanity checks. Everything the command does is
       output on the screen for checking purposes, and any problem found is reported.

       Otherwise, you have to copy the mailagent.cf file  held  in  the  mailagent  sub-directory
       /usr/share/mailagent (hereafter named Lib) as a .mailagent in your home directory. Edit it
       to configure the whole processing. In particular, you have to  choose  a  spool  directory
       (hereafter named Spool) and a log directory (hereafter named Log).

       Note that using the automatic installation procedure above does not prevent you from going
       through the file and modifying it as you wish.  In fact, you are greatly encouraged to  do
       this,  especially for the home directory setting, the logging level and the path or p_host
       variables. Once you are done, rerun the mailagent -I command to make  sure  everything  is
       fine.   Still,  you  will  have  to  plug  in  mailagent by creating a ~/.forward file, as
       explained in a few sections.

       Following is a description of each of the fields you will find in the  ~/.mailagent  file,
       followed  by  a  suggested  value,  when  applicable. Fields marked as optional may not be
       present in the configuration file. Some fields have a close relationship with others,  and
       that is given too.

       agemax    Period  after  which  an entry in the database should be removed (suggested: 1y)
                 This field is optional, but needed if autoclean is on.
       authfile  Remote sending authorizations (not implemented yet).
       autoclean Set to ON (case insensitively), mailagent will perform automatic cleaning of the
                 database entries under hash by removing all the items older than agemax. This is
                 an optional field, omitting it defaults to OFF.  (suggested: OFF, unless you use
                 ONCE, UNIQUE or RECORD commands, or activate the vacation mode.)
       biff      Whether  or  not biffing is wanted when mailagent delivers mail to a folder. Set
                 it to ON (case insensitively) to allow local  biffing  if  you  are  logged  in.
                 (optional, defaults to: OFF)
       biffhead  When  biffing  is  enabled,  this variable lists which headers should be printed
                 out. Headers should be given in their normalized format and  be  separated  with
                 commas. (optional, defaults to: From, To, Subject, Date).
       bifflen   The  maximum  length  of  the  message body that should be printed when biffing.
                 (optional, defaults to 560).
       bifflines The maximum number of lines of the message body  that  should  be  printed  when
                 biffing.  Actually,  mailagent  attempts to print that amount of lines, provided
                 the total amount  of  characters  printed  is  less  than  bifflen.   (optional,
                 defaults to 7).
       biffmh    When  turned ON, the body of the message is compacted before biffing by removing
                 consecutive spaces and replacing newlines with  a  single  space.   The  message
                 itself  is  not  altered  physically of course, only the output on the screen is
                 concerned.  Since this may yield to a difficult-to-read message, I  suggest  you
                 also turn on biffnice when using this option. (optional, defaults to: OFF).
       biffmsg   The  path  to  a  file  describing  the format biffing should use. If not set, a
                 default hardwired format is used. Season to taste. (suggested: ~/.biffmsg).
       biffnice  Whether the message should be reformatted  to  nicely  fit  into  the  terminal.
                 (optional, defaults to OFF, suggested: ON when biffmh is also ON).
       biffnl    Controls  whether "blank" body lines should be printed or not. By "blank" lines,
                 we mean lines not containing words. Set it to ON to print such blank  lines,  to
                 OFF  if  you wish to get a more compact view of the body within the limits fixed
                 by bifflen and bifflines. (optional, defaults to ON).
       biffquote Controls whether the leading attribution line introducing  a  trimmed  quotation
                 should be part of the biff message or not. When turned OFF, the attribution line
                 is trimmed along and this is reported in the trimming message, when bifftrim  is
                 ON. (optional, defaults to ON).
       bifftrim  Controls  whether  trimmed lines within the biff message should be replaced by a
                 message stating how many of them were trimmed. Only  used  by  the  %-T  biffing
                 macro. When turned OFF, it automatically turns off biffquote as well. (optional,
                 defaults to ON).
       bifftrlen States how many lines long a leading quotation should be before  performing  any
                 trimming. Only used by the %-T biffing macro. (optional, defaults to 2).
       callout   The  name  of the callout queue file where batched jobs are kept. This parameter
                 must be defined when using the AFTER command.  (suggested: $spool/callout)
       cleanlaps Cleaning period for database entries. The value of the last clean  up  is  saved
                 into  the  context  file.  This  is  optional,  but  needed  if autoclean is on.
                 (suggested: 1M)
       comfile   Name of the file containing authorized commands. Needed when  PROCESS  is  used.
                 (suggested: $spool/commands).
       compress  Name  of  the  file containing the list of compressed folders. See section about
                 folder compression. This is an optional parameter. (suggested: ~/.compress).
       compspecs Name of the file containing specifications for how to handle different types  of
                 compression formats.  See section about folder compression.  This is an optional
                 parameter. (suggested: $spool/compressors).
       comptag   The default compression tag when creating new folders.  If  not  specified,  the
                 default is 'gzip'.
       comserver Name  of  the  file  containing authorized SERVER commands and their definition.
                 This is an optional parameter if you don't plan to use the generic mail  server.
                 (suggested: $spool/server).
       context   File  holding the mailagent context. The context saves some variables which need
                 to be kept over the life of the process. Needed if auto cleaning  is  activated.
                 (suggested: $spool/context)
       distlist  A   list   of   all   the  available  distributions.  See  the  sample  held  in
                 Lib/mailagent/distribs. Needed by PROCESS only. (suggested: $spool/distribs)
       domain    Your domain name, without the leading dot, as  in  example.com.   The  value  is
                 appended  to  the  value  of  email when that variable does not have any '@', to
                 construct a fully qualified e-mail address.   See  also  the  hidenet  variable.
                 (optional, defaults to the domain name determined at build time).
       email     Your  electronic  mail address. If left unspecified, mailagent will try to guess
                 it. This address is used by mailagent when trying to send something to the  user
                 (you!). (suggested: specify your e-mail address).
       emergdir  Name  of  the  directory  which  should  be  used for dumps, preferably. This is
                 optional. (suggested: ~/tmp/lost+mail)
       execsafe  Whether to be strict before using exec() to launch a new  process  or  not.  The
                 value  of  this  variable  is  used  in place of secure when checking executable
                 files. (defaults to OFF, suggested: ON if possible).
       execskip  Whether to skip the exec() security  checks  alltogether.  Don't  turn  this  ON
                 unless  you  really  trust  all  the users having access to your machine or file
                 server. (optional, default to OFF, suggested: OFF).
       fromall   Whether or not mailagent should escape all the From lines in  the  message,  not
                 only  those  it thinks should appear dangerous (i.e. a From after a blank line).
                 This option only makes sense when fromesc  is  also  activated.  It  is  ignored
                 otherwise,  and  therefore  is  optional.  By  default, it is assumed to be OFF.
                 (suggested: OFF, until you have reasons  to  believe  your  mail  user-agent  is
                 confused  in  this mode: when it happens, your user agent will split mail for no
                 apparent reason).
       fromesc   Whether or not mailagent should escape potentially dangerous From lines in  mail
                 messages.  If  you  use  MH  or  if your mail reader does not use those lines to
                 separate messages, then you may set it to OFF. (suggested: ON)
       fromfake  Whether or not mailagent should fake a From: line into the message  header  when
                 it  is  absent.  Naturally,  it  requires  a valid leading From line to operate!
                 (optional, defaults to ON, suggested: ON).
       groupsafe If turned OFF, then group-writable files will be managed as if they were secure,
                 from  a security point of view. Leave it to ON if possible, or you may pass by a
                 huge security hole without your noticing (optional, defaults to  ON,  suggested:
                 ON).
       hash      The  directory  used  for  name  hashing  by the built-in database used by ONCE,
                 UNIQUE and RECORD commands. Optional, unless you make use of those  commands  or
                 activate  auto cleaning. The directory is placed in the spool area.  (suggested:
                 $spool/dbr).
       helpdir   Directory  where  help  files  for  SERVER  commands  are   kept.    (suggested:
                 $spool/help)
       hidenet   When  set  to  ON,  the value of the variable domain is the fully qualified name
                 used.  When OFF, the hostname is prepended to the domain.  If  the  hostname  is
                 already  fully qualified, then the value of domain is ignored.  Assuuming domain
                 is set to example.com and the hostname is host, then the  fully  qualified  name
                 will  be  host.example.com if hidenet is OFF, and example.com if ON.  (optional,
                 defaults to whatever was determined at build time)
       home      Defines where the home directory is. This must be accurate.
       level     Log level, see below for a definition of available levels (suggested: 9).
       linkdirs  When set to ON, carefully checks symbolic links to directories  when  performing
                 security  checks  on  sensitive  files.  This  will (recursively) check for each
                 symbolic link level that the target directory is not  world  writable  or  group
                 writable  and  that  the  parent  directory  of  each  target  link is not world
                 writable. If the secure option is OFF, this parameter  is  ignored.   (optional,
                 defaults to: ON, suggested: ON when secure is also ON).
       lockdekay The delay in seconds between two locking attempts. (optional, defaults to: 2).
       lockhold  The  maximum delay in seconds for holding a lock. After that time, the lock will
                 be broken. (optional, defaults to: 3600).
       lockmax   Maximum number of locking attempts before giving  up.  (optional,  defaults  to:
                 20).
       locksafe  When  locking  a  file,  mailagent  normally makes lockmax attempts separated by
                 lockdelay seconds, and then gives up. When facing a delivery to  a  mailbox,  it
                 may  make  sense  to  continue  even  if  no lock was grabbed, or even if only a
                 partial locking was done  (e.g.  one  of  the  .lock  or  flock()-style  locking
                 succeeded). This variable controls how safe you want to be. Set it to OFF to let
                 mailagent continue its mailbox delivery even though no locking was done,  to  ON
                 if  you  want  strict  locking, to PARTIAL if you can live with partial locking.
                 Messages not saved in a folder are dumped to an  emergency  mailbox.  (optional,
                 defaults to ON). On Debian systems, since mailagent can not grab locks,it should
                 always   be   left   ON,   or   else    mail    garbling    may    occur.    See
                 /usr/share/doc/mailagent/SECURITY for details.
       lockwarn  This  variable  controls  the  time after which mailagent should start emiting a
                 warning when busy trying to acquire a lock.  It is a  comma  separated  list  of
                 values,  in  seconds.  If  two  values  are given, the first is the initial time
                 threshold, the second is the repeat period. For instance,  a  value  of  "15,60"
                 would  cause a warning after 15 seconds, then every 60 seconds until the lock is
                 taken or the locking attempt time is expired (see lockmax  and  lockdelay).   If
                 only one value is given, it is taken as being both the initial threshold and the
                 period.  (optional, defaults to: 20,300).
       log       Name of the log file which will be put in Log directory. (suggested: agentlog).
       logdir    Logging directory. (suggested: ~/var/log).
       mailbox   The name of the system mailbox file, which by default is the value of  the  user
                 configuration variable. This is an optional parameter.
       maildrop  Location  of  the  system  mail  spool  directory. If none is provided, then the
                 mailagent will use the value determined by Configure.
       mailopt   Options to be passed to the mailer (see sendmail).  (optional,  suggested:  -odq
                 -i, when using sendmail).
       maxcmds   Maximum  number  of commands that are allowed to be executed by a SERVER command
                 before flushing the remaining of the mail message. (suggested: 10).
       maxerrors Maximum number of errors for the SERVER command before flushing the remaining of
                 the mail message. (suggested: 10).
       maxsize   Maximum  size in bytes of files before using kit for sending files. This is used
                 by PROCESS. (suggested: 150000).
       mboxlock  The format to be used for locking mailboxes  before  delivering  to  them.  This
                 string  goes  through  a  small  macro  substitution  mechanism  to make it more
                 general. The file name derived after macro substitution is the name of the  lock
                 that  will  be used, given the name of the file that is to be locked.  Available
                 macros are:

                      %D: the file directory name
                      %f: the file name to be locked (full path)
                      %F: the file base name (last path component)
                      %p: the current process pid number
                      %%: a plain % character

                 Common locking formats are "%f.lock" and "%D/.%F.lock". Of course, to be able to
                 use  this  feature, mailagent must not have been configured to use flock()-style
                 locking only. (optional, defaults to: %f.lock). This has  no  effect  on  Debian
                 systems, since mailagent can not get a lock anyway, since it is not sgid mail.
       mhprofile The  name  of  the MH profile to be used. This is needed only when attempting to
                 save in an MH folder. If this optional parameter is not set, the  default  value
                 ~/.mh_profile is used.
       mmdf      Set  this  to  ON  if  you wish to be able to save mail in MMDF-style mailboxes.
                 (suggested: OFF, unless you use MMDF or MH). This is invalid on a Debian system.
       mmdfbox   The value of this variable only matters when mmdf is on. If set to ON, then  new
                 folders  will  be created as MMDF ones. This variable is not used when saving to
                 an existing  folder,  since  in  that  case  the  mailagent  will  automatically
                 determine  the  type  and save the message accordingly.  (suggested: OFF, unless
                 you use MMDF or wish to use MH's mshf).
       msgprefix Name of the file to put in directory folders, specifying the message  prefix  to
                 be used. Optional, defaults to .msg_prefix.
       name      First  name  of the user, used by mailagent when referring to you. This sets the
                 value of the %U macro.
       newcmd    Name of the file  describing  new  filtering  commands.  See  section  Extending
                 Filtering  Commands  for  more details. Leave this optional parameter out unless
                 you are a mailagent expert. (suggested: $spool/newcmd).
       newsopt   Options to be passed to the news posting  program  (see  sendnews).   (optional,
                 suggested: leave empty when using inews).
       nfslock   Set  it to ON to ensure NFS-secure locks. The difference is that the hostname is
                 used in conjunction with the PID to obtain a lock.  However,  mailagent  has  to
                 fork/exec to obtain that information. This is an optional parameter which is set
                 to OFF by default. (suggested: OFF if you deliver mail from  only  one  machine,
                 even though it's via NFS).
       passwd    File  where  SERVER  power passwords are kept -- encrypted usually.  (suggested:
                 $powers/passwd).
       path      Minimum path to be used by C filter program.  To  set  a  specific  path  for  a
                 machine  host,  set  up a p_host variable. This will be prepended to the default
                 PATH variable supplied by other programs.  (suggested:  /bin:/usr/bin:/usr/ucb).
                 Note that the host name must be specified without any domain name appended to it
                 (e.g. for an host name of lyon.eiffel.com, use variable p_lyon).  If  your  host
                 name contains an '-' in it, you must write it as a '_', since '-' is not a valid
                 character for a perl variable name.
       perlib    This variable may be used to change the perl search  path  for  required  files.
                 Directories  should  be separated using a ':' character, just like a shell PATH.
                 This path is prepended to the  default  perl  search  path.  Any  directory  not
                 starting  with  a  '/'  (after  ~name  substitution)  is taken relatively to the
                 mailagent private lib directory determined at configuration time.
       plsave    Name of the file used to save the patchlevels for archived distributions.   This
                 is only used by the commands invoked via PROCESS. (suggested: $spool/plsave).
       powerdir  Directory    listing   user   clearances   for   SERVER   powers.    (suggested:
                 $powers/clearance)
       powerlist Name of file containing SERVER power aliases. Since power names can be arbitrary
                 long  but  some  filesystems  still  have  a 14 character limitation on filename
                 length, internal aliases are created and maintained by  mailagent.   (suggested:
                 $powers/aliases).
       powerlog  File  where SERVER power requests are logged, in addition to the agentlog. Since
                 those are a security concern, it is a good idea to log them separately.  If  not
                 defined, log them only in agentlog. (suggested: $logdir/powerlog).
       powers    Directory for SERVER power administration. (suggested: $spool/powers)
       proglist  A  small  description  for  the  available distributions. See the sample held in
                 Lib/mailagent/proglist.   This   is   used   by   PROCESS   only.    (suggested:
                 $spool/proglist)
       queue     Queue  directory  (messages  waiting  to  be  processed).  Required,  of course.
                 (suggested: $spool/queue)
       queuehold Maximum number of seconds a mail can sit in the  mailagent  queue  before  being
                 actually  processed.  During  that  time,  mailagent will not try to process the
                 message even when -q is used. (optional, defaults to: 1800).
       queuelost Maximum number of seconds after which mailagent should flag  messages  still  in
                 its queue as being old. (optional, defaults to: 86400, i.e. a day).
       queuewait Time  in  seconds  telling  the  C  filter  program how long it must wait before
                 launching mailagent. (optional, defaults to: 60, but can be lowered to 0 if  you
                 don't want to wait to delay getting new messages).
       rulecache The  name  of  the  file  used to cache the latest compiled rules. Since usually
                 mailagent works mainly with one same rule  file,  this  saves  the  overhead  of
                 recompiling all the rules each time. (optional, suggested: $spool/rulecache).
       rulemac   Set  this  to  ON  to  enable  macro substitutions in rule patterns.  (optional,
                 defaults to: OFF).
       rules     The name of the file  holding  the  filtering  rules  (optional  on  non  Debian
                 systems,  suggested: ~/.rules). On Debian systems, one must have a minimal rules
                 file   to   prevent   mailagent   from   trying    to    put    messages    into
                 /var/spool/mail/$USER, since mailagent can't lock that directory to prevent mail
                 from being  garbled.  This  is  because  Debian  policy  requires  all  entities
                 attempting  locks  on  that directory to be sgid mail, and making mailagent sgid
                 anything would be a security loophole.
                     { SAVE incoming };
                  is the suggested minimal rules file.
       runmax    Timeout for RUN commands and friends. (optional, defaults to: 3600).
       scriptcc  Flag indicating whether a copy of the SERVER session transcript should  be  send
                 to the user running mailagent. (suggested: OFF).
       secure    When  set  to  ON,  mailagent  and  the C filter will perform extensive security
                 checks  on  sensitive  files.  This  includes  checks  for  group   writability,
                 ownerships  and  protection testing on the directory where the file resides, and
                 checks on symbolic links to directories (mailagent only,  when  linkdirs  is  ON
                 too).  Note  that  secure  is  assumed to be ON, whatever its real setting, when
                 running as super-user. (suggested: ON).
       sendmail  The name of the program used to send mail. That program  must  accept  the  mail
                 message  with  headers  on  its  standard  input and a list of recipients on the
                 command line. If not specified, will use the mailer chosen at configuration time
                 (sendmail  usually).  The  command  line used to mail a message will be sendmail
                 mailopt address(es).  (optional, suggested: /usr/lib/sendmail).
       sendnews  The name of the program used to post news. That program  must  accept  the  news
                 article  with headers on its standard input. If not specified, will use the news
                 posting program chosen at configuration time (inews usually).  The command  line
                 used  to  post  an  article  will be sendnews -h newsopt.  (optional, suggested:
                 /usr/local/bin/inews).
       seq       File used to compute job numbers (suggested: .seq).
       servdir   The directory name where shell and perl server commands are stored. This is  the
                 default  lookup  place.  Optional  parameter unless SERVER is used.  (suggested:
                 $spool/cmds).
       servshell This is the name of the shell used to launch SERVER shell commands (actually  to
                 process  the  wrapper  file  that  will  ultimately exec() the command). On some
                 systems like HPUX 10.x, this has to be set to /usr/old/bin/sh to get  the  plain
                 old  Bourne  shell,  because /bin/sh is a braindead POSIX shell that closes file
                 descriptors greater than 2 upon exec(),  whereas  the  Bourne  shell  does  not.
                 (optional, suggested: /bin/sh unless you're on HPUX 10.x, as explained before).
       spool     Spool directory, required (suggested: ~/var/mailagent).
       statfile  File  where statistics should be gathered. If no such file exists, no statistics
                 will be recorded (suggested: $spool/mailagent.st).
       tofake    Whether or not mailagent should fake a To: line into the message header when  it
                 is  absent, which will be used for filtering purposes (no physical alteration of
                 the header occur). It uses Alternate-To: headers if found, otherwise it  assumes
                 the message was send to the user and takes the value from the user configuration
                 variable.  (optional, defaults to ON, suggested: ON; turn it  OFF  only  if  you
                 want to identify missing To: lines to detect SPAM).
       tome      This  optional  variable  may contain a comma separated list of alternate logins
                 that are also valid for the user (mail aliases). This is used in  vacation  mode
                 to  check  whether the mail was sent to the user or to a mailing list.  Matching
                 is anchored on the login name, so saying "ro*" will match both root and rom.
       track     Set to on (case insensitively), this turns on the -t option which tracks all the
                 rule  matches  and  the actions on standard output. This is optional (suggested:
                 OFF).
       timezone  The time zone value for environment variable TZ (optional).
       tmpdir    Directory for temporary files. Required (suggested: /tmp).
       umask     Default umask which is reset by mailagent before processing a message.   Assumed
                 to  be  decimal  unless starting with '0' (for octal) or '0x' (for hexadecimal).
                 The octal format is the easiest  way  to  specify  it  nonetheless.   (optional,
                 defaults to: 077).
       user      Login name of the user who runs mailagent. This sets the value of the %u macro.
       vacation  A flag set to ON or OFF to switch the vacation mode accordingly.
       vacfile   The name of the file to be sent back in vacation mode (suggested: ~/.vacation).
       vacfixed  When  ON,  all  changes  to  the  vacation  file  (even locally) by means of the
                 VACATION command are  forbidden.  This  is  useful  if  you  usually  have  many
                 customized  vacation messages for different people but temporarily want to force
                 one unique message (optional, defaults to: OFF).
       vacperiod The minimum time elapsed between  two  vacation  messages  to  a  given  address
                 (suggested: 1d).

   Available Logging Levels
       The following log levels can be used while running mailagent:

            0    No logging
            1    Major problems only
            2    Failed deliveries
            3    Successful deliveries
            4    Deferred messages
            5    Successful filter actions
            6    Unusual but benign incidents
            7    Informative messages
            8    Non-delivery filter actions
            9    Mail reception
            12   Debug
            19   Verbose
            20   Lot more verbose

   Plugging Mailagent
       Once  you  have  configured  mailagent  in  a  ~/.mailagent  (where ~ stands for your home
       directory), you must tell sendmail how to invoke it.  This is done by setting a ~/.forward
       file  which  looks  like  this (leading and trailing double quotes are a mandatory part of
       it):

            "| exec /users/ram/mail/filter >>/users/ram/.bak 2>&1"

       This will pipe all your mails to the filter program, redirecting all unusual  messages  to
       ~/.bak.  A sample filter shell script may be found in Lib/mailagent, as well as a C filter
       program. On some systems, it may be necessary to move the '|' character before the leading
       quote,  but  don't  try this unless you have no other choice (i.e. only as a last resort).
       Also, apparently Exim takes exeption to the exec, and even perhaps to the  redirection  --
       which would be a pity.

       It  is  very important to redirect error messages to some file within your home directory.
       For one thing, that will get you out of trouble if strange things  start  to  happen,  but
       more  to  the  point,  it  makes  your .forward file unique. Older sendmail program, in an
       heroic attempt to "optimize" delivery, will silently remove duplicate recipients, and if a
       recipient  has  a  .forward,  its  literal content is used in place of his e-mail address.
       Therefore, two local recipients with the same filtering string will be considered  as  one
       unique recipient and only one of them will get the message...

       If your system does not allow shell redirection from within the .forward, you can use this
       instead (only supported by the C filter):

            "| exec /users/ram/mail/filter -o /users/ram/.bak"

       which in effect redirects stdout and stderr to the specified file for you, appending  data
       at  the  end of the file.  If the filter runs setuid or setgid, you will not be allowed to
       create the file, nor to append to it unless the owner of the file is the real uid invoking
       the program (for security reasons).

       Note  that  the .forward file only pipes the mail to the filter program and does not leave
       any copy in the mailbox. It is up to you to decide in the rule file whether  you  want  to
       trash  the mail away or leave it in the mailbox.(Note that on Debian systems mailagent can
       not lock the spool directory, and letting it leave mail in mailbox may  cause  it  to  get
       garbled).  If  you  do  not  have  a  rule  file  (i.e.  you  left  a  blank entry in your
       ~/.mailagent, or you named a non-existent file,  or  your  file  is  simply  empty),   the
       default  action  is  to leave the mail in the mailbox, which is not a good idea for Debian
       machines. Please onstall a minimal rules file in any case,
        { SAVE incoming };
        is the suggested minimal rules file.

   Allowed Commands
       The allowed command file (as specified by  the  comfile  variable  in  your  ~/.mailagent)
       contains  all  the  recognized  and allowed commands.  The file commands held in directory
       Lib/mailagent should be copied as-is into your Spool directory.

   Testing Your Installation
       Now, assuming you have set a proper ~/.mailagent file and edited the configuration section
       of  the  filter,  it  is  time to test your installation. Make sure your .forward is world
       readable and that the filter has the execution bits set (there is no reason  to  make  the
       filter  world  readable).   Set  a log-level of 20 and disable vacation mode (the vacation
       entry in the ~/.mailagent should be OFF). Set the  name  of  the  rule  file  to  an  file
       containing a catch-all rule:
            { SAVE incoming };
        You are ready to proceed...

       Send  yourself  a  mail  and  give mailagent time to process your mail. The subject of the
       message should be 'test' (in fact, anything but 'Command').  You may want to run  a  "tail
       -f  logfile"  to  see  what's  happening. At the end of the processing, the logfile should
       contain something like the following (names  of  temporaries  may  -and  will-  of  course
       differ; timestamps have been removed):

            got the right to process mail
            building default rules
            parsing mail
            analyzing mail
            in mode 'INITIAL' for ALL
            selector 'All' on '<1,->', pattern '/^Subject: [Cc]ommand/'
            matching '/^Subject: [Cc]ommand/' on 'All' (<1,->) was false
            selector 'All'  on '<1,->'
            matching . on 'All' (<1,->) was true
            saving in folder incoming
            XEQ (LEAVE)
            starting LEAVE
            starting SAVE /home/ram/mail/incoming
            SAVED [qm7831] in folder incoming
            FILTERED [qm7831] from ram (Raphael Manfredi)
            mailagent continues
            mailagent exits

       If  you do not get that, there is a problem somewhere. Start by looking at the ~/.bak file
       (or whatever file the .forward uses  to  redirect  output  of  the  filter).  If  you  see
       something like:

            FATAL no valid queue directory
            DUMPED in ~/mbox.filter

       then  it  means  the  queue  parameter  in  your  ~/.mailagent  does  not point to a valid
       directory. Your mail has been dumped in an emergency mailbox.

       The ~/.bak file may also contain error messages stating that perl was not found.  In  that
       case, there should be an error message in the logfile:

            ERROR mailagent failed, [qm7886] left in queue

       In  that  case,  make  sure the mail has correctly been queued in a file qm7886. The queue
       will be processed again when another mail arrives or when the mailagent is invoked with -q
       (however,  to  avoid  race  conditions, only mails which have remained for a while will be
       processed).

       Queuing of mail also happens when another mailagent is running. If the logfile says:

            denied right to process mail

       then remove the perl.lock file in the Spool directory. Old lock  files  are  automatically
       discarded by the mailagent anyway (after one hour).

       If none of these occurs, then maybe sendmail did not process your ~/.forward at all or the
       file has a syntax error.  Check your mailbox, and if your mail is in there, your  .forward
       has  not  been  processed.  Otherwise,  ask  your system administrator to check sendmail's
       logfile. A correct entry would appear  as  (with  leading  timestamps  and  syslog  stamps
       removed):

            message-id=<9202041919.AA07882@york.eiffel.com>
            from=ram, size=395, class=0, received from local
            to="| /york/ram/mail/filter >>/york/ram/.bak 2>&1", delay=00:00:05, stat=Sent

       If  you  still  cannot find why the mail was not correctly processed, you should make sure
       you normally receive mail by removing (or renaming) your ~/.forward and  sending  yourself
       another test mail. Also make sure your home directory is world readable and "executable".

       If  you  are using the C filter, make sure it is running on the right platform.  There may
       be a low-level routing of all your mail to a mailhost machine, responsible for  the  final
       delivery,  and  the  filter  program  will  run  on that machine, which may be a different
       platform than the one you compiled filter on.  Also  make  sure  your  home  directory  is
       mounted  on  that  machine,  or  the  mail  transport  agent will be unable to locate your
       .forward file, less process it.

       This kind of centralized mail delivery is good only when a few people have mail processing
       hooks  (i.e. .forward files piping mail to a program); otherwise it's better to route mail
       to each user's workstation or  machine,  for  local  processing,  to  avoid  an  excessive
       workload on the mailhost machine, especially if it is a dedicated NFS server. If you are a
       system administrator installing mailagent and expect many people to use it, keep  this  in
       mind.

OPTIONS

       There  is  a limited set of options which may be used when calling the mailagent directly.
       Only one special option at a time may be specified.  Invoking mailagent  as  mailqueue  is
       equivalent to using the -l option.

       -c file        Specify  an  alternate  configuration  file  (~  substitution  occurs). The
                      default is ~/.mailagent.

       -d             The mailagent parses the rule file, compiles the rules and  dumps  them  on
                      the  standard output. This option is mainly used to check the syntax of the
                      rule file and make sure the rules are what the user really thinks they are.

       -e rule        This option lets you specify some rules on the  command  line,  which  will
                      override those specified via the ~/.mailagent, if any. There may be as many
                      -e as necessary, all the rules being concatenated  together  as  one  happy
                      array,  which  is then parsed the same way a rule file is. If only one rule
                      is given and there is no action specified between {...}  braces,  then  the
                      whole  line  is enclosed between braces. Hence saying -e 'SAVE foo' will be
                      understood as -e '{SAVE foo}', which will always  match  and  be  executed.
                      Using  the  -d  option  in conjunction with this one is a convenient way to
                      debug a set of rules.

       -f mailfile    Using mailfile as a  UNIX-style  mailbox  (i.e.  one  where  each  mail  is
                      preceded by a special From line stating the sender and the date the message
                      was issued), extract all its messages into the queue and process them as if
                      they were freshly arrived from the mail delivery subsystem.

       -F             Force  processing  on  already seen messages. Usually, mailagent enters the
                      special _SEEN_ state when it detects an X-Filter: line  issued  by  itself,
                      but  this option will have it continue as usual (although vacation messages
                      are disabled). Use this option when post-processing mail already  filtered.
                      Also look at the -U switch if you are using the RECORD or UNIQUE actions in
                      some rules.

       -h             Print out a usage message on the standard error and exit.

       -i             Interactive mode, directs mailagent to print a copy of all the log messages
                      on stderr.

       -I             Install  a  ~/.mailagent  file  from  template,  or merge new configuration
                      variables into an existing file; then  perform  sanity  checks  and  create
                      mandatory  files  or directories. This option may be viewed as an help into
                      setting  up  mailagent's  environment.  In  any  case,  the  created/merged
                      ~/.mailagent file should be manually verified before letting mailagent deal
                      with your mail by hooking it into ~/.forward.

       -l             List the mailagent queue. Recently queued mails which are waited for by the
                      filter  are skipped for about half an hour, to avoid race conditions.  This
                      may be configured via the queuehold variable.  Really  old  messages  (more
                      than queuelost seconds old) are flagged with a '#' character.  Messages out
                      of the queue (queue variable) are flagged with a '*', whilst  old  messages
                      out  of  the  queue  are  signaled  by  an  '@'. Locked messages have a '*'
                      appended to their status.

       -L level       Override the log level specified in the configuration file.

       -o override    This option lets you override a specific configuration option.  The  option
                      must  be followed by a valid configuration line, which will be parsed after
                      the configuration file itself. For instance, the -L 4 option is  completely
                      equivalent  to  -o  'level: 4'. Note that any white space must be protected
                      against shell interpretation by using the  appropriate  quoting  mechanism.
                      There may be as many -o options on the command line as necessary.

       -q             Force processing of mailagent's queue. Only the mails not tagged as skipped
                      by the -l option will be processed.

       -r file        Specify an alternate rule file.

       -s {umaryt}    Build a summary of all the statistics gathered so far. The  output  can  be
                      controlled  by  appending  one or more letters from the set {umaryt}. Using
                      -summary is a convenient way  to  get  the  whole  history  of  the  filter
                      actions.  The  u  modifier will print only used rules. The m will merge all
                      the statistics at the end while a reports the mode the filter was  in  when
                      the command was executed. The r asks for rule-based statistics and the y is
                      pretty useless and is here only to get a nice mnemonic  option.  Note  that
                      specifying  an option more than once has no effect whatsoever on the option
                      itself (i.e. you may put three Uu and only one m, but you'll still get  the
                      summary!).  The t letter may be followed by digits specifying how many rule
                      file versions relative to the topmost (most recent)  rule  file  we  should
                      extract from the statistics, that amount defaulting to 1: using -surat will
                      print a complete statistics report for the  last  version  of  your  rules,
                      while -surt12a would do the same for the last twelve versions of those same
                      rules.

       -t             Put mailagent in a special tracking mode where all  the  rule  matches  and
                      executed  actions are printed on the standard output. This is mostly useful
                      for  debugging  a  rule  file.  See  also  the  track  parameter   in   the
                      configuration file.

       -V             Print version number and exit.

       -U             Prevent  the UNIQUE and RECORD commands from rejecting an already processed
                      Message-ID the first time they are run on a given message.  This is  useful
                      when  processing  messages that have been dropped in the emergdir directory
                      due to some abnormal (but transient) condition and you  wish  to  reprocess
                      the message. Also see the -F switch if you are re-processing messages.

       If you invoke mailagent without options and without any arguments, the program waits for a
       mail on its standard input. If an argument is provided, it is the name of a  file  holding
       one  mail  to  be  processed.  This  is  the normal calling procedure from the filter, the
       argument being the location of the queued mail.

USING THE DEFAULT RULES

       If you do not want to use the filtering feature of mailagent, (NOTE: This may  cause  mail
       to  be  garbled  on  Debian systems, since mailagent can not lock the spol directory under
       Debian policy restrictions) then the default built-in  rules  will  be  used.   Those  are
       really  simple:  all  the  mails  are left in your mailbox and mails with a line "Subject:
       Command" anywhere in the message will be processed.  Commands  are  looked  for  on  lines
       starting with "@SH". The remaining of the line is then given to a shell for execution.

       Available  commands  are  read from a file (entry comfile in your configuration file), one
       command name per line. Only those listed there will be executed, others  will  produce  an
       error  message.  The  mailagent  traps  the exit status and will send an error report if a
       command fails (provided that the command does not issue a message by itself, in which case
       it should return a zero exit status).

       If you do not want to use the default rules, you may skip the remaining of this section.

   Configuring Help
       The  help  text  mailagent will send to people must be copied from Lib/mailagent/agenthelp
       into your own spool directory, as specified in your ~/.mailagent. Two macros may be used:

       =DEST=    This will be expanded to the sender's address (the one who  sent  you  the  mail
                 currently processed by mailagent).

       =MAXSIZE= This  stands  for  the  maximum  size  set before kit is used to send files back
                 (parameter maxsize in your ~/.mailagent file).

       You may use the default help file or design one that will give even more  details  to  the
       poor user.

   Distribution Files
       The  two files proglist and distribs held in Lib/mailagent describe the distributions your
       mailagent will be able to distribute.  The samples given  show  the  expected  syntax.  In
       order to clarify things, here is what the format should be:

       File  proglist  contains a small description for programs. The name of the program appears
       after a single star. It is followed by lines in free format. An optional three-dashes line
       separates  each  program's description. Note that a leading tab will be added to each line
       of description.

       The distribs file holds lines of the following form:

            progname version path archived compressed patches

       where:

       progname  is the program name (the same as the one mentioned in proglist).

       version   is the current version number. If none, a three-dashed line may be used.

       path      is the path where the distribution is stored. The ~ will be expanded  into  your
                 home  directory.  Note  that if the distribution is stored in archived form, the
                 path name is the one of the archive without the ending extension (which  may  be
                 .cpio.Z or .tar.Z).

       archived  is either y or n depending on whether the distribution is archived or not.

       compressed
                 is  either  y  or  n depending on whether the distribution is compressed or not.
                 This could be guessed from the extension's name,  but  we  must  think  of  file
                 systems with short names.

       patches   is  y or n depending on whether the distribution is maintained or not by you. If
                 you put a p, this means official patches are  available,  although  you  do  not
                 maintain  the  distribution.   Finally,  an o means that this is an old version,
                 where only patches are available, but maildist will  not  work.  In  that  case,
                 assuming  the  version  number  is  1.0,  old patches are expected in a bugs-1.0
                 directory.

       You may include comments in both files: all lines  starting  with  a  leading  #  will  be
       ignored.

   Testing Your Mail Agent
       It is now time to make sure your mailagent works. Send yourself the following mail:

            Subject: Command
            @SH mailhelp

       You  should  receive  back  a  mail  from yourself with the subject set to: "How to use my
       mailagent". If you don't, check the  file  ~/.bak  (or  whatever  file  you  set  in  your
       .forward).  If  it  is  empty,  look  at  the log file. If the log file is not empty, then
       perhaps the mail has been queued. Check the  sendmail  queue.  Also  make  sure  that  you
       removed  the  '#' comments in the filter script. On some systems, they cause some trouble.
       If you are using the C filter, maybe your sendmail is broken and you need to make your own
       setuid copy (or perl might complain that you have a kernel bug, etc...).

       If  you have done everything right but it still does not work properly, increase log level
       to 20 and resend your command mail. Then check the  log  file.  The  diagnosis  should  be
       easier.

       Once this works, you should check your distribs and proglist files by sending yourself the
       following mail:

            Subject: Command
            @SH maillist

       If the list you have in return is incorrect, then  your  distribution  files  are  wrongly
       written.  If  you  do  not  get  the  list,  there  is  a  problem  with  your mailagent's
       configuration. Retry with a log level set to 20 and look at the  issued  log  messages  in
       your  Log  directory.  Make  sure  that  the  file  listed  in  the  plsave  entry of your
       ~/.mailagent is correctly updated after a maillist has been run.

USING THE FILTER

       The mailagent can also be used as a filter: mail is parsed  and  some  actions  are  taken
       based  on  simple  lex-like  rules.  Actions  range  from  a  simple saving in a folder, a
       forwarding to another person, or even spawning of a shell command. Before  going  further,
       here is a small example of a valid rule file:

            From: root { FORWARD postmaster };
            To: gue@eiffel.fr { POST mail.gue };
            Subject: /metaconfig/ { SAVE dist };
            { SAVE incoming };

       There  are  three distinct rules. Rules are applied in sequence, until one matches (so the
       order is important). Any mail coming from root will be forwarded  to  user  postmaster.  A
       mail  addressed  to gue@eiffel.fr is a mail coming from a mailing list. The mail is posted
       on a local newsgroup mail.gue. Mails whose subject contains the word "metaconfig" will  be
       saved  in a folder dist for delayed reading and will not appear in the main mailbox. If no
       rule matched, the mail is left in the folder incoming.

   Rule File Syntax
       Here is a non-formal description of the rule file. Parsing of the file is done  lexically,
       hence  the  choice  of  non-ambiguous tokens like '{' or ';' which are easily parsed. This
       introduces some limitations which are silently applied: for instance, no '{' may  be  used
       as part of an address.

       Comments are introduced by a leading '#' , which must be on the left margin.  Unlike shell
       comments, a '#' which is not left justified will not be understood as a comment.  However,
       spaces or tabs are allowed in front of '#'.

       All  the  statements  in the rule file must end with a ';'. There are mainly four parts in
       each line. A list of comma separated modes, between '<' and '>', which  give  the  set  of
       modes  in  which  the rule applies. The special mode ALL will match everything. The filter
       begins in the mode INITIAL. Omitting the mode defaults to "<ALL>". It is possible to guard
       a rule against some specific mode by negating it, which is done by prefixing the mode with
       '!'.  Negated modes take precedence other plain modes,  meaning  "<!ALL>"  will  never  be
       matched, ever, and that "<MODE, !MODE>" is equivalent to "<!MODE>".

       Then  comes a list of selectors. Those selectors must be space separated and end with ':'.
       They represent the names of header fields which must  be  looked  at  by  the  forthcoming
       pattern. An empty selector list defaults to "Subject:".  Special selectors "All:", "Body:"
       and "Head:" apply to the whole message, its body or its header. A commonly  used  selector
       list  is  "To Cc:" which tests the recipient fields of the header. If the selector name is
       preceded by an exclamation mark '!', then the logical value of the test for that  selector
       is negated.

       The  list  of selectors may end with an optional range specification, given as <min, max>,
       before the final ':' character marking the end of the selector list. The  minimum  or  the
       maximum  may  be  given  as  '-', in which case it is replaced with the minimal or maximal
       possible value. Indices for selection begin at 1 (not 0), for  instance:  <3,  7>.  If  no
       range  selection  is  given, then the default <1, -> is used. Ranges normally select lines
       within the matching buffer, unless the selector is expecting  a  list  in  which  case  it
       operates  on  the  list  items.  For  instance,  Body  <3, 5>: would select lines #3 to #5
       (included) from the mail body, whereas To  Cc  <1,3>:  would  focus  on  the  first  three
       addresses  on  each  To: or Cc: header lines.  Negative values refer to that many lines or
       addresses back from the end, i.e.  Cc <-2,->: selects the last two addresses  on  the  Cc:
       line.   A  single number such as <2> is understood as <2, 2>, i.e. it select only one item
       in the list, <-> meaning everything (and being therefore redundant).

       The selector is then followed by a pattern within '/' or by a single name.   In  order  to
       ease  the  writing  of  the  rules,  the semantic of a single name varies depending on the
       selector  used.  For  the  special  selectors  "From:",  "To:",  "Cc:",  "Sender:",  their
       associated  "Resent-" fields, "Reply-To:", "Envelope:" and "Apparently-To:", a single name
       is understood as a match on the login name of the address. Note that if no "To:" field  is
       present  in  the  header,  one will be forged from the "Apparently-To:" for the purpose of
       filtering only (i.e. no physical modification on the header is done). If the login name of
       the  address  is  a  full  name of the form First.Last, only the last name is kept, and is
       lower-cased. If only a single name is  given,  only  shell  metacharacters  *  and  ?  are
       allowed, as well as intervals [].

       If  the  pattern is preceded by a single exclamation mark '!', then the matching status is
       negated (i.e. it will succeed if the pattern is not found).  If a single word is used  for
       non-special  selectors,  the same rules apply but the pattern is anchored at the beginning
       and the end for an exact match. With a pattern starting with '/', any  regular  expression
       understood by perl may be used and your pattern will not be modified in any way. The other
       special selector "Newsgroups:" works as "To:", excepted that newsgroups names are expected
       and  a  match is attempted on every item in the list. Every pattern match on a single name
       for an address-type field (i.e. "Newsgroups:"  excluded),  are  made  in  case-insensitive
       mode.  Otherwise, you can force a case-insensitive match by appending a trailing i option,
       as in /pattern/i.

       There is also a little magic involved when matching on an address field.  Namely,  if  the
       pattern  is not a single word and is anchored at the beginning, then only the address part
       of the field will be kept. For instance, if we have a From: field whose value  is  Raphael
       Manfredi  <ram@eiffel.com>,  then  the  pattern /Raphael/ would match, but not /^Raphael/.
       Instead, /^ram@.*$/ would match, but this is more easily done with a single  word  pattern
       ram,  for  it  only  focuses  on the login name of the address and would also match if the
       address was written  as  eiffel.com!ram.   A  single  address  in  Internet  form,  as  in
       ram@eiffel.com  is implicitely matching on the address part of the field, and you must not
       escape the '.' as you would have to in a regular expression.

       This may sound a little complex, but this design is meant to make things  easier  for  the
       user. Here are some other examples:

            # Match ram@eiffel.com as well as ram@educ.emse.fr.
            From: ram

            # Match root@eiffel.com, ram but not ribbon@eiffel.com
            From: r[oa]*

            # Match gue@eiffel.fr but not algue@eiffel.fr
            To Cc: /^gue@eiffel\.fr/

            # This will match gue@eiffel.fr as well as algue@eiffel.com
            To Cc: /gue@eiffel/

            # Match comp.lang.perl but not comp.lang.perl.poetry (?)
            Newsgroups: comp.lang.perl

            # Accept anything but messages coming from root
            From: !root

       When attempting a match on "To:", "Cc:" or "Apparently-To:", a list of addresses separated
       by a comma is expected, whereas only one address is expected after "From:".  If  you  omit
       the  pattern,  it  will  be  understood  as  * (recall that a single word uses shell meta-
       characters), which will match anything.

       Then comes the action to be taken when a match occurs. There are only  a  limited  set  of
       valid  actions  which  will  be  described soon in detail. The action is enclosed in curly
       braces '{' and '}' and actions are separated or terminated (depending on your taste) by  a
       ';'.  Action  names  are spelled in upper-case for readability, but case is irrelevant. If
       you want to put a ';' within the  rule,  it  must  be  escaped  by  preceding  it  with  a
       backslash.   A  double  backslash  is  translated  into a single one, and any other escape
       sequence involving the backslash character is ignored (i.e. \n would be kept verbatim).

       Note that a rule should be ended by a single ';' after the last '}'.  It  is  possible  to
       omit  this  final  ';',  but  that  single  token  is the re-synchronizing point for error
       recovery. One could argue however that there should be no syntax error, and thus  the  ';'
       ought to be safely omitted. Whenever in doubt, check your rule file with the -d option.

       Here  is  a  prototypical  rule  (using  perl  regular  expressions;  please  refer to the
       subsection Regular Expressions for more information):

            <ROOT> From: /^\w+@eiffel.com$/ { SAVE eiffel };

       That rule will only be taken into account when the filter is in the mode ROOT (recall that
       the  processing  starts  in  mode INITIAL; use BEGIN to change the mode, as in lex). So in
       mode ROOT, anything which comes from a user located in the eiffel.com  site  is  saved  in
       folder eiffel for deferred reading. The mail will not appear in the mailbox.

       It  is  possible  to  have  more  than  one  selection for a rule. Identical selectors are
       logically or'ed while different ones are and'ed. The selections are comma  separated.  For
       instance,

            From: root, To: ram, From: ram, Subject: /\btest\b/ { DELETE };

       will  delete  a  mail  from  root or ram if it is sent to ram and has the word test in its
       subject. It is also possible to write the previous rule as:

            From: root, ram, To: ram, Subject: /\btest\b/ { DELETE };

       because if no selector is given, the previous one is used (with the first  selector  being
       "Subject:" by default).

       Anywhere in the rule file, it is possible to define some variables. The list of recognized
       variables is given later. For now, let's say that maildir is the default folder directory.
       This  variable  is  used  by  the  SAVE command when the argument is not an absolute path.
       Setting

            maildir = ~/mail;

       will direct the filter to use ~/mail as the folder directory (default is ~/Mail). Note the
       ~ substitution and the final ';'. It is not possible (currently) to modify the environment
       by setting PATH for instance.

       Finally, there is a special construct to load patterns from a file. A pattern enclosed  in
       double  quotes  means  that  the patterns to be applied should be taken from the specified
       file. The file is expected to be in the directory mailfilter if it is not an absolute path
       (~ substitution occurs). If the variable is not set maildir will be used. If by chance (!)
       maildir is not set either, the home directory is used. The file should contain one pattern
       per line, shell comments (#) being allowed at the beginning of each line.

       An action may be followed by other rules. Hence the following is perfectly valid:

            From:
                 ram       { SAVE ram }
                 /plc/i         { SAVE plc }
                 root      { SAVE ~/admin }
                 /xyz/          { DELETE }
                 "users"        { LEAVE }
                 ;

       Note  the  use  of  the file inclusion: all the users listed in file users will have their
       mail left in the system mailbox. The usual rules apply for these loaded patterns.

   Selector Combination
       A single rule may have a various set of selectors. For instance, in the following rule:

            From: ram, To Cc: root, !Subject: /test/, From: raphael

       we have the following set { From, To Cc, !Subject }. The first two  selectors  are  called
       direct  selectors, !Subject: is called a negated selector.  The To Cc: selector is a group
       selector decomposing into two  direct  selectors,  while  From:  is  an  atomic  selector.
       Finally,  From:  is  also a selector with multiple occurrences. The value of a selector is
       its matching status logical value.

       Let D be the set of direct selectors and N the set of  negated  selectors,  which  form  a
       partition  of  R, the set of all the selectors in the rule. That is to say, R is the union
       of D and N, and D intersected with N is the empty set (trivial proof: a selector is either
       direct  or negated). If either D or N is empty, then it's not a partition but in that case
       we have either D = R or else N = R.

       Let's define the logical value of a set S as being the  logical  value  the  filter  would
       return  if  those rules were actually written.  Then the logical value of D is the logical
       value of each of its item with the AND logical operator distributed among them,  i.e.  the
       logical  value  of { a, b, c } is the value of (a AND b AND c). Let's write it AND(D). The
       logical value of each of the items is the logical value of the selector itself  if  it  is
       not  multiple,  or it is the logical value of all the occurrences of the multiple selector
       within the rule, with the logical OR operation distributed among them. That is to say,  in
       the above example, the value of From is true iff the From: fields contains ram OR raphael.
       Let's write that OR[From].

       To be sound, we have to apply De Morgan's Law on N, hence the following rules: the logical
       value  of  N  is  OR(N)  and  given a negated selector s, its logical value is AND[s]. And
       finally, the logical value of R is that of D AND N, with by convention having the  logical
       value of the empty set be true.

       For  those  who  do not know De Morgan's Law, here it is: given two logical propositions p
       and q, then the following identities occur:

            NOT (p AND q) <=> (NOT p) OR (NOT q)
            NOT (p OR q) <=> (NOT p) AND (NOT q)

       While we are in the logic of the propositions, note also that  OR  and  AND  are  mutually
       distributive, that is to say, given three logical propositions p, q and r, we have:

            p AND (q OR r) <=> (p AND q) OR (p AND r)
            p OR (q AND r) <=> (p OR q) AND (p OR r)

       To be complete, OR and AND are associative with themselves and commutative.  And the B set
       { 0, 1 } equipped with the set of operations (NOT, OR, AND) is an algebra (a Boolean one).
       I  will  spare  you  the  definition of an algebra, which really has nothing to do in this
       manual page (which is for a mail agent, in case you don't remember :-).

       The attentive reader will certainly have noted that I have not specified the logical value
       of  a  group  selector.  Well,  given a group selector G, we decompose it into a DG and NG
       partition, DG being the subset of (atomic) direct selectors of G and NG being  the  subset
       of  (atomic)  negated  selectors.   Then the logical value of DG is OR(DG) and the logical
       value of NG is AND(NG); the global logical value of G being that of DG  OR  NG.   In  case
       either  DG  or NG is empty, then we don't have a partition, but by convention the value of
       the empty set is false, and one of the sets is equal to  G.   Note  that  within  a  group
       selector, the rules are exactly the dual of the rules within R.

       Now the only rule which is not logical is whether a group selector belongs to D or N. I've
       chosen, for analogy reasons, to make the group selector belong to D if it does  not  start
       by  '!'  and  to  N  otherwise. That is, !To Cc: belongs to N whilst Cc !To: belongs to D.
       Apart from that, order within the group selector is irrelevant: To Cc: is equivalent to Cc
       To:, so the behavior in the quotient set is sound.

       Here are some examples:

            # Match anything: (not from ram OR not from root) is always true.
            From: !ram, !root

            # Match anything but reject mails coming from ram OR root
            !From: ram, root

            # Reject mails whose headers matching /^Re.*/ contain the word test
            !^Re.*: /\btest\b/

            # Keep mails whose subject contains test AND host
            !Subject: !/test/, !/host/

            # Matches if ram is listed in the To OR the Cc line
            To Cc: ram

   Minimal Header
       A  minimal  set  of selectors are guaranteed to be set, regardless of the actual header of
       the message. This is for  the  purpose  of  filtering  only,  no  physical  alteration  is
       performed.

       Envelope: This  is the address found in the mail envelope, i.e. the address where the mail
                 seems to originate from. This can be different from the From: address  field  if
                 the mail originates from a trusted user, in sendmail's terminology. If you don't
                 know what that is, simply ignore it.
       From:     User who wrote the mail. If this line is missing, uses the address found in  the
                 first From line.
       Length:   The  physical  length  of the body, in bytes, once content-transfer-encoding (if
                 any) has been removed.
       Lines:    The amount of lines in the body (decoded, if necessary).
       To:       The main recipient(s) of the message. If this line  is  missing  but  a  set  of
                 Apparently-To: lines is found, then those addresses are used instead. If no such
                 line exists, then assume the mail was  directed  to  the  user  (which  seems  a
                 reasonable assumption :-).
       Sender:   User  who  sent  the mail. This may differ from the From: line. If no such field
                 exists, then the address in the first From line is used (mail envelope).
       Relayed:  This computed header is a comma-separated  list  of  all  the  hosts  where  the
                 message  was  relayed,  in the proper transmission order. Each item in this list
                 can  be  a  machine  name  such  as  mail.hp.com  or  an  IP  address  such   as
                 [15.125.38.12].  The  list  is  derived  from the Received: lines present in the
                 message.
       Reply-To: Where any reply should be sent. If no  Reply-To:  field  is  present,  then  the
                 Return-Path  is  used  (with  <>  stripped  out), or the From: line is parsed to
                 extract the e-mail address of the author.

   Variables
       The mailagent supports user-defined variables, which are globals. They  are  set  via  the
       ASSIGN  command  and  referred to with the %# macro. Assuming we set a variable host, then
       %#host would be replaced by the actual value of the variable. This enables  some  variable
       propagation across the rules.

       For  example, let's say the user receives cron outputs from various machines and wishes to
       save them on a per-machine basis, differentiating between daily outputs and  weekly  ones.
       Here is a solution:

            Subject: /output for host (\w+)/   { ASSIGN host '%1'; REJECT };
            Subject: /^Daily output/ { SAVE %#host/daily.%D };
            Subject: /^Weekly output/     { SAVE %#host/weekly.%m-%d };

       Besides  variable  interpolation  via  the  %#  escape,  it  is  also  possible to perform
       substitutions and translations on the content of a variable (or a back-reference,  i.e.  a
       number between 1 and 99). The two commands SUBST and TR will respectively perform in-place
       substitutions and translations. In that case however, the name of  the  variable  must  be
       preceded  by  a  single  #. This differentiates the back-reference 1 from the variable #1,
       although 1 is a funny name for a variable. The need for # also prevents the common mistake
       of  writing %#, as mailagent will loudly complain if the first parameter of SUBST or TR is
       not a digit between 1 and 99 or does not start with a #.

       Here are some actions to canonicalize the host name into lower case  and  strip  down  the
       domain name, if any:

            { TR #host /A-Z/a-z/; SUBST #host /^([^.]*)\..*/$1/ };

       Those  actions  are  directly  translated into their perl equivalent, and any error in the
       specification of the regular expression will be reported.

       If the variable name begins with a colon ':', then the variable is made  persistent.  That
       is  to  say it will keep its value across different mailagent invocations. The variable is
       simply stored (with the leading ':' removed) in mailagent's database and is  thus  subject
       to the aging policy set up in the ~/.mailagent.

       Within  PERL  commands  or  mail  hooks  using  perl (see the MAIL HOOKS section), you can
       manipulate those (so-called) external variables via a set of interface  functions  located
       in  the  extern  package  (i.e. you must prefix each of the function name with its package
       name, set becoming extern'set). The following three interface functions are provided:

       val(name) Return the value of the variable name (the leading ':' is not part of the  name,
                 in any of these three interface functions).

       set(name, value)
                 Set  the  external variable name to hold value. No interpretation is done by the
                 function on the actual content of the value you are providing.

       age(name) Returns the age of the variable, i.e. the elapsed time in seconds since the last
                 modification made by set.

       There  is currently no way for erasing a variable from the database. But if you do not use
       the variable any more, it will be removed when its age becomes greater  than  the  maximum
       age specified by the agemax configuration variable.

   Regular Expressions
       All  the  regular  expressions  follow  the  V8  syntax,  as  in  perl,  with all the perl
       extensions. If a bracketing construct (...) is used inside a rule, then the  %digit  macro
       matches  the  digit's  substring  held  inside  the bracket. All those back-references are
       memorized on a per-rule basis, numbered from left to right. However, great  care  must  be
       taken  when  using a back-reference in multiply present selectors, as all the matches will
       be performed up-to the first match, and back-references are  computed  on  the  fly  while
       doing pattern matching.

       For instance:

            To: /(.*)/, Subject: /Output from (\w+)/ { ASSIGN to '%1'; SAVE %2 };

       will  save  the  To: field in variable 'to' and save the mail in a folder derived from the
       host name specified in the subject. However, if we say:

            Subject: /host (\w+)/, /from (\w+)/ { ASSIGN match '%1' };

       then there will be only one back-reference set, and it will come from  the  first  pattern
       matching  if  it succeeds, or from the second. Should the second or the first pattern have
       no bracketing construct and still match, then the back-reference would not be recorded  at
       all, which means the following is probably not what you want:

            Subject: /from/, /host (\w+)/, To: /(.*)/ { SAVE %1; REJECT };

       as  if  the  /from/  pattern  matches  then  /host  (\w+)/  will not be checked (identical
       selectors are or'ed and that is optimized), then %1 would refer to the To:  field  whereas
       if /host (\w+)/ matches, then %1 will be the host name.

       However,  this  behavior  can  be  used to selectively store a news article which has been
       mailed to you in a folder whose name is the newsgroup name in dot form. Assuming  we  want
       to give priority to comp.lang.perl, we could say:

            Newsgroups:
                 /(comp.lang.perl)/,
                 /(comp.mail.mh)/,
                 /(comp.compilers)/,
                 /([^,]*)/      { SAVE %1 };

       An  article  cross-posted  to  both  comp.lang.perl  and  comp.mail.mh would be saved in a
       comp.lang.perl folder, since this is what would match first.  The last rules takes care of
       other articles: the folder used being whatever newsgroup appears first.

       There  is  also  a  special  macro  %&,  which lists (it's a comma separated list) all the
       selectors specified via a regular expression which indeed matched.  For instance:

            Re.*: /york/        { ASSIGN which '%&' };

       would assign to which the list of  all  the  fields  matching  the  /Re.*/  pattern  which
       contained  'york',  be  it  a  Received:  field or a Resent-From: field (as both match the
       selector specification). Assuming both those fields contained the word york, the value  of
       %& would be 'Received,Resent-From;' (the fields are alphabetically sorted).

       Should  you have more than one such specified selector within a single rule, then it might
       be worth knowing that all the set of matching selectors are recorded within %&,  each  set
       terminated  with  a ';'. If a negated selector is used, then %& will record all the fields
       which did not contain the pattern, assuming the selection succeeded (otherwise nothing  is
       recorded).

   Available Actions
       The following actions are available as filtering commands. Case is irrelevant although the
       recommended style is to spell them upper-cased. As explained later, most  of  the  actions
       record  their  exit  status  in  a  special variable which may be tested via the -t and -f
       options of ABORT, REJECT and RESTART. For every command returning such an exit status, the
       failure  or  success  conditions  are  given at the end of each description. If nothing is
       specified, then the command does not return a meaningful status.

       ABORT [-tf] [mode]
                 Abort application of filtering rules immediately. See REJECT for the meaning  of
                 the optional parameters. (Does not modify existing status)

       AFTER [-sanc] (time) action
                 Records a callback for after the specified time, where action will be performed.
                 By default, a mailagent filtering action is assumed (-a option), on the  current
                 mail  message.  A shell command (-c) may be given instead, receiving the current
                 mail message as standard input. Finally, a plain shell command may be run  (with
                 no  input) using the -s option.  The option -n may be used when the current mail
                 message does not need to be kept for input. For instance:

                      AFTER -an (1 day) DO ~/process:proc'run(%u)

                 would call proc'run defined in the ~/process file in one day from  now,  without
                 giving any input (the action here does not require any).

                 When  running  mailagent commands, the initial working mode is set to _CALLOUT_.
                 This may matter if you call APPLY for instance. If the recorded time is less  or
                 equal  than  the  current  time  (which  is  now),  the callback will occur when
                 mailagent is done with the messages in its queue, before  exiting.  This  allows
                 for the following cute trick, found out by Randal Schwartz:

                      AFTER (now)         # fork a copy I can mangle
                           STRIP Reply-To \; RESYNC \;
                           ANNOTATE -du Reply-To %2 \; RESYNC \;
                           NOTIFY message %r \; DELETE \;
                           ;

                 Note  that  the command is not called AT because the call will only be performed
                 at the next mailagent invocation after the specified time has elapsed. Dates are
                 specified  using  the  same format as in SELECT.  (Fails if the action cannot be
                 recorded in the callout queue).

       ANNOTATE [-du] field value
                 Annotate message by adding field into the mail header, with the supplied  value.
                 This  is like the MH command anno, but the annotation is performed at the end of
                 the header, whereas MH does it at the top. Normally, an extra  field  is  added,
                 with the current date as field value.

                 This  can  be  suppressed  by using the -d option. If value is omitted, only the
                 date field is generated (hence it is an error  to  use  the  -d  option  without
                 supplying a value). As with all the commands which alter the header, a RESYNC is
                 necessary for the filter part to actually see the new header.

                 The -u option means "unique",  and  prevents  ANNOTATE  from  executing  if  the
                 specified field is already present in the header. Don't forget to RESYNC between
                 successive ANNOTATE commands using this option if the field refers to a previous
                 ANNOTATE target.  (Fails when no annotation takes place)

       APPLY rulefile
                 Get  the  rules  held  in  rulefile  and apply them to the current message.  The
                 filter will begin in whatever mode you were when using this command, but no feed
                 back  will  occur,  i.e.  any mode changing will be lost when returning from the
                 command.

                 Variables (see the %# macro)  are  propagated  back  and  forth  through  APPLY,
                 meaning  you see variables set by the caller, and you may change their values or
                 create new variables for the caller to later use.

                 If mail is saved during the application of the  rules,  then  the  corresponding
                 flag is set in the main filter (the one that started the APPLY command). You may
                 nest them, of course.  (Fails if  mail  is  not  saved  by  the  rules  held  in
                 rulefile)

       ASSIGN var value
                 Assign the value to the user-defined variable var, which may further be accessed
                 as '%#var' for macro substitution or #var in the TR and SUBST commands in  place
                 of  the  variable name. Note that there is no leading # in front of the variable
                 name. The value you provide is first ran through perl to see if it contains some
                 arithmetic  operations.  If the evaluation is successful, the resulting value is
                 used instead. If an error occurs in this evaluation process,  then  the  literal
                 value  provided  is  used.   To  avoid the evaluation, you may enclose the whole
                 value in simple quotes. Those will be trimmed before the assignment takes place.
                 If  you  actually want simple quotes in the first AND last position, you have to
                 double each of them.  (Does not modify existing status)

       BACK command
                 Execute command and take its output as new actions to be performed on  the  mail
                 (hence  performing  something  analogous to `command` in shell).  If there is no
                 output, nothing is done. BACK commands can be nested, although this may lead  to
                 surprises  this  manpage  will  not disclose (but I assure you it will be funny,
                 assuming we have the same sense of humor... :-). Note  that  both  the  standard
                 output and the standard error from the command are used.

                 If  the  command  fails,  the output is mailed back to the user and no action is
                 performed. Furthermore, normal feedback does not occur here: any output from the
                 command  is  taken  as  filter  actions,  which means the semantics of PASS, for
                 instance, is changed: we do not take a body back but commands.   (The  execution
                 status is that of the command)

       BEEP [-l] count
                 This command may be used to tune the amount of beeps emitted when biffing on the
                 terminal, for each %a expansion. By default, that amount is set to 1.  Using the
                 -l  option  alters  the beep count locally for the rule.  Otherwise, the default
                 amount is changed.

                 Note that this simply expands %a into the suitable amount of Ctrl-G  characters.
                 Your terminal must be allowed to issue consecutive bells for this to work.  Very
                 often, terminals are configured so that the first bell received disables further
                 beeps  for  some  period,  to  avoid  cascades  of  bells.  If you use xterm for
                 instance, you should use:

                      xterm -xrm "XTerm*BellSuppressTime: 0"

                 to enable consecutive bells. Otherwise, xterm will swallow them during  200  ms,
                 hence  making  the  BEEP  command  ineffective,  apparently.   (Does  not modify
                 existing status)

       BEGIN [-ft] state
                 Enter a new state. An explicit REJECT or  RESTART  is  necessary  to  abort  the
                 processing  of the current rule. The processing begins in the state INITIAL.  If
                 the -f (resp. -t) flag is specified, then the state change only  occurs  if  the
                 last  command  status  indicated  a failure (resp. a success).  A state name can
                 contain alphanumeric characters and  underscores.   (Does  not  modify  existing
                 status)

       BIFF [-l] on|off|path
                 Allow  or  disallow  biffing  dynamically.  When  biffing  is  turned on via the
                 configuration file or via this command, a message is  printed  on  some  of  the
                 terminals where the user is logged when mail is received, as explained under the
                 section MAIL BIFFING.

                 Instead of on or off, you can specify a file name (~ substitution allowed) being
                 the new path to be used for the biffing format template.

                 If you use the -l option, changes are made locally, for the duration of the rule
                 only. If you REJECT to go to some other rule, your changes  will  be  lost.  The
                 global  value  of the altered parameters is changed on the first local usage and
                 restored when a new rule is entered.  (Does not alter execution status)

       BOUNCE address(es)
                 Bounce the message to the specified address(es) and acts as if a save  had  been
                 done. The only difference with FORWARD is that no Resent-like lines are added to
                 the header. If an address is specified in double quotes, it is taken as the name
                 of  a  file  to be loaded to get addresses (one address per line, shell comments
                 (#) allowed). The file name resolving is the same as the one  used  for  pattern
                 loading.  (Fails if mail cannot be resent)

       DO routine [(arg1, arg2, ... , argn)]
                 Calls  the  perl routine, with the supplied arguments if any. This is a very low
                 level hook into mailagent's internal. The routine can  be  specified  by  itself
                 (package'name,  package  being main by default), or identified by a leading tag,
                 followed by a ':', then the routine name as before. The tag can be a path  to  a
                 file  where the routine is defined, or a command name (for user-defined commands
                 which are loaded dynamically). For instance

                      DO UNKIT:newcmd'unkit('true')

                 would lookup the user-defined UNKIT command, load the file where it  is  defined
                 (in  the  newcmd  package),  then call the routine with 'true' as argument.  The
                 package specified determines where the  loading  is  done,  so  be  sure  it  is
                 consistent with the definition in the file where the routine is defined.  (Fails
                 if the routine cannot be located and executed)

       DELETE    Delete the current message. Actually, this does not do anything, it  just  marks
                 the  mail as saved. If no further action involving saving is done, then the mail
                 will never show up in the mailbox.  (Never fails)

       FEED [-be] program
                 Feed the whole message to a program and get the output back as the new  message.
                 Hence  the  program  appears as a filter for the whole message.  It does not tag
                 the message as having been saved.  A RESYNC is automatically done  upon  return.
                 (Returns the status of program)

                 WARNING:  Your  program  must  be able to properly parse a MIME message and must
                 deal with transfer-encoded bodies by itself.  To make the program task  simpler,
                 you  can supply the -b switch which will let mailagent decode the whole body for
                 you, suppressing any Content-Transfer-Encoding header (implying "binary").  This
                 is  an  invalid  message format for sending the message, but it makes processing
                 easier.  You still have to parse the MIME parts yourself though.

                 Using -b does not prevent your program from outputing a valid message back,  one
                 that  can be possibly sent on the network so you have two options: either you do
                 not supply any Content-Transfer-Encoding in  the  headers,  and  mailagent  will
                 recode  the  body  for  you  using  the initial transfer encoding present in the
                 message (a relatively safe option if you make only changes in the body at  well-
                 defined  spots  without introducing 8-bit chars), or you can supply the Content-
                 Transfer-Encoding yourself and perform the body encoding manually.

                 To be completely safe and minimize the work in your program, the -e switch  will
                 let  mailagent  analyse the message body you are returning and select the proper
                 transfer encoding automatically.  Since this will cause the  whole  body  to  be
                 analysed,  and  it  can  be  potentially huge, that behaviour must be explicitly
                 asked for. If you need -e then you probably want -b as well (you can supply both
                 by saying -be naturally).

                 If  you  do not supply any switch, mailagent will give you the message as-is and
                 will get your message as-is without any additional magic.

       FORWARD address(es)
                 Forward mail to the specified address(es). This acts as if a save had been done,
                 in  order  to avoid the DELETE. Usually when you forward a mail, you do not wish
                 to keep it. The command adds Resent-like lines in the  header.  As  for  BOUNCE,
                 file inclusion is possible (i.e. use an address "forward_list" to forward a mail
                 to all the users listed in the file forward_list).  (Fails  if  mail  cannot  be
                 resent)

       GIVE program
                 Give  the  body  of the message to the specified program by feeding its standard
                 input. Any output is mailed to the user who runs the mailagent.  Note  that  the
                 message is not tagged as having been saved.  (Returns the status of program)

                 NOTE: If the message had a body that was encoded for transport (using one of the
                 base64 or quoted-printable  transfer  encoding),  mailagent  will  transparently
                 decode  it  and  supply a version that can be properly handled.  In other words,
                 the program does not need to care about the body being encoded in  the  message,
                 as  it  will  get  a plain one. (Since no headers are supplied, this is the only
                 possible option).

                 Caution though for MIME messages: you should use PIPE for them to give a  chance
                 to  the program to properly handle the body, but then it needs to be fully MIME-
                 aware.

       KEEP header_fields_list
                 Keeps only the corresponding lines in the header of the mail.  For  instance,  a
                 "KEEP  From  To  Cc  Subject"  will keep only the principal fields from the mail
                 message. This is suitable for archiving mailing lists messages.  You may  add  a
                 ':'  after  each  header  field  name  if  you  wish,  but  that is not strictly
                 necessary. Headers may be specified using shell-style regular  expressions,  and
                 file inclusion is allowed to get headers from a file.  (Does not modify existing
                 status)

       LEAVE     Leave incoming mail in the system mailbox. This is the default action if no rule
                 matched  or  if  no  saving occurred. This is not recommended on Debian systems.
                 (Fails if mail cannot be saved)

       MACRO [-rdp] name [= (value, type)]
                 Lets you specify user-defined macros, of the form %-(name). See the paragraph on
                 user-defined  macros  for  explanation  about the available types (SCALAR, EXPR,
                 CONST, FN, PROG, PROGC).  A perl interface to  the  underlying  user  macros  is
                 available  for  your perl commands. The -r option is used to replace an existing
                 macro (instead of pushing a new instance on the stack), the -d is to delete  all
                 the  instances of a named macro (in that case it takes only the first argument),
                 and -p pops the last instance of the macro from the stack  and  reverts  to  the
                 previous definition, if any (otherwise, it acts as -d).  If you wish to define a
                 simple SCALAR macro, you may omit the = (value, type) part and  simply  continue
                 with the macro value.  (Does not modify existing status)

       MESSAGE file
                 Send  message file back to the sender of the message (as derived from the header
                 of the message). The text of the message is run through the  macro  substitution
                 mechanism (described later on).  (Fails if message cannot be sent)

       NOP [-ft] No  operation.  If this seems a bit odd, think of it in terms of a ONCE command.
                 (Does not alter existing status unless -f or -t is used, in which case it forces
                 a false --failure-- or true success status)

       NOTIFY file address(es)
                 Send  a  notification  message  file  to  a  given address list. The text of the
                 message is run through the macro substitution mechanism  (described  later  on).
                 As  with  FORWARD, file inclusion for address specification is possible.  (Fails
                 if message cannot be sent)

       ON (day list) command
                 Execute the specified filter command only on the specified day list.  That  list
                 is  a  space-separated list of days, specified using the English names. Only the
                 first three characters are taken into  account,  case-insensitively.  Therefore,
                 the shortest valid day specifications are Mon, Tue, Wed, Thu, Fri, Sat and Sun.

                 This  command  can be used in conjunction with SELECT to do time-based selective
                 bouncing of messages to, for instance, your home address:

                      ON (Mon Tue Wed Thu) SELECT (18:30 .. 23:00) BOUNCE me@home.net;
                      ON (Fri) SELECT (18:30 .. 23:59) BOUNCE me@home.net;
                      ON (Sat Sun) BOUNCE me@home.net;

                 That would bounce messages only on week-ends and during the week,  after  18:30,
                 and  until  23:00 (assuming that's bed time, other messages will be seen at work
                 the next day). Note that on Fridays, we go as far as 23:59.  (Propagates  status
                 from command. If the command is not executed, always return success)

       ONCE (name, tag, period) command
                 Execute  the  specified  filter command once per period. The name and tag fields
                 are used to record timestamps of the last ONCE command.   More  on  this  later.
                 (Propagates  status  from command. If the command is not executed, always return
                 success)

       PASS program
                 Feed the body of the message to the specified program and get a  new  body  back
                 from  the  output of the program.  Note that the message is not tagged as having
                 been saved.  (Returns the status of program)

                 NOTE: If the message had a body that was encoded for transport (using one of the
                 base64  or  quoted-printable  transfer  encoding),  mailagent will transparently
                 decode it and supply a version that can be properly handled.  The body generated
                 by  the  program will then be automatically encoded back using the same transfer
                 encoding.

                 Caution though for MIME messages: you should use FEED for them to give a  chance
                 to  the program to properly handle the body, but then it needs to be fully MIME-
                 aware.

       PERL script [arguments]
                 Escape to a perl script to perform some actions on the message.  This  is  fully
                 described  further  in the manpage, and is very different from a RUN perl script
                 command. (Returns failure if the script did not compile or returned  a  non-zero
                 status).

       PIPE [-b] program
                 Pipe  the  whole message to the specified program, but do not get anything back.
                 Any output is mailed to the user who runs the mailagent.   The  message  is  not
                 tagged  as  having  been  saved in any case, so you must explicitly DELETE it if
                 piping was enough and it did not fail: "REJECT -f" is your friend here to  avoid
                 unwanted deletion.  (Returns the status of program)

                 WARNING:  Your  program  must  be able to properly parse a MIME message and must
                 deal with transfer-encoded bodies by itself.  To make the program task  simpler,
                 you  can supply the -b switch which will let mailagent decode the whole body for
                 you, suppressing any Content-Transfer-Encoding header (implying "binary").  This
                 is  an  invalid  message format for sending the message, but it makes processing
                 easier.  You still have to parse the MIME parts yourself though.

       POST [-lb] newsgroup(s)
                 Post the message to the  specified  newsgroup(s)  after  having  cleaned-up  the
                 header:  mail-related fields like Received: or In-Reply-To: are removed, a valid
                 From: line is generated, the original To: and Cc: are renamed with an X- prefix,
                 the  References:  line  is  updated/generated if necessary based on existing In-
                 Reply-To, and NNTP-specific fields are stripped so that the server can  add  its
                 own.

                 Running POST successfully acts as a saving.

                 If  the  first  name  is  -l as in "POST -l comp.mail.mh", then a "Distribution:
                 local" header is added to force a local delivery.  Otherwise, the default  inews
                 distribution will be used (world, usually).

                 When  the  -b  switch  is  given, a successful POST will result in biffing being
                 activated (see section MAIL BIFFING) for the resulting news article.

                 If more than one newsgroup is specified, they should be space separated.  It  is
                 possible  to  get a newsgroup list via file inclusion.  (Fails if message cannot
                 be posted)

       PROCESS   Run the mailagent processing which looks for @SH  commands  and  executes  them.
                 This was described before in the section dealing with default rules.  The action
                 associated by default to a mail having [Cc]ommand as  its  subject  is  PROCESS.
                 (Always returns success)

       PROTECT [-lu] mode
                 Sets  the  default  protection  mode  that  should be set on created folders (or
                 created files when saving into  an  MH  folder  or  a  directory).  By  default,
                 permissions  are  governed  by the UMASK command, but this lets you override the
                 default. The specified mode should be preceded by a 0 as in  0644  to  give  the
                 familiar octal permissions. Otherwise, it is interpreted as a decimal number, so
                 beware!

                 The -l option may be used to specify a mode locally for  one  rule.   Otherwise,
                 the  protection  mode is set globally. The -u option unsets the global (or local
                 when combined with -l) mode, reverting to the default behaviour where  only  the
                 umask is taken into account by the system.

                 Note  that  when  saving into an MH folder, the PROTECT command takes precedence
                 over the Msg-Protect field  from  your  ~/.mh_profile  file.   (Does  not  alter
                 execution status)

       PURIFY program
                 Feed  the  header  into  a  program  and  get  new  header  back. RESYNC is done
                 automatically upon return.  This may be used to  indeed  purify  the  header  by
                 removing  all  the  verbose  stuff added by so many mail transport agents (X-400
                 like lines for instance).  Obviously, this does not flag the message  as  having
                 been saved.  (Returns the status of program)

                 If  your program removes the Content-Transfer-Encoding header in a MIME message,
                 mailagent will properly transform the message to have a  non-encoded  body.   If
                 you  change  the  value  of the Content-Transfer-Encoding header, mailagent will
                 also correctly recode the body for you.  The only supported encodings are base64
                 and quoted-printable.

       QUEUE     Queue  mail  again. A successful queuing counts as if mail has been saved.  Mail
                 queued that way will not be processed during the  next  30  minutes.  Note  that
                 unless  mailagent is invoked on a regular basis by cron, the mail will remain in
                 the queue until another mail arrives.  (Fails when mail cannot be queued)

       RECORD [-acr] [state] [(tag-list)]
                 Record message in the history and enters state _SEEN_ if the message was already
                 present  there.  If  the  message  is  recorded  for  the first time, processing
                 continues normally. Otherwise a  REJECT  is  performed.  This  behavior  may  be
                 somewhat  modified  by using some options. See UNIQUE for a complete description
                 of the options and  arguments.  Naturally,  when  a  state  is  specified,  that
                 overrides  the default _SEEN_.  A state name can contain alphanumeric characters
                 and underscores.

                 When a tag-list (comma-separated list of names) is  specified,  the  message  is
                 only  recorded and checked against all those tags, but only them. Not specifying
                 any tag list means any occurrence, whether it is tagged or not.   See  paragraph
                 Using Tags in Record and Unique for more information.  (Returns a failure status
                 if mail was already recorded)

       REJECT [-tf] [state]
                 Abort execution of current action, and continue matching. If  -t  is  specified,
                 the  reject  will  occur  only if the previous action was successfully completed
                 (return status of true), whilst -f would cause the reject only  when  a  failure
                 occurred.  If a state is specified, we enter that state before rejection. REJECT
                 resets the matching flag, which means that  if  no  further  match  occurs,  the
                 default action will apply.  A state name can contain alphanumeric characters and
                 underscores.  (Does not alter execution status)

       REQUIRE file [package]
                 Behaves like the perl require operator by loading a perl file  into  memory.  By
                 default,  the  file  is read in the newcmd package, but you may specify whatever
                 package you wish to load it in. This command will only perform the loading  once
                 per  (file,  package) tuple. Unlike its perl equivalent, the file "value" is not
                 important, i.e. it does not have to end with a statement returning a true value.
                 (Fails if file cannot be loaded)

       RESTART [-tf] [state]
                 Abort  execution  of  current  action  and restart the matching process from the
                 beginning. To avoid loops, each rule may be  walked  through  once  in  a  given
                 state. See REJECT for the meaning of the optional parameters. RESTART resets the
                 matching flag, which means that the default action will apply, should no further
                 match occur.  (Does not alter execution status)

       RESYNC    Re-synchronize  header  used  for  matching with the header of the mail. This is
                 probably useful only when a SUBST or ANNOTATE command was run.  (Does not  alter
                 execution status)

                 NOTE: At RESYNC time, mailagent will check whether the Content-Transfer-Encoding
                 header was changed and will transparently recode the body if required,  so  that
                 the  whole message remains valid despite header mangling. It will also take care
                 of updating Content-Length if required.  Whenever you do change these  important
                 headers  via  SUBST  or ANNOTATE, be sure to call RESYNC before disposing of the
                 message or you run the risk of saving a  corrupted  version  that  will  not  be
                 properly understood by your mail user agent.

       RUN program
                 Run  the  specified  program and mail any output to the user who runs mailagent.
                 This action does not flag the message as having been saved.  (Returns the status
                 of program)

       SAVE folder
                 Save  message  in  the specified folder. If folder name starts with a '+', it is
                 handled as an MH-style folder and rcvstore is emulated to  deliver  the  message
                 into  that  folder.  If  folder is a directory, message is delivered in a single
                 file within that directory. See the FOLDERS section.  (Fails if  message  cannot
                 be saved)

       SELECT (start .. end) command
                 Execute  the command only within the time selection period specified.  Dates can
                 be specified in a wide range of formats. The output of the date(1) command is an
                 example of a valid specification. If the date, the year or the month is missing,
                 then the current one is substituted in place of  it.  The  following  dates  are
                 valid  specifications:  '10:04:25',  'now'  ,'April  1 1992', 'Dec 25', 'July 14
                 1789, 07:40' (err... it's valid according to the grammar, but  it's  before  the
                 Epoch  so  it  does  not  mean anything). Other fancy dates like 'last month - 5
                 minutes' or '3 weeks ago' are also enabled.  (Isn't that great to  have  a  real
                 parser?  The filtering rules could have been more elaborated if only I had known
                 about this Berkeley yacc producing a perl parser...).  (Returns  the  status  of
                 command, if run, otherwise returns true).

       SERVER [-t] [-d disabled commands]
                 Activate  server processing. The body of the message is interpreted as a list of
                 commands to execute. See section GENERIC MAIL SERVER for more information  about
                 the  server  itself.  The  -t  option  turns the server into trusted mode, where
                 powers may be gained. The -d option must be  followed  by  a  list  of  disabled
                 commands, separated by commas with no intervening spaces between them.

       SPLIT [-adeiw] folder
                 Split a mail in digest format into the specified folder (same naming conventions
                 as in SAVE). If no folder is specified, each digest item is queued and  will  be
                 analyzed  as  a  single mail by itself. The -d option deletes the digest header.
                 The -i option means split is done in-place and the original mail  is  discarded.
                 All  the  options may be used simultaneously provided they are stuck together at
                 the beginning (option parsing being really rudimentary).

                 If the mail is not in digest format and a folder is specified, then it is  saved
                 in that folder. Otherwise, the SPLIT action fails and nothing occurs (the filter
                 continues its processing though). The SPLIT command will correctly burst RFC-934
                 digest  messages  and  will  try to do its best otherwise. If the digest was not
                 RFC-934 compliant and there is a chance  SPLIT  might  have  produced  something
                 incorrect,  then  the  original message is also saved if -i, otherwise it is not
                 tagged as saved (so that the default LEAVE command may apply).  The  -w  (watch)
                 requests  special  care  and will detect every non RFC-934 digest, even when the
                 non-compliance is otherwise harmless; furthermore, any trailing  garbage  longer
                 that 100 bytes will be saved as a digest item by itself.

                 The  -a  option  annotates  every  digest item with an X-Digest-To: header line,
                 which is the concatenation of the To: and Cc:  fields  of  the  original  digest
                 message.  This  may  be used for instance to burst the digest into the queue and
                 then re-process each of its items according to this added field.   Finally,  the
                 -e  option  will  discard  the digest header only if its body is empty (i.e. the
                 moderator did not include any leading comment).  (Returns success if mail was in
                 digest format and correctly split without any error)

       STORE folder
                 Save  message  in  the  specified folder and leave a copy in the system mailbox.
                 The folder parameter follows the same naming  conventions  as  in  SAVE.  Again,
                 because  of  locking  issues,  leaving mail in the mailbox is not recommended on
                 Debian machines.  (Fails if message cannot be saved either in the folder  or  in
                 the mailbox)

       STRIP header_fields_list
                 Remove the corresponding lines in the header of the mail. For instance, a "STRIP
                 Newsgroups Apparently-To" will remove the appropriate  lines  to  wipe  out  any
                 Newsgroups:  or Apparently-To: header. You may add a ':' after each header field
                 name if you wish, but that is not strictly necessary. Headers may  be  specified
                 via  shell-style  regular  expressions or via "file" inclusion.  (Does not alter
                 execution status)

       SUBST var/header expression
                 Substitutes the expression on the specified user-defined variable (name starting
                 with  a  #)  or  back-reference (digit), or header field (optionally ending with
                 ':').  For instance

                      SUBST #foo /w/y/g

                 would substitute in user-defined variable foo all the w by y.  See  also  ASSIGN
                 and TR.

                 For substitutions on header fields, like:

                      SUBST Subject: /\[foo\]\s+//;

                 matching  header  lines will be reformatted when the substitution is successful,
                 which likely means original continuations will not be preserved.  The target  of
                 the  substitution  is  the  whole  header,  with continuations normalized to one
                 space.  You are therefore guaranteed to be independent from  the  actual  header
                 formatting in the original.

                 Do  not forget to issue a RESYNC after a header field SUBST, since some routines
                 (like POST) probe into the parsed  header  hash  table  to  generate  the  saved
                 message.

                 (Fails if error in expression)

       TR var/header translation
                 Perform  the  translation  on  the  specified variable, back-reference or header
                 field. For instance

                      TR 1 /A-Z/a-z/

                 would  canonicalize  content  of  reference  1  into  lowercase.    Successfully
                 transliterated  headers  are  reformatted,  even  when their overall size is not
                 changed.  See also ASSIGN and SUBST.  (Fails if error in translation)

       UMASK [-l] mode
                 Changes the process's umask to the specified mode, which can be  decimal,  octal
                 (if  preceded by '0') or hexadecimal (starting with '0x'). The octal notation is
                 the clearest way to specify the umask anyway. Aren't rumors  saying  that  octal
                 was  invented  for  that purpose only? ;-) Use the -l option to change the umask
                 for the duration of the current action rule only. Note that  the  default  umask
                 specified in your config file is used to reset mailagent's umask at the start of
                 each mail processing.  (Does not alter execution status)

       UNIQUE [-acr] [state] [(tag-list)]
                 Record message in the history and tag message as saved if it was already present
                 there.  If  the  message  is  recorded  for the first time, processing continues
                 normally. Otherwise a REJECT is performed. If -r was used,  a  RESTART  is  used
                 instead  whilst  -a  would  run  an  ABORT.   For  instance, to remove duplicate
                 messages from mailing lists, run a UNIQUE -a before saving  the  mail.   The  -c
                 option  may  be  used  alone to actually prevent the command from disturbing the
                 execution flow, and to later use the return status to see what happened:  UNIQUE
                 returns  a  failure  status if the message was already recorded.  If an optional
                 state argument is given, then the automaton will enter that state  if  the  mail
                 was  previously  in  the  database.  See also RECORD, and the paragraph entitled
                 Using Tags in Record and Unique for more information about the tag-list.  (Fails
                 if mail was already recorded)

       VACATION [-l] on|off|path [period]
                 Allow  or  disallow  a vacation message. When vacation mode is turned on via the
                 configuration file, a message is sent whenever the user receives a mail  meeting
                 some  requirements,  as  explained  under the section VACATION MODE.  One of the
                 conditions is that the vacation flag modified by  this  command  be  true.  This
                 makes  it  easy  to  disallow  vacation messages, ever, to a group of people for
                 instance.

                 Instead of on or off, you can specify a file name (~ substitution allowed) being
                 the  new  path  to  be used for locating the vacation file.  Optionally, you may
                 specify a last parameter, which will be  taken  as  the  period  to  apply  when
                 sending  the  vacation  message.   Changes  to  the  vacation  message  path are
                 forbidden when the configuration variable vacfixed is set to ON.

                 If you use the -l option, changes are made locally, for the duration of the rule
                 only.  If  you  REJECT  to go to some other rule, your changes will be lost. The
                 global value of the altered parameters is changed on the first local  usage  and
                 restored when a new rule is entered.  (Does not alter execution status)

       WRITE folder
                 Write the message in the specified folder, removing any pre-existing folder with
                 the same name. Hence, successive WRITE commands will overwrite the previous one.
                 This  is useful to store output of system commands ran by cron. Don't try to use
                 it with an MH folder or a directory folder or it will behave like SAVE.   (Fails
                 if message cannot be written)

   Execution Status
       Almost  all  the  actions  modify  a  variable  which  keeps track of the execution status
       (analogous to the $? variable in the shell).  This variable can be tested via the -t or -f
       option  of  the REJECT command for instance. To give but a single example, the SAVE action
       would return failed if it could not save the mail in the specified folder.  If  that  SAVE
       command was followed by a "REJECT -f FAILED", then the execution of the current rule would
       stop and the automaton would continue to analyze the mail in the FAILED state.

       Some of the actions however do not modify this last execution status. Typically, those are
       actions which make decisions based on that status, or simply actions which may never fail.
       Those special actions are: ABORT,  ASSIGN,  BEGIN,  KEEP,  MACRO,  NOP,  REJECT,  RESTART,
       RESYNC, STRIP and VACATION.

       It  is  unfortunate that ONCE or SELECT commands cannot make the difference between a non-
       execution and a successful execution of the specified command.  There may be a  change  in
       the way this scheme works, but it should remain backward compatible.

   Perl Escape
       By  using  the  PERL  command,  you  have  the  ability  to  perform  filtering  and other
       sophisticated actions directly in perl. This is really different from what you could do by
       feeding  your mail to a perl script. First of all, no extra process is created: the script
       is loaded directly into mailagent and compiled  in  a  special  package  called  mailhook.
       Secondly,  you  have a perl interface to all the filtering commands: each filtering action
       is associated  to  a  perl  function  (spelled  lower-cased).  Finally,  some  pre-defined
       variables are set for you by mailagent.

       Before  we go any further, please note that as there is no extra process created, you must
       not call the perl exit function. Use &exit instead, so that the exit may be trapped. &exit
       takes  one  argument,  the  exit code.  If you use 0, this is understood as a success, any
       other value meaning failure (i.e. the PERL command will return a  failure  status).  Using
       the  perl  exit  function directly would kill mailagent and would probably incur some mail
       losses.

       The scripts used should remain simple. In particular, you should  avoid  the  use  of  the
       package  directive  or  define functions with a package name other than mailhook (i.e. the
       package where your script is loaded). Failure to do so may raise some  name  clashes  with
       mailagent's  own  routines.   In  particular,  avoid the main package. Note that since the
       compilation environment is set-up to  mailhook,  not  specifying  package  names  in  your
       variables and subroutine is fine (in fact, it's meant to work that way).

       Your script is free to do whatever it wants to the mail. Most of the time however, you end
       up using the mailagent primitives to save the mail or forward it  (but  you  are  free  to
       redesign  your  own  and  call  them  instead,  of  course). The interface is simple: each
       function takes but one argument, a string, which is the arguments to the command, if  any.
       For instance, in a perl escape script, you would express:

            { SAVE list; FORWARD "users"; FEED ~/bin/newmail -tty; REJECT }

       with:

            &save('list');
            &forward('"users"');
            &feed('~/bin/newmail -tty');
            &reject;

       The  rule  is  simple:  each  command  is  replaced by a function call, with the remaining
       parameters enclosed in a string, if any. Alternatively, you may specify  parameters  as  a
       list:  all  the  arguments  you  provide are joined into a big happy string, using a space
       character as separator. The macro substitution mechanism is then  ran  on  this  resulting
       argument string.

       Each  function returns a boolean success status of the command (i.e. 1 means success). For
       those functions which usually do not modify the filter's last execution status variable, a
       success is always returned. This makes it possible to (intuitively) write:

            &exit(0) if &save('uucp');
            &bounce('root') || &save('emergency');

       and  get  the  expected  result.  The mail will be saved in the emergency folder only when
       saving in uucp folder failed and the mail could not be bounced to root.

       It is important to understand that these commands have exactly  the  same  effect  on  the
       filtering process when they are run from a perl escape script or from within the rule file
       as regular actions.  A &reject call will simply abandon the execution of the current  perl
       script  and  the  filter  automaton will regain control and attempt a new match.  But perl
       brings you much more power, in particular system calls, control  structures  like  if  and
       for, raw regular expressions, etc...

       The  special  perl  @INC  array  (which  controls the search path for require) is slightly
       modified by prepending mailagent's own private library path. This leaves the door open for
       future  mailagent  library  perl  scripts  which  may  be  required  by  the  perl script.
       Furthermore, the following special variables are  set-up  by  perl  before  invoking  your
       script:

       @ARGV          The  arguments  of  the  script, which were given by the PERL command. This
                      array is set up the exact same way you would expect it to be set up if  you
                      invoked  the command directly from the shell, excepted that @ARGV[0] is the
                      name of the script (since you cannot use perl's $0 to get at it; that would
                      give you mailagent's name).
       $address       The address part of the From: line.
       $cc            The raw content of the Cc: line.
       @cc            The list of addresses on the Cc: line, with comments suppressed.
       $envelope      The mail envelope, as computed using the first From line of the message.
       $friendly      The comment part of the From: line, if any.
       $from          The content of the From: line, with address and comment part.
       %header        This  table,  indexed  by  field  name,  returns  the  raw  content  on the
                      corresponding header line. See below.
       $msgpath       The full path name of the folder (or message within an MH folder) where the
                      last saving operation has occurred. This is intended to be used if you wish
                      to construct your own mail reception notification.
       $length        The message length, in bytes.
       $lines         The number of lines in the message.
       $login         The login name of the address on the From: line.
       $precedence    The content of the Precedence: line, if any at all.
       @relayed       The list of host names (possibly raw IP addresses if no DNS mapping) listed
                      in the (computed) Relayed: header line.
       $reply_to      The  e-mail  address  where  a  reply  should  be  sent  to,  with  comment
                      suppressed.
       $sender        The sender of the message (may have a comment), derived in the same way the
                      Sender: line is computed by mailagent.
       $subject       The subject of the message.
       $to            The raw content of the To: line.
       @to            The list of addresses on the To: line, with comments suppressed.

       The  associative  array  %header  gives  you access to all the fields in the header of the
       message. For instance, $to is really the value of  $header{'To'}.  The  key  is  specified
       using  a normalized case, i.e.  the first letter of each word is uppercased, the remaining
       being lowercased.  This is independent  of  the  actual  physical  representation  in  the
       message itself.

       The  pseudo keys Head, Body and All respectively gives you access to the raw header of the
       message, the body and the whole message.  The %header array is really a reference  to  the
       mailagent's  internal data structure, so modifying the values will influence the filtering
       process.  For instance, the SAVE command writes the Head, the X-Filter: line, the  end  of
       header  (a  single  newline)  and then the Body (this is an example only, not a documented
       feature :-).  The =Body= key is special: it is a Perl reference to a scalar containing the
       body with any content transfer encoding removed.

       Note that the $msgpath variable holds only a snapshot of the folder path at the time where
       the PERL escape was called. If you perform your own savings in perl, then you need to look
       at the $main'folder_saved variable instead to get the up-to-date folder path value.

       As  a  final  note,  resist  the  temptation of reading the internals of the mailagent and
       directly calling the routines you need. If it is not documented in the manual page, it may
       be  changed  without  notice by any further patch.  (And this does not say that documented
       features may not change also... It's just more unlikely, and patches would  clearly  state
       that, of course.)

   Program Environment
       All  the  programs  started  by  mailagent  via  RUN  and  friends  inherit  the following
       environment variables: HOME, USER  and  NAME,  respectively  set  from  the  configuration
       parameters  home,  user and name. If the mailagent is invoked by the filter, then the PATH
       is also set according to the configuration file (if you are using  the  C  filter)  or  to
       whatever you set PATH (if you are using the shell filter).

       All  the  programs  are  executed  from  within  the home directory. This includes scripts
       started via the PERL command and mail hooks.  The  latter  will  be  described  in  detail
       further down.

   File inclusion
       Some  commands like FORWARD or KEEP allow you to specify a file name between double quotes
       to actually load parameters from this file. Unless a full path  is  given,  the  following
       method  is  used  to  locate  the file: first in the location pointed to by the mailfilter
       variable if set, otherwise in maildir and finally in the home directory. Note that this is
       not a search path in the sense that if mailfilter is defined and the file is not there, an
       error will be reported.

       The file should list each parameter (be it an address, a header or a pattern) on a line by
       itself. Shell-style comments (#) are allowed within that file and leading white spaces are
       trimmed (but not trailing spaces).

   Macros Substitutions
       All the commands go through a macro substitution  mechanism  before  being  executed.  The
       following macros are available:

       %%        A real percent sign
       %A        The  internet  address  extracted  out  of  the  From: field (a.b.c in u@a.b.c),
                 converted to lower-case.
       %C        CPU name on which mailagent runs. That is a fully qualified  hostname  with  the
                 domain name, e.g. lyon.eiffel.com.
       %D        Day of the week (0-6)
       %H        Host  name (name of the machine on which the mailagent runs), without any domain
                 name. Always in lower-case, regardless of the machine name.
       %I        The internet domain name extracted out of the  From:  field  (b.c  in  u@a.b.c),
                 converted to lower-case.
       %L        Length of the body part, in bytes, with content-transfer-encoding removed.
       %N        Full name of the sender (login name if none)
       %O        The organization name extracted out of the From: field (b in u@a.b.c), converted
                 to lower-case.
       %R        Subject of the original message with leading Re: suppressed
       %S        Re: subject of original message
       %T        Time of the last modification on mailed file (commands MESSAGE and NOTIFY)
       %U        Full name of the user
       %Y        Full year, with four digits (so-called yyyy format)
       %_        A white space (useful to put white spaces in single patterns)
       %&        List of selectors which incurred match (among  those  specified  via  a  regular
                 expression  such as 'X-*: /foo/i'. If we find the foo substring in the X-Mailer:
                 header line, then %& will be set to this value). Values in the  list  are  comma
                 separated.
       %~        A null character, wiped out from the resulting string.
       %digit    Value of the corresponding back reference from the last match.
       %#var     Value of user-defined variable var
       %=var     Value   of  the  mailagent  configuration  variable  var  as  specified  in  the
                 ~/.mailagent file.
       %d        Day of the month (01-31)
       %e        The user's e-mail address (yours!).
       %f        Contents of the "From:" line, something like %N <%r> or %r (%N) depending on how
                 the mailer is configured.
       %h        Hour of the day (00-23)
       %i        Message ID, if available (otherwise, this is a null string)
       %l        Number of lines in the message, once content-transfer-encoding has been removed
       %m        Month of the year (01-12)
       %n        Lower-case login name of sender
       %o        Organization (where mailagent runs)
       %r        Return address of message
       %s        Subject of original message
       %t        Current hour and minute (in HH:MM format)
       %u        Login name of the user
       %y        Year (last two digits)
       %[To]     Value of the header field (here To:)

   User-defined Macros
       The  mailagent  lets  you  define your own macros in two ways: at the filter level via the
       MACRO command, or at the perl level in your own commands or perl actions.

       Once defined, a user macro (say foo) can be substituted by using %-(foo). In the case of a
       single-letter macro, that can be optimized into %-f for instance, i.e. the parenthesis can
       be omitted.

       There are six types of macros:

       SCALAR    A scalar value is given, e.g: red. The  macro's  value  is  the  literal  scalar
                 value, no further interpretation is performed on the data.

       EXPR      A  perl  expression  will  be evaled to get the value, e.g: $red.  Note that the
                 evaluation will be performed within the usrmac package, so if you are  referring
                 to  a  variable  in  another  package,  it  would  be  wise to specify it, as in
                 $foo'bar.

       CONST     It's really the same as EXPR, but the value is known to be a  constant.  So  the
                 first  time  a  substitution is made, the expression will be evaluated, and then
                 its result is cached.

       FN        A perl function name  (without  the  leading  &),  such  as  main'do_this.   The
                 function  will  be called with a single parameter: the name of the macro itself.
                 That leaves the door  open  for  further  user-defined  conventions  by  forcing
                 evaluation through one single perl function.

       PROG      A  program  to  run  to  get the actual value. Only trailing newline is chopped,
                 others are preserved. The program is forked each  time.  In  the  argument  list
                 given  to  the  program,  %n  is  expanded  as  the  macro name we are trying to
                 evaluate. If you specify that in the filtering rules, don't forget to escape the
                 first %.

       PROGC     Same as PROG really, but the program is forked only once and the value is cached
                 for later perusal.

       At the perl level, four functions let you manipulate and define your macros (all  part  of
       the usrmac package):

       new(name, value, type)
                 Replace or create a %-(name) macro. For instance:

                      new('foo', "$mailhook'header{'X-Foo'}", 'EXPR');

                 would create a new macro foo that would expand into the value of an hypothetical
                 X-Foo header.

       delete(name)
                 Delete all values recorded for the macro.

       push(name, value, type)
                 Stack a new macro, creating it if necessary.

       pop(name) Remove last macro definition on the stack.

       One macro stack is allocated for each macro, so that some kind of  crude  dynamic  scoping
       may  be  implemented.  Creating  a macro via push is like taking a local variable in perl,
       while creating one by new is simply assigning to a variable. Likely, pop is like exiting a
       block  with  a local variable definition and delete frees all the macro bearing that name,
       i.e. it deletes the whole stack.

       At the filter level, the MACRO command has three options. By default, the command  defines
       a  new  macro  by  using  push, and the other options each let you access one of the other
       interface functions.  Note that macro definitions persist across APPLY commands.

   User-defined Logging
       Most of the time when writing a new mailagent filtering command or an perl hook, you  will
       have  a need for specific logging, either to report a problem or to keep track of what you
       are performing.

       Normally, logs are appended into the agentlog file by calling  &main'add_log(string)  (see
       subsection General Purpose Routines).  For plain mailagent actions, this is fine.

       But  mailagent lets you define alternate logging files, referred to by name.  This generic
       logging interface is defined in the usrlog package:

       new(name, file, flag)
                 Records a new log file known as name and done in file. If the pathname given for
                 this  file  is not absolute, it is rooted under the logdir directory. If flag is
                 set to true, any logging done to this file will also be copied  to  the  default
                 system-wide logfile. Nothing is done if a logfile with the same name has already
                 been defined.

       delete(name)
                 Deletes the logfile known  as  name.  Further  logging  done  to  that  file  is
                 redirected to the default logfile.

       main'usr_log(name, string)
                 Adds  an  entry to the logfile name. The default logfile is known as default and
                 cannot be redefined nor deleted. Note that this function is available  from  the
                 main  package.  Calling  it  with  name  set  to  the string 'default' is mostly
                 equivalent to calling directly main'add_log with the notable exception that  the
                 -i  mailagent  option  will  not be honored in that case. This may or may not be
                 useful to you.

       If you call &main'usr_log with a non-existent logfile name, logging is redirected  to  the
       default system-wide logfile defined in your ~/.mailagent.

   Dynamically Loading New Code
       In you perl routines (user-defined commands, perl hooks, etc...), you may feel the need to
       dynamically load some new code into mailagent. You have  direct  access  to  the  internal
       routine  used  by  mailagent  to  implement the REQUIRE command or load your new filtering
       commands for example.

       Using the so-called dynload interface buys you some extra features:

       •    The mailagent public library path is automatically prepended to the @INC array, which
            lets  you  define  your  own  system-wide  or private perl library files (the private
            library path is defined by the perlib configuration variable, the public library path
            was defined at installation time).

       •    Like  perl's  require,  mailagent  keeps  track of which files were loaded into which
            packages and will not reload the same file in the same package twice.

       •    It is possible to make sure that a specific function be defined in the  loaded  file,
            with an error reported if this is not the case.

       •    You benefit from the default logging done by dynload when some error occurs.

       In order to do all this, you call:

            &dynload'load(package, file, function)

       specifying  the package into which you wish to load the file, and optionally the name of a
       function that must be defined once the file has been loaded (leave this field to undef  if
       you  do  not  have  such  a  constraint).  The routine returns undef if the file cannot be
       loaded (non-existent file, most probably), 0 if the file was loaded but contained a syntax
       error or did not define the specified function, and 1 for success.

   Using Once Commands
       The  ONCE  constructs  lets  you specify a given command to be run once every period (day,
       week...). The command is identified by a name and a tag, the combination of the two  being
       unique. Why not just a single identifier? Well, that would be fine, but assume you want to
       send a message in reply to someone once every week. You could use the  e-mail  address  of
       the person as the command identifier. But what if you also want to send another message to
       the same address, this time once a month?

       Here is a prototypical usage of a ONCE, which acts like  the  vacation  program,  excepted
       that it sends a reply only once a day for a given address:

            { ONCE (%r, message, 1d) MESSAGE ~/.message };

       This  relies  on the macro substitution mechanism to send only once a day the message held
       in ~/.message. Do not use the tag vacation, unless you know what you are  doing:  this  is
       the tag used internally by mailagent in vacation mode. Recall that no selector nor pattern
       is understood as "Subject: *", hence the rule is  always  executed  because  that  pattern
       always matches.

       The  timestamps  associated with each commands are kept in files under the Hash directory.
       The name is used as a hashing key to compute the name of the file (the two  first  letters
       are  used).  Inside  the  file, timestamps are sorted by name, then by tag. Of course, you
       could say (inverting tag and name):

            { ONCE (message, %r, 1d) MESSAGE ~/.message };

       but that would be likely to be less efficient, as the first hashing would  be  done  on  a
       fixed  word, hence all the timestamps would be located in the file Hash/m/e (where Hash is
       the name of your hashing directory, which is  the  hash  parameter  in  the  configuration
       file).

   Using Tags in Record and Unique
       Both the RECORD and UNIQUE commands let you specify a comma-separated tag list between '('
       and ')'. For each tag present in the list, there is  a  separate  entry  in  the  database
       associated with the message ID. When the message is recorded for at least one of the tags,
       the command "fails". Not specifying any tags means looking  for  any  occurrence  of  that
       message ID, whether it is tagged or not.

       This  is  very  useful  when receiving mail cross-posted to distinct mailing lists and you
       want to save one instance  of  the  message  in  each  folder,  but  still  guard  against
       duplicates. You may say:

            To Cc: unix-wizards {
                 UNIQUE (wizards);
                 SAVE wizards;
                 REJECT;
            };
            To Cc: majordomo-users   {
                 UNIQUE (majordomo);
                 SAVE majordomo;
                 REJECT;
            };

       and  only  one  instance  of the message will end up in each folder. When you have folders
       with conflicting interests, you might use a  tag  list,  instead  of  a  single  tag.  For
       instance,  assuming you wish to keep a single copy for messages cross-posted to both dist-
       users and agent-users, but have a separate copy if also cross-posted  to  majordomo-users,
       then say:

            To Cc: majordomo-users   {
                 UNIQUE (majordomo);
                 SAVE majordomo;
                 REJECT;
            };
            To Cc: dist-users {
                 UNIQUE (dist, agent);
                 SAVE dist-users;
                 REJECT;
            };
            To Cc: agent-users {
                 UNIQUE (dist, agent);
                 SAVE dist-users;
                 REJECT;
            };

       If  you  have  some  rule  using  UNIQUE without any tags, it will match when at least one
       instance of the message has been recorded, no matter what tag (if any at all) was used  in
       the first place.

   Specifying A Period
       The period parameter of the ONCE commands or the vacperiod parameter of your configuration
       file has the following format: a number followed by a modifier. The modifier is an  atomic
       period  like  a day or a week, the number is the number of atomic periods the final period
       should be equal to. The available modifiers are:

       m         minute
       h         hour (60 minutes)
       d         day (24 hours)
       w         week (7 days)
       M         month (30 days)
       y         year (365 days)

       All the periods are converted internally in seconds, although you do  not  really  care...
       Examples of valid periods range from "1m" to "136y" on a 32 bits machine (why ?).

   Timeouts
       In  order  to  avoid having a mailagent waiting for a command forever, a maximum execution
       time of one hour is allowed by default.  Past that amount of time, the  child  is  sent  a
       SIGTERM  signal.  If it does not die within the next 30 seconds, a SIGKILL is sent. Output
       from the program, if any so far, is mailed back to the user.  This default  behaviour  may
       be  altered  by  setting a proper runmax variable in your configuration file to allow more
       time for the command to complete.

       There is also a filter queue timeout. In order to  moderate  system  load,  the  C  filter
       program  waits 60 seconds by default (or whatever queuewait was set to in the config file)
       before launching mailagent. To avoid conflicts, messages queued by the first filter (which
       will  then  sleep  for queuewait seconds) are not processed by mailagent's -q option until
       they are at least queuehold seconds old. Another queue-related parameter is queuelost, the
       amount  of  seconds  after  which  mailagent will flag messages as "lost" when listing the
       queue.

       Finally, the locking timeout policy may also be configured. By default, a lock  is  broken
       when it is one hour old (configured by the lockhold variable) and mailagent will only make
       lockmax attempts, spaced by lockdelay seconds to acquire the lock. It  will  then  proceed
       whether  or  not  it got that lock. If you want a secure locking policy, make sure lockmax
       times lockdelay is greater than lockhold, that parameter being "large" enough.

   Avoiding Loops
       The mailagent leaves an "X-Filter:" header on each filtered message, which in turn is used
       to  detect loops. If a message already filtered is to be processed, the mailagent enters a
       special state _SEEN_. This state is special in the sense it is built-in, it is not matched
       by  ALL,  and  some  actions  are not made available, namely: BACK, BOUNCE, FEED, FORWARD,
       GIVE, NOTIFY, PASS, PIPE, POST, PURIFY, QUEUE and RUN. Also note that  although  the  ONCE
       and  SELECT  constructs  are  enabled,  they will not let you execute disallowed commands.
       Otherwise, the _SEEN_ state behaves like any other state you can select or  negate,  so  a
       <!_SEEN_> guard will not select the rule when we are in state _SEEN_.

       The  _SEEN_ state makes it easy to deal with mails which loop because of an alias loop you
       have no control on. If no action is found in the _SEEN_ state, the mail  is  left  in  the
       mailbox, as usual. Moreover, if no saving is done, a LEAVE is executed. This is the normal
       behavior.

       The "X-Filter:" header is only added when the message is saved. Actions such  as  PIPE  or
       GIVE  do  not  flag  the  message as being saved and therefore they do not add that header
       line.  You can add one via ANNOTATE if you wish to prevent loops, in case the  program  to
       which you are feeding the message might return it to you in some strange way.

   Message Files
       The  text  of  the message to be sent back (for MESSAGE or NOTIFY) is read from a file and
       passed through the macro substitution mechanism. The special macro %T is set to  the  date
       of  last  modification  made  on that file. The format is month/day, and the year is added
       before the month only if it differs from the current year.

       At the head of the message, you may put header  lines.  Those  lines  will  overwrite  the
       default  supplied  lines.  That  may  be  useful to change the default subject or add some
       additional fields like the name of your organization.  The end of your header is given  by
       the first blank line encountered.  If the top of the message you wish to send looks like a
       mail header, you may protect it by adding a blank line at the very top of the  file.  This
       dummy  line  will  be  removed  from the message and the whole file will be sent as a body
       part.

       Here is an example of a vacation file. We add a carbon copy as well as  the  name  of  our
       organization in the header:

            Cc: ram
            Organization: %o
            Precedence: bulk

            [Last revision made on %T]

            Dear %N:

            I've received your mail regarding "%R".
            It will be read as soon as I come back from vacation.

            Sincerely,
            --
            %U <%u@%C>

VACATION MODE

       When it's time to take some vacation, it is possible to set up mailagent in vacation mode.
       Every vacperiod, the  message  vacfile  will  be  sent  back  to  the  user  (with  macros
       substitutions) if the user is explicitly listed in the To or Cc field and if the sender is
       not a special user (root, uucp, news,  daemon,  postmaster,  newsmaster,  usenet,  Mailer-
       Daemon,  Mailer-Agent  or  nobody).   Matches  are  done  in a case insensitive manner, so
       MAILER-DAEMON will also be recognized as a special user.  Furthermore, any message  tagged
       with  a  Precedence:  field set to bulk, list or junk will not trigger a vacation message.
       This built-in behavior can of course be overloaded  by  suitable  rules  (by  testing  and
       issuing the vacation message yourself via MESSAGE).

       Internally,  mailagent uses a ONCE command tagged (%r, vacation, $vacperiod). This implies
       you must not use the vacation tag in your own ONCE commands, unless you know what you  are
       doing.

       Besides,  the  vacation message is sent only if no "VACATION off" commands were issued, or
       if another "VACATION on" overwrote the previous one. Note that whether a rule  matched  or
       not is irrelevant to the algorithm. By default, of course, the vacation message is allowed
       when the vacation configuration parameter is set to on.

       If you are not pleased by the fact that a vacation message is sent to people who addressed
       you a carbon copy only, then you may write at the top of your rule file:

            Cc: ram  { VACATION off; REJECT };

       Of course, you have to substitute your own login name in place of ram.  You cannot use the
       same scheme to allow vacation messages to special users like root, because  the  test  for
       "specialness"  occurs  after  the vacation mode flag. This is construed as a feature as it
       prevents stupid mistakes, like using r* instead of ram in the previous rule.

       You may also want to setup a different vacation message, meant only  for  people  in  your
       organization  given the sensitive nature of the information revealed ;-).  A simple way of
       doing that is:

            From: /^\w+$/, /^\w+@\w+$/, /^[\w.-]+@.*\.hp\.com$/i
                 { VACATION ~/.hp_vacation 1w; REJECT HP };

       Assuming the domain of my organization is .hp.com and that messages not bearing any domain
       are  local messages, the above rule sets up the file ~/.hp_vacation, sent once a week, for
       all HP employees.

       The VACATION command will not let you change the message path (but  will  allow  frequency
       changes anyway) when the vacfixed configuration variable is set to ON. This is meant to be
       used in emergency situations, when only one vacation message will fit. For instance,  when
       you are on a sick leave, a simple trigger message to your mailagent from home could change
       your ~/.mailagent configuration to force the ~/.i_am_sick message, regardless of what  the
       various  rules  have  to  say.  Actually,  this  is  precisely why this feature was added,
       amazing... :-)

VARIABLES

       The following variables are paid attention to: they may come from the  environment  or  be
       set in the rule file:

       mailfilter
                 indicates where loaded patterns are to be looked for, if the name of the file is
                 not fully qualified. If it is not set, maildir will be used instead. If  maildir
                 is not set either, the home directory is used.

       maildir   is  the  location  of  your  mail  folders.  Any  relative path is understood as
                 starting from maildir. If it is not set, ~/Mail is used.

       Those variables remain active while in the scope of the rule file.   Should  an  alternate
       rule file be used (via rules hook or the APPLY command), the current values are propagated
       to the new rule set unless overridden in  the  alternate  rule  file.  In  any  case,  the
       previous  value is restored when control is transferred back to the previous set of rules.
       That is, those variables are dynamically instead of statically scoped.

AUTOMATIC ACKNOWLEDGMENTS

       Anywhere in the mail, there can be an @RR left-justified line  which  will  send  back  an
       acknowledgment  to  the  sender  of  the  mail.  The  @RR may optionally be followed by an
       address, in which case the acknowledgment will be sent to that address instead.   In  fact
       (but  let's  keep  that  a  secret),  this  is  a way for me to be able to see who runs my
       mailagent program and who doesn't...

       The sendmail program usually implements such a feature  via  a  Return-Receipt-To:  header
       line,  which  sends  the  whole header back upon successful delivery. However, this is not
       implemented on all mail transport agents, and @RR is a good alternative :-).

NOTA BENE

       Throughout this manual page, I have always written header fields with the first letter  of
       each  word  uppercased, as in Return-Receipt-To. But RFC-822 does not impose this spelling
       convention, and a mailer could legally rewrite the  previous  field  as  return-receipt-to
       (and in fact so does sendmail in its own private mail queue files).

       However,  you  must  always  specify the headers in what could be called a normalized case
       (for headers anyway). The mailagent will correctly recognize cc:, CC: or  Cc:  in  a  mail
       message  and  will  allow  you  to select those fields via the normalized Cc: selector. In
       fact, it operates the normalization for you, and a cc: selector would not be recognized as
       such. Of course, no physical alteration is ever made on the header itself.

       This  is  also true for headers specified in the STRIP or KEEP command. If you write STRIP
       Cc, it will correctly remove any cc: line. Likewise, if you  use  regular  expressions  to
       specify  a  selector,  Re.*:  would match both original received: and Return-path: fields,
       internally known through their normalized representation.

MAIL HOOKS

       The mail hooks allow mailagent to transparently invoke some  scripts  or  perform  further
       processing  on  the  message.  Those  hooks  are  activated  via  the SAVE, STORE or LEAVE
       commands. Namely, saving in a folder whose executable bit is  set  will  raise  a  special
       processing.  By  default,  the folder is taken as a program where the mail should be piped
       to. If the "folder" program returns a zero status, then the message is considered saved by
       the  mailagent.  Otherwise, all the processing attached to failed save commands is started
       (including emergency saving attempts). Executable folders provide a transparent way  (from
       the rule file point of view) to deal with special kind of messages.

       In  fact,  five  different  types  of  hooks  are  available.  The  first one is the plain
       executable folder we have just spoken about. But in fact, here is what really happens when
       a  saving  command detects an executable folder: the mailagent scans the first line of the
       folder (in fact, the first 128 bytes)  and  looks  for  something  starting  with  #:  and
       followed  by  a single word, describing a special kind of hook. This is similar in the way
       the kernel deals with the #! hook in executable programs.  If no #:  is  found  or  #:  is
       followed by some garbage, then mailagent decides it is a simple program and feeds the mail
       message to this program. End of the story.

       But if the #: token is followed (spaces  allowed,  case  is  irrelevant)  by  one  of  the
       following words, then special actions are taken:

       rules     The file holds a set of mailagent rules which are to be applied. A new mailagent
                 process is created to actually deal with those and the exit status is propagated
                 back to the original mailagent.

       audit     This  is  similar  in  spirit  to what Martin Streicher's audit.pl package does,
                 hence the name of this hook. The special variables which are set up by the  PERL
                 filter commands are initialized and the script is loaded in the special mailhook
                 package name space, which also gives you an interface  to  the  mailagent's  own
                 routines.   You  may  safely  use the exit function here, since an extra fork is
                 done. This is the only difference between an audit and a perl hook.

       deliver   Same thing as for the audit hook, but the standard  output  of  your  script  is
                 monitored  by  mailagent  and  understood as mailagent filtering commands.  Upon
                 successful return, a mailagent process will be invoked to actually execute those
                 commands  on  the message. Again, this is similar in spirit to Chip Salzenberg's
                 deliver package and gave the name of this hook.

       perl      This hook is the same as  audit  but  it  is  executed  without  forking  a  new
                 mailagent,  and  you  have the perl interface to mailagent's filtering commands.
                 There is no difference with the PERL command, because  it  is  implemented  that
                 way, by calling a mailagent and forcing the PERL command to be executed. This is
                 similar in spirit to Larry Wall's famous perl language and it is responsible for
                 the name of this hook :-).

       As mentioned earlier in this manual page, the hook is invoked from with the home directory
       specified in your ~/.mailagent (which may differ from your real home directory, as far  as
       mailagent or mailhook are concerned).

       For  those hooks which are finally ran by perl, the special @INC array has mailagent's own
       private library path prepended to it, so that require first looks in this place.

FOLDERS

       A folder is a file or a directory which can be the target of a delivery by the  mailagent,
       that is to say the argument of SAVE-like commands.

   Folder Format
       By  default,  mails  are written into folders according to the standard UNIX-style mailbox
       format: each mail starts with a leading From line bearing the  sender's  address  and  the
       date.  However,  by  setting the mmdf parameter from the ~/.mailagent to ON, the mailagent
       will be able to save messages in MMDF format: each message is sandwiched between two lines
       of four Ctrl-A characters (ASCII code 1) and the leading From line is removed.

       When  MMDF  mode is activated, each folder will be scanned to see if it is a UNIX-style or
       MMDF-style mailbox and the message will be  saved  accordingly.   When  saving  to  a  new
       folder,  the  default  is to create a UNIX-style mailbox, unless the mmdfbox configuration
       variable was set to ON, in which case the MMDF format prevails.

       Note that the MMDF format is also the standard for MH packed folders, so by  enabling  the
       MMDF  mode,  you can actually deliver directly to those packed folders. The MH command inc
       is able to incorporate mail from either form anyway, i.e. it does not matter  whether  the
       folder is in UNIX format (also called UUCP-style) or in MMDF format.

       MH-style folders are also supported. It is mainly a directory in which messages are stored
       in individual files. To save directly into an MH folder, simply  prefix  the  folder  name
       with  '+',  just as you would do with MH commands.  The unseen sequences specified in your
       MH profile (the mhprofile parameter in your ~/.mailagent, default is  ~/.mh_profile)  will
       be correctly updated, as rcvstore would.

       When  the  target  folder is a directory, mailagent attempts the delivery in an individual
       numbered file. If a prefix  file  is  present  (config  parameter  msgprefix,  default  is
       .msg_prefix),  its  first  line  is  used  to specify the base name of the message, then a
       number is appended to give the name of the message file to use. That is, if  there  is  no
       such file, the folder will look like an MH one, without any MH sequence file though.

   Folder Compression
       If  you  have  one  or  more  of  the  widely available file compression utilities such as
       compress or gzip in your PATH (as set up by ~/.mailagent), then you may wish to use folder
       compression to save some disk space, especially when you are away for some time and do not
       want to see your mail fill-up the filesystem.

       To achieve folder compression, you have to set up a file,  referred  to  by  the  compress
       configuration  variable.  This file must list folder names, one per line, with blank lines
       ignored and shell-style (#) comments allowed. You may use shell-style patterns to  specify
       the  folders,  and  the  match  will  be  attempted  on the full pathname of the folder (~
       substitution occurs). If you do  not  specify  a  pattern  starting  with  a  leading  '/'
       character,  then  the match will be attempted on the basename of the folder (i.e. the last
       component of the folder path). If you want to compress all your folders, then simply put a
       single '*' inside this file.

       Mailagent  uses  the filename extension to determine what compression scheme is used for a
       particular folder.  The file referred to by the compspecs configuration variable  (default
       is  $spool/compressors)  is used to define the commands that mailagent will use to perform
       the compress, uncompress, and cat operations for a particular extension.

       The compressors file holds lines of the following form:

            tag extension compression_prog uncompress_prog cat_prog

       where:

       tag       is the logical name for the compression scheme.  This is typically the  same  as
                 the  name of the program used to provide the compression, but could be different
                 for some unforeseen reason.  This must be unique across all records in the file.

       extension is the extension to recognize as belonging to the specified tag.  This  must  be
                 unique across all records in the file.

       compression_prog
                 is  the  name  of  the  command  to  run to compress a folder.  The program must
                 replace the uncompressed  file  with  the  compressed  one  with  the  extension
                 appended to the filename (like compress or gzip).

       uncompression_prog
                 is  the  name  of  the  command to run to uncompress a folder.  The program must
                 replace the compressed file with the  uncompressed  one  without  the  extension
                 (like uncompress or gunzip).

       cat_prog  is  the  name of the command to output the uncompressed contents of a compressed
                 folder to stdout (like zcat or gzcat).

       The fields are separated by TABS to allow for the use of space characters in  the  command
       fields.

       If  the  file  referred  to by the compspecs configuration variable cannot be accessed for
       whatever reason, a default entry is hard-wired into mailagent (knows about  both  compress
       and gzip programs):

            compress <TAB> .Z <TAB> compress <TAB> uncompress <TAB> zcat
            gzip <TAB> .gz <TAB> gzip <TAB> gunzip <TAB> gunzip -c

       If  you  wish  to  add  more  compressors,  you can copy the default compressors file from
       mailagent's private library directory  and  setup  a  correct  entry  for  your  alternate
       compressor.  Keep  in  mind that the trailing extension needs to be unique amongst all the
       listed programs, since that extension  is  used  to  determine  the  type  of  compression
       performed on the folder.

       If the folder is created without any existing compressed form around, a default compressor
       is selected for you, as defined by the comptag configuration variable. That refers to  the
       tag  name  of the compspecs file, i.e. the first word on the line (usually the name of the
       compression program, but not necessarily).

       When attempting delivery, mailagent will  check  the  folder  name  against  the  list  of
       patterns  in  the compress file. If there is a match, the folder is flagged as compressed.
       Then mailagent attempts decompression if there is already a compressed form (ie. the  file
       has  a recognized filename extension) and if no uncompressed form is present.  Delivery is
       then made to the uncompressed folder. However, re-compression  is  not  done  immediately,
       since  it  is  still  possible  to get messages to that folder in a single batch delivery.
       Should disk space become so tight that  decompression  of  other  folders  is  impossible,
       mailagent  will  re-compress  the folders it has already uncompressed. Otherwise, it waits
       until the last moment.

       If for some reason there is a compressed folder which cannot  be  decompressed,  mailagent
       will  deliver  the mail to the plain folder. Further delivery to that folder will be faced
       with both a compressed and a plain version of the folder, and that will get you a  warning
       in the log file, but delivery will be made automatically to the plain file.

       On newly created folders the comptag configuration variable is referenced to determine the
       compression type to use for the folder.

MAIL BIFFING

       If you are receiving and processing mail on your own machine,  then  you  have  access  to
       local  mail  biffing  where  mailagent  can warn you about new messages and tell you about
       where they have been saved, printing a small subset of the header and the first few  lines
       of the body.

       To  use  biffing,  all  you  need  is  the  setting  of  the  few  biff parameters in your
       ~/.mailagent and make sure biff is set to ON. Actually, this is  the  only  parameter  you
       need  to  set  to  get  minimal  default  biffing behaviour. Don't forget to run the shell
       command "biff y" on the terminals where you want to get notification (you may do  that  on
       several ttys, one for each virtual display for instance).

       Upon  mail  reception  and saving on a folder or posting to a newsgroup, mailagent locates
       all the ttys where you are logged on, then selects  those  where  biffing  was  requested,
       finally  emitting a message and making a beeping sound (if your terminal supports this and
       you are using the standard format--see below).

   Customizing Biffing Output
       Should the default format not suit your needs,  you  may  customize  the  biffing  message
       freely,  setting  the  biffmsg  parameter to point to the file where the format is stored.
       Standard macros substitutions will be performed on your message, the following  macro  set
       superseding and completing the standard set:

       %-A       Same as writing %-H, new line, %-B
       %-B       The  body  part  of the biffing message, with content-transfer-encoding removed.
                 If the message is a MIME multipart one, the text/plain part is shown.  If only a
                 text/html part is available, the HTML markup is stripped for biffing.
       %-H       The  header  part  of the biffing message. If shows only From:, To: Subject: and
                 Date: headers, or whatever you have set the biffhead configuration variable  to.
                 All  headers  are showed as one line of text, regardless of their actual length.
                 There will be three trailing dots at the end to signal that truncation occurred.
                 For  a  news article (biffing after a POST -b), the To: and Cc: fields are never
                 shown, even if specified in biffhead.
       %-T       Same as %-B, but trimming is activated. The purpose of trimming is to remove any
                 leading  quotation  in  the message, to get only the most meaningful part.  This
                 assumes the quoting character  is  a  single  non-alphanumeric  character.   The
                 leading  attribution  line that may introduce the quotation can be also removed,
                 and a minimum length for the quotation can be set in the configuration file.
       %B        The relative path under %d of the message folder, full path (%p)  if  not  saved
                 under that directory.  The newsgroup name for news articles.
       %D        The  directory  where the message is stored. If an MH folder, this is the folder
                 full path. The home directory is replaced by a ~.  Empty for news articles.
       %F        The base name (last path component) of the message. For an MH message,  this  is
                 the message number.  Empty for news articles.
       %P        The folder path. It has the correct semantics for MH and directory folders, i.e.
                 it points to the folder directory itself. Otherwise, the same as %p.
       %a        Alarm characters (^G).  May expand to more than one under  the  control  of  the
                 BEEP filtering command. Use %b if you only want a single bell.
       %b        A beeping character (^G).  As opposed to %a, this only expands to give one bell.
       %d        Full  path  where  folders  such  as  the one being saved into are stored if not
                 qualified (i.e. your MH path for MH folders, of something like ~/Mail for  other
                 folders).  Empty for news articles.
       %f        Folder  where  mail was saved, home replaced by ~ for short.  The newsgroup when
                 article was posted for news.
       %m        A '+' sign if the folder is an MH one, empty otherwise.
       %p        The full path name (same as %f) of the message, but without any ~ shortcut.  The
                 newsgroup name for news articles.
       %t        The  type  of  message: usually "mail", but set to "article" for biffing after a
                 POST command.

       You can get the standard macro expansion by using %:f for instance, since the %f macro  is
       superseded.  The  %:  form lets you obtain the standard macro definition anyway, no matter
       what, so you don't have to remember whether a given macro is superseded in this context or
       not.   Besides,  it is safer since new macros may be added here without notice.  Note that
       macros related to the message content all start with %- and therefore are not  conflicting
       with standard one.

       Here  is  the  format  you  need to use to get the same behaviour as the default hardwired
       format:

            %b
            New %t for %u has arrived in %f:
            ----
            %-A
            ----%b

       Note that the string ...more... appears at the end of  the  body  when  it  has  not  been
       completely printed out on the screen and the remaining lines are not blank or similar.

   Trimming Leading Quotation
       It  is  a  standard  practice,  when  replying  to a message, to include an excerpt of the
       sentences being replied-to, using a non-alphanumeric  character  such  as  '>'  to  prefix
       quoted lines. Something like:

            Quoting John Doe:
            > This is quoted material.
            > Another line from John's mail.

            This is part of the reply to John.

       The  leading  "Quoting  ..."  line,  called  the  attribution line, is optional and may be
       missing or take another free form.

       However, when biffing, this may be seen as useless noise, especially nowadays where people
       freely  quote  more  and  more in their replies. Since the biff message only shows the top
       lines of the message, it may be desirable to automatically trim those quoted lines.

       Via the %-T macro in the customized biff format, you may request trimming of  the  leading
       quotation material, keeping the attribution line or not, and even replace trimmed material
       with a notification that so many lines have been removed.

       All this customization is  done  from  the  ~/.mailagent  configuration  file,  using  the
       bifftrim, bifftrlen and biffquote variables.

       You  first need to turn trimming on by using a customized biff format using the %-T macro.
       By setting bifftrlen to 3, you may request that only quotations of at  least  3  lines  be
       trimmed.  Turning  bifftrim  off  will  remove  the  trimming notification, whilst turning
       biffquote off will also strip the attribution line, when present.

       For instance, assuming the following settings:

            bifftrim : ON
            bifftrlen: 2
            biffquote: OFF

       then the above example would produce the following biffing output (header of  the  message
       not withstanding):

            [trimmed 3 lines starting with a leading '>' character & attribution line]
            This is part of the reply to John.

       because  the  blank  line  following  the  quoted material is counted as being part of the
       quotation. The "[trimmed ..]" message can be turned off by setting bifftrim to OFF.

       The trimming algorithm considers the first line of the body to see if  it  starts  with  a
       non-alphanumeric  character.  If  it does, then all the following lines starting with that
       same character, or any blank line is removed, up to the first non-blank line starting with
       another  character.  Optionally,  the  first  line  (and that line only) is skipped if the
       second one starts with a non-alphanumeric character, and the first line is taken as  being
       the attribution line.

   Using Compact MH-style Biffing
       The so-called MH-style biffing is a way of presenting a compacted body where all the lines
       are joined together into a big happy string with successive spaces turned  into  a  single
       space character. To enable it, you need to set the biffmh variable to ON.

       Since  this  compacting is output verbatim on the tty, line breaks will occur randomly and
       this may make reading  difficult.  You  may  request  an  automatic  reformatting  of  the
       compacted  body  by  turning biffnice to ON and the biff output will fit nicely within the
       terminal.

       Unfortunately, it is not possible to customize the amount of columns that should  be  used
       for  formatting:  since  you  may  biff  to  any  tty  you are logged on, that would force
       mailagent to probe the tty for its column size, for each possible tty where output may go,
       and there is no reliable portable way of doing that. Sorry.

EXTENDING FILTERING COMMANDS

       Once  you've reached the expert level, and provided you have a fair knowledge of perl, you
       may feel the need for more advanced commands which are not part of the standard set.  This
       section  explains  how  you  can achieve this dynamically, without the need of diving deep
       inside the source code.

       Once you have extended the filtering command set, you may use those  commands  inside  the
       rule  file as if they were built-in. You may even choose to redefine the standard commands
       if they do not suit you (however, if you wish to do that, you should know exactly what you
       are  doing,  or  you may start losing some mail or get an unexpected behavior -- this also
       voids your warranty :-).

       The ability to provide external commands without actually modifying the main  source  code
       is,  I  believe,  a  strong  point  in favor of having a program written in an interpreted
       language like perl. This of course once you have convinced yourself  that  it  is  a  Good
       Thing to customize and extend a program in the same language as the one used for the core,
       meaning usually a fairly low-level language with fewer user-friendly hooks.

   Overview
       In order to implement a new command, say FOLD, you will need to do the following:

       •    Write a perl subroutine to implement the FOLD action and put that  into  an  external
            file.  Say  we write the subroutine fold and we store that in a fold.pl file. This is
            naturally the difficult part,  where  you  need  to  know  some  basic  things  about
            mailagent internals.

       •    Choose where you want to store your fold.pl file. Then check the syntax with perl -c,
            just to be sure...

       •    Edit the newcmd file (as given by the configuration file) to record your new command.
            Then  make sure this file is tightly protected. You must own it, and it should not be
            writable by any other individual but you.

       •    Additionally, you may want  to  specify  whether  FOLD  is  to  modify  the  existing
            execution  status  and  whether  or  not it will be allowed within the special _SEEN_
            state.

       •    Write some rules using the new FOLD command. This is the easy part!  Note  that  your
            command  may  also  be  used  within perl hooks as if it were a builtin command (this
            means there is an interface function built for you within the mailhook package).

       In the following sections, we're going to describe the syntax  of  the  newcmd  file,  and
       we'll  then  present some low-level internal variables which may be used when implementing
       new commands.

   New Command File Format
       The newcmd file consists of a series of lines, each line  describing  one  command.  Blank
       lines  are  ignored  and  shell-style  comments  introduced by the sharp (#) character are
       allowed.

       Each line is formed by 3 principal fields and 2 optional ones;  fields  are  separated  by
       spaces or tabs. Here is a skeleton:

            <cmd_name> <path> <function> <status_flag> <seen_flag>

       The cmd_name is the name of the command you wish to add. In our previous example, it would
       be FOLD. The next field, path, tells mailagent  where  the  file  containing  the  command
       implementation  is  located. Say we store it in ~/mail/cmds/fold.pl. The function field is
       the name of the perl function implementing FOLD, which may be found in fold.pl.  Here,  we
       named  our  function  fold.  Note  that  if  your  function has its name within the newcmd
       package, which is the default behavior if you do not specify any, then there is no need to
       prefix the function name with the package. Otherwise, you must use a fully qualified name.

       The last two fields are optional, and are boolean values which may be specified by true or
       yes to express truth, and false or no to express falsehood. If status_flag is set to true,
       then  the  command  will modify the last execution status variable.  If seen_flag is true,
       then the command may be used when the filter is in _SEEN_ state. The  default  values  are
       respectively true and false.

       So in our example, we would have written:

            FOLD  ~/mail/cmds/fold.pl  fold  no  yes

       to  allow  FOLD  even  in  _SEEN_ state and have it executed without modifying the current
       value of the last-command-status variable.

   Writing An Implementation
       Your perl function will be loaded when needed into the special package newcmd, so that its
       own  name-space  is  protected  and  does  not  accidentally conflict with other mailagent
       routines or variables. When you need to call the perl interface of some  common  mailagent
       functions, you will have to remember to use the fully qualified routine name, for instance
       &mailhook'leave to actually execute the LEAVE command.

       (Normally, in PERL hooks, there is no need for this prefixing since  the  perl  script  is
       loaded in the mailhook package. When you are extending your mailagent, you should be extra
       careful however, and it does not really hurt to use this prefixing. You are  free  to  use
       the  perl  package directive within your function, hence switching to the mailhook package
       in the body of the routine but leaving its name in the newcmd package.)

       Since mailagent will dynamically load the implementation of your command the first time it
       is  run, by loading the specified perl script into memory and evaluating it, I suggest you
       put each command implementation in a separate file, to avoid storing potentially  unneeded
       code in memory.

       Each  command is called with one argument, namely the full command string as read from the
       filter rules. Additionally, the special @ARGV array is set  by  performing  a  shell-style
       parsing of the command line (which will fail if quotes are mismatched, but then you can do
       the parsing by yourself since you get the command line).  At the end of your routine,  you
       must return a failure status, i.e.  0 for success and 1 to signal failure.

       Those are your only requirements. You are free to do whatever you want inside the routine.
       To ease your task however, some variables are pre-computed for you, the same ones that are
       made  available  within  mail  hooks, only they are defined within the newcmd package this
       time. There are also a few special variables which you need to know about, and  a  set  of
       standard  routines  you  may  want  to  call.  Please avoid calling something which is not
       documented here, since it may change without prior notice. If you would like  to  use  one
       routine and it is not documented in this manual page, please let me know.

       Each  command  is  called from within an eval construct, so you may safely use die or call
       external library routines that use die.  If you use require, be aware  that  mailagent  is
       setting  up  a  special  @INC  array by putting its private library path first, so you may
       place all your mailagent-related library files in this place.

   Special Variables
       The following special variables (some of them  marked  read-only,  meaning  you  shouldn't
       modify  them, and indeed you can't) made available directly within the newcmd package, are
       pre-set by the filter automaton, and are used to control the filtering process:

       $mfile         The base name of the mail file being processed. This variable is read-only.
                      It  is mainly used in log messages, as in [$mfile] to tag each log, since a
                      single mailagent process may deal with multiple messages.

       $ever_saved    This is a boolean, which should be  set  to  1  once  a  successful  saving
                      operation has been completed. If at the end of the filtering, this variable
                      is still 0, then the default LEAVE will be executed.

       $folder_saved  The value of that variable governs the $msgpath  convenience  variable  set
                      for PERL escapes. It is updated whenever a message is written to a file, to
                      hold the path of the written file.

       $cont          This is the continuation status, a variable of the utmost  importance  when
                      dealing  with the control flow. Four constants from the main package can be
                      used  to  specify  whether  we  should  continue  with  the  current   rule
                      ($FT_CONT),  abandon  current rule ($FT_REJECT), restart filtering from the
                      beginning ($FT_RESTART) or simply abort  processing  ($FT_ABORT).  More  on
                      this later.

       $lastcmd       The  last failure status recorded by the last command (among those which do
                      modify the execution status).  You  should  not  have  to  update  this  by
                      yourself unless you are implementing some encapsulation for other commands,
                      like BACK or ONCE, since by default $lastcmd will be set to the  value  you
                      return at the end of the command.

       $wmode         This records the current state of the filter automaton (working mode), in a
                      literal string form, typically modified by the BEGIN command or as  a  side
                      effect, as in REJECT for instance.

       All  the  special  variables  set-up for PERL escapes are also installed within the newcmd
       package. Those are $login, %header, etc... You may peruse them at will.

       Other variables you might have a need  for  are  configuration  parameters,  held  in  the
       ~/.mailagent  configuration  file.  Well,  the rule is simple. The value of each parameter
       param from the configuration file is held in variable $cf'param. Variable $main'loglvl  is
       the  copy  of  $cf'level, since it's always shorter to type in $'loglvl after each call to
       the logging routine &add_log.

       There is one more variable worth knowing about: $main'FILTER, which  is  the  suitable  X-
       Filter  line  that  should be appended in all the mail you send via mailagent, in order to
       avoid loops. Also when you save mails to a folder, it's wise adding this line  in  case  a
       problem arises: you may then identify the culprit.

   Rule Environment
       An  action might have a legitimate desire of altering the environment for the scope of one
       rule only, reverting to the previous value when exiting the rule. Or  you  might  want  to
       change the value forever.

       When  we  speak  about  altering  the  environment,  we  refer  to  the one set up via the
       configuration file, whose values end-up in the cf package.  Well, some of those  variables
       are  copied  in the env package before filtering of a message starts (under the control of
       the @env'Env array).

       All rules should then refer to the version in the env package, and not in the cf  package,
       to  see  alterations. Global changes are made by affecting directly to the variable in the
       env package, while local changes are requested by calling the &env'local routine.

       For instance, the cf'umask value is copied as env'umask because umask is held in @env'Env.
       Global  changes  are  made  by setting that copy directly, while local changes may be made
       with:

                 &env'local('umask', 0722);

       to set-up a new local value. The first time &env'local is called on a variable, its  value
       is  saved somewhere, and will be restored upon exiting the scope of the rule. Then the new
       value is affected to the variable.

       Variables requiring a side effect when their value is changed (such as the umask variable,
       which requires a system call to let the kernel see the change) may specify it by accessing
       the %env'Spec array, the key being the name of the variable requiring a side  effect,  the
       value being interpreted as a bit of perl code ran once the original value is restored. For
       instance, we say somewhere (in &env'init):

                 package env;
                 $Spec{'umask'} = 'umask($umask)';

       to update the kernel view when leaving scope. Note that the side effect is evaluated  once
       the variable has recovered its original value, and within the env package.

       Internally,  the  &analyze_mail routine calls &env'setup before starting its processing to
       initialize the env package, and &env'cleanup at the end before returning.  Before  running
       the  actions  specified  on  a  rule  match,  &apply_rules  calls &env'restore to ensure a
       coherent view of the environment while running the actions for that particular rule.

   Altering Control Flow
       When you want to alter control flow to perform a REJECT, a RESTART or an ABORT,  you  have
       three choices. If you wish to control that action via an option, the same way the standard
       UNIQUE does (with -c, -r or -a), you may call &main'alter_execution(option, state)  giving
       it  two  parameters: the option letter and the state you wish to change to before altering
       the control flow.

       You may also want to directly alter the $wmode and $cont variables, but then  you'll  have
       to   do  your  own  logging  if  you  want  some.  Or  you  may  call  low-level  routines
       &main'do_reject,  &main'do_restart  and  &main'do_abort  to  perform   the   corresponding
       operation (with logging).

       Remember  that  the  _SEEN_ state is special and directly handled at the filter level, and
       the filter begins in the INITIAL state. The default action is to continue with the current
       rule, which is why there is no routine to perform this task.

       The  preferred  way  is  to  invoke  the  mailhook  interface  functions, &mailhook'begin,
       &mailhook'reject, etc..., and  that  will  work  even  if  you  redefine  those  functions
       yourself.  Besides,  that's  the  only  interface which is likely not to be changed by new
       versions.

   General Purpose Routines
       The following is a list of all the general routines you may wish to call  when  performing
       some  low-level  tasks.  Note that this information is version-dependent. Since I document
       them, I'll try to keep them in new versions, but I cannot guarantee I  will  not  have  to
       slightly  change  some  of  their semantics. There is a good chance you will never have to
       worry about that anyway.

       &header'format(rfc822-field)
                 Return a formatted RFC822 field to fit in 78 columns, with proper  continuations
                 introduced by eight spaces.

       &header'normalize(rfc822-header-name)
                 Normalize  case in RFC822 header and return the new header name with every first
                 letter uppercased.

       &header'reset
                 This is part of an RFC822  header  validation,  mainly  used  when  splitting  a
                 digest. This resets the recognition automaton (see &header'valid).

       &header'valid(line)
                 Returns  a  boolean  status,  indicating  if  all the lines given so far to this
                 function since the last &header'reset are part of a valid  RFC822  header.   The
                 function  understands  the  first From line which is part of UNIX mails.  At any
                 time, the variable $header'maybe may be checked to see if so far we  have  found
                 at least one essential mail header field.

       &main'acs_rqst(file)
                 Perform  a  .lock locking on the file, returning 0 on success and -1 on failure.
                 If an old lock was present, it is removed (time limit  set  to  one  hour).  Use
                 &main'free_file to release the lock.

       &main'add_log(string)
                 Add  the string to the logfile. The usual idiom is to postfix that call with the
                 if $'loglvl > value, where value is the logging level you wish  to  have  before
                 emitting that kind of log ($'loglvl is a short form for $main'loglvl).

       &main'free_file(file)
                 Remove  a  .lock on a file, obtained by &main'acs_rqst. It returns 0 if the lock
                 was successfully removed, -1 if it was a stale lock (obtained by someone else).

       &main'header_found(file)
                 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.

       &main'history_record
                 Record the message ID of the current message and return 0 if the message had not
                 been previously seen, 1 if it is a duplicate.

       &main'hostname
                 Return the value of the hostname, lowercased, with possible domain name appended
                 to  it.   The  hostname is cached, since its value must initially be obtained by
                 forking.  (see also &main'myhostname)

       &main'internet_info(email-address)
                 Parse an e-mail internet address and return a three-element array containing the
                 host, the domain and the country part of the internet host. For instance, if the
                 address is user@d.c.b.a, it will return (c, b, a).

       &main'login_name(email-address)
                 Parse the e-mail internet address and return the login name.

       &main'macros_subst(*line)
                 Perform in-place macro substitution (line passed  as  a  type  glob)  using  the
                 information  currently  held  in  the  %main'Header  array.  Do not pass *_ as a
                 parameter, since internally macros_subst uses a local variable bearing that name
                 to perform the substitutions and you would end up with an unmodified version. If
                 you really want  to  pass  *_,  then  you  must  use  the  returned  value  from
                 macros_subst  which  is  the  substituted  text,  but that's less efficient than
                 having it modified in place.

       &main'makedir(pathname, mode)
                 Make directory,  creating  all  the  intermediate  directories  needed  to  make
                 pathname  a  valid directory. Has no effect if the directory already exists. The
                 mode parameter is optional, 0700 is used (octal number) if not specified.

       &main'myhostname
                 Returns the hostname of the current  machine,  without  any  domain  name.   The
                 hostname is cached, since its value must initially be obtained by forking.

       &main'run_command(filter-command)
                 Execute  the single filter command specified and return the continuation status,
                 which should normally be affected to the $cont  variable.  You  will  need  this
                 routine when trying to implement commands which encapsulate other commands, like
                 ONCE or SELECT.

       &main'seconds_in_period(period)
                 Return the number of seconds in the period specified. See section  Specifying  A
                 Period to get valid period strings.

       &main'shell_command(program, input, feedback)
                 Run  a shell command and return a failure status (0 for OK). The input parameter
                 may be one of the following constants (defined in the main  package):  $NO_INPUT
                 to  close  standard  input, $BODY_INPUT to pipe the body of the current message,
                 $MAIL_INPUT to pipe the whole mail as-is, $MAIL_INPUT_BINARY to pipe  the  whole
                 mail  after  having  removed  any content transfer-encoding and $HEADER_INPUT to
                 pipe the message header. The feedback parameter  may  be  one  of  $FEEDBACK  or
                 $NO_FEEDBACK  depending  whether  or  not you wish to use the standard output to
                 alter the corresponding part of the message.  If  no  feedback  is  wanted,  the
                 output  of  the  command  is mailed back to the user.  The $FEEDBACK_ENCODING is
                 handled like $FEEDBACK but will tell mailagent to look at the best suitable body
                 encoding when the input is the whole message.

       &main'parse_address(rfc822-address)
                 Parse  an  RFC822  e-mail address and return a two-elements array containing the
                 internet address and the comment part of that address.

       &main'xeqte(filter-actions)
                 Execute a series of actions separated by the ';' character, calling  run_command
                 to  actually  perform  the  job.  Return  the  continuation  status.   Note that
                 $FT_ABORT will never be returned, since mailagent  usually  stops  after  having
                 executed  one  set of actions, only continuing if it saw an RESTART or a REJECT.
                 What ABORT does is skipping the remaining commands on the line and exiting as if
                 all the commands had been run. You could say xeqte is the equivalent of the eval
                 function in perl, since it interprets a little filter script and returns control
                 to the caller once finished, and ABORT is perl's die.

       You  may  also use the three functions from the extern package which manipulate persistent
       variables (already documented in the section dealing with variables) as well as the  user-
       defined macro routines.

   Example
       Writing  your  own  commands is not easy, since it requires some basic knowledge regarding
       mailagent internals. However, once you are familiar with that,  it  should  be  relatively
       straightforward.

       Here  is  a small example. We want to write a command to bounce back a mail message to the
       original sender, the way sendmail does, with some leading text to explain  what  happened.
       The command would have the following syntax:

            SENDBACK reason

       and  we  would like that command to modify the existing status, returning a failure if the
       mail cannot be bounced back. Since this command actually sends something back, we  do  not
       want it to be executed in the _SEEN_ state.  Here is my implementation (untested):

            sub sendback {
                 local($cmd_line) = @_;
                 local($reason) = join(' ', @ARGV[1..$#ARGV]);
                 unless (open(MAILER, "|/usr/lib/sendmail -odq -t")) {
                      &'add_log("ERROR cannot run sendmail to send message")
                           if $'loglvl;
                      return 1;
                 }
                 print MAILER <<EOF;
            From: mailagent
            To: $header{'Sender'}
            Subject: Returned mail: Mailagent failure
            $main'FILTER

              --- Transcript Of Session

            $reason

              --- Unsent Message Follows

            $header{'All'}
            EOF
                 close MAILER;
                 $ever_saved = 1;    # Don't want it in mailbox
                 $? == 0 ? 0 : 1;    # Failure status
            }

       Assuming  this  command is put into ~/mail/cmds/sendback.pl, the line describing it in the
       newcmd file would be:

            SENDBACK  ~/mail/cmds/sendback.pl  sendback  yes  no

       Now this command may be used freely in any rule, and will  be  logged  as  a  user-defined
       command by the command dispatcher. Who said it was not easy to do? :-)

       Note  the  use  of  the  $ever_saved  variable  to mark the mail as saved once it has been
       bounced. Indeed, should the SENDBACK action be the only one action to be run,  we  do  not
       want  mailagent  to  LEAVE  the  mail in the mailbox because it has never been saved (this
       default behavior being a precaution only -- better safe than sorry).

   Conclusion
       If along the way you imagine some useful commands which could be made part of the standard
       command set, please e-mail them to me and I'll consider integrating them. In the future, I
       would also like to provide a standard library of perl  scripts  to  implement  some  weird
       commands which could be needed in special cases.

       Note  that you may also use the information presented here inside the perl escape scripts.
       Via the require operator, it is easy to get  the  new  command  implementation  into  your
       script  and perform the same task.  You will maybe need to set up @ARGV by yourself if you
       rely on that feature in your command implementation.

       Command extension can also be viewed as a way to reuse some other perl code, the mailagent
       providing  a  fixed and reliable frame and the external program providing the service. One
       immediate extension would be mailing list handling, using this mechanism to interface with
       some mailing list management software written in perl.

GENERIC MAIL SERVER

       One nice thing about mailagent is that it provides you with the basic tools to implement a
       generic mail server. Indeed, via the SERVER command,  you  can  process  a  mail  message,
       extract  and  then  execute  some predefined commands.  For instance, you may implement an
       archive server, or a mailing list manager, etc...

       The major limitation currently is that only  plain  commands  are  accepted,  or  commands
       taking  some additional info as standard input or equivalent. There is no notion of modes,
       with separate command sets for each mode or limited name-space visibility,  at  least  for
       now,  so  it  is  not easy (albeit possible) to implement an ftpmail server, for instance,
       since this implies the notion of mode.

   Overview
       In order to implement a mail server command (say send file, which would send an  arbitrary
       file from the file system in a separate mail message), you need to do the following:

       •    Think  about  the command from a security point of view. Here, the command we want to
            implement is a potentially dangerous one since it can give access to any file on  the
            machine  the individual running mailagent has access to.  So we want to restrict that
            command to a limited number of trusted people, who will be granted the power  to  run
            this command. More on this later.

       •    Choose  whether  you  want to implement the command in perl or in another programming
            language. If you do the latter, your command will be known as a shell command (i.e. a
            command  runnable  directly  from  a  shell),  while in the former case, you have the
            choice of making it appear as a shell command, or have it hooked to the mailagent  in
            which  case  it  is  known as a perl command. In that last case, your command will be
            dynamically loaded into mailagent with all the advantages that brings you.  Here,  we
            are going to write our command as a shell script.

       •    Write  the  command itself. That's the most difficult part in this scheme.  Later on,
            we will see a straightforward implementation of the send command.

       •    Edit the comserver file (defined in your ~/.mailagent) to record  your  new  command.
            Then  make sure this file is tightly protected.  You must own it, and be the only one
            allowed to modify it.

       •    Additionally, you may want to hide some of the arguments in  the  session  transcript
            (more on this later), allow the command to take a flow of data as its standard input,
            assign a path to the command,  etc...   All  those  parameters  take  place  in  your
            comserver file.

       •    Start using the command... which of course is the nicest part in this scheme!

       In the following sections, we'll learn about the syntax of the comserver file, what powers
       are, how the session transcript is built, what the command environment is, etc...

   Builtin Commands Overview
       The mail server has a limited set of builtin commands, dealing  with  user  authentication
       and  command  environment  settings.  User  authentication  is  password  based and is not
       extremely strong since passwords are specified in clear within the  mail  message  itself,
       which could be easily intercepted.

       The  server  maintains  the  notion  of powers. One user may have more than one power at a
       time, each power granting only a limited access to some sensitive area. A few  powers  are
       hardwired in the server, but the user may create new ones when necessary. Those powers are
       software-enforced, meaning the command must check for itself whether is has the  necessary
       power(s) to perform correctly.

       Powers  are  protected by a password and a clearance file. Having the good password is not
       enough, you have to be cleared in order to (ab)use it. The clearance file is a list of  e-
       mail address patterns, using the shell metacharacters scheme, someone being cleared if and
       only if his e-mail address matches at least one of the patterns from the  clearance  file.
       The more use you will make of metacharacters, the weaker this clearance scheme will be, so
       be careful.

       Your commands and the output resulting from their execution is normally mailed back to you
       as a session transcript. For security reasons, passwords are hidden from the command line.
       Likewise, failure to get a power will not indicate whether  you  lacked  authorization  or
       whether your password was bad.

       A  user with the system power is allowed to create new powers, delete other powers, change
       power passwords, and list, remove or change power clearances. This is somehow an important
       power  which  should be detained by a small number of users with very strict clearance (no
       meta-characters in the address, if possible). A good password  should  also  protect  that
       power.

       However, a user with the system power is not allowed to directly get another power without
       specifying its password and being allowed to do so by the associated clearance  file.  But
       it  would  be possible to achieve that indirectly by removing the power and creating a new
       one bearing the same name. In order to control people with the system power and  also  for
       some tricky situation, there is another more god-like power: the root power.

       A  user  with  the  root  power  can do virtually anything, since it instantly grants that
       individual all the powers available on the server (but security). The only  limitation  is
       that  root  cannot remove the root power alone. One needs to specify the security password
       (another hardwired power) in order to proceed. Needless to say, only one individual should
       have  both  root  and security clearance, and only one individual should know the security
       password and be listed in the clearance file. The system power cannot harm  any  of  those
       two  powers.  Eventually,  more  than one user could have the root power, but do not grant
       that lightly...

       Getting the root power is necessary when system has messed with the  system  configuration
       in  an  hopeless way, or when a long atomic sequence of commands has to be issued: root is
       not subject to the maximum number of command that can be issued in one single message.

       In case you think this mailagent feature is dangerous for your account, do not create  the
       root and security powers, and do not write any sensitive commands.

   Builtin Commands Definition
       Now  let's  have a look at those builtin commands. Passwords of sensitive commands will be
       concealed in the session transcript. Some  commands  accept  input  by  reading  the  mail
       message  up to the EOF marker, which is a simple EOF string on a line by itself (analogous
       with shell's here documents).

       addauth power password
                 Add users to clearance file for power.  If  the  power  password  is  given,  no
                 special  power  is  needed, otherwise the system power is required.  For root or
                 security powers, the corresponding power is required, or the  password  must  be
                 specified.  The command reads the standard input up to the EOF marker to get the
                 new users.

       approve password command
                 Records the password in the command environment, then executes the command.   If
                 a power is required and not yet obtained, the command will look for the password
                 in the environment and try to get the relevant power using that password. Hence,
                 approved  command  (with proper password) will transparently execute without the
                 hassle of requesting the power, issuing  the  command  and  then  releasing  the
                 power.  It  is up to the command to perform the approve password test by looking
                 at the approve variable in the command environment (see below). Since  clearance
                 checks  (such  as those performed when requesting a power) are not performed, no
                 sensitive command should ever deal with the approve construct.

       delpower power password [security]
                 Delete a power from the system, and its associated clearance  list.  The  system
                 power  is  required to delete most powers except root and security. The security
                 power may only be deleted by itself and the root power may only be deleted  when
                 the security password is also specified.

       getauth power password
                 Get  current  clearance file for a given power. No special power required if the
                 password is given or the power is already detained. Otherwise, the system  power
                 is  needed  for all powers but root or security where the corresponding power is
                 mandatory.

       newpower power password [alias]
                 Add a new power to the system. The command then reads the  standard  mail  input
                 until  the  EOF  marker  to  get  the  power clearance list. The system power is
                 required to create a new power, unless it's root or security: The security power
                 is required to create root and the root power is required to create security.

       passwd power old new
                 Change  power password. It does not matter if you already hold the corresponding
                 power, you must give the proper old password. See also the password command.

       password power new
                 Change power password. The corresponding power is required, or you have  to  get
                 the  system  power.  To  change  the  root  or  security passwords, you need the
                 corresponding power.

       power name password
                 Ask for a new power. Of course, root does not need  to  request  for  any  other
                 power but security, less give any password. This command is not honored when the
                 server is not in trusted mode, unbeknownst to the user: the error message in the
                 transcript file is no different from the one obtained with an invalid password.

       powers regexp
                 List  all  the  powers  matching  the  perl regular expression, along with their
                 respective clearance file. The system power is required to get  the  list.   The
                 root  or  security  power  are  required  to  get access to the root or security
                 information, respectively.  If no  arguments  are  given,  all  the  powers  are
                 listed.

       release power
                 Get rid of some power.

       remauth power password
                 Remove  users from clearance file, getting the list by reading the standard mail
                 input until the EOF marker. This command does not require any special  power  if
                 the  proper  password  is given or if the power is already detained.  Otherwise,
                 the system power is needed. For root and security clearance,  the  corresponding
                 power is needed as well.

       set variable value
                 Set  the variable to the corresponding value. Useful to alter internal variables
                 like the EOF marker value, or change some command  environment.   The  user  may
                 define  his  own variables for his commands.  For flag-type variable, a value of
                 on, yes or true sets the variable to 1, any other string sets it to  0  (false).
                 Used  all  by  itself  as  set, the list of all the defined variables along with
                 their respective values is returned.

       setauth power password
                 Replace power clearance file with one obtained from standard mail  input  up  to
                 the  EOF mark. The system power is needed unless you specify the proper password
                 or the power is already yours. As usual, root or security clearances can only be
                 changed when the power is detained.

       user [e-mail [command]]
                 Execute command by assuming the e-mail identity specified. Powers are lost while
                 executing the command. The e-mail identity may be checked by the command itself,
                 which  may  impose  further  restrictions  on  the execution, like getting user-
                 defined powers. Note that this command only modifies the global environment, and
                 that  it's  up to the command implementation to make use of that information. If
                 no command is specified, the new identity is assumed until  changed  by  another
                 user  command  and all the powers currently held by the user are released. If no
                 e-mail address is given, the original user ID is restored.

   Command Environment
       There are six types of commands and variables that can be specified in server mode. Two of
       them,  end and help types are special and handled separately. Two types var and flag refer
       to variables and the last two types perl and shell refer to commands.

       Whenever mailagent fires a server command, it sets up an environment for that command:  if
       it  is  a  perl-type  command,  then  a  set  of perl variables are set before loading the
       command; if it is a shell-type command, some environment  variables  are  initialized  and
       file descriptor #3 is set up to point directly to the mailagent session transcript.

       A shell-type command is forked, whilst a perl-type command is loaded directly in mailagent
       within the cmdenv package. This operates much like the PERL filtering  command,  only  the
       target package differs and a distinct set of variables is preset.

       Some  commands  collect additional data up to an end-of-file marker (by default the string
       EOF on a line by itself) and those data are fed to shell commands via stdin  and  to  perl
       commands via the @buffer variable set up in the environment package named cmdenv (in which
       the command is loaded and run).

       If you define your own variables (types var or flag), you may use the builtin set  command
       to  modify  their  values.  Note  that no default value can be provided when defining your
       variable. A suitable default value must be set within commands making use  of  them,  with
       the advantage that different default values may be used by different commands.

       The  following  environment  variables  are  defined.  Most are read-only, unless notified
       otherwise, in which case the builtin set command may be used on them.

       approve   The approve password for approve commands, empty if not within a builtin approve
                 construct.

       auth      A  flag  set  to true when a valid envelope was found in the mail message.  When
                 this flag is false, the server cannot be put in trusted mode.

       cmd       The command line, as written in the message.

       collect   Internal flag set to true while collecting input from a  here-document.   It  is
                 normally reset to false before calling the command.

       debug     True when debug mode is activated (may be set).

       disabled  A  comma  separated list of disabled commands, with no space between them.  This
                 is initialized when the SERVER command is invoked and the -d option is used.

       eof       The current end-of-file marker for here-document commands.  By  default  set  to
                 'EOF' (may be changed).

       errors    Number of errors so far.

       jobnum    The job number assigned to the current mailagent.

       log       What was logged in the transcript, with some args possibly concealed.

       name      The command name.

       pack      Packing mode for file sending (may be set).

       path      Destination address for file sending or notification (may be set).

       powers    A  colon  (:)  separated  list  of  powers  the  user currently has successfully
                 requested and got.

       requests  Number of requests processed so far.

       trace     True when shell commands want to be traced in transcript (may be set).

       trusted   True when server is in trust mode, where powers may be gained. This is activated
                 by  the  -t  option  of  the  SERVER command, provided a valid mail envelope was
                 found.

       uid       Address of the sender of the  message,  where  transcript  is  to  be  sent.  By
                 extension,  the  real  user  ID  for  the server, which is the base of the power
                 clearance mechanism.

       user      The effective user ID, originally the same as the uid, but may  be  changed  via
                 the user builtin command.

   Session Transcript
       A  session  transcript  is  mailed  back  automatically to the user who requested a server
       access. This transcript shows the commands ran by the user and their status: OK or FAILED.
       Between  those two lines, the transcript show any output explicitly made by the command to
       the transcript. Typically, the transcript may be used to forward error  messages  back  to
       the  user,  but  even  commands executing correctly may want to issue an explicit message,
       stating what has just been done.

       A perl command may access the transcript via the MAILER file handle, defined in the cmdenv
       package, whilst a shell command may access it via its file descriptor #3.

       Note  that the session transcript is mailed to the sender of the message, i.e. whoever the
       envelope header line says it is. As far as the server is concerned, this e-mail address is
       used  as  the  user ID, just like a plain login name can be thought of as the user id. For
       sensitive commands, authentication based on  that  information  is  really  weak.  A  more
       "secure"  authentication  is  provided  by  the  server  powers,  which is password-based.
       Unfortunately, the clear password has to be transmitted in the message itself and could be
       eavesdropped.

   Recording New Commands and Variables
       Server  commands  and  variables  are  defined  in  the  comserver  file  defined  in your
       ~/.mailagent. The format of the file is that of a table with items on a row  separated  by
       tabs  characters.  Each  line defines one command or variable. Any irrelevant field may be
       entered as a single '-' (minus) character. The format allows for shell-style (#) comments.

       Each row has the following fields:

            name type hide collect-data path extra

       where:

       name           is the name of the command or variable as recognized by the server.

       type           is one of perl, shell, var, flag, help or end.

       hide           indicates which arguments in the command are to be hidden (the command name
                      being  argument  zero)  in  the session transcript. Use '-' if no arguments
                      need to be hidden. Typically, this is  used  to  hide  clear  passwords  in
                      commands.   If  more  than  one  argument  has to be hidden, then a list of
                      numbers separated by a ',' (comma) may be specified, with no spaces between
                      them. For instance '2,4' would hide arguments 2 and 4 in the transcript.

       collect-data   is  a  flag  (specify  as either 'y' or 'n', but you may use complete words
                      'yes' or 'no') indicating whether the command collects additional data in a
                      here-document  until  the EOF marker. Alternatively, you may specify '-' in
                      place of 'n'.

       path           specifies the path of the command  (~name  substitution  allowed).  If  not
                      relevant  (e.g.  when  defining  a  variable)  or when you want to leave it
                      blank, use '-'.  If a blank path is specified for a perl or shell  command,
                      then the implementation of that command is expected to be found in servdir,
                      as defined in ~/.mailagent. If the command name is cmd for  instance,  then
                      perl  command  are  expected  there  in a file named cmd of cmd.pl, whereas
                      shell commands are expected to be found in a cmd of cmd.sh file. Note  that
                      a  command  is  disabled  if it cannot be located at the time the comserver
                      file is parsed.

       extra          is any extra parameter needed for the command. Unlike  other  fields,  this
                      should  be  left blank if not needed. Anything up to the end of the line is
                      grabbed by this field. Perl commands should specify the name  of  the  perl
                      function  to call to execute the command; if none is specified, the name of
                      the command itself is called. Shell commands may use that field  to  supply
                      additional options, which will be inserted right after the command name and
                      before any other user-supplied arguments. Others should leave this alone.

   Special Command Types
       There are currently two special command types.

       The simplest is the end type. This is used to specify commands which may  end  the  server
       processing.  By  default,  processing  continues until the end of the file is reached or a
       signature delimiter '--' is found. For instance, you may wish to define the  command  quit
       and  give  it  the  end  type.   As  soon  as  the  server reaches that command, it aborts
       processing and discards the remaining of the message.

       The help type is usually attached to an help command and prints help on a  command  basis,
       help  for  each  command  being  stored  under  the  helpdir  variable  (defined  in  your
       ~/.mailagent) in a file bearing the same name as the command itself. For example, assuming
       a  command  shoot,  its  help file would be expected in helpdir/shoot. If no file is found
       there, mailagent looks in its public library  (/usr/share/mailagent)  for  an  help  file.
       Help is provided only when the help file exists and is not zero-sized.

   Creating the Root Power
       In  order to bootstrap the server, you need to create the root power. All the other powers
       may then be created by using the server interface, which ensures consistency and logs your
       actions. If you don't plan using powers at all, you may skip that section.

       First, you need to pick up a good password for the root power. Someone with the root power
       can do virtually anything with the server, so be careful. Let's assume  you  choose  root-
       pass as a password.

       Edit passwd (defined in your ~/.mailagent) and add the following line:

            root:<root-pass>:

       i.e. enter the password in clear between '<' and '>'. It won't stay in that form for long,
       but this is the easiest way to bootstrap it. Protect the passwd file  tightly  (read-write
       permissions  only  for you). Then create a powerdir/root file, protect it the same way and
       add your e-mail address to it, on a line by itself. That must be  the  address  that  will
       show  up  in  the  From:  line  of  your  mails. Since clearance files support shell-style
       patterns, you may use login@*domain.top to allow mails from your login from any machine in
       your domain.

       You are almost done. Now simply issue the following command:

            mailagent -i -e 'SERVER -t'

       and feed its standard input with:

            From your e-mail address
            From: your e-mail address

            power root root-pass
            password root root-pass
            ^D

       Note  that  the  first  From  line  is  mandatory  here,  since it's the envelope on which
       authentication is based. Since we're feeding mailagent with  an  handcrafted  message,  we
       must provide a valid envelope or the server will not switch into trusted mode...

       The  side effect of re-instantiating your password will be to crypt it in the passwd file,
       so that anybody looking at that file cannot guess your root password, hopefully.

       Once you have a valid root power installed, you may  create  the  system  power  by  using
       newpower. Further powers may then be created and deleted using the system power only.

       You  should  also create the security power and give it a different password than the root
       password. This is really needed only if you wish to remotely administrate the  server.  If
       you  have  local  access and things get corrupted, it's always possible to change the root
       password manually by repeating this bootstrapping sequence.

       Note that clearance checks are made using the envelope address of the message, which is  a
       little  harder  to forge than plain header fields like Sender:.  The envelope is extracted
       by looking at the first header line, which on Unix systems looks like:

                 From envelope-address send-date

       and is inserted by the mail transport agent (MTA). If you are using sendmail as  the  MTA,
       then  only  trusted  users  declared  in  the sendmail.cf file are able to create a "fake"
       envelope address, a feature typically used by mailing list dispatchers, since that address
       is  then  used  as  the bounce target in case the mail cannot be delivered.  If that first
       header line is absent, the sender is computed using the Sender: field if present, then the
       From:  field,  but  the  auth variable is set to false and the server will not switch into
       trusted mode; in other words, it will not be possible to gain powers in that session.

       Moreover, since the session transcript is sent to  that  same  envelope  address  used  to
       authenticate  the  eligibility  for  a  power,  the  server  feature can hardly be used to
       retrieve confidential information held at the site where the mailagent is  run  since  the
       information  would  be  sent  to  one  of  the  users  cleared  for  that power. It is the
       responsibility of you, the user, to make sure this cannot happen or  you  could  get  into
       legal troubles.

       Finally,  sensitive  commands should be protected by a proper power, and great care should
       be taken  in  writing  the  command  implementation  to  ensure  the  security  cannot  be
       circumvented.  But  no,  this  mailagent  feature  is not believed to be dangerous for the
       system or site it is used on, since a determined user could implement one trivially via  a
       five  line  shell script.  If security is really an issue, .forward files using the piping
       feature should be prohibited and access to cron forbidden in order to avoid automatic mail
       processing  (since  it  would  be possible to have cron invoke a mailagent process -or any
       other program for that matter- to process the incoming mail in a comparable way).

   Example
       Here is an example showing the steps involved in creating a  shell  command,  which  would
       take  a  script  by  collecting  lines  until  an EOF mark and feed it to a real shell for
       execution. Since allowing this feature without any safeguards would  be  a  real  security
       hole, we protect that by requesting the power shell before allowing the execution.

       Here  is  my  implementation of the shell command (available in the mailagent distribution
       under misc/shell):

            #!/bin/sh

            # Execute commands from stdin, as transmitted by the mailagent server.
            # File descriptor #3 is a channel to the session transcript.

            # Make sure we have the shell power.
            # Don't even allow the root power to bypass that for security reasons.
            case ":$powers:" in
            *:shell:*) ;;
            *)
                 echo "Permission denied." >&3
                 exit 1
                 ;;
            esac

            # Perhaps a shell was defined... Otherwise, use /bin/sh
            case "$shell" in
            '') shell='/bin/sh';;
            esac

            # Normally, a shell command has its output included in the transcript only in
            # case of error or when the user requests the trace. Here however, we need to
            # see what happened, so everything is redirected to the session transcript.

            exec $shell -x >&3 2>&3

       Note how we make access to the $powers and $shell environment variable. That last  one  is
       user-defined to allow dynamic set-up of a shell.

       Assuming  we  store that command under servdir/shell.sh (don't forget to add the execution
       bit on the file...), here is how we declare it and its variable in the comserver file.

            shell     shell     -    y    -
            shell     var  -    -    -

       This example shows that there  is  a  separate  name-space  for  variables  and  commands.
       Moreover, the command bears the same name as its type -- don't let that confuse you :-).

       Now,  assuming  you  have  already created a system power and protected it with a password
       (let's assume sys-pass for the purpose of this example), you  need  to  create  the  shell
       power.  Although you could do it manually (like when you handcrafted the root power), it's
       better to use the SERVER interface since it ensures consistency.

       In order to create the shell power required to use the newly created  shell  command,  you
       need to add the following rule to your rule file:

            Subject: Server          { SAVE server; SERVER -t };

       which  will  save  all  server  mail  in  a dedicated folder and process them. Note the -t
       option, which allows trusted mode, in which powers may be gained.  Now send  yourself  the
       following mail:

            Subject: Server
            power system sys-pass
            newpower shell shell-pass
            ram@acri.fr
            EOF

       which  requests  for  the system power (needed to created most powers), and then creates a
       new power shell, assigning shell-pass as its password and  clearing  ram@acri.fr  for  it.
       Note  the here-document fill-in for the newpower command, up to the EOF marker. Of course,
       you need to replace the address by your real address.

       You will receive a session transcript along these lines:

                ---- Mailagent session transcript for ram@acri.fr ----

            ----> power system ********
            OK.

            ====> newpower shell ********
            OK.

            ====> --
            End of processing (.signature)

                ---- End of mailagent session transcript ----

       Note the concealed passwords, and the  prompt  change  once  the  system  power  has  been
       granted. Since my mailer automatically appends a signature, the processing stops on it.

       Now let's use this new command... Send yourself the following mail:

            Subject: Server
            set shell /bin/ksh
            set eof END
            shell
            ls -l /etc/passwd
            END
            power shell shell-pass
            shell
            ls -l /etc/passwd
            END

       If you everything is right, you should receive back a transcript looking like this:

                ---- Mailagent session transcript for ram@acri.fr ----

            ----> set shell /bin/ksh
            OK.

            ----> set eof END
            OK.

            ----> shell
            Permission denied.
            Command returned a non-zero status (1).
            FAILED.

            ----> power shell ********
            OK.

            ====> shell
            + ls -l /etc/passwd
            -rw-r--r--   1 root     system       691 Oct 01 14:24 /etc/passwd
            OK.

            ====> --
            End of processing (.signature)

                ---- End of mailagent session transcript ----

       The  first invocation of the shell command fails since we lack the shell power. The string
       "Permission denied." is echoed by the command itself into file descriptor #3 and makes  it
       to the transcript.

   Conclusion
       The  generic  mail server implemented in mailagent can be used to implement a mailing list
       manager, a vote server, an archive server, etc...  Unfortunately, it  does  not  currently
       have  the  notion  of  state,  with  a  command  set dedicated to each state, so it is not
       possible to implement an intelligent archive server.

       If you implement new simple server commands  and  feel  they  are  generic  enough  to  be
       contributed, please send them to me and I will gladly integrate them.

EXAMPLES

       Here are some examples of rule files. First, if you do not specify a rule file or if it is
       empty, the following built-in rule applies:

            All: /^Subject: [Cc]ommand/ { LEAVE; PROCESS };

       Every mail is left in the mailbox. Besides, mail with "Subject: Command" anywhere  in  the
       message are processed.

       The following rule file is the one I am currently using:

            maildir = ~/mail;

            All: /^Subject: [Cc]ommand/   { SAVE cmds; PROCESS };

            To: /^gue@eiffel.fr/          { POST -l mail.gue };
            Apparently-To: ram,
            Newsgroups: mail.gue          { BOUNCE gue@eiffel.fr };

            <_SEEN_>
                 Apparently-To: ram,
                 Newsgroups: mail.gue     { DELETE };

            From: root, To: root          { BEGIN ROOT; REJECT };
            <ROOT> /^Daily run output/    { WRITE ~/var/log/york/daily.%D };
            <ROOT> /^Weekly run output/   { WRITE ~/var/log/york/weekly };
            <ROOT> /^Monthly run output/  { WRITE ~/var/log/york/monthly };

            From: ram      { BEGIN RAM; REJECT };
            <RAM> To: ram       { LEAVE };
            <RAM> X-Mailer: /mailagent/   { LEAVE };
            <RAM>               { DELETE };

       The  folder  directory  is  set  to  ~/mail.  All  command  mails  are saved in the folder
       ~/mail/cmds and processed. They do not show up in my mailbox. Mails directed  to  the  gue
       mailing  list  (French  Eiffel's  Users  Group, namely Groupe des Utilisateurs Eiffel) are
       posted on the local newsgroup mail.gue and do not appear in my mailbox either. Any follow-
       up  made  on  this  group  is mailed to me by inews (and not directly to the mailing list,
       because those mails would get back to me again and be fed to the newsgroup, which in  turn
       would  have  them  mailed back to the list, and so on, and so forth).  Hence the next rule
       which catches those follow-ups and bounces them to the  mailing  list.  Those  mails  will
       indeed come back, but the _SEEN_ rule will simply delete them.

       On  my machine, the mails for root are forwarded to me. However, everyday, the cron daemon
       starts some processes to do some administration clean-up (rotating log files, etc...), and
       mails  the results back. They are redirected into specific folders with the WRITE command,
       to ensure they do not grow up without limit. Note the macro  substitution  for  the  daily
       output (on Mondays, the output is stored in daily.1 for instance).

       The  next  group  of rules prevents the mail system from sending back mails when I am in a
       group alias expansion. This is a sendmail option which I disabled on my machine.  Care  is
       taken  however  to  keep mails coming from the mailagent which I receive as a blind carbon
       copy.

CAVEAT

       In order to limit the load overhead on the system, only one mailagent process  is  allowed
       to  run  the  commands.  If some new mail arrives while another mailagent is running, that
       mail is queued and will be processed later by the main mailagent.

       For the same reason, messages sent back by mailagent are queued by sendmail, to avoid  the
       cost of mail transfer while processing commands.

SECURITY

       First,  let  me  discuss  what security means here. It does not mean system safety against
       intruder attacks. If your system allows .forward hooks and/or  cron  jobs  to  be  set  by
       regular  users, then your system is not secure at all. Period. So we're not bothering with
       security at the system level, but rather at your own  account  level  where  all  sort  of
       precious data is held.

       To  avoid  any  pernicious intrusion via Trojan horses, the C filter will refuse to run if
       the configuration file ~/.mailagent or the rule file specified are world writable  or  not
       owned  by  the  user.  Those  tests  are  enforced even if the filter does not run setuid,
       because they compromise the security of your account.  The  mailagent  will  also  perform
       some of those checks, in case it is not invoked via the C filter.

       Indeed,  if  someone can write into your ~/.mailagent file, then he can easily change your
       rules configuration parameter to point to another faked rule file  and  then  send  you  a
       mail,  which  will  trigger mailagent, running as you. Via the RUN command, this potential
       intruder could run any command, using your privileges, and could set a  Trojan  horse  for
       later perusal. Applying the same logic, the rule file must also be protected tightly.

       And,  no  surprise,  the  same rules apply for your newcmd file, which is used to describe
       extended filtering commands. Otherwise it  would  allow  someone  to  quietly  redefine  a
       commonly used standard command like LEAVE and later be able to assume your identity.

       Versions  after  3.0  PL44  come with an improved (from a security point of view) C filter
       that will not only perform the aforementionned checks but will also ensure that  the  perl
       executable  and  the  mailagent script it is about to exec are not loosely protected (when
       execsafe is ON or when running with superuser privileges).  Furthermore, if the filter  is
       set up in your .forward as described in this man page, it will be able to check itself for
       safety and will warn you loundly if it can  be  tampered  with,  which  could  defeat  all
       security checks.

       Mailagent  was also extended so that all programs executed via RUN and friends, as well as
       mail hooks, are checked for obvious protection flaws before being actually run Interpreted
       scripts (starting with the #! magic token) and perl scripts following the magic "exec perl
       if $under_shell" incantation are specially checked for further security  of  the  relevant
       interpretor.  Those  checks  are  performed  systematically  (when  execsafe is ON or when
       running with superuser privileges) even if the secure parameter was not set to  ON.  Also,
       all  files about to be exec()ed are checked using the same extended check method used when
       secure is ON (ownership tests are skipped however  when  checking  for  exec()-ness  of  a
       file).

FILES

       ~/.mailagent        configuration file for mailagent.
       ~/agent.trace       trace dump from a PROCESS command when error cannot be mailed back.
       ~/mbox.filter       mailbox used by filter in case of error
       ~/mbox.urgent       mailbox used by mailagent in case of error
       ~/mbox.<username>   mailbox used if writing access is denied in the mail spool directory
       /usr/share/mailagent/mailagent
                           directory holding templates and samples.
       Log/agentlog        mailagent's log file.
       Spool/agent.wait    list   of  mails  waiting  to  be  processed  and  stored  outside  of
                           mailagent's queue directory. Even when logically empty, this  file  is
                           kept  around  and still holds one blank line to reserve a block on the
                           filesystem.
       Queue/qmXXXXX       mail spooled by filter.
       Queue/fmXXXXX       mail spooled by mailagent.
       Queue/cmXXXXX       mail spooled by the AFTER command.
       Hash/X/Y            hash files used by RECORD, UNIQUE, ONCE commands and vacation mode.

BUGS

       There is a small chance that mail arrives while the main mailagent is about to finish  its
       processing.  That  mail  will  be queued and not processed until another mail arrives (the
       main mailagent always processes the queue after having dealt with the message that invoked
       it).

       A version number must currently contain a dot. Moreover, an old system (i.e. a system with
       an o in the patches column) must have a version number, so that mailagent can compute  the
       name of the directory holding the patches.

       The  lock  file  is  deliberately  ignored  when -q option is used (in fact, it is ignored
       whenever an option is specified).  This may result in having  mails  processed  more  than
       once.

       Mailagent  is  at  the  mercy of any perl bug, and there is little I can do about it. Some
       spurious warnings may be emitted by the data-loaded version, although they do  not  appear
       with the plain version.

       Parsing  of the rule file should be done by a real parser and not lexically.  Or at least,
       it should be possible to escape otherwise meaningful characters like ';' or '}' within the
       rules.

AUTHOR

       Raphael Manfredi <Raphael_Manfredi@pobox.com>.

SEE ALSO

       maildist(1), mailhelp(1), maillist(1), mailpatch(1), perl(1).

                                          Version 3.1-81                             MAILAGENT(1)