/*
 * This file implements the ctApplicationLogEntry.
 */
/* General includes */
#include <sys/types.h>

/* Apache includes */
#include <httpd.h>
#include <http_log.h>

/* NET-SNMP includes */
#include <ucd-snmp-config.h>
#include <asn1.h>
#include <snmp.h>
#include <snmp_api.h>
#include <snmp_impl.h>
#include <snmp_debug.h>
#include <snmp_vars.h>
#include <var_struct.h>

#include "covalent-snmp-config.h"
#include "snmpcommon/snmpcommon.h"
#include "snmpcommon/snmpv2-tc.h"
#include "apache-logging-mib.h"

#ifdef COVALENT_APACHE_LOGGING_APPLICATION_GROUP
/* Declarations of the local functions */
FindVarMethod var_ctApplicationLogEntry;
FindVarMethod var_ctApplicationLogCtrlEntry;
FindVarMethod var_ctApplicationLogLastNEntry;
WriteMethod write_ctApplicationLogCtrlEnable;
WriteMethod write_ctApplicationLogCtrlLevel;
WriteMethod write_ctApplicationLogCtrlLastNSize;
loglevel_entry *get_application_log_level_row(struct variable *vp,
        oid *name, size_t *length, int exact);
last_n_log_entry *get_application_log_last_n_row(struct variable *vp,
        oid* name, size_t *name_length, int exact);



static apache_logging_info application_loginfo;

oid ctApplicationLogEntry_oid[] = { 1,3,6,1,4,1,6100,10,1,1,1 };
struct variable2 ctApplicationLogEntry_variables[] = {
#define   CTAPPLICATIONLOGCOUNTER  2
  { CTAPPLICATIONLOGCOUNTER, ASN_COUNTER, RONLY, var_ctApplicationLogEntry, 1, { 2 } },
#define   CTAPPLICATIONLOGLASTTIME  3
  { CTAPPLICATIONLOGLASTTIME, ASN_OCTET_STR, RONLY, var_ctApplicationLogEntry, 1, { 3 } },
#define   CTAPPLICATIONLOGLASTMSG  4
  { CTAPPLICATIONLOGLASTMSG, ASN_OCTET_STR, RONLY, var_ctApplicationLogEntry, 1, { 4 } },
};

oid ctApplicationLogCtrlEntry_oid[] = { 1,3,6,1,4,1,6100,10,1,2,1 };
struct variable2 ctApplicationLogCtrlEntry_variables[] = {
#define   CTAPPLICATIONLOGCTRLFILE  1
  { CTAPPLICATIONLOGCTRLFILE, ASN_OCTET_STR, RONLY, var_ctApplicationLogCtrlEntry, 1, { 1 } },
#define   CTAPPLICATIONLOGCTRLENABLE  2
  { CTAPPLICATIONLOGCTRLENABLE, ASN_INTEGER, RWRITE, var_ctApplicationLogCtrlEntry, 1, { 2 } },
#define   CTAPPLICATIONLOGCTRLLEVEL  3
  { CTAPPLICATIONLOGCTRLLEVEL, ASN_INTEGER, RWRITE, var_ctApplicationLogCtrlEntry, 1, { 3 } },
#define   CTAPPLICATIONLOGCTRLLASTNSIZE  4
  { CTAPPLICATIONLOGCTRLLASTNSIZE, ASN_UNSIGNED, RWRITE, var_ctApplicationLogCtrlEntry, 1, { 4 } },
};

oid ctApplicationLogLastNEntry_oid[] = { 1,3,6,1,4,1,6100,10,1,3,1 };
struct variable2 ctApplicationLogLastNEntry_variables[] = {
#define   CTAPPLICATIONLOGLASTNLEVEL  2
  { CTAPPLICATIONLOGLASTNLEVEL, ASN_INTEGER, RONLY, var_ctApplicationLogLastNEntry, 1, { 2 } },
#define   CTAPPLICATIONLOGLASTNWWWSERVICE  3
  { CTAPPLICATIONLOGLASTNWWWSERVICE, ASN_UNSIGNED, RONLY, var_ctApplicationLogLastNEntry, 1, { 3 } },
#define   CTAPPLICATIONLOGLASTNTIME  4
  { CTAPPLICATIONLOGLASTNTIME, ASN_OCTET_STR, RONLY, var_ctApplicationLogLastNEntry, 1, { 4 } },
#define   CTAPPLICATIONLOGLASTNMSG  5
  { CTAPPLICATIONLOGLASTNMSG, ASN_OCTET_STR, RONLY, var_ctApplicationLogLastNEntry, 1, { 5 } },
};


loglevel_entry *
get_application_log_level_row(struct variable *vp,
        oid *name, size_t *length, int exact)
{
oid *ptr;
int result;

    ptr = &(vp->name[ vp->namelen++ ]);
    *ptr = 1;
    while (*ptr < (APLOG_DEBUG + 1)) {
        result = snmp_oid_compare(name, *length, vp->name, vp->namelen);
        if (((exact) && (result == 0)) || ((!exact) && (result < 0))) {
            return(&(application_loginfo.loglevel_info[ *ptr - 1 ]));
        }
        (*ptr)++;
    }
    return(NULL);
}


/*
 * var_ctApplicationLogEntry():
 */
unsigned char *
var_ctApplicationLogEntry(struct variable *vp, 
        oid *name, size_t *length, 
        int exact, size_t *var_len, WriteMethod **write_method)
{
loglevel_entry *current_row;

    vp->name[ vp->namelen++ ] = (oid)get_appl_index();
    current_row = get_application_log_level_row(vp, name, length, exact);
    if (current_row == NULL) {
        return(NULL);
    }

    memcpy((char *)name, (char *)vp->name, vp->namelen * sizeof(oid));
    *length = vp->namelen;
    *write_method = 0;
    *var_len = sizeof(long_return);
    switch(vp->magic) {
        case CTAPPLICATIONLOGCOUNTER:
            return (unsigned char *) &(current_row->counter);
        case CTAPPLICATIONLOGLASTTIME:
            *var_len = snmp_time2DateAndTime(current_row->lasttime, return_buf);
            return (unsigned char *) return_buf;
        case CTAPPLICATIONLOGLASTMSG:
            *var_len = strlen(current_row->lastmsg);
            return (unsigned char *) current_row->lastmsg;
    }
    return NULL;
}




/*
 * var_ctApplicationLogCtrlEntry():
 */
unsigned char *
var_ctApplicationLogCtrlEntry(struct variable *vp, 
        oid *name, size_t *length, 
        int exact, size_t *var_len, WriteMethod **write_method)
{
int result;


    vp->name[ vp->namelen++ ] = get_appl_index();
    result = snmp_oid_compare(name, *length, vp->name, vp->namelen);
    if (!(exact && (result == 0)) && !(!exact && (result < 0))) {
        return(NULL);
    }

    memcpy((char *)name, (char *)vp->name, vp->namelen * sizeof(oid));
    *length = vp->namelen;
    *write_method = 0;
    *var_len = sizeof(long_return);

    switch(vp->magic) {
        case CTAPPLICATIONLOGCTRLFILE:
            strcpy(return_buf, "");
            *var_len = strlen(return_buf);
            return (unsigned char *) return_buf;
        case CTAPPLICATIONLOGCTRLENABLE:
            *write_method = write_ctApplicationLogCtrlEnable;
            long_return = application_loginfo.enable;
            return (unsigned char *) &long_return;
        case CTAPPLICATIONLOGCTRLLEVEL:
            *write_method = write_ctApplicationLogCtrlLevel;
            long_return = application_loginfo.level;
            return (unsigned char *) &long_return;
        case CTAPPLICATIONLOGCTRLLASTNSIZE:
            *write_method = write_ctApplicationLogCtrlLastNSize;
            long_return = application_loginfo.lastNSize;
            return (unsigned char *) &long_return;
    }
    return NULL;
}


int
write_ctApplicationLogCtrlEnable(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)
{
  static long *long_ret;
  int size;

  switch ( action ) {
        case RESERVE1:
          if (var_val_type != ASN_INTEGER){
              fprintf(stderr, "write to ctApplicationLogCtrlEnable not ASN_INTEGER\n");
              return SNMP_ERR_WRONGTYPE;
          }
          if (var_val_len > sizeof(long_ret)){
              fprintf(stderr,"write to ctApplicationLogCtrlEnable: bad length\n");
              return SNMP_ERR_WRONGLENGTH;
          }
          break;
        case RESERVE2:
          size = var_val_len;
          long_ret = (long *) var_val;
          break;
        case FREE:
             /* Release any resources that have been allocated */
          break;
        case ACTION:
             /* The variable has been stored in long_ret for
             you to use, and you have just been asked to do something with
             it.  Note that anything done here must be reversable in the UNDO case */
          break;
        case UNDO:
             /* Back out any changes made in the ACTION case */
          break;
        case COMMIT:
             /* Things are working well, so it's now safe to make the change
             permanently.  Make sure that anything done here can't fail! */
          break;
  }
  return SNMP_ERR_NOERROR;
}




int
write_ctApplicationLogCtrlLevel(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)
{
  static long *long_ret;
  int size;

  switch ( action ) {
        case RESERVE1:
          if (var_val_type != ASN_INTEGER){
              fprintf(stderr, "write to ctApplicationLogCtrlLevel not ASN_INTEGER\n");
              return SNMP_ERR_WRONGTYPE;
          }
          if (var_val_len > sizeof(long_ret)){
              fprintf(stderr,"write to ctApplicationLogCtrlLevel: bad length\n");
              return SNMP_ERR_WRONGLENGTH;
          }
          break;
        case RESERVE2:
          size = var_val_len;
          long_ret = (long *) var_val;
          break;
        case FREE:
             /* Release any resources that have been allocated */
          break;
        case ACTION:
             /* The variable has been stored in long_ret for
             you to use, and you have just been asked to do something with
             it.  Note that anything done here must be reversable in the UNDO case */
          break;
        case UNDO:
             /* Back out any changes made in the ACTION case */
          break;
        case COMMIT:
             /* Things are working well, so it's now safe to make the change
             permanently.  Make sure that anything done here can't fail! */
          break;
  }
  return SNMP_ERR_NOERROR;
}




int
write_ctApplicationLogCtrlLastNSize(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)
{
  static unsigned long *ulong_ret;
  int size;

  switch ( action ) {
        case RESERVE1:
          if (var_val_type != ASN_UNSIGNED){
              fprintf(stderr, "write to ctApplicationLogCtrlLastNSize not ASN_UNSIGNED\n");
              return SNMP_ERR_WRONGTYPE;
          }
          if (var_val_len > sizeof(ulong_ret)){
              fprintf(stderr,"write to ctApplicationLogCtrlLastNSize: bad length\n");
              return SNMP_ERR_WRONGLENGTH;
          }
          break;
        case RESERVE2:
          size = var_val_len;
          ulong_ret = (unsigned long *) var_val;
          break;
        case FREE:
             /* Release any resources that have been allocated */
          break;
        case ACTION:
             /* The variable has been stored in ulong_ret for
             you to use, and you have just been asked to do something with
             it.  Note that anything done here must be reversable in the UNDO case */
          break;
        case UNDO:
             /* Back out any changes made in the ACTION case */
          break;
        case COMMIT:
             /* Things are working well, so it's now safe to make the change
             permanently.  Make sure that anything done here can't fail! */
          break;
  }
  return SNMP_ERR_NOERROR;
}

last_n_log_entry *
get_application_log_last_n_row(struct variable *vp,
        oid* name, size_t *name_length, int exact)
{
int result;
int vpname_length = vp->namelen++;

    if (0 < (int)(application_loginfo.lastNIndex - application_loginfo.lastNSize)) {
        vp->name[ vpname_length ] = (application_loginfo.lastNIndex - application_loginfo.lastNSize);
    } else {
        vp->name[ vpname_length ] = 0;
    }
    while (vp->name[ vpname_length ] < (unsigned int)application_loginfo.lastNIndex) {
        result = snmp_oid_compare(name, *name_length, vp->name, vp->namelen);
        if (((exact) && (result == 0)) || ((!exact) && (result < 0))) {
            return(&(application_loginfo.lastNTable[ vp->name[ vpname_length ] % MAX_LASTN_LOG_MSG ]));
        }
        vp->name[ vpname_length ]++;
    }
    return(NULL);
}

/*
 * var_ctApplicationLogLastNEntry():
 */
unsigned char *
var_ctApplicationLogLastNEntry(struct variable *vp, 
        oid *name, size_t *length, 
        int exact, size_t *var_len, WriteMethod **write_method)
{
last_n_log_entry  *current_row;

    vp->name[ vp->namelen++ ] = get_appl_index();
    current_row = get_application_log_last_n_row(vp, name, length, exact);
    if (current_row == NULL) {
        return(NULL);
    }

    *length = vp->namelen;
    memcpy( (char *)name,(char *)vp->name, *length * sizeof(oid));
    *write_method = 0;
    *var_len = sizeof(long);    /* default length */

    switch(vp->magic) {
        case CTAPPLICATIONLOGLASTNWWWSERVICE:
            long_return = current_row->www_service;
            return (unsigned char *) &long_return;
        case CTAPPLICATIONLOGLASTNLEVEL:
            long_return = current_row->level + 1;
            return (unsigned char *) &long_return;
        case CTAPPLICATIONLOGLASTNTIME:
            *var_len = snmp_time2DateAndTime(current_row->time, return_buf);
            return (unsigned char *) return_buf;
        case CTAPPLICATIONLOGLASTNMSG:
            *var_len = strlen(current_row->msg);
            return (unsigned char *) current_row->msg;
    }
    return NULL;
}

void
update_apache_logging_mib_appl(int www_service, int log_level,
                                char *log_message)
{
    DEBUGTRACE;
    update_apache_logging_mib(APPLICATION, &application_loginfo,
                                www_service, log_level, log_message);
}

/*
 * init_apache_logging_mib_appl(apr_pool_t *p, server_rec *s)
 *   Initialization routine.  This is called when the agent starts up.
 */
void init_apache_logging_mib_appl(apr_pool_t *p, server_rec *s)
{
int max_log_level = 0;

    memset(&application_loginfo, 0, sizeof(apache_logging_info));
    while (s) {
	if (s->loglevel > max_log_level) {
            max_log_level = s->loglevel;
        }
        s = s->next;
    }
    application_loginfo.level = max_log_level + 1;
    application_loginfo.enable = 1;
    application_loginfo.lastNSize = DEFAULT_LASTN_LOG_MSG;

    REGISTER_MIB("ctApplicationLogEntry", ctApplicationLogEntry_variables,
               variable2, ctApplicationLogEntry_oid);
    REGISTER_MIB("ctApplicationLogCtrlEntry", ctApplicationLogCtrlEntry_variables,
               variable2, ctApplicationLogCtrlEntry_oid);
    REGISTER_MIB("ctApplicationLogLastNEntry", ctApplicationLogLastNEntry_variables,
               variable2, ctApplicationLogLastNEntry_oid);
}
#endif /* COVALENT_APACHE_LOGGING_APPLICATION_GROUP */
