[Logwatch-Devel] Fwd: Patches for amavis emerge vsftpd Dovecot Postfix

Kirk Bauer kirk at kaybee.org
Sun Sep 14 08:51:44 MST 2008


------------------------------------------------------
Kirk Bauer <kirk at kaybee.org>
http://linux.kaybee.org | www.logwatch.org
Author, Automating UNIX & Linux Administration




---------- Forwarded message ----------
From: Johny Ågotnes <johny at agotnes.com>
Date: Sun, Sep 14, 2008 at 3:53 AM
Subject: Patches for amavis emerge vsftpd Dovecot Postfix
To: logwatch-patches at logwatch.org


Please find attached some tidy-ups to deal with recent versions of
these programs. As I've updated my Gentoo server the logfile generated
grew to some 650kb with all the exceptions left in, now down to some
6kb and more focused for my needs.

Most changes should be generic and useful to anyone, feel free to use
as you see fit.

Postfix might not be so useful though, it is based on the 7.3.6
release as I much preferred this format over the CVS version. There is
a definite need to trim the output from Postfix 2.5.5 though as it has
a massive exception list.

Thanks for a great wee log analyser!

:)Johny

--- /root/logwatch/scripts/services/dovecot     2008-08-11
17:38:02.000000000 +0200
+++ dovecot     2008-09-14 11:57:57.000000000 +0200
@@ -130,7 +130,7 @@
      $Disconnected{$Reason}++;
   } elsif (($Reason, $Host) = ($ThisLine =~ /TLS initialization failed/) ) {
      $TLSInitFail++;
-   } elsif (($Host) = ($ThisLine =~ /Aborted login \[(.*)\]/) ) {
+   } elsif (($Host) = ($ThisLine =~ /^dovecot: imap-login: Aborted login/) ) {
      $Aborted{$Host}++;

 # This is for Dovecot 1.0 series
@@ -143,6 +143,8 @@
      $Disconnected{"no reason"}++;
   } elsif (($Reason) = ($ThisLine =~ /pop3-login: Disconnected: (.+)/) ) {
      $Disconnected{"no reason"}++;
+   } elsif (($Reason) = ($ThisLine =~ /imap-login: Disconnected (.+)/) ) {
+      $Disconnected{"no reason"}++;
   } elsif (($Reason) = ($ThisLine =~ /imap-login: Disconnected: (.+)/) ) {
      $Disconnected{"no reason"}++;
   } elsif (($Reason) = ($ThisLine =~ /IMAP.+: Disconnected: (.+)/) ) {
@@ -165,7 +167,7 @@
   print "\nDovecot was killed, and not restarted afterwards.\n";
 }

-if ( ( $Detail >=5 ) and $Restarts ) {
+if ( ( $Detail >=0 ) and $Restarts ) {
   print "\nDovecot restarted $Restarts time(s).";
 }

@@ -215,7 +217,7 @@
                 " |" . " " x $totalSpaceLength . $TotalCount . "\n";
 }

-if ( ( $Detail >= 10 ) and (keys %Login)) {
+if ( ( $Detail >= 0 ) and (keys %Login)) {
   print "\n\nDovecot IMAP and POP3 Successful Logins:";
   $LoginCount = 0;
   foreach my $User (keys %Login) {
@@ -245,7 +247,7 @@
   print "\n\nTotal: $LoginCount successful logins";
 }

-if (keys %Disconnected) {
+if ((keys %Disconnected) && ($Detail >= 10))  {
   print "\n\nDovecot disconnects:";
   foreach my $Reason (sort keys %Disconnected) {
      print "\n   $Reason: $Disconnected{$Reason} Time(s)";

--- /root/logwatch/scripts/services/emerge      2008-07-01
01:07:51.000000000 +0200
+++ emerge      2008-09-14 12:13:28.000000000 +0200
@@ -49,6 +49,7 @@
      ($ThisLine =~ /Compiling/) or
      ($ThisLine =~ /=== sync/) or
      ($ThisLine =~ /Starting rsync with/i) or
+      ($ThisLine =~ /Starting retry/) or
      ($ThisLine =~ /Merging/) or
      ($ThisLine =~ /Unmerging./) or
      ($ThisLine =~ /AUTOCLEAN/) or

--- /root/logwatch/scripts/services/postfix     2008-08-11
17:33:53.000000000 +0200
+++ postfix     2008-09-14 11:31:50.000000000 +0200
@@ -1,32 +1,117 @@
+#!/usr/bin/perl
 ##########################################################################
-# $Id: postfix,v 1.41 2008/08/11 15:33:53 mike Exp $
+# $Id: postfix,v 1.35 2007/05/14 17:27:27 mrc Exp $
 ##########################################################################
-
-#####################################################
-## Copyright (c) 2008 Sven Conrad
-## Covered under the included MIT/X-Consortium License:
-##    http://www.opensource.org/licenses/mit-license.php
-## All modifications and contributions by other persons to
-## this script are assumed to have been donated to the
-## Logwatch project and thus assume the above copyright
-## and licensing terms.  If you want to make contributions
-## under your own copyright or a different license this
-## must be explicitly stated in the contribution an the
-## Logwatch project reserves the right to not accept such
-## contributions.  If you have made significant
-## contributions to this script and want to claim
-## copyright please contact logwatch-devel at logwatch.org.
-#########################################################
-#
 # $Log: postfix,v $
-# Revision 1.41  2008/08/11 15:33:53  mike
-# Lost connection patch from Peter Johnson -mgt
-#
-# Revision 1.40  2008/06/30 23:07:51  kirk
-# fixed copyright holders for files where I know who they should be
-#
-# Revision 1.39  2008/05/25 01:16:22  mike
-# Reverting to version before the major rewrite -mgt
+# Revision 1.35  2007/05/14 17:27:27  mrc
+#  - Support for running in standalone mode (independent of logwatch)
+#  - Support postfix 2.5 TLS message changes (smtpd_tls_loglevel > 0)
+#  - Handle and report postfix/policydweight lines (postfix_PolicydWeight)
+#  - Handle and report Host offered STARTTLS lines
+#  - Move 4xx temporary rejects into their own section (experimental feature)
+#  - Allow for hold messages that do not contain a recipient
+#  - Escape metacharacters from being interpreted in recipient_delimiter
+#  - Never split mailer-daemon, double-bounce, or when recipient_delimiter
+#    is a "-" (dash) never split owner- or -request localparts
+#  - Add relay=virtual to "local" class for local vs. remote bounces
+#  - Generalize "maildrop: Unable to create a dot-lock at <path>" messages
+#  - Consolodate similar MX errors
+#  - set IP address to 127.0.0.1 when from=local, and reporting both
host/hostip
+#  - More cleanup (refactor common code, replace most global
variables with lexicals,
+#    lowercase non-global variable names, shorten variable names, etc.)
+#  - Capture postsuper hold messages
+#
+# Revision 1.34  2007/03/27 01:13:47  mrc
+#  - Lowercase recipient addresses in several Reject sections
+#  - Capture and report postfix-spf lines
+#  - New config variable postfix_PolicySPF
+#  - Capture and report reject_uknown_reverse_client_hostname
+#  - Capture and report as config warning: "looking for plugins" NSF error
+#  - fix reject header|body RE to allow "local" as host/ip
+#  - really ignore lines that don't match SyslogName;
+#  - add inc_unmatched subroutine for easier debug of unmatched lines
+#  - Capture and summarize postfix-script output (starts, stops, refresh, etc.)
+#  - Remove redundant chomps
+#
+# Revision 1.33  2007/02/27 20:28:20  mrc
+#  - Fix problem in sort routine where IP addresses were being captured
+#    anywhere in an output line for comparison via pack 'C4' - only
+#    attempt IP comparison if an IP address is the start of an output line
+#  - Provide support for syslog_name in Postfix 2.4 via postfix.conf
+#    variable postfix_Syslog_Name
+#  - Classify PIX workarounds based on type (there are several)
+#  - Change summary output criteria to check for any non-zero Totals
+#  - Don't interpolate log lines into printf; they may contain % chars
+#
+# Revision 1.32  2007/02/17 18:41:22  mrc
+#   - Ensure no output occurs when nothing is captured
+#
+# Revision 1.31  2007/02/16 06:18:45  mrc
+#   - Make reject and warn_if_reject distinct sections
+#   - Track Qids to properly report messages and bytes sent / accepted
+#   - Track both messages deferred and total deferrals
+#   - Place recipients and senders in their own keys, instead of combined
+#   - Consider reject VRFY a reject and accumulate in reject totals
+#   - Move header/body and 'MAIL from' reject code into main reject code block
+#   - Remove unused variable
+#   - Print row heading seperator lines only when appropriate
+#   - Move printing of report headings into printReports
+#   - Change Sent header to Sent via SMTP (orthogonal to Sent via LMTP)
+#
+# Revision 1.30  2007/02/09 22:26:39  mrc
+#   - Added new postfix.conf configuration variable
"postfix_Recipient_Delimiter",
+#     which can be set to match the postfix variable "recipient_delimiter".
+#     Allows Delivered and Sent reports to be grouped by email addresses
+#     minus their address extension.
+#   - Added new postfix.conf configuration variable "postfix_Max_Report_Width",
+#     to control maximum report width in postfix.conf
+#   - All line widths in report now obey max report width
+#   - Added VFRY reject section
+#   - Added RFC 3463 DSN code messages to bounce/deferred sections
+#   - Created a SASL authenticated relayed messages which hits with
+#     sasl_sender is present in smtpd messages
+#   - Split orig_to email addresses into a subkey.  Allows reports
+#     to be grouped by primary "to" address, instead of various aliases.
+#   - Split Host & HostIP into their own keys for Bounce Remote section
+#   - For Pix Workaround section, format Host & HostIP similar to others
+#   - Add 'o' option where missing in REs
+#   - Parse and canonicalize various "host...said" remote server messages for
+#     few report sections
+#   - Add Sent via LMTP section, removing lmtp-delivered mail out of Delivered.
+#     Allows users with lmtp-based content filters to avoid double counting
+#     (but only for message counts; byte counts are still about 50% too large).
+#     Configuration variable postfix_MsgsSentLmtp controls display
+#   - Added pre-queue content-filter overload section
+#   - Reworked Bounce (local/remote) and Deferred sections
+#   - Fixed several reversed captures of Host and HostIP
+#   - Format Host and HostIP in Numeric hostname section
+#   - Changed all From -> To lines to To <- From.  From address
+#     is often bogus and To is more interesting to see.
+#   - Made Reason the primary key in Deliverable/Undeliverable
sendmail -bv tests
+#   - Modified re_DSN RE to capture DSNs missing 3 number response code
+#   - Enhanced SASL authenticated messages to capture missing log lines
+#   - Added milter-reject section
+#   - Updated 'Reject server configuration error' RE for older postfix versions
+#   - Fix copy/paste error which caused use of incorrect variable in
bad size limit
+#   - Add Concurrency limit reached section
+#   - Add "maildrop" to the list of relay's considered local in Bounce section
+#   - Thanks: Jorey Bump, Mike Horwath,
+#
+# Revision 1.29  2007/01/27 20:21:46  mrc
+# Rewrite by Mike Cappella (MrC)
+#   - Provide more useful information and summaries
+#   - Provide increasing detail as requested via --detail
+#   - Provide ability to configure per section maximum detail
+#   - Optimize and combine the numerous REs
+#   - Capture and summarize many more log lines
+#   - Pin important errors to top of report
+#   - Sort by hits, IP, and lexically
+#   - Handle IPv6 addresses
+#   - Generalize log line capturing and reporting
+#   - Eliminate excessive copy/paste reporting code
+#   - Requires updated postfix.conf file
+#   - Thanks: Eray Aslan, Jorey Bump, Harald Geiger, Bill Hudacek,
+#     Frederic Jacquet, Geert Janssens, Leon Kolchinsky, Rob Myroon
 #
 # Revision 1.28  2006/12/15 06:24:49  bjorn
 # Filtering "sender non-delivery notification", by Ivana Varekova.
@@ -144,20 +229,9 @@
 # Revision 1.1  2002/03/29 15:32:14  kirk
 # Added some filters found in RH's release
 #
-#
 # Revision ???  2000/07/12 Simon Liddington <sjl at zepler.org>
 # converted from sendmail to postfix Sven Conrad <scon at gmx.net>
-# added unknown users
-# added relay denials
-# todo:
-# add authentication warnings
-# add forward errors
-# add returns after 4 hours
-# ignores alias database building
-# ignores daemon start messages
-# ignores clone messages
-# ignores all to= lines whatever follows stat=
-#
+# added unknown users, relay denials
 #
 # Revision 1.1  2003/03/21 21:10  sven
 # Initial revision
@@ -167,1033 +241,2173 @@
 ##########################################################################

 ########################################################
-# This was written and is maintained by:
-#    ??? Kenneth Porter <shiva at well.com> ???
-#    changed by Sven Conrad <scon at gmx.net>
-#
-# Please send all comments, suggestions, bug reports,
-#    etc, to ?? shiva at well.com.??
-#    Sven Conrad <scon at gmx.net>
+# Major rewrite by:
+#    Mike "MrC" Cappella <lists-logwatch at cappella.us>
+#
+# Please send all comments, suggestions, bug reports to the logwatch
+# mailing list (logwatch at logwatch.org), or to the email address above.
+# I will respond as timely as possible. [MrC]
+#
+# This file was originally written by:
+#    Kenneth Porter
 #
 ########################################################
+#
+# Test data included via inline comments starting with "#TD" and optionally
+# followed by an integer indicating replication count.
+#
+# Generate test data via the command:
+#
+#    perl -e  'while (<>) { print "$2\n" x ($1 ? $1:1)    if
/^\s*#TD(\d+)? (.*)$/}' postfix | sed "s#^#`date +"%b %d %H:%M:%S"`
`hostname` postfix/smtp[12345]: #"
+#

-my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
-my $Debug = $ENV{'LOGWATCH_DEBUG'} || 0;
+use warnings;
+no warnings "uninitialized";
+use strict;
+
+use Getopt::Long;
+use File::Basename;
+
+my $Version = "1.35.1";
+my $progname =  fileparse($0);
+my $progname_prefix = 'postfix';
+
+my %Opts = ();
+
+# Comamnd line options : config file variable
+$Opts{'detail'}                 = 10;      # report level detail
+$Opts{'max_report_width'}       = 100;     # maximum line width for
report output    : postfix_max_report_width
+$Opts{'syslog_name'} = "postfix";          # smtpd name (postconf(5),
syslog_name)   : postfix_syslog_name
+$Opts{'ipaddr_width'} = 15;                # width for printing ip
addresses         : postfix_ipaddr_width
+
+
+# The postfix-logwatch.conf file is used only in
+# standalone mode, and contains configuration variables
+# set prior to command line variables.
+# XXX: make configurable via command line switch
+my $config_file = "/usr/local/etc/${progname_prefix}-logwatch.conf";
+
+# Logwatch passes a filter's options via environment variables.
+# When running standalone (w/out logwatch), use command line options
+#
+my $standalone = $ENV{LOGWATCH_DETAIL_LEVEL} eq '' ? 1 : 0;
+
+unless ($standalone) {
+   $Opts{'detail'} = $ENV{LOGWATCH_DETAIL_LEVEL};
+}
+
+# Totals and Counts are the log line accumulators.
+# Totals: maintains section grand total for use in Summary section
+# Counts: maintains per-level key totals
+my (%Totals, %Counts);
+
+my (%UnmatchedList, %DeferredByQid, %Qids);
+
+my $OrigLine;     # used globally
+
+# Notes:
+#
+#   IN REs, always use /o option at end of RE when RE uses interpolated vars
+#   In REs, sender addresses may be empty "<>" - capture using *, not
+ ( eg. from=<[^>]*> )
+
+# IPv4 only
+#my $re_IP      = '(?:\d{1,3}\.){3}(?:\d{1,3})';
+
+# IPv4 and IPv6
+# See syntax in RFC 2821 IPv6-address-literal,
+# eg. IPv6:2001:630:d0:f102:230:48ff:fe77:96e
+my $re_IP      =
'(?:(?:::(?:ffff:|FFFF:)?)?(?:\d{1,3}\.){3}\d{1,3}|(?:[\da-fA-F]{0,4}:){2}(?:[\da-fA-F]{0,4}:){0,5}[\da-fA-F]{0,4})';
+
+my $re_DSN     = '(?:(?:\d{3})?(?: ?\d\.\d\.\d)?)';
+my $re_QID     = '[A-Z\d]+';
+my $re_DDD     = '(?:(?:conn_use=\d+ )?delay=-?[\d.]+(?:,
delays=[\d\/.]+)?(?:, dsn=[\d.]+)?)';
+
+sub usage($);
+sub version($);
+sub commify($);
+sub inc_unmatched($ $);
+sub get_vars_from_file($);
+sub env_to_cmdline(\%);
+sub buildTree(\% $ $);
+sub printTree($);
+sub printReports ($ \@);
+
+sub formathost($ $);
+sub cleanhostreply($ $ $ $);
+sub parse_spf($);
+sub parse_policydweight($);
+
+
+# References to these are used in the Formats table below; we'll
predeclare them.
+$Totals{'TotalRejects'} = 0;
+$Totals{'TotalRejectWarns'} = 0;
+$Totals{'TotalAcceptPlusReject'} = 0;
+
+#
+# The Formats table drives reports.  For each entry in the table, a
summary line and/or
+# detailed report section is a candidate for output, depending upon
logwatch Detail
+# level, and .conf configuration variables.  Each entry below has four fields:
+#
+#   1: Key to %Counts and %Totals accumulator hashes
+#   2: Numeric output format specifier
+#   3: Summary and Section Title
+#   4: A hash to a divisor used to calculate the percentage of a
total for that key
+#
+# Alternatively, when field 1 contains a single character, this character will
+# cause a line filled with that character to be output, but only if there was
+# output for that section.
+# The special name '__SECTION' is used to indicate the beginning of a
new section.
+# This ensures the printReports routine does not print needless
horizontal lines.
+#
+my @Formats = (
+   # Place configuration and critical errors appear first
+
+   [ '__SECTION' ],
+   [ 'PanicError',                  "d", "*Panic:   General panic" ],
+   [ 'FatalFileTooBig',             "d", "*Fatal:   Message file too big" ],
+   [ 'FatalConfigError',            "d", "*Fatal:   Configuration error" ],
+   [ 'FatalError',                  "d", "*Fatal:   General fatal" ],
+   [ 'WarnFileTooBig',              "d", "*Warning: Queue file size
limit exceeded" ],
+   [ 'WarnInsufficientSpace',       "d", "*Warning: Insufficient
system storage error" ],
+   [ 'WarnConfigError',             "d", "*Warning: Server
configuration error" ],
+   [ 'QueueWriteError',             "d", "*Warning: Error writing
queue file" ],
+   [ 'MessageWriteError',           "d", "*Warning: Error writing
message file" ],
+   [ 'DatabaseGeneration',          "d", "*Warning: Database file
needs update" ],
+   [ 'MailerLoop',                  "d", "*Warning: Mailer loop" ],
+   [ 'StartupError',                "d", "*Warning: Startup error" ],
+   [ 'MapProblem',                  "d", "*Warning: Map lookup problem" ],
+   [ 'PrematureEOI',                "d", "*Warning: Premature end of input" ],
+   [ 'ConcurrencyLimit',            "d", "*Warning: Connection
concurrency limit reached" ],
+   [ 'ConnectionLostOverload',      "d", "*Warning: Pre-queue
content-filter connection overload" ],
+   [ 'ProcessExit',                 "d", "Process exited" ],
+   [ 'Hold',                        "d", "Placed on hold" ],
+   [ 'CommunicationError',          "d", "Postfix communications error" ],
+   [ 'SaslAuthFail',                "d", "SASL authentication failed" ],
+   [ 'LdapError',                   "d", "LDAP error" ],
+   [ 'WarningsOther',               "d", "Miscellaneous warnings" ],
+   [ 'TotalRejectWarns',            "d", "Reject warnings (warn_if_reject)" ],
+   [ '\n' ],
+
+   [ '__SECTION' ],
+   [ 'BytesAccepted',               "Z", "Bytes accepted " ],
 # Z means print scaled as in 1k, 1m, etc.
+   [ 'BytesDelivered',              "Z", "Bytes delivered" ],
+   [ '='  ],
+   [ '\n' ],
+
+   [ '__SECTION' ],
+   [ 'MsgsAccepted',                "d", "Accepted",
        \$Totals{'TotalAcceptPlusReject'} ],
+   [ 'TotalRejects',                "d", "Rejected",
        \$Totals{'TotalAcceptPlusReject'} ],
+   [ '-',                           "",  "",
        \$Totals{'TotalAcceptPlusReject'} ],
+   [ 'TotalAcceptPlusReject',       "d", "Total",
        \$Totals{'TotalAcceptPlusReject'} ],
+   [ '=', ],
+   [ '\n' ],
+
+   [ '__SECTION' ],
+   [ 'RejectRelay',                 "d", "Reject relay denied",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectHelo',                  "d", "Reject HELO/EHLO",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectUnknownUser',           "d", "Reject unknown user",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectRecip',                 "d", "Reject recipient address",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectSender',                "d", "Reject sender address",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectClient',                "d", "Reject client host",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectUnknownClient',         "d", "Reject unknown client
host",        \$Totals{'TotalRejects'} ],
+   [ 'RejectUnknownReverseClient',  "d", "Reject unknown reverse
client host",        \$Totals{'TotalRejects'} ],
+   [ 'RejectRBL',                   "d", "Reject RBL",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectHeader',                "d", "Reject header",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectBody',                  "d", "Reject body",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectSize',                  "d", "Reject message size",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectMilter',                "d", "Reject milter",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectInsufficientSpace',     "d", "Reject insufficient space",
        \$Totals{'TotalRejects'} ],
+   [ 'RejectConfigError',           "d", "Reject server configuration
error", \$Totals{'TotalRejects'} ],
+   [ 'RejectVerify',                "d", "Reject VRFY",
        \$Totals{'TotalRejects'} ],
+   [ '-', ],
+   [ 'TotalRejects',                "d", "Total Rejects",
        \$Totals{'TotalRejects'} ],
+   [ '=', ],
+   [ '\n' ],
+
+   [ '__SECTION' ],
+   [ 'TempRejectRelay',                 "d", "4xx Reject relay
denied",               \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectHelo',                  "d", "4xx Reject HELO/EHLO",
                \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectUnknownUser',           "d", "4xx Reject unknown
user",               \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectRecip',                 "d", "4xx Reject recipient
address",          \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectSender',                "d", "4xx Reject sender
address",             \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectClient',                "d", "4xx Reject client
host",                \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectUnknownClient',         "d", "4xx Reject unknown
client host",        \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectUnknownReverseClient',  "d", "4xx Reject unknown
reverse client host",        \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectRBL',                   "d", "4xx Reject RBL",
                \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectHeader',                "d", "4xx Reject header",
                \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectBody',                  "d", "4xx Reject body",
                \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectSize',                  "d", "4xx Reject message
size",               \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectMilter',                "d", "4xx Reject milter",
                \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectInsufficientSpace',     "d", "4xx Reject insufficient
space",         \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectConfigError',           "d", "4xx Reject server
configuration error", \$Totals{'TotalTempRejects'} ],
+   [ 'TempRejectVerify',                "d", "4xx Reject VRFY",
                \$Totals{'TotalTempRejects'} ],
+   [ '-', ],
+   [ 'TotalTempRejects',                "d", "Total 4xx Rejects",
      \$Totals{'TotalTempRejects'} ],
+   [ '=', ],
+   [ '\n' ],
+
+   [ '__SECTION' ],
+   [ 'RejectWarnRelay',             "d", "Reject warning relay denied", ],
+   [ 'RejectWarnHelo',              "d", "Reject warning HELO/EHLO" ],
+   [ 'RejectWarnUnknownUser',       "d", "Reject warning unknown user" ],
+   [ 'RejectWarnRecip',             "d", "Reject warning recipient address" ],
+   [ 'RejectWarnSender',            "d", "Reject warning sender address" ],
+   [ 'RejectWarnClient',            "d", "Reject warning client host" ],
+   [ 'RejectWarnUnknownClient',     "d", "Reject warning unknown
client host" ],
+   [ 'RejectWarnUnknownReverseClient', "d", "Reject warning unknown
reverse client host" ],
+   [ 'RejectWarnRBL',               "d", "Reject warning via RBL" ],
+   [ 'RejectWarnInsufficientSpace', "d", "Reject warning insufficient space" ],
+   [ 'RejectWarnConfigError',       "d", "Reject warning server
configuration error" ],
+   [ 'RejectWarnVerify',            "d", "Reject warning VRFY" ],
+   [ '-', ],
+   [ 'TotalRejectWarns',            "d", "Total Reject Warnings" ],
+   [ '=', ],
+   [ '\n' ],
+
+   [ '__SECTION' ],
+   [ 'ConnectionInbound',           "d", "Connections made" ],
+   [ 'ConnectionLost',              "d", "Connections lost" ],
+   [ 'Disconnection',               "d", "Disconnections" ],
+   [ 'RemovedFromQueue',            "d", "Removed from queue" ],
+   [ 'MsgsDelivered',               "d", "Delivered" ],
+   [ 'MsgsSent',                    "d", "Sent via SMTP" ],
+   [ 'MsgsSentLmtp',                "d", "Sent via LMTP" ],
+   [ 'MsgsForwarded',               "d", "Forwarded" ],
+   [ 'MsgsResent',                  "d", "Resent" ],
+   [ 'MsgsDeferred',                "d", "Deferred" ],
+   [ 'Deferrals',                   "d", "Deferrals" ],
+   [ 'BounceLocal',                 "d", "Bounce (local)" ],
+   [ 'BounceRemote',                "d", "Bounce (remote)" ],
+   [ 'Filtered',                    "d", "Filtered" ],
+   [ 'Discarded',                   "d", "Discarded" ],
+   [ 'Requeued',                    "d", "Requeued messages" ],
+   [ 'ReturnedToSender',            "d", "Expired and returned to sender" ],
+   [ 'SenderDelayNotification',     "d", "Sender delay notification" ],
+   [ 'DSNDelivered',                "d", "DSNs delivered" ],
+   [ 'DSNUndelivered',              "d", "DSNs undeliverable" ],
+   [ 'PolicySPF',                   "d", "Policy SPF" ],
+   [ 'PolicydWeight',               "d", "Policyd-weight" ],
+   [ '\n' ],
+
+   [ '__SECTION' ],
+   [ 'ConnectToFailure',            "d", "Connection failure (outbound)" ],
+   [ 'TimeoutInbound',              "d", "Timeout (inbound)" ],
+   [ 'HeloError',                   "d", "HELO/EHLO conversations errors" ],
+   [ 'IllegalAddrSyntax',           "d", "Illegal address syntax in
SMTP command" ],
+   [ 'WarningHeader',               "d", "Header warning" ],
+   [ 'ReleasedFromHold',            "d", "Released from hold" ],
+   [ 'RBLError',                    "d", "RBL lookup error" ],
+   [ 'MxError',                     "d", "MX error" ],
+   [ 'NumericHostname',             "d", "Numeric hostname" ],
+   [ 'SmtpConversationError',       "d", "SMTP commands dialog error" ],
+   [ 'TooManyErrors',               "d", "Excessive errors in SMTP
commands dialog" ],
+   [ 'HostnameVerification',        "d", "Hostname verification errors" ],
+   [ 'HostnameValidationError',     "d", "Hostname validation error" ],
+   [ 'Deliverable',                 "d", "Address is deliverable
(sendmail -bv)" ],
+   [ 'Undeliverable',               "d", "Address is undeliverable
(sendmail -bv)" ],
+   [ 'TableChanged',                "d", "Restarts due to lookup
table change" ],
+   [ 'PixWorkaround',               "d", "Enabled PIX workaround" ],
+   [ 'TlsServerConnect',            "d", "TLS connections (server)" ],
+   [ 'TlsClientConnect',            "d", "TLS connections (client)" ],
+   [ 'SaslAuth',                    "d", "SASL authenticated messages" ],
+   [ 'SaslAuthRelay',               "d", "SASL authenticated relayed
messages" ],
+   [ 'TlsUnverified',               "d", "TLS certificate unverified" ],
+   [ 'TlsOffered',                  "d", "Host offered TLS" ],
+   [ '\n' ],
+
+   [ '__SECTION' ],
+   [ 'PostfixStart',                "d", "Postfix start" ],
+   [ 'PostfixStop',                 "d", "Postfix stop" ],
+   [ 'PostfixRefresh',              "d", "Postfix refresh" ],
+   [ 'PostfixWaiting',              "d", "Postfix waiting to terminate" ],
+);
+
+#-------------------------------------------------
+# RFC 3463 DSN Codes
+# http://www.faqs.org/rfcs/rfc3463.html
+#
+# Class.Subject.Detail
+#
+# Class
+my %dsn_codes = (
+    class => {
+       "2" => "Success",
+       "4" => "Persistent Transient Failure",
+       "5" => "Permanent Failure",
+    },
+
+    subject => {
+       "0" => "Other or Undefined Status",
+       "1" => "Addressing Status",
+       "2" => "Mailbox Status",
+       "3" => "Mail System Status",
+       "4" => "Network & Routing Status",
+       "5" => "Mail Delivery Protocol Status",
+       "6" => "Message Content or Media Status",
+       "7" => "Security or Policy Status",
+    },
+
+    detail => {
+       "0.0" => "Other undefined status",
+       "1.0" => "Other address status",
+       "1.1" => "Bad destination mailbox address",
+       "1.2" => "Bad destination system address",
+       "1.3" => "Bad destination mailbox address syntax",
+       "1.4" => "Destination mailbox address ambiguous",
+       "1.5" => "Destination mailbox address valid",
+       "1.6" => "Mailbox has moved",
+       "1.7" => "Bad sender's mailbox address syntax",
+       "1.8" => "Bad sender's system address",
+
+       "2.0" => "Other or undefined mailbox status",
+       "2.1" => "Mailbox disabled, not accepting messages",
+       "2.2" => "Mailbox full",
+       "2.3" => "Message length exceeds administrative limit.",
+       "2.4" => "Mailing list expansion problem",
+
+       "3.0" => "Other or undefined mail system status",
+       "3.1" => "Mail system full",
+       "3.2" => "System not accepting network messages",
+       "3.3" => "System not capable of selected features",
+       "3.4" => "Message too big for system",
+
+       "4.0" => "Other or undefined network or routing status",
+       "4.1" => "No answer from host",
+       "4.2" => "Bad connection",
+       "4.3" => "Routing server failure",
+       "4.4" => "Unable to route",
+       "4.5" => "Network congestion",
+       "4.6" => "Routing loop detected",
+       "4.7" => "Delivery time expired",
+
+       "5.0" => "Other or undefined protocol status",
+       "5.1" => "Invalid command",
+       "5.2" => "Syntax error",
+       "5.3" => "Too many recipients",
+       "5.4" => "Invalid command arguments",
+       "5.5" => "Wrong protocol version",
+
+       "6.0" => "Other or undefined media error",
+       "6.1" => "Media not supported",
+       "6.2" => "Conversion required & prohibited",
+       "6.3" => "Conversion required but not supported",
+       "6.4" => "Conversion with loss performed",
+       "6.5" => "Conversion failed",
+
+       "7.0" => "Other or undefined security status",
+       "7.1" => "Delivery not authorized, message refused",
+       "7.2" => "Mailing list expansion prohibited",
+       "7.3" => "Security conversion required but not possible",
+       "7.4" => "Security features not supported",
+       "7.5" => "Cryptographic failure",
+       "7.6" => "Cryptographic algorithm not supported",
+       "7.7" => "Message integrity failure",
+    },
+);
+
+# Initialize the Getopts option list
+my   @format_opts = ();
+push @format_opts, 'help';
+push @format_opts, 'version';
+push @format_opts, 'debug';
+push @format_opts, 'detail=i';
+push @format_opts, 'max_report_width=i';
+push @format_opts, 'deferred=i',             \$Opts{'msgsdeferred'};
# backwards compatability
+push @format_opts, 'ipaddr_width=i',         \$Opts{'ipaddr_width'};
+push @format_opts, 'recipient_delimiter=s',  \$Opts{'recipient_delimiter'};
+push @format_opts, 'syslog_name=s',          \$Opts{'syslog_name'};
+
+# Continue building the Getopts option list from the keys
+# in the Formats list. Any option that matches a key in the Formats list
+# controls the max print level for that section.
+foreach ( @Formats ) {
+   # ignore output formatting specifiers
+   next if ($_->[0] =~ /^.$/);
+   next if ($_->[0] =~ /^\\n$/);
+   next if ($_->[0] =~ /^__/);
+
+   # all Formats-derived options are integers
+   push @format_opts, "\L$_->[0]=i";
+}
+
+# All options are placed into, and processed from ARGV.
+# Most recently seen options override earlier options.
+#
+if ($standalone) {
+   # In standalone mode, obtain any options specified in
+   # a logwatch-style config file
+   my $href = get_vars_from_file($config_file);
+   if (-f "$config_file") {
+      get_vars_from_file($config_file);
+      unshift @ARGV, env_to_cmdline(%$href);
+   }
+} else {
+   # logwatch passes all config vars via environment variables
+   @ARGV=env_to_cmdline(%ENV);
+}
+
+#print "ARGC: ", scalar @ARGV, ", ARGV: @ARGV\n";
+#$Getopt::Long::debug = 1;
+
+GetOptions (\%Opts, @format_opts) || usage(undef);
+
+exists $Opts{'version'} && version(undef);
+exists $Opts{'help'} && usage(undef);
+
+#map { print "KEY: $_ => $Opts{$_}\n"}  keys %Opts;
+#print "ARGC: ", scalar @ARGV, "ARGV: @ARGV\n";
+
+# Main processing loop
+#
+while ( <> ) {
+   my $p1 = $_;
+
+   chomp ($p1);;
+   $OrigLine = $p1;
+   #print "OrigLine: \"$OrigLine\"\n";
+
+   my ($postfix_svc);
+
+   unless (($postfix_svc, $p1) = ( $OrigLine =~ /^... .. ..:..:.. [^
]* $Opts{'syslog_name'}\/([^[:]+)(?:\[\d+\])?: (?:\[ID \d+ \w+\.\w+\]
)?(.*)$/o) ) {
+      next;
+   }
+   $p1 =~ s/\s+$//;
+
+   # We don't care about these, but see also less frequent log
entries at the of the while loop
+   next if (
+         ( $p1 =~ /^Deleted: \d message$/ )
+      or ( $p1 =~ /: replace: header / )
+      or ( $p1 =~ /: Greylisted for / )                           #
Greylisting has it's own statistics tool
+      #XXX Perhaps the following are candidates for extended statistics
+      or ( $p1 =~ /certificate verification failed for/o )
+      or ( $p1 =~ /Server certificate could not be verified/o )
+      or ( $p1 =~ /certificate peer name verification failed/o )
+      # SSL rubbish when logging at/above INFO level
+      or ( $p1 =~ /^[a-f\d]{4} [a-f\d]{2}/ )
+      or ( $p1 =~ /^[a-f\d]{4} - <SPACES/ )
+      # more from mail.info level and above
+      or ( $p1 =~ m/^read from [a-f\d]{8}/ )
+      or ( $p1 =~ m/^write to [a-f\d]{8}/ )
+
+   );
+
+   my ($helo, $relay, $from, $origto, $to, $domain, $status,
+       $type, $reason, $reason2, $filter, $site, $cmd, $qid, $p2,
+       $rej_action, $host, $hostip);
+
+   # ^fatal: ...
+   if ( ($reason) = ($p1 =~ /^fatal: (.*)$/ )) {
+
+      if ($reason =~ /^[^ ]*\(\d+\): Message file too big$/) {
+         #TD fatal: root(0): Message file too big
+         $Totals{'FatalFileTooBig'}++;
+
+      # XXX its not clear this is at all useful - consider falling
through to last case
+      } elsif ( $reason =~ /^config variable ([^ ]*): (.*)$/ ) {
+         #TD fatal: config variable inet_interfaces: host not found:
10.0.0.1:2525
+         #TD fatal: config variable inet_interfaces: host not found: all:2525
+         $Totals{'FatalConfigError'}++;
+         $Counts{'FatalConfigError'}{$reason}++;
+      }
+      else {
+         #TD fatal: watchdog timeout
+         #TD fatal: bad boolean configuration: smtpd_use_tls =
+         $Totals{'FatalError'}++;
+         $Counts{'FatalError'}{"\u$reason"}++;
+      }
+   }

-my $re_DSN     = '(?:\d{3}(?: \d\.\d\.\d)?)';
-my $re_MsgID   = '[a-zA-Z\d]+';
+   # Policy-spf
+   elsif ($postfix_svc eq 'policy-spf') {

-$MsgsQueue              = 0;
-$BytesTransferred       = 0;
-$FourHourReturns        = 0;
-$ReturnedToSender       = 0;
-$ResentMessages         = 0;
-$RemovedFromQueue       = 0;
-$UnsupportedFamily      = 0;
-$TableChanged           = 0;
-$QueueSizeExceeded      = 0;
-$RejectedRBL            = 0;
-$ErrorRBL               = 0;
-$NoFreeSpace            = 0;
-$RejectClients          = 0;
-$RejectUnknownClients   = 0;
-$Undeliverable          = 0;
-$Deliverable            = 0;
+      my ($reason, $domain, $IP, $reason2) = parse_spf($p1);
+      next unless ($reason);

-while (defined($ThisLine = <STDIN>)) {
-   if (
-      ( $ThisLine =~ m/^$re_MsgID: client=([^ ]*\[[^ ]*\])\s*$/ ) or
-      ( $ThisLine =~ m/^$re_MsgID: message-id/ ) or
-      ( $ThisLine =~ m/^$re_MsgID: skipped, still being delivered/ ) or
-      ( $ThisLine =~ m/^$re_MsgID: to=\<.*>, relay=.*,
delay=[\d.]+,(?: delays=[\d\/.]+, dsn=[\d.]+,)?
status=(?:sent|deferred)/ ) or
-      ( $ThisLine =~ m/^$re_MsgID: host [^ ]*\[[^ ]*\] said: 4[0-9][0-9]/ ) or
-      ( $ThisLine =~ m/^$re_MsgID: host [^ ]*\[[^ ]*\] refused to
talk to me: 4[0-9][0-9]/ ) or
-      ( $ThisLine =~ m/^$re_MsgID: sender non-delivery notification:
$re_MsgID/ ) or
-      ( $ThisLine =~ m/^Deleted: \d message$/ ) or
-      ( $ThisLine =~ m/^Peer certficate could not be verified$/ ) or
#postfix typo
-      ( $ThisLine =~ m/^Peer certificate could not be verified$/ ) or
-      ( $ThisLine =~ m/^Peer verification:/ ) or
-      ( $ThisLine =~ m/^SSL_accept error from/ ) or
-      ( $ThisLine =~ m/^Verified: / ) or
-      ( $ThisLine =~ m/^cert has expired/ ) or
-      ( $ThisLine =~ m/^connect/ ) or
-      ( $ThisLine =~ m/^daemon started$/ ) or
-      ( $ThisLine =~ m/^daemon started -- version / ) or
-      ( $ThisLine =~ m/^dict_eval_action:/ ) or
-      ( $ThisLine =~ m/^disconnect/ ) or
-      ( $ThisLine =~ m/^mynetworks:/ ) or
-      ( $ThisLine =~ m/^name_mask:/ ) or
-      ( $ThisLine =~ m/^reload configuration/ ) or
-      ( $ThisLine =~ m/^setting up TLS connection (from|to)/ ) or
-      ( $ThisLine =~ m/^starting TLS engine$/ ) or
-      ( $ThisLine =~ m/^terminating on signal 15$/ ) or
-      ( $ThisLine =~ m/^warning: $re_MsgID: skipping further client
input$/ ) or
-      ( $ThisLine =~ m/^warning: (?:smtpd_peer_init: )?[\.0-9]+:
address not listed for hostname/ ) or
-      ( $ThisLine =~ m/^warning: (?:smtpd_peer_init: )?[\.0-9]+:
hostname .* verification failed: Host not found/ ) or
-      ( $ThisLine =~ m/^warning: (?:smtpd_peer_init: )?[\.0-9]+:
hostname .* verification failed: Name or service not known/ ) or
-      ( $ThisLine =~ m/^warning: (?:smtpd_peer_init: )?[\.0-9]+:
hostname .* verification failed: Temporary failure in name resolution/
) or
-      ( $ThisLine =~ m/^warning: Mail system is down -- accessing
queue directly$/ ) or
-      ( $ThisLine =~ m/^warning: SASL authentication failure:
Password verification failed$/ ) or
-      ( $ThisLine =~ m/^warning: SASL authentication failure: no
secret in database$/ ) or
-      ( $ThisLine =~ m/^warning: no MX host for .* has a valid A record$/ ) or
-      ( $ThisLine =~ m/^warning: numeric domain name in resource data
of MX record for .*$/ ) or
-      ( $ThisLine =~ m/^warning: premature end-of-input from cleanup
socket while reading input attribute name$/ ) or
-      ( $ThisLine =~ m/^warning: uid=\d: Broken pipe$/ ) or
-      ( $ThisLine =~ m/^verify error:num=/ ) or
-      ( $ThisLine =~ m/hold: header / )
-      or ( $ThisLine =~ m/^statistics: max / )
-      or ( $ThisLine =~ m/^statistics: start interval / )
-      or ( $ThisLine =~ m/^statistics: (address|domain) lookup / )
-      or ( $ThisLine =~ m/: replace: header / )
-      or ( $ThisLine =~ m/: Greylisted for / )
   # Greylisting has it's own statistics tool
-      or ( $ThisLine =~ m/certificate verification failed for/o )
   # Perhaps a candidate for extended statistics
-      or ( $ThisLine =~ m/Server certificate could not be verified/o
)   # Perhaps a candidate for extended statistics
-      or ( $ThisLine =~ m/certificate peer name verification failed/o
)  # Perhaps a candidate for extended statistics
-      or ( $ThisLine =~ m/sender non-delivery notification:/o )
  # Perhaps a candidate for extended statistics
-   ) {
-      # We don't care about these
-   } elsif ( ($Bytes) = ($ThisLine =~ /^$re_MsgID: from=[^,]+,
size=(\d+), .*$/o) ) {
-       #fixme count
-      $MsgsQueue++;
-      $BytesTransferred += $Bytes;
-   } elsif (($User) = ($ThisLine =~ /^$re_MsgID: to=\<([^ ]*)>,(?:
orig_to=\<(?:[^ ]*)>,)? relay=local, delay=-?\d+, status=bounced
\((?:unknown user|user unknown)/)) {
-      # unknown user
-      $UnknownUsers{$User}++;
-   } elsif (($User) = ($ThisLine =~ /^$re_MsgID: reject: RCPT from
(?:[^ ]*): $re_DSN <([^ ]*)>:(?:[^:]+: )?User unknown in(?: \w+)+
table/)) {
-      # unknown local mailbox, alias, virtual user
-      $UnknownUsers{$User}++;
-   } elsif (($User) = ($ThisLine =~ /^$re_MsgID: to=\<([^ ]*)>,(?:
orig_to=\<(?:[^ ]*)>,)? .*, status=bounced .*: User unknown in virtual
(alias|mailbox) table/)) {
-      # another unknown user probably could combine with local
unknown but again my perl is weak
-      $UnknownUsers{$User}++;
-   } elsif (($Dest, $Relay, $Msg) = ($ThisLine =~ /^$re_MsgID:
to=\<([^ ]*)>,(?: orig_to=\<(?:[^ ]*)>,)? relay=([^ ]*).*,
delay=-?[\d.]+(?:, delays=[\d\/.]+, dsn=[\d.]+)?, status=bounced
\(([^)]*)/ )) {
-      # unknown user
-      # $Msg = " hello "
-      # print "bounce message from " . $Dest . " msg : " . $Relay . "\n";
-      if ($Relay =~ m/^(none|local|avcheck|127\.0\.0\.1)/) {
-         $Temp = "To " . $Dest . " Msg=\"" . $Msg . "\"";
-         $LocalBounce{$Temp}++;
+      $Totals{'PolicySPF'}++;
+      if ($IP) {
+         $Counts{'PolicySPF'}{$reason}{$domain}{$IP}{$reason2}++;
      } else {
-         $Temp = "To " . $Dest . " Msg=\"" . $Msg . "\"";
-         $ForeignBounce{$Temp}++;
+         $Counts{'PolicySPF'}{$reason}{$domain}{$reason2}++;
      }
-   } elsif ( ($Relay,$Dest) = ($ThisLine =~ m/reject: RCPT from ([^
]*): $re_DSN <([^ ]*)>.* Relay access denied.* to=([^ ]*)/) ) {
-      # print "reject: " . $ThisLine . "\n";
-      # print "Relay :" . $Relay . " to " . $Dest . "\n";
-      $Temp = "From " . $Relay . " to " . $Dest;
-      $RelayDenied{$Temp}++;
-   } elsif ( ($User,$From) = ($ThisLine =~ /^$re_MsgID: uid=([^ ]*)
from=\<([^ ]*)>/)) {
-      #Messages sent by user
-      $Temp = $From . " (uid=" . $User . "): ";
-      $SentBy{$Temp}++;
-   } elsif ( ($From) = ($ThisLine =~ /^$re_MsgID: from=<([^ ]*)>,
status=expired, returned to sender$/)) {
-      $ReturnedToSender++;
-   } elsif ( (undef) = ($ThisLine =~ /^$re_MsgID:
resent-message-id=<([^ ]*)>$/)) {
-      $ResentMessages++;
-   } elsif (
-         ($Command,$Host) = ($ThisLine =~ /lost connection after (.*)
from ([^ ]*)$/) or
-         ($Host,$Command) = ($ThisLine =~ /^$re_MsgID: lost
connection with ([^ ]*) while (.*)$/)
-      ) {
-      # Make some better summary with hosts
-      $ConnectionLost{$Command}++;
-   } elsif (
-         ($Command,$Host) = ($ThisLine =~ /timeout after (.*) from
([^ ]*)$/) or
-         ($Host,$Command) = ($ThisLine =~ /^$re_MsgID: conversation
with ([^ ]*) timed out while (.*)$/)
-      ) {
-      # Make some better summary with hosts
-      $ConnectionLost{$Command}++;
-   } elsif ( ($Rejected,undef,undef,undef,$Reason) = ($ThisLine =~
/^$re_MsgID: reject: header (.*); from=<([^ ]*)> to=<([^ ]*)>(
proto=[^ ]* helo=<[^ ]*>)?: (.*)$/)) {
-      $HeaderReject{$Reason}{$Rejected}++;
-   } elsif ( ($Warning,undef,undef,undef,$Reason) = ($ThisLine =~
/^$re_MsgID: warning: header (.*); from=<([^ ]*)> to=<([^ ]*)>(
proto=[^ ]* helo=<[^ ]*>)?: (.*)$/)) {
-      $HeaderWarning{$Reason}{$Warning}++;
-   } elsif ( ($Warning,undef,undef,undef) = ($ThisLine =~
/^$re_MsgID: warning: header (.*); from=<([^ ]*)> to=<([^ ]*)>(
proto=[^ ]* helo=<[^ ]*>)?$/)) {
-      $HeaderWarning{"Unknown Reason"}{$Warning}++;
-   } elsif ( ($Rejected,undef,undef,undef,$Reason) = ($ThisLine =~
/^$re_MsgID: reject: body (.*); from=<([^ ]*)> to=<([^ ]*)>( proto=[^
]* helo=<[^ ]*>)?: (.*)$/)) {
-      $BodyReject{$Reason}{$Rejected}++;
-   } elsif ( (undef,undef,undef,$Reason) = ($ThisLine =~ /^$re_MsgID:
to=<([^ ]*)>,( orig_to=<[^ ]*>,)? relay=([^ ]*), delay=\d+,
status=undeliverable \((.*)\)$/)) {
-      $Undeliverable++;
-      $UndeliverableMsg{$Reason}++;
-   } elsif ( (undef,undef,undef,undef) = ($ThisLine =~ /^$re_MsgID:
to=<([^ ]*)>,( orig_to=<[^ ]*>,)? relay=([^ ]*), delay=\d+,
status=deliverable \((.*)\)$/)) {
-      $Deliverable++;
-   } elsif ( ($Host,$Sender,$Reason) = ($ThisLine =~ /reject: RCPT
from ([^ ]*\[[^ ]*\]): $re_DSN <(.*)>: Sender address rejected:
(.*);/)) {
-      $RejectSender{$Reason}{$Host}{$Sender}++;
-      $RejectSenderHost{$Reason}{$Host}++;
-      $RejectSenderReason{$Reason}++;
-   } elsif ( ($Host,$Reason,$Sender,$Recip) = ($ThisLine =~ /reject:
RCPT from ([^ ]*\[[^ ]*\]): $re_DSN <[^ ]*\[[^ ]*\]>: Client host
rejected: (.*); from=<(.*)> to=<(.*)> proto=/)) {
-      $RejectClient{$Reason}{$Host}{$Sender}{$Recip}++;
-      $RejectClientHost{$Reason}{$Host}++;
-      $RejectClientReason{$Reason}++;
-   } elsif ( ($Host,$Sender,$Recip,$Helo) = ($ThisLine =~ /reject:
RCPT from [^ ]*\[([^ ]*)\]: $re_DSN Client host rejected: cannot find
your hostname, \[\d+\.\d+\.\d+\.\d+\]; from=<(.*?)> to=<(.*?)>
proto=\S+ helo=<(.*)>/)) {
-      $RejectUnknownClient{$Host}{$Helo}{$Sender}{$Recip}++;
-      $RejectUnknownClientHost{"$Host  helo=<$Helo>"}++;
-      $RejectUnknownClients++;
-   } elsif ( ($Host,$Recip,$Reason) = ($ThisLine =~ /reject: RCPT
from ([^ ]*\[[^ ]*\]): $re_DSN <(.*)>: Recipient address rejected:
(.*);/)) {
-      $Temp = "$Host : $Reason";
-      $RejectRecip{$Recip}{$Temp}++;
-   } elsif ( ($Host,undef) = ($ThisLine =~ /reject: RCPT from ([^
]*\[[^ ]*\]): $re_DSN <(.*)>: Sender address rejected: Access
denied;/)) {
-      $RejectAddress{$Host}++;
-   } elsif ( ($Host,$Site,$Reason) = ($ThisLine =~ /reject: RCPT from
([^ ]*\[[^ ]*\]): $re_DSN Service unavailable; (?:Client host )?\[[^
]*\] blocked using ([^ ]*), reason: (.*);/)) {
-      $Temp = "$Host : $Reason";
-      $RejectRBL{$Site}{$Temp}++;
-      $RejectedRBL++;
-   } elsif ( ($Host,$Site) = ($ThisLine =~ /reject: RCPT from ([^
]*\[[^ ]*\]): $re_DSN Service unavailable; (?:Sender address |Client
host )?\[[^ ]*\] blocked using ([^ ]*);/)) {
-      $RejectRBL{$Site}{$Host}++;
-      $RejectedRBL++;
-   } elsif ( ($Host,$Site,$Reason) = ($ThisLine =~ /warning: ([^ ]*):
RBL lookup error: Name service error for \d+\.\d+\.\d+\.\d+\.([^ ]*):
(.*)$/)) {
-      $Temp = "$Host : $Reason";
-      $RBLError{$Site}{$Temp}++;
-      $ErrorRBL++;
-   } elsif ( ($Host,$Site,$Reason) = ($ThisLine =~ /discard: RCPT
from ([^ ]*\[[^ ]*\]): ([^ ]*): ([^;]*);/)) {
-      $Discarded{$Site}{$Reason}++;
-   } elsif ( (undef,undef,$Error) = ($ThisLine =~ /warning: ([^ ]*):
hostname ([^ ]*) verification failed: (.*)$/)) {
-      $HostnameVerification{$Error}++;
-   } elsif ( $ThisLine =~ /^$re_MsgID: removed\s*$/) {
-      $RemovedFromQueue++;
-   } elsif ( ($Host) = ($ThisLine =~ /^$re_MsgID: enabling PIX
<CRLF>.<CRLF> workaround for ([^ ]*\[[^ ]*\])$/)) {
-      $PixWorkaround{$Host}++;
-   } elsif ( ($Message) = ($ThisLine =~ /warning: valid_hostname: (.*)$/)) {
-      $ValidHostname{$Message}++;
-   } elsif ( ($Host,$Error) = ($ThisLine =~ /warning: host ([^ ]*\[[^
]*\]) (greeted me with my own hostname [^ ]*)$/)) {
-      $HeloError{$Error}{$Host}++;
-   } elsif ( ($Host,$Error) = ($ThisLine =~ /warning: host ([^ ]*\[[^
]*\]) (replied to HELO\/EHLO with my own hostname [^ ]*)$/)) {
-      $HeloError{$Error}{$Host}++;
-   } elsif ( ($Host,$Error) = ($ThisLine =~ /reject: RCPT from ([^
]*\[[^ ]*\]): $re_DSN <.*>: (Helo command rejected: .*);/)) {
-      $HeloError{$Error}{$Host}++;
-   } elsif ( ($Error,$Host) = ($ThisLine =~ /(bad size limit "\([^
]*\)" in EHLO reply) from ([^ ]*\[[^ ]*\])$/)) {
-      $HeloError{$Error}{$Host}++;
-   } elsif ( ($Host,$Command) = ($ThisLine =~ /warning: Illegal
address syntax from ([^ ]*\[[^ ]*\]) in ([^ ]*) command:/)) {
-      $IllegalAddressSyntax{$Command}{$Host}++;
-   } elsif ( ($Error) = ($ThisLine =~ /warning: mailer loop: (.*)$/)) {
-      $MailerLoop{$Error}++;
-   } elsif ( ($Host) = ($ThisLine =~ /warning: ([^ ]*\[[^ ]*\]): SASL
.* authentication failed/)) {
-      $SaslAuthenticationFail{$Host}++;
-   } elsif (
-         ($Host,$User) = ($ThisLine =~ /^$re_MsgID: client=([^ ]*\[[^
]*\]), .* sasl_username=([^ ]*)$/) or
-         ($Host,$User) = ($ThisLine =~ /^$re_MsgID: client=([^ ]*\[[^
]*\]), sasl_sender=([^ ]*)$/) or
-         ($Host,$User) = ($ThisLine =~ /^$re_MsgID: client=([^ ]*\[[^
]*\]), .* sasl_username=([^ ]*), sasl_sender=[^ ]*$/)
-      ) {
-      chomp($User);
-      $SaslAuth{$Host}{$User}++;
-   } elsif ( ($Host) = ($ThisLine =~ /TLS connection established from
([^ ]*\[[^ ]*\]):/)) {
-      $TLSconnectFrom{$Host}++;
-   } elsif ( ($Host) = ($ThisLine =~ /TLS connection established to
([^ ]*):/)) {
-      $TLSconnectTo{$Host}++;
-   } elsif ( ($Cert) = ($ThisLine =~ /^Unverified: (.*)/)) {
-      $TLSunverified{$Cert}++;
-   } elsif ( ($Domain) = ($ThisLine =~ /warning: malformed domain
name in resource data of MX record (.*)$/)) {
-      $MxError{$Domain}++;
-   } elsif ( ($Host,$Command) = ($ThisLine =~ /warning: ([^ ]*\[[^
]*\]) sent .* header instead of ([^ ]*) command: /)) {
-      $Error = "Sent message header instead of $Command command";
-      $SmtpConversationError{$Error}{$Host}++;
-   } elsif (
-         ($ThisLine =~ m/warning: smtp_connect_addr: socket: Address
family not supported by protocol/) or
-         ($ThisLine =~ m/warning: smtp_addr_one: unknown address
family \d for [^ ]*/)
-      ) {
-      $UnsupportedFamily++;
-   } elsif (
-         ($ThisLine =~ m/(lookup |)table has changed -- exiting$/) or
-         ($ThisLine =~ m/table ([^ ]*) has changed -- restarting$/)
-      ) {
-      $TableChanged++;
-   } elsif (
-         ($ThisLine =~ m/^fatal: [^ ]*\(\d+\): Message file too big$/) or
-         ($ThisLine =~ m/^warning: $re_MsgID: queue file size limit
exceeded$/) or
-         ($ThisLine =~ m/^warning: uid=\d+: File too large$/)
-      ) {
-      $QueueSizeExceeded++;
-   } elsif ( ($Command,$Host) = ($ThisLine =~ /too many errors after
([^ ]*) from ([^ ]*\[[^ ]*\])$/)) {
-      $TooManyErrors{$Command}{$Host}++;
-   } elsif ( (undef,undef,$To) = ($ThisLine =~ /^reject: RCPT from
([^ ]*\[[^ ]*\]): 552 Message size exceeds fixed limit; from=<([^ ]*)>
to=<([^ ]*)>$/)) {
-      $SizeLimit{"$From -> $To"}++;
-   } elsif ( ($Server) = ($ThisLine =~ /^NOQUEUE: reject: MAIL from
([^ ]*\[[^ ]*\]): 552 Message size exceeds fixed limit; proto=[^ ]*
helo=<[^ ]*>$/)) {
-      $SizeLimit{"MAIL from $Server"}++;
-   } elsif ( (undef,$Source) = ($ThisLine =~ /^warning: database ([^
]*) is older than source file ([a-zA-Z0-9\/]+)$/)) {
-      $DatabaseGeneration{$Source}++;
-   } elsif ( ($Reason) = ($ThisLine =~ /^warning: $re_MsgID: write
queue file: (.*)$/)) {
-      $QueueWriteError{$Reason}++;
-   } elsif ( ($Reason) = ($ThisLine =~ /^warning: open active
$re_MsgID: (.*)$/)) {
-      $QueueWriteError{"open active: $Reason"}++;
-   } elsif ( ($Reason) = ($ThisLine =~ /^warning:
qmgr_active_corrupt: save corrupt file queue active id $re_MsgID:
(.*)$/)) {
-      $QueueWriteError{"active corrupt: $Reason"}++;
-   } elsif ( ($Reason) = ($ThisLine =~ /^warning:
qmgr_active_done_3_generic: remove $re_MsgID: (.*)$/)) {
-      $QueueWriteError{"remove active: $Reason"}++;
-   } elsif ( ($Reason) = ($ThisLine =~ /^warning: [^ ]*\/$re_MsgID:
(Error writing message file)$/)) {
-      $MessageWriteError{$Reason}++;
-   } elsif ( $ThisLine =~ /reject: RCPT from [^ ]*\[[^ ]*\]: \d+
Insufficient system storage; from=<.*> to=<.*>/) {
-      $NoFreeSpace++;
-   } elsif ( ($Process,$Status) = ($ThisLine =~ /^warning: process
([^ ]*) pid \d+ exit status (\d+)$/)) {
-      $ProcessExit{$Status}{$Process}++;
-   } elsif ( ($Option,$Reason) = ($ThisLine =~ /^fatal: config
variable ([^ ]*): (.*)$/)) {
-      $ConfigError{$Option}{$Reason}++;
-   } elsif ( ($Warn) = ($ThisLine =~ /^warning: (.*)/)) {
-      # keep this as the next to last condition
-      $UnknownWarnings{$Warn}++;
-   } else {
-      push @OtherList,$ThisLine;
   }
-}

-##################################################################
+   # PolicydWeight
+   elsif ($postfix_svc =~ /policyd-?weight/) {

-#CRITICAL WARNINGS
-if ($NoFreeSpace > 0) {
-   print "\nWARNING!!!\n";
-   print "Insufficient system storage error $NoFreeSpace Time(s)\n";
-}
+      my ($reason, $reason2) = parse_policydweight($p1);
+      next unless ($reason);

-#STATS
-if ($MsgsQueue > 0) {
-   print "STATISTICS\n";
-   print "----------\n";
-   print "\n$BytesTransferred bytes transferred";
-   print "\n$MsgsQueue messages accepted for queue";
-}
+      $Totals{'PolicydWeight'}++;
+      $Counts{'PolicydWeight'}{$reason}{$reason2}++;
+   }

-if ($FourHourReturns > 0) {
-   print "\n$FourHourReturns messages returned after 4 hours";
-}
+   ### postfix-script
+   elsif ($postfix_svc eq 'postfix-script') {
+      if ($p1 =~ /^starting the Postfix mail system/) {
+         $Totals{'PostfixStart'}++;
+      } elsif ($p1 =~ /^stopping the Postfix mail system/) {
+         $Totals{'PostfixStop'}++;
+      } elsif ($p1 =~ /^refreshing the Postfix mail system/) {
+         $Totals{'PostfixRefresh'}++;
+      } elsif ($p1 =~ /^waiting for the Postfix mail system to terminate/) {
+         $Totals{'PostfixWaiting'}++;
+      }
+      else {
+         inc_unmatched('postfix-script', $OrigLine);
+      }
+   }

-if ($Deliverable > 0) {
-   print "\n$Deliverable messages accepted as deliverable";
-}
+   # common log entries up front
+   elsif ($p1 =~ /^connect from/) {
+      #TD25 connect from sample.net[10.0.0.1]
+      #TD connect from mail.example.com[2001:dead:beef::1]
+      #TD connect from localhost.localdomain[127.0.0.1]
+      $Totals{'ConnectionInbound'}++;
+   }
+   elsif ($p1 =~ /^disconnect from/) {
+      #TD25 disconnect from sample.net[10.0.0.1]
+      #TD disconnect from mail.example.com[2001:dead:beef::1]
+      $Totals{'Disconnection'}++;
+   }
+   elsif (($host,$hostip,$reason) = ($p1 =~ /^connect to
([^[]*)\[($re_IP)\]: (.*)$/o)) {
+      # all "connect to" messages indicate a problem with the connection
+      #TD connect to example.org[10.0.0.1]: Connection refused (port 25)
+      #TD connect to mail.sample.com[10.0.0.1]: No route to host (port 25)
+      #TD connect to sample.net[192.168.0.1]: read timeout (port 25)
+      #TD connect to mail.example.com[10.0.0.1]: server dropped
connection without sending the initial SMTP greeting (port 25)
+      #TD connect to mail.example.com[192.168.0.1]: server dropped
connection without sending the initial SMTP greeting (port 25)
+      #TD connect to ipv6-1.example.com[2001:dead:beef::1]:
Connection refused (port 25)
+      #TD connect to
ipv6-2.example.com[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:
Connection refused (port 25)
+      #TD connect to ipv6-3.example.com[1080:0:0:0:8:800:200C:4171]:
Connection refused (port 25)
+      #TD connect to ipv6-4.example.com[3ffe:2a00:100:7031::1]:
Connection refused (port 25)
+      #TD connect to ipv6-5.example.com[1080::8:800:200C:417A]:
Connection refused (port 25)
+      #TD connect to ipv6-6.example.com[::192.9.5.5]: Connection
refused (port 25)
+      #TD connect to ipv6-7.example.com[::FFFF:129.144.52.38]:
Connection refused (port 25)
+      #TD connect to ipv6-8.example.com[2010:836B:4179::836B:4179]:
Connection refused (port 25)
+      $Totals{'ConnectToFailure'}++;
+      $Counts{'ConnectToFailure'}{$reason}{formathost($hostip,$host)}++;
+   }
+
+   elsif ( ($reason) = ($p1 =~ /^panic: (.*)$/)) {
+         #TD panic: myfree: corrupt or unallocated memory block
+         $Totals{'PanicError'}++;
+         $Counts{'PanicError'}{"\u$reason"}++;
+   }
+
+   # ^warning: ...
+   elsif (my ($warning) = ($p1 =~ /^warning: (.*)$/ )) {
+      # Skip these
+      next if ( $warning =~ /$re_QID: skipping further client input$/o  );
+      next if ( $warning =~ /^Mail system is down -- accessing queue
directly$/ );
+      next if ( $warning =~ /^SASL authentication failure:
(?:Password verification failed|no secret in database)$/ );
+      next if ( $warning =~ /^no MX host for .* has a valid A record$/ );
+      next if ( $warning =~ /^uid=\d: Broken pipe$/ );
+
+      #TD warning: connect to 127.0.0.1:12525: Connection refused
+      #TD warning: problem talking to server 127.0.0.1:12525:
Connection refused
+      #TD warning: valid_ipv4_hostaddr: invalid octet count:
+
+      my ($addr, $size);
+
+      if ( ($hostip,$host,$reason) = ($warning =~
/^(?:smtpd_peer_init: )?($re_IP): hostname ([^ ]+) verification
failed: (.*)$/o ) or
+           ($hostip,$reason,$host) = ($warning =~
/^(?:smtpd_peer_init: )?($re_IP): (address not listed for hostname)
(.*)$/o )) {
+         #TD warning: 10.0.0.1: hostname sample.com verification
failed: Host not found
+         #TD warning: smtpd_peer_init: 192.168.0.1: hostname
example.com verification failed: Name or service not known
+         #TD warning: 192.168.0.1: address not listed for hostname sample.net
+         $Totals{'HostnameVerification'}++;
+         $Counts{'HostnameVerification'}{"\u$reason"}{formathost($hostip,$host)}++;
+
+      } elsif ( ($warning =~ /^$re_QID: queue file size limit exceeded$/o ) or
+                ($warning =~ /^uid=\d+: File too large$/)) {
+         $Totals{'WarnFileTooBig'}++;
+
+      } elsif ( my ($source) = ($warning =~ /^database (?:[^ ]*) is
older than source file ([\w\/]+)$/)) {
+         #TD warning: database /etc/postfix/client_checks.db is older
than source file /etc/postfix/client_checks
+         $Totals{'DatabaseGeneration'}++;
+         $Counts{'DatabaseGeneration'}{$source}++;
+
+      } elsif ( ($reason,$qid,$reason2) = ($warning =~ /^(open
active) ($re_QID): (.*)$/o ) or
+                ($reason,$qid,$reason2) = ($warning =~
/^qmgr_active_corrupt: (save corrupt file queue active) id ($re_QID):
(.*)$/o ) or
+                ($qid,$reason,$reason2) = ($warning =~ /^($re_QID):
(write queue file): (.*)$/o )) {
+
+         #TD warning: open active BDB9B1309F7: No such file or directory
+         #TD warning: qmgr_active_corrupt: save corrupt file queue
active id 4F4272F342: No such file or directory
+         #TD warning: E669DE52: write queue file: No such file or directory
+
+         $Totals{'QueueWriteError'}++;
+         $Counts{'QueueWriteError'}{"$reason: $reason2"}{$qid}++;
+
+      } elsif ( ($qid,$reason) = ($warning =~
/^qmgr_active_done_3_generic: remove ($re_QID) from active: (.*)$/o ))
{
+         #TD warning: qmgr_active_done_3_generic: remove AF0F223FC05
from active: No such file or directory
+         $Totals{'QueueWriteError'}++;
+         $Counts{'QueueWriteError'}{"remove from active: $reason"}{$qid}++;
+
+      } elsif ( my ($queue,$qid) = ($warning =~
/^([^\/]*)\/($re_QID): Error writing message file$/o )) {
+         #TD warning: maildrop/C9E66ADF: Error writing message file
+         $Totals{'MessageWriteError'}++;
+         $Counts{'MessageWriteError'}{$queue}{$qid}++;
+
+      } elsif (my ($process,$status) = ($warning =~ /^process ([^ ]*)
pid \d+ exit status (\d+)$/)) {
+         #TD warning: process /usr/lib/postfix/smtp pid 9724 exit status 1
+         $Totals{'ProcessExit'}++;
+         $Counts{'ProcessExit'}{"$process: exit status $status"}++;
+
+      } elsif ( ($reason) = ($warning =~ /^mailer loop: (.*)$/)) {
+         #TD warning: mailer loop: best MX host for example.com is local
+         $Totals{'MailerLoop'}++;
+         $Counts{'MailerLoop'}{$reason}++;
+
+      } elsif ( ($reason,$domain) = ($warning =~ /^(malformed domain
name in resource data of MX record) for (.*):$/)) {
+         #TD warning: malformed domain name in resource data of MX
record for mail.example.com:
+         $Totals{'MxError'}++;
+         $Counts{'MxError'}{"\u$reason"}{$domain}{""}++;
+
+      } elsif ( ($reason,$host,$reason2) = ($warning =~ /^(Unable to
look up MX host) for ([^:]*): (.*)$/)) {
+         #TD warning: Unable to look up MX host for example.com: Host not found
+         $reason2 = 'Host not found'  if ($reason2 =~ /^Host not
found, try again/);
+         $Totals{'MxError'}++;
+         $Counts{'MxError'}{"\u$reason"}{"\u$reason2"}{$host}{""}++;
+
+      } elsif ( ($reason,$host,$to,$reason2) = ($warning =~ /^(Unable
to look up MX host) (.*) for Sender address ([^:]*): (.*)$/)) {
+         #TD warning: Unable to look up MX host mail.example.com for
Sender address from at example.com: hostname nor servname provided, or
not known
+         $reason2 = 'Host not found'  if ($reason2 =~ /^Host not
found, try again/);
+         my ($name, $domain) = split ('@', "\L$to");
+         $Totals{'MxError'}++;
+         $Counts{'MxError'}{"\u$reason"}{"\u$reason2"}{$host}{$name}++;
+
+      } elsif ( ($host,$hostip,$type) = ($warning =~
/^([^[]+)\[($re_IP)\] sent \w+ header instead of SMTP command: (.*)$/o
)  or
+                ($host,$hostip,$type) = ($warning =~ /^non-SMTP
command from ([^[]+)\[($re_IP)\]: (.*)$/o )) {
+         # ancient
+         #TD warning: example.com[192.168.0.1] sent message header
instead of SMTP command: From: "Someone" <40245426501example.com>
+         # current
+         #TD warning: non-SMTP command from sample.net[10.0.0.1]:
Received: from 192.168.0.1 (HELO bogus.sample.com)
+
+         $Totals{'SmtpConversationError'}++;
+         $Counts{'SmtpConversationError'}{formathost($hostip,$host)}{$type}++;
+
+      } elsif ( my ($msg) = ($warning =~ /^valid_hostname: (.*)$/)) {
+         #TD warning: valid_hostname: empty hostname
+         $Totals{'HostnameValidationError'}++;
+         $Counts{'HostnameValidationError'}{$msg}++;
+
+      } elsif ( ($host,$hostip,$type) = ($warning =~
/^([^[]+)\[($re_IP)\]: SASL (.*) authentication failed/o )) {
+         #TD warning: example.com[192.168.0.1]: SASL DIGEST-MD5
authentication failed
+         $Totals{'SaslAuthFail'}++;
+         $Counts{'SaslAuthFail'}{formathost($hostip,$host)}++;
+
+      } elsif ( ($host,$site,$reason) = ($warning =~ /^([^:]*): RBL
lookup error:.* Name service error for (?:name=)?$re_IP\.([^:]*):
(.*)$/o )) {
+         #TD warning: 192.168.0.1.sbl.spamhaus.org: RBL lookup error:
Host or domain name not found. Name service error for
name=192.168.0.1.sbl.spamhaus.org type=A: Host not found, try again
+
+         #TD warning: 10.0.0.1.relays.osirusoft.com: RBL lookup
error: Name service error for 10.0.0.1.relays.osirusoft.com: Host not
found, try again
+         $Totals{'RBLError'}++;
+         $Counts{'RBLError'}{$site}{$reason}{$host}++;
+
+      } elsif (
+            ($host,$hostip,$reason,$helo) = ($warning =~ /^host
([^[]+)\[($re_IP)\] (greeted me with my own hostname) ([^ ]*)$/o ) or
+            ($host,$hostip,$reason,$helo) = ($warning =~ /^host
([^[]+)\[($re_IP)\] (replied to HELO\/EHLO with my own hostname) ([^
]*)$/o )) {
+         #TD warning: host example.com[192.168.0.1] greeted me with
my own hostname example.com
+         #TD warning: host example.com[192.168.0.1] replied to
HELO/EHLO with my own hostname example.com
+         $Totals{'HeloError'}++;
+         $Counts{'HeloError'}{"\u$reason"}{formathost($hostip,$host)}++;
+
+      } elsif ( ($host,$hostip,$cmd,$addr) = ($warning =~ /^Illegal
address syntax from ([^[]+)\[($re_IP)\] in ([^ ]*) command: (.*)/o ))
{
+         #TD warning: Illegal address syntax from
example.com[192.168.0.1] in MAIL command: user at sample.net
+         $addr =~ s/[<>]//g;
+         $Totals{'IllegalAddrSyntax'}++;
+         $Counts{'IllegalAddrSyntax'}{$cmd}{$addr}{formathost($hostip,$host)}++;
+
+      } elsif ( ($reason, $host) = ($warning =~ /^numeric (hostname):
($re_IP)$/o ) or
+                ($reason, $host) = ($warning =~ /^numeric domain name
in (resource data of MX record) for (.*)$/ )) {
+         #TD warning: numeric hostname: 192.168.0.1
+         #TD warning: numeric domain name in resource data of MX
record for sample.com: 192.168.0.1
+
+         if (($host,$hostip) = ($host =~ /([^:]+): ($re_IP)/o)) {
+            $host = formathost($hostip,$host);
+         }
+         $Totals{'NumericHostname'}++;
+         $Counts{'NumericHostname'}{"\u$reason"}{$host}++;
+
+      } elsif (my ($service,$when) = ($warning =~ /^premature
end-of-input on ([^ ]+) (.*)$/ )) {
+         #TD warning: premature end-of-input on private/anvil while
reading input attribute name
+         $Totals{'PrematureEOI'}++;
+         $Counts{'PrematureEOI'}{$service}{$when}++;
+
+      } elsif (($service,$reason) = ($warning =~ /^(.*): (bad command
startup -- throttling)/o )) {
+         #TD warning: /usr/libexec/postfix/trivial-rewrite: bad
command startup -- throttling
+         $Totals{'StartupError'}++;
+         $Counts{'StartupError'}{"Service: $service"}{$reason}++;
+
+      } elsif (($service,$reason) = ($warning =~ /(problem talking to
service [^:]*): (.*)$/o )) {
+         #TD warning: problem talking to service rewrite: Connection
reset by peer
+         #TD warning: problem talking to service rewrite: Success
+         $Totals{'CommunicationError'}++;
+         $Counts{'CommunicationError'}{"\u$service"}{$reason}++;
+
+      } elsif (my ($map,$key) = ($warning =~ /^$re_QID: ([^ ]*) map
lookup problem for (.*)$/o )) {
+         #TD warning: 6F74F74431: virtual_alias_maps map lookup
problem for root at example.com
+         $Totals{'MapProblem'}++;
+         $Counts{'MapProblem'}{"$map"}{$key}++;
+
+      } elsif (($map,$reason) = ($warning =~ /pcre map ([^,]+), (.*)$/ )) {
+         #TD warning: pcre map /etc/postfix/body_checks, line 92:
unknown regexp option "F": skipping this rule
+         $Totals{'MapProblem'}++;
+         $Counts{'MapProblem'}{$map}{$reason}++;
+
+      } elsif (($reason) = ($warning =~ /dict_ldap_lookup: (.*)$/ )) {
+         #TD warning: dict_ldap_lookup: Search error 80: Internal
(implementation specific) error
+         $Totals{'LdapError'}++;
+         $Counts{'LdapError'}{$reason}++;
+
+      } elsif ( ($size,$host,$hostip) = ($warning =~ /^bad size limit
"([^"]+)" in EHLO reply from ([^[]+)\[($re_IP)\]$/o )) {
+         #TD warning: bad size limit "-679215104" in EHLO reply from
example.com[192.168.0.1]
+         $Totals{'HeloError'}++;
+         $Counts{'HeloError'}{"Bad size limit in EHLO
reply"}{formathost($hostip,$host)}{"$size"}++;
+
+      } elsif ( ($size,$host,$hostip,$service) = ($warning =~
/^Connection concurrency limit exceeded: (\d+) from
([^[]+)\[($re_IP)\] for service (.*)/o )) {
+         #TD warning: Connection concurrency limit exceeded: 51 from
example.com[192.168.0.1] for service smtp
+         $Totals{'ConcurrencyLimit'}++;
+         $Counts{'ConcurrencyLimit'}{$service}{formathost($hostip,$host)}{$size}++;

-if ($Undeliverable > 0) {
-   print "\n$Undeliverable messages rejected as undeliverable";
-}
+      } else {
+         #TD warning: No server certs available. TLS won't be enabled
+         #TD warning: smtp_connect_addr: bind <localip>: Address already in use
+         $Totals{'WarningsOther'}++;
+         $Counts{'WarningsOther'}{$warning}++;
+      }
+   }
+   # end of warnings section
+
+
+   # ^$re_QID: ...
+   elsif ( ($qid, $p2) = ($p1 =~ /^($re_QID): (.*)$/o ) ) {
+      next if ( $p2 =~ /^client=(?:[^ ]*\[[^ ]*\])\s*$/o );
+      next if ( $p2 =~ /^skipped, still being delivered/o );
+      next if ( $p2 =~ /^host [^ ]*\[[^ ]*\] said: 4[0-9][0-9]/o );
+      next if ( $p2 =~ /^host [^ ]*\[[^ ]*\] refused to talk to me:
4[0-9][0-9]/o );
+      # postsuper double reports the following 3 lines
+      next if ( $p2 =~ /^released from hold$/o );
+      next if ( $p2 =~ /^placed on hold$/o );
+      next if ( $p2 =~ /^requeued$/o );
+
+      #TD DA080C2E0B: client=example.com[192.168.0.1]
+      #TD NOQUEUE: client=mail.example.com[2001:dead:beef::1]
+      #TD F0EC9BBE2: client=mail.example.com[2001:dead:beef::1]
+      #TD F0EC9BBE2: message-id=<C1BEA2A0.188572%from at example.com>
+
+      next if ( $p2 =~ /^message-id=/ );
+      # XXX probably don't care about message-id; for now, useful debug aid
+      #if (($p3) = ($p2 =~ /^message-id=<(.*)>$/ )) {
+      #   if (exists $Qids{$qid}) {
+      #      print "Error: Duplicate QID: $qid, $p3\n";
+      #   }
+      #   $Qids{$qid}{'message-id'} = $p3;
+      #}
+
+      my ($p3, $dsn, $DDD, $trigger);
+
+      # $re_QID: reject: ...
+      # $re_QID: reject_warning: ...
+      if (($rej_action,$p3) = ($p2 =~ /^(reject(?:_warning)?): (.*)$/ )) {
+         $rej_action =~ s/^r/R/; $rej_action =~ s/_warning$/Warn/;
+
+         # $re_QID: reject: RCPT from ...
+         if (my ($p4) = ($p3 =~ /^RCPT from (.*)$/o )) {
+            my ($p5, $p6, $recip);
+            #print "p4: $p4\n";
+
+            # Recipient address rejected: Unknown users and via
check_recipient_access
+
+            if ( $p4 !~ /^([^[]+)\[($re_IP)\]: ($re_DSN) (.*)$/o ) {
+               inc_unmatched('reject1', $OrigLine);
+               next;
+            }

-if ($ReturnedToSender >0) {
-   print "\n$ReturnedToSender messages expired and returned to sender";
-}
+            ($host,$hostip,$dsn,$p5) = ($1,$2,$3,$4);
+            #print "host: $host, hostip: $hostip, dsn: $dsn, p5: \"$p5\"\n";
+            $rej_action = "Temp$rej_action"    if ($dsn =~ /^4/);
+
+            # XXX there may be many semicolon separated messages;
need to parse based on "from="
+            if ( ($recip,$reason,$p6) = ($p5 =~ /^<(.*)>: Recipient
address rejected: ([^;]*);(.*)$/o )) {
+               # Unknown users; local mailbox, alias, virtual, relay
user, unspecified
+               if (($reason) =~ s/^User unknown *//o) {
+                  my ($table) = ($reason =~ /^in ((?:\w+ )+table)/o);
+                  ($from) = ($p6 =~ /^ from=<([^>]*)>/o );
+                  $table = "Address table unavailable" if ($table =~
/^$/);     # when show_user_unknown_table_name=no
+                  $from = "<>"         if ($from =~ /^$/);
+
+                  #TD NOQUEUE: reject: RCPT from
sample.net[192.168.0.1]: 550 <to at example.com>: Recipient address
rejected: User unknown in local recipient table; from=<>
to=<to at example.com> proto=SMTP helo=<sample.net>
+                  #TD NOQUEUE: reject_warning: RCPT from
sample.net[192.168.0.1]: 550 <to at example.com>: Recipient address
rejected: User unknown in local recipient table; from=<>
to=<to at example.com> proto=SMTP helo=<sample.net>
+                  #TD NOQUEUE: reject: RCPT from
localhost[127.0.0.1]: 550 5.1.1 <to at example.com>: Recipient address
rejected: User unknown in virtual address table;
from=<from at sample.net> to=<to at example.com> proto=ESMTP
helo=<localhost>
+                  #TD NOQUEUE: reject: RCPT from
example.com[10.0.0.1]: 450 4.1.1 <to at sample.net>: Recipient address
rejected: User unknown in virtual mailbox table;
from=<from at example.com> to=<to at sample.net> proto=ESMTP
helo=<example.com>
+                  #TD NOQUEUE: reject: RCPT from
sample.net[10.0.0.1]: 550 5.5.0 <to1 at example.com>: Recipient address
rejected: User unknown; from=<from1 at sample.net> to=<to at example.com>
proto=ESMTP helo=<[10.0.0.1]>
+                  #TD NOQUEUE: reject: RCPT from
example.com[2001:dead:beef::1]: 450 <to at example.net>: Recipient
address rejected: Greylisted; from=<from at example.com>
to=<to at example.net> proto=ESMTP helo=<example.com>
+                  #print "User: $User, table: $table\n";
+
+                  $Totals{"${rej_action}UnknownUser"}++;
+
$Counts{"${rej_action}UnknownUser"}{"\u$table"}{"\L$recip"}{$from}++;
+
+               # check_recipient_access
+               } else {
+                  #TD NOQUEUE: reject: RCPT from
example.com[10.0.0.1]: 454 4.7.1 <to at sample.net>: Recipient address
rejected: Access denied; from=<from at example.com> to=<to at sample.net>
proto=SMTP helo=<example.com>
+                  #TD NOQUEUE: reject_warning: RCPT from
example.com[10.0.0.1]: 454 4.7.1 <to at sample.net>: Recipient address
rejected: Access denied; from=<from at example.com> to=<to at sample.net>
proto=SMTP helo=<example.com>
+                  #TD NOQUEUE: reject: RCPT from
example.com[10.0.0.1]: 450 4.1.2 <to at example.com>: Recipient address
rejected: Domain not found; from=<from at sample.net> to=<to at example.com>
proto=ESMTP helo=<sample.net>
+                  #TD NOQUEUE: reject: RCPT from
example.com[10.0.0.1]: 554 <to at example.net>: Recipient address
rejected: Please see
http://www.openspf.org/why.html?sender=from%40example.net&ip=10.0.0.1&receiver=mx.example.net;
from=<from at example.net> to=<to at example.net> proto=ESMTP
helo=<to at example.com>
+                  #TD NOQUEUE: reject: RCPT from
mail.example.com[10.0.0.1]: 550 <unknown at example.net>: Recipient
address rejected: undeliverable address: host
mail.example.net[192.168.0.1] said: 550 <unknown at example.net>: User
unknown in virtual alias table (in reply to RCPT TO command);
from=<from at example.com> to=<unknown at example.net> proto=SMTP
helo=<mail.example.com>
+                  #TD NOQUEUE: reject: RCPT from unknown[10.0.0.1]:
554 <user at example.com>: Recipient address rejected: Please see
http://spf.pobox.com/why.html?sender=user%40example.com&ip=10.0.0.1&receiver=mail;
from=<user at example.com> to=<to at sample.net> proto=ESMTP helo=<10.0.0.1>
+
+                  if ($reason =~ m{^Please see http://[^/]+/why\.html}) {
+                     $reason = 'SPF reject';
+                  } elsif ($reason =~ /^undeliverable address: host
([^[]+)\[($re_IP)\] said:/o) {
+                     $reason = 'undeliverable address: remote host
rejected recipient';
+                  }

-if ($ResentMessages > 0) {
-   print "\n$ResentMessages resent messages";
-}
+                  $Totals{"${rej_action}Recip"}++;
+
$Counts{"${rej_action}Recip"}{"\u$reason"}{"\L$recip"}{formathost($hostip,$host)}++;
+               }

-if ($RemovedFromQueue > 0) {
-   print "\n$RemovedFromQueue messages removed from queue";
-}
+            } elsif ( ($to) = ($p5 =~ /^<([^ ]*)>.* Relay access
denied.* to=([^ ]*)/o ) ) {
+               #TD NOQUEUE: reject: RCPT from
example.com[192.168.0.1]: 554 <to at sample.net>: Relay access denied;
from=<from at example.com> to=<to at sample.net> proto=SMTP
helo=<example.com>
+               #TD NOQUEUE: reject_warning: RCPT from
example.com[192.168.0.1]: 554 <to at sample.net>: Relay access denied;
from=<from at example.com> to=<to at sample.net> proto=SMTP
helo=<example.com>
+               # print "host: \"$host\", hostip: \"$hostip\", To: \"$to\"\n";
+
+               $Totals{"${rej_action}Relay"}++;
+               $Counts{"${rej_action}Relay"}{formathost($hostip,$host)}{$to}++;
+
+            } elsif ( ($from,$reason) =  ($p5 =~ /^<(.*)>: Sender
address rejected: (.*);/o )) {
+               #TD NOQUEUE: reject: RCPT from sample.net[10.0.0.1]:
450 4.1.8 <from at sample.net>: Sender address rejected: Domain not
found; from=<from at sample.com> to=<to at example.com> proto=ESMTP
helo=<sample.net>
+               #TD NOQUEUE: reject_warning: RCPT from
sample.net[10.0.0.1]: 450 4.1.8 <from at sample.net>: Sender address
rejected: Domain not found; from=<from at sample.com> to=<to at example.com>
proto=ESMTP helo=<sample.net>
+               #TD NOQUEUE: reject: RCPT from
mail.example.com[10.0.0.1]: 550 <unknown at example.net>: Sender address
rejected: undeliverable address: host mail.example.net[192.168.0.1]
said: 550 <unknown at example.net>: User unknown in virtual alias table
(in reply to RCPT TO command); from=<unknown at example.net>
to=<user at example.net> proto=SMTP helo=<mail.example.com>
+               # print "host: \"$host\", hostip: \"$hostip\", from:
\"$from\", reason: \"$reason\"\n";
+               $from = "<>"            if ($from =~ /^$/);
+               if ($reason =~ /^undeliverable address: host
([^[]+)\[($re_IP)\] said:/o) {
+                  $reason = 'undeliverable address: remote host
rejected sender';
+               }
+               $Totals{"${rej_action}Sender"}++;
+
$Counts{"${rej_action}Sender"}{"\u$reason"}{formathost($hostip,$host)}{$from}++;

-if ($QueueSizeExceeded > 0) {
-   print "\n$QueueSizeExceeded messages exceeded queue or message
file size limit and removed";
-}
+            } elsif ( ($reason,$from,$recip) =   ($p5 =~
/^<[^[]+\[$re_IP\]>: Client host rejected: (.*); from=<(.*)> to=<(.*)>
proto=/o )) {

-if ($TableChanged > 0) {
-   print "\n$TableChanged exited after table change detection";
-}
+               #TD NOQUEUE: reject: RCPT from sample.net[10.0.0.1]:
554 <sample.net[10.0.0.1]>: Client host rejected: Access denied;
from=<from at sample.net> to=<to at example.com> proto=SMTP helo=<friend>
+               #TD NOQUEUE: reject_warning: RCPT from
sample.net[10.0.0.1]: 554 <sample.net[10.0.0.1]>: Client host
rejected: Access denied; from=<from at sample.net> to=<to at example.com>
proto=SMTP helo=<friend>
+               #TD NOQUEUE: reject: RCPT from sample.net[10.0.0.1]:
450 Client host rejected: cannot find your hostname, [10.0.0.1];
from=<from at sample.net> to=<to at example.com> proto=ESMTP
helo=<sample.net>
+               $from = "<>"            if ($from =~ /^$/);
+               $Totals{"${rej_action}Client"}++;
+
$Counts{"${rej_action}Client"}{"\u$reason"}{formathost($hostip,$host)}{"\L$recip"}{$from}++;
+
+            } elsif ( (my $p6) = ($p5 =~ /^Client host rejected:
cannot find your (.*)$/o )) {
+               if ( ($from,$recip,$helo) = ($p6 =~ /^hostname,
\[$re_IP\]; from=<(.*?)> to=<(.*?)> proto=\S+ helo=<(.*)>/o )) {
+                  #TD NOQUEUE: reject: RCPT from unknown[10.0.0.1]:
450 Client host rejected: cannot find your hostname, [10.0.0.1];
from=<from at example.com> to=<to at sample.net> proto=ESMTP
helo=<example.com>
+                  #TD NOQUEUE: reject_warning: RCPT from
unknown[10.0.0.1]: 450 Client host rejected: cannot find your
hostname, [10.0.0.1]; from=<from at example.com> to=<to at sample.net>
proto=ESMTP helo=<example.com>
+                  $from = "<>"         if ($from =~ /^$/);
+                  $Totals{"${rej_action}UnknownClient"}++;
+
$Counts{"${rej_action}UnknownClient"}{$host}{$helo}{$from}{"\L$recip"}++;
+
+               # reject_unknown_reverse_client_hostname (no DNS PTR
record for client's IP)
+
+               } elsif ( $p6 =~ /^reverse hostname, \[$re_IP\]/o ) {
+                  #TD NOQUEUE: reject: RCPT from
unknown[192.168.0.1]: 550 5.7.1 Client host rejected: cannot find your
reverse hostname, [192.168.0.1]
+                  $Totals{"${rej_action}UnknownReverseClient"}++;
+                  $Counts{"${rej_action}UnknownReverseClient"}{$host}++
+               } else {
+                  inc_unmatched('rejectclienthost', $OrigLine);
+               }

-if ($UnsupportedFamily > 0) {
-   print "\nUnknown address family $UnsupportedFamily Time(s)\n";
-}
+            } elsif ( ($site,$reason)  = ($p5 =~ /^Service
unavailable; (?:Client host |Sender address )?\[[^ ]*\] blocked using
([^ ]*)(, reason: .*)?;/o )) {
+               # Note: similar code below: search RejectRBL
+               #TD NOQUEUE: reject: RCPT from example.com[10.0.0.1]:
554 5.7.1 Service unavailable; Client host [10.0.0.1] blocked using
sbl-xbl.spamhaus.org; http://www.spamhaus.org/query/bl?ip=10.0.0.1;
from=<from at example.com> to=<to at sample.net> proto=ESMTP helo=<friend>
+               #TD NOQUEUE: reject_warning: RCPT from
example.com[10.0.0.1]: 554 5.7.1 Service unavailable; Client host
[10.0.0.1] blocked using sbl-xbl.spamhaus.org;
http://www.spamhaus.org/query/bl?ip=10.0.0.1; from=<from at example.com>
to=<to at sample.net> proto=ESMTP helo=<friend>
+
+               $Totals{"${rej_action}RBL"}++;
+               if ($reason =~ /^$/) {
+
$Counts{"${rej_action}RBL"}{$site}{formathost($hostip,$host)}++;
+               } else {
+
$Counts{"${rej_action}RBL"}{$site}{formathost($hostip,$host)}{$reason}++;
+               }

-#DETAILS
-if ($MsgsQueue > 0) {
-   print "\n\nDETAILS\n";
-   print "_______\n";
-}
+            } elsif ( ($reason,$helo) = ($p5 =~ /^<.*>: Helo command
rejected: (.*);.* helo=<(.*)>$/o )) {
+               #TD NOQUEUE: reject: RCPT from sample.net[10.0.0.1]:
454 4.7.1 <localhost>: Helo command rejected: Access denied;
from=<from at sample.net> to=<to at example.com> proto=SMTP helo=<localhost>
+               #TD NOQUEUE: reject_warning: RCPT from
sample.net[10.0.0.1]: 454 4.7.1 <localhost>: Helo command rejected:
Access denied; from=<from at sample.net> to=<to at example.com> proto=SMTP
helo=<localhost>
+               $Totals{"${rej_action}Helo"}++;
+
$Counts{"${rej_action}Helo"}{$reason}{formathost($hostip,$host)}{"$helo"}++;
+
+            } elsif ( ($from,$to) = ($p5 =~ /^Insufficient system
storage; from=<([^>]*)> to=<([^>]+)>/o )) {
+               #TD NOQUEUE: reject: RCPT from
example.com[192.168.0.1]: 452 Insufficient system storage;
from=<from at example.com> to=<to at sample.net>
+               #TD NOQUEUE: reject_warning: RCPT from
example.com[192.168.0.1]: 452 Insufficient system storage;
from=<from at example.com> to=<to at sample.net>
+               $from = "<>"            if ($from =~ /^$/);
+               $Totals{"${rej_action}InsufficientSpace"}++;
+
$Counts{"${rej_action}InsufficientSpace"}{formathost($hostip,$host)}{$to}{$from}++;
+
+               $Totals{'WarnInsufficientSpace'}++;    # to show in
Warnings section
+
+            } elsif ( ($from,$to) = ($p5 =~ /^Server configuration
(?:error|problem); from=<([^>]*)> to=<([^>]+)>/o )) {
+               #TD NOQUEUE: reject: RCPT from example.com[10.0.0.1]:
451 4.3.5 Server configuration error; from=<from at example.com>
to=<user at sample.net> proto=ESMTP helo=<example.com>
+               #TD NOQUEUE: reject_warning: RCPT from
example.com[10.0.0.1]: 451 4.3.5 Server configuration error;
from=<from at example.com> to=<user at sample.net> proto=ESMTP
helo=<example.com>
+               #TD NOQUEUE: reject: RCPT from
sample.net[192.168.0.1]: 450 Server configuration problem;
from=<from at sample.net> to=<to at example.com> proto=ESMTP
helo=<sample.net>
+               $from = "<>"            if ($from =~ /^$/);
+               $Totals{"${rej_action}ConfigError"}++;
+
$Counts{"${rej_action}ConfigError"}{formathost($hostip,$host)}{$to}{$from}++;
+
+               $Totals{'WarnConfigError'}++;          # to show in
Warnings section
+
+            # This would capture all other rejects, but I think it
might be more useful to add
+            # additional capture sections based on user reports of
uncapture lines.
+            #
+            #} elsif ( ($reason) = ($p5 =~ /^([^;]+);/o)) {
+            #  $Totals{"${rej_action}Other"}++;
+            #  $Counts{"${rej_action}Other"}{$reason}++;

-if (keys %ConfigError) {
-   print "\n\nWARNING!!!\n";
-   print "Configuration Errors:\n";
-   foreach $Option (sort {$a cmp $b} keys %ConfigError) {
-      print "   Option: $Option\n";
-      foreach $Reason (sort {$a cmp $b} keys %{$ConfigError{$Option}} ) {
-         print "      $Reason: $ConfigError{$Option}{$Reason} Time(s)\n";
-      }
-   }
-}
+            } else {
+               inc_unmatched('rejectother', $OrigLine);
+            }
+         }
+         # end of $re_QID: reject: RCPT from ...

-if (keys %QueueWriteError) {
-   if ($Detail >= 5) {
-      print "\n\nError writing queue file:\n";
-      foreach $Reason (sort {$a cmp $b} keys %QueueWriteError) {
-         print "   $Reason : $QueueWriteError{$Reason} Time(s)\n";
-      }
-   }
-   else {
-      $n=0;
-      foreach $Reason (keys %QueueWriteError) {
-         $n+=$QueueWriteError{$Reason};
-      }
-      print "\n\nError writing queue file: $n Time(s)";
-   }
-}
+         # $re_QID: reject: body ...
+         # $re_QID: reject: header ...
+         elsif ( ($reason,$host,$to,$reason2) = ($p3 =~
/^(?:header|body) (.*) from ([^;]+); from=<(?:[^ ]*)>(?:
to=<([^>]*)>)?(?: proto=[^ ]* helo=<[^ ]*>)?: (.*)$/o )) {
+            #TD 9804DB31C2: reject: header To: <user at example.com>
from sample.net[192.168.0.1]; from=<bogus at anywhere.com>
to=<user at example.com> proto=ESMTP helo=<anywhere.com>: Any reason
+            #TD 831C2C2E0D: reject: body Quality Replica watches!!!
from example.com[192.168.0.1]; from=<user at example.com>
to=<recip at sample.net> proto=SMTP helo=<example.com>: 5.7.1 Spam:
Watches
+            #TD 26B6AC2DB5: reject: body xx Subject: Cheapest Viagra
and Cialis you can find! from local; from=<root at localhost>: 5.7.1
Spam: Drugs
+            # Note: reject_warning does not seem to occur

-if (keys %MessageWriteError) {
-   if ($Detail >= 5) {
-      print "\n\nError writing message file:\n";
-      foreach $Reason (sort {$a cmp $b} keys %MessageWriteError) {
-         print "   $Reason : $MessageWriteError{$Reason} Time(s)\n";
-      }
-   }
-   else {
-      $n=0;
-      foreach $Reason (keys %MessageWriteError) {
-         $n+=$MessageWriteError{$Reason};
-      }
-      print "\n\nError writing message file: $n Time(s)";
-   }
-}
+            if ($host =~ /^local$/) {
+               $hostip = '127.0.0.1';
+            }
+            elsif ($host =~ /([^[]+)\[($re_IP)\]/) {
+               $host = $1; $hostip = $2;
+            }

-if (keys %DatabaseGeneration) {
-   if ($Detail >= 5) {
-      print "\n\nDatabase files are not up-to-date (probably rehash
is needed):\n";
-      foreach $Source (sort {$a cmp $b} keys %DatabaseGeneration) {
-         print "   $Source : $DatabaseGeneration{$Source} Time(s)\n";
-      }
-   }
-   else {
-      $n=0;
-      $fn=scalar(keys %DatabaseGeneration);
-      foreach $Source (keys %DatabaseGeneration) {
-         $n+=$DatabaseGeneration{$Source};
-      }
-      print "\n\nDatabase files are not up-to-date (probably rehash
is needed): $fn File(s), $n Time(s)";
-   }
-}
+            $reason =~ s/\s+/ /g;
+            if ($p3 =~ /^body/) {
+               $Totals{'RejectBody'}++;
+
$Counts{'RejectBody'}{$reason2}{$to}{formathost($hostip,$host)}{"$reason"}++;
+            }
+            else {
+               #print "reason: \"$reason\", host: \"$host\", hostip:
\"$hostip\", to: \"$to\", reason2: \"$reason2\"\n";
+               $Totals{'RejectHeader'}++;
+
$Counts{'RejectHeader'}{$reason2}{$to}{formathost($hostip,$host)}{"$reason"}++;
+            }
+         }

-if (keys %PixWorkaround) {
-   if ($Detail >= 5) {
-      print "\n\nEnabled PIX <CRLF>.<CRLF> workaround for:\n";
-      foreach $Host (sort {$a cmp $b} keys %PixWorkaround) {
-         print "   $Host : $PixWorkaround{$Host} Time(s)\n";
-      }
-   }
-   else {
-      $n=0;
-      $hn=scalar(keys %PixWorkaround);
-      foreach $Host (keys %PixWorkaround) {
-         $n+=$PixWorkaround{$Host};
-      }
-      print "\n\nEnabled PIX <CRLF>.<CRLF> workaround for: $hn
Host(s), $n Time(s)";
-   }
-}
+         # $re_QID: reject: MAIL from ...
+         elsif ( ($host,$hostip) = ($p3 =~ /^MAIL from
([^[]+)\[($re_IP)\]: $re_DSN Message size exceeds fixed limit;
proto=[^ ]* helo=<[^>]+>$/o )) {
+            # Postfix responds with this message after a MAIL
FROM:<...> SIZE=nnn  command, where postfix consider's nnn excessive
+            # Note: similar code below: search RejectSize
+            # Note: reject_warning does not seem to occur
+            #TD NOQUEUE: reject: MAIL from localhost[127.0.0.2]: 552
Message size exceeds fixed limit; proto=ESMTP helo=<localhost>
+            #TD NOQUEUE: reject: MAIL from example.com[192.168.0.2]:
452 4.3.4 Message size exceeds fixed limit; proto=ESMTP
helo=<example.com>
+            $Totals{'RejectSize'}++;
+            $Counts{'RejectSize'}{formathost($hostip,$host)}{'unknown'}++;
+         }
+
+         # $re_QID: reject: CONNECT from ...
+         elsif (($p4) = ($p3 =~ /^CONNECT from (.*)$/o )) {
+
+            if ( ($host,$hostip,$dsn,$reason) = ($p4 =~
/([^[]+)\[($re_IP)\]: ($re_DSN) <.*>: Client host rejected: ([^;]*);/o
)) {
+               #TD NOQUEUE: reject: CONNECT from
unknown[192.168.0.1]: 503 5.5.0 <unknown[192.168.0.1]>: Client host
rejected: Improper use of SMTP command pipelining; proto=SMTP
+               $rej_action = "Temp$rej_action" if ($dsn =~ /^4/);
+               $Totals{"${rej_action}Client"}++;
+
$Counts{"${rej_action}Client"}{"\u$reason"}{formathost($hostip,$host)}{""}++;
   # XXX currently need to keep same key depth - add CONNECT key to do
so
+            } else {
+               inc_unmatched('connfrom', $OrigLine);
+            }
+         }

-if (($Detail >=5) and (keys %SentBy)) {
-   print "\n\nTop ten local senders:\n";
-   foreach $ThisSender (sort {$a cmp $b} keys %SentBy) {
-      $ThisNumber = $SentBy{$ThisSender};
-      push(@{$ThisIsNumber{$ThisNumber}}, $ThisSender);
-   }
-   my $ListRank = 10;
-   foreach $SenderRank (sort {$b <=> $a} keys %ThisIsNumber) {
-      last unless ($ListRank > 0);
-      print "   $SenderRank messages sent by:\n";
-      foreach $ThisSender (@{$ThisIsNumber{$SenderRank}}) {
-         last unless ($ListRank > 0);
-         $ListRank--;
-         print"      $ThisSender\n";
-      }
-   }
-}
+         # $re_QID: reject: VRFY from ...
+         elsif (($p4) = ($p3 =~ /^VRFY from (.*)$/o )) {
+            #TD NOQUEUE: reject: VRFY from example.com[10.0.0.1]: 550
5.1.1 <:>: Recipient address rejected: User unknown in local recipient
table; to=<:> proto=SMTP helo=<192.168.0.1>
+            #TD NOQUEUE: reject_warning: VRFY from
example.com[10.0.0.1]: 450 4.1.2 <<D0-1C7-1F41F6 at BS>>: Recipient
address rejected: Domain not found; to=<<D0-1C7-1F41F6 at BS>> proto=SMTP
helo=<friend>
+            #TD NOQUEUE: reject: VRFY from example.com[10.0.0.1]: 450
4.1.8 <to at example.com>: Sender address rejected: Domain not found;
from=<to at example.com> to=<to> proto=SMTP
+            #TD NOQUEUE: reject: VRFY from example.com[10.0.0.1]: 554
5.7.1 Service unavailable; Client host [10.0.0.1] blocked using
zen.spamhaus.org; http://www.spamhaus.org/query/bl?ip=10.0.0.1; to=<u>
proto=SMTP
+
+            if ( ($host,$hostip,$dsn,$reason) = ($p4 =~
/([^[]+)\[($re_IP)\]: ($re_DSN) (?:<.*>: )?([^;]*);/o )) {
+               $rej_action = "Temp$rej_action" if ($dsn =~ /^4/);
+               $Totals{"${rej_action}Verify"}++;
+
$Counts{"${rej_action}Verify"}{"\u$reason"}{formathost($hostip,$host)}++;

-if (keys %UnknownUsers) {
-   $un=scalar(keys %UnknownUsers);
-   if ($Detail >= 10) {
-      print "\n\nUnknown users: $un Time(s)\n";
-      foreach $ThisOne (sort {$a cmp $b} keys %UnknownUsers) {
-         print "   $ThisOne : $UnknownUsers{$ThisOne} Time(s)\n";
-      }
-   }
-   else {
-      $n=0;
-      foreach $ThisOne (keys %UnknownUsers) {
-         $n+=$UnknownUsers{$ThisOne};
+            } else {
+               inc_unmatched('vrfyfrom', $OrigLine);
+            }
+         }
+         else {
+               inc_unmatched('rejectlast', $OrigLine);
+         }
      }
-      print "\n\nUnknown users: $un, $n Time(s)";
-   }
-}

-if (keys %SaslAuthenticationFail) {
-   if ($Detail >= 5) {
-      print "\n\nSASL Authentication failed from:\n";
-      foreach $Host (sort {$a cmp $b} keys %SaslAuthenticationFail) {
-         print "   $Host : $SaslAuthenticationFail{$Host} Time(s)\n";
-      }
-   }
-   else {
-      $n=0;
-      $hn=scalar(keys %SaslAuthenticationFail);
-      foreach $Host (keys %SaslAuthenticationFail) {
-         $n+=$SaslAuthenticationFail{$Host};
-      }
-      print "\n\nSASL Authentication failed from: $hn Host(s), $n Time(s)";
-   }
-}
+      # ^$re_QID: ...  (not rejects)
+      elsif ( my ($bytes,$nrcpt) = ($p2 =~ /^from=<[^>]*>,
size=(\d+), nrcpt=(\d+).*$/o ) ) {
+         #TD 4AEFAF569C11: from=<FROM: SOME USER at example.com>,
size=4051, nrcpt=1 (queue active)
+         #TD12 2A535C2E01: from=<anyone at example.com>, size=25302,
nrcpt=2 (queue active)
+         #TD F0EC9BBE2: from=<from at example.com>, size=5529, nrcpt=1
(queue active)
+
+         # Distinguish bytes accepted vs. bytes delivered due to
multiple recips
+
+         #if (!exists $Qids{$qid}) {
+         #   print "ERROR: no Qids{$qid} found\n";
+         #}
+         if (!exists $Qids{$qid} and !exists $Qids{$qid}{'nrcpt'}) {
+            $Qids{$qid}{'nrcpt'} = $nrcpt;
+            $Qids{$qid}{'size'} = $bytes;
+            $Totals{'MsgsAccepted'}++;
+            $Totals{'BytesAccepted'} += $bytes;
+         }
+         #else {
+         #   Occurs for each deferral
+         #   print "DEBUG: RETRY($Qid) $p2\n";
+         #}
+      }
+
+      ### sent, forwarded, bounced, softbounce, deferred, (un)deliverable
+      elsif ( ($to,$origto,$relay,$DDD,$status,$reason) = ($p2 =~
/^to=<([^>]*)>,(?: orig_to=\<([^>]*)>,)? relay=([^ ]*).*, ($re_DDD),
status=([^ ]+) (.*)$/o  )) {
+         #TD 552B6C20E: to=<to at sample.com>,
relay=mail.example.net[10.0.0.1]:25, delay=1021,
delays=1020/0.04/0.56/0.78, dsn=2.0.0, status=sent (250 Ok: queued as
6EAC4719EB)
+         #TD DD925BBE2: to=<to at example.net>,
orig_to=<to-ext at example.net>,
relay=mail.example.net[2001:dead:beef::1], delay=2, status=sent (250
Ok: queued as 5221227246)
+
+         $reason =~ s/\((.*)\)/$1/;    # Makes capturing nested parens easier
+         $to     = lc $to;
+         $origto = lc $origto;
+         my ($localpart, $domainpart) = split ('@', $to);
+
+         # If recipient_delimiter is set, break localpart into user + extension
+         # and save localpart in origto if origto is empty
+         #
+         if ($Opts{'recipient_delimiter'} and $localpart =~
/\Q$Opts{'recipient_delimiter'}\E/o) {
+
+            # special cases: never split mailer-daemon or double-bounce
+            # or owner- or -request if delim is "-" (dash).
+            unless ($localpart =~ /^(?:mailer-daemon|double-bounce)$/i or
+                ($Opts{'recipient_delimiter'} eq '-' and $localpart
=~ /^owner-.|.-request$/i)) {
+               my ($user,$extension) = split
(/$Opts{'recipient_delimiter'}/o, $localpart, 2);
+               $origto = $localpart    if ($origto =~ /^$/);
+               $localpart = $user;
+            }
+         }
+
+         unless (($dsn) = ($DDD =~ /dsn=(\d\.\d\.\d)/)) {
+            #$dsn = "X.X.X (DSN unavailable)";
+            $dsn = "";
+         }
+
+         ### sent
+         if ($status =~ /^sent$/) {
+            if ($reason =~ /forwarded as /) {
+               $Totals{'MsgsForwarded'}++;
+               $Counts{'MsgsForwarded'}{$domainpart}{$localpart}{$origto}++;
+            }
+            else {
+               if ($postfix_svc =~ /^lmtp$/) {
+                  $Totals{'MsgsSentLmtp'}++;
+                  $Counts{'MsgsSentLmtp'}{$domainpart}{$localpart}{$origto}++;
+               }
+               elsif ($postfix_svc =~ /^smtp$/) {
+                  $Totals{'MsgsSent'}++;
+                  $Counts{'MsgsSent'}{$domainpart}{$localpart}{$origto}++;
+               }
+               # virtual, command, ...
+               else {
+                  $Totals{'MsgsDelivered'}++;
+                  $Counts{'MsgsDelivered'}{$domainpart}{$localpart}{$origto}++;
+               }
+            }
+            if (exists $Qids{$qid} and exists $Qids{$qid}{'size'}) {
+               $Totals{'BytesDelivered'} += $Qids{$qid}{'size'};
+            }
+         }

-if (keys %SaslAuth) {
-   if ($Detail >= 5) {
-      print "\n\nSASL Authenticated messages from:\n";
-      foreach $Host (sort {$a cmp $b} keys %SaslAuth) {
-         if ($Detail >= 10) {
-            print "    $Host:\n";
-            foreach $User (sort {$a cmp $b} keys %{$SaslAuth{$Host}} ) {
-               print "        sasluser $User :
$SaslAuth{$Host}{$User} Times(s)\n";
+         ### bounced
+         elsif ($status =~ /^(?:bounced|SOFTBOUNCE)$/) {
+            #TD 76EB0D13: to=<user at example.com>, relay=none, delay=1,
status=bounced (mail for mail.example.com loops back to myself)
+            #TD C8103B94: to=<user at example.com>, relay=none, delay=0,
status=bounced (Host or domain name not found. Name service error for
name=unknown.com type=A: Host not found)
+            #TD C76431E2: to=<login at sample.net>, relay=local,
delay=2, status=SOFTBOUNCE (host sample.net[192.168.0.1] said: 450
<login at sample.com>: User unknown in local recipient table (in reply to
RCPT TO command))
+            #TD EB0B8770: to=<to at example.com>, orig_to=<postmaster>,
relay=none, delay=1, status=bounced (User unknown in virtual alias
table)
+            #TD EB0B8770: to=<to at example.com>, orig_to=<postmaster>,
relay=sample.net[192.168.0.1], delay=1.1, status=bounced (User unknown
in relay recipient table)
+            #TD D8962E54: to=<anyone at example.com>, relay=local,
conn_use=2 delay=0.21, delays=0.05/0.02/0/0.14, dsn=4.1.1,
status=SOFTBOUNCE (unknown user: "to")
+            #TD F031C832: to=<to at sample.net>,
orig_to=<alias at sample.net>, relay=local, delay=0.17,
delays=0.13/0.01/0/0.03, dsn=5.1.1, status=bounced (unknown user:
"to")
+            #TD 04B0702E: to=<anyone at example.com>,
relay=example.com[10.0.0.1]:25, delay=12, delays=6.5/0.01/0.03/5.1,
dsn=5.1.1, status=bounced (host example.com[10.0.0.1] said: 550 5.1.1
User unknown (in reply to RCPT TO command))
+            #TD 9DAC8B2D: to=<to at example.com>,
relay=example.com[10.0.0.1]:25, delay=1.4, delays=0.04/0/0.27/1.1,
dsn=5.0.0, status=bounced (host example.com[10.0.0.1] said: 511 sorry,
no mailbox here by that name (#5.1.1 - chkuser) (in reply to RCPT TO
command))
+            #TD 79CB702D: to=<to at example.com>,
relay=example.com[10.0.0.1]:25, delay=0.3, delays=0.04/0/0.61/0.8,
dsn=5.0.0, status=bounced (host example.com[10.0.0.1] said: 550
<to at example.com>, Recipient unknown (in reply to RCPT TO command))
+            #TD 88B7A079: to=<to at example.com>,
relay=example.com[10.0.0.1]:25, delay=45, delays=0.03/0/5.1/40,
dsn=5.0.0, status=bounced (host example.com[10.0.0.1] said: 550-"The
recipient cannot be verified.  Please check all recipients of this 550
message to verify they are valid." (in reply to RCPT TO command))
+            #TD 47B7B074: to=<to at example.com>,
relay=example.com[10.0.0.1]:25, delay=6.6, delays=6.5/0/0/0.11,
dsn=5.1.1, status=bounced (host example.com[10.0.0.1] said: 550 5.1.1
<to at example.com> User unknown; rejecting (in reply to RCPT TO
command))
+
+            # print "bounce message from " . $to . " msg : " . $relay . "\n";
+
+            ### local bounce
+            # XXX local v. remote bounce seems iffy, relative
+            if ($relay =~
/^(?:none|local|virtual|avcheck|maildrop|127\.0\.0\.1)/) {
+               $Totals{'BounceLocal'}++;
+               $Counts{'BounceLocal'}{get_dsn_msg($dsn)}{$to}{"\u$reason"}++;
+
+            ### remote bounce
+            } else {
+               my ($reply,$fmtdhost) =
cleanhostreply($reason,$relay,$to,$domainpart);
+
+               $Totals{'BounceRemote'}++;
+
$Counts{'BounceRemote'}{get_dsn_msg($dsn)}{$domainpart}{$localpart}{$fmtdhost}{$reply}++;
            }
         }
-         else {
-            $n=0;
-            foreach $User (keys %{$SaslAuth{$Host}} ) {
-               $n+=$SaslAuth{$Host}{$User};
+
+         elsif ($status =~ /deferred/) {
+
+            #TD DD4F2AC4D3: to=<to at example.com>, relay=none,
delay=27077, delays=27077/0/0.57/0, dsn=4.4.3, status=deferred (Host
or domain name not found. Name service error for name=example.com
type=MX: Host not found, try again)
+            #TD E52A1F1B52: to=<to at example.com>, relay=none,
delay=141602, status=deferred (connect to mx1.example.com[10.0.0.1]:
Connection refused)
+            #TD E52A1F1B52: to=<to at example.com>, relay=none,
delay=141602, status=deferred (delivery temporarily suspended: connect
to example.com[192.168.0.1]: Connection refused)
+            #TD DB775D7035: to=<to at example.com>, relay=none,
delay=306142, delays=306142/0.04/0.18/0, dsn=4.4.1, status=deferred
(connect to example.com[10.0.0.1]: Connection refused)
+            #TD EEDC1F1AA6: to=<to at example.org>,
relay=example.org[10.0.0.1], delay=48779, status=deferred (lost
connection with mail.example.org[10.0.0.1] while sending MAIL FROM)
+            #TD 8E7A0575C3: to=<to at sample.net>, relay=sample.net,
delay=26541, status=deferred (conversation with mail.example.com timed
out while sending end of data -- message may be sent more than once)
+            #TD 7CF61B7030: to=<to at sample.net>,
relay=sample.net[10.0.0.1]:25, delay=322, delays=0.04/0/322/0,
dsn=4.4.2, status=deferred (conversation with example.com[10.0.0.01]
timed out while receiving the initial server greeting)
+            #TD B8BF0AE331: to=<to at localhost>,
orig_to=<toalias at localhost>, relay=none, delay=238024, status=deferred
(delivery temporarily suspended: transport is unavailable)
+
+            # XXX postfix reports dsn=5.0.0, host's reply may contain
its own dsn's such as 511 and #5.1.1
+            # XXX should these be used instead?
+            #TD 232EAC2E55: to=<to at sample.net>,
relay=sample.net[10.0.0.1]:25, delay=5.7, delays=0.05/0.02/5.3/0.3,
dsn=4.7.1, status=deferred (host sample.net[10.0.0.1] said: 450 4.7.1
<to at sample.net>: Recipient address rejected: Greylisted (in reply to
RCPT TO command))
+            #TD 11677B700D: to=<to at example.com>,
relay=example.com[10.0.0.1]:25, delay=79799,
delays=79797/0.02/0.4/1.3, dsn=4.0.0, status=deferred (host
example.com[10.0.0.1] said: 450 <to at example.com>: User unknown in
local recipient table (in reply to RCPT TO command))
+            #TD 0DA72B7035: to=<to at example.com>,
relay=example.com[10.0.0.1]:25, delay=97, delays=0.03/0/87/10,
dsn=4.0.0, status=deferred (host example.com[10.0.0.1] said: 450
<to at example.com>: Recipient address rejected: undeliverable address:
User unknown in virtual alias table (in reply to RCPT TO command))
+
+            my ($reply,$fmtdhost) =
cleanhostreply($reason,$relay,$to,$domainpart);
+
+            if ($DeferredByQid{$qid}++ == 0) {
+               $Totals{'MsgsDeferred'}++;
            }
-            print "    $Host: $n Time(s)\n";
+            $Totals{'Deferrals'}++;
+            $Counts{'Deferrals'}{get_dsn_msg($dsn)}{$reply}{$domainpart}{$localpart}{$fmtdhost}++;
         }
-      }
-   }
-   else {
-      $n=0;
-      $hn=scalar(keys %SaslAuth);
-      foreach $Host (keys %SaslAuth) {
-         foreach $User (keys %{$SaslAuth{$Host}} ) {
-            $n+=$SaslAuth{$Host}{$User};
+
+         elsif ($status =~ /^undeliverable$/) {
+            #TD B54D220BFC: to=<u at example.com>,
relay=sample.com[10.0.0.1], delay=0, dsn=5.0.0, status=undeliverable
(host sample.com[10.0.0.1] refused to talk to me: 554 5.7.1
example.com Connection not authorized)
+            #TD 8F699C2EA6: to=<u at example.com>, relay=virtual,
delay=0.14, delays=0.06/0/0/0.08, dsn=5.1.1, status=undeliverable
(unknown user: "u at example.com")
+            $Totals{'Undeliverable'}++;
+            $Counts{'Undeliverable'}{$reason}{$origto ? "$to
($origto)" : "$to"}++;
+         }
+
+         elsif ($status =~ /^deliverable$/) {
+            # sendmail -bv style deliverable reports
+            #TD ED862C2EA6: to=<u at example.com>, relay=virtual,
delay=0.09, delays=0.03/0/0/0.06, dsn=2.0.0, status=deliverable
(delivers to maildir)
+            $Totals{'Deliverable'}++;
+            $Counts{'Deliverable'}{$reason}{$origto ? "$to ($origto)"
: "$to"}++;
         }
-      }
-      print "\n\nSASL Authenticated messages from: $hn Host(s), $n Time(s)";
-   }
-}

-if (keys %TLSconnectFrom) {
-   if ($Detail >= 5) {
-      print "\n\nTLS Connections from:\n";
-      foreach $Host (sort {$a cmp $b} keys %TLSconnectFrom) {
-         print "   $Host : $TLSconnectFrom{$Host} Time(s)\n";
-      }
-   }
-   else {
-      $n=0;
-      $hn=scalar(keys %TLSconnectFrom);
-      foreach $Host (keys %TLSconnectFrom) {
-         $n+=$TLSconnectFrom{$Host};
+         else {
+            # keep this as the last condition in this else clause
+            inc_unmatched('unknownstatus', $OrigLine);
+         }
+      } # end of sent, forwarded, bounced, softbounce, deferred,
(un)deliverable
+
+      # XXX don't care about this anymore; MsgsAccepted are counted
with from= lines
+      elsif ( $p2 =~ /^uid=(?:[^ ]*) from=<(?:[^>]*)>/o ) {
+         #TD2 1DFE2C2E18: uid=0 from=<root>
+         #$Totals{'MsgsAccepted'}++;
+      }
+
+      elsif ( ($from) = ($p2 =~ /^from=<([^>]*)>, status=expired,
returned to sender$/o )) {
+         #TD 9294C8866: from=<from at example.com>, status=expired,
returned to sender
+         $from = "<>"          if ($from =~ /^$/);
+         $Totals{'ReturnedToSender'}++;
+         $Counts{'ReturnedToSender'}{$from}++;
+
+      } elsif ( ($p2 =~ /^resent-message-id=<?(?:[^>]*)>?$/o  )) {
+         #TD 52A49200E1: resent-message-id=4739073.1
+         #TD DB2E3C2E0E: resent-message-id=<ARF+DXZwLECdxm at mail.example.com>
+         $Totals{'MsgsResent'}++;
+
+      # see also ConnectionLost elsewhere
+      } elsif (($host,$hostip,$reason) = ($p2 =~ /^lost connection
with ([^[]*)\[($re_IP)\] (while .*)$/o )) {
+         #TD EB7D4341F0: lost connection with sample.net[10.0.0.1]
while sending MAIL FROM
+         #TD 5F6C7C2E0F: lost connection with sample.net[10.0.0.2]
while receiving the initial server greeting
+         $Totals{'ConnectionLost'}++;
+         $Counts{'ConnectionLost'}{"\u$reason"}{formathost($hostip,$host)}++;
+      }
+
+      # see also TimeoutInbound elsewhere
+      elsif (($host,$hostip,$reason) = ($p2 =~ /^conversation with
([^[]*)\[($re_IP)\] timed out (while .*)$/o )) {
+         #TD C20574341F3: conversation with sample.net[10.0.0.1]
timed out while receiving the initial SMTP greeting
+         $Totals{'TimeoutInbound'}++;
+         $Counts{'TimeoutInbound'}{"\u$reason"}{formathost($hostip,$host)}++;
+      }
+
+      elsif ($p2 =~ /^sender delay notification: $re_QID$/o) {
+         #TD 8DB93C2FF2: sender delay notification: AA61EC2F9A
+         $Totals{'SenderDelayNotification'}++;
+
+      } elsif ( ($warning,$host,$hostip,$to,$reason) = ($p2 =~
/^warning: header (.*) from ([^[]+)\[($re_IP)\]; from=<(?:[^ ]*)>
to=<([^ ]*)>(?: proto=[^ ]* helo=<[^ ]*>)?(?:: (.*))?$/o )) {
+         $reason = 'Unknown Reason'    if ($reason =~ /^$/);
+         $Totals{'WarningHeader'}++;
+         $Counts{'WarningHeader'}{$reason}{formathost($hostip,$host)}{$to}{$warning}++;
+
+      ### filter messages
+      } elsif ( ($host,$hostip,$trigger,$reason,$filter,$from,$to) =
($p2 =~ /^filter: RCPT from ([^[]+)\[($re_IP)\]: <([^>]*)>: (.*)
triggers FILTER ([^;]+); from=<([^>]*)> to=<([^>]+)> proto=\S+
helo=<[^>]+>$/o )) {
+         $from = "<>"          if ($from =~ /^$/);
+         #TD NOQUEUE: filter: RCPT from example.com[10.0.0.1]: <>:
Sender address triggers FILTER filter:somefilter; from=<>
to=<to at sample.net> proto=SMTP helo=<example.com>
+         #TD NOQUEUE: filter: RCPT from example.com[192.168.0.1]:
<to at exmple.com>: Recipient address triggers FILTER
smtp-amavis:[127.0.0.1]:10024; from=<from at sample.net>
to=<to at example.com> proto=SMTP helo=<sample.net>
+         $Totals{'Filtered'
--- /root/logwatch/scripts/services/vsftpd      2008-07-15
16:57:32.000000000 +0200
+++ vsftpd      2008-09-14 12:21:00.000000000 +0200
@@ -83,7 +83,7 @@
   }
 }

-if ( (keys %AnonLogins) and ($Detail >= 5) ) {
+if (keys %AnonLogins)  {
   print "\nAnonymous FTP Logins:\n";
   foreach $ThisOne (keys %AnonLogins) {
      print $ThisOne . $AnonLogins{$ThisOne} . " Time(s)\n";
@@ -111,11 +111,11 @@

 if ( ( $#UploadedFiles >= 0 ) or
   ( $#FailedUploadedFiles >= 0 ) ) {
-   if ( $#UploadedFiles >= 0) {
+   if ( ( $#UploadedFiles >= 0) && ( $Detail >= 5) ) {
      print "\nIncoming FTP Files:\n";
      print @UploadedFiles;
   }
-   if ( $#FailedUploadedFiles >= 0) {
+   if ( ( $#FailedUploadedFiles >= 0) && ( $Detail >= 5) ) {
      print "\nFailed Uploads\n";
      print @FailedUploadedFiles;
   }
@@ -124,11 +124,11 @@

 if ( ( $#DownloadedFiles >= 0 ) or
   ( $#FailedDownloadedFiles >=0 ) ) {
-   if ( $#DownloadedFiles >= 0) {
+   if ( ( $#DownloadedFiles >= 0) && ( $Detail >= 5) ) {
      print "\nOutgoing FTP Files:\n";
      print @DownloadedFiles;
   }
-   if ( $#FailedDownloadedFiles >= 0) {
+   if ( ( $#FailedDownloadedFiles >= 0) && ( $Detail >= 5) ) {
      print "\nFailed Downloads\n";
      print @FailedDownloadedFiles;
   }

--- /root/logwatch/scripts/services/amavis      2008-06-17
23:46:40.000000000 +0200
+++ amavis      2008-09-14 12:11:28.000000000 +0200
@@ -74,6 +74,12 @@
        or ($ThisLine =~ /^Checking/)
        or ($ThisLine =~ /^(ESMTP|FWD|SEND) via/)
        or ($ThisLine =~ /^spam_scan/)
+        or ($ThisLine =~ /^virus_scan/)
+        or ($ThisLine =~ /^run_av/)
+        or ($ThisLine =~ /^check_header/)
+        or ($ThisLine =~ /^p.path/)
+        or ($ThisLine =~ /sender addr ignored/)
+        or ($ThisLine =~ /^smtp session rundown/)
        or ($ThisLine =~ /^Not-Delivered/)
        or ($ThisLine =~ /^SpamControl/)
        or ($ThisLine =~ /^SPAM-TAG/)
@@ -94,6 +100,7 @@
        or ($ThisLine =~ /^local delivery: /)
        or ($ThisLine =~ /^cached [a-zA-Z0-9]+ /)
        or ($ThisLine =~ /^loaded policy bank/)
+        or ($ThisLine =~ /smtp connection cache/)
        or ($ThisLine =~ /^wbl: soft-whitelisted/)
        or ($ThisLine =~ /^p\d+ \d+(\/\d+)* Content-Type: /)
        or ($ThisLine =~ /^Requesting (a |)process rundown after [0-9]+ tasks/)
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: dovecot.diff
Url: http://www2.list.logwatch.org:81/pipermail/logwatch-devel/attachments/20080914/a0ed6924/attachment-0004.cc 
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: emerge.diff
Url: http://www2.list.logwatch.org:81/pipermail/logwatch-devel/attachments/20080914/a0ed6924/attachment-0005.cc 
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: postfix.diff
Url: http://www2.list.logwatch.org:81/pipermail/logwatch-devel/attachments/20080914/a0ed6924/attachment-0006.cc 
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: vsftpd.diff
Url: http://www2.list.logwatch.org:81/pipermail/logwatch-devel/attachments/20080914/a0ed6924/attachment-0007.cc 
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: amavis.diff
Url: http://www2.list.logwatch.org:81/pipermail/logwatch-devel/attachments/20080914/a0ed6924/attachment-0008.cc 


More information about the Logwatch-Devel mailing list