/*
 * This file implements the ctWwwServiceLogEntry.
 */
/* 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/snmpv2-tc.h"
#include "snmpcommon/snmpcommon.h"
#include "apache-logging-mib.h"

#ifndef SNMP_MIN
#define SNMP_MIN(a,b)   (((a)<(b)) ? (a) : (b))
#endif

#define NEXT    FALSE
#define EXACT   TRUE
#define INDEX   2

#ifdef COVALENT_APACHE_LOGGING_WWW_SERVICE_GROUP

/* Declarations of the local functions */
FindVarMethod var_ctWwwServiceLogEntry;
FindVarMethod var_ctWwwServiceLogCtrlEntry;
FindVarMethod var_ctWwwServiceLogLastNEntry;
WriteMethod write_ctWwwServiceLogCtrlEnable;
WriteMethod write_ctWwwServiceLogCtrlLevel;
WriteMethod write_ctWwwServiceLogCtrlLastNSize;
loglevel_entry *get_www_service_log_level_row(struct variable *vp,
        oid *name, size_t *length, int exact, apache_logging_info *www_service_log);
last_n_log_entry *get_www_service_log_last_n_row(struct variable *vp,
        oid* name, size_t *name_length, int exact, apache_logging_info *www_service_log);
apache_logging_info *get_www_service_log_info_row(struct variable *vp,
        oid *name, size_t *namelength, int exact, unsigned int *index);


static apache_logging_info *www_service_loginfo;

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

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

oid ctWwwServiceLogLastNEntry_oid[] = { 1,3,6,1,4,1,6100,10,1,6,1 };
struct variable2 ctWwwServiceLogLastNEntry_variables[] = {
#define   CTAPPLICATIONLOGLASTNLEVEL  2
  { CTAPPLICATIONLOGLASTNLEVEL, ASN_INTEGER, RONLY, var_ctWwwServiceLogLastNEntry, 1, { 2 } },
#define   CTAPPLICATIONLOGLASTNTIME  3
  { CTAPPLICATIONLOGLASTNTIME, ASN_OCTET_STR, RONLY, var_ctWwwServiceLogLastNEntry, 1, { 3 } },
#define   CTAPPLICATIONLOGLASTNMSG  4
  { CTAPPLICATIONLOGLASTNMSG, ASN_OCTET_STR, RONLY, var_ctWwwServiceLogLastNEntry, 1, { 4 } },
};


loglevel_entry *
get_www_service_log_level_row(struct variable *vp,
        oid *name, size_t *length, int exact, apache_logging_info *www_service_log)
{
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(&(www_service_log->loglevel_info[ *ptr - 1 ]));
        }
        (*ptr)++;
    }
    return(NULL);
}

apache_logging_info *
get_www_service_log_info_row(struct variable *vp,
        oid *name, size_t *namelength,
        int exact, unsigned int *index)
{
oid *ptr;

    ptr = &(vp->name[ vp->namelen++ ]);
    while (*index < get_www_service_total()) {
        *ptr = *index + 1;
        if (exact == NEXT) {
            if (0 > snmp_oid_compare(name, *namelength, vp->name, vp->namelen)) {
                return(&(www_service_loginfo[ *index ]));
            }
        } else if (exact == EXACT) {
            if (0 == snmp_oid_compare(name, *namelength, vp->name, vp->namelen)) {
                return(&(www_service_loginfo[ *index ]));
            }
        } else if (exact == INDEX) {
            if (0 >= snmp_oid_compare(name, SNMP_MIN(*namelength,vp->namelen),
                            vp->name, SNMP_MIN(*namelength, vp->namelen))) {
                return(&(www_service_loginfo[ *index ]));
            }
        }
        (*index)++;
    }
    return(NULL);
}


/*
 * var_ctWwwServiceLogEntry():
 */
unsigned char *
var_ctWwwServiceLogEntry(struct variable *vp, 
        oid *name, size_t *length, 
        int exact, size_t *var_len, WriteMethod **write_method)
{
apache_logging_info *current_service;
loglevel_entry *current_row;
int www_service = 0;
int namelen = vp->namelen;

    do {
        vp->namelen = namelen;
        current_service = get_www_service_log_info_row(vp, name, length, INDEX, &www_service);
        if (current_service == NULL) {
            return(NULL);
        }
        current_row = get_www_service_log_level_row(vp, name, length, exact, current_service);
        www_service++;
    } while (current_row == 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;
}




int
write_ctWwwServiceLogCtrlEnable(int action,
        unsigned char *var_val, unsigned char var_val_type, size_t var_val_len,
        unsigned 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 ctWwwServiceLogCtrlEnable not ASN_INTEGER\n");
              return SNMP_ERR_WRONGTYPE;
          }
          if (var_val_len > sizeof(long_ret)){
              fprintf(stderr,"write to ctWwwServiceLogCtrlEnable: 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_ctWwwServiceLogCtrlLevel(int action,
        unsigned char *var_val, unsigned char var_val_type, size_t var_val_len,
        unsigned 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 ctWwwServiceLogCtrlLevel not ASN_INTEGER\n");
              return SNMP_ERR_WRONGTYPE;
          }
          if (var_val_len > sizeof(long_ret)){
              fprintf(stderr,"write to ctWwwServiceLogCtrlLevel: 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_ctWwwServiceLogCtrlLastNSize(int action,
        unsigned char *var_val, unsigned char var_val_type, size_t var_val_len,
        unsigned 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 ctWwwServiceLogCtrlLastNSize not ASN_UNSIGNED\n");
              return SNMP_ERR_WRONGTYPE;
          }
          if (var_val_len > sizeof(ulong_ret)){
              fprintf(stderr,"write to ctWwwServiceLogCtrlLastNSize: 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;
}

/*
 * var_ctWwwServiceLogCtrlEntry():
 */
unsigned char *
var_ctWwwServiceLogCtrlEntry(struct variable *vp, 
        oid *name, size_t *length, 
        int exact, size_t *var_len, WriteMethod **write_method)
{
apache_logging_info *current_service;
int www_service = 0;

    current_service = get_www_service_log_info_row(vp, name, length, exact, &www_service);
    if (current_service == 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 CTAPPLICATIONLOGCTRLFILE:
            strcpy(return_buf, "");
            *var_len = strlen(return_buf);
            return (unsigned char *) return_buf;
        case CTAPPLICATIONLOGCTRLENABLE:
            *write_method = write_ctWwwServiceLogCtrlEnable;
            long_return = current_service->enable;
            return (unsigned char *) &long_return;
        case CTAPPLICATIONLOGCTRLLEVEL:
            *write_method = write_ctWwwServiceLogCtrlLevel;
            long_return = current_service->level;
            return (unsigned char *) &long_return;
        case CTAPPLICATIONLOGCTRLLASTNSIZE:
            *write_method = write_ctWwwServiceLogCtrlLastNSize;
            long_return = current_service->lastNSize;
            return (unsigned char *) &long_return;
    }
    return NULL;
}


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

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

/*
 * var_ctWwwServiceLogLastNEntry():
 */
unsigned char *
var_ctWwwServiceLogLastNEntry(struct variable *vp, 
        oid *name, size_t *length, 
        int exact, size_t *var_len, WriteMethod **write_method)
{
apache_logging_info *current_service;
last_n_log_entry  *current_row;
int www_service = 0;
int namelen = vp->namelen;
 
    do {
        vp->namelen = namelen;
        current_service = get_www_service_log_info_row(vp, name, length, INDEX, &www_service);
        if (current_service == NULL) {
            return(NULL);
        }
        current_row = get_www_service_log_last_n_row(vp, name, length, exact, current_service);
        www_service++;
    } while (current_row == 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 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_www_service(int www_service, int log_level,
                                char *log_message)
{
    DEBUGTRACE;
    update_apache_logging_mib(WWW_SERVICE, &(www_service_loginfo[www_service - 1]),
                                www_service, log_level, log_message);
}

/*
 * init_apache_logging_mib_www_service(apr_pool_t *p, server_rec *s)
 *   Initialization routine.  This is called when the agent starts up.
 */
void init_apache_logging_mib_www_service(apr_pool_t *p, server_rec *s)
{
unsigned i;

    www_service_loginfo = (apache_logging_info *) apr_pcalloc(p,
                                        (sizeof(apache_logging_info) * get_www_service_total()));
    if (www_service_loginfo == NULL) {
        ap_log_error(APLOG_MARK, (APLOG_NOERRNO|APLOG_NOTICE), 0, NULL,
                        "SNMP:apache-logging-mib: could not allocate WWW Services");
        return;
    }
    memset(www_service_loginfo, 0, (sizeof(apache_logging_info) * get_www_service_total()));
    for (i = 0 ; ((i < get_www_service_total()) && (s)) ; i++, s = s->next) {
        www_service_loginfo[i].level = s->loglevel + 1;
        www_service_loginfo[i].enable = 1;
        www_service_loginfo[i].lastNSize = DEFAULT_LASTN_LOG_MSG;
    }

    REGISTER_MIB("ctWwwServiceLogEntry", ctWwwServiceLogEntry_variables,
               variable2, ctWwwServiceLogEntry_oid);
    REGISTER_MIB("ctWwwServiceLogCtrlEntry", ctWwwServiceLogCtrlEntry_variables,
               variable2, ctWwwServiceLogCtrlEntry_oid);
    REGISTER_MIB("ctWwwServiceLogLastNEntry", ctWwwServiceLogLastNEntry_variables,
               variable2, ctWwwServiceLogLastNEntry_oid);
}
#endif /* COVALENT_APACHE_LOGGING_WWW_SERVICE_GROUP */
