Provided by: mimedefang_2.84-4build3_amd64 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.  Within filter_end,
       you can call functions that modify the message headers body.

       5) After filter_end returns, the function filter_wrapup 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,  including  any  modifications  made  in
       filter_end.   Within  filter_wrapup,  you  can  not call functions that modify the message
       body, but you can still add or modify message headers.

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 five arguments: $hostip is the IP address of the  relay  host  (for
       example,   "127.0.0.1"),   $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.)

       The  remaining  three arguments to filter_relay are $port, $myip and $myport which contain
       the client's TCP port, the  Sendmail  daemon's  listening  IP  address  and  the  Sendmail
       daemon's listening port.

       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  six  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.

       The  remaining  three arguments to filter_relay are $port, $myip and $myport which contain
       the client's TCP port, the  Sendmail  daemon's  listening  IP  address  and  the  Sendmail
       daemon's listening port.

       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 worker 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  worker  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 worker.  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 worker.

       When a worker 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 worker resources.   The  return  value
       from  filter_cleanup  becomes the worker's exit status.  (You should therefore ensure that
       filter_cleanup returns an integer suitable for a process exit status.)

       If filter_cleanup takes longer than 10 seconds to  run,  the  worker  is  sent  a  SIGTERM
       signal.   If  that  doesn't  kill  it  (because  you're catching signals, perhaps), then a
       further 10 seconds later, the worker 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  workers  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{"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 earlier than version 6.

              $Features{"Virus:FPROTD6"} is currently always 0.  Set it to 1 in your filter  file
              if you have version 6 of 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:FPSCAN"}  is  the full path to F-Risk fpscan 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 such as SpamAssassin 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  in
              addition to the body filtering functions.

       $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 in addition to the body  filtering
              functions.

              $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 in addition to the body filtering functions.

       @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},
              ${daemon_port},  ${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}.  In
              addition, ${client_port} is set to the client's TCP port.

              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.

       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.

       action_add_entity($entity [, $offset])
              This is similar to action_add_part but takes a pre-built MIME::Entity object rather
              than  constructing  one  based  on $type, $encoding, $data, $fname and $disposition
              arguments.

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.   Note that the "relay_is_blacklisted" functions are deprecated and
       may be removed in a future release.  Instead, you should use the module Net::DNSBL::Client
       from CPAN.

       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 looks up all the MX records for the specified domain (or A records if
              there  are  no MX records) and returns a list of "bogus" IP addresses found amongst
              the 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.84").

       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_fpscan()

       message_contains_virus_fprotd()

       message_contains_virus_fprotd_v6()

       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_fpscan($entity)

       entity_contains_virus_fprotd($entity)

       entity_contains_virus_fprotd_v6($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.

       For   a   given   mail   message,  it  is  always  the  case  that  filter_begin,  filter,
       filter_multipart and filter_end are called in the same Perl process.  Therefore,  you  can
       use  global variables to carry state among those functions.  You should be very careful to
       initialize such variables in filter_begin to ensure no data  leaks  from  one  message  to
       another.

       Also 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 worker.  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 worker 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 workers 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 F-Prot v6 (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 Dianne Skoll <dfs@roaringpenguin.com>.  The mimedefang home page
       is http://www.mimedefang.org/.

SEE ALSO

       mimedefang(8), mimedefang.pl(8)