/*
 * SNMPStats Module
 * Copyright (C) 2006 SOMA Networks, INC.
 * Written by: Jeffrey Magder (jmagder@somanetworks.com)
 *
 * This file is part of Kamailio, a free SIP server.
 *
 * Kamailio is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version
 *
 * Kamailio is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA
 *
 * The file implements the kamailioSIPMethodSupportedTable.  The table is
 * populated by looking to see which modules are loaded, and guessing what SIP
 * Methods they  provide.  It is quite possible that this initial implementation
 * is not very good at guessing.  This should be fixed in future releases as
 * more information becomes available.
 *
 * For full details, please see the KAMAILIO-SIP-COMMON-MIB.
 *
 */

#include "../../core/sr_module.h"
#include "../../core/mem/mem.h"

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

#include <net-snmp/library/snmp_assert.h>

#include "snmpstats_globals.h"
#include "snmpSIPMethodSupportedTable.h"

static netsnmp_handler_registration *my_handler = NULL;
static netsnmp_table_array_callbacks cb;

oid kamailioSIPMethodSupportedTable_oid[] = {
		kamailioSIPMethodSupportedTable_TABLE_OID};

size_t kamailioSIPMethodSupportedTable_oid_len =
		OID_LENGTH(kamailioSIPMethodSupportedTable_oid);


/* Create a row at the given index, containing stringToRegister, and insert it
 * into the table.  Note that stringToRegister will be copied, so it is not
 * necessary to pre-allocate this string anywhere. */
void createRow(int index, char *stringToRegister)
{

	kamailioSIPMethodSupportedTable_context *theRow;

	oid *OIDIndex;
	char *copiedString;
	int stringLength;

	theRow = SNMP_MALLOC_TYPEDEF(kamailioSIPMethodSupportedTable_context);

	if(theRow == NULL) {
		LM_ERR("failed to create a row for kamailioSIPMethodSupportedTable\n");
		return;
	}

	OIDIndex = pkg_malloc(sizeof(oid));

	if(OIDIndex == NULL) {
		free(theRow);
		LM_ERR("failed to create a row for kamailioSIPMethodSupportedTable\n");
		return;
	}

	stringLength = strlen(stringToRegister);

	copiedString = pkg_malloc((stringLength + 1) * sizeof(char));

	if(copiedString == NULL) {
		free(theRow);
		free(OIDIndex);
		LM_ERR("failed to create a row for kamailioSIPMethodSupportedTable\n");
		return;
	}

	strcpy(copiedString, stringToRegister);

	OIDIndex[0] = index;

	theRow->index.len = 1;
	theRow->index.oids = OIDIndex;
	theRow->kamailioSIPMethodSupportedIndex = index;

	theRow->kamailioSIPMethodName = (unsigned char *)copiedString;
	theRow->kamailioSIPMethodName_len = stringLength;

	CONTAINER_INSERT(cb.container, theRow);
}


/* Initializes the kamailioSIPMethodSupportedTable, and populates the tables
 * contents */
void init_kamailioSIPMethodSupportedTable(void)
{
	initialize_table_kamailioSIPMethodSupportedTable();

	/* Tables is defined as follows:
	 *
	 * 	1)  METHOD_INVITE
	 *  	2)  METHOD_CANCEL
	 *	3)  METHOD_ACK
	 *	4)  METHOD_BYE
	 *	5)  METHOD_INFO
	 *	6)  METHOD_OPTIONS
	 *	7)  METHOD_UPDATE
	 *	8)  METHOD_REGISTER
	 *	9)  METHOD_MESSAGE
	 *	10) METHOD_SUBSCRIBE
	 *	11) METHOD_NOTIFY
	 *	12) METHOD_PRACK
	 *	13) METHOD_REFER
	 *	14) METHOD_PUBLISH
	 *
	 * We should keep these indices fixed.  For example if we don't support
	 * METHOD_REGISTER but we do support METHOD_MESSAGE, then METHOD_MESSAGE
	 * should still be at index 9.
	 *
	 * NOTE: My way of checking what METHODS we support is probably wrong.
	 * Please feel free to correct it! */

	createRow(1, "METHOD_INVITE");
	createRow(2, "METHOD_CANCEL");
	createRow(3, "METHOD_ACK");
	createRow(4, "METHOD_BYE");

	if(module_loaded("options") || module_loaded("siputils")) {
		createRow(6, "METHOD_OPTIONS");
	}

	createRow(7, "METHOD_UPDATE");

	if(module_loaded("registrar")) {
		createRow(8, "METHOD_REGISTER");
		createRow(10, "METHOD_SUBSCRIBE");
		createRow(11, "METHOD_NOTIFY");
	}

	createRow(5, "METHOD_INFO");
	createRow(9, "METHOD_MESSAGE");
	createRow(12, "METHOD_PRACK");
	createRow(13, "METHOD_REFER");
	createRow(14, "METHOD_PUBLISH");
}


/* Initialize the kamailioSIPMethodSupportedTable by defining its structure and
 * callback mechanisms */
void initialize_table_kamailioSIPMethodSupportedTable(void)
{
	netsnmp_table_registration_info *table_info;

	if(my_handler) {
		snmp_log(LOG_ERR, "initialize_table_kamailioSIPMethodSupported"
						  "Table_handler called again\n");
		return;
	}

	memset(&cb, 0x00, sizeof(cb));

	/** create the table structure itself */
	table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
	if(table_info == NULL) {
		snmp_log(LOG_ERR, "failed to allocate table_info\n");
		return;
	}

	my_handler = netsnmp_create_handler_registration(
			"kamailioSIPMethodSupportedTable",
			netsnmp_table_array_helper_handler,
			kamailioSIPMethodSupportedTable_oid,
			kamailioSIPMethodSupportedTable_oid_len, HANDLER_CAN_RONLY);

	if(!my_handler) {
		SNMP_FREE(table_info);
		snmp_log(LOG_ERR, "malloc failed in initialize_table_kamailio"
						  "SIPMethodSupportedTable_handler\n");
		return;
	}

	netsnmp_table_helper_add_index(table_info, ASN_UNSIGNED);

	table_info->min_column = kamailioSIPMethodSupportedTable_COL_MIN;
	table_info->max_column = kamailioSIPMethodSupportedTable_COL_MAX;

	/***************************************************
	 * registering the table with the master agent
	 */
	cb.get_value = kamailioSIPMethodSupportedTable_get_value;
	cb.container =
			netsnmp_container_find("kamailioSIPMethodSupportedTable_primary:"
								   "kamailioSIPMethodSupportedTable:"
								   "table_container");

	DEBUGMSGTL(("initialize_table_kamailioSIPMethodSupportedTable",
			"Registering table kamailioSIPMethodSupportedTable"
			"as a table array\n"));

	netsnmp_table_container_register(
			my_handler, table_info, &cb, cb.container, 1);
}

/*
 * This routine is called to process get requests for elements of the table.
 *
 * The function is pretty much left as is from the auto-generated code.
 */
int kamailioSIPMethodSupportedTable_get_value(netsnmp_request_info *request,
		netsnmp_index *item, netsnmp_table_request_info *table_info)
{
	netsnmp_variable_list *var = request->requestvb;

	kamailioSIPMethodSupportedTable_context *context =
			(kamailioSIPMethodSupportedTable_context *)item;

	switch(table_info->colnum) {
		case COLUMN_KAMAILIOSIPMETHODNAME:

			/** SnmpAdminString = ASN_OCTET_STR */
			snmp_set_var_typed_value(var, ASN_OCTET_STR,
					(unsigned char *)context->kamailioSIPMethodName,
					context->kamailioSIPMethodName_len);
			break;

		default: /** We shouldn't get here */
			snmp_log(LOG_ERR, "unknown column in kamailioSIPMethod"
							  "SupportedTable_get_value\n");
			return SNMP_ERR_GENERR;
	}

	return SNMP_ERR_NOERROR;
}

/*
 * kamailioSIPMethodSupportedTable_get_by_idx is an auto-generated function.
 */
const kamailioSIPMethodSupportedTable_context *
kamailioSIPMethodSupportedTable_get_by_idx(netsnmp_index *hdr)
{
	return (const kamailioSIPMethodSupportedTable_context *)CONTAINER_FIND(
			cb.container, hdr);
}