Provided by: mimedefang_2.64-6_i386 bug

NAME

       mimedefang-filter - Configuration file for MIMEDefang mail filter.

DESCRIPTION

       mimedefang-filter  is  a  Perl fragment that controls how mimedefang.pl
       disposes of various parts of a MIME message.  In addition, it  contains
       some   global   variable   settings   that   affect  the  operation  of
       mimedefang.pl.

CALLING SEQUENCE

       Incoming messages are scanned as follows:

       1) A temporary working directory is created.  It is  made  the  current
       working  directory  and  the e-mail message is split into parts in this
       directory.  Each part is  represented  internally  as  an  instance  of
       MIME::Entity.

       2)  If  the file /etc/mail/mimedefang-filter.pl defines a Perl function
       called filter_begin, it is called with a single argument consisting  of
       a  MIME::Entity  representing  the  parsed  e-mail message.  Any return
       value is ignored.

       3) For each leaf part of the mail message, filter is called  with  four
       arguments: entity, a MIME::Entity object; fname, the suggested filename
       taken  from  the  MIME  Content-Disposition  header;  ext,   the   file
       extension,  and  type,  the MIME Content-Type value.  For each non-leaf
       part of the mail message, filter_multipart is called with the same four
       arguments  as  filter.   A  non-leaf  part  of a message is a part that
       contains nested parts.  Such a part has no useful body, but you  should
       still  perform  filename checks to check for viruses that use malformed
       MIME  to  masquerade  as  non-leaf  parts  (like  message/rfc822).   In
       general, any action you perform in filter_multipart applies to the part
       itself and any contained parts.

       Note that both filter and filter_multipart are optional.  If you do not
       define  them, a default function that simply accepts each part is used.

       4) After all parts have been  processed,  the  function  filter_end  is
       called  if  it  has  been  defined.   It  is  passed  a single argument
       consisting of the (possibly modified) MIME::Entity object  representing
       the message about to be delivered.

DISPOSITION

       mimedefang.pl  examines  each  part  of  the MIME message and chooses a
       disposition for that part.  (A disposition is selected by  calling  one
       of the following functions from filter and then immediately returning.)
       Available dispositions are:

       action_accept
              The  part  is  passed  through  unchanged.   If  no  disposition
              function is returned, this is the default.

       action_accept_with_warning
              The  part is passed through unchanged, but a warning is added to
              the mail message.

       action_drop
              The part is deleted without any notification to the  recipients.

       action_drop_with_warning
              The  part is deleted and a warning is added to the mail message.

       action_replace_with_warning
              The part is deleted and instead replaced with a text message.

       action_quarantine
              The part is deleted and a warning is added to the mail  message.
              In  addition,  a copy of the part is saved on the mail server in
              the directory /var/spool/MIMEDefang and a notification  is  sent
              to the MIMEDefang administrator.

       action_bounce
              The  entire  e-mail message is rejected and an error returned to
              the sender.  The intended recipients  are  not  notified.   Note
              that  in  spite of the name, MIMEDefang does not generate and e-
              mail a failure notification.  Rather, it causes the SMTP  server
              to return a 5XX SMTP failure code.

       action_discard
              The  entire  e-mail  message is discarded silently.  Neither the
              sender nor the intended recipients are notified.

CONTROLLING RELAYING

       You can define a function called filter_relay  in  your  filter.   This
       lets  you  reject SMTP connection attempts early on in the SMTP dialog,
       rather than waiting until the whole message has been sent.   Note  that
       for this check to take place, you must use the -r flag with mimedefang.

       filter_relay is passed two arguments: $hostip is the IP address of  the
       relay  host  (for example, "127.0.0.1"), and $hostname is the host name
       if known (for example, "localhost.localdomain") If the host name  could
       not  be  determined,  $hostname is $hostip enclosed in square brackets.
       (That is, ("$hostname" eq "[$hostip]") will be true.)

       filter_relay must return  a  two-element  list:  ($code,  $msg).   $msg
       specifies  the  text  message to use for the SMTP reply, but because of
       limitations in the  Milter  API,  this  message  is  for  documentation
       purposes only---you cannot set the text of the SMTP message returned to
       the SMTP client from filter_relay.

       $code is a literal string, and can have one of the following values:

       â€â€™REJECTâ€â€™
              if the connection should be rejected.

       â€â€™CONTINUEâ€â€™
              if the connection should be accepted.

       â€â€™TEMPFAILâ€â€™
              if a temporary failure code should be returned.

       â€â€™DISCARDâ€â€™
              if the message should be accepted and silently discarded.

       â€â€™ACCEPT_AND_NO_MORE_FILTERINGâ€â€™
              if the connection should be accepted and  no  further  filtering
              done.

       Earlier versions of MIMEDefang used -1 for TEMPFAIL, 0 for REJECT and 1
       for CONTINUE.  These values still work, but are deprecated.

       In the case of REJECT or TEMPFAIL, $msg specifies the text part of  the
       SMTP reply.  $msg must not contain newlines.

       For example, if you wish to reject connection attempts from any machine
       in the spammer.com domain, you could use this function:

       sub filter_relay {
            my ($ip, $name) = @_;
            if ($name =~ /spammer\.com$/) {
                 return (’REJECT’, "Sorry; spammer.com is blacklisted");
            }
            return (’CONTINUE’, "ok");
       }

FILTERING BY HELO

       You can define a function called filter_helo in your filter.  This lets
       you reject connections after the HELO/EHLO SMTP command.  Note that for
       this function to be called, you must use the -H flag with mimedefang.

       filter_helo is passed three arguments: $ip and $name are the IP address
       and name of the sending relay, as in filter_relay.  The third argument,
       $helo, is the argument supplied in the HELO/EHLO command.

       filter_helo must return  a  two-to-five  element  list:  ($code,  $msg,
       $smtp_code,  $smtp_dsn, $delay).  $code is a return code, with the same
       meaning as the $code return from filter_relay.  $msg specifies the text
       message  to  use  for  the SMTP reply.  If $smtp_code and $smtp_dsn are
       supplied, they become the SMTP numerical reply code  and  the  enhanced
       status  delivery  code  (DSN code).  If they are not supplied, sensible
       defaults are used.  $delay specifies a delay in seconds; the  C  milter
       code  will  sleep  for  $delay  seconds  before  returning the reply to
       Sendmail.  $delay defaults to zero.

       (Note that the delay is implemented  in  the  Milter  C  code;  if  you
       specify  a  delay of 30 seconds, that doesn’t mean a Perl slave is tied
       up for the duration of the delay.  The  delay  only  costs  one  Milter
       thread.)

FILTERING BY SENDER

       You  can  define  a function called filter_sender in your filter.  This
       lets you reject messages from  certain  senders,  rather  than  waiting
       until  the  whole  message  has been sent.  Note that for this check to
       take place, you must use the -s flag with mimedefang.

       filter_sender is passed four arguments:  $sender is the envelope e-mail
       address  of  the sender (for example, "<dfs@roaringpenguin.com>").  The
       address may or may not be surrounded by angle brackets.  $ip and  $name
       are  the IP address and host name of the SMTP relay.  Finally, $helo is
       the argument to the SMTP "HELO" command.

       Inside filter_sender, you can  access  any  ESMTP  arguments  (such  as
       "SIZE=12345")  in  the  array @ESMTPArgs.  Each ESMTP argument occupies
       one array element.

       filter_sender must return a two-to-five element  list,  with  the  same
       meaning as the return value from filter_helo.

       For  example,  if  you wish to reject messages from spammer@badguy.com,
       you could use this function:

       sub filter_sender {
            my ($sender, $ip, $hostname, $helo) = @_;
            if ($sender =~ /^<?spammer\@badguy\.com>?$/i) {
                 return (’REJECT’, ’Sorry; spammer@badguy.com is blacklisted.’);
            }
            return (’CONTINUE’, "ok");
       }

       As another example, some spammers identify their own  machine  as  your
       machine  in  the  SMTP "HELO" command.  This function rejects a machine
       claiming to be in the "roaringpenguin.com" domain unless it really is a
       Roaring Penguin machine:

       sub filter_sender {
         my($sender, $ip, $hostname, $helo) = @_;
         if ($helo =~ /roaringpenguin.com/i) {
           if ($ip ne "127.0.0.1" and
               $ip ne "216.191.236.23" and
               $ip ne "216.191.236.30") {
                 return(’REJECT’, "Go away... $ip is not in roaringpenguin.com");
           }
         }
         return (’CONTINUE’, "ok");
       }

       As  a  third  example, you may wish to prevent spoofs by requiring SMTP
       authentication when email is  sent  from  some  email  addresses.  This
       function  rejects  mail  from "king@example.com", unless the connecting
       user properly authenticated as "elvisp". Note that this needs access to
       the  %SendmailMacros  global,  that  is  not available in filter_sender
       until after a call to read_commands_file.

       sub filter_sender {
               my($sender, $ip, $hostname, $helo) = @_;
               read_commands_file();
               ### notice: This assumes The King uses authentication without realm!
               if ($sender =~ /^<?king\@example\.com>?$/i and
                   $SendmailMacros{auth_authen} ne "elvisp") {
                       return(’REJECT’, "Faking mail from the king is not allowed.");
               }
               return (’CONTINUE’, "ok");
       }

FILTERING BY RECIPIENT

       You can define a function called filter_recipient in your filter.  This
       lets  you  reject  messages  to certain recipients, rather than waiting
       until the whole message has been sent.  Note that  for  this  check  to
       take place, you must use the -t flag with mimedefang.

       filter_recipient  is passed nine arguments:  $recipient is the envelope
       address of the recipient and $sender is the envelope e-mail address  of
       the  sender  (for  example, "<dfs@roaringpenguin.com>").  The addresses
       may or may not be surrounded by angle brackets.  $ip and $name are  the
       IP  address  and  host  name of the SMTP relay.  $first is the envelope
       address of the first recipient for  this  message,  and  $helo  is  the
       argument  to  the  SMTP  "HELO"  command.   The  last  three arguments,
       $rcpt_mailer, $rcpt_host and $rcpt_addr are the Sendmail  mailer,  host
       and  address  triple for the recipient address.  For example, for local
       recipients, $rcpt_mailer is likely to  be  "local",  while  for  remote
       recipients, it is likely to be "esmtp".

       Inside  filter_recipient,  you  can access any ESMTP arguments (such as
       "NOTIFY=never") in the array @ESMTPArgs.  Each ESMTP argument  occupies
       one array element.

       filter_recipient   must   return   a  two-to-five  element  list  whose
       interpretation is the same as for filter_sender.  Note,  however,  that
       if  filter_recipient returns ’DISCARD’, then the entire message for all
       recipients is discarded.  (It doesn’t really make sense, but that’s how
       Milter works.)

       For  example,  if  you wish to reject messages from spammer@badguy.com,
       unless  they  are  to  postmaster@mydomain.com,  you  could  use   this
       function:

       sub filter_recipient {
            my ($recipient, $sender, $ip, $hostname, $first, $helo,
                   $rcpt_mailer, $rcpt_host, $rcpt_addr) = @_;
            if ($sender =~ /^<?spammer\@badguy\.com>?$/i) {
                 if ($recipient =~ /^<?postmaster\@mydomain\.com>?$/i) {
                      return (’CONTINUE’, "ok");
                 }
                 return (’REJECT’, ’Sorry; spammer@badguy.com is blacklisted.’);
            }
            return (’CONTINUE’, "ok");
       }

INITIALIZATION AND CLEANUP

       Just before a slave begins processing messages, mimedefang.pl calls the
       functions filter_initialize (if it is defined) with no  arguments.   By
       the  time  filter_initialize  is  called,  all the other initialization
       (such as setting up syslog facility and priority) has been done.

       If you are not using an embedded Perl interpreter, then  performing  an
       action  inside  filter_initialize is practically the same as performing
       it directly in  the  filter  file,  outside  any  function  definition.
       However,  if  you are using an embedded Perl interpreter, then anything
       you call directly from outside a function definition is  executed  once
       only  in the parent process.  Anything in filter_initialize is executed
       once per slave.  If you use any  code  that  opens  a  descriptor  (for
       example,  a  connection  to  a database server), you must run that code
       inside filter_initialize and not directly from the filter, because  the
       multiplexor  closes all open descriptors when it activates a new slave.

       When a slave  is  about  to  exit,  mimedefang.pl  calls  the  function
       filter_cleanup (if it is defined) with no arguments.  This function can
       do whatever cleanup you like, such  as  closing  file  descriptors  and
       cleaning   up  long-lived  slave  resources.   The  return  value  from
       filter_cleanup becomes the slave’s exit status.

       If filter_cleanup takes longer than 10 seconds to  run,  the  slave  is
       sent  a  SIGTERM  signal.   If  that  doesn’t  kill  it (because you’re
       catching signals, perhaps), then a further 10 seconds later, the  slave
       is sent a SIGKILL signal.

CONTROLLING PARSING

       If   you  define  a  function  called  filter_create_parser  taking  no
       arguments, then mimedefang.pl will call it  to  create  a  MIME::Parser
       object for parsing mail messages.

       Filter_create_parser is expected to return a MIME::Parser object (or an
       instance of a class derived from MIME::Parser).

       You  can  use  filter_create_parser  to  change  the  behavior  of  the
       MIME::Parser used by mimedefang.pl.

       If  you  do not define a filter_create_parser function, then a built-in
       version equivalent to this is used:

            sub filter_create_parser () {
                 my $parser = MIME::Parser->new();
                 $parser->extract_nested_messages(1);
                 $parser->extract_uuencode(1);
                 $parser->output_to_core(0);
                 $parser->tmp_to_core(0);
                 return $parser;
            }

EXTENDING MIMEDEFANG

       The man page for mimedefang-protocol(7) lists commands that are  passed
       to  slaves  in  server  mode (see "SERVER COMMANDS".)  You can define a
       function called filter_unknown_cmd to extend the set of  commands  your
       filter can handle.

       If you define filter_unknown_cmd, it is passed the unknown command as a
       single argument.  It should return a list of values  as  follows:   The
       first  element  of  the  list must be either "ok" or "error:" (with the
       colon.)   The  remaining  arguments  are  percent-encoded.    All   the
       resulting  pieces are joined together with a single space between them,
       and the resulting string passed back as the reply to the multiplexor.

       For example, the following function will make your filter  reply  to  a
       "PING" command with "PONG":

       sub filter_unknown_cmd ($) {
           my($cmd) = @_;
           if ($cmd eq "PING") {
               return("ok", "PONG");
           }
           return("error:", "Unknown command");
       }

       You can test this filter by typing the following as root:

       md-mx-ctrl PING

       The response should be:

       ok PONG

       If  you extend the set of commands using filter_unknown_cmd, you should
       make all your commands start with an upper-case letter to avoid clashes
       with future built-in commands.

REJECTING UNKNOWN USERS EARLY

       A very common mail setup is to have a MIMEDefang machine act as an SMTP
       proxy, accepting and scanning mail and then relaying  it  to  the  real
       mail  server.   Unfortunately,  this  means that the MIMEDefang machine
       cannot know if a local address is valid or not, and  will  forward  all
       mail  for  the  appropriate domains.  If a mail comes in for an unknown
       user, the MIMEDefang machine  will  be  forced  to  generate  a  bounce
       message when it tries to relay the mail.

       It’s  often  desirable  to  have the MIMEDefang host reply with a "User
       unknown" SMTP response directly.  While this can be done by copying the
       list  of local users to the MIMEDefang machine, MIMEDefang has a built-
       in function called md_check_against_smtp_server  for  querying  another
       relay host:

       md_check_against_smtp_server($sender,  $recip,  $helo,  $server, $port)
       This
              function  connects  to  the  SMTP server $server and pretends to
              send mail from $sender to $recip.  The return value is always  a
              two-element array.  If the RCPT TO: command succeeds, the return
              value is ("CONTINUE", "OK").  If the RCPT fails with a permanent
              failure, the return value is ("REJECT", $msg), where $msg is the
              message  from  the  SMTP  server.    Any   temporary   failures,
              connection errors, etc. result in a return value of ("TEMPFAIL",
              $msg).

              The optional argument $port specifies the TCP  port  to  connect
              to.   If it is not supplied, then the default SMTP port of 25 is
              used.

       Suppose the machine filter.domain.tld is filtering  mail  destined  for
       the   real   mail   server   mail.domain.tld.    You   could   have   a
       filter_recipient function like this:

       sub filter_recipient
       {
           my($recip, $sender, $ip, $host, $first, $helo,
              $rcpt_mailer, $rcpt_host, $rcpt_addr) = @_;
           return md_check_against_smtp_server($sender, $recip,
                                "filter.domain.tld",
                                "mail.domain.tld");
       }

       For each RCPT TO: command,  MIMEDefang  opens  an  SMTP  connection  to
       mail.domain.tld and checks if the command would succeed.

       Please  note  that  you should only use md_check_against_smtp_server if
       your mail server responds with a failure code for nonexistent users  at
       the  RCPT  TO: level.  Also, this function may impose too much overhead
       if you receive a lot of e-mail, and it will generate  lots  of  useless
       log  entries  on  the  real  mail  server  (because of all the RCPT TO:
       probes.)  It may also significantly increase the load on the real  mail
       server.

GLOBAL VARIABLES YOU CAN SET

       The following Perl global variables should be set in mimedefang-filter:

       $AdminAddress
              The e-mail address of the MIMEDefang administrator.

       $DaemonAddress
              The   e-mail   address    from    which    MIMEDefang-originated
              notifications come.

       $AddWarningsInline
              If this variable is set to 0, then all MIMEDefang warnings (such
              as created by action_quarantine or action_drop_with_warning) are
              collected  together  and  added  in  a separate MIME part called
              WARNING.TXT.  If the variable is set to 1, then the warnings are
              added  directly  in  the first text/plain and text/html parts of
              the message.  If the message does not contain any text/plain  or
              text/html  parts,  then  a  WARNING.TXT  MIME  part  is added as
              before.

       $MaxMIMEParts
              A message containing many MIME parts can  cause  MIME::Tools  to
              consume  large  amounts  of  memory and bring your system to its
              knees.  If you set $MaxMIMEParts to a positive number, then MIME
              parsing  is  terminated  for  messages  with more than that many
              parts, and the message is bounced.  In this case, none  of  your
              filter functions is called.

              By  default,  $MaxMIMEParts  is  set  to -1, meaning there is no
              limit on the number of parts in a message.  Note that  in  order
              to  use  this  variable,  you  must  install the Roaring Penguin
              patched version of MIME::Tools, version 5.411a-RP-Patched-02  or
              newer.

       $Stupidity{"NoMultipleInlines"}
              Set  this  to 1 if your e-mail is too stupid to display multiple
              MIME parts in-line.  In this case, a nasty hack causes the first
              part  of  the  original  message  to  appear as an attachment if
              warning are issued.  Mail clients that are not this  stupid  are
              Netscape  Communicator  and  Pine.  On the other hand, Microsoft
              Exchange and Microsoft Outlook are indeed this stupid.   Perhaps
              users of those clients should switch.

              The  following  global variables may optionally be set.  If they
              are not set, sensible defaults are used:

       $AddApparentlyToForSpamAssassin
              By default, MIMEDefang tries to pass SpamAssassin a message that
              looks  exactly  like  one  it  would receive via procmail.  This
              means adding a Received: header, adding a Message-ID  header  if
              necessary,  and  adding  a  Return-Path:  header.   If  you  set
              $AddApparentlyToForSpamAssassin to 1, then MIMEDefang also  adds
              an Apparently-To: header with all the envelope recipients before
              passing the message to  SpamAssassin.   This  lets  SpamAssassin
              detect possibly whitelisted recipient addresses.

              The default value for $AddApparentlyToForSpamAssassin is 0.

       $SyslogFacility
              This  specifies  the logging facility used by mimedefang.pl.  By
              default, it is set to "mail",  but  you  can  set  it  to  other
              possibilites.   See  the  openlog(3)  man page for details.  You
              should name facilities  as  all-lowercase  without  the  leading
              "LOG_".  That is, use "local3", not "LOG_LOCAL3".

       $WarningLocation (default 0)
              If set to 0 (the default), non-inline warnings are placed first.
              If  you  want  the  warning  at  the  end  of  the  e-mail,  set
              $WarningLocation to -1.

       $DaemonName (default "MIMEDefang")
              The full name used when MIMEDefang sends out notifications.

       $AdminName (default "MIMEDefang Administrator")
              The full name of the MIMEDefang administrator.

       $SALocalTestsOnly (default 1)
              If set to 1, SpamAssassin calls will use only local tests.  This
              is the default and recommended setting.  This disables Received,
              RBL  and Razor tests in an all or nothing fashion.  To use Razor
              this MUST be set to 0.  You can add ’skip_rbl_checks 1’ to  your
              SpamAssassin config file if you need to.

       $NotifySenderSubject (default "MIMEDefang Notification")
              The    subject    used    when    e-mail    is   sent   out   by
              action_notify_sender().  If you set this, you should set it each
              time you call action_notify_sender() to ensure consistency.

       $NotifyAdministratorSubject (default "MIMEDefang Notification")
              The    subject    used    when    e-mail    is   sent   out   by
              action_notify_administrator().  If you set this, you should  set
              it  each  time  you call action_notify_administrator() to ensure
              consistency.

       $QuarantineSubject (default "MIMEDefang Quarantine Report")
              The subject used  when  a  quarantine  notice  is  sent  to  the
              administrator.  If you set this, you should set it each time you
              call action_quarantine() or  action_quarantine_entire_message().

       $NotifyNoPreamble (default 0)
              Normally,  notifications  sent  by action_notify_sender() have a
              preamble warning about message modifications.   If  you  do  not
              want this, set $NotifyNoPreamble to 1.

       $CSSHost (default 127.0.0.1:7777:local)
              Host and port for the Symantec CarrierScan Server virus scanner.
              This takes the form ip_addr:port:local_or_nonlocal.  The ip_addr
              and  port  are  the host and port on which CarrierScan Server is
              listening.  If you want to scan local files,  append  :local  to
              force  the  use  of the AVSCANLOCAL command.  If the CarrierScan
              Server is on another host, append :nonlocal to  force  the  file
              contents to be sent to the scanner over the socket.

       $SophieSock (default /var/spool/MIMEDefang/sophie)
              Socket     used     for     Sophie     daemon    calls    within
              message_contains_virus_sophie  and  entity_contains_virus_sophie
              unless a socket is provided by the calling routine.

       $ClamdSock (default /var/spool/MIMEDefang/clamd.sock)
              Socket     used     for     clamd     daemon     calls    within
              message_contains_virus_clamd   and   entity_contains_virus_clamd
              unless a socket is provided by the calling routine.

       $TrophieSock (default /var/spool/MIMEDefang/trophie)
              Socket     used     for     Trophie    daemon    calls    within
              message_contains_virus_trophie and entity_contains_virus_trophie
              unless a socket is provided by the calling routine.

FILTER

       The  heart  of  mimedefang-filter  is  the  filter  procedure.  See the
       examples that came with MIMEDefang to learn to  write  a  filter.   The
       filter is called with the following arguments:

       $entity
              The  MIME::Entity  object.   (See  the  MIME::tools  Perl module
              documentation.)

       $fname The suggested attachment filename, or "" if none was supplied.

       $ext   The file extension (all characters from the rightmost period  to
              the end of the filename.)

       $type  The MIME type (for example, "text/plain".)

       The filename is derived as follows:

       o      First, if the Content-Disposition header has a "filename" field,
              it is used.

       o      Otherwise, if the Content-Type header has a "name" field, it  is
              used.

       o      Otherwise, the Content-Description header value is used.

       Note  that  the truly paranoid will check all three fields for matches.
       The functions re_match  and  re_match_ext  perform  regular  expression
       matches  on  all  three  of the fields named above, and return 1 if any
       field matches.  See  the  sample  filters  for  details.   The  calling
       sequence is:

            re_match($entity, "regexp")
            re_match_ext($entity, "regexp")

       re_match  returns  true if any of the fields matches the regexp without
       regard to case.  re_match_ext returns true  if  the  extension  in  any
       field  matches.   An extension is defined as the last dot in a name and
       all remaining characters.

       A third function called re_match_in_zip_directory will look inside  zip
       files  and  return true if any of the file names inside the zip archive
       match the regular expression.  Call it like this:

            my $bh = $entity->bodyhandle();
            my $path = (defined($bh)) ? $bh->path() : undef;
            if (defined($path) and re_match_in_zip_directory($path, "regexp")) {
                # Take action...
            }

       You should not call re_match_in_zip_directory unless you know that  the
       entity is a zip file attachment.

GLOBAL VARIABLES SET BY MIMEDEFANG.PL

       The  following  global  variables  are  set  by  mimedefang.pl  and are
       available for use in your filter.  All of these  variables  are  always
       available to filter_begin, filter, filter_multipart and filter_end.  In
       addition, some of them are available in filter_relay, filter_sender  or
       filter_recipient.  If this is the case, it will be noted below.

       %Features
              This  hash  lets  you  determine  at  run-time  whether  certain
              functionality is available.  This hash is available at all times
              assuming  the  detect_and_load_perl_modules()  function has been
              called.  The defined features are:

              $Features{"SpamAssassin"} is 1 if SpamAssassin 1.6 or better  is
              installed; 0 otherwise.

              $Features{"HTMLCleaner"}   is   1   if   Anomy::HTMLCleaner   is
              installed; 0 otherwise.

              $Features{"HTML::Parser"} is 1 if HTML::Parser is  installed;  0
              otherwise.

              $Features{"Virus:FPROTD"} is currently always 0.  Set it to 1 in
              your filter file if you have F-Risk’s FPROTD scanner.

              $Features{"Virus:SymantecCSS"} is currently always 0.  Set it to
              1  in  your  filter  file  if  you have the Symantec CarrierScan
              Server virus scanner.

              $Features{"Virus:NAI"} is the full path to NAI uvscan if  it  is
              installed; 0 if it is not.

              $Features{"Virus:BDC"} is the full path to Bitdefender bdc if it
              is installed; 0 if it is not.

              $Features{"Virus:NVCC"} is the full path to Norman Virus Control
              nvcc if it is installed; 0 if it is not.

              $Features{"Virus:HBEDV"}  is  the full path to H+BEDV AntiVir if
              it is installed; 0 if it is not.

              $Features{"Virus:VEXIRA"} is the full path  to  Central  Command
              Vexira if it is installed; 0 if it is not.

              $Features{"Virus:SOPHOS"} is the full path to Sophos sweep if it
              is installed; 0 if it is not.

              $Features{"Virus:SAVSCAN"} is the full path to Sophos savscan if
              it is installed; 0 if it is not.

              $Features{"Virus:CLAMAV"}  is  the full path to Clam AV clamscan
              if it is installed; 0 if it is not.

              $Features{"Virus:AVP"} is the full path to AVP AvpLinux if it is
              installed; 0 if it is not.

              $Features{"Virus:AVP5"}   is   the   full   path   to  Kaspersky
              "aveclient" if it is installed; 0 if it is not.

              $Features{"Virus:CSAV"} is the full path to Command csav  if  it
              is installed; 0 if it is not.

              $Features{"Virus:FSAV"}  is the full path to F-Secure fsav if it
              is installed; 0 if it is not.

              $Features{"Virus:FPROT"} is the full path to F-Risk f-prot if it
              is installed; 0 if it is not.

              $Features{"Virus:SOPHIE"}  is  the  full path to Sophie if it is
              installed; 0 if it is not.

              $Features{"Virus:CLAMD"} is the full path  to  clamd  if  it  is
              installed; 0 if it is not.

              $Features{"Virus:TROPHIE"}  is the full path to Trophie if it is
              installed; 0 if it is not.

              $Features{"Virus:NOD32"} is the full path to ESET NOD32 nod32cli
              if it is installed; 0 if it is not.

              NOTE:  Perl-module based features (SpamAssassin and HTMLCleaner)
              are determined at runtime and may change as these are added  and
              removed.   Most  Virus features are predetermined at the time of
              configuration and do not adapt to  runtime  availability  unless
              changed by the filter rules.

       $CWD   This  variable  holds  the  working  directory  for  the current
              message.  During filter processing, mimedefang.pl  chdir’s  into
              this  directory  before  calling  any  of the filter_ functions.
              Note that this variable is set correctly  in  filter_sender  and
              filter_recipient, but not in filter_relay.

       $SuspiciousCharsInHeaders
              If  this  variable  is  true,  then  mimedefang  has  discovered
              suspicious characters in message  headers.   This  might  be  an
              exploit  for bugs in MIME-parsing routines in some badly-written
              mail user agents (e.g. Microsoft Outlook.)   You  should  always
              drop such messages.

       $SuspiciousCharsInBody
              If  this  variable  is  true,  then  mimedefang  has  discovered
              suspicious characters in the message body.   This  might  be  an
              exploit  for bugs in MIME-parsing routines in some badly-written
              mail user agents (e.g. Microsoft Outlook.)   You  should  always
              drop such messages.

       $RelayHostname
              The  host  name of the relay.  This is the name of the host that
              is attempting to send e-mail to your host.  May  be  "undef"  if
              the  host  name  could  not  be  determined.   This  variable is
              available in filter_relay, filter_sender and filter_recipient.

       $RelayAddr
              The IP address of the sending relay (as a string  consisting  of
              four  dot-separated  decimal  numbers.)   One  potential  use of
              $RelayAddr is to limit mailing to certain lists to people within
              your  organization.  This variable is available in filter_relay,
              filter_sender and filter_recipient.

       $Helo  The argument given to the SMTP "HELO" command.  This variable is
              available  in  filter_sender  and  filter_recipient,  but not in
              filter_relay.

       $Subject
              The contents of the "Subject:" header.

       $Sender
              The sender of the e-mail.  This variable is set in filter_sender
              and filter_recipient.

       @Recipients
              A list of the recipients.  In filter_recipient, it is set to the
              single  recipient  currently  under  consideration.  Or,   after
              calling  read_commands_file within filter_recipient, the current
              recipient under consideration is in the final  position  of  the
              array,  at  $Recipients[-1],  while  any previous (and accepted)
              recipients are at the  beginning  of  the  array,  that  is,  in
              @Recipients[0 .. $#Recipients-1].

       $MessageID
              The  contents  of  the  "Message-ID:"  header if one is present.
              Otherwise, contains the string "NOQUEUE".

       $QueueID
              The  Sendmail  queue  identifier  if  it  could  be  determined.
              Otherwise,  contains  the string "NOQUEUE". This variable is set
              correctly in filter_sender and filter_recipient, but it  is  not
              available in filter_relay.

       $MsgID Set  to $QueueID if the queue ID could be determined; otherwise,
              set to $MessageID.  This identifier should be used  in  logging,
              because  it  matches  the  identifier  used  by  Sendmail to log
              messages.   Note  that  this  variable  is  set   correctly   in
              filter_sender  and  filter_recipient, but it is not available in
              filter_relay.

       $VirusScannerMessages
              Each time a virus-scanning function is called, messages (if any)
              from  the  virus  scanner are accumulated in this variable.  You
              can use it in filter_end to formulate  a  notification  (if  you
              wish.)

       $VirusName
              If  a  virus-scanning function found a virus, this variable will
              hold the virus name (if it could be determined.)

       $SASpamTester
              If defined, this is  the  configured  Mail::SpamAssassin  object
              used  for  mail  tests.   It  may  be initialized with a call to
              spam_assassin_init which also returns it.

       %SendmailMacros
              This hash contains the values of some Sendmail macros.  The hash
              elements  exist  only  for  macros defined by Sendmail.  See the
              Sendmail documentation for the meanings of the macros.

              By default,  mimedefang  passes  the  values  of  the  following
              macros:  ${daemon_name},  ${if_name},  ${if_addr},  $j,  $_, $i,
              ${tls_version},  ${cipher},   ${cipher_bits},   ${cert_subject},
              ${cert_issuer},   ${auth_type},   ${auth_authen},   ${auth_ssf},
              ${auth_author}, ${mail_mailer}, ${mail_host} and ${mail_addr}.

              If any macro is not set or not passed  to  milter,  it  will  be
              unavailable.  To access the value of a macro, use:

                   $SendmailMacros{"macro_name"}

              Do  not  place  curly  brackets  around  the  macro  name.  This
              variable is  available  in  filter_sender  and  filter_recipient
              after a call to read_commands_file.

       @SenderESMTPArgs
              This array contains all the ESMTP arguments supplied in the MAIL
              FROM: command.  For example:

              sub print_sender_esmtp_args {
                  foreach (@SenderESMTPArgs) {
                      print STDERR "Sender ESMTP arg: $_0;
                  }
              }

       %RecipientESMTPArgs
              This hash contains all the ESMTP arguments supplied in each RCPT
              TO: command.  For example:

              sub print_recip_esmtp_args {
                  foreach my $recip (@Recipients) {
                      foreach(@{$RecipientESMTPArgs{$recip}}) {
                          print STDERR "Recip ESMTP arg for $recip: $_0;
                      }
                  }
              }

       %RecipientMailers
              This hash contains the Sendmail "mailer-host-address" triple for
              each recipient.  Here’s an example of how to use it:

              sub print_mailer_info {
                  my($recip, $mailer, $host, $addr);
                  foreach $recip (@Recipients) {
                      $mailer = ${RecipientMailers{$recip}}[0];
                      $host = ${RecipientMailers{$recip}}[1];
                      $addr =  ${RecipientMailers{$recip}}[2];
                      print STDERR "$recip: mailer=$mailer, host=$host, addr=$addr\n";
                  }
              }

              In filter_recipient, this  variable  by  default  only  contains
              information  on  the  recipient  currently  under investigation.
              Information  on  all  recipients  is  available  after   calling
              read_commands_file.

ACTIONS

       When  the  filter procedure decides how to dispose of a part, it should
       call one or more action_ subroutines.  The action subroutines are:

       action_accept()
              Accept the part.

       action_rebuild()
              Rebuild the mail body, even if mimedefang thinks no changes were
              made.   Normally,  mimedefang  does  not  alter  a message if no
              changes were made.  action_rebuild  may  be  used  if  you  make
              changes  to  entities  directly (by manipulating the MIME::Head,
              for example.)  Unless you call action_rebuild,  mimedefang  will
              be unaware of the changes.  Note that all the built-in action...
              routines that change a message implicitly call action_rebuild.

       action_add_header($hdr, $val)
              Add a header to the message.  This can be used  in  filter_begin
              or  filter_end.   The  $hdr component is the header name without
              the colon, and the $val is the header value.   For  example,  to
              add the header:

                   X-MyHeader: A nice piece of text

              use:

                   action_add_header("X-MyHeader", "A nice piece of text");

       action_change_header($hdr, $val, $index)
              Changes  an  existing header in the message. This can be used in
              filter_begin or filter_end.  The $hdr parameter  is  the  header
              name  without  the  colon, and $val is the header value.  If the
              header does not exist, then a header with  the  given  name  and
              value is added.

              The  $index  parameter  is  optional;  it defaults to 1.  If you
              supply it, then  the  $index’th  occurrence  of  the  header  is
              changed,  if  there  is more than one header with the same name.
              (This is common with the Received: header, for example.)

       action_insert_header($hdr, $val, $index)
              Add a header to the message int the specified  position  $index.
              A  position  of  0 specifies that the header should be prepended
              before existing headers.  This can be used  in  filter_begin  or
              filter_end.   The  $hdr component is the header name without the
              colon, and the $val is the header value.

       action_delete_header($hdr, $index)
              Deletes an existing header in the message. This can be  used  in
              filter_begin  or  filter_end.   The $hdr parameter is the header
              name without the colon.

              The $index parameter is optional; it  defaults  to  1.   If  you
              supply  it,  then  the  $index’th  occurrence  of  the header is
              deleted, if there is more than one header with the same name.

       action_delete_all_headers($hdr)
              Deletes all headers with the specified name.  This can  be  used
              in filter_begin or filter_end.  The $hdr parameter is the header
              name without the colon.

       action_drop()
              Drop the part.   If  called  from  filter_multipart,  drops  all
              contained parts also.

       action_drop_with_warning($msg)
              Drop  the  part, but add the warning $msg to the e-mail message.
              If called from filter_multipart, drops all contained parts also.

       action_accept_with_warning($msg)
              Accept the part, but add the warning $msg to the e-mail message.

       action_replace_with_warning($msg)
              Drop the part and replace it with a text part $msg.   If  called
              from filter_multipart, drops all contained parts also.

       action_replace_with_url($entity, $doc_root, $base_url, $msg, [$cd_data,
       $salt])
              Drop the part, but save it in a unique location under $doc_root.
              The part is replaced with the text  message  $msg.   The  string
              "_URL_"  in  $msg is replaced with $base_url/something, that can
              be used to retrieve the message.

              You should not use this function in filter_multipart.

              This action is intended for stripping large  parts  out  of  the
              message  and  replacing  them to a link on a Web server.  Here’s
              how you would use it in filter():

              $size = (stat($entity->bodyhandle->path))[7];
              if ($size > 1000000) {
                   return action_replace_with_url($entity,
                        "/home/httpd/html/mail_parts",
                        "http://mailserver.company.com/mail_parts",
                        "The attachment was larger than 1,000,000 bytes.\n" .
                        "It was removed, but may be accessed at this URL:\n\n" .
                        "\t_URL_\n");
              }

              This example moves attachments greater than 1,000,000 bytes into
              /home/httpd/html/mail_parts  and replaces them with a link.  The
              directory  should  be   accessible   via   a   Web   server   at
              http://mailserver.company.com/mail_parts.

              The  generated  name is created by performing a SHA1 hash of the
              part and adding the extension to the ASCII-HEX representation of
              the  hash.   If  many  different  e-mails are sent containing an
              identical large part, only one  copy  of  the  part  is  stored,
              regardless of the number of senders or recipients.

              For  privacy  reasons,  you must turn off Web server indexing in
              the directory in which you place mail parts, or anyone  will  be
              able  to  read them.  If indexing is disabled, an attacker would
              have to guess the SHA1 hash of a part in order to read it.

              Optionally, a fifth argument can supply data to be saved into  a
              hidden  dot filename based on the generated name.  This data can
              then be read in on the fly by a CGI script  or  mod_perl  module
              before  serving  the  file  to  a  web  client,  and used to add
              information to the response, such as Content-Disposition data.

              A sixth optional argument, $salt, is mixed in to the SHA1  hash.
              This  salt  can  be  any string and should be kept confidential.
              The salt is designed to prevent people from guessing whether  or
              not  a particular attachment has been received on your server by
              altering the SHA1 hash calculation.

       action_defang($entity, $name, $fname, $type)
              Accept the part, but change its name  to  $name,  its  suggested
              filename  to  $fname  and  its  MIME type to $type.  If $name or
              $fname are "", then mimedefang.pl generates generic  names.   Do
              not use this action in filter_multipart.

              If  you  use  action_defang, you must define a subroutine called
              defang_warning  in  your  filter.   This   routine   takes   two
              arguments:  $oldfname  (the  original name of an attachment) and
              $fname (the defanged  version.)   It  should  return  a  message
              telling the user what happened.  For example:

              sub defang_warning {
                  my($oldfname, $fname) = @_;
                  return "The attachment ’$oldfname’ was renamed to ’$fname’\n";
              }

       action_external_filter($entity, $cmd)
              Run  an  external UNIX command $cmd.  This command must read the
              part from  the  file  ./FILTERINPUT  and  leave  the  result  in
              ./FILTEROUTPUT.   If  the command executes successfully, returns
              1, otherwise 0.  You can test the return value and call  another
              action_  if  the  filter  failed.   Do  not  use  this action in
              filter_multipart.

       action_quarantine($entity, $msg)
              Drop and quarantine the part, but add the warning $msg to the e-
              mail message.

       action_quarantine_entire_message($msg)
              Quarantines  the entire message in a quarantine directory on the
              mail server, but does not otherwise affect  disposition  of  the
              message.   If  "$msg"  is  non-empty,  it  is  included  in  any
              administrator notification.

       action_sm_quarantine($reason)
              Quarantines a message in the Sendmail mail queue using  the  new
              QUARANTINE  facility  of  Sendmail  8.13.   Consult the Sendmail
              documentation for details  about  this  facility.   If  you  use
              action_sm_quarantine  with  a version of Sendmail that lacks the
              QUARANTINE facility, mimedefang will log an  error  message  and
              not quarantine the message.

       action_bounce($reply, $code, $dsn)
              Reject  the entire e-mail message with an SMTP failure code, and
              the one-line error message $reply.  If the  optional  $code  and
              $dsn  arguments  are  supplied,  they specify the numerical SMTP
              reply code and the extended status  code  (DSN  code).   If  the
              codes  you  supply  do  not  make  sense  for a bounce, they are
              replaced with "554" and "5.7.1" respectively.

              action_bounce merely makes a note that  the  message  is  to  be
              bounced;  remaining parts are still processed.  If action_bounce
              is called for more than one part, the mail is bounced  with  the
              message  in the final call to action_bounce.  You can profitably
              call action_quarantine followed by action_bounce if you want  to
              keep a copy of the offending part.  Note that the message is not
              bounced immediately; rather, remaining parts are  processed  and
              the message is bounced after all parts have been processed.

              Note  that  despite  its name, action_bounce does not generate a
              "bounce message".  It merely rejects the message  with  an  SMTP
              failure code.

              WARNING: action_bounce() may cause the sending relay to generate
              spurious bounce messages if the sender address is  faked.   This
              is  a particular problem with viruses.  However, we believe that
              on balance, it’s better to  bounce  a  virus  than  to  silently
              discard it.  It’s almost never a good idea to hide a problem.

       action_tempfail($msg, $code, $dsn)
              Cause  an  SMTP  "temporary failure" code to be returned, so the
              sending mail relay requeues the message and tries  again  later.
              The  message  $msg  is included with the temporary failure code.
              If the optional $code and  $dsn  arguments  are  supplied,  they
              specify  the  numerical  SMTP reply code and the extended status
              code (DSN code).  If the codes you supply do not make sense  for
              a  temporary  failure,  they are replaced with "450" and "4.7.1"
              respectively.

       action_discard()
              Silently  discard  the  message,  notifying  nobody.   You   can
              profitably  call action_quarantine followed by action_discard if
              you want to keep a copy of the offending part.   Note  that  the
              message  is  not  discarded immediately; rather, remaining parts
              are processed and the message is discarded after all parts  have
              been processed.

       action_notify_sender($message)
              This action sends an e-mail back to the original sender with the
              indicated message.  You may call another action after this  one.
              If  action_notify_sender  is called more than once, the messages
              are accumulated into a single e-mail  message  --  at  most  one
              notification  message is sent per incoming message.  The message
              should be terminated with a newline.

              The notification is delivered in deferred mode; you should run a
              client-queue runner if you are using Sendmail 8.12.

              NOTE:  Viruses  often fake the sender address.  For that reason,
              if a virus-scanner has detected a virus, action_notify_sender is
              disabled  and will simply log an error message if you try to use
              it.

       action_notify_administrator($message)
              This action e-mails the MIMEDefang  administrator  the  supplied
              message.    You   may   call  another  action  after  this  one;
              action_notify_administrator does not affect mail processing.  If
              action_notify_administrator   is  called  more  than  once,  the
              messages are accumulated into a single e-mail message -- at most
              one  notification  message  is  sent  per incoming message.  The
              message should be terminated with a newline.

              The notification is delivered in deferred mode; you should run a
              client-queue runner if you are using Sendmail 8.12.

       anomy_clean_html($entity, {"name" => val , ...})
              If     you     have    the    Anomy    mail    cleaning    tools
              (http://mailtools.anomy.net)  and  have  installed   the   Anomy
              modules in a standard Perl include directory, this function uses
              an Anomy::HTMLCleaner  object  to  sanitize  the  HTML  code  in
              $entity,   which   assumed   to   be  of  type  text/html.   The
              configuration  arguments  are  optional;  possible  values   are
              documented  in comments in the Anomy/HTMLCleaner.pm Perl module.

       append_text_boilerplate($entity, $boilerplate, $all)
              This action should only be called from filter_end.   It  appends
              the  text  "\n$boilerplate\n"  to  the first text/plain part (if
              $all is 0) or to all text/plain parts (if $all is 1).

       append_html_boilerplate($entity, $boilerplate, $all)
              This action should only be called from filter_end.  It adds  the
              text  "\n$boilerplate\n" to the first text/html part (if $all is
              0) or to all text/html parts (if  $all  is  1).   This  function
              tries  to  be  smart  about  inserting  the boilerplate; it uses
              HTML::Parser to detect closing tags and inserts the  boilerplate
              before  the  </body>  tag if there is one, or before the </html>
              tag if there is no </body>.  If there is no </body>  or  </html>
              tag, it appends the boilerplate to the end of the part.

              Do not use append_html_boilerplate unless you have installed the
              HTML::Parser Perl module.

              Here is an example  illustrating  how  to  use  the  boilerplate
              functions:

                   sub filter_end {
                        my($entity) = @_;
                        append_text_boilerplate($entity,
                             "Lame text disclaimer", 0);
                        append_html_boilerplate($entity,
                             "<em>Lame</em> HTML disclaimer", 0);
                   }

       action_add_part($entity,  $type, $encoding, $data, $fname, $disposition
       [, $offset])
              This  action  should only be called from the filter_end routine.
              It adds a new part  to  the  message,  converting  the  original
              message to mutipart if necessary.  The function returns the part
              so that additional mime attributes may be set on it.  Here’s  an
              example:

                   sub filter_end {
                        my($entity) = @_;

                        action_add_part($entity, "text/plain", "-suggest",
                                  "This e-mail does not represent" .
                                  "the official policy of FuBar, Inc.\n",
                                  "disclaimer.txt", "inline");
                      }

              The  $entity  parameter  must  be  the  argument  passed  in  to
              filter_end.  The $offset parameter is optional; if  omitted,  it
              defaults  to  -1,  which  adds the new part at the end.  See the
              MIME::Entity man page and the add_part member function  for  the
              meaning of $offset.

              Note  that  action_add_part  tries  to  be more intelligent than
              simply calling $entity->add_part.  The decision  process  is  as
              follows:

       o      If  the  top-level  entity  is multipart/mixed, then the part is
              simply added.

       o      Otherwise,  a  new  top-level   multipart/mixed   container   is
              generated,  and  the original top-level entity is made the first
              part of the multipart/mixed container.  The  new  part  is  then
              added to the multipart/mixed container.

USEFUL ROUTINES

       mimedefang.pl  includes  some  useful  functions you can call from your
       filter:

       detect_and_load_perl_modules()
              Unless you really know what you’re doing, this function must  be
              called first thing in your filter file.  It causes mimedefang.pl
              to detect and load  Perl  modules  such  as  Mail::SpamAssassin,
              Net::DNS, etc., and to populate the %Features hash.

       send_quarantine_notifications()
              This  function  should  be called from filter_end.  If any parts
              were quarantined, a  quarantine  notification  is  sent  to  the
              MIMEDefang  administrator.   Please note that if you do not call
              send_quarantine_notifications, then no quarantine  notifications
              are sent.

       get_quarantine_dir()
              This  function  returns  the  full  path  name of the quarantine
              directory.  If you have not yet quarantined  any  parts  of  the
              message,  a  quarantine  directory  is  created and its pathname
              returned.

       change_sender($sender)
              This function changes the envelope sender to  $sender.   It  can
              only  be called from filter_begin or any later function.  Please
              note that this function is only supported  with  Sendmail/Milter
              8.14.0  or  newer.   It  has  no  effect if you’re running older
              versions.

       add_recipient($recip)
              This function adds $recip to the list of envelope recipients.  A
              copy of the message (after any modifications by MIMEDefang) will
              be sent to $recip in addition to the original recipients.   Note
              that  add_recipient  does  not  modify the @Recipients array; it
              just makes a note to Sendmail to add the recipient.

       delete_recipient($recip)
              This function deletes $recip from the list of recipients.   That
              person  will  not  receive  a  copy  of the mail.  $recip should
              exactly  match  an  entry   in   the   @Recipients   array   for
              delete_recipient() to work.  Note that delete_recipient does not
              modify the @Recipients array; it just makes a note  to  Sendmail
              to delete the recipient.

       resend_message($recip1, $recip2, ...)
              or

       resend_message(@recips)
              This  function immediately resends the original, unmodified mail
              message to each of the named recipients.  The  sender’s  address
              is preserved.  Be very careful when using this function, because
              it resends the original message,  which  may  contain  undesired
              attachments.   Also,  you  should  not  call  this function from
              filter(), because it resends the message each time it is called.
              This  may  result  in  multiple copies being sent if you are not
              careful.  Call from filter_begin() or filter_end() to be safe.

              The function returns true on success, or false if it fails.

              Note that the  resend_message  function  delivers  the  mail  in
              deferred  mode  (using  Sendmail’s "-odd" flag.)  You must run a
              client-submission queue processor if you use Sendmail 8.12.   We
              recommend executing this command as part of the Sendmail startup
              sequence:

                   sendmail -Ac -q5m

       remove_redundant_html_parts($entity)
              This function should only be called from filter_end.  It removes
              redundant HTML parts from the message.  It works by deleting any
              part of type text/html from the message if (1) it is a  sub-part
              of  a  multipart/alternative part, and (2) there is another part
              of type text/plain under the multipart/alternative part.

       replace_entire_message($entity)
              This function can only be called from filter_end.   It  replaces
              the  entire message with $entity, a MIME::Entity object that you
              have constructed.  You can use any of the MIME::Tools  functions
              to construct the entity.

       read_commands_file()
              This  function  should  only  be  called  from filter_sender and
              filter_recipient. This will read the COMMANDS file (as described
              in   mimedefang-protocol(7)),   and  will  fill  or  update  the
              following    global     variables:     $Sender,     @Recipients,
              %RecipientMailers,  $RelayAddr,  $RealRelayAddr, $RelayHostname,
              $RealRelayHostname, $QueueID, $Helo, %SendmailMacros.

              If you do not call read_commands_file, then the only information
              available in filter_sender and filter_recipient is that which is
              passed as an argument to the function.

       stream_by_domain()
              Do not use this function  unless  you  have  Sendmail  8.12  and
              locally- submitted e-mail is submitted using SMTP.

              This  function  should  only  be called at the very beginning of
              filter_begin(), like this:

                   sub filter_begin {
                        if (stream_by_domain()) {
                             return;
                        }
                        # Rest of filter_begin
                   }

              stream_by_domain() looks at all the recipients of  the  message,
              and  if  they  belong  to the same domain (e.g., joe@domain.com,
              jane@domain.com and sue@domain.com), it returns 0 and  sets  the
              global  variable  $Domain  to  the  domain  (domain.com  in this
              example.)

              If users are in different  domains,  stream_by_domain()  resends
              the  message (once to each domain) and returns 1 For example, if
              the  original  recipients  are  joe@abc.net,  jane@xyz.net   and
              sue@abc.net,  the  original message is resent twice: One copy to
              joe@abc.net and sue@abc.net, and another copy  to  jane@xyz.net.
              Also,   any   subsequent  scanning  is  canceled  (filter()  and
              filter_end() will not be called for the  original  message)  and
              the message is silently discarded.

              If  you  have Sendmail 8.12, then locally-submitted messages are
              sent via SMTP, and MIMEDefang will be  called  for  each  resent
              message.   It  is  possible  to set up Sendmail 8.12 so locally-
              submitted  messages  are  delivered  directly;  in  this   case,
              stream_by_domain will not work.

              Using stream_by_domain allows you to customize your filter rules
              for each domain.  If you use the function  as  described  above,
              you can do this in your filter routine:

                   sub filter {
                        my($entity, $fname, $ext, $type) = @_;
                        if ($Domain eq "abc.com") {
                             # Filter actions for abc.com
                        } elsif ($Domain eq "xyz.com") {
                             # Filter actions for xyz.com
                        } else {
                             # Default filter actions
                        }
                   }

              You  cannot  rely  on  $Domain  being set unless you have called
              stream_by_domain().

       stream_by_recipient()
              Do not use this function  unless  you  have  Sendmail  8.12  and
              locally- submitted e-mail is submitted using SMTP.

              This  function  should  only  be called at the very beginning of
              filter_begin(), like this:

                   sub filter_begin {
                        if (stream_by_recipient()) {
                             return;
                        }
                        # Rest of filter_begin
                   }

              If there  is  more  than  one  recipient,  stream_by_recipient()
              resends  the  message once to each recipient.  That way, you can
              customize your filter rules on a per-recipient basis.  This  may
              increase the load on your mail server considerably.

              Also,  a  "recipient"  is determined before alias expansion.  So
              "all@mydomain.com" is considered a  single  recipient,  even  if
              Sendmail delivers to a list.

              If  you  have Sendmail 8.12, then locally-submitted messages are
              sent via SMTP, and MIMEDefang will be  called  for  each  resent
              message.   It  is  possible  to set up Sendmail 8.12 so locally-
              submitted  messages  are  delivered  directly;  in  this   case,
              stream_by_recipient() will not work.

              stream_by_recipient()  allows you to customize your filter rules
              for each recipient in a manner similar to stream_by_domain().

LOGGING

       md_graphdefang_log_enable($facility, $enum_recips)
              Enables the md_graphdefang_log function (described  next).   The
              function  logs  to  syslog using the specified facility.  If you
              omit $facility, it defaults to  ’mail’.   If  you  do  not  call
              md_graphdefang_log_enable  in  your  filter,  then  any calls to
              md_graphdefang_log simply do nothing.

              If you supply $enum_recips as 1,  then  a  line  of  logging  is
              output  for  each  recipient  of a mail message.  If it is zero,
              then only a single line is output for each message.  If you omit
              $enum_recips, it defaults to 1.

       md_graphdefang_log($event, $v1, $v2)
              Logs  an  event  with  up to two optional additional parameters.
              The log message has a specific format useful for graphing tools;
              the message looks like this:

                   MDLOG,msgid,event,v1,v2,sender,recipient,subj

              "MDLOG"   is  literal  text.   "msgid"  is  the  Sendmail  queue
              identifier.  "event" is the event name, and "v1"  and  "v2"  are
              the  additional  parameters.   "sender"  is  the sender’s e-mail
              address. "recipient" is  the  recipient’s  e-mail  address,  and
              "subj"  is  the message subject.  If a message has more than one
              recipient, md_graphdefang_log may log an event message for  each
              recipient,       depending      on      how      you      called
              md_graphdefang_log_enable.

              Note that md_graphdefang_log should not be used in filter_relay,
              filter_sender  or  filter_recipient.   The  global  variables it
              relies on are not valid in that context.

              If  you  want  to  log  general  text  strings,   do   not   use
              md_graphdefang_log.  Instead, use md_syslog (described next).

       md_syslog($level, $msg)
              Logs  the message $msg to syslog, using level $level.  The level
              is a literal string,  and  should  be  one  of  ’err’,  ’debug’,
              ’warning’,  ´emerg’, ’crit’, ’notice’ or ’info’.  (See syslog(3)
              for details.)

              Note  that  md_syslog  does  not  perform  %-subsitutions   like
              syslog(3)  does.  Depending on your Perl installation, md_syslog
              boils   down   to   a   call    to    Unix::Syslog::syslog    or
              Sys::Syslog::syslog.   See  the  Unix::Syslog or Sys::Syslog man
              pages for more details.

       md_openlog($tag, $facility)
              Sets the tag used in syslog messages to $tag, and sends the logs
              to the $facility facility.  If you do not call md_openlog before
              you call md_syslog, then it is called implicitly with  $tag  set
              to mimedefang.pl and $facility set to mail.

RBL LOOKUP FUNCTIONS

       mimedefang.pl  includes  the  following  functions  for  looking  up IP
       addresses in DNS-based real-time blacklists.

       relay_is_blacklisted($relay, $domain)
              This checks a DNS-based real-time spam  blacklist,  and  returns
              true  if the relay host is blacklisted, or false otherwise.  (In
              fact, the return value is whatever the blacklist  returns  as  a
              resolved hostname, such as "127.0.0.4")

              Note  that  relay_is_blacklisted uses the built-in gethostbyname
              function; this is usually quite inefficient and does not  permit
              you to set a timeout on the lookup.  Instead, we recommend using
              one of the other DNS lookup function described in this  section.
              (Note,  though,  that  the  other  functions  require  the  Perl
              Net::DNS module, whereas relay_is_blacklisted does not.)

              Here’s an example of how to use relay_is_blacklisted:

                   if (relay_is_blacklisted($RelayAddr, "rbl.spamhaus.org")) {
                        action_add_header("X-Blacklist-Warning",
                               "Relay $RelayAddr is blacklisted by Spamhaus");
                   }

       relay_is_blacklisted_multi($relay,      $timeout,      $answers_wanted,
       [$domain1, $domain2, ...], $res)
              This function is similar to relay_is_blacklisted, except that it
              takes  a timeout argument (specified in seconds) and an array of
              domains to check.  The function checks all domains in  parallel,
              and  is guaranteed to return in $timeout seconds.  (Actually, it
              may take up to one second longer.)

              The parameters are:

              $relay -- the IP address you want to look up

              $timeout -- a timeout in seconds after which the function should
              return

              $answers_wanted  --  the  maximum number of positive answers you
              care about.  For example, if you’re looking up an address in  10
              different  RBLs,  but are going to bounce it if it is on four or
              more, you can set $answers_wanted to 4, and the function returns
              as   soon   as   four   "hits"   are  discovered.   If  you  set
              $answers_wanted to zero,  then  the  function  does  not  return
              early.

              [$domain1, $domain2, ...] -- a reference to an array of strings,
              where each string is an RBL domain.

              $res -- a Net::DNS::Resolver object.  This argument is optional;
              if   you  do  not  supply  it,  then  relay_is_blacklisted_multi
              constructs its own resolver.

              The return value is a reference to a hash; the keys of the  hash
              are  the  original  domains,  and  the  corresponding values are
              either SERVFAIL, NXDOMAIN, or a list of IP addresses in  dotted-
              quad notation.

              Here’s an example:

                  $ans = relay_is_blacklisted_multi($RelayAddr, 8, 0,
                      ["sbl.spamhaus.org", "relays.ordb.org"]);

                  foreach $domain (keys(%$ans)) {
                      $r = $ans->{$domain};
                      if (ref($r) eq "ARRAY") {
                          # It’s an array -- it IS listed in RBL
                          print STDERR "Lookup in $domain yields [ ";
                          foreach $addr (@$r) {
                              print STDERR $addr . " ";
                          }
                          print STDERR "]\n";
                      } else {
                          # It is NOT listed in RBL
                          print STDERR "Lookup in $domain yields "
                                       . $ans->{$domain} . "\n";
                      }
                  }

              You  should  compare  each  of $ans->{$domain} to "SERVFAIL" and
              "NXDOMAIN" to see if the relay is not listed.  Any other  return
              value will be an array of IP addresses indicating that the relay
              is listed.

              Any lookup that does not succeed within $timeout seconds has the
              corresponding return value set to SERVFAIL.

       relay_is_blacklisted_multi_list($relay,    $timeout,   $answers_wanted,
       [$domain1, $domain2, ...], $res)
              This  function  is  similar to relay_is_blacklisted_multi except
              that the return value is simply an array of RBL domains in which
              the relay was listed.

       relay_is_blacklisted_multi_count($relay,   $timeout,   $answers_wanted,
       [$domain1, $domain2, ...], $res)
              This  function  is  similar to relay_is_blacklisted_multi except
              that the return value is an integer  specifying  the  number  of
              domains on which the relay was blacklisted.

       md_get_bogus_mx_hosts($domain)
              This function is not really an RBL lookup.  What it does is look
              up all the MX records for the specified  domain,  and  return  a
              list  of  "bogus"  IP addresses found amongst the MX records.  A
              "bogus" IP address  is  an  IP  address  in  a  private  network
              (10.0.0.0/8,   172.16.0.0/12,   192.168.0.0/16),   the  loopback
              network     (127.0.0.0/8),     local-link     for      auto-DHCP
              (169.254.0.0/16),   IPv4  multicast  (224.0.0.0/4)  or  reserved
              (240.0.0.0/4).

       Here’s how you might use the function in filter_sender:

       sub filter_sender {
           my ($sender, $ip, $hostname, $helo) = @_;
           if ($sender =~ /@([^>]+)/) {
               my $domain = $1;
               my @bogushosts = md_get_bogus_mx_hosts($domain);
               if (scalar(@bogushosts)) {
                   return(’REJECT’, "Domain $domain contains bogus MX record(s) " .
                          join(’, ’, @bogushosts));
               }
           }
           return (’CONTINUE’, ’ok’);
       }

TEST FUNCTIONS

       mimedefang.pl includes some "test" functions:

       md_version()
              returns the version of MIMEDefang  as  a  string  (for  example,
              "2.64").

       message_rejected()
              Returns   true  if  any  of  action_tempfail,  action_bounce  or
              action_discard have been called for this message; returns  false
              otherwise.

       If   you   have  the  Mail::SpamAssassin  Perl  module  installed  (see
       http://www.spamassassin.org) you may call any  of  the  spam_assassin_*
       functions.   They should only be called from filter_begin or filter_end
       because they operate on the entire message at once.  Most functions use
       an  optionally  provided  config  file.  If no config file is provided,
       mimedefang.pl will look for one of four default SpamAssassin preference
       files.  The first of the following found will be used:

       o      /etc/sa-mimedefang.cf

       o      /etc/mail/sa-mimedefang.cf

       o      /etc/spamassassin/local.cf

       o      /etc/spamassassin.cf

       Important  Note:   MIMEDefang  does  not  permit SpamAssassin to modify
       messages.  If you want to tag spam messages  with  special  headers  or
       alter  the  subject  line,  you must use MIMEDefang functions to do it.
       Setting SpamAssassin configuration options to alter messages  will  not
       work.

       spam_assassin_is_spam([ $config_file ])
              Determine  if  the  current message is SPAM/UCE as determined by
              SpamAssassin.  Compares the score of  the  message  against  the
              threshold  score  (see  below)  and returns true if it is.  Uses
              spam_assassin_check below.

       spam_assassin_check([ $config_file ])
              This function returns a four-element list of  the  form  ($hits,
              $required,  $tests, $report).  $hits is the "score" given to the
              message by SpamAssassin (higher score means more  likely  SPAM).
              $required  is  the  number  of hits required before SpamAssassin
              concludes that the message is SPAM.  $tests is a comma-separated
              list  of  SpamAssassin test names, and $report is text detailing
              which tests triggered and their point  score.   This  gives  you
              insight  into  why  SpamAssassin  concluded  that the message is
              SPAM.  Uses spam_assassin_status below.

       spam_assassin_status([ $config_file ])
              This function returns a Mail::SpamAssasin::PerMsgStatus  object.
              Read  the  SpamAssassin  documentation  for  details  about this
              object.  You are responsible for calling the finish method  when
              you   are   done   with   it.    Uses   spam_assassin_init   and
              spam_assassin_mail below.

       spam_assassin_init([ $config_file ])
              This function returns the new global  Mail::SpamAssassin  object
              with  the  specified or default config (outlined above).  If the
              global object is already defined, returns it -- does not  change
              config   files!   The  object  can  be  used  to  perform  other
              SpamAssassin related functions.

       spam_assassin_mail()
              This function returns a  Mail::SpamAssassin::NoMailAudit  object
              with  the current email message contained in it.  It may be used
              to perform other SpamAssassin related functions.

       md_copy_orig_msg_to_work_dir()
              Normally, virus-scanners are passed only the  unpacked,  decoded
              parts  of  a  MIME  message.   If you want to pass the original,
              undecoded message in as well, call  md_copy_orig_msg_to_work_dir
              prior to calling message_contains_virus.

       md_copy_orig_msg_to_work_dir_as_mbox_file()
              Normally,  virus-scanners  are passed only the unpacked, decoded
              parts of a MIME message.  If you  want  to  pass  the  original,
              undecoded   message   in  as  a  UNIX-style  "mbox"  file,  call
              md_copy_orig_msg_to_work_dir_as_mbox_file   prior   to   calling
              message_contains_virus.    The   only  difference  between  this
              function and md_copy_orig_msg_to_work_dir is that this  function
              prepends  a  "From_"  line to make the message look like a UNIX-
              style mbox file.  This is required for some virus scanners (such
              as Clam AntiVirus) to recognize the file as an e-mail message.

       message_contains_virus()
              This function runs every installed virus-scanner and returns the
              scanner results.  The function should be called in list context;
              the  return  value  is  a  three-element list ($code, $category,
              $action).

              $code is the actual return code from the virus scanner.

              $category is a string categorizing the return code:

              "ok" - no viruses detected.

              "not-installed" - indicated virus scanner is not installed.

              "cannot-execute" - for some reason, the  scanner  could  not  be
              executed.

              "virus" - a virus was found.

              "suspicious" - a "suspicious" file was found.

              "interrupted" - scanning was interrupted.

              "swerr" - an internal scanner software error occurred.

              $action is a string containing the recommended action:

              "ok" - allow the message through unmolested.

              "quarantine" - a virus was detected; quarantine it.

              "tempfail" - something went wrong; tempfail the message.

       message_contains_virus_trend()

       message_contains_virus_nai()

       message_contains_virus_bdc()

       message_contains_virus_nvcc()

       message_contains_virus_csav()

       message_contains_virus_fsav()

       message_contains_virus_hbedv()

       message_contains_virus_vexira()

       message_contains_virus_sophos()

       message_contains_virus_clamav()

       message_contains_virus_avp()

       message_contains_virus_avp5()

       message_contains_virus_fprot()

       message_contains_virus_fprotd()

       message_contains_virus_nod32()

              These  functions should be called in list context.  They use the
              indicated anti-virus software to scan the message  for  viruses.
              These  functions  are intended for use in filter_begin() to make
              an initial scan of the e-mail message.

              The supported virus scanners are:

       nai    NAI "uvscan" - http://www.nai.com/

       Bitdefender "bdc" - http://www.bitdefender.com/

       csav   Command Anti-Virus - http://www.commandsoftware.com/

       fsav   F-Secure Anti-Virus - http://www.f-secure.com/

       hbedv  H+BEDV "AntiVir" - http://www.hbedv.com/

       vexira Vexira "Vexira" - http://www.centralcommand.com/

       sophos Sophos AntiVirus - http://www.sophos.com/

       avp    Kaspersky AVP and aveclient (AVP5) - http://www.avp.ru/

       clamav Clam AntiVirus - http://www.clamav.net/

       f-prot F-RISK F-PROT - http://www.f-prot.com/

       nod32cli
              ESET NOD32 - http://www.eset.com/

       message_contains_virus_carrier_scan([$host])
              Connects to the specified  host:port:local_or_nonlocal  (default
              $CSSHost),  where  the  Symantec  CarrierScan  Server  daemon is
              expected to be listening.  Return values are  the  same  as  the
              other message_contains_virus functions.

       message_contains_virus_sophie([$sophie_sock])
              Connects  to  the  specified socket (default $SophieSock), where
              the Sophie daemon is expected to be  listening.   Return  values
              are the same as the other message_contains_virus functions.

       message_contains_virus_clamd([$clamd_sock])
              Connects to the specified socket (default $ClamdSock), where the
              clamd daemon is expected to be listening.  Return values are the
              same as the other message_contains_virus functions.

       message_contains_virus_trophie([$trophie_sock])
              Connects  to  the specified socket (default $TrophieSock), where
              the Trophie daemon is expected to be listening.   Return  values
              are the same as the other message_contains_virus functions.

       entity_contains_virus($entity)

              This  function  runs  the  specified  MIME::Entity through every
              installed virus-scanner and returns the  scanner  results.   The
              return values are the same as for message_contains_virus().

       entity_contains_virus_trend($entity)

       entity_contains_virus_nai($entity)

       entity_contains_virus_bdc($entity)

       entity_contains_virus_nvcc($entity)

       entity_contains_virus_csav($entity)

       entity_contains_virus_fsav($entity)

       entity_contains_virus_hbedv($entity)

       entity_contains_virus_sophos($entity)

       entity_contains_virus_clamav($entity)

       entity_contains_virus_avp($entity)

       entity_contains_virus_avp5($entity)

       entity_contains_virus_fprot($entity)

       entity_contains_virus_fprotd($entity)

       entity_contains_virus_nod32($entity)
              These  functions,  meant to be called from filter(), are similar
              to the message_contains_virus functions except  they  scan  only
              the  current part.  They should be called from list context, and
              their   return    values    are    as    described    for    the
              message_contains_virus functions.

       entity_contains_virus_carrier_scan($entity[, $host])
              Connects  to  the specified host:port:local_or_nonlocal (default
              $CSSHost), where  the  Symantec  CarrierScan  Server  daemon  is
              expected  to  be  listening.   Return values are the same as the
              other entity_contains_virus functions.

       entity_contains_virus_sophie($entity[, $sophie_sock])
              Connects to the specified socket  (default  $SophieSock),  where
              the  Sophie  daemon  is expected to be listening.  Return values
              are the same as the other entity_contains_virus functions.

       entity_contains_virus_trophie($entity[, $trophie_sock])
              Connects to the specified socket (default  $TrophieSock),  where
              the  Trophie  daemon is expected to be listening.  Return values
              are the same as the other entity_contains_virus functions.

       entity_contains_virus_clamd($entity[, $clamd_sock])
              Connects to the specified socket (default $ClamdSock), where the
              clamd daemon is expected to be listening.  Return values are the
              same as the other entity_contains_virus functions.

SMTP FLOW

       This section illustrates the flow of messages through MIMEDefang.

       1. INITIAL CONNECTION
              If you invoked mimedefang with the -r option and have defined  a
              filter_relay routine, it is called.

       2. SMTP HELO COMMAND
              The  HELO  string  is stored internally, but no filter functions
              are called.

       3. SMTP MAIL FROM: COMMAND
              If you invoked mimedefang with the -s option and have defined  a
              filter_sender routine, it is called.

       4. SMTP RCPT TO: COMMAND
              If  you invoked mimedefang with the -t option and have defined a
              filter_recipient routine, it is called.

       5. END OF SMTP DATA
              filter_begin is called.  For each MIME part, filter  is  called.
              Then filter_end is called.

PRESERVING RELAY INFORMATION

       Most organizations have more than one machine handling internet e-mail.
       If the primary machine is down, mail  is  routed  to  a  secondary  (or
       tertiary,  etc.)  MX server, which stores the mail until the primary MX
       host comes back up.  Mail is then relayed to the primary MX host.

       Relaying from a secondary to a primary MX host has the unfortunate side
       effect   of   losing  the  original  relay’s  IP  address  information.
       MIMEDefang allows you to preserve this information.  One way around the
       problem  is to run MIMEDefang on all the secondary MX hosts and use the
       same filter.  However, you may not have control over the  secondary  MX
       hosts.  If you can persuade the owners of the secondary MX hosts to run
       MIMEDefang with a simple filter that only preserves  relay  information
       and  does  no  other  scanning,  your  primary MX host can obtain relay
       information and make decisions using $RelayAddr and $RelayHostname.

       When you configure MIMEDefang, supply the "--with-ipheader" argument to
       the  ./configure  script.   When  you install MIMEDefang, a file called
       /etc/mimedefang-ip-key will  be  created  which  contains  a  randomly-
       generated  header name.  Copy this file to all of your mail relays.  It
       is important that all of your MX hosts have  the  same  key.   The  key
       should be kept confidential, but it’s not disastrous if it leaks out.

       On your secondary MX hosts, add this line to filter_end:

            add_ip_validation_header();

       Note:   You  should only add the validation header to mail destined for
       one of your other MX hosts!  Otherwise, the validation header will leak
       out.

       When  the  secondary  MX hosts relay to the primary MX host, $RelayAddr
       and $RelayHostname will be set based on the IP validation  header.   If
       MIMEDefang  notices this header, it sets the global variable $WasResent
       to 1.  Since you don’t want to trust the header unless it  was  set  by
       one   of  your  secondary  MX  hosts,  you  should  put  this  code  in
       filter_begin:

            if ($WasResent) {
                 if ($RealRelayAddr ne "ip.of.secondary.mx" and
                     $RealRelayAddr ne "ip.of.tertiary.mx") {
                      $RelayAddr = $RealRelayAddr;
                      $RelayHostname = $RealRelayHostname;
                 }
            }

       This resets the relay address and hostname to the actual relay  address
       and  hostname,  unless  the message is coming from one of your other MX
       hosts.

       On the primary MX host, you should add this in filter_begin:

            delete_ip_validation_header();

       This prevents the validation header from leaking out to recipients.

       Note:  The  IP  validation  header  works  only   in   message-oriented
       functions.  It (obviously) has no effect on filter_relay, filter_sender
       and filter_recipient, because no header information is  available  yet.
       You  must  take  this  into  account when writing your filter; you must
       defer relay-based decisions to the message  filter  for  mail  arriving
       from your other MX hosts.

GLOBAL VARIABLE LIFETIME

       The  following  list describes the lifetime of global variables (thanks
       to Tony Nugent for providing this documentation.)

       If you set a global variable:

       Outside a subroutine in your filter file
              It is available to all functions, all the time.

       In filter_relay, filter_sender or filter_recipient
              Not guaranteed to be available to any other function,  not  even
              from  one  filter_recipient  call  to the next, when receiving a
              multi-recipient email message.

       In filter_begin
              Available to filter_begin, filter and filter_end

       In filter
              Available to filter and filter_end

       In filter_end
              Available within filter_end

       The  "built-in"  globals  like  $Subject,  $Sender,  etc.  are   always
       available to filter_begin, filter and filter_end. Some are available to
       filter_relay, filter_sender or filter_recipient, but you  should  check
       the documentation of the variable above for details.

MAINTAINING STATE

       There are four basic groups of filtering functions:

       1      filter_relay

       2      filter_sender

       3      filter_recipient

       4      filter_begin, filter, filter_multipart, filter_end

       In  general, for a given mail message, these groups of functions may be
       called in completely different Perl processes.  Thus, there is  no  way
       to  maintain  state  inside Perl between groups of functions.  That is,
       you cannot set a variable in filter_relay and expect it to be available
       in filter_sender, because the filter_sender invocation might take place
       in a completely different process.

       However, for a given mail message, the $CWD global variable  holds  the
       message  spool  directory,  and the current working directory is set to
       $CWD.  Therefore, you  can  store  state  in  files  inside  $CWD.   If
       filter_sender  stores data in a file inside $CWD, then filter_recipient
       can retrieve that data.

       Since filter_relay is  called  directly  after  a  mail  connection  is
       established, there is no message context yet, no per-message mimedefang
       spool directory, and the $CWD global is not set. Therefore, it  is  not
       possible  to  share  information  from filter_relay to one of the other
       filter functions. The only thing that filter_relay has in  common  with
       the  other  functions  are  the  values  in  the globals $RelayAddr and
       $RelayHostname.  These  could  be  used   to   access   per-remote-host
       information in some database.

       Inside $CWD, we reserve filenames beginning with upper-case letters for
       internal MIMEDefang use.  If you want to create files to  store  state,
       name  them  beginning  with  a  lower-case letter to avoid clashes with
       future releases of MIMEDefang.

SOCKET MAPS

       If you have Sendmail 8.13 or later,  and  have  compiled  it  with  the
       SOCKETMAP option, then you can use a special map type that communicates
       over a socket with another program (rather than looking up a key  in  a
       Berkeley database, for example.)

       mimedefang-multiplexor  implements  the  Sendmail SOCKETMAP protocol if
       you supply the -N option.  In that case,  you  can  define  a  function
       called  filter_map  to  implement  map  lookups.   filter_map takes two
       arguments:  $mapname is the name of the Sendmail map (as given in the K
       sendmail configuration directive), and $key is the key to be looked up.

       filter_map must return a two-element list: ($code, $val) $code  can  be
       one of:

       OK     The  lookup  was  successful.   In  this  case, $val must be the
              result of the lookup

       NOTFOUND
              The lookup was unsuccessful -- the key was not found.   In  this
              case, $val should be the empty string.

       TEMP   There  was  a  temporary  failure  of some kind.  $val can be an
              explanatory error message.

       TIMEOUT
              There was a timeout of some kind.  $val can  be  an  explanatory
              error message.

       PERM   There  was  a  permanent  failure.   This  is not the same as an
              unsuccessful lookup; it  should  be  used  only  to  indicate  a
              serious misconfiguration.  As before, $val can be an explanatory
              error message.

       Consider this small example.  Here is a minimal Sendmail  configuration
       file:

            V10/Berkeley
            Kmysock socket unix:/var/spool/MIMEDefang/map.sock
            kothersock socket unix:/var/spool/MIMEDefang/map.sock

       If   mimedefang-multiplexor   is   invoked   with   the   arguments  -N
       unix:/var/spool/MIMEDefang/map.sock, and the filter defines  filter_map
       as follows:

            sub filter_map ($$) {
                my($mapname, $key) = @_;
                my $ans;
                if($mapname ne "mysock") {
                    return("PERM", "Unknown map $mapname");
                }
                $ans = reverse($key);
                return ("OK", $ans);
            }

       Then in Sendmail’s testing mode, we see the following:

            > /map mysock testing123
            map_lookup: mysock (testing123) returns 321gnitset (0)
            > /map othersock foo
            map_lookup: othersock (foo) no match (69)

       (The return code of 69 means EX_UNAVAILABLE or Service Unavailable)

       A  real-world  example could do map lookups in an LDAP directory or SQL
       database, or perform other kinds of processing.  You can even implement
       standard Sendmail maps like virtusertable, mailertable, access_db, etc.
       using SOCKETMAP.

TICK REQUESTS

       If you supply the -X option to mimedefang-multiplexor,  then  every  so
       often,  a  "tick"  request  is  sent  to  a free slave.  If your filter
       defines a function called filter_tick, then  this  function  is  called
       with  a  single  argument: the tick type.  If you run multiple parallel
       ticks, then each tick has a type ranging from 0 to n-1, where n is  the
       number  of  parallel  ticks.   If you’re only running one tick request,
       then the argument to filter_tick is always 0.

       You can use this facility to run periodic tasks from within MIMEDefang.
       Note,  however,  that you have no control over which slave is picked to
       run filter_tick.  Also, at most one filter_tick call with a  particular
       "type"  argument  will  be active at any time, and if there are no free
       slaves when a tick would occur, the tick is skipped.

SUPPORTED VIRUS SCANNERS

       The following virus scanners are supported by MIMEDefang:

       o      Symantec                   CarrierScan                    Server
              (http://www.symantec.com/region/can/eng/product/scs/)

       o      Trend Micro vscan (http://www.antivirus.com/)

       o      Sophos                                                     Sweep
              (http://www.sophos.com/products/antivirus/savunix.html)

       o      H+BEDV AntiVir (http://www.hbedv.com/)

       o      Central Command Vexira (http://www.centralcommand.com/)

       o      NAI uvscan (http://www.nai.com)

       o      Bitdefender bdc (http://www.bitdefender.com)

       o      Norman Virus Control (NVCC) (http://www.norman.no/)

       o      Command csav (http://www.commandsoftware.com)

       o      F-Secure fsav (http://www.f-secure.com)

       o      The clamscan command-line scanner and the clamd daemon from Clam
              AntiVirus (http://www.clamav.net/)

       o      Kaspersky Anti-Virus (AVP) (http://www.kaspersky.com/)

       o      F-Risk F-Prot (http://www.f-prot.com/)

       o      F-Risk FPROTD (daemonized version of F-Prot)

       o      Symantec                    CarrierScan                   Server
              (http://www.symantec.ca/region/can/eng/product/scs/buymenu.html)

       o      Sophie   (http://www.vanja.com/tools/sophie/),  which  uses  the
              libsavi library from Sophos,  is  supported  in  daemon-scanning
              mode.

       o      Trophie  (http://www.vanja.com/tools/trophie/),  which  uses the
              libvsapi library from  Trend  Micro,  is  supported  in  daemon-
              scanning mode.

       o      ESET NOD32 (http://www.eset.com/)

AUTHORS

       mimedefang was written by David F. Skoll <dfs@roaringpenguin.com>.  The
       mimedefang home page is http://www.mimedefang.org/.

SEE ALSO

       mimedefang(8), mimedefang.pl(8)