]> git.sven.stormbind.net Git - sven/pflogsumm.git/commitdiff
New upstream version 1.1.14 upstream upstream/1.1.14
authorSven Hoexter <sven@stormbind.net>
Fri, 13 Feb 2026 15:35:30 +0000 (16:35 +0100)
committerSven Hoexter <sven@stormbind.net>
Fri, 13 Feb 2026 15:35:30 +0000 (16:35 +0100)
ChangeLog
pffrombyto.1
pflogsumm
pflogsumm.1
pftobyfrom.1

index 35b2707a1676a75a1bcc118dc735a199c79991ef..d8c7ac950699fda9dc9828babd7ca77c75344b9d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,30 @@ ChangeLog for pflogsumm
      feed for update notifications.]
 
 
+rel-1.1.14     20260209
+
+    Bug Fixes
+
+       Date range not displayed in multi-day reports for January (month 0).
+
+    Enhancements
+
+       Now captures and reports messages expired (queue lifetime exceeded).
+        Thanks and a tip o' the hat to Bill Carson
+       (bill-carlson-at-wkks-dot-org) for bringing this to my attention.
+
+       Modified status line capture to account for new TLS status logging.
+       (N.B.: Not currently doing anything with the captured TLS info.)
+
+       Now condenses "Domain <blurfl> does not accept mail (nullMX)" under
+       single subheading.
+
+       Added long-form options to doc header and --help output.
+
+    Miscellaneous
+
+       A bit of minor refactoring.
+
 rel-1.1.13     20251023
 
     Bug Fixes
index 7b625d603dbe31499cf105688e884858aa42ca24..55fef3a4b9860b047153c458e13b612e44a3a80b 100644 (file)
@@ -55,7 +55,7 @@
 .\" ========================================================================
 .\"
 .IX Title "PFFROMBYTO 1"
-.TH PFFROMBYTO 1 2025-05-22 1.1.13 "User Contributed Perl Documentation"
+.TH PFFROMBYTO 1 2025-05-22 1.1.14 "User Contributed Perl Documentation"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
index 8d14a12a03e6863b622cd417b7fdc73cc7aabdac..40feefd997b7cc4f32a49f81b8630177e537c10d 100755 (executable)
--- a/pflogsumm
+++ b/pflogsumm
@@ -6,20 +6,21 @@ eval 'exec perl -S $0 "$@"'
 
 pflogsumm - Produce Postfix MTA logfile summary
 
-Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.13
+Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.14
 
 =head1 SYNOPSIS
-
-    pflogsumm [--config <file>] [--bounce-detail <cnt>]
-      [--colwidth <n>] [--deferral-detail <cnt>] [--detail <cnt>]
-      [-d <date [range]>] [--dow0mon] [-e] [-h <cnt>] [-i]
-      [--iso-date-time] [--mailq] [-m] [--no-no-msg-size]
+    pflogsumm [--config <file>] [--bounce-detail <cnt>] [--colwidth <n>]
+      [-d|--date-range <date [range]>] [--deferral-detail <cnt>]
+      [--detail <cnt>] [--dow0mon] [-e|--extended-detail]
+      [--expired-detail <cnt> ] [-h|--host-cnt <cnt>] [-i|--ignore-case]
+      [--iso-date-time] [-m|--uucp-mung] [--mailq] [--no-no-msg-size]
       [--problems-first] [--pscrn-detail <cnt>] [--pscrn-stats]
-      [-q] [--rej-add-from] [--rej-add-to] [--reject-detail <cnt>]
-      [--smtp-detail <cnt>] [--smtpd-stats] [--smtpd-warning-detail <cnt>]
-      [--srs-mung] [--syslog-name=string] [-u <cnt>]
-      [--unprocd-file <filename> ] [--use-orig-to] [--verbose-msg-detail]
-      [--verp-mung[=<n>]] [-x] [--zero-fill] [file1 [filen]]
+      [-q|--quiet] [--rej-add-from] [--rej-add-to] [--reject-detail <cnt>]
+      [--smtp-detail <cnt>] [--smtpd-stats]
+      [--smtpd-warning-detail <cnt>] [--srs-mung] [--syslog-name=string]
+      [-u|--user-cnt <cnt>] [--unprocd-file <filename> ] [--use-orig-to]
+      [--verbose-msg-detail] [--verp-mung[=<n>]] [-x|--debug] [--zero-fill]
+      [file1 [filen]]
 
     pflogsumm --[dump-config|help|version]
 
@@ -117,6 +118,10 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.13
 
                        "2025-07 - 2025-08" == 2025-07-01 - 2025-08-31
 
+    --debug        Enable debugging to STDERR
+
+                   See Also: -x
+
     --dow0mon
                    First day of the week is Monday, rather than Sunday.
 
@@ -144,6 +149,11 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.13
 
                    pflogsumm --dump-config <add'l args> |grep -v ' = $'
 
+    --expired-detail <cnt>
+
+                  Limit detailed message queue time expired reports to
+                  the top <cnt>.  0 to suppress entirely.
+
     -e
     --extended-detail
 
@@ -364,6 +374,8 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.13
 
     -x             Enable debugging to STDERR
 
+                   See Also: --debug
+
     --zero-fill    "Zero-fill" certain arrays so reports come out with
                    data in columns that that might otherwise be blank.
 
@@ -561,7 +573,7 @@ eval { require Config::Simple };
 my $haveConfigSimple = $@ ? 0 : 1;
 
 my $mailqCmd = "mailq";
-my $release = "1.1.13";
+my $release = "1.1.14";
 
 # Variables and constants used throughout pflogsumm
 our (
@@ -610,10 +622,10 @@ use constant {
 };
 
 my (
-    $cmd, $qid, $addr, $orig_to, $size, $relay, $status, $delay,
+    $svc, $qid, $addr, $orig_to, $size, $relay, $status, $delay, $tls,
     $strtDate, $endDate,
     %panics, %fatals, %warnings, %masterMsgs,
-    %deferred, %bounced,
+    %deferred, %bounced, %expired,
     %noMsgSize, %msgDetail,
     $msgsRcvd, $msgsDlvrd, $sizeRcvd, $sizeDlvrd,
     $msgMonStr, $msgMon, $msgDay, $msgTimeStr, $msgHr, $msgMin, $msgSec,
@@ -623,7 +635,7 @@ my (
     %warns, $msgsWrnd,
     %discards, $msgsDscrdd,
     %holds, $msgsHld,
-    %rcvdMsg, $msgsFwdd, $msgsBncd,
+    %rcvdMsg, $msgsFwdd, $msgsBncd, $msgsExprd,
     $msgsDfrdCnt, $msgsDfrd, %msgDfrdFlgs,
     %connTime, %smtpdPerDay, %smtpdPerDom, $smtpdConnCnt, $smtpdTotTime,
     %pscrnConnTime, %pscrnPerDay, %pscrnPerIP, $pscrnConnCnt, $pscrnTotTime,
@@ -695,21 +707,20 @@ my %pscrnHits;
 ($progName = $0) =~ s/^.*\///;
 
 $usageMsg =
-    "usage: $progName [--config <file>] [--bounce-detail <cnt>]
-      [--colwidth <n>] [--deferral-detail <cnt>] [--detail <cnt>]
-      [-d <date [range]>] [--dow0mon] [-e] [-h <cnt>] [-i]
-      [--iso-date-time] [--mailq] [-m] [--no-no-msg-size]
+    "usage: $progName [--config <file>] [--bounce-detail <cnt>] [--colwidth <n>]
+      [-d|--date-range <date [range]>] [--deferral-detail <cnt>]
+      [--detail <cnt>] [--dow0mon] [-e|--extended-detail]
+      [--expired-detail <cnt> ] [-h|--host-cnt <cnt>] [-i|--ignore-case]
+      [--iso-date-time] [-m|--uucp-mung] [--mailq] [--no-no-msg-size]
       [--problems-first] [--pscrn-detail <cnt>] [--pscrn-stats]
-      [-q] [--rej-add-from] [--rej-add-to] [--reject-detail <cnt>]
-      [--smtp-detail <cnt>] [--smtpd-stats] [--smtpd-warning-detail <cnt>]
-      [--srs-mung] [--syslog-name=string] [-u <cnt>]
-      [--unprocd-file <filename> ] [--use-orig-to] [--verbose-msg-detail]
-      [--verp-mung[=<n>]] [-x] [--zero-fill] [file1 [filen]]
-
-       $progName --[dump-config|help|version]
+      [-q|--quiet] [--rej-add-from] [--rej-add-to] [--reject-detail <cnt>]
+      [--smtp-detail <cnt>] [--smtpd-stats]
+      [--smtpd-warning-detail <cnt>] [--srs-mung] [--syslog-name=string]
+      [-u|--user-cnt <cnt>] [--unprocd-file <filename> ] [--use-orig-to]
+      [--verbose-msg-detail] [--verp-mung[=<n>]] [-x|--debug] [--zero-fill]
+      [file1 [filen]]
 
-       Note: Where both long- and short-form options exist only the
-       latter are shown above. See man page for long-form equivalents.";
+       $progName --[dump-config|help|version]";
 
 #
 # Central options specifications. This allows us to create a unified set
@@ -729,6 +740,7 @@ my %optionSpec = (
     'detail'                 => { type => 'i' },
     'dow0mon'                => { type => 'b' },
     'dump-config'            => { type => 'b' },
+    'expired-detail'         => { type => 'i' },
     'extended-detail'        => { type => 'b', short => 'e' },
     'help'                   => { type => 'b' },
     'host-cnt'               => { type => 'i', short => 'h' },
@@ -935,13 +947,13 @@ GetOptions(@getopt_args) or die "Invalid command-line arguments\n\n$usageMsg\n";
 # internally: 0 == none, undefined == -1 == all
 #
 $opts{'colwidth'} = 0 if($opts{'verbose-msg-detail'}); # This one's a bit different
-foreach my $optName (qw(bounce-detail colwidth deferral-detail host-cnt pscrn-detail reject-detail smtp-detail smtpd-warning-detail user-cnt)) {
+foreach my $optName (qw(bounce-detail colwidth deferral-detail expired-detail host-cnt pscrn-detail reject-detail smtp-detail smtpd-warning-detail user-cnt)) {
     $opts{$optName} = -1 unless(defined($opts{$optName}));
 }
 
 # If --detail was specified, set anything that's not enumerated to it
 if(defined($opts{'detail'})) {
-    foreach my $optName (qw (bounce-detail deferral-detail host-cnt pscrn-detail reject-detail smtp-detail smtpd-warning-detail user-cnt)) {
+    foreach my $optName (qw (bounce-detail deferral-detail expired-detail host-cnt pscrn-detail reject-detail smtp-detail smtpd-warning-detail user-cnt)) {
        $opts{$optName} = $opts{'detail'} unless($opts{"$optName"} != -1);
     }
 }
@@ -999,12 +1011,12 @@ while(<>) {
     next unless((($msgYr, $msgMon, $msgDay, $msgHr, $msgMin, $msgSec, $logRmdr) = line_matches_dates($_, $strtDate, $endDate)) == 7);
 
     # Snag first date seen
-    ($fromDate{'yr'}, $fromDate{'mon'}, $fromDate{'day'}) = ($msgYr, $msgMon, $msgDay) unless($fromDate{'mon'});
+    ($fromDate{'yr'}, $fromDate{'mon'}, $fromDate{'day'}) = ($msgYr, $msgMon, $msgDay) unless(defined($fromDate{'mon'}));
     # Snag last date seen
     ($thruDate{'yr'}, $thruDate{'mon'}, $thruDate{'day'}) = ($msgYr, $msgMon, $msgDay);
 
-    unless((($cmd, $qid) = $logRmdr =~ m#^(?:postfix|$syslogName)(?:/(?:smtps|submission))?/([^\[:]*).*?: ([^:\s]+)#o) == 2 ||
-           (($cmd, $qid) = $logRmdr =~ m#^((?:postfix)(?:-script)?)(?:\[\d+\])?: ([^:\s]+)#o) == 2)
+    unless((($svc, $qid) = $logRmdr =~ m#^(?:postfix|$syslogName)(?:/(?:smtps|submission))?/([^\[:]*).*?: ([^:\s]+)#o) == 2 ||
+           (($svc, $qid) = $logRmdr =~ m#^((?:postfix)(?:-script)?)(?:\[\d+\])?: ([^:\s]+)#o) == 2)
     {
        print $unProcd "[01]: $_" if $unProcd;
        next;
@@ -1024,30 +1036,30 @@ while(<>) {
     }
 
     # regexp rejects happen in "cleanup"
-    if($cmd eq "cleanup" && (my($rejSubTyp, $rejReas, $rejRmdr) = $logRmdr =~
+    if($svc eq "cleanup" && (my($rejSubTyp, $rejReas, $rejRmdr) = $logRmdr =~
        /\/cleanup\[\d+\]: .*?\b((?:milter-)?reject|warning|hold|discard): (header|body|END-OF-MESSAGE) (.*)$/) == 3)
     {
        $rejRmdr =~ s/( from \S+?)?; from=<.*$// unless($opts{'verbose-msg-detail'});
        # FIXME: In retrospect: I've no idea where I came up with the magic numbers I pass to this function.
        $rejRmdr = string_trimmer($rejRmdr, 64);
        if($rejSubTyp eq "reject" or $rejSubTyp eq "milter-reject") {
-           ++$rejects{$cmd}{$rejReas}{$rejRmdr} unless($opts{'reject-detail'} == 0);
+           ++$rejects{$svc}{$rejReas}{$rejRmdr} unless($opts{'reject-detail'} == 0);
            ++$msgsRjctd;
            if($opts{'debug'}) {
-               push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, \$rejSubTyp: $rejSubTyp, --\$msgsRcvd");
+               push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, \$rejSubTyp: $rejSubTyp, --\$msgsRcvd");
                ++$qidTracker{$qid}{'lateRejects'};
                print STDERR "dbg: late reject \$rcvdMsg{$qid}{'size'}: $rcvdMsg{$qid}{'size'}\n" if $rcvdMsg{$qid}{'size'};
            }
            --$msgsRcvd;        # Late Reject: It will have already been counted as "Received," even though it ultimately is not
        } elsif($rejSubTyp eq "warning") {
-           ++$warns{$cmd}{$rejReas}{$rejRmdr} unless($opts{'reject-detail'} == 0);
+           ++$warns{$svc}{$rejReas}{$rejRmdr} unless($opts{'reject-detail'} == 0);
            ++$msgsWrnd;
        } elsif($rejSubTyp eq "hold") {
-           ++$holds{$cmd}{$rejReas}{$rejRmdr} unless($opts{'reject-detail'} == 0);
+           ++$holds{$svc}{$rejReas}{$rejRmdr} unless($opts{'reject-detail'} == 0);
            ++$msgsHld;
        } elsif($rejSubTyp eq "discard") {
-           push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, \$rejSubTyp: $rejSubTyp") if $opts{'debug'};
-           ++$discards{$cmd}{$rejReas}{$rejRmdr} unless($opts{'reject-detail'} == 0);
+           push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, \$rejSubTyp: $rejSubTyp") if $opts{'debug'};
+           ++$discards{$svc}{$rejReas}{$rejRmdr} unless($opts{'reject-detail'} == 0);
            ++$msgsDscrdd;
        }
        delete($rcvdMsg{$qid}); # We're done with this
@@ -1077,17 +1089,17 @@ while(<>) {
            $warnReas =~ s/(process .+) pid \d+ (exit status \d+)/$1 $2/;
        }
        $warnReas = string_trimmer($warnReas, 66);
-       unless($cmd eq "smtpd" && $opts{'smtpd-warning-detail'} == 0) {
-           ++$warnings{$cmd}{$warnReas};
+       unless($svc eq "smtpd" && $opts{'smtpd-warning-detail'} == 0) {
+           ++$warnings{$svc}{$warnReas};
        }
     } elsif($qid eq 'fatal') {
        (my $fatalReas = $logRmdr) =~ s/^.*fatal: //;
        $fatalReas = string_trimmer($fatalReas, 66);
-       ++$fatals{$cmd}{$fatalReas};
+       ++$fatals{$svc}{$fatalReas};
     } elsif($qid eq 'panic') {
        (my $panicReas = $logRmdr) =~ s/^.*panic: //;
        $panicReas = string_trimmer($panicReas, 66);
-       ++$panics{$cmd}{$panicReas};
+       ++$panics{$svc}{$panicReas};
     } elsif($qid eq 'reject') {
        proc_smtpd_reject($logRmdr, \%rejects, \$msgsRjctd, \$rejPerHr[$msgHr],
                          \${$msgsPerDay{$revMsgDateStr}}[4]);
@@ -1100,21 +1112,18 @@ while(<>) {
     } elsif($qid eq 'discard') {
        proc_smtpd_reject($logRmdr, \%discards, \$msgsDscrdd, \$rejPerHr[$msgHr],
                          \${$msgsPerDay{$revMsgDateStr}}[4]);
-    } elsif($cmd eq 'master') {
+    } elsif($svc eq 'master') {
        ++$masterMsgs{(split(/^.*master.*: /, $logRmdr))[1]};
-    } elsif($cmd eq 'smtpd' || $cmd eq 'postscreen') {
-       if((my ($clientInfo)) = $logRmdr =~ /\[\d+\]: \w+: client=(.+?)(?:,|$)/) {
-           #
-           # Warning: this code in two places!
-           #
+    } elsif($svc eq 'smtpd' || $svc eq 'postscreen' || $svc eq 'pickup') {
+       if((my ($clientInfo)) = $logRmdr =~ /(?|\[\d+\]: \w+: client=(.+?)(?:,|$)|\/(pickup)\[\d+\]: \w+: (?:sender|uid)=)/) {
            ++$rcvPerHr[$msgHr];
            ++${$msgsPerDay{$revMsgDateStr}}[0];
            if($opts{'debug'}) {
-               push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, ++\$msgsRcvd");
+               push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, ++\$msgsRcvd");
                ++$qidTracker{$qid}{'rcvdCnt'};
            }
            ++$msgsRcvd;
-           $rcvdMsg{$qid}{'whence'} = gimme_domain($clientInfo);       # Whence it came
+           $rcvdMsg{$qid}{'whence'} = $clientInfo eq 'pickup'? $clientInfo : gimme_domain($clientInfo);        # Whence it came
        } elsif(my($rejSubTyp) = $logRmdr =~ /\[\d+\]: \w+: (reject(?:_warning)?|hold|discard): /) {
            if($rejSubTyp eq 'reject') {
                proc_smtpd_reject($logRmdr, \%rejects, \$msgsRjctd,
@@ -1123,7 +1132,7 @@ while(<>) {
                # Experimental
                unless($qid eq 'NOQUEUE') {
                    if($opts{'debug'}) {
-                       push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, \$rejSubTyp: $rejSubTyp, --\$msgsRcvd");
+                       push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, \$rejSubTyp: $rejSubTyp, --\$msgsRcvd");
                        ++$qidTracker{$qid}{'lateRejects'};
                        print STDERR "dbg: late reject \$rcvdMsg{$qid}{'size'}: $rcvdMsg{$qid}{'size'}\n" if $rcvdMsg{$qid}{'size'};
                    }
@@ -1135,19 +1144,19 @@ while(<>) {
                                  \$rejPerHr[$msgHr],
                                  \${$msgsPerDay{$revMsgDateStr}}[4]);
            } elsif($rejSubTyp eq 'hold') {
-               push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, \$rejSubTyp: $rejSubTyp") if $opts{'debug'};
+               push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, \$rejSubTyp: $rejSubTyp") if $opts{'debug'};
                proc_smtpd_reject($logRmdr, \%holds, \$msgsHld,
                                  \$rejPerHr[$msgHr],
                                  \${$msgsPerDay{$revMsgDateStr}}[4]);
            } elsif($rejSubTyp eq 'discard') {
-               push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, \$rejSubTyp: $rejSubTyp") if $opts{'debug'};
+               push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, \$rejSubTyp: $rejSubTyp") if $opts{'debug'};
                proc_smtpd_reject($logRmdr, \%discards, \$msgsDscrdd,
                                  \$rejPerHr[$msgHr],
                                  \${$msgsPerDay{$revMsgDateStr}}[4]);
            }
        }
        else {
-           if($cmd eq 'smtpd') {
+           if($svc eq 'smtpd') {
                next unless(defined($opts{'smtpd-stats'}));
                if($logRmdr =~ /: connect from /) {
                    $logRmdr =~ /\/smtpd\[(\d+)\]: /;
@@ -1188,7 +1197,7 @@ while(<>) {
                        $smtpdTotTime += $tSecs;
                    }
                }
-           } elsif($cmd eq 'postscreen' && (defined $opts{'pscrn-stats'} || $opts{'pscrn-detail'})) {
+           } elsif($svc eq 'postscreen' && (defined $opts{'pscrn-stats'} || $opts{'pscrn-detail'})) {
 
                my ($pscrnAct, $clientIP, $clientPort, $pscrnAddl, $capCnt);
                print STDERR "\n" if($opts{'debug'});
@@ -1212,11 +1221,11 @@ while(<>) {
                    if($capCnt == 4) {
                        print STDERR "Bumping \$pscrnHits{\"$pscrnAct $pscrnAddl\"}{\"$clientIP\"} on \$logRmdr: \"$logRmdr\"\n" if($opts{'debug'});
                        ++$pscrnHits{"$pscrnAct $pscrnAddl"}{$clientIP} if($opts{'pscrn-detail'});
-                       print STDERR "\$cmd: \"$cmd\", \$logRmdr: \"$logRmdr\"\n" if($opts{'debug'});
+                       print STDERR "\$svc: \"$svc\", \$logRmdr: \"$logRmdr\"\n" if($opts{'debug'});
                    } else {
                        print STDERR "Bumping \$pscrnHits{\"$pscrnAct\"}{\"$clientIP\"} on \$logRmdr: \"$logRmdr\"\n" if($opts{'debug'});
                        ++$pscrnHits{$pscrnAct}{$clientIP} if($opts{'pscrn-detail'});
-                       print STDERR "\$cmd: \"$cmd\", \$logRmdr: \"$logRmdr\"\n" if($opts{'debug'});
+                       print STDERR "\$svc: \"$svc\", \$logRmdr: \"$logRmdr\"\n" if($opts{'debug'});
                    }
                };
 
@@ -1311,8 +1320,25 @@ while(<>) {
                $sizeRcvd += $size;
            }
        }
-       elsif((($addr, $orig_to, $relay, $delay, $status, $toRmdr) = $logRmdr =~
-               /to=<([^>]*)>, (?:orig_to=<([^>]*)>, )?relay=([^,]+), (?:conn_use=[^,]+, )?delay=([^,]+), (?:delays=[^,]+, )?(?:dsn=[^,]+, )?status=(\S+)(.*)$/) >= 4)
+       elsif(((
+               $addr,
+               $orig_to,
+               $relay,
+               $delay,
+               $tls,         # <— new optional capture
+               $status,
+               $toRmdr
+              ) = $logRmdr =~ m{
+                                to=<([^>]*)>,\s+
+                                (?:orig_to=<([^>]*)>,\s+)?        # optional
+                                relay=([^,]+),\s+
+                                (?:conn_use=[^,]+,\s+)?           # optional
+                                delay=([^,]+),\s+
+                                (?:delays=[^,]+,\s+)?             # optional
+                                (?:tls=([^,]+),\s+)?              # <— optional tls=... (captures if present)
+                                (?:dsn=[^,]+,\s+)?                # optional
+                                status=(\S+)(.*)$
+                               }x) >= 4)
        {
            $addr = $orig_to if($opts{'use-orig-to'} && $orig_to);
 
@@ -1327,7 +1353,7 @@ while(<>) {
 
                # was it actually forwarded, rather than delivered?
                if(my ($newQid) = $toRmdr =~ /\(forwarded as ([^\)]+)\)/) {
-                   push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, \$status: $status, forwarded as new qid $1, ++\$msgsFwdd") if $opts{'debug'};
+                   push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, \$status: $status, forwarded as new qid $1, ++\$msgsFwdd") if $opts{'debug'};
                    ++$msgsFwdd;
                    delete($rcvdMsg{$qid});             # We're done with this
                    next;
@@ -1345,7 +1371,7 @@ while(<>) {
                ++$dlvPerHr[$msgHr];
                ++${$msgsPerDay{$revMsgDateStr}}[1];
                if($opts{'debug'}) {
-                   push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, \$status: $status, ++\$msgsDlvrd");
+                   push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, \$status: $status, ++\$msgsDlvrd");
                    ++$qidTracker{$qid}{'dlvrdCnt'};
                }
                ++$msgsDlvrd;
@@ -1383,14 +1409,14 @@ while(<>) {
                        $reason .= $moreReason if($moreReason); # ick
                        # Finally...
                        $reason = said_string_trimmer($reason, 66);
-                       ++$deferred{$cmd}{$host}{$reason};
+                       ++$deferred{$svc}{$host}{$reason};
                    } else {
-                       ++$deferred{$cmd}{$deferredReas};
+                       ++$deferred{$svc}{$deferredReas};
                    }
                }
                 ++$dfrPerHr[$msgHr];
                ++${$msgsPerDay{$revMsgDateStr}}[2];
-               push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, \$status: $status, ++\$msgsDfrd") if $opts{'debug'};
+               push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, \$status: $status, ++\$msgsDfrd") if $opts{'debug'};
                ++$msgsDfrdCnt;
                ++$msgsDfrd unless($msgDfrdFlgs{$qid}++);
                ++${$recipDom{$domAddr}}[MSG_DFRS_I];
@@ -1399,6 +1425,12 @@ while(<>) {
                {
                    ${$recipDom{$domAddr}}[MSG_DLY_MAX_I] = $delay
                }
+               # For "expired" detail reports
+               if($rcvdMsg{$qid}) {
+                   my ($relay) = $logRmdr =~ /, relay=([^:]+):/;
+                   $rcvdMsg{$qid}{'relay'} = $relay;
+               }
+
            } elsif($status eq 'bounced') {
                unless($opts{'bounce-detail'} == 0) {
                    my ($bounceReas) = $logRmdr =~ /, status=bounced \((.+)\)/;
@@ -1409,26 +1441,13 @@ while(<>) {
                }
                 ++$bncPerHr[$msgHr];
                ++${$msgsPerDay{$revMsgDateStr}}[3];
-               push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, \$status: $status, ++\$msgsBncd") if $opts{'debug'};
+               push(@{$qidTracker{$qid}{'status'}}, "\$svc: $svc, \$status: $status, ++\$msgsBncd") if $opts{'debug'};
                ++$msgsBncd;
            } else {
                print $unProcd "[03]: $_\n" if $unProcd;
            }
        }
-       elsif($cmd eq 'pickup' && $logRmdr =~ /: (sender|uid)=/) {
-           #
-           # Warning: this code in two places!
-           #
-           ++$rcvPerHr[$msgHr];
-           ++${$msgsPerDay{$revMsgDateStr}}[0];
-           if($opts{'debug'}) {
-               push(@{$qidTracker{$qid}{'status'}}, "\$cmd: $cmd, ++\$msgsRcvd");
-               ++$qidTracker{$qid}{'rcvdCnt'};
-           }
-           ++$msgsRcvd;
-           $rcvdMsg{$qid}{'whence'} = "pickup";        # Whence it came
-       }
-       elsif($cmd eq 'smtp' && $opts{'smtp-detail'} != 0) {
+       elsif($svc eq 'smtp' && $opts{'smtp-detail'} != 0) {
            # Was an IPv6 problem here
            if($logRmdr =~ /.* connect to (\S+?): ([^;]+); address \S+ port.*$/) {
                ++$smtpMsgs{lc($2)}{$1};
@@ -1438,12 +1457,16 @@ while(<>) {
                print $unProcd "[04]: $_\n" if $unProcd;
            }
        }
-       elsif($cmd =~ /^n?qmgr$/ && $logRmdr =~ /\bremoved$/) {
+       elsif($svc =~ /^n?qmgr$/ && $logRmdr =~ /, status=expired, returned to sender$/) {
+           ++$expired{$rcvdMsg{$qid}{'relay'}};
+           ++$msgsExprd;
+       }
+       elsif($svc =~ /^n?qmgr$/ && $logRmdr =~ /\bremoved$/) {
            delete($rcvdMsg{$qid});             # We're done with this
        }
        else
        {
-           print $unProcd "[05]: $_\n" if $unProcd;
+           print $unProcd "[05]: (\$svc: \"$svc\") $_\n" if $unProcd;
        }
     }
 }
@@ -1578,6 +1601,7 @@ printf " %6d%s  deferred", adj_int_units($msgsDfrd);
 printf "  (%d%s deferrals)", adj_int_units($msgsDfrdCnt) if($msgsDfrdCnt);
 print "\n";
 printf " %6d%s  bounced\n", adj_int_units($msgsBncd);
+printf " %6d%s  expired\n", adj_int_units($msgsExprd);
 printf " %6d%s  rejected (%d%%)\n", adj_int_units($msgsRjctd), $msgsRjctdPct;
 printf " %6d%s  reject warnings\n", adj_int_units($msgsWrnd);
 printf " %6d%s  held\n", adj_int_units($msgsHld);
@@ -1653,6 +1677,9 @@ sub print_problems_reports {
     unless($opts{'bounce-detail'} == 0) {
        print_nested_hash(\%bounced, "message bounce detail (by relay)", $opts{'bounce-detail'}, $opts{'quiet'});
     }
+    unless($opts{'expired-detail'} == 0) {
+       print_nested_hash(\%expired, "message expired detail (by relay)", $opts{'expired-detail'}, $opts{'quiet'});
+    }
     unless($opts{'reject-detail'} == 0) {
        print_nested_hash(\%rejects, "message reject detail", $opts{'reject-detail'}, $opts{'quiet'});
        print_nested_hash(\%warns, "message reject warning detail", $opts{'reject-detail'}, $opts{'quiet'});
@@ -2530,6 +2557,8 @@ sub proc_smtpd_reject {
            $rejReas =~ s/^\d{3} \d\.\d\.\d (Server configuration (?:error|problem));.+$/$1/;
            # Condense fqrdns.pcre reports
            $rejReas =~ s/^Unverified (Client host rejected: Generic - Please relay via ISP).*$/$1/;
+           # Condense nullMX reports
+           $rejReas =~ s/^(Sender address rejected: Domain) .+ (does not accept mail \(nullMX\)).*$/$1 $2/;
        } elsif($rejTyp eq "MAIL") {    # *more* special treatment :-( grrrr...
            $rejReas =~ s/^\d{3} (?:<.+>: )?([^;:]+)[;:]?.*$/$1/;
        } elsif($rejTyp eq "connect") { # and still *more* special treatment :-( *sigh*...
index 8304080d6bd044ca8def6d3c5091542f1c9d083e..05afaa4390d3bd02f3fd5608972bb5fbea4fb13a 100644 (file)
@@ -55,7 +55,7 @@
 .\" ========================================================================
 .\"
 .IX Title "PFLOGSUMM 1"
-.TH PFLOGSUMM 1 2025-10-22 1.1.13 "User Contributed Perl Documentation"
+.TH PFLOGSUMM 1 2026-02-09 1.1.14 "User Contributed Perl Documentation"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
 .SH NAME
 pflogsumm \- Produce Postfix MTA logfile summary
 .PP
-Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.13
-.SH SYNOPSIS
-.IX Header "SYNOPSIS"
-.Vb 10
-\&    pflogsumm [\-\-config <file>] [\-\-bounce\-detail <cnt>]
-\&      [\-\-colwidth <n>] [\-\-deferral\-detail <cnt>] [\-\-detail <cnt>]
-\&      [\-d <date [range]>] [\-\-dow0mon] [\-e] [\-h <cnt>] [\-i]
-\&      [\-\-iso\-date\-time] [\-\-mailq] [\-m] [\-\-no\-no\-msg\-size]
-\&      [\-\-problems\-first] [\-\-pscrn\-detail <cnt>] [\-\-pscrn\-stats]
-\&      [\-q] [\-\-rej\-add\-from] [\-\-rej\-add\-to] [\-\-reject\-detail <cnt>]
-\&      [\-\-smtp\-detail <cnt>] [\-\-smtpd\-stats] [\-\-smtpd\-warning\-detail <cnt>]
-\&      [\-\-srs\-mung] [\-\-syslog\-name=string] [\-u <cnt>]
-\&      [\-\-unprocd\-file <filename> ] [\-\-use\-orig\-to] [\-\-verbose\-msg\-detail]
-\&      [\-\-verp\-mung[=<n>]] [\-x] [\-\-zero\-fill] [file1 [filen]]
-\&
+Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.14
+.SH "SYNOPSIS pflogsumm [\-\-config <file>] [\-\-bounce\-detail <cnt>] [\-\-colwidth <n>] [\-d|\-\-date\-range <date [range]>] [\-\-deferral\-detail <cnt>] [\-\-detail <cnt>] [\-\-dow0mon] [\-e|\-\-extended\-detail] [\-\-expired\-detail <cnt> ] [\-h|\-\-host\-cnt <cnt>] [\-i|\-\-ignore\-case] [\-\-iso\-date\-time] [\-m|\-\-uucp\-mung] [\-\-mailq] [\-\-no\-no\-msg\-size] [\-\-problems\-first] [\-\-pscrn\-detail <cnt>] [\-\-pscrn\-stats] [\-q|\-\-quiet] [\-\-rej\-add\-from] [\-\-rej\-add\-to] [\-\-reject\-detail <cnt>] [\-\-smtp\-detail <cnt>] [\-\-smtpd\-stats] [\-\-smtpd\-warning\-detail <cnt>] [\-\-srs\-mung] [\-\-syslog\-name=string] [\-u|\-\-user\-cnt <cnt>] [\-\-unprocd\-file <filename> ] [\-\-use\-orig\-to] [\-\-verbose\-msg\-detail] [\-\-verp\-mung[=<n>]] [\-x|\-\-debug] [\-\-zero\-fill] [file1 [filen]]"
+.IX Header "SYNOPSIS pflogsumm [--config <file>] [--bounce-detail <cnt>] [--colwidth <n>] [-d|--date-range <date [range]>] [--deferral-detail <cnt>] [--detail <cnt>] [--dow0mon] [-e|--extended-detail] [--expired-detail <cnt> ] [-h|--host-cnt <cnt>] [-i|--ignore-case] [--iso-date-time] [-m|--uucp-mung] [--mailq] [--no-no-msg-size] [--problems-first] [--pscrn-detail <cnt>] [--pscrn-stats] [-q|--quiet] [--rej-add-from] [--rej-add-to] [--reject-detail <cnt>] [--smtp-detail <cnt>] [--smtpd-stats] [--smtpd-warning-detail <cnt>] [--srs-mung] [--syslog-name=string] [-u|--user-cnt <cnt>] [--unprocd-file <filename> ] [--use-orig-to] [--verbose-msg-detail] [--verp-mung[=<n>]] [-x|--debug] [--zero-fill] [file1 [filen]]"
+.Vb 1
 \&    pflogsumm \-\-[dump\-config|help|version]
 \&
 \&    Note: Where both long\- and short\-form options exist only the
@@ -176,6 +165,10 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.13
 \&
 \&                        "2025\-07 \- 2025\-08" == 2025\-07\-01 \- 2025\-08\-31
 \&
+\&    \-\-debug        Enable debugging to STDERR
+\&
+\&                   See Also: \-x
+\&
 \&    \-\-dow0mon
 \&                   First day of the week is Monday, rather than Sunday.
 \&
@@ -203,6 +196,11 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.13
 \&
 \&                    pflogsumm \-\-dump\-config <add\*(Aql args> |grep \-v \*(Aq = $\*(Aq
 \&
+\&    \-\-expired\-detail <cnt>
+\&
+\&                   Limit detailed message queue time expired reports to
+\&                   the top <cnt>.  0 to suppress entirely.
+\&
 \&    \-e
 \&    \-\-extended\-detail
 \&
@@ -423,6 +421,8 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.13
 \&
 \&    \-x             Enable debugging to STDERR
 \&
+\&                   See Also: \-\-debug
+\&
 \&    \-\-zero\-fill    "Zero\-fill" certain arrays so reports come out with
 \&                   data in columns that that might otherwise be blank.
 .Ve
index e9d6faa4185703b72edb9f3f577c82ab8cbb6d9c..2a010ab7fec0737ce23f5a90a701bad07c78dab6 100644 (file)
@@ -55,7 +55,7 @@
 .\" ========================================================================
 .\"
 .IX Title "PFTOBYFROM 1"
-.TH PFTOBYFROM 1 2025-05-22 1.1.13 "User Contributed Perl Documentation"
+.TH PFTOBYFROM 1 2025-05-22 1.1.14 "User Contributed Perl Documentation"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l