/*
 * Note: this file originally auto-generated by mib2c using
 *        : mib2c.iterate_access.conf,v 1.11 2004/08/31 10:23:16 dts12 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 "test_handler.h"
#include "snmp_common.h"


static netsnmp_oid_stash_node *undoStorage   = NULL;
static netsnmp_oid_stash_node *commitStorage = NULL;

void initialize_table_TEST_Table(void);
int TEST_Table_handler(netsnmp_mib_handler * handler,
                               netsnmp_handler_registration * reginfo,
                               netsnmp_agent_request_info * reqinfo,
                               netsnmp_request_info * requests);



/** Initializes the TEST_Table module */
void init_TEST_Table(void)
{
    /** here we initialize all the tables we're planning on supporting */
    initialize_table_TEST_Table();
}



/** Initialize the TEST_Table table by defining its contents and how it's structured */
void initialize_table_TEST_Table(void)
{
    static oid TEST_Table_oid[]   = { 1, 3, 6, 1, 4, 1, 21079, 4, 1, 2, 2, 2, 1, 4};
    static int TEST_Table_oid_len = OID_LENGTH(TEST_Table_oid);

    netsnmp_table_registration_info *table_info;
    netsnmp_handler_registration *my_handler;
    netsnmp_iterator_info *iinfo;
    netsnmp_mib_handler *cache_handler;

    /** create the table registration information structures */
    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
    iinfo      = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);

    my_handler = netsnmp_create_handler_registration("TEST_Table",
                                                     TEST_Table_handler,
                                                     TEST_Table_oid,
                                                     TEST_Table_oid_len,
                                                     HANDLER_CAN_RWRITE);

    if (!my_handler || !table_info || !iinfo)
    {
        snmp_log(LOG_ERR, "malloc failed in initialize_table_TEST_Table");
        return; /** Serious error. */
    }

    /***************************************************
     * Setting up the table's definition
     */
    netsnmp_table_helper_add_indexes(table_info,
                                     ASN_PRIV_IMPLIED_OCTET_STR,  /** index: string, fixed length */
                                     ASN_PRIV_IMPLIED_OCTET_STR,  /** index: arr, fixed length */
                                     ASN_UNSIGNED,                /** index: uinteger */
                                     0);

    /** Define the minimum and maximum accessible columns.  This
        optimizes retrival. */
    table_info->min_column = COLUMN_TESTString1;
    table_info->max_column = COLUMN_TESTLASTCHANGED;

    /** iterator access routines */
    iinfo->get_first_data_point = TEST_Table_get_first_data_point;
    iinfo->get_next_data_point  = TEST_Table_get_next_data_point;

    /** you may wish to set these as well */
#ifdef MAYBE_USE_THESE
    iinfo->make_data_context = TEST_Table_context_convert_function;
    iinfo->free_data_context = TEST_Table_data_free;

    /** pick *only* one of these if you use them */
    iinfo->free_loop_context        = TEST_Table_loop_free;
    iinfo->free_loop_context_at_end = TEST_Table_loop_free;
#endif

    /** tie the two structures together */
    iinfo->table_reginfo = table_info;

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

    cache_handler = netsnmp_get_cache_handler(TABLE_TIMEOUT,
                                              TEST_Table_load,
                                              TEST_Table_free,
                                              TEST_Table_oid,
                                              TEST_Table_oid_len);
    if (!cache_handler)
    {
        snmp_log(LOG_ERR, "%s: malloc failed\n", __func__);
        return;         /** Serious error. */
    }

    netsnmp_inject_handler_before(my_handler, cache_handler, TABLE_ITERATOR_NAME);

}


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

    netsnmp_request_info *request;
    netsnmp_table_request_info *table_info;
    netsnmp_variable_list *var;
    struct commitInfo *ci = NULL;

    void *data_context = NULL;

    oid *suffix;
    size_t suffix_len;
    BOOL ok;

    snmp_log(LOG_INFO, "%s\n", __func__);

    /** column and row index encoded portion */
    suffix = requests->requestvb->name + reginfo->rootoid_len + 1;
    suffix_len = requests->requestvb->name_length - (reginfo->rootoid_len + 1);

    for (request = requests; request; request = request->next)
    {
        snmp_log(LOG_INFO, "%s mode %s\n", __func__, SNMP_mode_to_string(reqinfo->mode));

        var = request->requestvb;
        if (request->processed != 0)
        {
            snmp_log(LOG_INFO, "%s: skipping request->processed\n", __func__);
            continue;
        }

        switch (reqinfo->mode)
        {
            case MODE_GET:
                data_context = netsnmp_extract_iterator_context(request);
                if (data_context == NULL)
                {
                    snmp_log(LOG_INFO, "%s: skipping data_context == NULL\n", __func__);
                    netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
                    continue;
                }
                break;

            case MODE_SET_RESERVE1:
                data_context = netsnmp_extract_iterator_context(request);
                if (data_context == NULL)
                {
                    snmp_log(LOG_INFO, "%s: skipping data_context == NULL\n", __func__);
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION);
                    continue;
                }
                break;

            default:           /* == the other SET modes */
                ci = netsnmp_oid_stash_get_data(commitStorage, suffix + 1, suffix_len - 1);
                ok = SNMP_is_valid_commit_info(__func__, ci, reqinfo->mode);
                if (!ok)
                {
                    snmp_log(LOG_INFO, "%s: skipping commit !ok\n", __func__);
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
                    continue;
                }
                break;
        }

        /** 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)
        {
            snmp_log(LOG_INFO, "%s: skipping table_info == NULL\n", __func__);
            continue;
        }

        snmp_log(LOG_INFO, "%s: table_info->column = %d\n", __func__, table_info->colnum);

        switch (reqinfo->mode)
        {
            case MODE_GET:
                switch (table_info->colnum)
                {

                    case COLUMN_TESTString1NAME:
                        {
                            char *retval;
                            size_t retval_len = 0;

                            retval = get_TEST_str1(data_context, &retval_len);
                            if (retval)
                                snmp_set_var_typed_value(var, ASN_OCTET_STR, (const u_char *) retval, retval_len);
                        }
                        break;

                    case COLUMN_TESTArr1:
                        {
                            char *retval;
                            size_t retval_len = 0;

                            retval = get_TEST_arr1(data_context, &retval_len);
                            if (retval)
                                snmp_set_var_typed_value(var, ASN_OCTET_STR, (const u_char *) retval, retval_len);
                        }
                        break;

                    case COLUMN_TESTInt1:
                        {
                            u_long *retval;
                            size_t retval_len = 0;

                            retval = get_TEST_Int1(data_context, &retval_len);
                            if (retval)
                                snmp_set_var_typed_value(var, ASN_UNSIGNED, (const u_char *) retval, retval_len);
                        }
                        break;


                    case COLUMN_TESTUSAGETYPE:
                        {
                            long *retval;
                            size_t retval_len = 0;

                            retval = get_TEST_UsageType(data_context, &retval_len);
                            if (retval)
                                snmp_set_var_typed_value(var, ASN_INTEGER, (const u_char *) retval, retval_len);
                        }
                        break;

                    case COLUMN_TESTEFFECTIVEDATE:
                        {
                            char *retval;
                            size_t retval_len = 0;

                            retval = get_TEST_Date(data_context, &retval_len);
                            if (retval)
                                snmp_set_var_typed_value(var, ASN_OCTET_STR, (const u_char *) retval, retval_len);
                        }
                        break;

 
                    case COLUMN_TEST_LASTCHANGED:
                        {
                        }
                        break;

                    default:
                        /** We shouldn't get here */
                        snmp_log(LOG_ERR, "%s: Unknown column %d\n", __func__, table_info->colnum);
                }
                break;

            case MODE_SET_RESERVE1:
                ci = netsnmp_oid_stash_get_data(commitStorage, suffix + 1, suffix_len - 1);

                if (!ci)
                {
                    ci = SNMP_create_commit_storage_and_row(__func__,
                                                            &commitStorage,
                                                            data_context,
                                                            TEST_Table_create_data_context,
                                                            table_info->indexes,
                                                            suffix+1,
                                                            suffix_len-1);
                    if (!ci)
                        netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
                }
                break;

            case MODE_SET_RESERVE2:
                switch (table_info->colnum)
                {
                    case COLUMN_TESTUSAGETYPE:
                        {
                            long *retval;
                            size_t retval_len = 0;
                            struct undoInfo *ui = NULL;
                            int ret;


                            /** first, get the old value */
                            retval = get_TESTUsageType(ci->data_context, &retval_len);
                            if (retval)
                                ui = SNMP_create_undo_info(__func__, (u_char *)retval, retval_len);

                            /** check the new value, possibly against the
                                older value for a valid state transition */
                            ret = check_TESTUsageType(request->requestvb->type,
                                                      (long *) request->requestvb->val.string,
                                                      request->requestvb->val_len,
                                                      retval, retval_len);
                            if (ret != SNMP_ERR_NOERROR)
                            {
                                netsnmp_set_request_error(reqinfo, request, ret);
                                SNMP_free_undoInfo(ui);
                            }
                            else if (!ui)
                                netsnmp_set_request_error(reqinfo, request, SNMP_ERR_GENERR);
                            else
                                netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui);

                        }
                        break;


                    default:
                        netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE);
                        break;
                }
                break;

            case MODE_SET_ACTION:
                switch (table_info->colnum)
                {
                    case COLUMN_TESTUSAGETYPE:
                        {
                            int ret;

                            ret = set_TESTUsageType(ci->data_context,
                                                    (long *) request->requestvb->val.string, request->requestvb->val_len);

                            if (ret)
                            {
                                netsnmp_set_request_error(reqinfo, request, ret);
                            }
                        }
                        break;
                }
                break;

            case MODE_SET_COMMIT:
                if (!ci->have_committed)
                {
                    /** do this once per row only */
                    TEST_Table_commit_row(&ci->data_context, ci->new_row);
                    ci->have_committed = 1;
                }
                break;

            case MODE_SET_UNDO:
                /** save a variable copy */
                switch (table_info->colnum)
                {
                    case COLUMN_TESTUSAGETYPE:
                        {
                            int retval = SNMP_ERR_UNDOFAILED;
                            struct undoInfo *ui;

                            ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len);
                            if (ui)
                                retval = set_TESTUsageType(ci->data_context, (long *)(ui->ptr), ui->len);
                            if (retval)
                            {
                                netsnmp_set_request_error(reqinfo, request, SNMP_ERR_UNDOFAILED);
                            }
                        }
                        break;

                }
                break;

            case MODE_SET_FREE:
                break;

            default:
                snmp_log(LOG_ERR, "%s: Unknown mode %d\n", __func__, reqinfo->mode);
        }
    }

    /** clean up after all requset processing has ended */
    switch (reqinfo->mode)
    {
        case MODE_SET_UNDO:
        case MODE_SET_FREE:
        case MODE_SET_COMMIT:
            /** clear out the undo cache */
            netsnmp_oid_stash_free(&undoStorage, SNMP_free_undoInfo);
            netsnmp_oid_stash_free(&commitStorage, netsnmp_oid_stash_no_free);
    }

    return SNMP_ERR_NOERROR;
}



