#! /usr/bin/perl -T
# Check mailflow plugin for Nagios
# 2006-03-28, anders@bsdconsulting.no

package NagiosMailflow;
use Getopt::Std;
use Mail::Sendmail;
use strict;
use Sys::Hostname;
use Mail::POP3Client;
getopts('s:3:i:u:p:l:f:r:w:c:d');

# -s <smtp server> (mandatory)
# -3 <pop server>
# -i <imap server>
# -u <username> (mandatory, for pop/imap server)
# -p <password> (mandatory, for pop/imap server)
# -l <local hostname (for helo)>
# (either choose pop or imap)
# -f <from address> (mandatory)
# -r <recipient address (mandatory)
# -w <warning sleep> (mandatory)
# -c <critical sleep> (mandatory)
# -d (debug, optional)

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

$NagiosMailflow::magicstart = "%%NAGIOSMAILFLOW: ";
$NagiosMailflow::subject = "Nagios mailflow check";
use vars qw { $opt_s $opt_3 $opt_i $opt_u $opt_p $opt_f $opt_r $opt_l $opt_c $opt_w $opt_d };

sub critical {
	print "CRITICAL: $_[0]\n";
	exit(2);
}
sub unknown {
	print "UNKNOWN: $_[0]\n";
	exit(3);
}
sub warning {
	print "WARNING: $_[0]\n";
	exit(1);
}
sub ok {
	print "OK: $_[0]\n";
	exit(0);
}

unknown("Use -r <recipient>") unless ($opt_r);
unknown("Use -f <from address>") unless ($opt_f);
unknown("Use -3 <pop server> or -i <imap server>") unless (($opt_3) || ($opt_i));
if ($opt_3) {
	if ($opt_3 =~ /^([\s\w\.-_]+)$/) {
		# untaint pop3server
		$opt_3 = $1;
	} else {
		unknown("Bad data in POP3 server name");
	}
} else {
	if ($opt_i =~ /^([\s\w\.-_]+)$/) {
		# untaint imapserver
		$opt_i = $1;
	} else {
		unknown("Bad data in IMAP server name");
	}
}
unknown("Use -u <username> (for pop/imap server)") unless ($opt_u);
unknown("Use -p <password> (for pop/imap server)") unless ($opt_p);
unknown("Use -s <smtp server>") unless ($opt_s);
if ($opt_s =~ /^([\s\w\.-_]+)$/) {
	# untaint mailserver
	$opt_s = $1;
} else {
	unknown("Bad data in SMTP server name");
}
unknown("Set -c <secs to wait before critical> and/or -w <secs to wait before warning>") unless (($opt_c) || ($opt_w));
unknown("Critical waiting time must be longer than warning") if ((($opt_c) && ($opt_w)) && ($opt_w >= $opt_c));

sub sender {
	my $text = "$_[0]";
	my %mail = ( To      => "$opt_r",
		  From    => "$opt_f",
		  Message => "$text",
		  Subject => "$NagiosMailflow::subject"
		);
	if (!sendmail(%mail)) {
		my $err = $Mail::Sendmail::error;
		$err =~ s@\r@@g;
		$err =~ s@\n@ @g;
		critical("Could not send mail through $opt_s, bailing out. Error: $err");
	}
}

sub randchar {
	my $number = int rand (62)+1;
	my $pos;

        if ($number<11) { $pos = $number+47; }
        elsif ($number<37) { $pos = $number-10+64; }
        else { $pos = $number-10-26+96; }

        return chr($pos);
}

sub randstr {
	my $str = "";
	for (my $i = 0; $i <= 20; $i++) {
		$str .= randchar;
	}
	return $str;
}

sub ckpop {
	my $pop = new Mail::POP3Client( USER     => $opt_u,
					PASSWORD => $opt_p,
					HOST     => $opt_3,
					);
	if ($pop->Count() == -1) {
		return(0);
	}
	for (my $i = 1; $i <= $pop->Count(); $i++) {
		if ($opt_d) { print "DEBUG: Checking POP mail $i on $opt_p.. "; }
		if ($pop->Body($i) =~ /$NagiosMailflow::magic/) {
			# Yep, found it
			if ($opt_d) { print "FOUND\n"; }
			$pop->Delete($i);
			$pop->Close;
			return(1);
		} else {
			if ($opt_d) { print "MISSING\n"; }
		}
	}
	$pop->Close;
	return(0);
}

#sub ckmail {
#	if ($opt_p) {
#		return(ckpop());
#	}
#else {
#
#}

# Set SMTP server
unshift @{$Mail::Sendmail::mailcfg{'smtp'}} , $opt_s;
# Set optional local hostname
if ($opt_l) { $Sys::Hostname::host = $opt_l };

# Seed random
srand(time() ^ ($$ + ($$ << 15)) );
# The magic text to send and look for
$NagiosMailflow::magic = "%%NAGIOSMAILFLOW: " . randstr . " %%";
# Send the mail
sender($NagiosMailflow::magic . "\n");

if ($opt_w) {
	sleep($opt_w);
	if(ckpop()) {
		if ($opt_3) {
			ok("Found test mail on $opt_3 (POP3 server), after $opt_w seconds wait time");
		} else {
			ok("Found test mail on $opt_i (IMAP server), after $opt_w seconds wait time");
		}
	} elsif (!$opt_c) {
		if ($opt_3) {
			warning("Did not find test mail on $opt_3 (POP3 server), after $opt_w seconds wait time");
		} else {
			warning("Did not find test mail on $opt_i (IMAP server), after $opt_w seconds wait time");
		}
	}
}

if ($opt_c) {
	sleep($opt_c-$opt_w);
	if(ckpop) {
		if ($opt_3) {
			if ($opt_w) {
				warning("Found test mail on $opt_3 (POP3 server), after $opt_c seconds wait time");
			} else {
				ok("Found test mail on $opt_3 (POP3 server), after $opt_c seconds wait time");
			}
		} else {
			if ($opt_w) {
				warning("Found test mail on $opt_i (IMAP server), after $opt_c seconds wait time");
			} else {
				ok("Found test mail on $opt_i (IMAP server), after $opt_c seconds wait time");
			}
		}
	} else {
		if ($opt_3) {
			critical("Did not find test mail on $opt_3 (POP3 server), after $opt_c seconds wait time");
		} else {
			critical("Did not find test mail on $opt_i (IMAP server), after $opt_c seconds wait time");
		}
	}
}
