//
// Copyright (C) 2000 Shivakumar C. Patil <shivakumar.patil@stdc.com>
//  
// 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.
// 
// Tab Size = 8
//
// $Id: snmpd.java,v 1.1 2000/06/08 17:19:47 weave Exp $
//
// Log:
//  06/08/00 - Brian Weaver <weave@opennms.org>
//      Commented and added file to CVS
//
// Adapted from trapd 9/8/00 by Bob Snider <bsnider@seekone.com>

package org.opennms.test;

import java.lang.*;
import java.net.*;
import java.util.*;

import org.opennms.protocols.snmp.*;

/**
 * <P>Implements a sample SNMP trap daemon that listens and prints
 * traps received from remote agents on port 162.</P>
 *
 * @author <A HREF="mailto:bsnider@seekone.com">Bob Snider</A>
 * @author <A HREF="mailto:shivakumar.patil@stdc.com">Shivakumar C. Patil</A>
 * @author <A HREF="mailto:weave@opennms.org">Brian Weaver</A>
 * @author <A HREF="http://www.opennms.org/">OpenNMS</A>
 * @version $Revision: 1.1 $
 */
public class snmpd implements SnmpAgentHandler
{
  /**
   * The main routine. All arguments are ignored. The program
   * will terminate if any error in the trap session occur. However,
   * malformed packets will be discarded in the error handling method
   * of this class.
   *
   * @param args    The command line arguments -- IGNORED.
   */
  public static void main (String args[])
  {
    try
      {
    SnmpAgentSession testTrapSession = new SnmpAgentSession(new snmpd());
    System.out.println("SNMP Agent Started");
    synchronized(testTrapSession)
      {
        testTrapSession.wait();
      }
    System.out.println("SNMP Agent Exiting");
    testTrapSession.close();
      }
    catch (Exception e)
      {
    System.out.println("Exception in main(): " + e);
    e.printStackTrace();
      }
  }
  
  /**
   * Receives and prints information about SNMPv2c traps.
   *
   * @param session The Trap Session that received the PDU.
   * @param agent       The address of the remote sender.
   * @param port        The remote port where the pdu was transmitted from.
   * @param community   The decoded community string.
   * @param pdu     The decoded V2 trap pdu.
   *
   */
  
  // This should probably be refactored into snmpReceivedGet, snmpReceivedSet, etc.....
  public void snmpReceivedPdu(SnmpAgentSession      session, 
                  java.net.InetAddress  manager, 
                  int           port,
                  SnmpOctetString       community,
                  SnmpPduPacket         pdu)
  {
    System.out.println("Message from manager " + manager.toString() + " on port " + port);
    int cmd = pdu.getCommand();
    System.out.println("Unsupported PDU command......... " + cmd);
    //synchronized(session)
    //{
    //  session.notify();
    //}
  }
  
  
  public SnmpPduRequest snmpReceivedGet(SnmpPduPacket pdu, boolean getNext)
  {
    SnmpPduRequest response = null;
    // System.out.println((getNext) ? "GetNext Command":"Get Command");
    int k = pdu.getLength();
    // System.out.println("ID = " + pdu.getRequestId() + " length = " +k);
    SnmpVarBind[] vblist  = new SnmpVarBind[k];
    int errorStatus = SnmpPduPacket.ErrNoError;
    int errorIndex = 0;

    for (int i = 0; i < k ; i++ )
      {
    SnmpVarBind vb = pdu.getVarBindAt(i);
    SnmpObjectId oid = vb.getName();
    if (getNext) {      // simulate the getNext
      int[] oidArray = oid.getIdentifiers();
      int finalId = oidArray[oidArray.length-1];
      if (finalId == 1) {
        oid.append(".2");
      } else if (finalId < 20) {
        oidArray[oidArray.length-1]++;
        oid.setIdentifiers(oidArray);
      }
      else {
        errorStatus = SnmpPduPacket.ErrNoSuchName;
        errorIndex = i+1;
      }
    }
    vblist[i] = new SnmpVarBind(oid);

    vblist[i].setValue(new SnmpInt32(i+1)); // the i is a dummy to do a count
    // System.out.print("Varbind[" + i + "] := " + vblist[i].getName().toString());
    // System.out.println(" --> " + vblist[i].getValue().toString());       
      }
    response = new SnmpPduRequest(SnmpPduPacket.RESPONSE, vblist);
    response.setErrorStatus(errorStatus);
    response.setErrorIndex(errorIndex);
    return response;
  }

  public SnmpPduRequest snmpReceivedSet(SnmpPduPacket pdu)
  {
    SnmpPduRequest response = null;
    // System.out.println("Get Command");
    int k = pdu.getLength();
    // System.out.println("ID = " + pdu.getRequestId() + " length = " +k);
    SnmpVarBind[] vblist  = new SnmpVarBind[k];
    for (int i = 0; i < k ; i++ )
      {
    SnmpVarBind vb = pdu.getVarBindAt(i);
    vblist[i] = new SnmpVarBind(vb);
//      System.out.print("Varbind[" + i + "] := " + vb.getName().toString());
//      System.out.println(" --> " + vb.getValue().toString());     
      }
    response = new SnmpPduRequest(SnmpPduPacket.RESPONSE, vblist);
    return response;
  }

  /**
   * Process session errors.
   *
   * @param session The trap session in error.
   * @param error       The error condition.
   * @param ref     The reference object, if any.
   *
   */
  public void SnmpAgentSessionError(SnmpAgentSession    session,
                    int         error,
                    java.lang.Object    ref)
  {
    System.out.println("An error occured in the trap session");
    System.out.println("Session error code = " + error);
    if(ref != null)
      {
    System.out.println("Session error reference: " + ref.toString());
      }
    
    if(error == SnmpAgentSession.ERROR_EXCEPTION)
      {
    synchronized(session)
      {
        session.notify(); // close the session
      }
      }
  }
}