#!/usr/bin/perl -w
use strict;
use Getopt::Long;

# Copyright (c) 2004 Doug Alcorn, <doug@lathi.net>
#
#      This program is free software; you can redistribute it and/or
#      modify it under the terms of the GNU General Public License as
#      published by the Free Software Foundation; either version 2 of
#      the License, or (at your option) any later version.

my %pIDS;
my %msgIDS;
my @unknown;
my %ips;
my %hostnames;
my %address;
my %rejects;
my %warnings;
my $SPAM_SCORE = 5;
my %spam;

my $rejects_only = 0;
my $msgid;
my $pid;
my $email;
my $warnings_only = 0;
my $summary = 0;
GetOptions ("--email=s" => \$email,
            "--message-id=s" => \$msgid,
            "--postfix-id=s" => \$pid,
            "--summary" => \$summary,
            "--rejects-only" => \$rejects_only,
            "--warnings-only" => \$warnings_only,);

my $id = shift;

my $lineno = 0;
while (<ARGV>) {
    my $pid;
    my $msgid;
    if (/([0-9A-F]{9}):/) {
        $pid = $1;
        if (/$pid: reject:/) {
            $rejects{$pid} = 1;
        }
        if (/$pid: reject_warning:/) {
            $warnings{$pid} = 1;
        }
        while (/(to|from)=<([^>]+)>/g) {
            my $address = $2;
            $address =~ tr/A-Z/a-z/;
            unless (exists $address{$address}) {
                $address{$address} = {};
            }
            $address{$address}->{$pid} = 1;
        }
        if (/client=(.*?)\[([0-9.]+)\]/) {
            my ($hostname, $ip) = ($1, $2);
            next if ($ip eq "127.0.0.1");
            next if (exists $hostnames{$hostname} 
                     and $hostnames{$hostname} =~ /$pid/);
            $hostnames{$hostname} .= "$pid ";
            $ips{$ip} .= "$pid ";
        }
        unless (exists $pIDS{$pid}) {
            $pIDS{$pid} = {};
            $pIDS{$pid}->{lines} = [];
            $pIDS{$pid}->{linenos} = {};
        }
        $pIDS{$pid}->{linenos}->{$lineno} = $lineno;
        push @{$pIDS{$pid}->{lines}}, "$lineno $_";
    }
    if (/message-id(=|: )<([^>]+)>/i) {
        $msgid = $2;
        if (/, Hits: (.*)/) {
            my $score = $1;
            if ($score =~ /\d/ and $score > $SPAM_SCORE) {
                $spam{$msgid} = $score;
            }
        }
        unless (exists $msgIDS{$msgid}) {
            $msgIDS{$msgid} = {};
            $msgIDS{$msgid}->{lines} = [];
            $msgIDS{$msgid}->{pid} = "";
        }
        if ($pid) {
            $pIDS{$pid}->{msgid} = $msgid;
            $msgIDS{$msgid}->{pid} .= "$pid ";
        } else {
            push @{$msgIDS{$msgid}->{lines}}, "$lineno $_";
        }
    }
    unless ($msgid or $pid) {
        push @unknown, $_;
    }
    $lineno++;
}

foreach my $pid (keys %pIDS) {
    if (exists $pIDS{$pid}->{msgid}) {
        my $msgid = $pIDS{$pid}->{msgid};
        foreach my $line (@{$msgIDS{$msgid}->{lines}}) {
            $line =~ /^(\d+) /;
            my $lineno = $1;
            next if exists $pIDS{$pid}->{linenos}->{$lineno};
            push @{$pIDS{$pid}->{lines}}, $line;
            $pIDS{$pid}->{linenos}->{$lineno} = $lineno;
        }
        foreach my $otherid (split / /, $msgIDS{$msgid}->{pid}) {
            next if ($otherid eq $pid);
            foreach my $line (@{$pIDS{$otherid}->{lines}}) {
                $line =~ /^(\d+) /;
                my $lineno = $1;
                next if exists $pIDS{$pid}->{linenos}->{$lineno};
                push @{$pIDS{$pid}->{lines}}, $line;
                $pIDS{$pid}->{linenos}->{$lineno} = $lineno;
            }
        }
    }
}

if (exists $hostnames{$id}) {
    foreach my $pid (split / /, $hostnames{$id}) {
        print grepmsg($pid);
    }
} elsif (exists $ips{$id}) {
    foreach my $pid (split / /, $ips{$id}) {
        print grepmsg($pid);
    }
} elsif (exists $address{$id}) {
    foreach my $pid (keys %{$address{$id}}) {
        print grepmsg($pid);
    }
} elsif ($id =~ /\*/) {
    # assume it's a hostname regexp pattern
    foreach my $hostname (keys %hostnames) {
        if ($hostname =~ /$id/) {
            foreach my $pid (split / /, $hostnames{$hostname}) {
                print grepmsg($pid);
            }
        }
    }
} else {
    print grepmsg($id);
}

sub grepmsg {
    my $id = shift;
    return if ($rejects_only and not exists $rejects{$id});
    return if ($warnings_only and not exists $warnings{$id});
    my @lines;
    if (exists $pIDS{$id}) {
    } elsif (exists $msgIDS{$id}) {
        my $pid = $msgIDS{$id}->{pid};
        $pid =~ s/ .*//;
        $id = $pid;
    }
    @lines =  grep {s/^\d+ //}
    sort {$a =~ /^(\d+) /; my $aa = $1; $b =~ /^(\d+) /; my $bb = $1; $aa <=> $bb} 
    @{$pIDS{$id}->{lines}};
    if ($summary  and $rejects_only) {
        my @summary;
        foreach my $line (@lines) {
            next unless ($line =~ /(... .. ..:..:..) .*$id: reject:.*[45]\d\d.*?\] (.*?); from=<([^>]+)> to=<([^>]+)>/);
            my ($date, $msg, $from, $to) = ($1, $2, $3, $4);
            push @summary, "$date $id to=<$to> from=<$from> $msg\n";
        }
        @lines = @summary;
    }
    return @lines;
}


