#!/usr/bin/perl
# 
# ----------------------------------------------------------------
# Based on rt-crontool found in /opt/rt/bin directory.
# Thanks to good people in bestpractical Solutions, LLC.
#
# see "Usage". Returns exit status suitable for Nagios if
# tickets are open too long
#
# Andrew Daviel, Hossein Rafighi April 2010
#
use strict;
use Carp;
use Time::Local ;
my $defhwarn=5*24 ; my $defhcrit=7*24 ; my $defhnwarn=24 ; my $defhncrit=48 ;

# fix lib paths, some may be relative
BEGIN {
    require File::Spec;
    my @libs = ("lib", "local/lib");
    my $bin_path;

    for my $lib (@libs) {
        unless ( File::Spec->file_name_is_absolute($lib) ) {
            unless ($bin_path) {
                if ( File::Spec->file_name_is_absolute(__FILE__) ) {
                    $bin_path = ( File::Spec->splitpath(__FILE__) )[1];
                }
                else {
                    require FindBin;
                    no warnings "once";
                    $bin_path = $FindBin::Bin;
                }
            }
            $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib );
        }
        unshift @INC, $lib;
    }
}

use RT;

use Getopt::Std;
my $STATE_OK = 0;
my $STATE_WARNING = 1;
my $STATE_CRITICAL = 2;
my $STATE_UNKNOWN = 3;
my $USAGE = "
Usage: $0 -q <queue> [-w <hours>][-c <hours>][-W <hours>][-C <hours>]

     -q queue name e.g. 'General'
     -c # of hours ticket open to trigger a critical failure ($defhcrit)
     -w # of hours ticket open to trigger a warning ($defhwarn)
     -C # of hours ticket new  to trigger a critical failure ($defhncrit)
     -W # of hours ticket new  to trigger a warning ($defhnwarn)
     -v verbose
";

use RT::Interface::CLI qw(CleanEnv GetCurrentUser GetMessageContent loc);
use RT::Tickets;

#Clean out all the nasties from the environment
CleanEnv();

my ( $search, $search_arg, $log );
# hardcode
$search = 'RT::Search::FromSQL' ;

my %opts; 
unless (getopts('q:c:C:w:W:v', \%opts)) {
   print $USAGE;
   exit 1;
}
unless (defined $opts{'q'}) {
   print $USAGE;
   exit 1;
}
my $rstatus ;

my $queue ; my $hwarn=$defhwarn ; my $hcrit=$defhcrit ; my $hnwarn=$defhnwarn ; my $hncrit= $defhncrit ;
my $ncrit = 0 ; my $nwarn = 0 ;
$queue = $opts{'q'};

if (defined $opts{'w'}) { # hours open till warn
  if ($opts{'w'} =~ /(^[\d]+)$/) {
    $hwarn = $1 ;
  } else {
    print "Error: -w requires numeric number of hours\n" ;
    exit 1 ;
  }
}
if (defined $opts{'c'}) { # hours open till critical
  if ($opts{'c'} =~ /(^[\d]+)$/) {
    $hcrit = $1 ;
  } else {
    print "Error: -c requires numeric number of hours\n" ;
    exit 1 ;
  }
}
if (defined $opts{'W'}) {  # hours new till warn
  if ($opts{'W'} =~ /(^[\d]+)$/) {
    $hnwarn = $1 ;
  } else {
    print "Error: -W requires numeric number of hours\n" ;
    exit 1 ;
  }
}
if (defined $opts{'C'}) {  # hours new till critical
  if ($opts{'C'} =~ /(^[\d]+)$/) {
    $hncrit = $1 ;
  } else {
    print "Error: -C requires numeric number of hours\n" ; 
    exit 1 ;
  }
}

# Load the config file
RT::LoadConfig();

# adjust logging to the screen according to options
RT->Config->Set( LogToScreen => $log ) if $log;

#Connect to the database and get RT::SystemUser and RT::Nobody loaded
RT::Init();

#Get the current user all loaded
my $CurrentUser = GetCurrentUser();

unless ( $CurrentUser->Id ) {
    print loc("No RT user found. Please consult your RT administrator.\n");
    exit(1);
}

# We _must_ have a search object
load_module($search);

# search for new tickets
$search_arg = "Queue = '$queue' AND Status = 'new'" ;
#find a bunch of tickets
my $tickets = RT::Tickets->new($CurrentUser);
my $search  = $search->new(
    TicketsObj  => $tickets,
    Argument    => $search_arg,
    CurrentUser => $CurrentUser
);

my $now = time() ;
$search->Prepare();
if ($opts{'v'}) { print "New tickets in $queue, warn over $hnwarn hours, critical over $hncrit hours\n" ; }
my $tickets = $search->TicketsObj;
my $nnew = 0 ; my $nncrit = 0 ; my $nnwarn = 0 ;
while ( my $ticket = $tickets->Next() ) {
  $nnew++ ;
  my $created ; my $lcreated ; my $age ; 
  my $id = $ticket->Id ;
  my $name = $ticket->QueueObj->Name() ;
  my $date = $ticket->Created ;
  my $update = $ticket->LastUpdated ;
  my $status = $ticket->Status ;
  if ($ticket->Created =~ /([\d]+)-([\d]+)-([\d]+)[\s]+([\d]+):([\d]+):([\d]+)/) {
    $created = timegm($6,$5,$4,$3,$2-1,$1) ;
    $lcreated = localtime($created) ;
    $age = int(($now - $created) / 3600) ; # open $age hours
  } else {
    print "ERROR parsing $ticket->Created\n" ;
  }
  if ($opts{'v'}) {
    print "Ticket #: $id\tQueue: $name\tCreated On: $date GMT\tLast Updated: $update GMT\tStatus: $status\t$age hours\n";
  }
  if ($age > $hncrit) {
    $nncrit++ ;
  } 
  if ($age > $hnwarn) {
    $nnwarn++ ;
  }
}

# search for open tickets

$search_arg = "Queue = '$queue' AND Status = 'open'" ;
#find a bunch of tickets
my $tickets = RT::Tickets->new($CurrentUser);
my $search  = $search->new(
    TicketsObj  => $tickets,
    Argument    => $search_arg,
    CurrentUser => $CurrentUser
);

$search->Prepare();

if ($opts{'v'}) { print "Open tickets in $queue, warn over $hwarn hours, critical over $hcrit hours\n" ; }

# TicketsFound is an RT::Tickets object
my $tickets = $search->TicketsObj;

my $nwarn = 0 ; my $nopen = 0 ; my $ncrit = 0 ;
#for each ticket we've found
while ( my $ticket = $tickets->Next() ) {
  my $created ; my $lcreated ; my $age ; 
  my $id = $ticket->Id ;
  my $name = $ticket->QueueObj->Name() ;
  my $date = $ticket->Created ;
  my $update = $ticket->LastUpdated ;
  my $status = $ticket->Status ;
  if ($ticket->Created =~ /([\d]+)-([\d]+)-([\d]+)[\s]+([\d]+):([\d]+):([\d]+)/) {
    $created = timegm($6,$5,$4,$3,$2-1,$1) ;
    $lcreated = localtime($created) ;
    $age = int(($now - $created) / 3600) ; # open $age hours
  } else {
    print "ERROR parsing $ticket->Created\n" ;
  }
  $nopen++ ;
  if ($age > $hcrit) {
    $ncrit++ ;
  } 
  if ($age > $hwarn) {
    $nwarn++ ;
  }
  if ($opts{'v'}) { print "Ticket #: $id\tQueue: $name\tCreated On: $date GMT\tLast Updated: $update GMT\tStatus: $status\t$age hours\n"; }
}
my $hwarnh = $hwarn.'h' ;
my $hcrith = $hcrit.'h' ;
my $hnwarnh = $hnwarn.'h' ;
my $hncrith = $hncrit.'h' ;
print "$nnew new tickets: $nnwarn > $hnwarnh, $nncrit > $hncrith; $nopen open: $nwarn > $hwarnh, $ncrit > $hcrith\n" ;
if ($ncrit or  $nncrit) { exit $STATE_CRITICAL; }
if ($nwarn or $nnwarn) { exit $STATE_WARNING; }
exit $STATE_OK;

# {{{ load_module 

=head2 load_module

Loads a perl module, dying nicely if it can't find it.

=cut

sub load_module {
    my $modname = shift;
    eval "require $modname";
    if ($@) {
        die loc( "Failed to load module [_1]. ([_2])", $modname, $@ );
    }

}

# }}}

# {{{ loc 

=head2 loc LIST

Localize this string, with the current user's currentuser object

=cut

sub loc {
    $CurrentUser->loc(@_);
}

# }}}

