#!/usr/bin/perl
##############################################################
# Script:       /var/lib/nagios2/jabber-bot
# Description:  This script acts as a jabber bot between
#  nagios and jabber, interacting with both.
# Author:       Brendan Beveridge <brendan@sitesuite.com.au>
# Date:         2008-05-14
##############################################################

use strict;
use Proc::Daemon;
use Proc::PID_File;
use Net::Jabber qw(Client Message) ;
use Sys::Syslog qw( :DEFAULT setlogsock );

use constant PIDDIR    => '/var/run';
use constant SERVER    => 'jabberserver.com';
use constant PORT      => 5222;
use constant USER      => 'jabberuser';
use constant PASSWORD  => 'password';
use constant RESOURCE  => 'nagios';

our $ME = $0; $ME =~ s/.*\///;
our $PROGNAME = $ME; $PROGNAME =~ s/\.pl$//;
our $PIDFILE = PIDDIR . "/$ME.pid";
our $NAGIOSCMDFILE = '/var/lib/nagios2/rw/nagios.cmd';
startDaemon();

$SIG{HUP}  = sub { exit(0) };
$SIG{TERM}  = sub { exit(0) };

# Establish a connection to Jabber Server
my $con = Net::Jabber::Client->new();
$con->Connect( "hostname" => SERVER,"port" => PORT )  or die "Cannot connect ($!)\n";

# Send Auth
my @result = $con->AuthSend( "username" => USER,"password" =>
PASSWORD,"resource" => RESOURCE );

if ($result[0] ne "ok") {
	die "Ident/Auth with server failed: $result[0] - $result[1]\n";
}

my @con;
$con->SetMessageCallBacks( normal=>\&handle_message, chat=>\&handle_message );
$con->RosterGet();
$con->PresenceSend();

# Loop until connection ends
while( defined( $con->Process() )) { }

#########################################
# END OF MAIN
#########################################
sub startDaemon {
	eval { Proc::Daemon::Init; };
	if ($@) {
		print "Unable to start Daemon: $@\n";
		logit('error', "Unable to start Daemon: $@");
		return;
	}
	# Get a pid file
	die "Already running...\n" if hold_pid_file($PIDFILE);
}
sub handle_message() {
	my ($sid,$msg) = @_;
	my $type = $msg->GetType();
	my $from = $msg->GetFrom();	
	my $body = $msg->GetBody();
	if ((length($body) > 0) && ($body !~ /keywords/)) {
		# Check to see if the message body is prefixed with '-'
		if ( $body =~ /^\-/ ) {
			logit('info', "Type: $type, From: $from, Body: $body");
			my $reply = commands($from, $body);
		}
			
	}
}
sub commands() {
	my ($jid,$msg) = @_;
	my @commands = qw(list help ack);
	my @body = undef;
	if ( $msg =~ /^\-list/) {
		push (@body, "Listing Nagios Service/Host Problems:\n" );
		my $hash_ref = nagios_problems();
		foreach my $host ( sort keys %{$hash_ref} ) {
			if ( $hash_ref->{$host}->{'host'}{'current_state'} == 1 ) {
				push (@body, "Host: $host is: " . $hash_ref->{$host}->{'host'}->{'plugin_output'} . "\n");
			}
			foreach my $service ( keys %{$hash_ref->{$host}->{'service'}} ) {
				if ( $hash_ref->{$host}->{'service'}->{$service}->{'current_state'} > 0 ) {
					push (@body, "Host: $host Service: " . $hash_ref->{$host}->{'service'}->{$service}->{'plugin_output'} . "\n");
				}
			}
		}
	}
	elsif ( $msg =~ /^-ack\s+(service|host)\s+(.*)/ ) {
		my $time = time;
		my $type = $1;
		my $details = $2;
		my $fh;
		open($fh, ">", $NAGIOSCMDFILE);
		
		if ( $type eq 'host' ) {
			if ( $details =~ /(\S+)\s(\S+$)/ ) {
				my $hostname = $1;
				my $comment = $2;
				my $cmd = undef;
				my $cmd = "ACKNOWLEDGE_HOST_POBLEM;$hostname;1;1;1;$jid;$comment";
				push ( @body, "RUNNING:\n printf '[%u] " . $cmd . " > $NAGIOSCMDFILE\n");
				logit('info', "ACKNOWLEDGE: $cmd $time");
				printf $fh ('[%u] %s\n', $time, $cmd);
			}
			else {
				push ( @body, "ERROR: incorrect format, see -help\n");
			}
		}
		elsif ( $type eq 'service' ) {
			if ( $details =~ /(\S+)\s(\S+)\s(.*)/ ) {
				my $hostname = $1;
				my $service_description = $2;
				my $comment = $3;
				my $cmd = "ACKNOWLEDGE_SVC_PROBLEM;$hostname;$service_description;1;1;1;$jid;$comment";
				push ( @body, "RUNNING:\n printf '[%u] " . $cmd . " > $NAGIOSCMDFILE\n");
				logit('info', "ACKNOWLEDGE: $cmd $time");
				printf $fh ('[%u] %s\n', $time, $cmd);


			}
			else {
				push ( @body, "ERROR: incorrect format, see -help\n");
			}
		}
		else {
				push ( @body, "ERROR: incorrect format, see -help\n");
		}
		close($fh);
	}
	else {
		push ( @body, "USAGE: -(help|list|ack)\n");
		push ( @body, " -help = display this message\n");
		push ( @body, " -list = display current host/service problems\n");
		push ( @body, " -ack = acknowledge current host/service problems,\n");
		push ( @body, "   format for host = -ack host hostname comment\n");
		push ( @body, "   format for service = -ack service hostname service_description comment\n");
	}
	my $reply = Net::Jabber::Message->new();
	$reply->SetMessage (
		"to" => "$jid",
		"type" => "chat",
		"body" => "@body",
	);
	$con->Send($reply);
}


sub nagios_problems() {
	my %hosts;
	my $retention_file = '/var/lib/nagios2/retention.dat';
	open(FILE, '<', "$retention_file");
	my $hostname = undef;
	my $service_name = undef;
	my $type = undef ;
	while (<FILE>) {
		# Look for the start ( ^host to ^\s+\} ) and end block  
		if (/^(host|service)\s\{/ .. /^\s+\}/) {
			$type = $1;
				if ( $_ =~ /host_name=(\S+)/ ) {
					$hostname = $1;
				}
				elsif ( $_ =~ /service_description=(\S+)/ ) {
					$service_name = $1;
				}
				elsif ( $_ =~ /^\s+(\S+)=(.*)/  ) {
					my $key = $1;
					my $value = $2;
					#my ( $key, $value ) = split('=',$1);
					if ( $type eq 'host' ) {
						$hosts{$hostname}{$type}{$key} = $value;	

					}
					if ( $type eq 'service' ) {
						$hosts{$hostname}{$type}{$service_name}{$key} = $value;	
					}
				}
		}
	}
	return \%hosts;
}

sub logit {
	my ($priority, $msg ) = @_;
	return 0 unless ($priority =~ /info|err|debug/);

	setlogsock('unix');
	openlog($PROGNAME, 'pid,cons', 'daemon');
	syslog($priority, $msg);
	closelog();
	return 1;
}



