#!/usr/bin/perl -w

use strict;
use warnings;

=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) 2006-2009 Nicolai Langfeldt
  Copyright (C) 2004-2005,2011 Jimmy Olsen
  Copyright (C) Henrik Grindal
  Copyright (C) Torstein Svendsen

Torstein Svendsen recalls originally writing this with Henrik Grindal
Bakken to create MRTG graphs of exims mailqueues for Linpros client
RunBox.  Thus this code predates Munin itself.

The first traces of the plugin in CVS seems to be 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 lib $ENV{'MUNIN_LIBDIR'};
use Munin::Plugin;

##########

sub get_exim_logfile
{
    my ($spec, $type, $time) = @_;
    chomp($spec);
    $time ||= 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;
}


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

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

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

    if ($rotated || $received eq 'U') {
        # Reset everything if the log has been rotated or we've just initialised
        $pos = $received = $completed = $rejected = 0;
    }

    while (<$LOGFILE>) {
        chomp;

        if (/ <= /) {
            $received++;
        }
        elsif (m/ Completed(?: |$)/) {
            $completed++;
        }
        elsif (/ rejected /) {
            $rejected++;
        }
    }
    return tail_close($LOGFILE);
}


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") {
    if (defined($LOGDIR)) {
        if (! -d $LOGDIR) {
            print "no (logdir '$LOGDIR' does not exist)\n";
            exit 0;
        }
        $logfile = $LOGDIR . '/' . ($LOGNAME || 'mainlog');
    }
    else {
        my $logfilespec = `$EXIM -bP log_file_path 2>/dev/null`;

        if ($? == 0) {
            $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 0;
            }
        }
        elsif ($? == 127) {
            print "no (exim not found)\n";
            exit 0;
        }
        else {
            print "no ('$EXIM -bP log_file_path' returned an error)\n";
            exit 0;
        }
    }

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

    exit 0;
}


my $logfilespec;

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

die "Logfile '$logfile' is not readable\n" 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 mail\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;
}

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

if (! defined $pos) {
    # No state file present.  Avoid startup spike: Do not read log
    # file up to now, but remember how large it is now, and next
    # time read from there.
    $pos = (stat $logfile)[7];  # File size
    $received = $completed = $rejected = 'U';
}
else {
    $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);

