#!/usr/bin/perl
#
# SNMPTT v0.9
#
# Copyright 2002 Alex Burger
# alex_b@users.sourceforge.net
# 4/11/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
# (at your option) 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
#
##############################################################################
#
# http://www.sourceforge.net/projects/snmptt
#
# This script is a snmp trap handler for use with the NET-SNMP / UCD-SNMP 
# snmptrapd program.
#
# The script is called by defining a 'traphandle' in snmptrapd.conf.  
# For example:
#
# traphandle default /sbin/snmptt
# 
# SNMPTRAPD feeds details about the trap to the launched program's standard
# input in the following format (see snmptrapd.conf man page for a complete
# descriptipon)
#
# HOSTNAME: 	The name of the host in question  that  sent the  trap
# IPADDRESS: 	The IP address of the  host  that  sent  the trap
# VARBINDS: 	A  list  of  variable bindings that describe the trap and 
# 		the variables enclosed  in  it.  
#
# See the SNMPTT documentation (readme.html) for more information.
#
##############################################################################
#

$snmptt_version = "v0.9";

sub showversion
{
	print "\nSNMPTT $snmptt_version\n";
	print "(c) 2002 Alex Burger\n";
	print "http://snmptt.sourceforge.net\n\n";
}

##############################################################################
# Process command line arguments

use Getopt::Long;

$version = 0;
$daemon = 0;
$debug = 0;
$debugfile = '';
$dump = 0;
$help = 0;
$time = 0;
$ini = '';

GetOptions 	('version' => \$version, 
		'daemon' => \$daemon,
		'debug:i' => \$debug,
		'debugfile=s' => \$debugfile,
		'dump' => \$dump,
		'help' => \$help,
		'ini=s' => \$ini,
		'time' => \$time);  

if ($version == 1)
{
	&showversion;
	exit(0);
}

if ($help == 1)
{
$USAGE = qq/Usage:
    snmptt [<options>] 
Options:
    --daemon                             Run as a daemon
    --debug=n                            Set debug level (1 or 2)
    --debugfile=filename                 Set debug output file
    --dump                               Dump (display) defined traps
    --help                               Display this message
    --ini=filename                       Set configuration file to load
    --version                            Display author and version information
    --time                               Use to see how long it takes to load and 
                                         process trap file (eg: time snmptt --time)
/;
		
	&showversion;
	print $USAGE;

	exit(0);
}

if ($debug >= 1)
{
  $DEBUGGING = $debug;	
  $debugcmdline = 1;
}
else
{
  $DEBUGGING = 0;	
  $debugcmdline = 0;
}

if ($daemon == 1)
{
  	# $daemon = 1;	
	$daemoncmdline = 1;
}
else
{
 	$daemoncmdline = 0;
}

if ($dump ==1)
{
	$DEBUGGING = 2;
	$debugcmdline = 1;
	&findsnmpttini;
	&loadsnmpttini;
	&loadsnmpttconf;		# Load SNMPTT.CONF file
	print ("\n\n");
	exit(0);
}

if ($time ==1)
{
	&findsnmpttini;
	&loadsnmpttini;
	&loadsnmpttconf;		# Load SNMPTT.CONF file
	exit(0);
}

if ($debugfile ne '') 
{
	$DEBUGGING_FILE = $debugfile;	# commandline overpowers snmptt script
	$debugfilecmdline = 1;
}
else
{
  $debugfilecmdline = 0;
}

##############################################################################
#
# Load config file 
#

&findsnmpttini;
&loadsnmpttini;
		
##############################################################################

use Text::ParseWords;
use POSIX qw(strftime);

if ($syslog_enable == 1 || $syslog_system_enable == 1)
{
	require Sys::Syslog;
}

if ($eventlog_system_enable == 1 || $eventlog_enable == 1)
{
	require Win32::EventLog;
	
	# Constants not available when using 'require' (!)
	$eventlog_error = 1;		# EVENTLOG_ERROR_TYPE
	$eventlog_warning = 2;		# EVENTLOG_WARNING_TYPE
	$eventlog_information = 4;	# EVENTLOG_INFORMATION_TYPE
}

$debug_file_used = 0;
if ($DEBUGGING >= 1)
{
	if ($DEBUGGING_FILE ne '') 
	{
	  if (open DEBUGFILE, ">>$DEBUGGING_FILE")
	  {
	    select DEBUGFILE;	# change default output to debug file
	    $debug_file_used = 1;
	  }
	  else
	  {
	    warn "could not open debug output file ($!)";
	  }
	}
	
	# print out time
	print "********** SNMPTT $snmptt_version started: ",scalar(localtime)," **********\n\n"
}

if ($syslog_system_enable == 1 && $daemon == 1)
{
  syslog_system("SNMPTT $snmptt_version started");
}

if ($eventlog_system_enable == 1 && $daemon == 1)
{
  eventlog_system("SNMPTT $snmptt_version started",0,$eventlog_information);
}

if ($net_snmp_perl_enable == 1)
{
	require SNMP;
	if (defined ($mibs_environment))
	{
	  $ENV{'MIBS'} = $mibs_environment;
	}
	my $noperlwarning;
	&SNMP::initMib();

	$SNMP::best_guess = $net_snmp_perl_best_guess;
	$noperlwarning = $SNMP::best_guess;  # Just to get rid of the Perl warning that var used only once

	$SNMP::use_long_names = 0;	# Set to 0, otherwise getType may fail when using a long name on 4.2.x
	$noperlwarning = $SNMP::use_long_names;  # Just to get rid of the Perl warning that var used only once

	if ($DEBUGGING >= 1)
	{
	  print "********** Net-SNMP version $SNMP::VERSION Perl module enabled **********\n\n";
	  if (defined ($mibs_environment))
	  {
	    print "********** MIBS: $mibs_environment **********\n\n";
	  }
	}
}

if ($dns_enable == 1)
{
  require Socket;
  if ($DEBUGGING >= 1)
  {
    print "********** DNS enabled **********\n\n";
  }
}

if ($mysql_dbi_enable == 1)
{
	require DBI;
	require DBD::mysql;
	
	unless ($dbh_mysql = DBI->connect("DBI:mysql:database=$mysql_dbi_database;host=$mysql_dbi_host;
                port=$mysql_dbi_port",$mysql_dbi_username,$mysql_dbi_password) )
	{
	  warn "MySQL error: Unable to connect to database: $DBI::errstr\n";
	  if ($syslog_system_enable == 1)
	  {
	    syslog_system("MySQL error: Unable to connect to database: $DBI::errstr");
	  }
	  if ($eventlog_system_enable == 1)
	  {
	    eventlog_system("MySQL error: Unable to connect to database: $DBI::errstr",12,$eventlog_error);
	  }
	}
}

if ($postgresql_dbi_enable == 1)
{
	require DBI;
	my $dbi_module;
	my $connect_string;
	
	if ($postgresql_dbi_module == 0)
	{
	  require DBD::PgPP;
	  $dbi_module = "PgPP";
	}
	else
	{
	  require DBD::Pg;
	  $dbi_module = "Pg";
	}

	if ($postgresql_dbi_hostport_enable == 0)
	{
	  # No network support
	  $connect_string = "DBI:$dbi_module:dbname=$postgresql_dbi_database;";
	}
	else
	{
	  # Network support - include host and port
	  $connect_string = "DBI:$dbi_module:dbname=$postgresql_dbi_database;host=$postgresql_dbi_host;port=$postgresql_dbi_port";
	}
	
	unless ($dbh_postgresql = DBI->connect($connect_string,$postgresql_dbi_username,$postgresql_dbi_password) )
        {
	  warn "Postgres error: Unable to connect to database: $DBI::errstr\n";
	  if ($syslog_system_enable == 1)
	  {
	    syslog_system("Postgres error: Unable to connect to database: $DBI::errstr");
  	  }
	  if ($eventlog_system_enable == 1)
	  {
	    eventlog_system("Postgres error: Unable to connect to database: $DBI::errstr",18,$eventlog_error);
	  }
 	}
}


if ($dbd_odbc_enable == 1)
{
	require DBI;
	
	unless ($dbh_odbc = DBI->connect("DBI:ODBC:$dbd_odbc_dsn",$dbd_odbc_username,$dbd_odbc_password) )
	{
	  warn "DBI DBD:ODBC error: Unable to connect to DSN: $DBI::errstr\n";
	  if ($syslog_system_enable == 1)
	  {
	    syslog_system("DBI DBD:ODBC error: Unable to connect to DSN: $DBI::errstr");
	  }
	  if ($eventlog_system_enable == 1)
	  {
	    eventlog_system("DBI DBD:ODBC error: Unable to connect to DSN: $DBI::errstr",12,$eventlog_error);
	  }
	}
}

if ($sql_win32_odbc_enable == 1)
{
	require Win32::ODBC;
	unless ($dbh_win32_odbc = new Win32::ODBC("DSN=$sql_win32_odbc_dsn","UID=$sql_win32_odbc_username","PWD=$sql_win32_odbc_password") )
	{
	  warn "SQL error: Unable to connect to DSN $sql_win32_odbc_dsn:" . Win32::ODBC::Error() . "\n";

	  if ($eventlog_system_enable == 1)
	  {
	    eventlog_system("SQL error: Unable to connect to DSN $sql_win32_odbc_dsn:" . Win32::ODBC::Error(),13,$eventlog_error);
	  }
	}


}

##############################################################################
####  MAIN SECTION START

# Pull in passed SNMP info from snmptrapd via STDIN and place in the array @tempvar

if ($daemon == 1)
{
	$SIG{HUP} = \&signal_handler_reload;

	$SIG{TERM} = \&signal_handler_die;
	
	$timetoreload = 0;
	$timetodie = 0;

	&loadsnmpttconf;	# Load SNMPTT.CONF file

        # Only fork to the background if not Win32
	if (($^O ne "MSWin32") && ($daemon_fork==1))
	{
	        use POSIX qw(setsid);
		use Cwd;

		my $working_dir = cwd;
		print "cwd: $working_dir\n";
	
		chdir '/'
		   or die "Can't chdir to /: $!";
		open STDIN, '/dev/null'
		   or die "Can't read /dev/null: $!";
		open STDOUT, '>>/dev/null'
		   or die "Can't write to /dev/null: $!";
		open STDERR, '>>/dev/null'
		   or die "Can't write to /dev/null: $!";
		defined(my $pid = fork)
		   or die "Can't fork: $!";

		if ($pid)
		{		  
	 	  if ( ! (open(PID, ">/var/run/snmptt.pid") ))
  		  {
  		    open(PID, ">$working_dir/snmptt.pid");
  		  }
		  
		  if (defined (PID))
  		  {
  		    print(PID "$pid\n");
  		    close(PID);
  		  }
		  exit;
		}

		POSIX:setsid
		   or die "Can't start a new session: $!";
		umask 0;
	}

	# Change user if not Windows, and daemon_uid ini parameter not blank
	if ($^O ne "MSWin32" && $daemon_uid ne '')
	{
	  my $daemon_uid_name = '';
	  
	  if ($daemon_uid =~ /\D/)
	  {
	    # no numbers found, so assume it's a textual name
	    
	    $daemon_uid_name = $daemon_uid;
	    
	    $daemon_uid = getpwnam($daemon_uid_name);
	    if (!defined($daemon_uid))
	    {
	      syslog_system("Could not convert user id \'$daemon_uid_name\' to a numeric UID\n");
	    }
	  }
	  
	  # Change current uid to new_uid
	  if (defined($daemon_uid))
	  {
	    if ($daemon_uid_name ne '')
	    {
	      syslog_system("Changing to UID: $daemon_uid_name \($daemon_uid\)");
	      if ($DEBUGGING >= 1)
	      {
		print "Changing to UID: $daemon_uid_name \($daemon_uid\)\n";
	      }
	    }
	    else
	    {
	      syslog_system("Changing to UID: $daemon_uid");
	      if ($DEBUGGING >= 1)
	      {
		print "Changing to UID: $daemon_uid\n";
	      }
	    }
	    
	    # Close debug file before changing users and re-open after
	    if (defined (DEBUGFILE))
	    {
	      close(DEBUGFILE);
	    }
	    
	    $> = $daemon_uid;
	    
	    # Re-open debug file (if needed) as the new user
	    if ($DEBUGGING >= 1)
	    {
	      if ($DEBUGGING_FILE ne '') 
	      {
		if (open DEBUGFILE, ">>$DEBUGGING_FILE")
		{
		  select DEBUGFILE;	# change default output to debug file
		  $debug_file_used = 1;
		}
		else
		{
		  warn "could not open debug output file ($!)";
		}
	      }
	    }
	  }
	}
	
	while (!$timetodie)
	{
		if (! (chdir($spool_directory)))
		{
		  if ($DEBUGGING >= 1)
		  {
		    print "Unable to enter spool dir $spool_directory:$!\n";
		  }
		  warn "Unable to enter spool dir $spool_directory:$!\n";
		  
		  if ($syslog_system_enable == 1)
		  {
		    syslog_system("Unable to enter spool dir $spool_directory");
		  }
		  if ($eventlog_system_enable == 1)
		  {
		    eventlog_system("Unable to enter spool dir $spool_directory",3,$eventlog_error);
		  }
		}
		elsif (! (opendir(DIR, ".")))
		{
		  if ($DEBUGGING >= 1)
		  {
		    print "Unable to open $spool_directory:$!\n";
		  }
		  warn "Unable to open spool dir $spool_directory:$!\n";

		  if ($syslog_system_enable == 1)
		  {
		    syslog_system("Unable to open spool dir $spool_directory");
		  }
		  if ($eventlog_system_enable == 1)
		  {
		    eventlog_system("Unable to open spool dir $spool_directory",4,$eventlog_error);
		  }
		}
		elsif (! (@filenames = readdir(DIR)))
		{
		  if ($DEBUGGING >= 1)
		  {
		    print "Unable to read spool dir $spool_directory:$!\n";
		  }
		  warn "Unable to read spool dir $spool_directory:$!\n";

		  if ($syslog_system_enable == 1)
		  {
		    syslog_system("Unable to read spool dir $spool_directory");
		  }
		  if ($eventlog_system_enable == 1)
		  {
		    eventlog_system("Unable to read spool dir $spool_directory",5,$eventlog_error);
		  }		  
		}
		else
		{
		  closedir(DIR);
		  
		  @filenames = sort (@filenames);		# Sort list of filenames to ensure they
		  						# are processed in the order they were
		  						# received
		  
		  foreach my $file (@filenames)
		  {
		    next if ($file eq ".");
		    next if ($file eq "..");

		    if (lc($file) eq "!reload")
		    {
		      $timetoreload = 1;
		      unless (unlink($file))		      
		      {
			if ($DEBUGGING >= 1)
			{
			  print "Unable to delete !reload file from spool dir:$!\n";
			}
			warn "Unable to delete !reload file from spool dir:$!\n";
			
			if ($syslog_system_enable == 1)
			{
			  syslog_system("Unable to delete !reload file from spool dir");
			}
			if ($eventlog_system_enable == 1)
			{
			  eventlog_system("Unable to delete !reload file from spool dir",20,$eventlog_error);
			}
		      }
		      next;
		    }

		    if ($DEBUGGING >= 1)
		    {
		      print "Processing file: $file\n";
		    }
		    
		    $filesuccess = 1;
		    unless (open FILE, $spool_directory.$file)
		    {
		      if ($DEBUGGING >= 1)
		      {
			print "Could not open trap file $spool_directory$file: ($!)\n";
		      }
		      warn "Could not open trap file $spool_directory$file: ($!)\n";
		      
		      if ($syslog_system_enable == 1)
		      {
			syslog_system("Could not open trap file $spool_directory$file");
		      }
		      if ($eventlog_system_enable == 1)
		      {
			eventlog_system("Could not open trap file $spool_directory$file",6,$eventlog_error);
		      }
		      
		      $filesuccess = 0;
		    }
		    
		    $input = 'FILE';
		    		
		    &readtrap;			# Read trap from STDIN or file
		    
		    &searchfortrap;		# Search for trap snmptt.conf (array)
		    
		    close FILE;
		    
		    if ($filesuccess == 1)
		    {
		      if ($keep_unlogged_traps == 0 || $trap_successfully_logged == 1)
		      {
			unless (unlink($file))
			{
			  if ($DEBUGGING >= 1)
			  {
			    print "Unable to delete trap file $file from spool dir:$!\n";
			  }
			  warn "Unable to delete trap file $file from spool dir:$!\n";
			  
			  if ($syslog_system_enable == 1)
			  {
			    syslog_system("Unable to delete trap file $file from spool dir");
			  }
			  if ($eventlog_system_enable == 1)
			  {
			    eventlog_system("Unable to delete trap file $file from spool dir",7,$eventlog_error);
			  }
			}
		      }
		    }
		  }
		}
		if ($DEBUGGING >= 1)
		{
			print "Sleeping for $sleep seconds\n\n";
		}
		sleep $sleep;

		if ($timetoreload == 1)
		{
			if ($DEBUGGING >= 1)
			{
				print "Reloading configuration file\(s\)\n\n";
			}
			
			if ($syslog_system_enable == 1)
			{
			  syslog_system("Reloading configuration file\(s\)");
			}
			if ($eventlog_system_enable == 1)
			{
			  eventlog_system("Reloading configuration file\(s\)",8,$eventlog_information);
			}

			&loadsnmpttini;		# Load ini file
			&loadsnmpttconf;	# Load SNMPTT.CONF file
			$timetoreload = 0;
		}
	}
	if ($DEBUGGING >= 1)
	{
		print "SNMPTT $snmptt_version shutdown: ",scalar(localtime),"\n\n"
	}
	
	if ($syslog_system_enable == 1 &&  $daemon == 1)
	{
	  syslog_system("SNMPTT $snmptt_version shutdown");
	}
	if ($eventlog_system_enable == 1 &&  $daemon == 1)
	{
	  eventlog_system("SNMPTT $snmptt_version shutdown",1,$eventlog_information);
	}
}
else
{
	$input = 'STDIN';
	
	&readtrap;		# Read trap from STDIN or file

	&loadsnmpttconf;	# Load SNMPTT.CONF file

	&searchfortrap;		# Search for trap snmptt.conf (array)
}

if (defined $dbh_mysql)
{
	$dbh_mysql->disconnect;
}
if (defined $dbh_postgresql)
{
	$dbh_postgresql->disconnect;
}

if (defined $dbh_odbc)
{
	$dbh_odbc->disconnect;
}
if (defined $dbh_win32_odbc)
{
	$dbh_win32_odbc->Close();
}

exit();

####  MAIN SECTION END

sub processtrap
{
	# Variables of trap received by SNMPTRAPD:
	# 
	# $var[0]		hostname
	# $var[1] 		ip address
	# $var[2] 		uptime
	# $var[3] 		trapname / OID
	# $var[4] 		ip address from trap agent
	# $var[5] 		trap community string
	# $var[6] 		enterprise
	#
	# $entvarname[0]	passed variable name 1
	# $entvarname[1]	passed variable name 2
	#
	# $entvar[0]		passed variable 1
	# $entvar[1]		passed variable 2
	# .
	# .
	# etc..
	# 
	# $event hash for each trapped defined in snmptt.conf with following values:
	# 
	# 0: name of trap
	# 1: category
	# 2: severity
	# 3: FORMAT string
	# 4: EXEC string
	# 5: NODES string
	# 6: REGEX array
	# 7: MATCH array
	#
	# Example: 	To access FORMAT string for received trap:
	# 		$event{"$var[3]"}[3]
	#
	#		or
	# 		
	# 		$event{"$receivedtrap_entry"}[3]	
	###############################################################################
	# if no nodes list, then $hostmatch = 1 so trap is logged etc, otherwise it is not

	$l = 1;	# Start with first event entry

	$multiple_event_passes = 0;	# Below, if =1, then abort because we already found a match for
					# this trap.  This would only happen if you have a trap
					# defined multiple times in the config file to allow 
					# different machines to have different actions based on 
					# the node name.
	
	while (defined($event{$receivedtrap_entry}[$l+1]))
	{
	  if (($multiple_event == 0) && ($multiple_event_passes > 0))
	  {
	    if ($DEBUGGING >= 1)
	    {
	      print "  multiple_event = $multiple_event, multiple_event_passes = " .
	            "$multiple_event_passes so don't process any more entries\n";
            }
	    last;	# Don't look any further - stop
	  }
	  if ($DEBUGGING >= 1)
		{
			print  "Working with EVENT entry: $receivedtrap_entry => $event{$receivedtrap_entry}[0+$l],$event{$receivedtrap_entry}[1+$l],$event{$receivedtrap_entry}[2+$l],$event{$receivedtrap_entry}[5+$l]\n";
		}
		
		$hostmatch = 0;
		$nodesmatch = 0;	# Match from NODES
		my $match_found = 0;	# Match from MATCH
	
		# $event is the hash of events defined in the config file
		# $event2 is a copy of the matching event
	
		# Flush out @event2
		@event2 = ();
		
		# Flush out @nodes
		#@nodes = ();
		@nodes2 = ();
	
		#	$event2[0]=$event{"$receivedtrap_entry"}[0];	# 0: name of trap	
		#	$event2[1]=$event{"$receivedtrap_entry"}[1];	# 1: category
		#	$event2[2]=$event{"$receivedtrap_entry"}[2];	# 2: severity
		#	$event2[3]=$event{"$receivedtrap_entry"}[3];	# 3: FORMAT string
		#	$event2[4]=$event{"$receivedtrap_entry"}[4];	# 4: EXEC string
		#	$event2[5]=$event{"$receivedtrap_entry"}[5];	# 5: NODES string
		
		$event2[0]=$event{"$receivedtrap_entry"}[0+$l];	# 0: name of trap	
		$event2[1]=$event{"$receivedtrap_entry"}[1+$l];	# 1: category
		$event2[2]=$event{"$receivedtrap_entry"}[2+$l];	# 2: severity
		$event2[3]=$event{"$receivedtrap_entry"}[3+$l];	# 3: FORMAT string
		$event2[4]=$event{"$receivedtrap_entry"}[4+$l];	# 4: EXEC string
		$event2[5]=$event{"$receivedtrap_entry"}[5+$l];	# 5: NODES string
		$event2[6]=$event{"$receivedtrap_entry"}[6+$l];	# 6: REGEX string		
		$event2[7]=$event{"$receivedtrap_entry"}[7+$l];	# 7: MATCH string		
		
		$l+=9;
			
		if ($event2[5] eq '')
		{
		  $nodesmatch = 1;
		  #$hostmatch = 1;		# No nodes defined, so default to all nodes
		  #$multiple_event_passes++;
		  #$processed = 1;
		  if ($DEBUGGING >= 1)
		  {
		    print "  No nodes defined for this entry so all nodes will match\n";
		  }
		}
		else
		{
			if ($DEBUGGING >= 1)
			{
			  print "  Nodes defined for this entry...\n";
			}	

			@nodes2 = &process_nodes($event2[5]);
			
			if ($DEBUGGING >= 1)
			{
			  print "  NODES entries: @nodes2\n";
			}

			foreach my $a (@nodes2)
			{	
				if ($a =~ /^(\d+\.\d+\.\d+\.\d+)/) # NODES entry is an IP address / cidr / range
				{
				  #if ( $a eq $var[1])     # compare against agent ip
				  if ( checkip($var[4], $a) == 1)
				  {				  
				    $nodesmatch = 1;
				    #$hostmatch = 1;
				    #$processed = 1;
				  }
				}
				elsif ($dns_enable == 1)	# Resolve NODES entry to IP address, and compare
				{
				  my $temp = gethostbyname($a);
				  if (defined($temp))
				  {
				    $temp = Socket::inet_ntoa(scalar($temp));
				    if ($DEBUGGING => 1)
				    {
				      print "    NODES entry ($a) resolved to: $temp\n";
				    }
				    if ( checkip($var[4], $temp) == 1)
				    {
				      $nodesmatch = 1;
				    }
				  }
				  else
				  {
				    print "    NODES entry ($a) could NOT be resolved.\n";
				  }
				}
	                        elsif (lc $a eq lc $agent_dns_name)	# NODES entry is a host name.  Do lowercase compare
				{
				  $nodesmatch = 1;
				  #$hostmatch = 1;
				  #$processed = 1;
				}
			}
			#if ($hostmatch == 1)
			if ($DEBUGGING >= 1)
			{			  
			  if ($nodesmatch == 1)
 			  {
			    print "  Node found in list\n";
			  }
			  else
			  {
			    print "  Node NOT found in list\n";
			  }
			}
		}

		# Check for MATCH entries
		if ($nodesmatch == 1 && defined($event2[7][0]))	# Only if NODES has matched and 
		{						# we have some MATCH statements
		  my @match = ();
		  my $match_type;
		  		  
		  for (my $i=0; defined($event2[7][$i]); $i++)
		  {
		    my $match_temp = $event2[7][$i];
		    $match_temp =~ s/\s//g;	# Remove any white space from $match
		    if ($match_temp =~ /^mode=(.*)/i)
		    {
		      $match_type = lc($1);
		      last;
		    }
		  }
		  if ($match_type ne 'and' && $match_type ne 'or')
		  {
		    $match_type = 'or';
		  }
		  if ($DEBUGGING >= 2)
		  {
		    print "  MATCH statements found\n";
		    print "    MATCH mode: " . uc($match_type) . "\n";
		  }
		  
		  for (my $i=0; defined($event2[7][$i]); $i++)
		  {
		    my $match_temp = $event2[7][$i];

                    # If it's a regex (has ()) then remove white space before and after ()s.  
		    # Otherwise, remove all white space
		    #print "!$match_temp!\n";
		    if ($match_temp =~ /\(|\)/)
		    {
			$match_temp =~ s/\s*(\(.*\))\s*/$1/g;	# Remove any white space from before and after ()'s

			$match_temp =~ s/\)\s*(\i)\s*/\)$1/g;	# Remove any white space from before and after i modifier
			                                        # if there is one
			
			$match_temp =~ s/\s*(\!.*)/$1/g;	# Remvoe any white space in front of the ! if there is one
		    }
		    else
		    {
		      $match_temp =~ s/\s//g;	# Remove any white space from $match
		    }
		    #print "!$match_temp!\n";
		    
		    # DEFAULT= line
		    if ($match_temp =~ /^mode=(.*)/i)
		    {
		      next;
		    }

		    if (match($match_temp) == 1)
		    {
		      $match_found = 1;
		      if ($match_type eq "or")
		      {
			last;
		      }
		    }
		    else
		    {
		      $match_found = 0;
		      if (lc($match_type) eq "and")
		      {
			last;
		      }
		    }
		  }
		  if ($DEBUGGING >= 1)
		  {
		    if ($match_found == 1)
		    {
		      print "  MATCH statement(s) final result = true...\n\n";
		    }
		    else 
		    {
		      print "  MATCH statement(s) final result = false...\n\n";
		    }
		  }
		}
		else
		{
		  if ($DEBUGGING >= 1)
		  {
		    print "  No MATCH entries defined for this entry\n";
		  }
		  $match_found = 1;	# Default to match_found if no MATCH entries
		}

		if ($nodesmatch == 1 && $match_found == 1)
		{
		  $multiple_event_passes++;
		  $hostmatch = 1;
		  $processed = 1;
		}
		
		if ($hostmatch == 1 && $event2[1] ne "IGNORE")
		{

			# Trap received exists in our list of trap definitions
			if ($DEBUGGING >= 1)
			{
				print "\nTrap defined, processing...\n\n";
				print "\n\nFORMAT line:\n";
			}
			
			# Variable substitution for FORMAT string
			
			$_ = $event2[3];	# FORMAT string
		
			$receivedtrap_trans = $receivedtrap;	# Default to numeric OID of received trap
	
			if ($net_snmp_perl_enable == 1 && $translate_log_trap_oid)
			{
			  # Try to convert to text
			  if ($DEBUGGING >= 2) {
			    print "\nOID of trap: $receivedtrap.  Will attempt to translate to text\n";
			  }
			  my $temp2 = my_translateObj("$receivedtrap",$translate_log_trap_oid);
			  if (defined ($temp2) ) {
			    if ($DEBUGGING >= 2) {
			      print "  Translated to $temp2\n";
			    }
			    $receivedtrap_trans = $temp2;
			  }
			  else {
			    # Could not translate default to numeric
			    if ($DEBUGGING >= 2) {
			      print "  Could not translate - defaulting to numeric\n";
			    }
			  }
			}
			
			$enterprise_trans = $var[6];	# Default to numeric enterprise
			if ($net_snmp_perl_enable == 1 && $var[6] ne '')
			{
			  if ($DEBUGGING >= 2) {
			    print "\nOID of enterprise: $var[6].  Will attempt to translate to text\n";
			  }
			  my $temp = my_translateObj("$var[6]",$translate_enterprise_oid_format);
			  if (defined ($temp) ) {
			    if ($DEBUGGING >= 2) {
			      print "  Translated to $temp\n";
			    }
			    $enterprise_trans = $temp;
			  }
			  else 
			  {
			    # Could not translate default to numeric
			    if ($DEBUGGING >= 2) {
			      print "  Could not translate - defaulting to numeric\n";
			    }
			  }
			}

			&substitute;
		
			$message_short = $_;
			
			$message = "$receivedtrap_trans $event2[2] \"$event2[1]\" $agent_dns_name - $message_short\n";
			
			if ($stdout_enable == 1)
			{
			  #select STDOUT;
			  print STDOUT "$message";

			  #if ($debug_file_used == 1)
			  #{
			  #  select DEBUGFILE;
			  #}
			}

			if ($DEBUGGING >= 1)
			{
				print "$message_short\n";
				print "\n$message";
			}
			
			if ($log_enable == 1)
			{
				$trap_attempted_to_log++;	
				
				if (open LOGFILE, ">>$log_file")
				{
					print LOGFILE $trap_date_time." $message";
					close LOGFILE;
					$trap_successfully_logged++;
				}
				else
				{
				  warn "Can not open log file $log_file: $!";

				  if ($syslog_system_enable == 1)
				  {
				    syslog_system("Can not open log file $log_file");
				  }

				  if ($eventlog_system_enable == 1)
				  {
				    eventlog_system("Can not open log file $log_file",14,$eventlog_information);
				  }
				}
			}
	
			if ($syslog_enable == 1)
			{
				$trap_attempted_to_log++;

				my $syslog_level_temp = 99;
				my $temp;
				
				foreach $temp (@syslog_level_debug)
				{
				  if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'debug' }
				}
				foreach $temp (@syslog_level_info)
				{
				  if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'info' }
				}
				foreach $temp (@syslog_level_notice)
				{
				  if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'notice' }
				}
				foreach $temp (@syslog_level_warning)
				{
				  if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'warning' }
				}
				foreach $temp (@syslog_level_err)
				{
				  if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'err' }
				}
				foreach $temp (@syslog_level_crit)
				{
				  if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'crit' }
				}
				foreach $temp (@syslog_level_alert)
				{
				  if (lc($event2[2]) eq lc($temp)) { $syslog_level_temp = 'alert' }
				}
				
				if ($syslog_level_temp == 99)
				{
				  $syslog_level_temp = $syslog_level;
				}

				#if (Sys::Syslog::openlog('TRAPD', '',$syslog_facility) )
				if (Sys::Syslog::openlog('snmptt[' . $> . ']', '',$syslog_facility) )
				{
					Sys::Syslog::syslog ($syslog_level_temp, $message,1);
					Sys::Syslog::closelog();
					$trap_successfully_logged++;
				}
				else
				{
					warn "Can not open log_file: $!";
				}
			}
			
			if ($eventlog_enable == 1)
			{
			  $trap_attempted_to_log++;
			  
			  my $eventlog_type_temp = 99;
			  my $temp;

			  foreach $temp (@eventlog_type_information)
			  {
			    if (lc($event2[2]) eq lc($temp)) { $eventlog_type_temp = $eventlog_information }
			  }

			  foreach $temp (@eventlog_type_warning)
			  {
			    if (lc($event2[2]) eq lc($temp)) { $eventlog_type_temp = $eventlog_warning }
			  }
			  
			  foreach $temp (@eventlog_type_error)
			  {
			    if (lc($event2[2]) eq lc($temp)) { $eventlog_type_temp = $eventlog_error }
			  }
			  
			  if ($eventlog_type_temp == 99)
			  # Use the default eventlog type
			  {
			    if ($eventlog_type =~ /INFORMATION/s)
			    {
			      if (eventlog_system($message,2,$eventlog_information) == 0)
			      {
				$trap_successfully_logged++;
			      }
			    }
			    elsif ($eventlog_type =~ /ERROR/s)
			    {
			      if (eventlog_system($message,2,$eventlog_error) == 0)
			      {
				$trap_successfully_logged++;
			      }
			    }
			    else
			    {
			      if (eventlog_system($message,2,$eventlog_warning) == 0)
			      {
				$trap_successfully_logged++;
			      }
			    }
			  }
			  else
			  {
			    if (eventlog_system($message,2,$eventlog_type_temp) == 0)
			    {
			      $trap_successfully_logged++;
			    }
			  }
			}

			if ($net_snmp_perl_enable == 1 && $db_translate_enterprise == 1)
			{
			  $db_enterprise = $enterprise_trans;
			}
			else
			{
			  $db_enterprise = $var[6];
			}

			if ($mysql_dbi_enable == 1 && defined ($dbh_mysql))
			{
				$trap_attempted_to_log++;	
				
				# Backslash any quotes
				my $message_short2 = $message_short;
				$message_short2 =~ s(\')(\\\')g;   #'
				$message_short2 =~ s(\")(\\\")g;   #"

				my $community = $var[5];
				$community =~ s(\')(\\\')g;   #'
				$community =~ s(\")(\\\")g;   #"				
				
				unless (defined ($dbh_mysql->do(
					"INSERT INTO $mysql_dbi_table (eventname, eventid, trapoid, enterprise, 
					community, hostname, agentip, category, severity, uptime, traptime, 
					formatline) VALUES (
					\'$event2[0]\',\'$receivedtrap_entry'\,\'$receivedtrap_trans'\,\'$db_enterprise\',
					\'$community\',\'$agent_dns_name\',\'$var[4]\',
					\'$event2[1]\',\'$event2[2]\',\'$var[2]\',\'".$trap_date_time."\',
					\'$message_short2\')" ) ) )
					{
					  warn "MySQL error: Unable to perform INSERT INTO: ".$dbh_mysql->errstr."\n";

					  if ($syslog_system_enable == 1)
					  {
					    syslog_system("MySQL error: Unable to perform INSERT INTO: ".$dbh_mysql->errstr);
					  }
					  
					  if ($eventlog_system_enable == 1)
					  {
					    eventlog_system("MySQL error: Unable to perform INSERT INTO: ".$dbh_mysql->errstr,
					    		15,$eventlog_error);
					  }
				 }
				 else
				 {
				   $trap_successfully_logged++;
				 }
			}

			if ($postgresql_dbi_enable == 1 && defined ($dbh_postgresql))
			{
				$trap_attempted_to_log++;	

				# Backslash any quotes
				my $message_short2 = $message_short;
				$message_short2 =~ s(\')(\\\')g;   #'
				$message_short2 =~ s(\")(\\\")g;   #"

				my $community = $var[5];
				$community =~ s(\')(\\\')g;   #'
				$community =~ s(\")(\\\")g;   #"
				
				unless (defined ($dbh_postgresql->do(
					"INSERT INTO $postgresql_dbi_table (eventname, eventid, trapoid, enterprise, 
					community, hostname, agentip, category, severity, uptime, traptime, 
					formatline) VALUES (
					\'$event2[0]\',\'$receivedtrap_entry'\,\'$receivedtrap_trans'\,
					\'$db_enterprise\',\'$community\',\'$agent_dns_name\',\'$var[4]\',
					\'$event2[1]\',\'$event2[2]\',\'$var[2]\',\'".$trap_date_time."\',
					\'$message_short2\')" ) ) )
					{
					  warn "Postgres error: Unable to perform INSERT INTO: ".$dbh_postgresql->errstr."\n";

					  if ($syslog_system_enable == 1)
					  {
					    syslog_system("Postgres error: Unable to perform INSERT INTO: ".$dbh_postgresql->errstr);
					  }
					  
					  if ($eventlog_system_enable == 1)
					  {
					    eventlog_system("Postgres error: Unable to perform INSERT INTO: ".$dbh_postgresql->errstr,
					    		19,$eventlog_error);
					  }
				 }
				 else
				 {
				   $trap_successfully_logged++;
				 }
			}
			
			if ($dbd_odbc_enable == 1 && defined ($dbh_odbc))
			{
				$trap_attempted_to_log++;

				# Double any single quotes
				my $message_short2 = $message_short;
				$message_short2 =~ s(\')('')g;     #'

				my $community = $var[5];
				$community =~ s(\')('')g;   #'
				
				unless (defined ($dbh_odbc->do(
					"INSERT INTO $dbd_odbc_table (eventname, eventid, trapoid, enterprise, 
					community, hostname, agentip, category, severity, uptime, traptime, 
					formatline) VALUES (
					\'$event2[0]\',\'$receivedtrap_entry'\,\'$receivedtrap_trans'\,
					\'$db_enterprise\',\'$community\',\'$agent_dns_name\',\'$var[4]\',
					\'$event2[1]\',\'$event2[2]\',\'$var[2]\',\'".$trap_date_time."\',
					\'$message_short2\')" ) ) )
					{
					  warn "DBI DBD::ODBC error: Unable to perform INSERT INTO: ".$dbh_odbc->errstr."\n";

					  if ($syslog_system_enable == 1)
					  {
					    syslog_system("DBI DBD::ODBC error: Unable to perform INSERT INTO: ".$dbh_odbc->errstr);
					  }
					  
					  if ($eventlog_system_enable == 1)
					  {
					    eventlog_system("DBI DBD::ODBC error: Unable to perform INSERT INTO: ".$dbh_odbc->errstr,
					    		16,$eventlog_error);
					  }

					}
					else
					{
					  $trap_successfully_logged++;
					}
			}				 
			
			if ($sql_win32_odbc_enable == 1 && defined ($dbh_win32_odbc) )
			{
				$trap_attempted_to_log++;	

				# Double any single quotes
				my $message_short2 = $message_short;
				$message_short2 =~ s(\')('')g;     #'

				my $community = $var[5];
				$community =~ s(\')('')g;   #'
				
				# if defined, there's an error
				if (defined ($dbh_win32_odbc->Sql
				        ("INSERT INTO $sql_win32_odbc_table (eventname, eventid, trapoid, enterprise, 
					community, hostname, agentip, category, severity, uptime, traptime, 
					formatline) VALUES (
					\'$event2[0]\',\'$receivedtrap_entry'\,\'$receivedtrap_trans'\,
					\'$db_enterprise\',\'$community\',\'$agent_dns_name\',\'$var[4]\',
					\'$event2[1]\',\'$event2[2]\',\'$var[2]\',\'".$trap_date_time."\',
					\'$message_short2\')" ) ) )
				{					
				  warn "Unable to perform INSERT INTO: ".Win32::ODBC::Error()."\n";
				  
				  if ($eventlog_system_enable == 1)
				  {
				    eventlog_system("Win32::ODBC error: Unable to perform INSERT INTO: ".Win32::ODBC::Error(),
				    17,$eventlog_error);
				  }
				}
				else
				{
				  $trap_successfully_logged++;
				}
			}				 

			
			#
			# Variable substitution for EXEC string
			#

			if ($DEBUGGING >= 1)
			{
				print "\n\nEXEC line(s):\n";
			}
			
			if ($event2[4] ne '' && $event2[1] ne "LOGONLY")
			{
			  for (my $i=0; defined($event2[4][$i]); $i++)
			  {
			    $_ = $event2[4][$i];
			    
			    &substitute;
			    
			    my $command = $_;
			    
			    if ($exec_enable == 1)
			    {
			      if ($DEBUGGING >= 1)
			      {	
				print "EXEC command:$command\n";
			      }
			      # Execute command
			      system $command;
			    }
			  }
			}
			elsif ($DEBUGGING >= 1)
			{
				if ($event2[1] eq "LOGONLY")
				{
					print "\n\nTrap set to LOGONLY...\n\n";
				}
			}
		}
		else
		{
			if ($DEBUGGING >= 1)
			{
				if ($event2[1] eq "IGNORE")
				{
				  print "\nTrap set to IGNORE...\n\n";
				}
				else
				{
				  print "\nTrap defined, but NODES or MATCH check failed - skipping this EVENT entry..\n\n";
				}
			}
		}
	
	} #while defined..
}

sub substitute
{
  # Perform substitution on $_ variable

  # Wildcards - $*, $+*, $-*
  my $temp_wildcard1 = ();
  my $temp_wildcard2 = ();
  my $temp_wildcard3 = ();
  for($i=1;$i <= $#entvar+1; $i++)
  {
    $temp_wildcard1 = $temp_wildcard1 . "\$$i" . $wildcard_expansion_separator;
    $temp_wildcard2 = $temp_wildcard2 . "\$\+$i" . $wildcard_expansion_separator;
    $temp_wildcard3 = $temp_wildcard3 . "\$-$i" . $wildcard_expansion_separator;
  }
  
  # Chop off last space
  if (defined ( $temp_wildcard1) )
  {
    chop ($temp_wildcard1);
    chop ($temp_wildcard2);
    chop ($temp_wildcard3);
  }
  
  s(\$\*)($temp_wildcard1)g;
  s(\$\+\*)($temp_wildcard2)g;
  s(\$-\*)($temp_wildcard3)g;
  
  # $v - Names of variable-bindings 
  # Count down backwards to make sure 10 is not mistaken for $1
  for($i=$#entvarname+1;$i > 0; $i--)
  {
    if ($net_snmp_perl_enable == 1)
    {
      my $temp = my_translateObj($entvarname[$i-1],$translate_varname_oid_format);
      if (!defined ($temp) )
      {
	$temp = $entvarname[$i-1];
      }
      s(\$v$i)($temp)g;
    }
    else
    {
      s(\$v$i)($entvarname[$i-1])g;
    }
  }
  
  # $n - Variable-bindings
  # Count down backwards to make sure 10 is not mistaken for $1
  for($i=$#entvar+1;$i > 0; $i--)
  {
    my $val = $entvar[$i-1];
    
    if ($DEBUGGING >= 2)
    {
      print "\nVariable $entvarname[$i-1] with value $entvar[$i-1]\n";
    }
    
    # This will translate (if enabled) any OIDs found in the VALUE (not the variable name) to the textual  
    # name if possible.  For example, if the value was 'A UPS Alarm (.1.3.6.1.4.1.534.1.7.12) has cleared.', 
    # it could be translated to: 'A UPS Alarm (xupsBuildingAlarm) has cleared.'
    if ($translate_value_oids > 0 && $net_snmp_perl_enable == 1)
    {
      $val = &translate_value_oids_sub($val);
    }

    if ($dns_enable == 1 && $resolve_value_ip_addresses == 1 && $net_snmp_perl_enable == 1)
    {
      $val = &resolve_value_ip_addresses_sub($val);
    }
    
    if ($translate_integers == 1 && $net_snmp_perl_enable == 1)
    {
      if (! ($entvar[$i-1] =~ /\D+/))				# Check to see if value is numerical
      {
	if ($DEBUGGING >= 2)
	{
	  print "  Value is numerical\n";
	}
	
	my $temp_OID_type = uc (my_getType($entvarname[$i-1]));
	if ($temp_OID_type eq "INTEGER32" || $temp_OID_type eq "INTEGER")  # Make sure it's a SNMP INTEGER type
	{
	  if ($DEBUGGING >= 2)
	  {
	    print "  Value is defined as an INTEGER in the mib - will attempt to translate\n";
	  }
	  my $val2 = my_mapEnum($entvarname[$i-1], $entvar[$i-1]);
	  if ($val2 ne '')					# Make sure we got something
	  {
	    $val = $val2;
	    
	    if ($DEBUGGING >= 2)
	    {
		    print "    Translated to: $val2\n";
	    }    
          }
	  else
	  {
	    $val = $entvar[$i-1];
	    if ($DEBUGGING >= 2)
	    {
		    print "    Could not translate\n";
	    } 
	  }
	}
	else
	{
	  if ($DEBUGGING >= 2)
	  {
	    print "  Value is NOT defined as an INTEGER or Integer32 in the mib\n";
	  }
	}
      }
    }
    
    if ($net_snmp_perl_enable == 1)
    {
      s(\$$i)($val)g;			# $n	      

      # Translate for $+n and $-n
      my $temp = my_translateObj($entvarname[$i-1],$translate_varname_oid_format);
      if (!defined ($temp) )		
      {
	$temp = $entvarname[$i-1];
      }

      my $temp2 = &my_getType($entvarname[$i-1]);
      if (!defined ($temp2))
      {
	$temp2 = "unknown";
      }
            
      s(\$\+$i)($temp:$val)g;		# $+n

      s(\$-$i)($temp ($temp2):$val)g;	# $-n
    }
    else
    {
      s(\$$i)($val)g;				# $n
      s(\$\+$i)($entvarname[$i-1]:$val)g;		# $+n
      
      s(\$-$i)($entvarname[$i-1] (unknown):$val)g;	# $-n
    }
  }
  
  # $c - Category
  s(\$c)($event2[1])g;
  
  # $C - Trap community string
  s(\$C)($var[5])g;
  
  # $E - Enterprise trap (symbolic)
  s(\$E)($enterprise_trans)g;
  
  # $e - Enterprise trap (numerical)
  s(\$e)($var[6])g;
  
  # $N - Event name
  s(\$N)($event2[0])g;

  # $i - Event OID
  s(\$i)($receivedtrap_entry)g;
  
  # $# - Number of variable-bindings in the trap
  my $entvar_temp = $#entvar+1;
  s(\$#)($entvar_temp)g;
  
  # $$ - Print a $
  s(\$\$)(\$)g;
  
  # $O - Received trap (symbolic)
  if ($net_snmp_perl_enable == 1)
  {
    if ($DEBUGGING >= 2) {
      print "\nOID of received trap: $receivedtrap.  Will attempt to translate to text\n";
    }
    my $temp = my_translateObj("$receivedtrap",$translate_trap_oid_format);
    if (defined ($temp) ) {
      if ($DEBUGGING >= 2) {
	print "  Translated to $temp\n";
      }
      s(\$O)($temp)g;
    }
    else 
    {
      # Could not translate default to numeric
      if ($DEBUGGING >= 2) {
	print "  Could not translate - defaulting to numeric\n";
      }
      s(\$O)($temp)g;
    }
  }
  else
  {
    s(\$O)($receivedtrap)g;
  }

  # $o - Received trap (numerical)
  s(\$o)($receivedtrap)g;	
  
  # $s - Severity
  s(\$s)($event2[2])g;
  
  # $AR, $ar - IP address
  s(\$aR)($var[1])g;
  s(\$ar)($var[1])g;
  
  # $R, $r - Hostname
  s(\$R)($var[0])g;
  s(\$r)($var[0])g;
  
  # $A, $a - Trap agent IP address
  s(\$aA)($var[4])g;		# IP address
  s(\$A)($agent_dns_name)g;	# hostname
  
  # $T - Uptime
  s(\$T)($var[2])g;
  
  # $x - Current date
  s(\$x)($trap_date)g;	
  
  # $X - Current time
  s(\$X)($trap_time)g;	
  
  # $@ - Current time since epoch (Jan 1, 1904 for Mac, Jan 1, 1900 for most others)
  s(\$@)($trap_date_time_epoch)g;
  
  # iso(1) org(3) dod(6) internet(1) snmpV2(6) snmpModules(3) snmpMIB(1) snmpMIBObjects(1) 5
  # SNMPv2 Generic?  1=coldStart....5=authenticationFailure, 6=egpNeighborLoss so 0=enterprise?
  if ($receivedtrap =~ /^.1.3.6.1.6.3.1.1.5/)
  {
    # It's a generic trap
      
    # $S - Specific trap number - 0
    s(\$S)(0)g;
    
    # $G - Generic trap number - last #
    my $temp = $_; 		# Save old $_
    $_ = $receivedtrap;
    /(\d+)$/;
    my $temp2 = $1;
    $_ = $temp;		# Restore old $_
    s(\$G)($temp2)g;
  }
  else
  {
    # It's an enterprise trap
    
    # $S - Specific trap number - last #
    my $temp = $_; 		# Save old $_
    $_ = $receivedtrap;
    /(\d+)$/;
    my $temp2 = $1;
    $_ = $temp;		# Restore old $_
    s(\$S)($temp2)g;
    
    # $G - Generic trap number - 0
    s(\$G)(0)g;	  
  }	
  
  # Do user defined REGEX on $message
  
  if ($DEBUGGING >= 2 && defined($event2[6][0]))
  {
    print "\n$_\n";
  }
  
  for (my $i=0; defined($event2[6][$i]); $i++)
  {
    my $regex_temp = $event2[6][$i];
    
    #print "!!!!!!$regex_temp\n";
    # Remove starting and ending ()
    #$regex_temp =~ /^\((.*)\)$/;
    $regex_temp =~ /^\((.*)\)(.*)$/;
    $regex_temp = $1;
    my $modifiers = $2;
    
    # Split using )(
    my @regex_temp2 = split(/\)\(/,$regex_temp,2);
    #print "0:$regex_temp2[0]\n";
    #print "1:$regex_temp2[1]\n";
    #print "Modifiers: $modifiers\n";

    if ($regex_temp2[0] ne '')
    {
      # allowed modifiers: any combination of: i, g, e, ee+ not permitted
      my $modifiers2 = 0;
      if ($modifiers =~ /i/) { $modifiers2 = $modifiers2 | 1; }
      if ($modifiers =~ /g/) { $modifiers2 = $modifiers2 | 2; }
      if ($modifiers =~ /e/) 
      { 
	if ($allow_unsafe_regex == 1)
	{
	  $modifiers2 = $modifiers2 | 4;
	  
	  # Append a package declaration to the beginning to prevent global variables from being
	  # visible.  Also remove any attempts to access variables from the main:: package.
	  $regex_temp2[1] = "package regexisoloate;$regex_temp2[1]";
	  $regex_temp2[1] =~ s/\$main::/\$/gi;	# Remove attempts to access the main package
	}
	else
	{
	  if ($DEBUGGING >= 2)
          {
	    print "  REGEX detected with e modifier, but allow_unsafe_regex is disabled.  Removing e modifier\n";
          }
	}
      }

      #print "modifiers2 = $modifiers2\n";
      
      # 0	none
      # 1	i
      # 2	g
      # 3	ig
      # 4	e
      # 5	ie
      # 6	ge
      # 7	ige

      if ($DEBUGGING >= 2)
      {
	print "  Doing REGEX: s($regex_temp2[0])($regex_temp2[1])$modifiers\n";
      }

      # If unsafe is off, then don't use the e modifier.  This means that variable interopolation
      # will not work on the right side.  If the user puts a $1 on the right, it will print out $1.
      # 
      # If unsafe is on, then we use the /ee modifier.
      # 
      # With a normal regular expression in a program, the e modifier is not requried for variable 
      # interopolation to work.  If you want to have code executed, then you need at least one e
      # modifier in a regular program.
      # 
      # Because we are passing the right side to a perl program instead of hard-coding the right side
      # *inside* of the program, we need to handle it differently.  These are the rules:
      # 
      # -for interopolation and / or code execution to work, we need to use the /ee modifier inside the 
      #  program (snmptt)
      # -if we only want interop and no code execution (same behaviour as a program with no e modifier),
      #  then we:
      #   -escape all backslashes
      #   -escape all double quotes
      #   -escape all single quotes
      #   -put quotes around the whole thing
      # - One would assume that if we didn't put quotes around everything, and used one /e instead of two, then
      #   it would work, but it does not..
      #   
      # -if we want both interop and code to execute (same behaviour as a program with one e modifier), 
      #  then we:
      #   -do nothing extra (no escaping or putting quotes around it)
      # 
      # With unsafe off, or unsafe no with NO e modifier, whatever the user puts in the right side of the 
      # REGEX will display exactly, with the only exception of the $n variable interop working with unsafe on.
      #
      # With unsafe on and one e modifier, the right side is evaluated so any text needs to be in quotes, and
      # printable quotes need to be escaped etc just like a normal program.  
      #
      # Example1:
      # 
      # "5 + 5 is ".(5+5)."and \"this is quoted\""
      # will output:
      # 5+5 is 10 and "this is quoted"
      #
      # If unsafe was off, it would output:
      #
      # "5 + 5 is ".(5+5)."and \"this is quoted\""
      #
      # Example2:
      # 
      # "5 + 5 is ".sprintf("%d",(5+5))."and \"this is quoted\""
      # will output:
      # 5+5 is 10 and "this is quoted"
      #
      # If unsafe was off, it would output:
      #
      # "5 + 5 is ".sprintf("%d",(5+5))."and \"this is quoted\""

      if ($allow_unsafe_regex == 0)
      {
	# unsafe_regex is OFF
	if    ($modifiers2 == 0 ) { s($regex_temp2[0])($regex_temp2[1]); }
        elsif ($modifiers2 == 1)  { s($regex_temp2[0])($regex_temp2[1])i; }
        elsif ($modifiers2 == 2)  { s($regex_temp2[0])($regex_temp2[1])g; }
        elsif ($modifiers2 == 3)  { s($regex_temp2[0])($regex_temp2[1])ig; }
      }
      else
      {
	# unsafe_regex is ON
	
	# If unsafe is on, use two e's.  If user does not specify an e, 
	# escape back slashes and quotes, and put quotes around the whole string
	# to prevent functions from being executed
	if (! ($modifiers =~ /e/))
	{
	  # If it contains a \, then escape it
	  $regex_temp2[1] =~ s/\\/\\\\/g;
	  # Escape each quote
	  $regex_temp2[1] =~ s/\"/\\\"/g;	# double quotes
	  $regex_temp2[1] =~ s/\'/\\\'/g;	# single quotes
	  # put quotes around the whole thing
	  $regex_temp2[1] = "\"$regex_temp2[1]\"";
	}      
	#print "1:$regex_temp2[1]\n";
	if    ($modifiers2 == 0 ) { s($regex_temp2[0])($regex_temp2[1])ee; }
        elsif ($modifiers2 == 1)  { s($regex_temp2[0])($regex_temp2[1])eei; }
        elsif ($modifiers2 == 2)  { s($regex_temp2[0])($regex_temp2[1])eeg; }
        elsif ($modifiers2 == 3)  { s($regex_temp2[0])($regex_temp2[1])eeig; }
        elsif ($modifiers2 == 4)  { s($regex_temp2[0])($regex_temp2[1])ee; }
        elsif ($modifiers2 == 5)  { s($regex_temp2[0])($regex_temp2[1])eei; }
        elsif ($modifiers2 == 6)  { s($regex_temp2[0])($regex_temp2[1])eeg; }
        elsif ($modifiers2 == 7)  { s($regex_temp2[0])($regex_temp2[1])eeig; }
      }
    }
  }
}

sub loadsnmpttconf
{
	#
	# snmptt.conf loader.
	# This section loads the snmptt.conf which defines the traps and text strings
	# that will be used for variable substitution

	# Flush variables in case this is a re-load during run
	@snmpttconf = ();
	# @snmptt_conf_files = ();
	undef %event;
	undef %nodes_file_hash;		# NODES entries from NODES files
	
	foreach $snmpttconffile (@snmptt_conf_files)
	{
	  if ($DEBUGGING >= 1)
	  {
	    print "\n\tLoading $snmpttconffile\n";
	  }
	  
	  if ($syslog_system_enable == 1 && $daemon == 1)
	  {
	    syslog_system("Loading $snmpttconffile");
	  }
	  if ($eventlog_system_enable == 1 && $daemon == 1)
	  {
	    eventlog_system("Loading $snmpttconffile",9,$eventlog_information);
	  }
	  
	  unless (open SNMPTTCONF, $snmpttconffile)
	  {
	    warn "Could not open configuration file: $snmpttconffile ($!)";
	    if ($DEBUGGING >= 1)
	    {
	      print "\n\tCould not open configuration file: $snmpttconffile\n";
	    }
	    
	    if ($syslog_system_enable == 1 && $daemon == 1)
	    {
	      syslog_system("Could not open configuration file: $snmpttconffile");
	    }
	    if ($eventlog_system_enable == 1 && $daemon == 1)
	    {
	      eventlog_system("Could not open configuration file: $snmpttconffile",10,$eventlog_error);
	    }
	    
	    next;
	  }
	  $tempcount = 0;
	  while (<SNMPTTCONF>)
	  {
	    chomp;				#remove <cr> at end of line	
	    s/\015//;                       	# Remove any DOS carriage returns
	    push(@snmpttconf, $_);		#add to each line to @trapconf array
	    $tempcount++;
	  }
	  
	  if ($DEBUGGING >= 1)
	  {
	    print "\tFinished loading $tempcount lines from $snmpttconffile\n";
	  }
	  if ($syslog_system_enable == 1 && $daemon == 1)
	  {
	    syslog_system("Finished loading $tempcount lines from $snmpttconffile");
	  }
	  if ($eventlog_system_enable == 1 && $daemon == 1)
	  {
	    eventlog_system("Finished loading $tempcount lines from $snmpttconffile",11,$eventlog_information);
	  }
	}
	
	if ($DEBUGGING >= 1)
	{
		print "\nFinished loading configuration files\n";
	}
	
	# Process each line of snmptt.conf loaded into @snmpttconf array.
	# Add each EVENT to %event hash
	
	if ($DEBUGGING >= 1)
	{
		print "\nProcessing memory copy of configuration files\n";
	}
	
	$currentline=0;
	$tempcount=0;
	$tempcount2=0;
	
	while ($currentline <= $#snmpttconf)
	{
		$line = $snmpttconf[$currentline];
	
		if ($line =~ /^EVENT/)
		{
			#EVENT name .x.x.x.x "category" severity  (note: .x.x. is FULL OID!)
			#0      1       2        3         4
			
			# use shellwords to divide the two space separated values
			# without messing up quoted text and re-join using :: as the
			# delimiter
			#
			# hash elements:
			# 0: name of trap
			# 1: category
			# 2: severity
			# 3: FORMAT string
			# 4: EXEC string
			# 5: NODES string
			
			$tempcount++;		# Temporary counter of the number of EVENTS found
			
			# Divide up line taking into consideration strings in quotes
			$temp = join "::::", shellwords($line);                

			#print "line is: $temp\n";
	
			# Split line up into multiple elements of an array using the new delimiter
			@temp = split ("::::",$temp);
			
			if (! ($temp[2] =~ /^(\.\d+)+$/) && ! ($temp[2] =~ /^(\.\d+)+\.\*$/))
			{
			  # OID contains text, so it's not fully numerical
			  if ($net_snmp_perl_enable == 1)
			  {
			    # Try to convert to numerical
			    if ($DEBUGGING >= 2)
			    {
			      print "Non-numeric OID: $temp[2].  Will attempt to translate to numerical\n";
			    }
			    my $temp2 = SNMP::translateObj("$temp[2]",0);
			    if (defined ($temp2) )
			    {
			      if ($DEBUGGING >= 2)
			      {
				print "  Translated to $temp2\n";
			      }
			      $temp[2] = $temp2;
			    }
			    else
			    {
			      # Could not translate, so skip this entry
			      if ($DEBUGGING >= 2)
			      {
				print "  Could not translate - skipping entry\n";
			      }
			      $currentline++; # Increment to the next line
			      next;
			    }
			  }
			  else
			  {
			    # Net-SNMP Perl module not enabled, and OID is not numeric so skip this entry
			    if ($DEBUGGING >= 2)
			    {
			      print "Non-numeric OID: $temp[2].  Net-SNMP Perl module not enabled - skipping entry\n";
			    }
			    $currentline++; # Increment to the next line
			    next;
			  }
			}
			
			# Clear out the FORMAT, EXEC and NODES lines in case they are not found.  Don't want old
			# data in them..
			$lineformat = '';
			$lineexec = '';
			$linenodes = '';
			$lineregex = '';
			@exec = ();
			@regex = ();
			@match = ();
	
			$currentline++; # Increment to the next line which should be a FORMAT, EXEC or NODES
			$line2 = $snmpttconf[$currentline];
			
			while ( ($currentline <= $#snmpttconf) && !($line2 =~ /^EVENT/) )
			{
				# Keep going through the file until the next EVENT or the end of snmptt.conf
				# is reached
			
				# Check to see if next line is a FORMAT line (it should be!)
				if ($line2 =~ /^FORMAT/)
				{
					# It's a FORMAT line
					
					$lineformat = substr($line2,7);
				}
				elsif ($line2 =~ /^EXEC/)
				{
					# It's an EXEC line
					
					$lineexec = substr($line2,5);

					push (@exec,$lineexec);
				}
				elsif ($line2 =~ /^NODES/)
				{
					# It's a NODES line
					# Allow for multiple NODES lines - concatenate them

					$linenodes = $linenodes . substr($line2,6) . " ";
				}
				elsif ($line2 =~ /^REGEX/)
				{
					# It's a REGEX line
					
					$lineregex = substr($line2,6);

					# Remove spaces before and after
					$lineregex =~ /^\s*(.*?)\s*$/;
					$lineregex = $1;

					# Make sure it looks like ()() before accepting
					if ($lineregex =~ /\(.*?\)\(.*?\)/ )
					{
					  push (@regex,$lineregex);
					}
				}
				elsif ($line2 =~ /^MATCH/)
				{
					# It's a MATCH line
					
					$linematch = substr($line2,6);

					push (@match,$linematch);
				}
				$currentline++; # Increment to the next line
				$line2 = $snmpttconf[$currentline]; # Get next line
			}
			if ($lineformat ne '')
			{			
				# At least the mandatory FORMAT line was defined, so we'll keep it
				# Stuff all elements into a one hash
				# $event{@temp[2]} = [@temp[1],@temp[3],@temp[4],$lineformat,$lineexec,$linenodes];

				if (!defined(@{ $event{$temp[2]} }[0])) 
				{  
					@{ $event{$temp[2]} }[0] = 0;
				}

				#@regex = qw/one two/;
								
				$countx = @{ $event{$temp[2]} }[0];
				#print "countx $countx\n";
				@{ $event{$temp[2]} }[1+$countx]= $temp[1];
				@{ $event{$temp[2]} }[2+$countx]= $temp[3];
				@{ $event{$temp[2]} }[3+$countx]= $temp[4];
				@{ $event{$temp[2]} }[4+$countx]= $lineformat;
				#@{ $event{$temp[2]} }[5+$countx]= $lineexec;
				@{ $event{$temp[2]} }[5+$countx]= [@exec];
				
				# If dynamic_nodes is disabled, process the nodes list to load any nodes
				# files first so they are not loaded each time a trap is processed
				if ($dynamic_nodes == 0)
				{
				  my @nodes2 = &process_nodes($linenodes);
				  @{ $event{$temp[2]} }[6+$countx]= "@nodes2";
				}
				else
				{
				  @{ $event{$temp[2]} }[6+$countx]= $linenodes;
				}

				@{ $event{$temp[2]} }[7+$countx]= [@regex];
				@{ $event{$temp[2]} }[8+$countx]= [@match];
				@{ $event{$temp[2]} }[0]= 9+ @{ $event{$temp[2]} }[0];
				
				$tempcount2++;		# Temporary counter of the number of EVENTS found with at
							# least a FORMAT line specified
			}
	
			# Change currentline back so the next increment will re-evalutate the last line which
			# would have been an EVENT (to get out of the WHILE loop above), or the end of the file
			$currentline--;
		}
		$currentline++;		# Increment current line for next loop through snmpttconf array	
	}
	if ($DEBUGGING >= 1)
	{
		print "$tempcount EVENTs found\n";
		print "$tempcount2 EVENTs found that contain at least the mandatory FORMAT line\n";
		if($tempcount2<$tempcount)
		{
			print "  Warning:  EVENT entries were found that did not contain the mandatory FORMAT line!\n";
			print "  These EVENTS will be ignored!\n";
		}
		print "Finished processing memory copy of configuration files\n\n";
	}
	
	if ($DEBUGGING >= 2)
	{
		print "Printing out all the events in hash table:\n\n";
		foreach $key (sort keys %event)
		{		
			$l=0;
			while (defined($event{$key}[$l+1]))
			{	
				print  "hash: $key => $event{$key}[1+$l],$event{$key}[2+$l],$event{$key}[3+$l],$event{$key}[4+$l],$event{$key}[7+$l][0]\n";
			$l+=9;
			}

		}
		print "Finished printing out all events in hash table\n";
	}

	close SNMPTTCONF;
}

sub readtrap
{
	# Flush out @tempvar, @var and @entvar
	@tempvar = ();
	@var = ();
	@entvar = ();
	@entvarname = ();

	if ($DEBUGGING >= 2) 
	{	  
	  print "Reading trap.  Current time: " . scalar(localtime()). "\n";
	}
	
	if ( $daemon == 1)
	{
	  chomp($trap_date_time_epoch = (<$input>));	# Pull time trap was spooled
	  $trap_date_time_epoch =~ s(`)(')g;	#` Replace any back ticks with regular single quote
	}
	else
	{
	  $trap_date_time_epoch = time();		# Use current time as time trap was received
	}
	
	if ( $daemon == 1 && $use_trap_time == 1 )	# Daemon mode only
	{
	  $trap_date_time = localtime($trap_date_time_epoch);
	  $trap_date = strftime "%a %b %e %Y", localtime($trap_date_time_epoch);
	  $trap_time = strftime "%H:%M:%S", localtime($trap_date_time_epoch);
	}
	else
	{
	  $trap_date_time = localtime();
	  $trap_date = strftime "%a %b %e %Y", localtime();
	  $trap_time = strftime "%H:%M:%S", localtime();
	}
	
	chomp($tempvar[0]=<$input>);	# hostname
	$tempvar[0] =~ s(`)(')g;	#` Replace any back ticks with regular single quote
	
	chomp($tempvar[1]=<$input>);	# ip address
	$tempvar[1] =~ s(`)(')g;	#` Replace any back ticks with regular single quote
	
	# Some systems pass the IP address as udp:ipaddress:portnumber.  This will pull
	# out just the IP address
	$tempvar[1] =~ /(\d+\.\d+\.\d+\.\d+)/;
	$tempvar[1] = $1;
	
	#Process varbinds
	#Separate everything out, keeping both the variable name and the value
	$linenum = 1;
	while (defined($line = <$input>))
	{
	  $line =~ s(`)(')g;	#` Replace any back ticks with regular single quote
	  
	  if ($remove_backslash_from_quotes == 1)  # Remove escape from quotes if enabled
	  {
	    $line =~ s/\\\"/"/g;
	  }
	  
	  my $temp1;
	  my $temp2;

	  ($temp1, $temp2) = split (/ /, $line, 2);
  
	  chomp ($temp1);
	  chomp ($temp2);
	  chomp ($line);
	
	  if ($linenum == 1)
	  {
	    if (defined($temp2) )	# Check if line 1 contains 'variable value' or just 'value'  
	    {
	      $variable_fix = 0;
	    }
	    else
	    {
	      $variable_fix = 1;
	    }
	  }

	  if ($variable_fix == 0 )
	  {
	    # If line begins with a double quote (") but does not END in a double quote then we need to merge
	    # the following lines together into one until we find the closing double quote.
	    # Net-SNMP sometimes divides long lines into multiple lines..
	    if ( ($temp2 =~ /^\"/) && ( ! ($temp2 =~ /\"$/)) )
	    {
	      if ($DEBUGGING >= 2) {
		print "  Multi-line value detected - merging onto one line...\n";
	      }
	      chomp $temp2;				# Remove the newline character
	      while (defined($line2 = <$input>))
	      {
		chomp $line2;
		$temp2.=" ".$line2;
		if ($line2 =~ /\"$/)
		{
		  last;
		}
	      }
	    }

	    # Check to see if OID passed from snmptrapd is fully numeric.  If not, try to translate
	    if (! ($temp1 =~ /^(\.\d+)+$/)) 
	    {
	      # Not numeric
	      # Try to convert to numerical
	      if ($DEBUGGING >= 2) {
		print "\n  Symbolic trap variable name detected ($temp1).  Will attempt to translate to a numerical OID\n";
	      }
	      if ($net_snmp_perl_enable == 1)
	      {
		my $temp3 = SNMP::translateObj("$temp1",0);
		if (defined ($temp3) ) {
		  if ($DEBUGGING >= 2) {
		    print "    Translated to $temp3\n";
		  }
		  $temp1 = $temp3;
		}
		else {
		  # Could not translate default to numeric
		  if ($DEBUGGING >= 2) {
		    print "  Could not translate - will leave as-is\n";
		  }
		}
	      }
	      else
	      {
		if ($DEBUGGING >= 2) {
		  print "  Could not translate - Net-SNMP Perl module not enabled - will leave as-is\n";
		}
	      }
	    }
	    # If the value is blank, set it to (null)
	    if ($temp2 eq "")
	    {
	      $temp2 = "(null)";
	    }
	    
	    if ($temp2 =~ /^\"/ && $temp2 =~ /$\"/)			# Have quotes around it?
	    {
	      $temp2 = substr($temp2,1,(length($temp2)-2));		# Remove quotes
	      push(@tempvar, $temp1);
	      push(@tempvar, $temp2);
	    }
	    else
	    {
	      push(@tempvar, $temp1);
	      push(@tempvar, $temp2);
	    }
	  }
	  else
	  {
	    # Should have been variable value, but only value found.  Workaround
	    # 
	    # Normally it is expected that a line contains a variable name
	    # followed by a space followed by the value (except for the 
	    # first line which is the hostname and the second which is the
	    # IP address).  If there is no variable name on the line (only
	    # one string), then add a variable string called 'variable' so 
	    # it is handled correctly in the next section.
	    # This happens with ucd-snmp v4.2.3 but not v4.2.1 or v4.2.5.
	    # This appears to be a bug in ucd-snmp v4.2.3.  This works around
	    # the problem by using 'variable' for the variable name, although 
	    # v4.2.3 should NOT be used with SNMPTT as it prevents SNMP V2 traps 
	    # from being handled correctly.

	    if ($DEBUGGING >= 2)
	    {
	      print "Data passed from snmptrapd is incorrect.  UCD-SNMP v4.2.3 is known to cause this\n";
	    }

	    # If line begins with a double quote (") but does not END in a double quote then we need to merge
	    # the following lines together into one until we find the closing double quote.
	    # Net-SNMP sometimes divides long lines into multiple lines..
	    if ( ($line =~ /^\"/) && ( ! ($line =~ /\"$/)) )
	    {
	      if ($DEBUGGING >= 2) {
		print "  Multi-line value detected - merging onto one line...\n";
	      }
	      chomp $line;				# Remove the newline character
	      while (defined($line2 = <$input>))
	      {
		chomp $line2;
		$line.=" ".$line2;
		if ($line2 =~ /\"$/)
		{
		  last;
		}
	      }
	    }

	    # If the value is blank, set it to (null)
	    if ($line eq "")
	    {
	      $line = "(null)";
	    }
	    
	    if ($line =~ /^\"/ && $line =~ /$\"/)			# Have quotes around it?
	    {
	      $line = substr($line,1,(length($line)-2));		# Remove quotes
	      push(@tempvar, "variable");
	      push(@tempvar, $line);
	    }
	    else
	    {
	      push(@tempvar, "variable");
	      push(@tempvar, $line);
	    }
	  }
	
	  $linenum++;
	}
	
	if ($DEBUGGING >= 2)
	{
		# Print out all items passed from snmptrapd
		print "\nItems passed from snmptrapd:\n";
		for ($i=0;$i <= $#tempvar;$i++)
		{
			print "value $i: $tempvar[$i]\n\n";
		}
	}
	
	# Copy what I need to new variables to make it easier to manipulate later
	
	# Standard variables
	$var[0] = $tempvar[0];		# hostname
	$var[1] = $tempvar[1];		# ip address
	$var[2] = $tempvar[3];		# uptime
	$var[3] = $tempvar[5];		# trapname / OID - assume first value after uptime is
					# the trap OID (value for .1.3.6.1.6.3.1.1.4.1.0)
	
	$var[4] = "";	# Clear ip address from trap agent
	$var[5] = "";	# Clear trap community string
	$var[6] = "";	# Clear enterprise
	
	# Cycle through remaining variables searching for for agent IP (.1.3.6.1.6.3.18.1.3.0),
	# community name (.1.3.6.1.6.3.18.1.4.0) and enterpise (.1.3.6.1.6.3.1.1.4.3.0)
	# All others found are regular passed variables
	$j=0;
	for ($i=6;$i <= $#tempvar; $i+=2)
	{
		if ($tempvar[$i] =~ /^.1.3.6.1.6.3.18.1.3.0$/)		# ip address from trap agent
		{
			$var[4] = $tempvar[$i+1];
		}
		elsif ($tempvar[$i] =~ /^.1.3.6.1.6.3.18.1.4.0$/)	# trap community string
		{
			$var[5] = $tempvar[$i+1];
		}
		elsif ($tempvar[$i] =~ /^.1.3.6.1.6.3.1.1.4.3.0$/)	# enterprise
		{
			$var[6] = $tempvar[$i+1];
		}
		else	# application specific variables
		{
			$entvarname[$j] = $tempvar[$i];
			$entvar[$j] = $tempvar[$i+1];
			$j++;
		}
		
	}

	if ($dns_enable == 1 && $var[0] =~  /^\d+\.\d+\.\d+\.\d+$/) # Only if it's not already resolved
	{
	  my $temp = gethostbyaddr(Socket::inet_aton($var[0]),Socket::AF_INET());
	  if (defined ($temp))
	  {
	    if ($DEBUGGING => 1)
	    {
	      print "Host IP address ($var[0]) resolved to: $temp\n\n";
	    }
	    $var[0] = $temp;
	  }
	  else
	  {
	    if ($DEBUGGING => 1)
	    {
	      print "Host IP address ($var[0]) could not be resolved by DNS.  Variable \$r / \$R etc will use the IP address\n\n";
	    }
	  }
	}

        # If the agent IP is blank, copy the IP from the host IP.
        # var[4] would only be blank if it wasn't passed from snmptrapd, which
        # should only happen with ucd-snmp 4.2.3, which you should be using anyway!
        if ($var[4] eq '')
        {
          $var[4] = $var[1];
          if ($DEBUGGING => 1)
          {
            print "Agent IP address was blank, so setting to the same as the host IP address of $var[1]\n\n";
          }
        }

        # If the agent IP is the same as the host IP, then just use the host DNS name, no need
        # to look up, as it's obviously the same..
        if ($var[4] eq $var[1])
        {
          if ($DEBUGGING => 1)
          {
            print "Agent IP address ($var[4]) is the same as the host IP, so copying the host name: $var[0]\n\n";
          }
          $agent_dns_name = $var[0];
        }
        else
        {
          $agent_dns_name = $var[4];     # Default to IP address
	  if ($dns_enable == 1 && $var[4] ne '')
	  {
	    my $temp = gethostbyaddr(Socket::inet_aton($var[4]),Socket::AF_INET());
	    if (defined ($temp))
	    {
	      if ($DEBUGGING => 1)
	      {
	        print "Agent IP address ($var[4]) resolved to: $temp\n\n";
	      }
	      $agent_dns_name = $temp;
	    }
	    else
	    {
	      if ($DEBUGGING => 1)
	      {
	        print "Agent IP address ($var[4]) could not be resolved by DNS.  Variable \$A etc will use the IP address\n\n";
	      }
            }
	  }
	}

	if ($strip_domain)
	{
	  $var[0] = strip_domain_name($var[0], $strip_domain);
	  $agent_dns_name = strip_domain_name($agent_dns_name, $strip_domain);
	}
	
	if ($DEBUGGING >= 1)
	{
		print "Trap received from $tempvar[0]: $tempvar[5]\n";
	}
	
	if ($DEBUGGING >= 2)
	{
		print "0:		hostname\n";
		print "1:		ip address\n";
		print "2:		uptime\n";
	 	print "3:		trapname / OID\n";
		print "4:		ip address from trap agent\n";
		print "5:		trap community string\n";
		print "6:		enterprise\n";
		print "0+:		passed variables\n\n";	
		
		#print out all standard variables
		for ($i=0;$i <= $#var;$i++)
		{
			print "Value $i: $var[$i]\n\n";
		}
               
                print "Agent dns name: $agent_dns_name\n\n";

		#print out all enterprise specific variables
		for ($i=0;$i <= $#entvar;$i++)
		{
			print "Ent Value $i: $entvarname[$i]=$entvar[$i]\n\n";
		}
	}
		
	# Variables of trap received by SNMPTRAPD:
	# 
	# $var[0]		hostname
	# $var[1] 		ip address
	# $var[2] 		uptime
	# $var[3] 		trapname / OID
	# $var[4] 		ip address from trap agent
	# $var[5] 		trap community string
	# $var[6] 		enterprise
	#
	# $entvarname[0]	passed variable name 1
	# $entvarname[1]	passed variable name 2
	#
	# $entvar[0]		passed variable 1
	# $entvar[1]		passed variable 2
	# .
	# .
	# etc..
	#
	##############################################################################
	
}
	
sub searchfortrap
{
		
	# Variables of trap received by SNMPTRAPD:
	# 
	# $var[0]		hostname
	# $var[1] 		ip address
	# $var[2] 		uptime
	# $var[3] 		trapname / OID
	# $var[4] 		ip address from trap agent
	# $var[5] 		trap community string
	# $var[6] 		enterprise
	#
	# $entvarname[0]	passed variable name 1
	# $entvarname[1]	passed variable name 2
	#
	# $entvar[0]		passed variable 1
	# $entvar[1]		passed variable 2
	# .
	# .
	# etc..
	# 
	# $event hash for each trapped defined in snmptt.conf with following values:
	# 
	# 0: name of trap
	# 1: category
	# 2: severity
	# 3: FORMAT string
	# 4: EXEC string
	# 5: NODES string
	# 6: REGEX array
	#
	# Example: 	To access FORMAT string for received trap:
	# 		$event{"$var[3]"}[3]
	#
	#		or
	# 		
	# 		$event{"$receivedtrap"}[3]	
	###############################################################################
	# Check to see if received trap is defined in the snmptt.conf, and perform variable
	# substitution, logging etc if found
	
	# Look for matching OID
	
	$processed = 0;
	$receivedtrap = $var[3];
	$receivedtrap_entry = $receivedtrap; 	# Will be used to processtrap to lookup EVENT info
						# Changed to actual EVENT entry if using a wildcard 

	$trap_attempted_to_log = 0;
	$trap_successfully_logged = 0;

	# Check for exact match
	if (exists $event{"$receivedtrap"})
	{
		if ($DEBUGGING >= 1)
		{
			print "Exact match of trap found in EVENT hash table\n\n";
		}
		
		&processtrap;
	}
	else
	{
		if ($DEBUGGING >= 1)
		{
			print "Exact match of trap NOT found in EVENT hash table\n\n";
		}
	}
	
	# Check for wildcard match in hash table if not already processed
	if ($processed == 0)
	{
		$receivedtraptemp = $receivedtrap;
		
		$counter = 0;	# Drill down only 40 times.  Should never need this, but
				# it's here to prevent an infinite loop in this while statement
				# just in case
		
		if ($DEBUGGING >= 1)
		{
		  print "Looking for wildcards in the EVENT hash table\n";
		}			
				
		while ($counter <= 40 && $receivedtraptemp ne '')
		{
			# Remove last digit of recevied trap, add a * and look for match
			$receivedtraptemp =~ s/(.*)\.\d+$/$1/;
	
			if ($DEBUGGING >= 2)
			{
				print "Drilling down looking for wildcards in the EVENT hash table\n";
				print $receivedtraptemp.".\*\n\n";
			}
			
			if (exists $event{$receivedtraptemp.'.*'})
			{
				$receivedtrap_entry = $receivedtraptemp.'.*';	# Set $receivedtrap to matching trap with wildcard
				&processtrap;
				last;	# found, so stop this while loop
			}
			$counter++;
		}
	}
	
	# Log to unknowntraplog etc if no match was found
	if ($processed == 0)
	{
		if ($DEBUGGING >= 1)
		{
			print "\n\nTrap not defined.  Nothing to do...\n\n";
		}
		
		if ($unknown_trap_log_enable == 1)
		{
			if (open LOGFILE, ">>$unknown_trap_log_file")
			{	
				print LOGFILE scalar($trap_date_time),": Unknown trap ($var[3]) received from $var[0] at: \n";
				#print out all standard variables
				for ($i=0;$i <= $#var;$i++)
				{
					print 	LOGFILE "Value $i: $var[$i]\n";
				}
				#print out all enterprise specific variables
				for ($i=0;$i <= $#entvar;$i++)
				{
					print LOGFILE "Ent Value $i: $entvarname[$i]=$entvar[$i]\n";
				}
				print LOGFILE "\n\n";
				close LOGFILE;
			}
			else
			{
				warn "Can not open log_file: $!";
			}
		}
	}
	

	# If keep_unlogged_traps is set to 0, or if we didn't even try to log, set it as a successful log 
	# so the trap file gets deleted from the spool dir (the trap wasn't found, or a node didn't match)
	if ($trap_attempted_to_log == 0 || $keep_unlogged_traps == 0)	
	{					
	  $trap_successfully_logged = 1;	
	}
	elsif ($keep_unlogged_traps == 1)	# Delete spool if ONE successfully logged
	{
	  if ($trap_successfully_logged >= 1)
	  {
	    $trap_successfully_logged = 1;
	  }
	  else
	  {
	    $trap_successfully_logged = 0;
	  }
	}
	elsif ($keep_unlogged_traps == 2)	# Delete spool if ALL successfully logged
	{
	  if ($trap_successfully_logged == $trap_attempted_to_log)
	  {
	    $trap_successfully_logged = 1;
	  }
	  else
	  {
	    $trap_successfully_logged = 0;
	  }
	}
}

sub findsnmpttini
{
	##############################################################################
	# Load config file start
	# 
	# For Linux / Unix, try /etc/snmp/snmptt.ini first, /etc/snmptt.ini second.
	#
	# For Windows, try %SystemRoot%\snmptt.ini only.
	# 
	if ($ini ne '')
	{
	  $configfile = $ini;
	}
	else
	{	
	 	if ($^O ne "MSWin32")
		{
		  $configfile = '/etc/snmp/snmptt.ini';
		  if( open( CONFIG, '/etc/snmp/snmptt.ini' ) )
		  {
		    $configfile = '/etc/snmp/snmptt.ini';
		    close CONFIG;
		  }
		  elsif ( open( CONFIG, '/etc/snmptt.ini' ) )
		  {
		    $configfile = '/etc/snmptt.ini';
		    close CONFIG;
		  }
		}
		else {
		  $configfile = $ENV{'SystemRoot'}."\\snmptt.ini";
		}
	}
	##############################################################################
}
      
sub loadsnmpttini {

	##############################################################################
	# 
	# Load config file start
	# 
	use Config::IniFiles;
	my $cfg;

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

	if( open( CONFIG, $configfile ) ) {
	  close CONFIG;
	  $cfg = new Config::IniFiles( -file => $configfile);
	}
	else
	{
	  if ($DEBUGGING >= 0) {
	  	print "Config file could not be loaded\n";
	  }
	  exit(1);
	}
	
	if (! $cfg)
	{
	  if ($DEBUGGING >= 0) {
		  print "Error in config file - please check the syntax in the config file\n";
	  }
	  exit(1);
	}

	@snmptt_conf_files = '';
	
	# General
	if ( ($cfg->val('General', 'mode') eq "daemon") || ($daemoncmdline == 1) )
	{
	  $daemon = 1;
	}
	else {
	  $daemon = 0;
	}
	
	$multiple_event = $cfg->val('General', 'multiple_event');
	$dns_enable = $cfg->val('General', 'dns_enable');
	$strip_domain = $cfg->val('General', 'strip_domain');
	@strip_domain_list = $cfg->val('General', 'strip_domain_list');
	$net_snmp_perl_enable = $cfg->val('General', 'net_snmp_perl_enable');
	$net_snmp_perl_best_guess = $cfg->val('General', 'net_snmp_perl_best_guess');
	$translate_log_trap_oid = $cfg->val('General', 'translate_log_trap_oid');
	$translate_value_oids = $cfg->val('General', 'translate_value_oids');
	$resolve_value_ip_addresses = $cfg->val('General', 'resolve_value_ip_addresses');
	$translate_enterprise_oid_format = $cfg->val('General', 'translate_enterprise_oid_format');
	$translate_trap_oid_format = $cfg->val('General', 'translate_trap_oid_format');
	$translate_varname_oid_format = $cfg->val('General', 'translate_varname_oid_format');
	$translate_integers = $cfg->val('General', 'translate_integers');
	$wildcard_expansion_separator = $cfg->val('General', 'wildcard_expansion_separator');
	$mibs_environment = $cfg->val('General', 'mibs_environment');
	$allow_unsafe_regex = $cfg->val('General', 'allow_unsafe_regex');
	$remove_backslash_from_quotes = $cfg->val('General', 'remove_backslash_from_quotes');
	$dynamic_nodes = $cfg->val('General', 'dynamic_nodes');
	
	# DaemonMode
	$daemon_fork = $cfg->val('DaemonMode', 'daemon_fork');
	$daemon_uid = $cfg->val('DaemonMode', 'daemon_uid');
	$spool_directory = $cfg->val('DaemonMode', 'spool_directory');
	$sleep = $cfg->val('DaemonMode', 'sleep');
	$use_trap_time = $cfg->val('DaemonMode', 'use_trap_time');
	$keep_unlogged_traps = $cfg->val('DaemonMode', 'keep_unlogged_traps');	
	
	# Logging
	$stdout_enable = $cfg->val('Logging', 'stdout_enable');
	$log_enable = $cfg->val('Logging', 'log_enable');
	$log_file = $cfg->val('Logging', 'log_file');
	$unknown_trap_log_enable = $cfg->val('Logging', 'unknown_trap_log_enable');
	$unknown_trap_log_file = $cfg->val('Logging', 'unknown_trap_log_file');
	$syslog_enable = $cfg->val('Logging', 'syslog_enable');
	$syslog_facility = $cfg->val('Logging', 'syslog_facility');
	@syslog_level_alert = $cfg->val('Logging', 'syslog_level_alert');
	@syslog_level_crit = $cfg->val('Logging', 'syslog_level_crit');
	@syslog_level_err = $cfg->val('Logging', 'syslog_level_err');	
	@syslog_level_warning = $cfg->val('Logging', 'syslog_level_warning');
	@syslog_level_notice = $cfg->val('Logging', 'syslog_level_notice');
	@syslog_level_info = $cfg->val('Logging', 'syslog_level_info');	
	@syslog_level_debug = $cfg->val('Logging', 'syslog_level_debug');
	$syslog_level = $cfg->val('Logging', 'syslog_level');
	$syslog_system_enable = $cfg->val('Logging', 'syslog_system_enable');
	$syslog_system_facility = $cfg->val('Logging', 'syslog_system_facility');
	$syslog_system_level = $cfg->val('Logging', 'syslog_system_level');
	$eventlog_enable = $cfg->val('Logging', 'eventlog_enable');
	@eventlog_type_information = $cfg->val('Logging', 'eventlog_type_information');
	@eventlog_type_warning = $cfg->val('Logging', 'eventlog_type_warning');
	@eventlog_type_error = $cfg->val('Logging', 'eventlog_type_error');	
	$eventlog_type = $cfg->val('Logging', 'eventlog_type');
	$eventlog_system_enable = $cfg->val('Logging', 'eventlog_system_enable');
	
	# Exec
	$exec_enable = $cfg->val('Exec', 'exec_enable');
	
	# SQL
	$db_translate_enterprise = $cfg->val('SQL', 'db_translate_enterprise');
	$mysql_dbi_enable = $cfg->val('SQL', 'mysql_dbi_enable');
	$mysql_dbi_host = $cfg->val('SQL', 'mysql_dbi_host');
	$mysql_dbi_port = $cfg->val('SQL', 'mysql_dbi_port');
	$mysql_dbi_database = $cfg->val('SQL', 'mysql_dbi_database');
	$mysql_dbi_table = $cfg->val('SQL', 'mysql_dbi_table');
	$mysql_dbi_username = $cfg->val('SQL', 'mysql_dbi_username');
	$mysql_dbi_password = $cfg->val('SQL', 'mysql_dbi_password');

	$postgresql_dbi_enable = $cfg->val('SQL', 'postgresql_dbi_enable');
	$postgresql_dbi_module = $cfg->val('SQL', 'postgresql_dbi_module');
	$postgresql_dbi_hostport_enable = $cfg->val('SQL', 'postgresql_dbi_hostport_enable');
	$postgresql_dbi_host = $cfg->val('SQL', 'postgresql_dbi_host');
	$postgresql_dbi_port = $cfg->val('SQL', 'postgresql_dbi_port');
	$postgresql_dbi_database = $cfg->val('SQL', 'postgresql_dbi_database');
	$postgresql_dbi_table = $cfg->val('SQL', 'postgresql_dbi_table');
	$postgresql_dbi_username = $cfg->val('SQL', 'postgresql_dbi_username');
	$postgresql_dbi_password = $cfg->val('SQL', 'postgresql_dbi_password');
	
	$dbd_odbc_enable = $cfg->val('SQL', 'dbd_odbc_enable');
	$dbd_odbc_dsn = $cfg->val('SQL', 'dbd_odbc_dsn');
	$dbd_odbc_table = $cfg->val('SQL', 'dbd_odbc_table');
	$dbd_odbc_username = $cfg->val('SQL', 'dbd_odbc_username');
	$dbd_odbc_password = $cfg->val('SQL', 'dbd_odbc_password');
	
	$sql_win32_odbc_enable = $cfg->val('SQL', 'sql_win32_odbc_enable');
	$sql_win32_odbc_dsn = $cfg->val('SQL', 'sql_win32_odbc_dsn');
	$sql_win32_odbc_table = $cfg->val('SQL', 'sql_win32_odbc_table');
	$sql_win32_odbc_username = $cfg->val('SQL', 'sql_win32_odbc_username');
	$sql_win32_odbc_password = $cfg->val('SQL', 'sql_win32_odbc_password');
	
	# Debugging
	if ($debugcmdline == 0) {
	  $DEBUGGING = $cfg->val('Debugging', 'DEBUGGING');
	}
	if ($debugfilecmdline == 0) {
	  $DEBUGGING_FILE = $cfg->val('Debugging', 'DEBUGGING_FILE');
	}
	
	# TrapFiles
	@snmptt_conf_files = $cfg->val('TrapFiles', 'snmptt_conf_files');
	
	$cfg->Delete;

	# 
	# Defaults Start
	# 
	if (! defined ($multiple_event)) { $multiple_event = 0} ;
	if (! defined ($dns_enable)) { $dns_enable = 0} ;
	if (! defined ($strip_domain)) { $strip_domain = 0} ;
	if (! defined ($net_snmp_perl_enable)) { $net_snmp_perl_enable = 0} ;
	if (! defined ($net_snmp_perl_best_guess)) { $net_snmp_perl_best_guess = 0} ;
	if (! defined ($translate_log_trap_oid)) { $translate_log_trap_oid = 0} ;
	if (! defined ($translate_value_oids)) { $translate_value_oids = 0} ;
	if (! defined ($resolve_value_ip_addresses)) { $resolve_value_ip_addresses = 0} ;
	if (! defined ($translate_enterprise_oid_format)) { $translate_enterprise_oid_format = 1} ;
	if (! defined ($translate_trap_oid_format)) { $translate_trap_oid_format = 1} ;
	if (! defined ($translate_varname_oid_format)) { $translate_varname_oid_format = 1} ;
	if (! defined ($translate_integers)) { $translate_integers = 0} ;
	if (! defined ($wildcard_expansion_separator)) { $wildcard_expansion_separator = " "} ;
	if (! defined ($allow_unsafe_regex)) { $allow_unsafe_regex = 0} ;
	if (! defined ($remove_backslash_from_quotes)) { $remove_backslash_from_quotes = 0} ;
	if (! defined ($dynamic_nodes)) { $dynamic_nodes = 0} ;
	
	if (! defined ($daemon_fork)) { $daemon_fork = 1} ;
	if (! defined ($daemon_uid)) { $daemon_uid = ''} ;
	if (! defined ($spool_directory)) { $spool_directory = ''} ;
	if (! defined ($sleep)) { $sleep = 5} ;
	if (! defined ($use_trap_time)) { $use_trap_time = 1} ;

	if (! defined ($keep_unlogged_traps)) { $keep_unlogged_traps = 1} ;
	if (! defined ($stdout_enable)) { $stdout_enable = 0} ;
	if (! defined ($log_enable)) { $log_enable = 1} ;
	if (! defined ($log_file)) { $log_file = ''} ;
	if (! defined ($unknown_trap_log_enable)) { $unknown_trap_log_enable = 0} ;
	if (! defined ($unknown_trap_log_file)) { $unknown_trap_log_file = ''} ;
	if (! defined ($syslog_enable)) { $syslog_enable = 0} ;
	if (! defined ($syslog_facility)) { $syslog_facility = 'local0'} ;
	if (! defined ($syslog_level)) { $syslog_level = 'warning'} ;
	if (! defined ($syslog_system_enable)) { $syslog_system_enable = 0} ;
	if (! defined ($syslog_system_facility)) { $syslog_system_facility = 'local0'} ;
	if (! defined ($syslog_system_level)) { $syslog_system_level = 'warning'} ;
	if (! defined ($eventlog_enable)) { $eventlog_enable = 0} ;
	if (! defined ($eventlog_enable)) { $eventlog_enable = 'WARNING'} ;
	if (! defined ($eventlog_system_enable)) { $eventlog_system_enable = 0} ;	
	if (! defined ($exec_enable)) { $exec_enable = 1} ;
	if (! defined ($db_translate_enterprise)) { $db_translate_enterprise = 0} ;
	if (! defined ($mysql_dbi_enable)) { $mysql_dbi_enable = 0} ;
	if (! defined ($mysql_dbi_host)) { $mysql_dbi_host = 'localhost'} ;
	if (! defined ($mysql_dbi_port)) { $mysql_dbi_port = '3306'} ;
	if (! defined ($mysql_dbi_database)) { $mysql_dbi_database = ''} ;
	if (! defined ($mysql_dbi_table)) { $mysql_dbi_table = ''} ;
	if (! defined ($mysql_dbi_username)) { $mysql_dbi_username = ''} ;
	if (! defined ($mysql_dbi_password)) { $mysql_dbi_password = ''} ;
	if (! defined ($postgresql_dbi_enable)) { $postgresql_dbi_enable = 0} ;
	if (! defined ($postgresql_dbi_module)) { $postgresql_dbi_module = 0} ;
	if (! defined ($postgresql_dbi_hostport_enable)) { $postgresql_dbi_hostport_enable = 0} ;
	if (! defined ($postgresql_dbi_host)) { $postgresql_dbi_host = 'localhost'} ;
	if (! defined ($postgresql_dbi_port)) { $postgresql_dbi_port = '5432'} ;
	if (! defined ($postgresql_dbi_database)) { $postgresql_dbi_database = ''} ;
	if (! defined ($postgresql_dbi_table)) { $postgresql_dbi_table = ''} ;
	if (! defined ($postgresql_dbi_username)) { $postgresql_dbi_username = ''} ;
	if (! defined ($postgresql_dbi_password)) { $postgresql_dbi_password = ''} ;
	if (! defined ($dbd_odbc_enable)) { $dbd_odbc_enable = 0} ;
	if (! defined ($dbd_odbc_dsn)) { $dbd_odbc_dsn = ''} ;
	if (! defined ($dbd_odbc_table)) { $dbd_odbc_table = ''} ;
	if (! defined ($dbd_odbc_username)) { $dbd_odbc_username = ''} ;
	if (! defined ($dbd_odbc_password)) { $dbd_odbc_password = ''} ;
	if (! defined ($sql_win32_odbc_enable)) { $sql_win32_odbc_enable = 0} ;
	if (! defined ($sql_win32_odbc_dsn)) { $sql_win32_odbc_dsn = ''} ;
	if (! defined ($sql_win32_odbc_table)) { $sql_win32_odbc_table = ''} ;
	if (! defined ($sql_win32_odbc_username)) { $sql_win32_odbc_username = ''} ;
	if (! defined ($sql_win32_odbc_password)) { $sql_win32_odbc_password = ''} ;
	if (! defined ($DEBUGGING)) { $DEBUGGING = 0} ;
	if (! defined ($DEBUGGING_FILE)) { $DEBUGGING_FILE = ''} ;

	# Make sure it's at least 3 characters, and remove quotes around wildcard_expansion_separator
	if (length ($wildcard_expansion_separator) < 3)
	{
	  $wildcard_expansion_separator = "x x";
	}
	$wildcard_expansion_separator = substr($wildcard_expansion_separator,1,(length($wildcard_expansion_separator)-2));	
	#
	# Defaults End
	# 
	
	# print "Config file loaded\n";
	
	# 
	# Load config file end
	# 
	##############################################################################
}

sub signal_handler_reload {
	#
	# Daemon reload
	#
	$timetoreload = 1;
}

sub signal_handler_die {
	#
	# Daemon die
	#
	$timetodie = 1;
}

sub syslog_system {
  my $message = $_[0];
  if (Sys::Syslog::openlog('snmptt-sys[' . $> . ']', '',$syslog_system_facility) )
  {
    Sys::Syslog::syslog ($syslog_system_level, $message,1);
    Sys::Syslog::closelog();
  }
  else
  {
    warn "Can not open log_file: $!";
  }
}

sub eventlog_system {
  my $message = $_[0];
  my $eventid = $_[1];
  my $type = $_[2];
  my $trap_log = $_[3];		# Should be 1 if this is a trap log.  Used
  				# to set $trap_successfully_logged variable below.

  my %event_entry = ('Source' => "SNMPTT",
  		     'EventType' => $type,
		     'Category' => NULL,
		     'EventID' => $eventid,
		     'Strings' => $message);
  
  if (my $eventlog=Win32::EventLog->new('Application') )
  {
    unless ($eventlog->Report(\%event_entry) )
    {
      warn "Can not create event log entry: $!";
      $eventlog->Close();
      return 1;
    }
    $eventlog->Close();
    return 0;
  }
  else
  {
    warn "Can not open log_file: $!";
    return 1;
  }
}  
  
sub checkip
{
  my $node1 = $_[0];		# Should be a plain IP address
  my $node2 = $_[1];		# Can be a plain IP address, CIDR or range

  # Remove all white space
  $node1 =~ s/\s*//g;
  $node2 =~ s/\s*//g;
  
  # Check for an exact match
  if ($node1 eq $node2)
  {
    return 1;
  }

  #print "node1:$node1\n";
  
  # First is an IP address, and second IP address is a CIDR address
  if ($node1 =~ /^\d+\.\d+\.\d+\.\d+$/ && $node2 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/)
  {   
    # Get IP address in binary
    $node1 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/;
    my $node1_binary = dec2bin($1) . dec2bin($2) .dec2bin($3) .dec2bin($4);
    
    # Get CIDR network address in binary
    $node2 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)\/(\d+)/;
    my $cidr_binary = dec2bin($1) . dec2bin($2) .dec2bin($3) .dec2bin($4);
    my $net_bits = $5;
    my $host_bits = 32 - $net_bits;
    $cidr_binary = substr($cidr_binary, 0, $net_bits);
    
    # Get network number for ip_address
    my $node1_binary_net = substr($node1_binary, 0, $net_bits);
    
    if ($node1_binary_net eq $cidr_binary)
    {
      return 1;
    }
    else
    {
      return 0;
    }
  }
  # First is an IP address, and second IP address is a network range
  elsif ($node1 =~ /^\d+\.\d+\.\d+\.\d+$/ && $node2 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)\.(\d+)/)
  {
    # Get IP address in binary
    $node1 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/;
    my $node1_binary = dec2bin($1) . dec2bin($2) .dec2bin($3) .dec2bin($4);
    
    # Get left network address in binary
    $node2 =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)-(\d+)\.(\d+)\.(\d+)\.(\d+)/;
    my $left_binary = dec2bin($1) . dec2bin($2) .dec2bin($3) .dec2bin($4);
    my $right_binary = dec2bin($5) . dec2bin($6) .dec2bin($7) .dec2bin($8);
    
    if (bin2dec($node1_binary) >= bin2dec($left_binary) &&
    	bin2dec($node1_binary) <= bin2dec($right_binary))
    {
      return 1;
    }
    else
    {
      return 0;
    }
  }
  # Didn't match at all, so return 0.
  else
  {
	  return 0;
  }

}

sub dec2bin {
    my $str = unpack("B8", pack("C", shift));
    #$str =~ s/^0+(?=\d)//;   # otherwise you'll get leading zeros
    return $str;
}

sub bin2dec {
    return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}

sub translate_value_oids_sub
{
  my $string = $_[0];

  if ($string =~ /\.\d+/)	# If it appears to contain an OID
  {
    if ($DEBUGGING >= 2)
    {
      print "  Value appears to contain an OID or IP address.\n";
    }
    my $string_temp = $string;
    my @oids = ();
    my $done = 1;
    my $noinf = 0;

    # Find any IP addresses and remove from $string_temp
    
    $noinf = 0;
    while ($done)
    {
      if ($string_temp =~ /(?<!\.)(?<!\d)(\d+\.\d+\.\d+\.\d+)(?!\.\d)(?!\d)/ ) { $found = 1; }
      #if ($string_temp =~ /(?<!\.)(\d+\.\d+\.\d+\.\d+)(?!\.)/ ) { $found = 1; }
      else { $found = 0; }

      if ($found)
      {
	#print "ip:$&\n";
	$string_temp =~ s/(?<!\.)$1(?!\.)//g;	# Remove IP from string_temp
      }
      else
      {
	$done = 0;
      }
      $noinf++;
      if ($noinf >= 100) # Safe guard to make sure regex pattern search / replace doesn't cause an
                         # infinit loop in the while.  Shouldn't, but just in case..
      {
	$done = 0;
        if ($DEBUGGING >= 2)
        {
          print "  Possible infinit loop (1) in translate_value_oids_sub averted.\n";
        }
      }
    }

    # Find all the OIDs and put them in a @oids array, and remove from $string_temp
    $done = 1;
    my $oid_found = 0;
    $noinf = 0;
    while ($done)
    {   
      if ($string_temp =~ /(?<!\d)(\.\d+)+/) {	$found = 1; }  # don't match n.n.n but do match .n.n.n
      else { $found = 0; }

      if ($found)
      {
	my $oid = $&;
	push (@oids, $oid);
	#print "oid:$oid\n";
	#print "\$string_temp before: $string_temp\n";
	$string_temp =~ s/(?<!\d)$oid(?!\.\d)//g;	# Remove OID from string_temp
	#print "\$string_temp after : $string_temp\n";
	$oid_found = 1;
      }
      else
      {
	$done = 0;
      }
      $noinf++;
      if ($noinf >= 100) # Safe guard to make sure regex pattern search / replace doesn't cause an
                         # infinit loop in the while.  Shouldn't, but just in case..
      {
	$done = 0;
        if ($DEBUGGING >= 2)
        {
          print "  Possible infinit loop (2) in translate_value_oids_sub averted.\n";
        }
      }
    }

    if ($oid_found == 1 && $DEBUGGING >= 2)
    {
      print "  Value contains an OID.\n";
    }
    
    # Reverse sort the list to make sure large OIDs are done first, so we don't get half
    # converted OIDs.  Probably not needed due to look ahead and behind expression below
    @oids = reverse sort(@oids);
 
    #print "oids: @oids\n";
     
    # Replace all OIDs in $string with textual names if possible
    foreach my $oid (@oids)
    {
      my $temp = my_translateObj($oid,$translate_value_oids);
      if (defined ($temp))
      {
	$string =~ s/(?<!\.|\d)$oid(?!\.\d)/$temp/g;
	if ($oid_found == 1 && $DEBUGGING >= 2)
	{
	  print "    OID: $oid=$temp\n";
	}
      }
    }
  }
  else
  {
    if ($DEBUGGING >= 2)
    {
      print "  Value does not appear to contain an OID\n";
    }
  }
  # Return the new string
  return $string;    
}

sub resolve_value_ip_addresses_sub
{
  my $string = $_[0];

  if ($string =~ /(?<!\.)(\d+\.\d+\.\d+\.\d+)(?!\.)/)	# If it appears to contain an IP address
  {
    if ($DEBUGGING >= 2)
    {
      print "  Value appears to contain an IP address.\n";
    }
    my $string_temp = $string;
    my @hostnames = ();
    my $done = 1;
    my $noinf = 0;

    # Find any IP addresses and put them in a @oids array, and remove from $string_temp
    
    $done = 1;
    my $hostname_found = 0;
    $noinf = 0;
    while ($done)
    {
      if ($string_temp =~ /(?<!\.)(?<!\d)(\d+\.\d+\.\d+\.\d+)(?!\.\d)(?!\d)/ ) { $found = 1; }
      #if ($string_temp =~ /(?<!\.)(\d+\.\d+\.\d+\.\d+)(?!\.)/ ) { $found = 1; }
      else { $found = 0; }

      if ($found)
      {
	my $hostname = $&;
	push (@hostnames, $hostname);
	#print "ip:$&\n";
	$string_temp =~ s/(?<!\.)$1(?!\.)//g;	# Remove IP from string_temp
	$hostname_found = 1;
      }
      else
      {
	$done = 0;
      }
      $noinf++;
      if ($noinf >= 100) # Safe guard to make sure regex pattern search / replace doesn't cause an
                         # infinit loop in the while.  Shouldn't, but just in case..
      {
	$done = 0;
        if ($DEBUGGING >= 2)
        {
          print "  Possible infinit loop (1) in resolve_value_ip_addresses_sub averted.\n";
        }
      }
    }

    if ($hostname_found == 1 && $DEBUGGING >= 2)
    {
      print "  Value contains an IP address.\n";
    }
    
    #print "hostnames: @hostnames\n";
     
    # Replace all ip addresses in $string with textual names if possible
    foreach my $hostname (@hostnames)
    {
      my $temp = gethostbyaddr(Socket::inet_aton($hostname),Socket::AF_INET());
      if (defined ($temp))
      {
	if ($DEBUGGING => 2)
	{
	  print "    IP address ($hostname) resolved to: $temp\n";
	}
	if ($strip_domain)
	{
	  $temp = strip_domain_name($temp, $strip_domain);
	}
	$string =~ s/(?<!\.|\d)$hostname(?!\.\d)/$temp/g;
      }
      else
      {
	if ($DEBUGGING => 2)
	{
	  print "    IP address ($hostname) could not be resolved by DNS.\n";
	}
      }
    }
  }
  else
  {
    if ($DEBUGGING >= 2)
    {
      print "  Value does not appear to contain an IP address\n";
    }
  }
  # Return the new string
  return $string;    
}

sub match
{
  my $match = shift;
  my $value;
  my $not = 0;
  my $result = 0;

  $match =~ /^\$(\d+):(.*)/;
  $value = $entvar[$1-1];
  $match = $2;

  if ($value eq '' || $match eq '')
  {
    return 0;
  }
  if ($match =~ /^\!(.*)/) 
  {
    $not = 1;
    $match = $1;
  }
  else 
  {  
    $not = 0; 
  }
  
  # Match is a REGEX
  if ($match =~ /\(.*\)/)
  {
    #print "Regex detected\n";
      
    $result = match_regex($value, $match);
    $result = match_result($result, $not);
    if ($DEBUGGING >= 1)
    {
      print "    REGEX: value=$value, match=" . ($not == 1 ? "!$match" : "$match") . " Result=" . 
             ($result == 1 ? "true" : "false") . "\n";
    }
  }
  # Match is an IP address
  elsif ($match =~ /\d+\.\d+\.\d+\.\d+/)
  {
    #print "IP address of some sort\n";
    $result = checkip($value, $match);
    $result = match_result($result, $not);
    if ($DEBUGGING >= 1)
    {
      print "    IP ADDRESS: value=$value, match=" . ($not == 1 ? "!$match" : "$match") . " Result=" . 
             ($result == 1 ? "true" : "false") . "\n";
    }
  }
  # Match is a number
  elsif ($match =~ /\d+/)
  {
    #print "Number detected\n";
    $result = match_number($value, $match);
    $result = match_result($result, $not);
    if ($DEBUGGING >= 1)
    {
      print "    NUMBER: value=$value, match=" . ($not == 1 ? "!$match" : "$match") . " Result=" . 
             ($result == 1 ? "true" : "false") . "\n";
    }
  }
  # Unknown entry - ignore it
  else
  {
    if ($DEBUGGING >= 1)
    {
      print "    IGNORED: value=$value, match=" . ($not == 1 ? "!$match" : "$match") . "\n";
      $result = 0;
    }
  }
  
  if ($result == 1)
  {
    #print "true\n";
    return 1;
  }
  else
  {
    #print "false\n";
    return 0;
  }
}

sub match_result
{
  my $result = shift;
  my $not = shift;

  if ($not == 0)
  {
    return $result;
  }
  else
  {
    if ($result >= 1)
    {
      return 0;
    }
    else
    {
      return 1;
    }
  }
  return 0;
}

sub match_number
{
  my $value = shift;
  my $match = shift;

  my $result;

  if ($match == $value)
  {
    return 1;
  }
  elsif ($match =~ /,/)
  {
    my @temp = split (",",$match);
    foreach my $a (@temp)
    {
      if ($a == $value)
      {
	return 1;
      }
    }
  }
  elsif ($match =~ /^\>(.*)/)
  {
    if ($value > $1)
    {
      return 1;
    }
  }
  elsif ($match =~ /^\<(.*)/)
  {
    if ($value < $1)
    {
      return 1;
    }
  }
  elsif ($match =~/(\d+)-(\d+)/)
  {
    if ($value => $1 && $value <= $2)
    {
      return 1;
    }
  }
  return 0;
}

sub match_regex
{
  my $value = shift;
  my $regex_temp = shift;

  my $result;
  my $modifier_i = 0;

  #print "value: $value\n";
  #print "regex: $regex_temp\n";

  if ($regex_temp =~ /i$/)
  {
    #print "! i modifier\n";
    $modifier_i = 1;
  }
  
  $regex_temp =~ /\((.*)\)/;
  $regex_temp = $1;

  #print ":$regex_temp:\n";
       			  
  if ($regex_temp ne '')
  {
    if ($DEBUGGING >= 1)
    {
      print "  Doing REGEX MATCH: ($regex_temp)\n";
    }
    if ($modifier_i == 1)
    {
      if ($value =~ /$regex_temp/i)
      {
	#print "Match!\n";
	return 1;
      }
    }
    else
    {
      if ($value =~ /$regex_temp/)
      {
	#print "Match!\n";
	return 1;
      }
    }
  }
  return 0;
}

sub my_translateObj
{
  my $oid = shift;
  my $mode = shift;
  
  my $use_long = 0;
  my $include_module = 0;
  my $temp;
    
  if ($mode == 1) 	# Short text
  {
    $use_long = 0;
    $include_module = 0;
  }
  elsif ($mode == 2)	# Short module::text
  {
    $use_long = 0;
    $include_module = 1;
  }
  elsif ($mode == 3)	# Long text
  {
    $use_long = 1;
    $include_module = 0;
  }
  elsif ($mode == 4)	# Long module::text
  {
    $use_long = 1;
    $include_module = 1;
  }
  
  $temp = &SNMP::translateObj($oid,$use_long,$include_module);
  if (defined ($temp))
  {
    # If it ends in a single ., chop it off
    if ($temp =~ /\.$/)
    {
      chop $temp;
    }
  }
  return $temp;	# Will be either the translated trap, or undef if translateObj failed
}

# Strip domain name from hostname
sub strip_domain_name
{
  my $name = shift;
  my $mode = shift;

  # If mode = 1, strip off all domain names leaving only the host
  if ($mode == 1 && !($name =~ /^\d+\.\d+\.\d+\.\d+$/))
  {
    if ($name =~ /\./)      # Contain a . ?
    {
      $name =~ /^([^\.]+?)\./;
      $name = $1;
    }
  }
  # If mode = 2, strip off the domains as listed in strip_domain_list in .ini file
  elsif ($mode == 2 && !($name =~ /^\d+\.\d+\.\d+\.\d+$/))
  {
    if (defined (@strip_domain_list))
    {
      foreach $strip_domain_list_temp (@strip_domain_list)
      {
	if ($strip_domain_list_temp =~ /^\..*/) # If domain from list starts with a '.' then remove it first
	{
	  ($strip_domain_list_temp) = $strip_domain_list_temp =~ /^\.(.*)/;
	}
	
	if ($name =~ /^.+\.$strip_domain_list_temp/)      # host is something . domain name?	      
	{
	  $name =~ /(.*)\.$strip_domain_list_temp/;	# strip the domain name
	  $name = $1;
	  last;  # Only process once 
	}
      }
    }
  }
  return $name;
}

sub my_getType
{
  my $oid = shift;

  # Problem #1: UCD-SNMP 4.2.3 allows getType and mapEnum to be passed a numerical OID.  
  # Net-SNMP 5.0.8 does not.  Because of this, lets try using the OID first.  If that 
  # fails, then we try the short textual OID instead. 

  my $type = SNMP::getType($oid);
  if (defined($type))
  {
    #print "my_getType: numeric\n";
    return $type;
  }
  else
  {
    my $temp_textOID = &my_translateObj($oid,0);
    #print "temp_textOID:$temp_textOID\n";
    my $type = &SNMP::getType($temp_textOID);
    if (defined($type))
    {
      #print "my_getType: symbolic\n";
      return $type;
    }
    else
    {
      #print "my_getType: failed\n";
      return undef;
    }
  }
}

sub my_mapEnum
{
  my $oid = shift;
  my $value = shift;

  # Problem #1: UCD-SNMP 4.2.3 allows getType and mapEnum to be passed a numerical OID.  
  # Net-SNMP 5.0.8 does not.  Because of this, lets try using the OID first.  If that 
  # fails, then we try the short textual OID instead. 

  my $enum = SNMP::mapEnum($oid, $value);
  if (defined($enum))
  {
    #print "my_mapEnum: numeric\n";
    return $enum;
  }
  else
  {
    my $temp_textOID = &my_translateObj($oid,0);
    #print "temp_textOID:$temp_textOID\n";
    my $enum = &SNMP::mapEnum($temp_textOID, $value);
    if (defined($enum))
    {
      #print "my_mapEnum: symbolic\n";
      return $enum;
    }
    else
    {
      #print "my_mapEnum: failed\n";
      return undef;
    }
  }
}
 
sub process_nodes
{
  my $nodes_list = shift;
  my @nodes = ();
  my @nodes2 = ();

  # print "Processing NODES\n";
  
  # Put all the NODES entries into @nodes, and then go through them all and put
  # them into @nodes2.  This is done so files that are in the NODES list can be
  # read in and merged into @nodes2 to allow a NODES line to contain both host
  # names / ip addresses AND the entries from nodes files.
  @nodes = split /\s/, $nodes_list;
  foreach my $a (@nodes)
  {
    # Contain a \ or /?  Must be a filename and not an IP address / network number
    if ( ($a =~ /\\|\//) && !($a =~ /\d+\.\d+\.\d+\.\d+/))
    {
      if ($dynamic_nodes == 1)		# Dynamic enabled, always load the file
      {	
	#print "!Dynamic enabled\n";
	if (open NODESFILE, $a)
	{
	  while (defined($line = <NODESFILE>))
	  {
	    chomp($line);
	    # Allow comment lines starting with a #
	    if (!($line =~ /((^#)|(\s+#)).*/))
	    {
	      my @temp2 = split /\s/, $line;
	      foreach my $b (@temp2)
	      {
		push (@nodes2, $b);
	      }
	    }
	  }
	  close LOGFILE;
	}
	else
	{
	  warn "Can not open NODES file: $event2[5] $!";
	}
      }
      else				# Not dynamic, so check nodes_file_hash first before loading
      {
	#print "!Dynamic NOT enabled\n";
	if ($nodes_file_hash{$a})
	{
	  push(@nodes2, $nodes_file_hash{$a});
	  #print " !Found in hash\n";
	}
	else
	{
	  #print " !Not found in hash\n";
	  if (open NODESFILE, $a)
	  {
	    while (defined($line = <NODESFILE>))
	    {
	      chomp($line);
	      # Allow comment lines starting with a #
	      if (!($line =~ /((^#)|(\s+#)).*/))
	      {
		my @temp2 = split /\s/, $line;
		foreach my $b (@temp2)
		{
		  push (@nodes2, $b);
		}
	      }
	    }
	    close LOGFILE;
	    $nodes_file_hash{$a} = "@nodes2";
	  }
	  else
	  {
	    warn "Can not open NODES file: $event2[5] $!";
	  }
	}
      }
    }
    else 	# Must be a single node
    {
      push (@nodes2, $a);
    }
  }
  return @nodes2;
}
