#! @PERL@ -w # vim:syntax=perl use strict; use DB_File; use lib '@LR_PERL5LIBDIR@'; use Lire::Email; use Lire::Program qw( :msg :dlf ); my $dbfile = shift or die "give dumpfilestem as arg\n"; # # should be merged with &Email::print_dlf # sub Print_dlf { my ($c, $dlf_maker) = @_; my $dlflines = 0; my %dlf = map { $_ => $c->{$_} } qw/time from_user from_domain from_relay_host from_relay_ip logrelay queueid msgid size stat xstat/; if (! defined $c->{deliveries}) { # Message rejected before the sender was known my $dlf = $dlf_maker->( \%dlf ); print join( " ", @$dlf ), "\n"; $dlflines++; } else { foreach my $to ( keys %{$c->{deliveries}} ) { my $to_infos = $c->{deliveries}{$to}; foreach my $f ( qw/delay to_user to_domain to_relay_host to_relay_ip stat xstat/ ) { $dlf{$f} = $to_infos->{$f}; } my $dlf = $dlf_maker->( \%dlf ); print join( " ", @$dlf ), "\n"; $dlflines++; $c->{nrcpts}--; delete $c->{deliveries}{$to}; } } return $dlflines; } my %dlfids; # maps dlfids to nof occurrences in log # default is , O_CREAT|O_RDWR, , we only need readaccess tie %dlfids, "DB_File", "$dbfile", O_RDONLY, 0666, $DB_HASH or die "cannot tie to $dbfile\n"; my $schema = eval { Lire::DlfSchema::load_schema( "email" ) }; lr_err( "failed to load email schema: $@" ) if $@; my $dlf_maker = $schema->make_hashref2asciidlf_func( qw/time logrelay queueid msgid from_user from_domain from_relay_host from_relay_ip size delay xdelay to_user to_domain to_relay_host to_relay_ip stat xstat /); my ($dlflines, $errorlines) = (0, 0); my %msg; init_dlf_converter( "email" ); while (<>) { chomp; s/^ //; my @a = split / /; # [27-Mar:16:07 Fruit] if(foo&1) bit-is-odd; unless ($#a & 1) { # @a has odd nof elements lr_err "'$_' does not look like postfix2dlf_pre generated line: " . "spaces don't match\n"; } my %line = @a; my $dlfid = $line{'dlfid'} or lr_err "no dlfid in line $_\n"; $msg{$dlfid} ||= {}; my $cur = $msg{$dlfid}; $cur->{'dlfids'}++; # count nof dlfid's processed for my $k ( 'logrelay', 'queueid', 'time', 'from_user', 'from_domain', 'from_relay_host', 'from_relay_ip', 'size', 'msgid' ) { $cur->{$k} ||= $line{$k}; } if (defined $line{'to_user'}) { my $to = $line{'to_user'} . '@' . $line{'to_domain'}; for my $k ( 'to_user', 'to_domain', 'to_relay_host', 'to_relay_ip', 'delay', 'xdelay', 'stat', 'xstat' ) { $cur->{deliveries}{$to}->{$k} ||= $line{$k}; } } if ($cur->{'dlfids'} >= $dlfids{$dlfid}) { # last minute fix-up: # Mar 3 00:09:36 ohno.example.net postfix/nqmgr[15927]: [ID 197553 # mail.info] A87CEAB774: from=, status=expired, # returned to sender # would yield a size-field '-' (!defined $cur->{size} or $cur->{size} !~ /^\d+$/) and $cur->{size} = 0; # print it ... $dlflines += Print_dlf( $cur, $dlf_maker ); # ... and flush it delete $msg{$dlfid}; } } # add errorlines found by lr_postfix2dlf_pre unless (defined $dlfids{'errorlines'}) { lr_err "no errorlines key in $dbfile, was it created by " . "lr_postfix2dlf_pre?\n"; } $errorlines += $dlfids{'errorlines'}; # only lr_postfix2dlf_pre knows about the nof raw loglines defined $dlfids{'loglines'} or lr_err "no loglines key in $dbfile, was it created by " . "lr_postfix2dlf_pre?\n"; my $loglines = $dlfids{'loglines'}; untie %dlfids; end_dlf_converter( $loglines, $dlflines, $errorlines ); __END__ =pod =head1 NAME postfix2dlf_main - convert postfix2dlf_pre output to email dlf =head1 SYNOPSIS B I =head1 DESCRIPTION B expect a preprocessed postfix logfile, as written by postfix2dlf_pre(1) on STDIN. It prints a Lire email DLF file on stdout, using a Berkeley DB in I, holding a mapping from hostname-queueid to number-of-lines-with-this-id. =head1 DEVELOPERS Datastructures are the same as the ones in sendmail2dlf. %msg stores all currently being processed information from the log. In sendmail2dlf, this hash is indexed by dlfid's: $dlfid = $log->{'hostname'} . $log->{'queueid'} . In postfix2dlf we use just the queueid, for now. Scalar values: $msg{$dlfid} = { logrelay => ..., queueid => ..., time => ..., nrcpts => ..., from_user => ..., from_domain => ..., from_relay_host => ..., from_relay_ip => ..., size => ..., msgid => ..., }; Furthermore: $del = $msg{$dlfid}->{deliveries}{$to}; $to is an email address as returned by &Lire::Email::sanitize_tos . $del->{to_user} = ....; $del->{to_domain} = ....; Other $del keys with scalar values: to_relay_host to_relay_ip delay xdelay stat xstat . The hash reference $msg{$dlfid} is often assigned to `$cur'. =head1 EXAMPLES postfix2dlf_main will be rarely used on its own: it is called by postfix2dlf(1). Refer to the postfix2dlf manpage for examples and usage information. =head1 SEE ALSO postfix2dlf(1), postfix2dlf_pre(1), sendmail2dlf(1) =head1 VERSION $Id: postfix2dlf_main.in,v 1.10 2006/07/23 13:16:34 vanbaal Exp $ =head1 COPYRIGHT Copyright (C) 2002 Stichting LogReport Foundation LogReport@LogReport.org 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program (see COPYING); if not, check with http://www.gnu.org/copyleft/gpl.html. =head1 AUTHOR Joost van Baal =cut # Local Variables: # mode: cperl # End: