#!/usr/local/bin/perl -w
###
### Listen for SNMP traps, decode and print them
### Simple example for a trap listener program.
###
### To make this useful, you should probably add some filtering
### capabilities and trap-specific pretty-printing.
###
package main;

use strict;

use SNMP_Session "0.60";
use BER;
use Socket;

### Forward declarations
sub print_trap ($$);
sub usage ($);

my $port = 162;

while (defined $ARGV[0] && $ARGV[0] =~ /^-/) {
    if ($ARGV[0] eq '-p') {
	shift @ARGV;
	usage (1) unless defined $ARGV[0];
	$port = $ARGV[0];
	usage (1) unless $port > 0 && $port < 65536;
    } elsif ($ARGV[0] eq '-h') {
	usage (0);
	exit 0;
    } else {
	usage (1);
    }
}

my $session = SNMPv1_Session->open_trap_session ($port)
    or die "couldn't open trap session";
$SNMP_Session::suppress_warnings = 1; # We print all error messages ourselves.
my ($trap, $sender, $sender_port);

while (($trap, $sender, $sender_port) = $session->receive_trap ()) {
    print STDERR "received trap from [".inet_ntoa ($sender)."].".$sender_port."\n";
    print_trap ($session, $trap);
}
1;

sub print_trap ($$) {
    my ($this, $trap) = @_;
    my ($encoded_pair, $oid, $value);
    my ($community, $ent, $agent, $gen, $spec, $dt, $bindings)
	= $this->decode_trap_request ($trap);
    if (defined $community) {
	my ($binding, $prefix);
	if (defined $community) {
	    print "    community: ".$community."\n";
	    if (defined $ent) {
		## SNMPv1 Trap
		print "   enterprise: ".BER::pretty_oid ($ent)."\n";
		print "   agent addr: ".inet_ntoa ($agent)."\n";
		print "   generic ID: $gen\n";
		print "  specific ID: $spec\n";
		print "       uptime: ".BER::pretty_uptime_value ($dt)."\n";
	    }
	    ## Otherwise we have an SNMPv1 Trap which basically just
	    ## consists of bindings.
	    ##
	    $prefix = "     bindings: ";
	    while ($bindings) {
		($binding,$bindings) = decode_sequence ($bindings);
		($oid,$value) = decode_by_template ($binding, "%O%@");
		print $prefix.BER::pretty_oid ($oid)." => ".pretty_print ($value)."\n";
		$prefix = "               ";
	    }
	} else {
	    warn "decoding trap request failed:\n".$SNMP_Session::errmsg;
	}
    } else {
	warn "receiving trap request failed:\n".$SNMP_Session::errmsg;
    }
}

sub usage ($) {
    warn <<EOM;
Usage: $0 [-p port]
       $0 -h

  -h           print this usage message and exit.

  -p port      Select the UDP port on which the program will listen
  	       for SNMP traps.  The default port is 162.

EOM
    exit (1) if $_[0];
}
