#!/usr/bin/perl -w
# mnalis+news@carnet.hr, 20090310, GPLv3+
# 
# nagios plugin to check number of new articles in some high-traffic groups,
# and raise alert if they're not arriving... Also tests user/pass authentication
#
# TODO:
# - script currently requires that news server implements NEWNEWS command
# - only plain NNTP, no NNTPS or STARTTLS support, as News::NNTPClient doesn't support it. 
#   You may want to use stunnel4(8) or similar for workaround if you need it.
#

use strict;
use News::NNTPClient;
use Getopt::Std;

my $VER = '1.01';

# exits with critical error
sub greska ($)
{
  my ($greska) = @_;
  print "ARTICLES CRITICAL - $greska\n";
  exit 2;
}

# usage help screen
sub HELP_MESSAGE()
{
  print "Usage: $0 $VER -H <hostname> [-p <port>] [-d <debug>] [-w <warn>] [-c <crit>] [-u <user>] [-p <pass>] [-g <groups>]\n";
  print " -w/-c are in seconds; you'll get a warning if there are no articles newer than this in given groups.\n";
  print " <groups> are comma separated list of groups, like: 'misc.test,news.admin.nocem'\n";
  exit 1;
}

# HERE GOES THE MAIN !
our ($opt_H, $opt_u, $opt_p);
our $opt_P = 119;
our $opt_d = 0;
our $opt_w = 600;
our $opt_c = 3600;
our $opt_g = 'misc.test,news.admin.nocem,alt.test';

getopts('H:P:g:w:c:d:u:p:') or HELP_MESSAGE();

HELP_MESSAGE() unless ($opt_H);

my @CHECK_GROUPS = split /,/, $opt_g;
  
my $conn = new News::NNTPClient ($opt_H, $opt_P) or greska ("Can't connect to: $opt_H:$opt_P");
$conn->mode_reader() or greska ("Can't enter reader mode on $opt_H:$opt_P");
$opt_d && print "DEBUG: mode reader OK on $opt_H:$opt_P\n";

if ($opt_u) {
  $conn->authinfo ($opt_u, $opt_p) or greska ("authinfo failed");
  $opt_d && print "authenticated OK as $opt_u\n";
}


our $msg = '**unknown**';

if ($opt_g) {
  if (newsgroups_stale ($opt_c)) {
    print "ARTICLES CRITICAL - no new messages in monitored groups in $opt_c seconds\n";
    exit 0;
  }

  if (newsgroups_stale ($opt_w)) {
    print "ARTICLES WARNING - no new messages in monitored groups in $opt_w seconds\n";
    exit 0;
  }
} else {
  $msg = 'skipped checking new articles.'
}

print "ARTICLES OK: $msg\n";
exit 0;

# checks groups for given timeout. 
# returns true if groups is stale (no new articles), or false if ok.
sub newsgroups_stale
{
  my ($last_seconds) = @_;

  foreach my $group (@CHECK_GROUPS) {
    my @msg = $conn->newnews($group, time() - $last_seconds);
    my $count = scalar @msg;
    $opt_d && print "*** $group: $count new messages in $last_seconds seconds\n";
    if ($opt_d > 1) {
      foreach my $m (@msg) { print "  m=$m" }
    }
    if ($count > 0) {
      $msg = "found $count new messages in $group in last $last_seconds seconds";
      return 0;
    }
  }

  return 1;	# group stale
}


