/*
 * Note: this file originally auto-generated by mib2c using
 *        : mib2c.create-dataset.conf,v 5.2 2002/07/17 14:41:53 dts12 Exp $
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-features.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "mteTriggerTable.h"
#include "mteEventTable.h"
#include "mteEventNotificationTable.h"
#include "mteObjectsTable.h"

netsnmp_feature_require(table_dataset);
netsnmp_feature_require(table_set_multi_add_default_row);

static netsnmp_table_data_set *table_set = NULL;

/** Initialize the mteEventTable table by defining its contents and how it's structured */
void
initialize_table_mteEventTable(void)
{
    static oid      mteEventTable_oid[] =
        { 1, 3, 6, 1, 2, 1, 88, 1, 4, 2 };
    size_t          mteEventTable_oid_len = OID_LENGTH(mteEventTable_oid);

    /*
     * create the table structure itself 
     */
    table_set = netsnmp_create_table_data_set("mteEventTable");

    /*
     * comment this out or delete if you don't support creation of new rows 
     */
    table_set->allow_creation = 1;
    /* mark the row status column */
    table_set->rowstatus_column = COLUMN_MTEEVENTENTRYSTATUS;

    /***************************************************
     * Adding indexes
     */
    DEBUGMSGTL(("initialize_table_mteEventTable",
                "adding indexes to table mteEventTable\n"));
    netsnmp_table_set_add_indexes(table_set,
                                  ASN_OCTET_STR,   /* index: mteOwner */
                                  ASN_PRIV_IMPLIED_OCTET_STR, /* index: mteEventName */
                                  0);

    DEBUGMSGTL(("initialize_table_mteEventTable",
                "adding column types to table mteEventTable\n"));
    netsnmp_table_set_multi_add_default_row(table_set,
                                            COLUMN_MTEEVENTNAME,
                                            ASN_OCTET_STR, 0, NULL, 0,
                                            COLUMN_MTEEVENTCOMMENT,
                                            ASN_OCTET_STR, 1, NULL, 0,
                                            COLUMN_MTEEVENTACTIONS,
                                            ASN_OCTET_STR, 1, NULL, 0,
                                            COLUMN_MTEEVENTENABLED,
                                            ASN_INTEGER, 1, NULL, 0,
                                            COLUMN_MTEEVENTENTRYSTATUS,
                                            ASN_INTEGER, 1, NULL, 0, 0);

    /* keep index values around for comparisons later */
    table_set->table->store_indexes = 1;
    /*
     * registering the table with the master agent 
     */
    /*
     * note: if you don't need a subhandler to deal with any aspects
     * of the request, change mteEventTable_handler to "NULL" 
     */
    netsnmp_register_table_data_set(netsnmp_create_handler_registration
                                    ("mteEventTable",
                                     mteEventTable_handler,
                                     mteEventTable_oid,
                                     mteEventTable_oid_len,
                                     HANDLER_CAN_RWRITE), table_set, NULL);
}

/** Initializes the mteEventTable module */
void
init_mteEventTable(void)
{

    /*
     * here we initialize all the tables we're planning on supporting 
     */
    initialize_table_mteEventTable();

    snmpd_register_config_handler("notificationEvent", parse_notificationEvent,
                                  NULL,
                                  "notificationEvent NAME TRAP_OID [[-w] EXTRA_OID ...]");

    snmpd_register_config_handler("linkUpDownNotifications",
                                  parse_linkUpDownNotifications,
                                  NULL,
                                  "linkUpDownNotifications (yes|no)");
}

/** handles requests for the mteEventTable table, if anything else needs to be done */
int
mteEventTable_handler(netsnmp_mib_handler *handler,
                      netsnmp_handler_registration *reginfo,
                      netsnmp_agent_request_info *reqinfo,
                      netsnmp_request_info *requests)
{
    /*
     * perform anything here that you need to do.  The requests have
     * already been processed by the master table_dataset handler, but
     * this gives you chance to act on the request in some other way
     * if need be. 
     */

    /* XXX: on rowstatus = destroy, remove the corresponding rows from the
       other tables: snmpEventNotificationTable and the set table */
    return SNMP_ERR_NOERROR;
}

void
parse_linkUpDownNotifications(const char *token, char *line) {
    if (strncmp(line, "y", 1) == 0) {
        parse_notificationEvent("notificationEvent", "linkUpTrap   	 linkUp     ifIndex ifAdminStatus ifOperStatus");
        parse_notificationEvent("notificationEvent", "linkDownTrap 	 linkDown   ifIndex ifAdminStatus ifOperStatus");

        parse_simple_monitor("monitor", "-r 60 -e linkUpTrap \"Generate linkUp\" ifOperStatus != 2");
        parse_simple_monitor("monitor", "-r 60 -e linkDownTrap \"Generate linkDown\" ifOperStatus == 2");
    }
}

void
parse_notificationEvent(const char *token, char *line) {
    char            name_buf[64];
    char            oid_name_buf[SPRINT_MAX_LEN];
    oid             oid_buf[MAX_OID_LEN];
    size_t          oid_buf_len = MAX_OID_LEN;
    int             wild = 1;
    netsnmp_table_row *row;
    long tlong;
    char tc;

    /* get the owner */
    const char *owner = "snmpd.conf";

    /* get the name */
    char *cp = copy_nword(line, name_buf, SPRINT_MAX_LEN);

    if (!cp || name_buf[0] == '\0') {
        config_perror("syntax error.");
        return;
    }

    for(row = table_set->table->first_row; row; row = row->next) {
        if (strcmp(row->indexes->val.string, owner) == 0 &&
            strcmp(row->indexes->next_variable->val.string,
                   name_buf) == 0) {
            config_perror("An eventd by that name has already been defined.");
            return;
        }
    }

    /* now, get all the trap oid */
    cp = copy_nword(cp, oid_name_buf, SPRINT_MAX_LEN);

    if (oid_name_buf[0] == '\0') {
        config_perror("syntax error.");
        return;
    }
    if (!snmp_parse_oid(oid_name_buf, oid_buf, &oid_buf_len)) {
        snmp_log(LOG_ERR,"namebuf: %s\n",oid_name_buf);
        config_perror("unable to parse trap oid");
        return;
    }

    /*
     * add to the mteEventNotificationtable to point to the
     * notification and the objects.
     */
    row = netsnmp_create_table_data_row();

    /* indexes */
    netsnmp_table_row_add_index(row, ASN_OCTET_STR, owner, strlen(owner));
    netsnmp_table_row_add_index(row, ASN_PRIV_IMPLIED_OCTET_STR,
                                name_buf, strlen(name_buf));


    /* columns */
    netsnmp_set_row_column(row, COLUMN_MTEEVENTNOTIFICATION, ASN_OBJECT_ID,
                           (char *) oid_buf, oid_buf_len * sizeof(oid));
    netsnmp_set_row_column(row, COLUMN_MTEEVENTNOTIFICATIONOBJECTSOWNER,
                           ASN_OCTET_STR, owner, strlen(owner));
    netsnmp_set_row_column(row, COLUMN_MTEEVENTNOTIFICATIONOBJECTS,
                           ASN_OCTET_STR, name_buf, strlen(name_buf));

    netsnmp_table_data_add_row(mteEventNotif_table_set->table, row);

    /*
     * add to the mteEventTable to make it a notification to trigger
     * notification and the objects.
     */
    row = netsnmp_create_table_data_row();

    /* indexes */
    netsnmp_table_row_add_index(row, ASN_OCTET_STR, owner, strlen(owner));
    netsnmp_table_row_add_index(row, ASN_PRIV_IMPLIED_OCTET_STR,
                                name_buf, strlen(name_buf));


    /* columns */
    tc = (u_char)0x80;
    netsnmp_set_row_column(row, COLUMN_MTEEVENTACTIONS, ASN_OCTET_STR,
                           &tc, 1);
    tlong = MTETRIGGERENABLED_TRUE;
    netsnmp_set_row_column(row, COLUMN_MTEEVENTENABLED,
                           ASN_INTEGER, (char *) &tlong, sizeof(tlong));
    tlong = RS_ACTIVE;
    netsnmp_set_row_column(row, COLUMN_MTEEVENTENTRYSTATUS,
                           ASN_INTEGER, (char *) &tlong, sizeof(tlong));

    netsnmp_table_data_add_row(table_set->table, row);
    
    /*
     * now all the objects to put into the trap's object row
     */
    while(cp) {
        cp = copy_nword(cp, oid_name_buf, SPRINT_MAX_LEN);
        if (strcmp(oid_name_buf, "-w") == 0) {
            wild = 0;
            continue;
        }
        oid_buf_len = MAX_OID_LEN;
        if (!snmp_parse_oid(oid_name_buf, oid_buf, &oid_buf_len)) {
            config_perror("unable to parse an object oid");
            return;
        }
        mte_add_object_to_table("snmpd.conf", name_buf,
                                oid_buf, oid_buf_len, wild);
        wild = 1;
    }
}

/*
 * send trap 
 */
void
run_mte_events(struct mteTriggerTable_data *item,
               oid * name_oid, size_t name_oid_len,
               const char *eventobjowner, const char *eventobjname)
{
    static oid      objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };     /* snmpTrapIOD.0 */

    netsnmp_variable_list *var_list = NULL;

    netsnmp_table_row *row, *notif_row;
    netsnmp_table_data_set_storage *col1, *tc, *no, *noo;

    for(row = table_set->table->first_row; row; row = row->next) {
        if (strcmp(row->indexes->val.string, eventobjowner) == 0 &&
            strcmp(row->indexes->next_variable->val.string,
                   eventobjname) == 0) {
            /* run this event */
            col1 = (netsnmp_table_data_set_storage *) row->data;
            
            tc = netsnmp_table_data_set_find_column(col1,
                                                    COLUMN_MTEEVENTACTIONS);
            if (!(tc->data.bitstring[0] & 0x80)) {
                /* not a notification.  next! (XXX: do sets) */
                continue;
            }

            tc = netsnmp_table_data_set_find_column(col1,
                                                    COLUMN_MTEEVENTENABLED);
            if (*(tc->data.integer) != 1) {
                /* not enabled.  next! */
                continue;
            }

            if (!mteEventNotif_table_set) {
                /* no notification info */
                continue;
            }

            /* send the notification */
            var_list = NULL;

            /* XXX: get notif information */
            for(notif_row = mteEventNotif_table_set->table->first_row;
                notif_row; notif_row = notif_row->next) {
                if (strcmp(notif_row->indexes->val.string,
                           eventobjowner) == 0 &&
                    strcmp(notif_row->indexes->next_variable->val.string,
                           eventobjname) == 0) {

                    /* run this event */
                    col1 = (netsnmp_table_data_set_storage *) notif_row->data;
            
                    tc = netsnmp_table_data_set_find_column(col1, COLUMN_MTEEVENTNOTIFICATION);
                    no = netsnmp_table_data_set_find_column(col1, COLUMN_MTEEVENTNOTIFICATIONOBJECTS);
                    noo = netsnmp_table_data_set_find_column(col1, COLUMN_MTEEVENTNOTIFICATIONOBJECTSOWNER);
                    if (!tc)
                        continue; /* no notification to be had. XXX: return? */
                    
                    /*
                     * snmpTrap oid 
                     */
                    snmp_varlist_add_variable(&var_list, objid_snmptrap,
                                              sizeof(objid_snmptrap) /
                                              sizeof(oid),
                                              ASN_OBJECT_ID,
                                              (u_char *) tc->data.objid,
                                              tc->data_len);

                    /* XXX: add objects from the mteObjectsTable */
                    DEBUGMSGTL(("mteEventTable:send_events", "no: %x, no->data: %s", no, no->data.string));
                    DEBUGMSGTL(("mteEventTable:send_events", "noo: %x, noo->data: %s", noo, noo->data.string));
                    DEBUGMSGTL(("mteEventTable:send_events", "name_oid: %x",name_oid));
                    if (no && no->data.string &&
                        noo && noo->data.string && name_oid) {
                        char *tmpowner =
                            netsnmp_strdup_and_null(noo->data.string,
                                                    noo->data_len);
                        char *tmpname =
                            netsnmp_strdup_and_null(no->data.string,
                                                    no->data_len);

                        DEBUGMSGTL(("mteEventTable:send_events", "Adding objects for owner=%s name=%s", tmpowner, tmpname));
                        mte_add_objects(var_list, item,
                                        tmpowner, tmpname, 
                                       name_oid + item->mteTriggerValueIDLen,
                                        name_oid_len - item->mteTriggerValueIDLen);
                        free(tmpowner);
                        free(tmpname);
                    }

                    DEBUGMSGTL(("mteEventTable:send_events", "sending an event "));
                    DEBUGMSGOID(("mteEventTable:send_events", tc->data.objid, tc->data_len / sizeof(oid)));
                    DEBUGMSG(("mteEventTable:send_events", "\n"));
                    
                    send_v2trap(var_list);
                    snmp_free_varbind(var_list);
                }
            }
        }
    }
}
