#!/usr/bin/perl -w

# Nagios Watch - Gtk-Perl frontend for Nagios
#
# Author: Niels van Sluis, <n.vansluis@amc.uva.nl>

use Gtk;
use IO::Socket;
use Proc::Simple;
use strict;

my $server = "nagios.mydomain.org";
my $port   = "33333";
my $browser = "/usr/bin/mozilla";
my $url = "http://nagios.mydomain.org/nagios/";
my $pixmapdir = "/usr/local/share/nagwatch";


### Probably from here, nothing should be changed

set_locale Gtk;  # internationalize
init Gtk;        # initialize Gtk-Perl

my $false = 0;
my $true = 1;
my $version = "v0.1";
my $gviewall = $true;
my %hostsdown = ();

# 30 seconds interval
my $interval = 30000;
my @data;
my $timer = Gtk->timeout_add($interval, \&getdata, @data);

my $table;
my $scrolled_window;

my $window = new Gtk::Window();
$window->set_title("Nagios Watch");
$window->set_default_size(700,200);
$window->signal_connect( "delete_event", \&CloseAppWindow );   
$window->border_width( 0 );
$window->show();

my $vbox = new Gtk::VBox($false,1);
$window->add($vbox);
$vbox->show();

my $statusbar = new Gtk::Statusbar();
$vbox->pack_end($statusbar,$false,$false,0);
$statusbar->show();

my $contextid = $statusbar->get_context_id("Nagios Watch");

buildmenu();

getdata();

main Gtk;

exit( 0 );



sub CloseAppWindow
  {
    Gtk->exit( 0 );
    return $false;
  }

sub getdata {
 %hostsdown = ();

 $statusbar->pop($contextid);
 $statusbar->push($contextid,"Retrieving new data");

 my @rawitems = ();
 my @services = ();
 my @hosts = ();

 @rawitems = split(/\n/,getrawlist());
 foreach(@rawitems) {
   if(/^\[.*\] HOST;.*/) { # match host lines
     push @hosts, $_;
   }
   elsif(/^\[.*\] SERVICE;.*/) { # match service lines
       push @services, $_;
   }
   
 }


 processhosts(@hosts);
 @services = processservices(@services);
 showservices(@services);

 $statusbar->pop($contextid);
 my $mytime = localtime;
 $mytime = "Last checked: $mytime";
 $statusbar->push($contextid,$mytime); 
 return $true;
}

sub getrawlist {
  my $rawdata;
  my $socket = IO::Socket::INET->new(Proto=>"tcp",
				     PeerAddr=>$server,
				     PeerPort=>$port )
	or die "Can't connect to $server\n";

  $socket->autoflush(1);
  while(<$socket>) {
    $rawdata .= $_;
  }
  close $socket;

  return $rawdata;
}

sub showservices {
  my @services = @_;
  my $count = @services;
  my $i = 0;

  $table = new Gtk::Table(4,$count,$false);

  foreach (@services) {
    my @tarray = split(/;/,$_);

    if(defined($hostsdown{"$tarray[1]"})) {
      if($hostsdown{"$tarray[1]"} == $true) {
        $tarray[2] = "HOST";
        $tarray[3] = "CRITICAL";
        $tarray[31] = "Host down";
        $hostsdown{"$tarray[1]"} = $false;
      }
      else {
        next;
      }
    }

    # picture
    my $pixmap;
    my $gdkpixmap;
    my $mask;
    my $style;

    $style = $window->get_style()->bg('normal');
    if($tarray[3] eq "WARNING") {
      ($gdkpixmap,$mask) = Gtk::Gdk::Pixmap->create_from_xpm( $window->window,
      				$style,
    				"$pixmapdir/warning.xpm");
    }
    elsif($tarray[3] eq "CRITICAL") {
    ($gdkpixmap,$mask) = Gtk::Gdk::Pixmap->create_from_xpm( $window->window,
    				$style,
    				"$pixmapdir/critical.xpm");
    }
    else {
    ($gdkpixmap,$mask) = Gtk::Gdk::Pixmap->create_from_xpm( $window->window,
    				$style,
    				"$pixmapdir/ok.xpm");
    }
    $pixmap = new Gtk::Pixmap($gdkpixmap,$mask);
    $pixmap->show();


    my $abutton = new Gtk::Button();
    my $bbutton = new Gtk::Button();
    my $cbutton = new Gtk::Button();
    my $dbutton = new Gtk::Button();
    my $ebutton = new Gtk::Button();

    my $alabel = new Gtk::Label( "$tarray[1]" );
    my $blabel = new Gtk::Label( "$tarray[2]" );
    my $clabel = new Gtk::Label( "$tarray[3]" );
    my $dlabel = new Gtk::Label( "$tarray[31]" );
 
    $abutton->add ( $alabel );
    $bbutton->add ( $blabel );
    $cbutton->add ( $clabel );
    $dbutton->add ( $dlabel );

    $alabel->set_alignment(0,0);
    $blabel->set_alignment(0,0);
    $clabel->set_alignment(0,0);
    $dlabel->set_alignment(0,0);

    $ebutton->add($pixmap);

    $abutton->signal_connect( "clicked", \&ClickedButtonEvent, $tarray[1]);
    $bbutton->signal_connect( "clicked", \&ClickedButtonEvent, $tarray[1]);
    $cbutton->signal_connect( "clicked", \&ClickedButtonEvent, $tarray[1]);
    $dbutton->signal_connect( "clicked", \&ClickedButtonEvent, $tarray[1]);
    $ebutton->signal_connect( "clicked", \&ClickedButtonEvent, $tarray[1]);

    $table->attach_defaults($ebutton,0,1, $i, $i + 1);
    $table->attach_defaults($abutton,1,2, $i, $i + 1);
    $table->attach_defaults($bbutton,2,3, $i, $i + 1);
    $table->attach_defaults($cbutton,3,4, $i, $i + 1);
    $table->attach_defaults($dbutton,4,5, $i, $i + 1);

    $alabel->show();
    $blabel->show();
    $clabel->show();
    $dlabel->show();

    $abutton->show();
    $bbutton->show();
    $cbutton->show();
    $dbutton->show();
    $ebutton->show();

    $i++;
  }

  $table->show();

  if(defined($scrolled_window)) {
    $vbox->remove ($scrolled_window);
  }
  $scrolled_window= new Gtk::ScrolledWindow("","");
  $scrolled_window->border_width(10);
  $scrolled_window->set_policy("automatic","always");
  $scrolled_window->add_with_viewport( $table );
  $scrolled_window->show();

  if(defined($window)) {
    $vbox->pack_start($scrolled_window, $true,$true,2);
    $window->show();
  }
  return $true;
}

sub processhosts {
  my @hosts = @_;

  foreach (@hosts) {
    my @tarray = split(/;/,$_);
    if($tarray[2] ne "UP") {
      $hostsdown{"$tarray[1]"} = $true;
    }
  }
}

sub processservices {
  my @services = @_;
  my @crit;
  my @warn;
  my @other;
  my @return_array;

  foreach (@services) {
    my @tarray = split(/;/,$_);

    if($tarray[3] eq "CRITICAL") {
      push @crit, $_;
    }
    elsif($tarray[3] eq "WARNING") {
      push @warn, $_;
    }
    else {
      push @other, $_;
    }
  }

  foreach (@crit) {
      push @return_array, $_;
  }
  foreach (@warn) {
    push @return_array, $_;
  }

  if($gviewall == $true) {
    foreach (@other) {
      push @return_array, $_;
    }
  }

  return @return_array;
  
}

sub ClickedButtonEvent {
  my ( $widget, $host ) = @_;

  my $myproc = Proc::Simple->new();

  if($host ne "") {
    my $murl = $url . "cgi-bin/status.cgi?host=$host";
    $myproc->start($browser,$murl);
  }
  else {
    $myproc->start($browser,$url);
  }
}

sub buildmenu {
  my $hseparator = new Gtk::HSeparator();
  my $rootmenu = new Gtk::MenuItem("File");;
  my $menubar = new Gtk::MenuBar();
  my $filemenu = new Gtk::Menu();
  my $quit_item = new Gtk::MenuItem("Quit");
  my $viewmenu = new Gtk::MenuItem("View");
  my $subviewmenu = new Gtk::Menu();
  my $all_item = new Gtk::CheckMenuItem("Show All");
  my $helpmenu = new Gtk::MenuItem("Help");
  my $subhelpmenu = new Gtk::Menu();
  my $about_item = new Gtk::MenuItem("About");

  $filemenu->append($quit_item);
  $subviewmenu->append($all_item);
  $subhelpmenu->append($about_item);

  $about_item->signal_connect('activate',\&about);
  $about_item->show();

  $helpmenu->set_submenu($subhelpmenu);
  $helpmenu->right_justify();
  $helpmenu->show();

  $all_item->signal_connect('activate',\&view_all);
  $all_item->show();

  $quit_item->signal_connect('activate',\&file_quit);
  $quit_item->show();

  $rootmenu->show();
  $rootmenu->set_submenu( $filemenu );
  $viewmenu->show();
  $viewmenu->set_submenu( $subviewmenu );

  $vbox->pack_start($menubar,$false,$false,0);
  $menubar->show();
  $menubar->append( $rootmenu);
  $menubar->append( $viewmenu);
  $menubar->append( $helpmenu);
  
  $vbox->pack_start($hseparator,$false,$false,0);
  $hseparator->show();
}

sub file_quit {
  exit(0);
}

sub view_all {
    if($gviewall == $true) {
      $gviewall = $false;
    }
    else {
      $gviewall = $true;
    }
}

sub about {
  my $dialog = new Gtk::Dialog();
  my $button = new Gtk::Button("Close");
  my $nlabel = new Gtk::Label();

  $dialog->set_title("About Nagios Watch");
  $dialog->set_default_size(200,200);

  $button->signal_connect("clicked",sub { $dialog->hide();} );
  $button->show;

  $nlabel->set_text("Nagios Watch $version\n\nAuthor: Niels van Sluis\nEmail: N.vanSluis\@amc.uva.nl");
  $nlabel->show();

  $dialog->action_area->pack_start( $button, $true,$true,0);
  $dialog->vbox->pack_start($nlabel,$true,$true,0);
  $dialog->show();
}
