| 1 | #!/usr/bin/perl -w |
|---|
| 2 | |
|---|
| 3 | =head1 NAME |
|---|
| 4 | |
|---|
| 5 | pl-bouncedb - dump the Project Lancelot bounce database |
|---|
| 6 | |
|---|
| 7 | =head1 SYNOPSIS |
|---|
| 8 | |
|---|
| 9 | pl-bouncedb [-dv?] --dump [--count=BUCKETS] [--size=SECS] |
|---|
| 10 | [--threshold=THRESHOLD] [--timebase=SECS] list@domain |
|---|
| 11 | pl-bouncedb [-dv?] --parse [--address=ADDRESS] [--parser=PARSERS] |
|---|
| 12 | list@domain [MESSAGE] |
|---|
| 13 | |
|---|
| 14 | =head1 DESCRIPTION |
|---|
| 15 | |
|---|
| 16 | The B<pl-bouncedb> command is useful for debugging Project Lancelot's |
|---|
| 17 | bounce processing subsystem. B<pl-bouncedb --dump> dumps the content |
|---|
| 18 | of the bounce database to standard output. B<pl-bouncedb --parse> |
|---|
| 19 | applies the given bounce parser(s) to a message and outputs the result |
|---|
| 20 | (without changing the database). The message is taken either from a |
|---|
| 21 | file named on the command line or from standard input. If no parsers |
|---|
| 22 | are specified on the command line, the default set of parsers is used. |
|---|
| 23 | |
|---|
| 24 | =head1 SEE ALSO |
|---|
| 25 | |
|---|
| 26 | pl-incoming(1), pl-init(1), pl-subchange(1) |
|---|
| 27 | |
|---|
| 28 | =head1 AUTHOR |
|---|
| 29 | |
|---|
| 30 | Anselm Lingnau <anselm@anselms.net> |
|---|
| 31 | |
|---|
| 32 | =head1 COPYRIGHT AND LICENSE |
|---|
| 33 | |
|---|
| 34 | Copyright 2006 by Anselm Lingnau. This program is free software; you |
|---|
| 35 | may redistribute it and/or modify it under the terms of the GNU |
|---|
| 36 | General Public License as published by the Free Software Foundation; |
|---|
| 37 | either version 2 of the License, or (at your option) any later version. |
|---|
| 38 | |
|---|
| 39 | This program is distributed in the hope that it will be useful, but |
|---|
| 40 | WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 42 | General Public License for more details. |
|---|
| 43 | |
|---|
| 44 | You should have received a copy of the GNU General Public License |
|---|
| 45 | along with this program; if not, refer to |
|---|
| 46 | <URL:http://www.gnu.org/copyleft/gpl.html>. You may also obtain it by |
|---|
| 47 | writing to the Free Software Foundation, Inc., 59 Temple Place - Suite |
|---|
| 48 | 330, Boston, MA 02111-1307, USA. |
|---|
| 49 | |
|---|
| 50 | =cut |
|---|
| 51 | |
|---|
| 52 | use strict; |
|---|
| 53 | |
|---|
| 54 | use Config; |
|---|
| 55 | use File::Basename; |
|---|
| 56 | use Time::Piece; |
|---|
| 57 | use Email::MIME; |
|---|
| 58 | |
|---|
| 59 | use vars qw($g_base_dir); |
|---|
| 60 | BEGIN { |
|---|
| 61 | use FindBin qw($Bin); |
|---|
| 62 | $g_base_dir = dirname($Bin); |
|---|
| 63 | } |
|---|
| 64 | use lib "$g_base_dir/lib"; |
|---|
| 65 | use lib "$g_base_dir/lib/perl5/$Config{version}"; |
|---|
| 66 | use lib "$g_base_dir/lib/perl5/site_perl/$Config{version}"; |
|---|
| 67 | |
|---|
| 68 | use Lancelot::GetOpt qw/GetOptions/; |
|---|
| 69 | use Pod::Usage; |
|---|
| 70 | |
|---|
| 71 | use Lancelot::DB; |
|---|
| 72 | use Lancelot::Log qw/log/; |
|---|
| 73 | |
|---|
| 74 | use Lancelot::Module::process_bounce; |
|---|
| 75 | |
|---|
| 76 | my (%opts) = ( dump => 0, parse => 0, parser => '' ); |
|---|
| 77 | |
|---|
| 78 | GetOptions(\%opts, -argvmin => 1, "no list address specified", |
|---|
| 79 | -argvmax => 2, "too many arguments", |
|---|
| 80 | "dump?", "count|c=", "size|s=", "threshold|T=", |
|---|
| 81 | "parse?", "parser|P=", "address|a=", "timebase|t="); |
|---|
| 82 | |
|---|
| 83 | pod2usage( -message => "$0: need --dump or --parse", |
|---|
| 84 | -exitvalue => 2) |
|---|
| 85 | if $opts{dump} + $opts{parse} != 1; |
|---|
| 86 | |
|---|
| 87 | my ($listaddr) = shift; |
|---|
| 88 | |
|---|
| 89 | my $db = new Lancelot::DB $listaddr |
|---|
| 90 | or die "$0: error accessing list $listaddr\n"; |
|---|
| 91 | |
|---|
| 92 | if ($opts{dump}) { |
|---|
| 93 | my $bucket_count = $opts{count} || $db->get_config("bounce.bucketcount"); |
|---|
| 94 | my $bucket_size = $opts{size} || $db->get_config("bounce.bucketsize"); |
|---|
| 95 | my $bounce_threshold = $opts{threshold} || $db->get_config("bounce.threshold"); |
|---|
| 96 | log_and_die "crit", "bounce hander parameter(s) missing from configuration" |
|---|
| 97 | unless $bucket_count && $bucket_size && $bounce_threshold; |
|---|
| 98 | my $timebase = $opts{timebase} || time; |
|---|
| 99 | |
|---|
| 100 | foreach my $address ($db->get_bounce_addresses()) { |
|---|
| 101 | my $t = Lancelot::Module::process_bounce::total_score($db, $address, |
|---|
| 102 | $bucket_count, |
|---|
| 103 | $bucket_size); |
|---|
| 104 | my $bounces = $db->get_bounces($address, 0); |
|---|
| 105 | print "$address: ", scalar(@$bounces), |
|---|
| 106 | " bounces (total score $t, bounce_threshold $bounce_threshold)\n"; |
|---|
| 107 | foreach my $bounce (@$bounces) { |
|---|
| 108 | my ($timestamp, $score, $message) = @$bounce; |
|---|
| 109 | my ($bucket) = int(($timebase - $timestamp) / $bucket_size); |
|---|
| 110 | printf "%3d", $bucket < $bucket_count ? $bucket : "-"; |
|---|
| 111 | print " ", localtime($timestamp)->datetime, " ", $score, " ", |
|---|
| 112 | $message, "\n"; |
|---|
| 113 | } |
|---|
| 114 | } |
|---|
| 115 | } elsif ($opts{parse}) { |
|---|
| 116 | log "debug", "parsing incoming bounce message for $listaddr"; |
|---|
| 117 | my $msg = Email::MIME->new(join "", <>); |
|---|
| 118 | my $address = $opts{address} || "test\@example.com"; |
|---|
| 119 | |
|---|
| 120 | my @parts = $msg->subparts; |
|---|
| 121 | if (@parts == 2 && $parts[0]->body =~ m/^This just came in to /) { |
|---|
| 122 | log "debug", "message presumed forwarded to owner, replacing with second part"; |
|---|
| 123 | $msg = Email::MIME->new($parts[1]->body); |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | log "debug", "parse: parser=$opts{parser}"; |
|---|
| 127 | my $parsers = [ split m/,/, $opts{parser} ]; |
|---|
| 128 | my (@bounces) = Lancelot::Module::process_bounce::classify($db, $msg, |
|---|
| 129 | $address, |
|---|
| 130 | $parsers); |
|---|
| 131 | foreach my $b (@bounces) { |
|---|
| 132 | my ($bounce_addr, $bounce_type) = @$b; |
|---|
| 133 | print "$bounce_type\t$bounce_addr\n"; |
|---|
| 134 | } |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | exit 0; |
|---|