#!/usr/bin/perl
# -*- perl -*-

=head1 NAME

exim_mailstats - Plugin to monitor the number of mails received and
delivered by exim.

=head1 APPLICABLE SYSTEMS

Exim version 3 or 4.

=head1 CONFIGURATION

Usually no configuration is needed for this plugin.

  [exim*]
     env.logdir   /path/to/exim-logs/
     env.logname  mainlog
     env.exim     /usr/sbin/exim

The default value for the C<logdir> variable is determined by running
C<exim -bP log_file_path>.  C<mainlog> is the default name given to
exims main log, but it has been known to be called "main.log" in some
versions of Red Hat/Fedora for example.

NOTE: If you need to set logname you must also set logdir as there is
no automatic way to determine the path then.

The default value of the C<exim> variable is C</usr/sbin/exim>, but if
there is a executable called C</usr/sbin/exim4> this is used instead.

=head1 INTERPRETATION

Need some input from an exim postmaster here.

=head1 MAGIC MARKERS

  #%# family=auto
  #%# capabilities=autoconf

=head1 BUGS

None Known

=head1 AUTHOR

Copyright (C) 2002-2008 Torstein Svendsen, Jimmy Olsen, Nicolai Langfeldt

Original author not documented, but likely Torstein Svendsen in 2002.
Further messing by Jimmy Olsen the same year.  Bugfixing and cleanup
by Nicolai Langfeldt 2008.

=head1 LICENSE

GPLv2

=cut

# In most installations the "use lib" can be removed as the Munin
# modules are installed in perls module path.

use strict;
use lib $ENV{'MUNIN_LIBDIR'};
use Munin::Plugin;

##########

sub get_exim_logfile {
    my ($spec, $type, $time) = @_;
    chomp($spec);
    $time = time() unless $time;
    my $logfile = $spec;
    $logfile =~ s/^log_file_path = //;
    $logfile =~ s/\%s/$type/;

    if( $logfile =~ /\%D/ ) {
	my @t=localtime($time);
	my $ts = sprintf("%04d%02d%02d",$t[5]+1900, $t[4]+1, $t[3]);
	$logfile =~ s/\%D/$ts/g;
    }
    my @lfiles = split(/\s?:\s?/, $logfile);
    foreach (@lfiles) {
	return $_ unless /^syslog/;
    }
    return undef;
}

my $pos   = undef;
my $received = 0;
my $completed = 0;
my $rejected = 0;
my $dirname;

($dirname = $0) =~ s/[^\/]+$//;

my $EXIM = "/usr/sbin/exim";

$EXIM = "/usr/sbin/exim4" if (-x "/usr/sbin/exim4"); # a Debianism
$EXIM = $ENV{'exim'} if defined  $ENV{'exim'};

my $LOGDIR = $ENV{'logdir'} || undef;
my $LOGNAME = $ENV{'logname'} || '';

my $logfile;

if ( $ARGV[0] and $ARGV[0] eq "autoconf" )
{
    my $logfile;

    if(defined($LOGDIR)) {
	if(! -d $LOGDIR) {
	    print "no (logdir does not exist)\n";
	    exit 1;
	}
	$logfile = $LOGDIR . '/' . ($LOGNAME || 'mainlog');

    } else {

	my $logfilespec = `$EXIM -bP log_file_path 2>/dev/null`;
	if (! $?) {
	    $logfile = get_exim_logfile( $logfilespec, 'main');
	    if (! defined($logfile) ) {
		print "no (not able to parse output of '$EXIM -bP log_file_path' = '$logfilespec')\n";
		exit 1;
	    }
	} elsif ($? eq "127") {
	    print "no (exim not found)\n";
	    exit 1;
	} else {
	    print "no ('$EXIM -bP log_file_path' returned an error)\n";
	    exit 1;
	}
    }

    if ($logfile) {
	if (-r "$logfile") {
	    print "yes\n";
	    exit 0;
	} else {
	    print "no (logfile '$logfile' not readable)\n";
	}
    }

    exit 1;
}


my $logfilespec;

if(defined($LOGDIR)) {
    $logfilespec = '';
    $logfile = $LOGDIR . '/' . ($LOGNAME || 'mainlog');
} else {
    $logfilespec = `$EXIM -bP log_file_path`;
    $logfile = get_exim_logfile( $logfilespec, 'main');
}

exit 1 unless -r $logfile;

if ( $ARGV[0] and $ARGV[0] eq "config" ) {
    print "graph_title Exim mail throughput\n";
    print "graph_args --base 1000 -l 0\n";
    print "graph_vlabel mails/\${graph_period}\n";
    print "graph_scale  no\n";
    print "graph_category exim\n";
    print "received.label received\n";
    print "received.type DERIVE\n";
    print "received.min 0\n";
    print "received.draw AREA\n";
    print "completed.label completed\n";
    print "completed.type DERIVE\n";
    print "completed.min 0\n";
    print "rejected.label rejected\n";
    print "rejected.type DERIVE\n";
    print "rejected.min 0\n";
    exit 0;
}

if (! -f $logfile) {
    print "completed.value U\n";
    print "received.value U\n";
    print "rejected.value U\n";
    exit 0;
}

($pos,$received,$completed,$rejected) = restore_state();

# No (valid) state present?
$pos = $received = $completed = $rejected = 0 if !defined($rejected);

$pos = parseEximfile ($logfile, $pos);

print "received.value $received\n";
print "completed.value $completed\n";
print "rejected.value $rejected\n";

save_state($pos,$received,$completed,$rejected);

sub parseEximfile {
    my ($fname, $start, $stop) = @_;

    my ($LOGFILE,$rotated) = tail_open($fname, $start);

    if ($rotated) {
	# Reset everything if the log has been rotated
	$pos = $received = $completed = $rejected = 0;
    }

    my $line;

    while ($line = <$LOGFILE>) {
	chomp ($line);

	if (substr ($line, 37,2 ) eq '<=') {
	    $received++;
	} elsif (substr ($line, 37,9) eq 'Completed') {
	    $completed++;
	} elsif ($line=~/rejected/) {
            $rejected++;
        }
    }
    close($LOGFILE) or die "Could not close $fname after reading: $!";
}

# vim:syntax=perl
