/*
 * Note: this file originally auto-generated by mib2c using
 *        : mib2c.iterate.conf,v 1.5 2001/12/04 21:36:27 hardaker Exp $
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "nsModuleTable.h"

void
nsModuleTable_free(void *context, netsnmp_iterator_info *dont_care)
{
    free(context);
}
    
/** Initialize the nsModuleTable table by defining it's contents and how it's structured */
void
initialize_table_nsModuleTable(void)
{
    static oid      nsModuleTable_oid[] =
        { 1, 3, 6, 1, 4, 1, 8072, 1, 2, 1 };
    netsnmp_table_registration_info *table_info;
    netsnmp_handler_registration *my_handler;
    netsnmp_iterator_info *iinfo;

    /*
     * create the table structure itself 
     */
    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
    iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);

    /*
     * if your table is read only, it's easiest to change the
     * HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY 
     */
    my_handler = netsnmp_create_handler_registration("nsModuleTable",
                                                     nsModuleTable_handler,
                                                     nsModuleTable_oid,
                                                     OID_LENGTH
                                                     (nsModuleTable_oid),
                                                     HANDLER_CAN_RWRITE);

    if (!my_handler || !table_info || !iinfo) {
        if (my_handler)
            netsnmp_handler_registration_free(my_handler);
        SNMP_FREE(table_info);
        SNMP_FREE(iinfo);
        return;                 /* mallocs failed */
    }

    /***************************************************
     * Setting up the table's definition
     */
    netsnmp_table_helper_add_indexes(table_info, ASN_OCTET_STR, /* context name */
                                     ASN_OBJECT_ID,     /* reg point */
                                     ASN_INTEGER,       /* priority */
                                     0);

    table_info->min_column = 4;
    table_info->max_column = 6;

    /*
     * iterator access routines 
     */
    iinfo->get_first_data_point = nsModuleTable_get_first_data_point;
    iinfo->get_next_data_point = nsModuleTable_get_next_data_point;
    iinfo->free_loop_context_at_end = nsModuleTable_free;
    iinfo->table_reginfo = table_info;

    /***************************************************
     * registering the table with the master agent
     */
    DEBUGMSGTL(("initialize_table_nsModuleTable",
                "Registering table nsModuleTable as a table iterator\n"));
    netsnmp_register_table_iterator(my_handler, iinfo);
}

/** Initialzies the nsModuleTable module */
void
init_nsModuleTable(void)
{

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

/** returns the first data point within the nsModuleTable table data.

    Set the my_loop_context variable to the first data point structure
    of your choice (from which you can find the next one).  This could
    be anything from the first node in a linked list, to an integer
    pointer containing the beginning of an array variable.

    Set the my_data_context variable to something to be returned to
    you later that will provide you with the data to return in a given
    row.  This could be the same pointer as what my_loop_context is
    set to, or something different.

    The put_index_data variable contains a list of snmp variable
    bindings, one for each index in your table.  Set the values of
    each appropriately according to the data matching the first row
    and return the put_index_data variable at the end of the function.
*/
typedef struct context_tree_ptr_s {
    netsnmp_subtree *tree;
    subtree_context_cache *context_ptr;
} context_tree_ptr;

netsnmp_variable_list *
nsModuleTable_get_first_data_point(void **my_loop_context,
                                   void **my_data_context,
                                   netsnmp_variable_list * put_index_data,
                                   netsnmp_iterator_info *otherstuff)
{

    struct variable_list *vptr;
    u_long          ultmp;
    context_tree_ptr *ctree;

    ctree = SNMP_MALLOC_TYPEDEF(context_tree_ptr);

    ctree->context_ptr = get_top_context_cache();
    /* Skip empty context registrations */
    while (!ctree->context_ptr->first_subtree) {
        ctree->context_ptr = ctree->context_ptr->next;
        if (!ctree->context_ptr) {
            SNMP_FREE(ctree);
            return NULL;
        }
    }
    ctree->tree = ctree->context_ptr->first_subtree;

    *my_loop_context = ctree;
    *my_data_context = ctree->tree;

    vptr = put_index_data;
    snmp_set_var_value(vptr, (u_char *) ctree->context_ptr->context_name,
                       strlen(ctree->context_ptr->context_name));

    vptr = vptr->next_variable;
    snmp_set_var_value(vptr,
                       (u_char *)ctree->context_ptr->first_subtree->name_a,
                       ctree->context_ptr->first_subtree->namelen *
                       sizeof(oid));

    ultmp = ctree->context_ptr->first_subtree->priority;
    vptr = vptr->next_variable;
    snmp_set_var_value(vptr, (u_char *) & ultmp, sizeof(ultmp));

    return put_index_data;
}

/** functionally the same as nsModuleTable_get_first_data_point, but
   my_loop_context has already been set to a previous value and should
   be updated to the next in the list.  For example, if it was a
   linked list, you might want to cast it and the return
   my_loop_context->next.  The my_data_context pointer should be set
   to something you need later and the indexes in put_index_data
   updated again. */

struct variable_list *
nsModuleTable_get_next_data_point(void **my_loop_context,
                                  void **my_data_context,
                                  struct variable_list *put_index_data,
                                  netsnmp_iterator_info *otherstuff)
{

    struct variable_list *vptr;
    context_tree_ptr *ctree = (context_tree_ptr *) * my_loop_context;
    u_long          ultmp;

    if (ctree->tree->next)
        ctree->tree = ctree->tree->next;
    else {
        ctree->context_ptr = ctree->context_ptr->next;
        if (!ctree->context_ptr) {
            return NULL;
        }
        ctree->tree = ctree->context_ptr->first_subtree;
    }

    *my_data_context = ctree->tree;

    vptr = put_index_data;
    snmp_set_var_value(vptr, (u_char *) ctree->context_ptr->context_name,
                       strlen(ctree->context_ptr->context_name));

    vptr = vptr->next_variable;
    snmp_set_var_value(vptr, (u_char *) ctree->tree->name_a,
                       ctree->tree->namelen * sizeof(oid));

    ultmp = ctree->tree->priority;
    vptr = vptr->next_variable;
    snmp_set_var_value(vptr, (u_char *) & ultmp, sizeof(ultmp));

    return put_index_data;
}

/** handles requests for the nsModuleTable table, if anything else needs to be done */
int
nsModuleTable_handler(netsnmp_mib_handler *handler,
                      netsnmp_handler_registration *reginfo,
                      netsnmp_agent_request_info *reqinfo,
                      netsnmp_request_info *requests)
{

    netsnmp_table_request_info *table_info;
    netsnmp_request_info *request;
    netsnmp_variable_list *var;
    netsnmp_subtree *tree;
    u_long          ultmp;
    u_char          modes[1];

    for (request = requests; request; request = request->next) {
        var = request->requestvb;
        if (request->processed != 0)
            continue;

        /*
         * perform anything here that you need to do.  The request 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. 
         */

        /*
         * the following extracts the my_data_context pointer set in the
         * loop functions above.  You can then use the results to help
         * return data for the columns of the nsModuleTable table in
         * question 
         */
        tree = (netsnmp_subtree *)netsnmp_extract_iterator_context(request);
        if (tree == NULL) {
            if (reqinfo->mode == MODE_GET) {
                netsnmp_set_request_error(reqinfo, request,
                                          SNMP_NOSUCHINSTANCE);
                continue;
            }
            /*
             * XXX: no row existed, if you support creation and this is a
             * set, start dealing with it here, else continue 
             */
        }

        /*
         * extracts the information about the table from the request 
         */
        table_info = netsnmp_extract_table_info(request);

        /*
         * table_info->colnum contains the column number requested 
         */
        /*
         * table_info->indexes contains a linked list of snmp variable
         * bindings for the indexes of the table.  Values in the list have 
         * been set corresponding to the indexes of the request 
         */
        if (table_info == NULL) {
            continue;
        }

        switch (reqinfo->mode) {
            /*
             * the table_iterator helper should change all GETNEXTs into
             * GETs for you automatically, so you don't have to worry
             * about the GETNEXT case.  Only GETs and SETs need to be
             * dealt with here 
             */
        case MODE_GET:
            switch (table_info->colnum) {
            case COLUMN_NSMODULENAME:
		if (tree->reginfo->handlerName) {
                    snmp_set_var_typed_value(var, ASN_OCTET_STR,
                                           tree->reginfo->handlerName,
                                           strlen(tree->reginfo->handlerName));
                } else {
                    snmp_set_var_typed_value(var, ASN_OCTET_STR, "", 0);
		}
                break;

            case COLUMN_NSMODULEMODES:
                /*
                 * basically, these BITS needs to be inverted in order 
                 */
                modes[0] =
                    ((HANDLER_CAN_GETANDGETNEXT & tree->reginfo->
                      modes) << 7) | ((HANDLER_CAN_SET & tree->reginfo->
                                       modes) << 5) | ((HANDLER_CAN_GETBULK
                                                        & tree->reginfo->
                                                        modes) << 3);
		/*  yuck  */
                snmp_set_var_typed_value(var, ASN_OCTET_STR, modes, 1);
                break;

            case COLUMN_NSMODULETIMEOUT:
                ultmp = tree->timeout;
                snmp_set_var_typed_value(var, ASN_INTEGER,
                                         (u_char *) & ultmp,
                                         sizeof(u_long));
                break;

            default:
                /*
                 * We shouldn't get here 
                 */
                snmp_log(LOG_ERR,
                         "problem encountered in nsModuleTable_handler: unknown column\n");
            }
            break;

        default:
            snmp_log(LOG_ERR,
                     "problem encountered in nsModuleTable_handler: unsupported mode\n");
        }
    }
    return SNMP_ERR_NOERROR;
}
