#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long;
use Net::ManageSieve;
use Time::HiRes;

my $PROGNAME = "check_sieve_login";
my $TIMEOUT  = 120;

my ($sieve,$output,$status,$return);

my $options = {
    'globaltimeout' => 180,
    'port'          => '4190',
    'timeout'       => 30,
    'warning'       => 30,
    'critical'      => 30
};

my $ERRORS = {
    'OK'        => 0,
    'WARNING'   => 1,
    'CRITICAL'  => 2,
    'UNKNOWN'   => 3,
    'DEPENDENT' => 4
};

my $state = 'UNKNOWN';

# close MANAGESIEVE connection, print result and exit
sub nsexit {
    $sieve->logout() if ($sieve);
    my ($msg,$code) = @_;
    $code=$state if (!defined $code);
    print "SIEVE $code: $msg\n" if (defined $msg);
    exit $ERRORS->{$code};
}

# Show verbose help screen
sub print_help() {
    print "$PROGNAME - (c) 2012-2012 Daniel Parthey <d.parthey\@metaways.de>\n";
    print "This program is licensed under the terms of the GNU GPLv2\n";
    print "\n";
    print "Checks login to a MANAGESIEVE account\n";
    print "\n";
    print "Usage: \n";
    print " $PROGNAME -h host -u user -p password [-P port] [-t secs]\n";
    print " $PROGNAME [-h | --help]\n";
    print "\n";
    print "    --help                 This help text\n";
    print " -h|--hostname <hostname>  Hostname or IP address of POP3 server\n";
    print " -P|--port     <port>      Port number of POP3 server (optional)\n";
    print " -u|--username <username>  Username of POP3 mailbox account\n";
    print " -p|--password <password>  Password of POP3 mailbox account\n";
    print " -t|--timeout  <timeout>   Number of seconds until login attempt times out\n";
    print " -w|--warning  <seconds>   Warn if login lasts more than number of seconds\n";
    print " -c|--critical <seconds>   Critical if login lasts more than number of seconds\n";
    exit $ERRORS->{'UNKNOWN'};
};

# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
     print ("ERROR: $0 Time-Out $TIMEOUT s \n");
     exit $ERRORS->{'UNKNOWN'};
};
alarm($TIMEOUT);

# Evaluate Command Line Parameters
Getopt::Long::Configure('no_ignore_case');
my $getopt = GetOptions(
    'help' => \$options->{'help'},
    "h=s"  => \$options->{'hostname'}, "hostname=s" => \$options->{'hostname'},
    "u=s"  => \$options->{'username'}, "username=s" => \$options->{'username'},
    "p=s"  => \$options->{'password'}, "password=s" => \$options->{'password'},
    "P=s"  => \$options->{'port'},     "port=s"     => \$options->{'port'},
    "t=i"  => \$options->{'timeout'},  "timeout=i"  => \$options->{'timeout'},
    "w=i"  => \$options->{'warning'},  "warning=i"  => \$options->{'warning'},
    "c=i"  => \$options->{'critical'}, "critical=i" => \$options->{'critical'}
);

if (!$getopt)                { print_help() };
if (!$options->{'hostname'}) { print "hostname missing\n"; print_help(); };
if (!$options->{'username'}) { print "username missing\n"; print_help(); };
if (!defined($options->{'password'}))
{
    print "password missing\n";
    print_help();
}

my $starttime = Time::HiRes::time();
$sieve = Net::ManageSieve->new(
    Debug   => 0,
    Host    => $options->{'hostname'},
    Port    => $options->{'port'},
    Timeout => $options->{'timeout'}
);

if (!defined($sieve))
{
    nsexit(
        "No MANAGESIEVE banner found on $options->{'hostname'}:$options->{'port'}", 'CRITICAL'
    );
}

my $login_success = $sieve->login(
    $options->{'username'},
    $options->{'password'}
);
if (!defined($login_success))
{
    nsexit("Login failed for user $options->{'username'}",'CRITICAL');
}

my $scripts;
$scripts = $sieve->listscripts();

if (!$scripts)
{
    nsexit("Could not list sieve scripts",'CRITICAL');
}

my $endtime = Time::HiRes::time();
my $duration = $endtime-$starttime;
my $rounded_duration = sprintf("%.1f", $duration);

if ($rounded_duration > $options->{'critical'})
{
    nsexit("Login time of ${rounded_duration}s exceeds critical limit of $options->{'critical'} seconds",'CRITICAL'); 
}

if ($rounded_duration > $options->{'warning'})
{
    nsexit("Login time of ${rounded_duration}s exceeds warning limit of $options->{'warning'} seconds",'WARNING'); 
}

$state = 'OK';
nsexit(scalar(@$scripts)." scripts listed after $rounded_duration seconds", $state);