#! /usr/bin/perl 
#
# jabber-alert.pl - send a Lithium alert notification via Jabber.
#
# 2008 Andrew J Cosgriff, In Systems <ajc@insys.com.au>
#
# based on the distributed Lithium action scripts.
#
# IMPORTANT NOTES
#
# If you're using the Openfire Jabber server, you may find you get
# errors like this:
#
# Can't use an undefined value as a HASH reference at
# /usr/lib/perl5/site_perl/5.8.8/XML/Stream.pm line 1165.
#
# 1) to fix that, see http://hiddenrealms.org/articles/net-jabber1.php
#    but only apply the first patch (for XML::Stream) - we have
#    another work around for the second issue mentioned on that page.
#
# 2) the second fix is to use AuthIQAuth method rather than AuthSend,
#    in setupJabberConnection down at the end of this file.
#
use XML::Simple; 
use Net::SMTP; 
use Data::Dumper; 
use Time::CTime; 
use Net::Jabber qw(Client);
use Net::Jabber qw(Message);
use Net::Jabber qw(Protocol);

###################################
#  Script Configuration Variables
###################################

%xmlstruct = (  'desc' => "Jabber Notification Script",
                'version' => '1.0',
                'config_variable'=> [
                              {
                                'name' => 'jabber_server',
                                'required' => '1',
                                'desc' => 'Jabber Server hostname'
                              },
                              {
                                'name' => 'user',
                                'required' => '1',
                                'desc' => 'Jabber user to send message from'
                              },
                              {
                                'name' => 'passwd',
                                'required' => '1',
                                'desc' => 'Jabber password to authenticate with'
                              },
                              {
                                'name' => 'recipients',
                                'required' => '1',
                                'desc' => 'Recipients (comma-separated)'
                              }
                 ]
            );


###################################
#  Command processing
###################################

($ARGV[0] eq "info") and ($#ARGV == 0) and
   print &generateConfig($xmlroot, \%xmlstruct);
 
($ARGV[0] eq "report") and ($#ARGV != 0) and
  reportIncident($ARGV[$#ARGV]);

($ARGV[0] eq "remind") and ($#ARGV != 0) and
  remindIncident($ARGV[$#ARGV]);

($ARGV[0] eq "clear") and ($#ARGV != 0) and
  clearIncident($ARGV[$#ARGV]);

###################################
# Handling of an incident report
###################################

sub reportIncident
{
  # 1 Parameter: Filename for the XML
  my ($filename) = @_;

  # Retrieve action from ARGV 
  %action = &getAction();
  
  # Extract Variables from XML and store in %variables Hash
  %variables = &getVariables($filename);
   
  # Set variables from XML
  my @recipients = split (/[,;]/, %variables->{recipients}->{value});
  my $jabber_server  = %variables->{jabber_server}->{value};
  my $user      = %variables->{user}->{value};
  my $passwd    = %variables->{passwd}->{value};

  # Design email content
  my $subject = "Lithium: ";
  $subject .= " " . %action->{device};
  $subject .= " at " . %action->{site};
  $subject .= " " . %action->{container};
  $subject .= " " . %action->{object};
  $subject .= " " . %action->{metric};
  $subject .= " " . %action->{trigger};
  my $content = "This is an automated incident report from Lithium.\n\n";
  $content .= ctime(%action->{start_time});
  $content .= "\nThe value of the " . %action->{metric};
  $content .= " metric for " . %action->{container} . " ";
  $content .= %action->{object} . " on device " . %action->{device} . " at " . %action->{site};
  $content .= " exceeded the pre-defined " . %action->{trigger} . " trigger.\n\n";
  $content .= "Incident ID:   " . %action->{incident_id} . "\n";
  $content .= "Site:          " . %action->{site} . "\n";
  $content .= "Device:        " . %action->{device} . "\n";
  $content .= "Container:     " . %action->{container} . "\n";
  $content .= "Object:        " . %action->{object} . "\n";
  $content .= "Metric:        " . %action->{metric} . "\n";
  $content .= "Trigger:       " . %action->{trigger} . "\n\n";
  
  if (%action->{state} eq "0") { $content .= "Current State: Normal\n\n" };
  if (%action->{state} eq "1") { $content .= "Current State: Warning\n\n" };
  if (%action->{state} eq "2") { $content .= "Current State: Impaired\n\n" };
  if (%action->{state} eq "3") { $content .= "Current State: Critical\n\n" };
  
  $content .= "Start Time:    " . ctime(%action->{start_time}) . "\n";
  if (%action->{end_time} != 0) { $content .= "End Time:      " . ctime(%action->{end_time}) . "\n\n"; }

  # Send the message via Jabber
  my $connection = setupJabberConnection($jabber_server, $user, $passwd);
  foreach ( @recipients ) {
      my $message = Net::Jabber::Message->new();
      $message->SetMessage( "to"           => $_,
			    "subject"      => "Lithium Notification",
			    "type"         => "chat",
			    "body"         => $content);
      
      $connection->Send($message);
      sleep(2);
  }
  $connection->Disconnect();

  print "initial message sent to ",join(", ",@recipients),".\n";
}

############################################
# Handling of an incident reminder (re-run)
############################################

sub remindIncident
{
  # 1 Parameter: Filename for the XML
  
  my ($filename) = @_;

  # Retrieve action from ARGV 
  %action = &getAction();
  
  # Extract Variables from XML and store in %variables Hash
  %variables = &getVariables($filename);
   
  # Set variables from XML
  my @recipients = split (/[,;]/, %variables->{recipients}->{value});
  my $jabber_server  = %variables->{jabber_server}->{value};
  my $user      = %variables->{user}->{value};
  my $passwd    = %variables->{passwd}->{value};

  # Design email content
  my $content = "This is an automated reminder of an existing incident from Lithium.\n\n";
  $content .= ctime(%action->{start_time});
  $content .= "\nThe value of the " . %action->{metric};
  $content .= " metric for " . %action->{container};
  $content .= %action->{object} . " on device " . %action->{device} . " at " . %action->{site};
  $content .= " exceeded the pre-defined " . %action->{trigger} . " trigger.\n\n";
  $content .= "Incident ID:   " . %action->{incident_id} . "\n";
  $content .= "Site:          " . %action->{site} . "\n";
  $content .= "Device:        " . %action->{device} . "\n";
  $content .= "Container:     " . %action->{container} . "\n";
  $content .= "Object:        " . %action->{object} . "\n";
  $content .= "Metric:        " . %action->{metric} . "\n";
  $content .= "Trigger:       " . %action->{trigger} . "\n\n";
  
  if (%action->{state} eq "0") { $content .= "Current State: Normal\n\n" };
  if (%action->{state} eq "1") { $content .= "Current State: Warning\n\n" };
  if (%action->{state} eq "2") { $content .= "Current State: Impaired\n\n" };
  if (%action->{state} eq "3") { $content .= "Current State: Critical\n\n" };
  
  $content .= "Start Time:    " . ctime(%action->{start_time}) . "\n";
  if (%action->{end_time} != 0) { $content .= "End Time:      " . ctime(%action->{end_time}) . "\n\n"; }

  # Send the message via Jabber
  # Send the message via Jabber
  my $connection = setupJabberConnection($jabber_server, $user, $passwd);
  foreach ( @recipients ) {
      my $message = Net::Jabber::Message->new();
      $message->SetMessage( "to"           => $_,
			    "subject"      => "Lithium Notification",
			    "type"         => "chat",
			    "body"         => $content);
      
      $connection->Send($message);
      sleep(2);
  }
  $connection->Disconnect();  

  print "reminder message sent to ",join(", ",@recipients),".\n";
}

###########################################
# Handling of incident cleared
###########################################

sub clearIncident
{
  # 1 Parameter: Filename for the XML
  
  my ($filename) = @_;

  # Retrieve action from ARGV 
  %action = &getAction();
  
  # Extract Variables from XML and store in %variables Hash
  %variables = &getVariables($filename);
   
  # Set variables from XML
  my @recipients = split (/[,;]/, %variables->{recipients}->{value});
  my $jabber_server  = %variables->{jabber_server}->{value};
  my $user      = %variables->{user}->{value};
  my $passwd    = %variables->{passwd}->{value};

  # Design email content
  my $content = "This is an automated incident cleared/resolved report from Lithium.\n\n";
  $content .= ctime(%action->{end_time});
  $content .= "\nThe value of the " . %action->{metric};
  $content .= " metric for " . %action->{container};
  $content .= %action->{object} . " on device " . %action->{device} . " at " . %action->{site};
  $content .= " is no longer within the pre-defined " . %action->{trigger} . " trigger range.\n\n";
  $content .= "Incident ID:   " . %action->{incident_id} . "\n";
  $content .= "Site:          " . %action->{site} . "\n";
  $content .= "Device:        " . %action->{device} . "\n";
  $content .= "Container:     " . %action->{container} . "\n";
  $content .= "Object:        " . %action->{object} . "\n";
  $content .= "Metric:        " . %action->{metric} . "\n";
  $content .= "Trigger:       " . %action->{trigger} . "\n\n";
  
  $content .= "Start Time:    " . ctime(%action->{start_time}) . "\n";
  if (%action->{end_time} != 0) { $content .= "End Time:      " . ctime(%action->{end_time}) . "\n\n"; }

  # Send the message via Jabber
  my $connection = setupJabberConnection($jabber_server, $user, $passwd);
  foreach ( @recipients ) {
      my $message = Net::Jabber::Message->new();
      $message->SetMessage( "to"           => $_,
			    "subject"      => "Lithium Notification",
			    "type"         => "chat",
			    "body"         => $content);
      
      $connection->Send($message);
      sleep(2);
  }
  $connection->Disconnect();

  print "cleared/resolved message sent to ",join(", ",@recipients),".\n";
}

###########################################
# Standard Functions
###########################################

sub generateConfig 
{
  # Create the XML Config file. 
  # You don't have to make changes to this sub.
  # To make changes to this XML Structure:
  #   Modify %xmlstruct at the begining of this file

  # Parameter 1: Temporary XML File
  my ($xmlrool) = $_[0];
  my (%struct) = %{$_[1]};
  
  my $xml = new XML::Simple(NoAttr=>1, RootName=>"action_script",XMLDecl=>1);
  $data = $xml->XMLout(\%struct);
  return "$data";
}

sub getVariables 
{
  # Parameter: Filename for the XML
  my ($filename) = @_;

  # ------>Collect XML Info Here <----------
  my $xml = new XML::Simple; # create new XML object
  my $data = $xml->XMLin($filename);
  my %variables =%{$data->{variable}};
  return %variables;
}

sub getAction
{
  my %action = ( incident_id => $ARGV[1],
                 entity_address => $ARGV[2],
                 state => $ARGV[3],
                 customer => $ARGV[4],
                 site => $ARGV[5],
                 device => $ARGV[6],
                 container => $ARGV[7],
                 object => $ARGV[8],
                 metric => $ARGV[9],
                 trigger => $ARGV[10],
                 run_count => $ARGV[11],
                 start_time => $ARGV[12],
                 end_time => $ARGV[13]
               );
  return %action;
}

sub setupJabberConnection
{
    my ($jabber_server, $user, $passwd) = @_;

    my $connection = Net::Jabber::Client->new();
    $connection->Connect( "hostname" => $jabber_server,
			  "port"     => 5222,
			  "tls"	     => 1 )
	or die "Cannot connect to Jabber server: $!\n";
    #
    # if using the OpenFire Jabber server, replace AuthSend with AuthIQAuth below
    # see http://www.igniterealtime.org/community/message/111378#111378
    #
    my @result = $connection->AuthSend( "username" => $user,
					"password" => $passwd,
					"resource" => "Lithium" );
    if ($result[0] ne "ok") {
	die "Ident/Auth with Jabber server failed: $result[0] - $result[1]\n";
    }
    return $connection;
}
