/*
 * This file implements the COVALENT-WWW-EXTENSIONS-MIB module.
 * $Id: notification.c 8676 2008-01-17 23:11:17Z ispringer $
 */
/* Includes */
#include <sys/types.h>

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

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

/* module includes */
#include "covalent-snmp-config.h"
#include "snmpcommon/snmpcommon.h"
#include "snmpcommon/snmpv2-tc.h"
#include "www-mib/www-mib.h"
#include "www-extensions-mib.h"

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

#define NEXT    FALSE
#define EXACT   TRUE

#define CTNOTIFYCTRLVALUE              2
#define CTNOTIFYCTRLCACHEENTRIES       3

#ifdef COVALENT_WWW_EXTENSIONS_NOTIFICATION_GROUP

int ctWwwExtNotifyResponse_enabled(www_protocol_t *protocol, int responseType);
server_rec *get_ctResponseNotifyCtrl_wwwServiceIndex(struct variable *vp,
        oid *name, size_t *namelength,
        oid *newname, size_t *newname_length,
        server_rec *service);
int get_ctResponseNotifyCtrlIndex(oid *name, size_t *name_length,
        oid *newname, size_t *newname_length,
        int exact, www_protocol_t *protocol);

/*
 * Function:
 *       ctWwwExtNotifyResponse_enabled
 * Parameters:
 *       int wwwServiceIndex - The service index from which this response was
 *                             send.
 *       int responseType    - The response that was returned to the client.
 * Returns: int - '0' meaning notify disabled for this response type.
 *                '1' meaning notify enabled for this response type.
 * Description:
 *       This function should filter the notification send.
 *       It should filter on the ctWwwExtNotifyResponseTable, but is
 *       currently implemented only to return all 4xx and 5xx
 *       response codes. (See HTTP/1.1 standard)
 */
int
ctWwwExtNotifyResponse_enabled(www_protocol_t *protocol, int responseType)
{

    if (!strcmp(protocol->protocol, "HTTP")) {
        if (responseType >= 400) {
            return(1);
        }
    }
    if (!strcmp(protocol->protocol, "FTP")) {
        if ((responseType == 202) /* NOT_IMPLEMENTED */ &&
            (responseType == 421) /* SERVICE_NOT_AVAILABLE */ &&
            (responseType > 425)) {
            return(1);
        }
    }
    return(0);
}


server_rec *
get_ctResponseNotifyCtrl_wwwServiceIndex(struct variable *vp,
        oid *name, size_t *namelength,
        oid *newname, size_t *newname_length,
        server_rec *service)
{
oid *ptr;

    *newname_length = vp->namelen;
    memcpy((char *)newname, (char *)vp->name, *newname_length * sizeof(oid));
    ptr = &(newname[ (*newname_length)++ ]);
    *ptr = 1;
    while (service) {
        if ( 0 >= snmp_oid_compare(name, SNMP_MIN(*namelength,*newname_length),
                                newname, SNMP_MIN(*namelength, *newname_length))) {
            return(service);
        }
        (*ptr)++;
        service = service->next;
    }
    return(NULL);
}



int
get_ctResponseNotifyCtrlIndex(oid *name, size_t *name_length, oid *newname, size_t *newname_length, int exact, www_protocol_t *protocol)
{
int i;
int result;
oid *response_type_index;

    i = 0;
    response_type_index = &(newname[ (*newname_length)++ ]);
    *response_type_index= get_response_type(protocol, i++);
    while (*response_type_index > 0) {
        result = snmp_oid_compare(name, *name_length, newname, *newname_length);
        if (((exact == EXACT) && (result == 0)) || ((exact == NEXT) && (0 > result))) {
            return(*response_type_index);
        } /* if */
        *response_type_index= get_response_type(protocol, i++);
    } /* while */
return(-1);
}


static unsigned char *
var_ctWwwExtNotifyCtrlEntry(struct variable *vp,
    oid     *name,
    size_t  *length,
    int     exact,
    size_t  *var_len,
    WriteMethod **write_method)
{
oid newname[ MAX_OID_LEN ];
size_t newname_length;
int responseType;
char *protocol;
www_protocol_t *protocol_definition;
server_rec *service = get_www_service_root();

    do {
        service = get_ctResponseNotifyCtrl_wwwServiceIndex(vp, name, length,
                                newname, &newname_length, service);
        if (service) {
            protocol = get_www_service_protocol(service);
            protocol_definition = get_www_protocol_definition_by_name(protocol);
            responseType = get_ctResponseNotifyCtrlIndex(name, length,
                                newname, &newname_length,
                                exact, protocol_definition);
        } else {
            return(NULL);
        }
        service = service->next;
    } while ( responseType > 0 );

    *length = newname_length;
    memcpy( (char *)name,(char *)newname, *length * sizeof(oid));
    *write_method = NULL;

    /* This could be optimised, but left in place for similarity for nono's. */
    switch (vp->magic) {
    case CTNOTIFYCTRLVALUE:
        *var_len = sizeof(long);
        long_return = (ctWwwExtNotifyResponse_enabled(protocol_definition, responseType) ? 10 : 0 );
        return (unsigned char *) &long_return;
    case CTNOTIFYCTRLCACHEENTRIES:
        *var_len = sizeof(long);
        long_return = 1;
        return (unsigned char *) &long_return;
    }
    return NULL;
}

static oid ctWwwExtNotifyCtrlEntry_oid[] = {1, 3, 6, 1, 4, 1, 6100, 15, 1, 1, 1, 1};
struct variable2 ctWwwExtNotifyCtrlEntry_variables[] = {
    { CTNOTIFYCTRLVALUE, ASN_INTEGER, RWRITE, var_ctWwwExtNotifyCtrlEntry, 1, {2} },
    { CTNOTIFYCTRLCACHEENTRIES, ASN_INTEGER, RWRITE, var_ctWwwExtNotifyCtrlEntry, 1, {3} },
};

void init_covalent_www_extensions_notification_group()
{
    REGISTER_MIB("www-resp-notify-mib/ctWwwExtNotifyCtrlEntry", ctWwwExtNotifyCtrlEntry_variables,
         variable2, ctWwwExtNotifyCtrlEntry_oid);
};

void
generate_ctWwwExtResponseNotification(unsigned int wwwServiceIndex,
                                   unsigned int wwwProtocol,
                                   apr_time_t wwwRequestTime,
                                   unsigned long wwwRequestInType,
                                   unsigned long wwwBytesIn,
                                   unsigned long wwwResponseOutType,
                                   unsigned long wwwBytesOut,
                                   char *wwwDocName,
                                   char *wwwStatusMsg)
{
/* Oid definition of the Notification */
static oid ctWwwExtNotifyResponse_oid[] = { 1, 3, 6, 1, 4, 1, 6100, 3, 3, 1 };
/* Oid definition of the Notification Objects */
static oid ctWwwExtNotifyWwwService_oid[] = { 1, 3, 6, 1, 4, 1, 6100, 3, 2, 1, 0 };
static oid ctWwwExtNotifyWwwDocName_oid[] = { 1, 3, 6, 1, 4, 1, 6100, 3, 2, 2, 0 };
static oid ctWwwExtNotifyWwwTimeStamp_oid[] = { 1, 3, 6, 1, 4, 1, 6100, 3, 2, 3, 0 };
static oid ctWwwExtNotifyWwwRequestType_oid[] = { 1, 3, 6, 1, 4, 1, 6100, 3, 2, 4, 0 };
static oid ctWwwExtNotifyWwwResponseType_oid[] = { 1, 3, 6, 1, 4, 1, 6100, 3, 2, 5, 0 };
static oid ctWwwExtNotifyWwwStatusMessage_oid[] = { 1, 3, 6, 1, 4, 1, 6100, 3, 2, 6, 0 };
/* varbind variables of the Notification Objects */
struct variable_list ctWwwExtNotifyWwwService_var;
struct variable_list ctWwwExtNotifyWwwDocName_var;
struct variable_list ctWwwExtNotifyWwwTimeStamp_var;
struct variable_list ctWwwExtNotifyWwwRequestType_var;
struct variable_list ctWwwExtNotifyWwwResponseType_var;
struct variable_list ctWwwExtNotifyWwwStatusMessage_var;
www_protocol_t *protocol;
char *request_type;
server_rec *service;

    DEBUGTRACE;
    for (service = get_www_service_root(); service ; service = service->next) {
        if (wwwServiceIndex == get_www_service_index(service)) {
            break;
        }
    } 
    protocol = get_www_protocol_definition_by_number(wwwProtocol);
    if (ctWwwExtNotifyResponse_enabled(protocol, wwwResponseOutType)) {
        memset(&ctWwwExtNotifyWwwService_var, 0, sizeof(ctWwwExtNotifyWwwService_var));
        snmp_set_var_objid(&ctWwwExtNotifyWwwService_var, ctWwwExtNotifyWwwService_oid,
				sizeof(ctWwwExtNotifyWwwService_oid)/sizeof(oid));
        long_return = wwwServiceIndex + 1;
        snmp_set_var_value(&ctWwwExtNotifyWwwService_var, (u_char *)&(long_return),
				sizeof(long_return));
        ctWwwExtNotifyWwwService_var.type = ASN_UNSIGNED;
        ctWwwExtNotifyWwwService_var.next_variable = &ctWwwExtNotifyWwwDocName_var;

        memset(&ctWwwExtNotifyWwwDocName_var, 0, sizeof(ctWwwExtNotifyWwwDocName_var));
        snmp_set_var_objid(&ctWwwExtNotifyWwwDocName_var, ctWwwExtNotifyWwwDocName_oid,
				sizeof(ctWwwExtNotifyWwwDocName_oid)/sizeof(oid));
        snmp_set_var_value(&ctWwwExtNotifyWwwDocName_var, wwwDocName,
				strlen(wwwDocName));
        ctWwwExtNotifyWwwDocName_var.type = ASN_OCTET_STR;
        ctWwwExtNotifyWwwDocName_var.next_variable = &ctWwwExtNotifyWwwTimeStamp_var;

        memset(&ctWwwExtNotifyWwwTimeStamp_var, 0, sizeof(ctWwwExtNotifyWwwTimeStamp_var));
        snmp_set_var_objid(&ctWwwExtNotifyWwwTimeStamp_var, ctWwwExtNotifyWwwTimeStamp_oid,
				sizeof(ctWwwExtNotifyWwwTimeStamp_oid)/sizeof(oid));
        snmp_set_var_value(&ctWwwExtNotifyWwwTimeStamp_var, return_buf,
				snmp_time2DateAndTime(wwwRequestTime, return_buf));
        ctWwwExtNotifyWwwTimeStamp_var.type = ASN_OCTET_STR;
        ctWwwExtNotifyWwwTimeStamp_var.next_variable = &ctWwwExtNotifyWwwRequestType_var;
        request_type = (char *)get_request_type(protocol, wwwRequestInType);
        if (request_type == NULL) {
            request_type = "<unknown>";
        }
        memset(&ctWwwExtNotifyWwwRequestType_var, 0, sizeof(ctWwwExtNotifyWwwRequestType_var));
        snmp_set_var_objid(&ctWwwExtNotifyWwwRequestType_var, ctWwwExtNotifyWwwRequestType_oid,
				sizeof(ctWwwExtNotifyWwwRequestType_oid)/sizeof(oid));
        snmp_set_var_value(&ctWwwExtNotifyWwwRequestType_var, request_type,
				strlen(request_type));
        ctWwwExtNotifyWwwRequestType_var.type = ASN_OCTET_STR;
        ctWwwExtNotifyWwwRequestType_var.next_variable = &ctWwwExtNotifyWwwResponseType_var;

        memset(&ctWwwExtNotifyWwwResponseType_var, 0, sizeof(ctWwwExtNotifyWwwResponseType_var));
        snmp_set_var_objid(&ctWwwExtNotifyWwwResponseType_var, ctWwwExtNotifyWwwResponseType_oid,
				sizeof(ctWwwExtNotifyWwwResponseType_oid)/sizeof(oid));
        snmp_set_var_value(&ctWwwExtNotifyWwwResponseType_var, (u_char *)&wwwResponseOutType,
				sizeof(wwwResponseOutType));
        ctWwwExtNotifyWwwResponseType_var.type = ASN_INTEGER;
        ctWwwExtNotifyWwwResponseType_var.next_variable = &ctWwwExtNotifyWwwStatusMessage_var;

        memset(&ctWwwExtNotifyWwwStatusMessage_var, 0, sizeof(ctWwwExtNotifyWwwStatusMessage_var));
        snmp_set_var_objid(&ctWwwExtNotifyWwwStatusMessage_var, ctWwwExtNotifyWwwStatusMessage_oid,
				sizeof(ctWwwExtNotifyWwwStatusMessage_oid)/sizeof(oid));
        snmp_set_var_value(&ctWwwExtNotifyWwwStatusMessage_var, wwwStatusMsg,
				strlen(wwwStatusMsg));
        ctWwwExtNotifyWwwStatusMessage_var.type = ASN_OCTET_STR;
        ctWwwExtNotifyWwwStatusMessage_var.next_variable = NULL;

        send_enterprise_trap_vars(6, wwwResponseOutType, ctWwwExtNotifyResponse_oid,
				sizeof(ctWwwExtNotifyResponse_oid)/sizeof(oid),
							&ctWwwExtNotifyWwwService_var);
    }
    return;
}

#endif /* COVALENT_WWW_EXTENSIONS_NOTIFICATION_GROUP */

