diff options
Diffstat (limited to '')
-rwxr-xr-x | auxiliary/collate/collate.pl | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/auxiliary/collate/collate.pl b/auxiliary/collate/collate.pl new file mode 100755 index 0000000..62d08b9 --- /dev/null +++ b/auxiliary/collate/collate.pl @@ -0,0 +1,146 @@ +#! /usr/bin/perl + +use strict; +use warnings; + +# Postfix delivery agents +my @agents = qw(discard error lmtp local pipe smtp virtual); + +my $instre = qr{(?x) + \A # Absolute line start + (?:\S+ \s+){3} # Timestamp, adjust for other time formats + \S+ \s+ # Hostname + (postfix(?:-[^/\s]+)?) # Capture instance name stopping before first '/' + (?:/\S+)* # Optional non-captured '/'-delimited qualifiers + / # Final '/' before the daemon program name + }; + +my $cmdpidre = qr{(?x) + \G # Continue from previous match + (\S+)\[(\d+)\]:\s+ # command[pid]: +}; + +my %smtpd; +my %smtp; +my %transaction; +my $i = 0; +my %seqno; +my %deleted; + +my %isagent = map { ($_, 1) } @agents; + +while (<>) { + next unless m{$instre}ogc; my $inst = $1; + next unless m{$cmdpidre}ogc; my $command = $1; my $pid = $2; + + if ($command eq "smtpd") { + if (m{\Gconnect from }gc) { + # Start new log + $smtpd{$pid}->{"log"} = $_; next; + undef $smtpd{$pid}->{"qid"}; + } + + $smtpd{$pid}->{"log"} .= $_; + + if (m{\G(\w+): client=}gc) { + # Fresh transaction + my $qid = "$inst/$1"; + $smtpd{$pid}->{"qid"} = $qid; + $transaction{$qid} = $smtpd{$pid}->{"log"}; + $seqno{$qid} = ++$i; + next; + } + + my $qid = $smtpd{$pid}->{"qid"}; + $transaction{$qid} .= $_ + if (defined($qid) && exists $transaction{$qid}); + if (m{\Gdisconnect from}gc) { + if (!defined($qid)) { + print $smtpd{$pid}->{"log"}, "\n"; + } elsif (delete $deleted{$qid}) { + print delete $transaction{$qid}, "\n"; + } + delete $smtpd{$pid}; + } + next; + } + + if ($command eq "pickup") { + if (m{\G(\w+): uid=}gc) { + my $qid = "$inst/$1"; + $transaction{$qid} = $_; + $seqno{$qid} = ++$i; + } + next; + } + + # bounce(8) logs transaction start after cleanup(8) already logged + # the message-id, so the cleanup log entry may be first + # + if ($command eq "cleanup") { + next unless (m{\G(\w+): }gc); + my $qid = "$inst/$1"; + $transaction{$qid} .= $_; + $seqno{$qid} = ++$i if (! exists $seqno{$qid}); + if (m{\G(?:milter(?:-(?:header|body))?-)?(?:reject|discard|hold): }) { + $deleted{$qid} = 1; + } + next; + } + + if ($command eq "qmgr") { + next unless (m{\G(\w+): }gc); + my $qid = "$inst/$1"; + if (defined($transaction{$qid})) { + $transaction{$qid} .= $_; + if (m{\Gremoved$}gc) { + print delete $transaction{$qid}, "\n"; + } + } + next; + } + + # Save pre-delivery messages for smtp(8) and lmtp(8) + # + if ($command eq "smtp" || $command eq "lmtp") { + $smtp{$pid} .= $_; + + if (m{\G(\w+): to=}gc) { + my $qid = "$inst/$1"; + if (defined($transaction{$qid})) { + $transaction{$qid} .= $smtp{$pid}; + } + delete $smtp{$pid}; + } + next; + } + + if ($command eq "bounce") { + if (m{\G(\w+): .*? notification: (\w+)$}gc) { + my $qid = "$inst/$1"; + my $newid = "$inst/$2"; + if (defined($transaction{$qid})) { + $transaction{$qid} .= $_; + } + $transaction{$newid} = + $_ . $transaction{$newid}; + $seqno{$newid} = ++$i if (! exists $seqno{$newid}); + } + next; + } + + if ($isagent{$command}) { + if (m{\G(\w+): to=}gc) { + my $qid = "$inst/$1"; + if (defined($transaction{$qid})) { + $transaction{$qid} .= $_; + } + } + next; + } +} + +# Dump logs of incomplete transactions. +foreach my $qid (sort {$seqno{$a} <=> $seqno{$b}} keys %transaction) { + print $transaction{$qid}, "\n"; +} |