#!/usr/local/bin/perl

# Trap Handler for Net-SNMP to handle EXTREME NETWORKS Traps
# (c) 2002 Ben Rockwood - HOMESTEAD INC
# v0.6 - Thu Dec 12 12:20:16 PST 2002

#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

# Festival Loader
use Festival::Client; #Comment out this line if you do not want festival functionality
$SPEAK = "yes";	#Change to "no" to turn festival functionality off.
 

$COMMUNITY = "public";		# Community String to do simple SNMP get's
$MIB = "/home/benr/extreme/extreme620.mib";	# Location of the Extreme MIB
$SNMPGETCMD = "/usr/local/bin/snmpget";		# Location of the SNMPGET binary
my $TRAP_FILE = "/var/snmp/traps.all.log";		# File to log ALL traps to
my $TRAP_LOG = "/var/snmp/traps.handled.log";		# File to log handled and formated traps to

$ADMIN_ADDR = '123@skytel.com,456@skytel.com,me@me.com';	# Address to send mail to
$SENDMAIL = "/usr/lib/sendmail";					# Location of the sendmail binary


### Generic Handler ############################################################

my $host = <STDIN>;	# Read the Hostname - First line of input from STDIN
chomp($host);
my $ip = <STDIN>;	# Read the IP - Second line of input
chomp($ip);

my $OID = $ARGV[0];

while(<STDIN>) {
	chomp($_);
	push(@vars,$_);
}


### Default Handler ################################################################################


open(TRAPFILE, ">> $TRAP_FILE");
$date = `date`;
chomp($date);
print(TRAPFILE "New trap recieved: $date for $OID\n\nHOST: $host\nIP: $ip\n");
foreach(@vars) {
	print(TRAPFILE "TRAP: $_\n");
}
print(TRAPFILE "\n\n----------\n");
close(TRAPFILE);

###################################################################################################

## Convence routine:
$SNMPGET = "$SNMPGETCMD -v1 -c $COMMUNITY $host -m $MIB -Oqv";
##


### Handler for State Changes ######################################################################
if ($OID eq "statechange") {
	foreach(@vars){
		if($_ =~ /^EXTREME-SYSTEM-MIB::extremeSlotNumber/){
			$slotnum = $_;
			$slotnum =~ s/.+\s+(.+)/$1/;
		}
		if($_ =~ /^EXTREME-SYSTEM-MIB::extremeSlotModuleInsertedType/){
			$insertedtype = $_;
			$insertedtype =~ s/.+\s+(.+)/$1/;
		}
		if($_ =~ /^EXTREME-SYSTEM-MIB::extremeSlotModuleConfiguredType/){
			$configedtype = $_;
			$configedtype =~ s/.+\s+(.+)/$1/;
		}
		if($_ =~ /^EXTREME-SYSTEM-MIB::extremeSlotModuleState/){
			$modstate = $_;
			$modstate =~ s/.+\s+(.+)/$1/;
		}
		if($_ =~ /^SNMPv2-SMI::snmpModules.18.1.4.0/){
			$commname = $_;
			$commname =~ s/.+\s+\"(.+)\"/$1/;
		}	
	}

	# Make a best guess at what the module in question is, without answering none.
	# Inserted type is prefered, as it's more current than the configed type.
	if($insertedtype eq "none") {
		$modtype = $configedtype; 
		} elsif($configedtype eq "none") {
		$modtype = $insertedtype;
		} else {
		$modtype = $insertedtype;
	}

	# Change slots 9 and 10 to match A and B
	if($slotnum == "9"){
		$realslot = "A";
		} elsif($slotnum == "10") {
		$realslot = "B";
		} else {
		$realslot = $slotnum;
	}

	$MESSAGE = "$date: A statechange for $host has occured: Module $modtype in slot $realslot changed state to $modstate\n";
	#&__send_mail();
	
	open(CLEANFILE, ">> $TRAP_LOG");
	 print(CLEANFILE "$MESSAGE");
		if($modstate eq "operational"){
			$new_sn = `$SNMPGET EXTREME-SYSTEM-MIB::extremeSlotModuleSerialNumber.$slotnum`;
			chomp($new_sn);
			print(CLEANFILE "$date: New $modtype module in slot $realslot has serial number: $new_sn\n");
		}
			
	close(CLEANFILE);

        $SAY = "$HOST has registered a state change ... Slot ... $realslot ... Module ... $modtype ... State ... $modstate\n";
        &__speak();
  

#} else {
#	open(CLEANFILE, ">> $TRAP_LOG");
#	 print(CLEANFILE "$date: A trap of type \"$OID\" has occured.\n");
#	close(CLEANFILE);
}
##############################################################################


#        extremeHealthCheckFailed NOTIFICATION-TYPE
#                OBJECTS {
#                     sysDescr,
#                         extremeSlotNumber,
#                         extremeHealthCheckErrorType,
#                         extremeHealthCheckAction,
#                         extremeHealthCheckMaxRetries
#                        }
#                STATUS current
#                DESCRIPTION
#                "Cpu HealthCheck has failed."
#                ::= { extremeCoreSCTrapPrefix 1 }


### Handle healthcheck (.1.3.6.1.4.1.1916.4.1.0.1 v2) ########################
if ($OID eq "healthcheck") {
	foreach(@vars){
		if($_ =~ /^EXTREME-SYSTEM-MIB::extremeSlotNumber/){
			$slotnum = $_;
                        $slotnum =~ s/.+\s+(.+)/$1/;
		}	
		if($_ =~ /^EXTREME-SYSTEM-MIB::extremeHealthCheckErrorType/){
			$errortype = $_;
			$errortype =~ s/.+\s+(.+)/$1/;
		}
		if($_ =~ /^EXTREME-SYSTEM-MIB::extremeHealthCheckAction/){
			$action = $_;
			$action =~ s/.+\s+(.+)/$1/;
		}
		if($_ =~ /^EXTREME-SYSTEM-MIB::extremeHealthCheckMaxRetries/){
			$checkretry = $_;
			$checkretry =~ s/.+\s+(.+)/$1/;
		}
	}

        # Change slots 9 and 10 to match A and B
        if($slotnum == "9"){
                $realslot = "A";
                } elsif($slotnum == "10") {
                $realslot = "B";
                } else {
                $realslot = $slotnum;
        }

	$MESSAGE = "$date: HEALTH CHECK FAILURE FOR $host ON SLOT $realslot: TYPE: $errortype ACTION: $action MAX RESETS: $checkretry\n";
	#&__send_mail();

	open(CLEANFILE, ">> $TRAP_LOG");
         print(CLEANFILE "$MESSAGE");
	close(CLEANFILE);

        $SAY = "$HOST has failed a health check on slot $realslot ... Error type is ... $errortype ... with an action of $action\n";
        &__speak();
	
}	

##############################################################################
## Handlers for un-specified traps

foreach(@vars){
	if($_ =~ /^SNMPv2-MIB::snmpTrapOID.0/){
		$TRAP_TYPE = $_;
		$TRAP_TYPE =~ s/.+\s+(.+)/$1/;
	}
}


############################################################################
## Port status change 

if($TRAP_TYPE eq "IF-MIB::linkUp" || $TRAP_TYPE eq "IF-MIB::linkDown"){
	foreach(@vars){
		if($_ =~ /^RFC1213-MIB::ifIndex/){
			$IF_INDEX = $_;
			$IF_INDEX =~ s/.+\s+(.+)/$1/;
		}
		if($_ =~ /^RFC1213-MIB::ifAdminStatus/){
			$ADMIN_STATUS = $_;
			$ADMIN_STATUS =~ s/.+\s+(.+)/$1/;
		}
		if($_ =~ /^RFC1213-MIB::ifOperStatus/){
			$OPER_STATUS = $_;
			$OPER_STATUS =~ s/.+\s+(.+)/$1/;
		}
	}	

	$SLOT = int($IF_INDEX / 1000);
	$PORT = $IF_INDEX % 1000;

	#($SLOT,$PORT) = split(/??/, $IF_INDEX);

	## NOTE: I need a better message that more descriptive but in one work for both statuses.
        $MESSAGE = "$date: Port Change on $host: PORT $SLOT/$PORT STATE: $ADMIN_STATUS HOST: $OPER_STATUS \n"; 
        #&__send_mail();	## DON'T UNCOMMENT THIS UNLESS YOU WANNA GO CRAZY!

        open(CLEANFILE, ">> $TRAP_LOG");
         print(CLEANFILE "$MESSAGE");
        close(CLEANFILE);

	$ADMIN_STATUS =~ s/up/online/;
	$ADMIN_STATUS =~ s/down/offline/;
	$OPER_STATUS =~ s/up/online/;
	$OPER_STATUS =~ s/down/offline/;

        $SAY = "A port change has occured on $host.  Slot $SLOT, port $PORT ...  registered state is ... $ADMIN_STATUS ... and link status is ... $OPER_STATUS\n";
        &__speak();

	
}
		



##############################################################################
## Subroutine: Send Mail
sub __send_mail {

        #print("DEBUGGING: I am sending the message: $MESSAGE");   #DEBUGGING

        ##NOTE: To send a message it must have a line return, and not contain any ":"s
        $MESSAGE =~ s/:/\./g;

        if ($MESSAGE) {
                open(SENDMAIL, "|$SENDMAIL $ADMIN_ADDR") || die "Cannot open $SENDMAIL: $!";
                 print SENDMAIL $MESSAGE;
                close(SENDMAIL);
         } else {
                print("Error: You are try to send a message without any text! \n");
        }

}

##############################################################################
## Subroutine: Speak -> Requires Festival Module and Festival Server
sub __speak {

	if($SPEAK eq "yes"){
		print("Saying: $SAY\n");
		my $Festival = Festival::Client->new("localhost");
		$Festival->say("$SAY");
	}
}

  ####   #    #  #####   #####   #       ######   #####  ######   ####   #    #
 #    #  #    #  #    #  #    #  #       #          #    #       #    #  #    #
 #       #    #  #    #  #    #  #       #####      #    #####   #       ######
 #       #    #  #    #  #    #  #       #          #    #       #       #    #
 #    #  #    #  #    #  #    #  #       #          #    #       #    #  #    #
  ####    ####   #####   #####   ######  ######     #    ######   ####   #    #


