use strict;

#
# Section IV - Notifications/DSN, bounce/reject/discard/pass, quarantine
#

# Select notifications text encoding when Unicode-aware Perl is converting
# text from internal character representation to external encoding (charset
# in MIME terminology). Used as argument to Perl Encode::encode subroutine.
#
#   to be used in RFC 2047-encoded header field bodies, e.g. in Subject:
#$hdr_encoding = 'iso-8859-1';  # MIME charset (default: 'iso-8859-1')
#$hdr_encoding_qb = 'Q';        # MIME encoding: quoted-printable (default)
#$hdr_encoding_qb = 'B';        # MIME encoding: base64
#
#   to be used in notification body text: its encoding and Content-type.charset
#$bdy_encoding = 'iso-8859-1';  # (default: 'iso-8859-1')

# Default template texts for notifications may be overruled by directly
# assigning new text to template variables, or by reading template text
# from files. A second argument may be specified in a call to read_text(),
# specifying character encoding layer to be used when reading from the
# external file, e.g. 'utf8', 'iso-8859-1', or often just $bdy_encoding.
# Text will be converted to internal character representation by Perl 5.8.0
# or later; second argument is ignored otherwise. See PerlIO::encoding,
# Encode::PerlIO and perluniintro man pages.
#
# $notify_sender_templ      = read_text("$MYHOME/notify_sender.txt");
# $notify_virus_sender_templ= read_text("$MYHOME/notify_virus_sender.txt");
# $notify_virus_admin_templ = read_text("$MYHOME/notify_virus_admin.txt");
# $notify_virus_recips_templ= read_text("$MYHOME/notify_virus_recips.txt");
# $notify_spam_sender_templ = read_text("$MYHOME/notify_spam_sender.txt");
# $notify_spam_admin_templ  = read_text("$MYHOME/notify_spam_admin.txt");

# If notification template files are collectively available in some directory,
# one may call read_l10n_templates which invokes read_text for each known
# template. This is primarily a Debian-specific feature, but was incorporated
# into base code to facilitate porting.
#
#   read_l10n_templates('/etc/amavis/en_US');
#
# If read_l10n_templates is called, a localization template directory must
# contain the following files:
#   charset                       this file should contain a one-line name
#                                 of the character set used in the template
#                                 files (e.g. utf8, iso-8859-2, ...) and is
#                                 passed as the second argument to read_text;
#   template-dsn.txt              content fills the $notify_sender_templ
#   template-virus-sender.txt     content fills the $notify_virus_sender_templ
#   template-virus-admin.txt      content fills the $notify_virus_admin_templ
#   template-virus-recipient.txt  content fills the $notify_virus_recips_templ
#   template-spam-sender.txt      content fills the $notify_spam_sender_templ
#   template-spam-admin.txt       content fills the $notify_spam_admin_templ


# $hdr_encoding = 'koi8-r';  # header field bodies charset
# $bdy_encoding = 'koi8-r';  # notification body text charset
# $hdr_encoding_qb = 'Q';        # quoted-printable (Q or B)

# $notify_sender_templ      = read_text('/etc/amavis/notify_sender.txt');
# $notify_virus_sender_templ= read_text('/etc/amavis/notify_virus_sender.txt');
# $notify_virus_admin_templ = read_text('/etc/amavis/notify_virus_admin.txt');
# $notify_virus_recips_templ= read_text('/etc/amavis/notify_virus_recips.txt');
# $notify_spam_sender_templ = read_text('/etc/amavis/notify_spam_sender.txt');
# $notify_spam_admin_templ  = read_text('/etc/amavis/notify_spam_admin.txt');
# $notify_spam_recips_templ= read_text('/etc/amavis/notify_spam_recips.txt');

# Here is an overall picture (sequence of events) of how pieces fit together
#
#   bypass_virus_checks set for all recipients? ==> PASS
#   no viruses?   ==> PASS
#   log virus     if $log_templ is nonempty
#   quarantine    if $virus_quarantine_to is nonempty
#   notify admin  if $virus_admin (lookup) nonempty
#   notify recips if $warnvirusrecip and (recipient is local or $warn_offsite)
#   add address extensions for local recipients (when enabled)
#   send (non-)delivery notifications
#      to sender if DSN needed (BOUNCE or ($warnvirussender and D_PASS))
#   virus_lovers or final_destiny==D_PASS  ==> PASS
#   DISCARD (2xx) or REJECT (5xx) (depending on final_*_destiny)
#
# Equivalent flow diagram applies for spam checks.
# If a virus is detected, spam checking is skipped entirely.

# The following symbolic constants can be used in *_destiny settings:
#
# D_PASS     mail will pass to recipients, regardless of bad contents;
#
# D_DISCARD  mail will not be delivered to its recipients, sender will NOT be
#            notified. Effectively we lose mail (but will be quarantined
#            unless disabled). Losing mail is not decent for a mailer,
#            but might be desired.
#
# D_BOUNCE   mail will not be delivered to its recipients, a non-delivery
#            notification (bounce) will be sent to the sender by amavisd-new;
#            Exception: bounce (DSN) will not be sent if a virus name matches
#            @viruses_that_fake_sender_maps, or to messages from mailing lists
#            (Precedence: bulk|list|junk), or for spam level that exceeds
#            the $sa_dsn_cutoff_level.
#
# D_REJECT   mail will not be delivered to its recipients, sender should
#            preferably get a reject, e.g. SMTP permanent reject response
#            (e.g. with milter), or non-delivery notification from MTA
#            (e.g. Postfix). If this is not possible (e.g. different recipients
#            have different tolerances to bad mail contents and not using LMTP)
#            amavisd-new sends a bounce by itself (same as D_BOUNCE).
#            Not to be used with Postfix or dual-MTA setups!
#
# Notes:
#   D_REJECT and D_BOUNCE are similar, the difference is in who is responsible
#            for informing the sender about non-delivery, and how informative
#            the notification can be (amavisd-new knows more than MTA);
#   With D_REJECT, MTA may reject original SMTP, or send DSN (delivery status
#            notification, colloquially called 'bounce') - depending on MTA;
#            Best suited for sendmail milter and Courier, especially for spam.
#   With D_BOUNCE, amavisd-new (not MTA) sends DSN (can better explain the
#            reason for mail non-delivery or even suppress DSN, but unable
#            to reject the original SMTP session). Best suited to reporting
#            viruses, and for Postfix and other dual-MTA setups, which can't
#            reject original client SMTP session, as the mail has already
#            been enqueued.

# Alternatives to consider for spam:
# - use D_PASS if clients will do filtering based on inserted
#   mail headers or added address extensions ('plus-addressing');
# - use D_DISCARD, if kill_level is set comfortably high;
#
# D_BOUNCE is preferred for viruses, but consider:
# - use D_PASS (or virus_lovers) to deliver viruses;
# - use D_REJECT instead of D_BOUNCE if using Courier or milter and under heavy
#   virus storm;


# The use of new *_by_ccat hashes is illustrated by the following examples
# on configuring final_*_destiny.


# using traditional settings of $final_*_destiny variables, relying on a
# default setting of an associative array %final_destiny_by_ccat which is
# backwards compatible and contains references to these traditional variables:
#
$final_virus_destiny      = D_DISCARD; # (defaults to D_DISCARD)
$final_banned_destiny     = D_BOUNCE;  # (defaults to D_BOUNCE)
$final_spam_destiny       = D_BOUNCE;  # (defaults to D_BOUNCE)
$final_bad_header_destiny = D_PASS;    # (defaults to D_PASS)

# to explicitly list all (or most) possible contents category (ccat) keys:
#%final_destiny_by_ccat = (
#  CC_VIRUS,      D_DISCARD,
#  CC_BANNED,     D_BOUNCE,
#  CC_UNCHECKED,  D_PASS,
#  CC_SPAM,       D_BOUNCE,
#  CC_BADH,       D_PASS,
#  CC_OVERSIZED,  D_BOUNCE,
#  CC_CLEAN,      D_PASS,
#  CC_CATCHALL,   D_PASS,
#);

# to rely on a catchall ccat key and only list exceptions (alternative 1):
#%final_destiny_by_ccat = (
#  CC_VIRUS,      D_DISCARD,
#  CC_BANNED,     D_BOUNCE,
#  CC_SPAM,       D_BOUNCE,
#  CC_BADH.',4',  D_BOUNCE, # BadHdrSpace
#  CC_BADH.',3',  D_BOUNCE, # BadHdrChar
#  CC_OVERSIZED,  D_BOUNCE,
#  CC_CATCHALL,   D_PASS,
#);

# to rely on a catchall ccat key and list exceptions (alternative 2):
#%final_destiny_by_ccat = (
#  CC_VIRUS,      D_DISCARD,
#  CC_UNCHECKED,  D_PASS,
#  CC_BADH.',6',  D_PASS,   # BadHdrSyntax
#  CC_BADH.',5',  D_PASS,   # BadHdrLong
#  CC_BADH.',2',  D_PASS,   # BadHdr8bit
#  CC_BADH.',1',  D_PASS,   # BadHdrMime
#  CC_CLEAN,      D_PASS,
#  CC_CATCHALL,   D_BOUNCE,
#);

# to rely on a catchall ccat key and list exceptions (alternative 3):
#%final_destiny_by_ccat = (
#  CC_VIRUS,      D_DISCARD,
#  CC_UNCHECKED,  D_PASS,
#  CC_BADH.',4',  D_BOUNCE, # BadHdrSpace
#  CC_BADH.',3',  D_BOUNCE, # BadHdrChar
#  CC_BADH,       D_PASS,   # sub-catchall for CC_BADH
#  CC_CLEAN,      D_PASS,
#  CC_CATCHALL,   D_BOUNCE,
#);

# to rely on a default %final_destiny_by_ccat and only change few settings:
#$final_destiny_by_ccat{+CC_SPAM} = D_PASS;
#$final_destiny_by_ccat{+CC_BADH} = D_BOUNCE;
#$final_destiny_by_ccat{+CC_BADH.',2'} = D_PASS;  # BadHdr8bit



# For monitoring / testing purposes let the administrator receive a copy
# of certain delivery status notifications that are mailed back to senders:
#
#%dsn_bcc_by_ccat = (
# CC_BANNED,    undef,
# CC_SPAM,      undef,
# CC_BADH,      undef,
# CC_CATCHALL,  'admin+test@example.com',
#);
#
# or use a simpler form, taking advantage of defaults in %dsn_bcc_by_ccat:
#$dsn_bcc = 'admin+test@example.com';


# The following $warn*sender settings are ONLY used when mail is
# actually passed to recipients ($final_*_destiny=D_PASS, or *_lovers*).
# Bounces or rejects produce non-delivery status notification regardless.
#
# Notify sender of syntactically invalid header containing non-ASCII chars?
#$warnbadhsender = 1;	# (defaults to false (undef))

# Notify virus (or banned files or bad headers) RECIPIENT?
#  (not very useful, but some policies demand it)
#$warnvirusrecip = 1;	# (defaults to false (undef))
#$warnbannedrecip = 1;	# (defaults to false (undef))
#$warnbadhrecip = 1;	# (defaults to false (undef))

# Notify also non-local virus/banned recipients if $warn*recip is true?
#  (including those not matching local_domains*)
#$warn_offsite = 1;	# (defaults to false (undef), i.e. only notify locals)


# Treat envelope sender address as unreliable and don't send sender
# notification / bounces if name(s) of detected virus(es) match the list.
# Note that virus names are supplied by external virus scanner(s) and are
# not standardized, so virus names may need to be adjusted.
# See README.lookups for syntax, check also README.policy-on-notifications.
# If the intention is to treat all viruses as faking the sender address, it
# is equivalent but more efficient to just set $final_virus_destiny=D_DISCARD;
#
@viruses_that_fake_sender_maps = (new_RE(
  qr'nimda|hybris|klez|bugbear|yaha|braid|sobig|fizzer|palyh|peido|holar'i,
  qr'tanatos|lentin|bridex|mimail|trojan\.dropper|dumaru|parite|spaces'i,
  qr'dloader|galil|gibe|swen|netwatch|bics|sbrowse|sober|rox|val(hal)?la'i,
  qr'frethem|sircam|be?agle|tanx|mydoom|novarg|shimg|netsky|somefool|moodown'i,
  qr'@mm|@MM',    # mass mailing viruses as labeled by f-prot and uvscan
  qr'Worm'i,      # worms as labeled by ClamAV, Kaspersky, etc
  [qr'^(EICAR|Joke\.|Junk\.)'i         => 0],
# [qr'^(WM97|OF97|W95/CIH-|JS/Fort)'i  => 0],
  [qr/^/ => 1],   # true by default  (remove or comment-out if undesired)
));

# where to send ADMIN VIRUS NOTIFICATIONS (should be a fully qualified address)
# - the administrator envelope address may be a simple fixed e-mail address
#   (a scalar), or may depend on the RECIPIENT address (e.g. its domain).
#
#   Empty or undef lookup disables virus admin notifications.

# The full set of configurable administrator addresses is:
#   @virus_admin_maps    ... notifications to admin about viruses
#   @newvirus_admin_maps ... newly encountered viruses since amavisd startup
#   @spam_admin_maps     ... notifications to admin about spam
#   @banned_admin_maps   ... notifications to admin about banned contents
#   @bad_header_admin_maps ... notifications to admin about bad headers

$virus_admin = "postmaster\@$mydomain";
# $virus_admin = 'virus-admin@example.com';
# $virus_admin = undef;   # do not send virus admin notifications (default)
#
#@virus_admin_maps = (    # by-recipient maps
#  {'not.example.com' => '',
#   '.' => 'virusalert@example.com'},
#  $virus_admin,   # the usual default
#);

# equivalent to $virus_admin, but for spam admin notifications:
# $spam_admin = "spamalert\@$mydomain";
# $spam_admin = undef;    # do not send spam admin notifications (default)
#@spam_admin_maps = (     # by-recipient maps
#  {'not.example.com' => '',
#   '.' => 'spamalert@example.com'},
#  $spam_admin,   # the usual default
#);

# receive a copy of all delivery status notifications sent;
# useful for testing or monitoring
#$dsn_bcc = "mailadmin\@$mydomain";

#advanced example, using a hash lookup table and a scalar default,
#lookup key is a recipient envelope address:
#@virus_admin_maps = (    # by-recipient maps
#  { 'baduser@sub1.example.com' => 'HisBoss@sub1.example.com',
#    '.sub1.example.com'  => 'virusalert@sub1.example.com',
#    '.sub2.example.com'  => '',               # don't send admin notifications
#    'a.sub3.example.com' => 'abuse@sub3.example.com',
#    '.sub3.example.com'  => 'virusalert@sub3.example.com',
#    '.example.com'       => 'noc@example.com', # default for our virus senders
#  },
#  'virusalert@hq.example.com',  # catchall for the rest
#);

# sender envelope address, from which notification reports are sent from;
# may be a null reverse path, or a fully qualified address:
#   (admin and recip sender addresses default to a null return path).
#   If using strings in double quotes, don't forget to quote @, i.e. \@
#
$mailfrom_notify_admin     = "postmaster\@$mydomain";
$mailfrom_notify_recip     = "postmaster\@$mydomain";
$mailfrom_notify_spamadmin = "spam.police\@$mydomain";

# 'From' HEADER FIELD for sender and admin notifications.
# This should be a replyable address, see rfc1894. Not to be confused
# with $mailfrom_notify_sender, which is the envelope return address
# and can be empty (null reverse path) according to rfc2821.
#
# The syntax of the 'From' header field is specified in rfc2822, section
# '3.4. Address Specification'. Note in particular that display-name must be
# a quoted-string if it contains any special characters like spaces and dots.
#
# $hdrfrom_notify_sender = "amavisd-new <postmaster\@$mydomain>";
# $hdrfrom_notify_sender = 'amavisd-new <postmaster@example.com>';
# $hdrfrom_notify_sender = '"Content-Filter Master" <postmaster@example.com>';
# $hdrfrom_notify_admin = $mailfrom_notify_admin;
# $hdrfrom_notify_spamadmin = $mailfrom_notify_spamadmin;
#   (default: "\"Content-filter at $myhostname\" <postmaster\@$myhostname>")

# whom quarantined messages appear to be sent from (envelope sender);
# keeps original sender if undef, or set it explicitly, default is undef
$mailfrom_to_quarantine = '';   # override sender address with null return path


# Location to put infected mail into: (applies to 'local:' quarantine method)
#   empty for not quarantining, may be a file (Unix-style mailbox),
#   or a directory (no trailing slash)
#   (the default value is undef, meaning no quarantine)
#
$QUARANTINEDIR = "$MYHOME/quarantine"; # -Q

#$quarantine_subdir_levels = 1;  # add level of subdirs to disperse quarantine

#$clean_quarantine_method          = 'local:clean-%m';  # disabled by default
#$virus_quarantine_method          = 'local:virus-%m';     # default
#$spam_quarantine_method           = 'local:spam-%m.gz';   # default
#$banned_files_quarantine_method   = 'local:banned-%m';    # default
#$bad_header_quarantine_method     = 'local:badh-%m';      # default

# Separate quarantine subdirectories virus, spam, banned and badh within
# the directory $QUARANTINEDIR may be specified by the following settings
# (the subdirectories need to exist - must be created manually):
#$clean_quarantine_method          = 'local:clean/%m';
#$virus_quarantine_method          = 'local:virus/%m';
#$spam_quarantine_method           = 'local:spam/%m.gz';
#$banned_files_quarantine_method   = 'local:banned/%m';
#$bad_header_quarantine_method     = 'local:badh/%m';
#
#use the 'bsmtp:' method as an alternative to the default 'local:'
#$virus_quarantine_method = "bsmtp:$QUARANTINEDIR/virus-%m.bsmtp";
#$spam_quarantine_method  = "bsmtp:$QUARANTINEDIR/spam-%m.bsmtp";
#
#using the 'pipe:' method might be useful for some special purpose:
#$mailfrom_to_quarantine = undef;  # pass on the original sender address
#$spam_quarantine_method = 'pipe:argv=/usr/bin/myscript.sh spam-%b ${sender}';
#
#using the 'sql:' method to store quarantined message to a SQL database:
#$virus_quarantine_method = $spam_quarantine_method =
#  $banned_files_quarantine_method = $bad_header_quarantine_method = 'sql:';

# Send copy of every mail to an archival mail address:
#$archive_quarantine_method = $notify_method;
#@archive_quarantine_to_maps = ( 'collector@example.com' );


# When using the 'local:' quarantine method (default), the following applies:
#
# A finer control of quarantining is available through
# variables $virus_quarantine_method/$spam_quarantine_method/
# $banned_files_quarantine_method/$bad_header_quarantine_method.
#
# The value of scalar $virus_quarantine_to/$spam_quarantine_to (or a
# per-recipient lookup result from lookup tables @virus_quarantine_to_maps)
# is/are interpreted as follows:
#
# VARIANT 1:
#   empty or undef disables quarantine;
#
# VARIANT 2:
#   a string NOT containing an '@';
# amavisd will behave as a local delivery agent (LDA) and will quarantine
# viruses to local files according to hash %local_delivery_aliases (pseudo
# aliases map) - see subroutine mail_to_local_mailbox() for details.
# Some of the predefined aliases are 'virus-quarantine' and 'spam-quarantine'.
# Setting $virus_quarantine_to ($spam_quarantine_to) to this string will:
#
# * if $QUARANTINEDIR is a directory, each quarantined virus will go
#   to a separate file in the $QUARANTINEDIR directory (traditional
#   amavis style, similar to maildir mailbox format);
#
# * otherwise $QUARANTINEDIR is treated as a file name of a Unix-style
#   mailbox. All quarantined messages will be appended to this file.
#   Amavisd child process must obtain an exclusive lock on the file during
#   delivery, so this may be less efficient than using individual files
#   or forwarding to MTA, and it may not work across NFS or other non-local
#   file systems (but may be handy for pickup of quarantined files via IMAP
#   for example);
#
# VARIANT 3:
#   any email address (must contain '@').
# The e-mail messages to be quarantined will be handed to MTA
# for delivery to the specified address. If a recipient address local to MTA
# is desired, you may leave the domain part empty, e.g. 'infected@', but the
# '@' character must nevertheless be included to distinguish it from variant 2.
#
# This variant enables more refined delivery control made available by MTA
# (e.g. its aliases file, other local delivery agents, dealing with
# privileges and file locking when delivering to user's mailbox, nonlocal
# delivery and forwarding, fan-out lists). Make sure the mail-to-be-quarantined
# will not be handed back to amavisd for checking, as this will cause a loop
# (hopefully broken at some stage)! If this can be assured, notifications
# will benefit too from not being unnecessarily virus-scanned.
#
# By default this is safe to do with Postfix and Exim v4 and dual-sendmail
# setup, but probably not safe with sendmail milter interface without tricks.

# (default values are: virus-quarantine, banned-quarantine, spam-quarantine)

$virus_quarantine_to  = 'virus-quarantine';    # traditional local quarantine
#$virus_quarantine_to = 'infected@';           # forward to MTA for delivery
#$virus_quarantine_to = "virus-quarantine\@$mydomain";   # similar
#$virus_quarantine_to = 'virus-quarantine@example.com';  # similar
#$virus_quarantine_to = undef;                 # no quarantine
#
# lookup key is envelope recipient address:
#@virus_quarantine_to_maps = (   # per-recip multiple quarantines
#  new_RE( [qr'^user@example\.com$'i => 'infected@'],
#          [qr'^(.*)@example\.com$'i => 'virus-${1}@example.com'],
#          [qr'^(.*)(@[^@])?$'i      => 'virus-${1}${2}'] ),
#  $virus_quarantine_to,  # the usual default
#);

# similar for banned names and bad headers and spam (set to undef to disable)
$banned_quarantine_to     = 'banned-quarantine';     # local quarantine
$bad_header_quarantine_to = 'bad-header-quarantine'; # local quarantine
$spam_quarantine_to       = 'spam-quarantine';       # local quarantine

# or to a mailbox:
#$spam_quarantine_to = "spam-quarantine\@$mydomain";
#
#@spam_quarantine_to_maps = (    # per-recip multiple quarantines
#  new_RE( [qr'^(.*)@example\.com$'i => 'spam-${1}@example.com'] ),
#  $spam_quarantine_to,  # the usual default
#);


# In addition to per-recip quarantine, a by-sender lookup is possible.
# It is similar to $spam_quarantine_to, but the lookup key is the
# envelope sender address:
#$spam_quarantine_bysender_to = undef;   # dflt: no by-sender spam quarantine


# Spam level beyond which quarantining is disabled (global value):
#$sa_quarantine_cutoff_level = 20;  # dflt: undef, which disables this feature

#@spam_quarantine_cutoff_level_maps = (  # per-recip. quarantine cutoff levels
#  { 'user1@example.com' => 20.5,
#    'postmaster@example.com' => 9999,
#    '.example.com' => 25 },
#  \$sa_quarantine_cutoff_level,   # catchall default
#);


# Add X-Virus-Scanned header field to mail?
$X_HEADER_TAG = 'X-Virus-Scanned';	# (default: 'X-Virus-Scanned')

# Set to empty to add no header field	# (dflt "$myproduct_name at $mydomain")
# $X_HEADER_LINE = "$myproduct_name at $mydomain";
# $X_HEADER_LINE = "by $myproduct_name using ClamAV at $mydomain";
# $X_HEADER_LINE = "$myproduct_name $myversion_id ($myversion_date) at $mydomain";

# a string to prepend to Subject (for local recipients only) if mail could
# not be decoded or checked entirely, e.g. due to password-protected archives
#$undecipherable_subject_tag = '***UNCHECKED*** ';  # undef disables it

# MIME defanging wraps the entire original mail in a MIME container of type
# 'Content-type: multipart/mixed', where the first part is a text/plain with
# a short explanation, and the second part is a complete original mail,
# enclosed in a 'Content-type: message/rfc822' MIME part.
# Defanging is only done when enabled (selectively by malware type),
# and mail is considered malware (virus/spam/...), and the malware is allowed
# to pass (*_lovers or *_destiny=D_PASS)
#
$defang_virus  = 1;  # default is false: don't modify mail body
$defang_banned = 1;  # default is false: don't modify mail body
# $defang_bad_header     = 1;  # default is false: don't modify mail body
# $defang_undecipherable = 1;  # default is false: don't modify mail body
# $defang_spam = 1;  # default is false: don't modify mail body

# NOTE: setting the following variables to true may break mail signatures
#   (DKIM and DomainKeys) when verification is done after content filtering:
#   $remove_existing_x_scanned_headers, $remove_existing_x_scanned_headers,
#   and $allow_fixing_improper_header_folding (and defanging, described
#   elsewhere). This is rarely an issue, as mail signing should be done
#   after content filtering, and mail verification should preferably be done
#   before filtering or by SpamAssassin called from within amavisd, which
#   sees still-unmodified mail.
#
$remove_existing_x_scanned_headers = 0; # leave existing X-Virus-Scanned alone
					# (defaults to false)
#$remove_existing_x_scanned_headers= 1; # remove existing X-Virus-Scanned
#$remove_existing_spam_headers = 0;     # leave existing X-Spam* headers alone
$remove_existing_spam_headers  = 1;     # remove existing spam headers if
					# spam scanning is enabled (default)
#$allow_fixing_improper_header_folding = 1;  # (default is true)

# set $bypass_decode_parts to true if you only do spam scanning, or if you
# have a good virus scanner that can deal with compression and recursively
# unpacking archives by itself, and save amavisd the trouble.
# Disabling decoding also causes banned_files checking to only see
# MIME names and MIME content types, not the content classification types
# as provided by the file(1) utility.
# It is a double-edged sword, make sure you know what you are doing!
#
#$bypass_decode_parts = 1;		# (defaults to false)

# don't trust this file type or corresponding unpacker for this file type,
# keep both the original and the unpacked file for a virus checker to see
# (lookup key is what file(1) utility returned):
#
@keep_decoded_original_maps = (new_RE(
# qr'^MAIL$',   # retain full original message for virus checking (can be slow)
  qr'^MAIL-UNDECIPHERABLE$',  # retain full mail if it contains undecipherables
  qr'^(ASCII(?! cpio)|text|uuencoded|xxencoded|binhex)'i,
# qr'^Zip archive data',      # don't trust Archive::Zip
));


# Checking for banned MIME types and names. If any mail part matches,
# the whole mail is rejected. Object $banned_filename_re provides a list
# of Perl regular expressions to be matched against each part's:
#
#  * Content-Type value (both declared and effective mime-type),
#    such as the possible security-risk content types
#    'message/partial' and 'message/external-body', as specified in rfc2046
#    or 'application/x-msdownload' and 'application/x-msdos-program';
#
#  * declared (recommended) file names as specified by MIME subfields
#    Content-Disposition.filename and Content-Type.name, both in their
#    raw (encoded) form and in rfc2047-decoded form if applicable
#    as well as (recommended) file names specified in archives;
#
#  * file content type as guessed by 'file(1)' utility, mapped
#    (by @map_full_type_to_short_type_maps) into short type names such as
#    .asc, .txt, .html, .doc, .jpg, .pdf, .zip, .exe-ms, ..., which always
#    starts with a dot. These short types are available unless
#    $bypass_decode_parts is true.
#
# All nodes (mail parts) of the fully recursively decoded mail and embedded
# archives are checked, each node independently from remaining nodes.
#
# For each node all its ancestor nodes including itself are checked against
# $banned_filename_re lookup list, top-down. The search for a node stops
# at the first match, the right-hand side of the matching key determines
# the result (true or false, absent right-hand side implies true, as explained
# in README.lookups).
#
# Although repeatedly re-checking ancestor nodes may seem excessive, it gives
# the opportunity to specify rules which make a particular node hide its
# descendents, e.g. allow any name or file type within a .zip, even though
# .exe files may otherwise not be allowed.
#
# Leave $banned_filename_re undefined to disable these checks
# (giving an empty list to new_RE() will also always return false)

# for $banned_namepath_re (a new-style of banned table) see amavisd.conf-sample

$banned_filename_re = new_RE(

### BLOCKED ANYWHERE
# qr'^UNDECIPHERABLE$',  # is or contains any undecipherable components
  qr'^\.(exe-ms|dll)$',                   # banned file(1) types, rudimentary
# qr'^\.(exe|lha|tnef|cab|dll)$',         # banned file(1) types

### BLOCK THE FOLLOWING, EXCEPT WITHIN UNIX ARHIVES:
# [ qr'^\.(gz|bz2)$'             => 0 ],  # allow any in gzip or bzip2
# [ qr'^\.(rpm|cpio|tar)$'       => 0 ],  # allow any in Unix-type archives

  qr'.\.(pif|scr)$'i,                     # banned extensions - rudimentary
# qr'^\.zip$',                            # block zip type

### BLOCK THE FOLLOWING, EXCEPT WITHIN ARHIVES:
# [ qr'^\.(zip|rar|arc|arj|zoo)$'=> 0 ],  # allow any within these archives

  qr'^application/x-msdownload$'i,        # block these MIME types
  qr'^application/x-msdos-program$'i,
  qr'^application/hta$'i,

# qr'^message/partial$'i,         # rfc2046 MIME type
# qr'^message/external-body$'i,   # rfc2046 MIME type

# qr'^(application/x-msmetafile|image/x-wmf)$'i,  # Windows Metafile MIME type
# qr'^\.wmf$',                            # Windows Metafile file(1) type

  # block certain double extensions in filenames
  qr'\.[^./]*[A-Za-z][^./]*\.\s*(exe|vbs|pif|scr|bat|cmd|com|cpl|dll)[.\s]*$'i,
  
# qr'\{[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\}?'i, # Class ID CLSID, strict
  qr'\{[0-9a-z]{4,}(-[0-9a-z]{4,}){0,7}\}?'i, # Class ID extension CLSID, loose

  qr'.\.(exe|vbs|pif|scr|cpl)$'i,             # banned extension - basic
# qr'.\.(exe|vbs|pif|scr|cpl|bat|cmd|com)$'i, # banned extension - basic+cmd
# qr'.\.(ade|adp|app|bas|bat|chm|cmd|com|cpl|crt|emf|exe|fxp|grp|hlp|hta|
#        inf|ins|isp|js|jse|lnk|mda|mdb|mde|mdw|mdt|mdz|msc|msi|msp|mst|
#        ops|pcd|pif|prg|reg|scr|sct|shb|shs|vb|vbe|vbs|
#        wmf|wsc|wsf|wsh)$'ix,  # banned ext - long
# qr'.\.(ani|cur|ico)$'i,                 # banned cursors and icons filename
# qr'^\.ani$',                            # banned animated cursor file(1) type

# qr'.\.(mim|b64|bhx|hqx|xxe|uu|uue)$'i,  # banned extension - WinZip vulnerab.
);
# See http://support.microsoft.com/default.aspx?scid=kb;EN-US;q262631
# and http://www.cknow.com/vtutor/vtextensions.htm

# A little trick: a pattern qr'\.exe$' matches both a short type name '.exe',
# as well as any file name which happens to end with .exe. If only matching
# a file name is desired, but not the short type, a pattern qr'.\.exe$'i
# or similar may be used, which requires that at least one character precedes
# the '.exe', and so it will never match short file types which always start
# with a dot.


# the syntax of these Perl regular expressions is a bit awkward if not
# familiar with them, so please do follow examples and stick to the idioms:
#   \A        ... at the beginning of the first component
#   \z        ... at the end of the the last (leaf) component
#   ^         ... at the beginning of each component in the path
#   $         ... at the end of each component in the path
#   (.*\t)?   ... at the beginning of a field
#   (\t.*)?   ... at the end of a field
#   \t(.*\t)* ... separating fields
#   [^\t\n]   ... any single character, but don't escape from this field
#   (.*\n)+   ... one or more levels down
#   (?#...)   ... a comment within a regexp

# new-style of banned lookup table
$banned_namepath_re = new_RE(

### BLOCKED ANYWHERE

  qr'(?# BLOCK Microsoft EXECUTABLES and DLL )
     ^ (.*\t)? T=(exe-ms|dll) (\t.*)? $'xm, # banned file(1) types, rudimentary

# qr'(?# BLOCK ANY EXECUTABLE )
#    ^ (.*\t)? T=exe (\t.*)? $'xm,          # banned file(1) type

# qr'(?# BLOCK THESE TYPES )
#    ^ (.*\t)? T=(exe|lha|tnef|cab|dll) (\t.*)? $'xm,  # banned file(1) types


### BLOCK THE FOLLOWING, EXCEPT WITHIN UNIX ARHIVES:

# # within traditional gzip and bzip2 allow any name and type
# [ qr'(?#rule-3) ^ (.*\t)? T=(gz|bz2)       (\t.*)? $'xmi => 0 ],  # allow

# # within traditional Unix archives allow any name and type
# [ qr'(?#rule-4) ^ (.*\t)? T=(tar|rpm|cpio) (\t.*)? $'xmi => 0 ],  # allow

  # banned filename extensions (in declared names) anywhere - rudimentary
  qr'(?# BLOCK COMMON NAME EXENSIONS )
     ^ (.*\t)? N= [^\t\n]* \. (pif|scr) (\t.*)? $'xmi,

# # block anything within a zip
# qr'(?#rule-5) ^ (.*\t)? T=zip (\t.*)? (.*\n)+ .* $'xmi,


### BLOCK THE FOLLOWING, EXCEPT WITHIN ARHIVES OR CRYPTED:

# # within PC archives allow any types or names at any depth
# [ qr'(?#rule-7) ^ (.*\t)? T=(zip|rar|arc|arj|zoo) (\t.*)? $'xmi => 0 ],  # ok

# # within certain archives allow leaf members at any depth if crypted
# [ qr'(?# ALLOW ENCRYPTED )
#      ^ (.*\t)? T=(zip|rar|arj) (.*\n)+ (.*\t)? A=C (\t.*)? \z'xmi => 0 ],

# # allow crypted leaf members regardless of their name or type
# [ qr'(?# ALLOW IF ENCRYPTED )    ^ (.*\t)? A=C (\t.*)? \z'xmi => 0 ],

  # block these MIME types
  qr'(?#NO X-MSDOWNLOAD)   ^(.*\t)? M=application/x-msdownload   (\t.*)? $'xmi,
  qr'(?#NO X-MSDOS-PROGRAM)^(.*\t)? M=application/x-msdos-program(\t.*)? $'xmi,
  qr'(?#NO HTA)            ^(.*\t)? M=application/hta            (\t.*)? $'xmi,

# # block rfc2046 MIME types
# qr'(?# BLOCK RFC2046 ) ^ (.*\t)? M=message/partial       (\t.*)? $'xmi,
# qr'(?# BLOCK RFC2046 ) ^ (.*\t)? M=message/external-body (\t.*)? $'xmi,

# qr'(?#No Metafile MIME) ^(.*\t)? M=application/x-msmetafile (\t.*)? $'xmi,
# qr'(?#No Metafile MIME) ^(.*\t)? M=image/x-wmf              (\t.*)? $'xmi,
# qr'(?#No Metafile file) ^(.*\t)? T=wmf                      (\t.*)? $'xm,
# qr'(?#No animated cursors) ^(.*\t)? T=ani                   (\t.*)? $'xm,

  # block certain double extensions in filenames
  qr'(?# BLOCK DOUBLE-EXTENSIONS )
     ^ (.*\t)? N= [^\t\n]* \. [^./\t\n]* [A-Za-z] [^./\t\n]* \.
                  (exe|vbs|pif|scr|bat|cmd|com|cpl|dll) \.? (\t.*)? $'xmi,

  [ qr'(?# BLOCK EMPTY MIME PART APPLICATION/OCTET-STREAM )
       ^ (.*\t)? M=application/(octet-stream|x-msdownload|x-msdos-program)
       \t(.*\t)* T=empty (\t.*)? $'xmi
    => 'DISCARD' ],

# [ qr'(?# BLOCK EMPTY MIME PARTS )
#      ^ (.*\t)? M= [^\t\n]+ \t(.*\t)* T=empty (\t.*)? $'xmi => 'DISCARD' ],

# # block Class ID (CLSID) extensions in filenames, strict
# qr'(?# BLOCK CLSID-EXTENSIONS )
#    ^ (.*\t)? N= [^\t\n]* \{[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\}?
#    [^\t\n]* (\t.*)? $'xmi,

# # banned suggested names with three or more consecutive spaces
# qr'(?# BLOCK NAMES WITH SPACES )
#    ^ (.*\t)? N= [^\t\n]*  [ ]{3,} 'xmi,

# # block if any component can not be decoded (is encrypted or bad archive)
# qr'(?# BLOCK IF UNDECIPHERABLE ) ^ (.*\t)? A=U (\t.*)? \z'xmi,

# [ qr'(?# SPECIAL ALLOWANCES - MAGIC NAMES)
#      \A (.*\t)? T=(rpm|cpio|tar|zip|rar|arc|arj|zoo|Z|gz|bz2)
#         \t(.*\t)* N=example\d+[^\t\n]*
#         (\t.*)? $'xmi => 0 ],

  # banned filename extensions (in suggested names) anywhere - basic
  qr'(?# BLOCK COMMON NAME EXENSIONS )
     ^ (.*\t)? N= [^\t\n]* \. (exe|vbs|pif|scr|cpl) (\t.*)? $'xmi,

# # banned filename extensions (in suggested names) anywhere - basic+cmd
# qr'(?# BLOCK COMMON NAME EXENSIONS )
#    ^ (.*\t)? N= [^\t\n]* \. (exe|vbs|pif|scr|cpl|bat|cmd|com) (\t.*)? $'xmi,

# # banned filename extensions (in suggested names) anywhere - long
# qr'(?# BLOCK MORE NAME EXTENSIONS )
#    ^ (.*\t)? N= [^\t\n]* \. (
#    ade|adp|app|bas|bat|chm|cmd|com|cpl|crt|emf|exe|fxp|grp|hlp|hta|
#    inf|ins|isp|js|jse|lnk|mda|mdb|mde|mdw|mdt|mdz|msc|msi|msp|mst|
#    ops|pcd|pif|prg|reg|scr|sct|shb|shs|vb|vbe|vbs|
#    wmf|wsc|wsf|wsh) (\t.*)? $'xmi,

# qr'(?# BLOCK CURSOR AND ICON NAME EXENSIONS )
#    ^ (.*\t)? N= [^\t\n]* \. (ani|cur|ico) (\t.*)? $'xmi,

# # banned filename extensions anywhere - WinZip vulnerability (pre-V9)
# qr'(?# BLOCK WinZip VULNERABILITY EXENSIONS )
#    ^ (.*\t)? N= [^\t\n]* \. (mim|b64|bhx|hqx|xxe|uu|uue) (\t.*)? $'xmi,

);

# use old or new style of banned lookup table; not both to avoid confusion
#
# @banned_filename_maps = ();   # to disable old-style
  $banned_namepath_re = undef;  # to disable new-style


%banned_rules = (
  'MYNETS-DEFAULT' => new_RE(   # permissive set of rules for internal hosts
    [ qr'^\.(rpm|cpio|tar)$' => 0 ],  # allow any name/type in Unix archives
    qr'.\.(vbs|pif|scr)$'i,     # banned extension - rudimentary
  ),
  'DEFAULT' => $banned_filename_re,
);

1;  # insure a defined return
