/**************************************************************
 * Copyright (C) 2001 Alex Rozin, Optical Access
 *
 *                     All Rights Reserved
 *
 * Permission to use, copy, modify and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * ALEX ROZIN DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * ALEX ROZIN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 ******************************************************************/

#include <net-snmp/net-snmp-config.h>

#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if TIME_WITH_SYS_TIME
# ifdef WIN32
#  include <sys/timeb.h>
# else
#  include <sys/time.h>
# endif
# include <time.h>
#else
# if HAVE_SYS_TIME_H
#  include <sys/time.h>
# else
#  include <time.h>
# endif
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <ctype.h>

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

#include "util_funcs.h"

#include "event.h"

/*
 * Implementation headers 
 */
#include "agutil_api.h"
#include "row_api.h"

/*
 * File scope definitions section 
 */

/*
 * from MIB compilation 
 */
#define eventEntryFirstIndexBegin       11

#define EVENTINDEX            3
#define EVENTDESCRIPTION      4
#define EVENTTYPE             5
#define EVENTCOMMUNITY        6
#define EVENTLASTTIMESENT     7
#define EVENTOWNER            8
#define EVENTSTATUS           9

#define Leaf_event_description  2
#define MIN_event_description   0
#define MAX_event_description   127
#define Leaf_event_type         3
#define Leaf_event_community    4
#define MIN_event_community     0
#define MAX_event_community     127
#define Leaf_event_last_time_sent 5
#define Leaf_eventOwner        6
#define Leaf_eventStatus       7


#define LOGEVENTINDEX         3
#define LOGINDEX              4
#define LOGTIME               5
#define LOGDESCRIPTION        6


/*
 * defaults & limitations 
 */

#define MAX_LOG_ENTRIES_PER_CTRL	200

typedef struct data_struct_t {
    struct data_struct_t *next;
    u_long          data_index;
    u_long          log_time;
    char           *log_description;
} DATA_ENTRY_T;

typedef enum {
    EVENT_NONE = 1,
    EVENT_LOG,
    EVENT_TRAP,
    EVENT_LOG_AND_TRAP
} EVENT_TYPE_T;

typedef struct {
    char           *event_description;
    char           *event_community;
    EVENT_TYPE_T    event_type;
    u_long          event_last_time_sent;

    SCROLLER_T      scrlr;
#if 0
    u_long          event_last_logged_index;
    u_long          event_number_of_log_entries;
    DATA_ENTRY_T   *log_list;
    DATA_ENTRY_T   *last_log_ptr;
#endif
} CRTL_ENTRY_T;

/*
 * Main section 
 */

static TABLE_DEFINTION_T EventCtrlTable;
static TABLE_DEFINTION_T *table_ptr = &EventCtrlTable;

/*
 * Control Table RowApi Callbacks 
 */

static int
data_destructor(SCROLLER_T * scrlr, void *free_me)
{
    DATA_ENTRY_T   *lptr = free_me;

    if (lptr->log_description)
        AGFREE(lptr->log_description);

    return 0;
}

int
event_Create(RMON_ENTRY_T * eptr)
{                               /* create the body: alloc it and set defaults */
    CRTL_ENTRY_T   *body;

    eptr->body = AGMALLOC(sizeof(CRTL_ENTRY_T));
    if (!eptr->body)
        return -3;
    body = (CRTL_ENTRY_T *) eptr->body;

    /*
     * set defaults 
     */

    body->event_description = NULL;
    body->event_community = AGSTRDUP("public");
    /*
     * ag_trace ("Dbg: created event_community=<%s>", body->event_community); 
     */
    body->event_type = EVENT_NONE;
    ROWDATAAPI_init(&body->scrlr,
                    MAX_LOG_ENTRIES_PER_CTRL,
                    MAX_LOG_ENTRIES_PER_CTRL,
                    sizeof(DATA_ENTRY_T), &data_destructor);


    return 0;
}

int
event_Clone(RMON_ENTRY_T * eptr)
{                               /* copy entry_bod -> clone */
    CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;
    CRTL_ENTRY_T   *clone = (CRTL_ENTRY_T *) eptr->tmp;

    if (body->event_description)
        clone->event_description = AGSTRDUP(body->event_description);

    if (body->event_community)
        clone->event_community = AGSTRDUP(body->event_community);
    return 0;
}

int
event_Copy(RMON_ENTRY_T * eptr)
{
    CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;
    CRTL_ENTRY_T   *clone = (CRTL_ENTRY_T *) eptr->tmp;

    if (body->event_type != clone->event_type) {
        body->event_type = clone->event_type;
    }

    if (clone->event_description) {
        if (body->event_description)
            AGFREE(body->event_description);
        body->event_description = AGSTRDUP(clone->event_description);
    }

    if (clone->event_community) {
        if (body->event_community)
            AGFREE(body->event_community);
        body->event_community = AGSTRDUP(clone->event_community);
    }

    return 0;
}

int
event_Delete(RMON_ENTRY_T * eptr)
{
    CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr;

    if (body->event_description)
        AGFREE(body->event_description);

    if (body->event_community)
        AGFREE(body->event_community);

    return 0;
}

int
event_Activate(RMON_ENTRY_T * eptr)
{                               /* init logTable */
    CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;

    ROWDATAAPI_set_size(&body->scrlr,
                        body->scrlr.data_requested,
                        (u_char)(RMON1_ENTRY_VALID == eptr->status) );

    return 0;
}

int
event_Deactivate(RMON_ENTRY_T * eptr)
{                               /* free logTable */
    CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) eptr->body;

    /*
     * free data list 
     */
    ROWDATAAPI_descructor(&body->scrlr);

    return 0;
}

static int
write_eventControl(int action, u_char * var_val, u_char var_val_type,
                   size_t var_val_len, u_char * statP,
                   oid * name, size_t name_len)
{
    long            long_temp;
    char           *char_temp;
    int             leaf_id, snmp_status;
    static int      prev_action = COMMIT;
    RMON_ENTRY_T   *hdr;
    CRTL_ENTRY_T   *cloned_body;
    CRTL_ENTRY_T   *body;

    switch (action) {
    case RESERVE1:
    case FREE:
    case UNDO:
    case ACTION:
    case COMMIT:
    default:
        return ROWAPI_do_another_action(name, eventEntryFirstIndexBegin,
                                        action, &prev_action,
                                        table_ptr, sizeof(CRTL_ENTRY_T));

    case RESERVE2:
        /*
         * get values from PDU, check them and save them in the cloned entry 
         */
        long_temp = name[eventEntryFirstIndexBegin];
        leaf_id = (int) name[eventEntryFirstIndexBegin - 1];
        hdr = ROWAPI_find(table_ptr, long_temp);        /* it MUST be OK */
        cloned_body = (CRTL_ENTRY_T *) hdr->tmp;
        body = (CRTL_ENTRY_T *) hdr->body;
        switch (leaf_id) {
        case Leaf_event_description:
            char_temp = AGMALLOC(1 + MAX_event_description);
            if (!char_temp)
                return SNMP_ERR_TOOBIG;
            snmp_status = AGUTIL_get_string_value(var_val, var_val_type,
                                                  var_val_len,
                                                  MAX_event_description,
                                                  1, NULL, char_temp);
            if (SNMP_ERR_NOERROR != snmp_status) {
                AGFREE(char_temp);
                return snmp_status;
            }

            if (cloned_body->event_description)
                AGFREE(cloned_body->event_description);

            cloned_body->event_description = AGSTRDUP(char_temp);
            /*
             * ag_trace ("rx: event_description=<%s>", cloned_body->event_description); 
             */
            AGFREE(char_temp);

            break;
        case Leaf_event_type:
            snmp_status = AGUTIL_get_int_value(var_val, var_val_type,
                                               var_val_len,
                                               EVENT_NONE,
                                               EVENT_LOG_AND_TRAP,
                                               &long_temp);
            if (SNMP_ERR_NOERROR != snmp_status) {
                return snmp_status;
            }
            cloned_body->event_type = long_temp;
            break;
        case Leaf_event_community:
            char_temp = AGMALLOC(1 + MAX_event_community);
            if (!char_temp)
                return SNMP_ERR_TOOBIG;
            snmp_status = AGUTIL_get_string_value(var_val, var_val_type,
                                                  var_val_len,
                                                  MAX_event_community,
                                                  1, NULL, char_temp);
            if (SNMP_ERR_NOERROR != snmp_status) {
                AGFREE(char_temp);
                return snmp_status;
            }

            if (cloned_body->event_community)
                AGFREE(cloned_body->event_community);

            cloned_body->event_community = AGSTRDUP(char_temp);
            AGFREE(char_temp);

            break;
        case Leaf_eventOwner:
            if (hdr->new_owner)
                AGFREE(hdr->new_owner);
            hdr->new_owner = AGMALLOC(MAX_OWNERSTRING);;
            if (!hdr->new_owner)
                return SNMP_ERR_TOOBIG;
            snmp_status = AGUTIL_get_string_value(var_val, var_val_type,
                                                  var_val_len,
                                                  MAX_OWNERSTRING,
                                                  1, NULL, hdr->new_owner);
            if (SNMP_ERR_NOERROR != snmp_status) {
                return snmp_status;
            }

            break;
        case Leaf_eventStatus:
            snmp_status = AGUTIL_get_int_value(var_val, var_val_type,
                                               var_val_len,
                                               RMON1_ENTRY_VALID,
                                               RMON1_ENTRY_INVALID,
                                               &long_temp);
            if (SNMP_ERR_NOERROR != snmp_status) {
                return snmp_status;
            }
            hdr->new_status = long_temp;
            break;
        default:
            ag_trace("%s:unknown leaf_id=%d\n", table_ptr->name,
                     (int) leaf_id);
            return SNMP_ERR_NOSUCHNAME;
        }                       /* of switch by 'leaf_id' */
        break;
    }                           /* of switch by actions */

    prev_action = action;
    return SNMP_ERR_NOERROR;
}

unsigned char  *
var_eventTable(struct variable *vp,
               oid * name,
               size_t * length,
               int exact, size_t * var_len, WriteMethod ** write_method)
{
    static long     long_ret;
    static CRTL_ENTRY_T theEntry;
    RMON_ENTRY_T   *hdr;

    *write_method = write_eventControl;
    hdr = ROWAPI_header_ControlEntry(vp, name, length, exact, var_len,
                                     table_ptr,
                                     &theEntry, sizeof(CRTL_ENTRY_T));
    if (!hdr)
        return NULL;

    *var_len = sizeof(long);    /* default */

    switch (vp->magic) {
    case EVENTINDEX:
        long_ret = hdr->ctrl_index;
        return (unsigned char *) &long_ret;
    case EVENTDESCRIPTION:
        if (theEntry.event_description) {
            *var_len = strlen(theEntry.event_description);
            return (unsigned char *) theEntry.event_description;
        } else {
            *var_len = 0;
            return (unsigned char *) "";
        }
    case EVENTTYPE:
        long_ret = theEntry.event_type;
        return (unsigned char *) &long_ret;
    case EVENTCOMMUNITY:
        if (theEntry.event_community) {
            *var_len = strlen(theEntry.event_community);
            return (unsigned char *) theEntry.event_community;
        } else {
            *var_len = 0;
            return (unsigned char *) "";
        }
    case EVENTLASTTIMESENT:
        long_ret = theEntry.event_last_time_sent;
        return (unsigned char *) &long_ret;
    case EVENTOWNER:
        if (hdr->owner) {
            *var_len = strlen(hdr->owner);
            return (unsigned char *) hdr->owner;
        } else {
            *var_len = 0;
            return (unsigned char *) "";
        }
    case EVENTSTATUS:
        long_ret = hdr->status;
        return (unsigned char *) &long_ret;
    default:
        ag_trace("EventControlTable: unknown vp->magic=%d",
                 (int) vp->magic);
        ERROR_MSG("");
    }
    return NULL;
}

static SCROLLER_T *
event_extract_scroller(void *v_body)
{
    CRTL_ENTRY_T   *body = (CRTL_ENTRY_T *) v_body;
    return &body->scrlr;
}

unsigned char  *
var_logTable(struct variable *vp,
             oid * name,
             size_t * length,
             int exact, size_t * var_len, WriteMethod ** write_method)
{
    static long     long_ret;
    static DATA_ENTRY_T theEntry;
    RMON_ENTRY_T   *hdr;
    CRTL_ENTRY_T   *ctrl;

    *write_method = NULL;
    hdr = ROWDATAAPI_header_DataEntry(vp, name, length, exact, var_len,
                                      table_ptr,
                                      &event_extract_scroller,
                                      sizeof(DATA_ENTRY_T), &theEntry);
    if (!hdr)
        return NULL;

    ctrl = (CRTL_ENTRY_T *) hdr->body;

    *var_len = sizeof(long);    /* default */

    switch (vp->magic) {
    case LOGEVENTINDEX:
        long_ret = hdr->ctrl_index;
        return (unsigned char *) &long_ret;
    case LOGINDEX:
        long_ret = theEntry.data_index;
        return (unsigned char *) &long_ret;
    case LOGTIME:
        long_ret = theEntry.log_time;
        return (unsigned char *) &long_ret;
    case LOGDESCRIPTION:
        if (theEntry.log_description) {
            *var_len = strlen(theEntry.log_description);
            return (unsigned char *) theEntry.log_description;
        } else {
            *var_len = 0;
            return (unsigned char *) "";
        }
    default:
        ERROR_MSG("");
    }

    return NULL;
}

/*
 * External API section 
 */

static char    *
create_explanaition(CRTL_ENTRY_T * evptr, u_char is_rising,
                    u_long alarm_index, u_long event_index,
                    oid * alarmed_var,
                    size_t alarmed_var_length,
                    u_long value, u_long the_threshold,
                    u_long sample_type, char *alarm_descr)
{
#define UNEQ_LENGTH	(1 + 11 + 4 + 11 + 1 + 20)
    char            expl[UNEQ_LENGTH];
    static char     c_oid[SPRINT_MAX_LEN];
    size_t          sz;
    char           *descr;
    register char  *pch;
    register char  *tmp;


    snprint_objid(c_oid, sizeof(c_oid)-1, alarmed_var, alarmed_var_length);
    c_oid[sizeof(c_oid)-1] = '\0';
    for (pch = c_oid;;) {
        tmp = strchr(pch, '.');
        if (!tmp)
            break;
        if (isdigit(tmp[1]) || '"' == tmp[1])
            break;
        pch = tmp + 1;
    }

    snprintf(expl, UNEQ_LENGTH, "=%ld %s= %ld :%ld, %ld",
             (unsigned long) value,
             is_rising ? ">" : "<",
             (unsigned long) the_threshold,
             (long) alarm_index, (long) event_index);
    sz = 3 + strlen(expl) + strlen(pch);
    if (alarm_descr)
        sz += strlen(alarm_descr);

    descr = AGMALLOC(sz);
    if (!descr) {
        ag_trace("Can't allocate event description");
        return NULL;
    }

    if (alarm_descr) {
        strcpy(descr, alarm_descr);
        strcat(descr, ":");
    } else
        *descr = '\0';

    strcat(descr, pch);
    strcat(descr, expl);
    return descr;
}

extern void     send_enterprise_trap_vars(int, int, oid *, int,
                                          netsnmp_variable_list *);

static netsnmp_variable_list *
oa_bind_var(netsnmp_variable_list * prev,
            void *value, int type, size_t sz_val, oid * oid, size_t sz_oid)
{
    netsnmp_variable_list *var;

    var = (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list));
    if (!var) {
        ag_trace("FATAL: cannot malloc in oa_bind_var\n");
        exit(-1);               /* Sorry :( */
    }
    memset(var, 0, sizeof(netsnmp_variable_list));
    var->next_variable = prev;
    snmp_set_var_objid(var, oid, sz_oid);
    snmp_set_var_value(var, (u_char *) value, sz_val);
    var->type = type;

    return var;
}

static void
event_send_trap(CRTL_ENTRY_T * evptr, u_char is_rising,
                u_int alarm_index,
                u_int value, u_int the_threshold,
                oid * alarmed_var, size_t alarmed_var_length,
                u_int sample_type)
{
    static oid      rmon1_trap_oid[] = { 1, 3, 6, 1, 2, 1, 16, 0, 0 };
    static oid      alarm_index_oid[] =
        { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 1 };
    static oid      alarmed_var_oid[] =
        { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 3 };
    static oid      sample_type_oid[] =
        { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 4 };
    static oid      value_oid[] = { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 5 };
    static oid      threshold_oid[] = { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 7 };     /* rising case */
    netsnmp_variable_list *top = NULL;
    register int    iii;

    /*
     * set the last 'oid' : risingAlarm or fallingAlarm 
     */
    if (is_rising) {
        iii = OID_LENGTH(rmon1_trap_oid);
        rmon1_trap_oid[iii - 1] = 1;
        iii = OID_LENGTH(threshold_oid);
        threshold_oid[iii - 1] = 7;
    } else {
        iii = OID_LENGTH(rmon1_trap_oid);
        rmon1_trap_oid[iii - 1] = 0;
        iii = OID_LENGTH(threshold_oid);
        threshold_oid[iii - 1] = 8;
    }

    /*
     * build the var list 
     */
    top = oa_bind_var(top, &alarm_index, ASN_INTEGER, sizeof(u_int),
                      alarm_index_oid, OID_LENGTH(alarm_index_oid));

    top =
        oa_bind_var(top, alarmed_var, ASN_OBJECT_ID,
                    sizeof(oid) * alarmed_var_length, alarmed_var_oid,
                    OID_LENGTH(alarmed_var_oid));

    top = oa_bind_var(top, &sample_type, ASN_INTEGER, sizeof(u_int),
                      sample_type_oid, OID_LENGTH(sample_type_oid));

    top = oa_bind_var(top, &value, ASN_INTEGER, sizeof(u_int),
                      value_oid, OID_LENGTH(value_oid));

    top = oa_bind_var(top, &the_threshold, ASN_INTEGER, sizeof(u_int),
                      threshold_oid, OID_LENGTH(threshold_oid));


    send_enterprise_trap_vars(SNMP_TRAP_ENTERPRISESPECIFIC, 0,
                              rmon1_trap_oid,
                              OID_LENGTH(rmon1_trap_oid), top);
    ag_trace("rmon trap has been sent");
    snmp_free_varbind(top);

}


static void
event_save_log(CRTL_ENTRY_T * body, char *event_descr)
{
    register DATA_ENTRY_T *lptr;

    lptr = ROWDATAAPI_locate_new_data(&body->scrlr);
    if (!lptr) {
        ag_trace("Err: event_save_log:cannot locate ?");
        return;
    }

    lptr->log_time = body->event_last_time_sent;
    lptr->log_description = AGSTRDUP(event_descr);
    lptr->data_index = ROWDATAAPI_get_total_number(&body->scrlr);

    /*
     * ag_trace ("log has been saved, data_index=%d", (int) lptr->data_index); 
     */
}

int
event_api_send_alarm(u_char is_rising,
                     u_long alarm_index,
                     u_long event_index,
                     oid * alarmed_var,
                     size_t alarmed_var_length,
                     u_long sample_type,
                     u_long value, u_long the_threshold, char *alarm_descr)
{
    RMON_ENTRY_T   *eptr;
    CRTL_ENTRY_T   *evptr;

    if (!event_index)
        return SNMP_ERR_NOSUCHNAME;

#if 0
    ag_trace("event_api_send_alarm(%d,%d,%d,'%s')",
             (int) is_rising, (int) alarm_index, (int) event_index,
             alarm_descr);
#endif
    eptr = ROWAPI_find(table_ptr, event_index);
    if (!eptr) {
        /*
         * ag_trace ("event cannot find entry %ld", event_index); 
         */
        return SNMP_ERR_NOSUCHNAME;
    }

    evptr = (CRTL_ENTRY_T *) eptr->body;
    evptr->event_last_time_sent = AGUTIL_sys_up_time();


    if (EVENT_TRAP == evptr->event_type
        || EVENT_LOG_AND_TRAP == evptr->event_type) {
        event_send_trap(evptr, is_rising, alarm_index, value,
                        the_threshold, alarmed_var, alarmed_var_length,
                        sample_type);
    }

    if (EVENT_LOG == evptr->event_type
        || EVENT_LOG_AND_TRAP == evptr->event_type) {
        register char  *explain;

        explain = create_explanaition(evptr, is_rising,
                                      alarm_index, event_index,
                                      alarmed_var, alarmed_var_length,
                                      value, the_threshold,
                                      sample_type, alarm_descr);
        /*
         * if (explain) ag_trace ("Dbg:'%s'", explain); 
         */
        event_save_log(evptr, explain);
        if (explain)
            AGFREE(explain);
    }

    return SNMP_ERR_NOERROR;
}

#if 1                           /* debug, but may be used for init. TBD: may be token snmpd.conf ? */
int
add_event_entry(int ctrl_index,
                char *event_description,
                EVENT_TYPE_T event_type, char *event_community)
{
    register RMON_ENTRY_T *eptr;
    register CRTL_ENTRY_T *body;
    int             ierr;

    ierr = ROWAPI_new(table_ptr, ctrl_index);
    if (ierr) {
        ag_trace("ROWAPI_new failed with %d", ierr);
        return ierr;
    }

    eptr = ROWAPI_find(table_ptr, ctrl_index);
    if (!eptr) {
        ag_trace("ROWAPI_find failed");
        return -4;
    }

    body = (CRTL_ENTRY_T *) eptr->body;

    /*
     * set parameters 
     */

    if (event_description) {
        if (body->event_description)
            AGFREE(body->event_description);
        body->event_description = AGSTRDUP(event_description);
    }

    if (event_community) {
        if (body->event_community)
            AGFREE(body->event_community);
        body->event_community = AGSTRDUP(event_community);
    }

    body->event_type = event_type;

    eptr->new_status = RMON1_ENTRY_VALID;
    ierr = ROWAPI_commit(table_ptr, ctrl_index);
    if (ierr) {
        ag_trace("ROWAPI_commit failed with %d", ierr);
    }

    return ierr;
}
#endif

/*
 * Registration & Initializatio section 
 */

oid             eventTable_variables_oid[] =
    { 1, 3, 6, 1, 2, 1, 16, 9, 1 };
oid             logTable_variables_oid[] = { 1, 3, 6, 1, 2, 1, 16, 9, 2 };

struct variable2 eventTable_variables[] = {
    /*
     * magic number        , variable type, ro/rw , callback fn  ,           L, oidsuffix 
     */
    {EVENTINDEX, ASN_INTEGER, RONLY, var_eventTable, 2, {1, 1}},
    {EVENTDESCRIPTION, ASN_OCTET_STR, RWRITE, var_eventTable, 2, {1, 2}},
    {EVENTTYPE, ASN_INTEGER, RWRITE, var_eventTable, 2, {1, 3}},
    {EVENTCOMMUNITY, ASN_OCTET_STR, RWRITE, var_eventTable, 2, {1, 4}},
    {EVENTLASTTIMESENT, ASN_TIMETICKS, RONLY, var_eventTable, 2, {1, 5}},
    {EVENTOWNER, ASN_OCTET_STR, RWRITE, var_eventTable, 2, {1, 6}},
    {EVENTSTATUS, ASN_INTEGER, RWRITE, var_eventTable, 2, {1, 7}}
};

struct variable2 logTable_variables[] = {
    /*
     * magic number        , variable type, ro/rw , callback fn  ,           L, oidsuffix 
     */
    {LOGEVENTINDEX, ASN_INTEGER, RONLY, var_logTable, 2, {1, 1}},
    {LOGINDEX, ASN_INTEGER, RONLY, var_logTable, 2, {1, 2}},
    {LOGTIME, ASN_TIMETICKS, RONLY, var_logTable, 2, {1, 3}},
    {LOGDESCRIPTION, ASN_OCTET_STR, RONLY, var_logTable, 2, {1, 4}}

};

void
init_event(void)
{
    REGISTER_MIB("eventTable", eventTable_variables, variable2,
                 eventTable_variables_oid);
    REGISTER_MIB("logTable", logTable_variables, variable2,
                 logTable_variables_oid);

    ROWAPI_init_table(&EventCtrlTable, "Event", 0, &event_Create, &event_Clone, &event_Delete, NULL,    /* &event_Validate, */
                      &event_Activate, &event_Deactivate, &event_Copy);
#if 0
    add_event_entry(3, "Alarm", EVENT_LOG_AND_TRAP, NULL);
    /*
     * add_event_entry (5, ">=", EVENT_LOG_AND_TRAP, NULL); 
     */
#endif
}
