<?php

/*
 * Let you create ports and ip addresses by reading snmp ifTable / ifxTable / ipAdEntIfIndex 
 * If Port name or L2Address already exists the port is not checked for adding.
 *
 * Also bind ip addresses to Object if not already allocated.
 * 
 * Let you select the interfaces, ip address and attributes to be created / set.
 *
 * Won't add anything until "Create Ports and IPs" pressed!
 * 
 *
 * Tested only with some Enterasys switches C/B and S !!!!
 *	cisco 2620XM (thx to Rob)
 * 
 * 
 * 
 * TESTED on FreeBSD 8.2, nginx/1.0.8, php 5.3.8, NET-SNMP 5.7
 *	and RackTables 0.19.11
 *
 * (c)2012 Maik Ehinger <m.ehinger@ltur.de>
 */

/****
 * INSTALL
 *
 * add to local.php
 *	include 'inc/snmpgeneric.php';
 * 
 */

/* TODOs
 * 
 *  - code cleanup
 *  - test and finalize SNMP v3 support
 *
 *  - correct iif_name display if != 1
 *
 *  - set more Object attributs / fields
 *  
 */

/*************************
 * Change Log
 * 
 * 09.12.11	minor cleanups
 * 10.02.12	make host selectable
 * 16.02.12	use getConfigVar('DEFAULT_SNMP_COMMUNITY');
 *		make snmp port types ignorable (see sg_ifType2oif_id array)
 *		add create_noconnector_ports
 * 17.02.12	changed operator & to &&
 *		make attributes, add port, add ip and port type changeable before create
 *		add sg_oid2attr
 *		add trigger (prepared only)
 *		add sg_ifType_ignore
 * 19.02.12	add ifAlias to visible label 
 *		allow ifName input if empty (preset with ifDescr)
 * 20.02.12 	change attribute code
 *		add $sg_known_sysObjectIDs (add $known_switches from snmp.php) to set HW Type
 * 		added attribute processor function code
 * 21.02.12	add vendor / device specific ports
 *		change processor function code
 *			allow to return attributes and ports
 *		add check / uncheck all (doesn't work with IE)
 *		hide snmpv3 settings if not needed
 *		add ifInOctets and ifOutOctets to interface list
 * 22.02.12	add hrefs to l2address and ipaddr
 *		add readonly textfields for ifDescr and ifAlias
 * 23.02.12	change sysObjectID merge code 
 *		change attrib processing code
 *		add regex processor function
 * 25.02.12	prefix global vars with sg_
 *		add SW version for Enterasys devices 
 * 29.02.12	add snmpgeneric_pg_entitymib
 *
 */

require_once('snmp.php');

$tab['object']['snmpgeneric'] = 'SNMP Generic sync';
$tabhandler['object']['snmpgeneric'] = 'snmpgeneric_tabhandler';
//$trigger['object']['snmpgeneric'] = 'snmpgeneric_tabtrigger';

$ophandler['object']['snmpgeneric']['create'] = 'snmpgeneric_opcreate';

/* create ports without connector */
$sg_create_noconnector_ports = FALSE;

/* deselect add port for this snmp port types */
$sg_ifType_ignore = array(
	  '1',	/* other */
	 '24',	/* softwareLoopback */
	 '33',	/*  rs232 */
	 '34', 	/* para */
	 '53',	/* propVirtual */
	'131',	/* tunnel */
	'136',	/* l3ipvlan */
	'160',	/* usb */
	'161',	/* ieee8023adLag */
);

/* ifType to RT oif_id mapping */
$sg_ifType2oif_id = array(
	/* 440 causes SQLSTATE[23000]: Integrity constraint violation:
	 *				 1452 Cannot add or update a child row: 
	 *					a foreign key constraint fails
	 */
	//  '1' => 440,	/* other => unknown 440 */
	  '1' => 1469,	/* other => virutal port 1469 */
	  '6' => 24, 	/* ethernetCsmacd => 1000BASE-T 24 */
	 '24' => 1469,	/* softwareLoopback => virtual port 1469 */
	 '33' => 1469,	/*  rs232 => RS-232 (DB-9) 681 */
	 '34' => 1469, 	/* para => virtual port 1469 */
	 '53' => 1469,	/* propVirtual => virtual port 1469 */
	 '62' => 1195,	/* fastEther => 100BASE-FX 1195 */
	'131' => 1469,	/* tunnel => virtual port 1469 */
	'136' => 1469,	/* l3ipvlan => virtual port 1469 */
	'160' => 1469,	/* usb => virtual port 1469 */
	'161' => 1469,	/* ieee8023adLag => virtual port 1469 */
);

/* -------------------------------------------------- */

/* snmp vendor list http://www.iana.org/assignments/enterprise-numbers */

$sg_known_sysObjectIDs = array
(
	/* ------------ default ------------ */
	'default' => array
	(
	//	'text' => 'default',
		'attr' => array
		(
			 2 => array('pf' => 'snmpgeneric_pf_hwtype'), 				/* HW Typ*/
				/* FQDN check only if regex matches */
			 3 => array('oid' => 'sysName.0', 'regex' => '/^[^ .]+(\.[^ .]+)+\.?/', 'uncheck' => 'no FQDN'),
			// 4 => array('pf' => 'snmpgeneric_pf_entitymib'),
			 14 => array('oid' => 'sysContact.0'),					/* Contact person */
			// 1235 => array('value' => 'Constant'),
		), 
		'port' => array
		( 
			// 'AC-in' => array('porttypeid' => '1-16', 'uncheck' => 'uncheck reason/comment'),
			// 'name' => array('porttypeid' => '1-24', 'ifDescr' => 'visible label'),
		),
	),

	/* ------------ Frauenhofer FOKUS ------------ */
	'12325' => array
	(
		'text' => 'Fraunhofer FOKUS',
	),

	'12325.1.1.2.1.1' => array
	(
		'dict_key' => 42, /* Server model noname/unknown */
		'text'	=> 'BSNMP - mini SNMP daemon (bsnmpd)',
	),

	/* ------------ Enterasys --------------- */
	'5624' => array
	(
		'text' => 'Enterasys',
		'attr' => array(
				4 => array('pf' => 'snmpgeneric_pf_enterasys'), /* SW type/version */
				),
	),

	/* Enterasys N3 */
	'5624.2.1.53' => array
	(	
		'dict_key' => 50000,
		'text' => 'N3', 
	), 

	'5624.2.2.284' => array
	(	
		'dict_key' => 50002,
		'text' => 'Securestack C2', 
	), 

	'5624.2.1.98' => array
	(	
		'dict_key' => 50002,
		'text' => 'Securestack C3', 
	), 

	'5624.2.1.100' => array
	(	
		'dict_key' => 50002,
		'text' => 'Securestack B3', 
	), 

	'5624.2.1.137' => array
	(	
		'dict_key' => 50002,
		'text' => 'Securestack B5 POE', 
	), 

	/* S3 */
	'5624.2.1.131' => array
	(
		'dict_key' => 50001,
		'text' => 'S-series',
	),

	/* S4 */
	'5624.2.1.132' => array
	(
		'dict_key' => 50001, 
		'text' => 'S-series'
	),

	/* S8 */
	'5624.2.1.133' => array
	(
		'dict_key' => 50001, 
		'text' => 'S-series'
	),

	/* ------------ Catalyst --------------- */
	'9.1' => array
	(
		'text' => 'Catalyst',
		'attr' => array(
				5 => array('pf' => 'snmpgeneric_pf_catalyst'),
				),
		
	),
) + $known_switches;
/* add snmp.php known_switches */

/* ------------ Sample function --------------- */
/*
 * Sample Precessing Function (pf)
 */
function snmpgeneric_pf_sample(&$snmp, &$sysObjectID, $attr_id) {

	$attr = &$sysObjectID['attr'][$attr_id];

	if(!isset($attr['oid']))
		return;

	/* output success banner */
	showSuccess('Found sysObjectID '.$sysObjectID['value']);

	/* access attribute oid setting and do snmpget */
	$oid = $attr['oid'];
	$value = $snmp->get($oid);

	/* set new attribute value */
	$attr['value'] = $value;

	/* do not check attribute per default */
	$attr['uncheck'] = "comment";

	/* set informal comment */
	$attr['comment'] = "comment";

	/* add additional ports */
 //	$sysObjectID['port']['name'] = array('porttypeid' => '1-24', 'ifPhysAddress' => '001122334455', 'ifDescr' => 'visible label', 'uncheck' => 'comment', 'disabled' => 'porttypeid select disabled');

} /* snmpgeneric_pf_sample */

/* ------------ Enterasys --------------- */

function snmpgeneric_pf_enterasys(&$snmp, &$sysObjectID, $attr_id) {

		$attrs = &$sysObjectID['attr'];

		snmpgeneric_pf_entitymib($snmp, $sysObjectID, $attr_id);

		/* TODO find correct way to get Bootroom and Firmware versions */

		/* Model */
 		/*if(preg_match('/.*\.([^.]+)$/', $sysObjectID['value'], $matches)) {
		 *	showNotice('Device '.$matches[1]);
		 *}
		 */

		/* TODO SW type */
		//$attrs[4]['value'] = 'Enterasys'; /* SW type */

		/* set SW version only if not already set by entitymib */
		if(isset($attrs[5]['value']) && !empty($attrs[5]['value'])) {
		
			/* SW version from sysDescr */
 			if(preg_match('/^Enterasys .* Inc\. (.+) [Rr]ev ([^ ]+) ?(.*)$/', $snmp->sysDescr, $matches)) {

				$attrs[5]['value'] = $matches[2]; /* SW version */
	
			//	showSuccess("Found Enterasys Model ".$matches[1]);
			}

		} /* SW version */

		/* add serial port */
 		//$sysObjectID['port']['console'] = array('porttypeid' => '1-29',  'ifDescr' => 'console', 'disabled' => 'disabled');

}

/* ------------ Catalyst --------------- */

/* logic from snmp.php */
function snmpgeneric_pf_catalyst(&$snmp, &$sysObjectID, $attr_id) {
		$attrs = &$sysObjectID['attr'];
 		$ports = &$sysObjectID['port'];

                $exact_release = preg_replace ('/^.*, Version ([^ ]+), .*$/', '\\1', $snmp->sysDescr);
                $major_line = preg_replace ('/^([[:digit:]]+\.[[:digit:]]+)[^[:digit:]].*/', '\\1', $exact_release);
                $ios_codes = array
                (
                        '12.0' => 244,
                        '12.1' => 251,
                        '12.2' => 252,
                );
		
		$attrs[5]['value'] = $exact_release;

                if (array_key_exists ($major_line, $ios_codes))
			$attrs[4]['value'] = $ios_codes[$major_line];

                $sysChassi = $snmp->get ('1.3.6.1.4.1.9.3.6.3.0');
                if ($sysChassi !== FALSE or $sysChassi !== NULL)
			$attrs[1]['value'] = str_replace ('"', '', substr ($sysChassi, strlen ('STRING: ')));

 		$ports['con0'] = array('porttypeid' => '1-29',  'ifDescr' => 'console'); // RJ-45 RS-232 console

		if (preg_match ('/Cisco IOS Software, C2600/', $snmp->sysDescr))
 			$ports['aux0'] = array('porttypeid' => '1-29', 'ifDescr' => 'auxillary'); // RJ-45 RS-232 aux port

                // blade devices are powered through internal circuitry of chassis
                if ($sysObjectID['value'] != '9.1.749' and $sysObjectID['value'] != '9.1.920')
                {
 			$ports['AC-in'] = array('porttypeid' => '1-16');
                }

};

/* -------------------------------------------------- */
/* -------------------------------------------------- */

/* HW Type processor function */
function snmpgeneric_pf_hwtype(&$snmp, &$sysObjectID, $attr_id) {

	$attr = &$sysObjectID['attr'][$attr_id];

	if (isset($sysObjectID['dict_key'])) {

		$value = $sysObjectID['dict_key'];
		showSuccess("Found HW type dict_key: $value");
	
		/* return array of attr_id => attr_value) */
		$attr['value'] = $value;

		/* add additional port */
 		//$sysObjectID['port']['name'] = array('porttypeid' => '1-24', 'ifPhysAddress' => '001122334455', 'ifDescr' => 'visible label');

	} else {
		showNotice("HW type dict_key not set");
	}

} /* snmpgeneric_pf_hwtype */

/* -------------------------------------------------- */

/* try to set SW version 
 * and add some AC ports
 *
 */
/* needs more testing */
function snmpgeneric_pf_entitymib(&$snmp, &$sysObjectID, $attr_id) {

	$attrs = &$sysObjectID['attr'];
	$ports = &$sysObjectID['port'];

	$entPhysicalClass = $snmp->walk('.1.3.6.1.2.1.47.1.1.1.1.5'); /* entPhysicalClass */

	if(empty($entPhysicalClass))
		return;

/*		PhysicalClass 
 *		1:other
 *		2:unknown
 *		3:chassis
 *		4:backplane
 *		5:container
 *		6:powerSupply
 *		7:fan
 *		8:sensor
 *		9:module
 *		10:port
 *		11:stack
 *		12:cpu
 */
	$modules = array_keys($entPhysicalClass, '9'); /* 9 Modules */

	if(!empty($modules)) {

		echo '<br><br>Modules<br><table>';
		echo("<tr><th>Name</th><th>MfgName</th><th>ModelName</th><th>HardwareRev</th><th>FirmwareRev</th><th>SoftwareRev</th><th>SerialNum</th>");
	
		foreach($modules as $key => $oid) {

			/* get index */
			if(!preg_match('/\.(\d+)$/',$oid, $matches)) 
				continue;

			$index = $matches[1]; 
			$name = $snmp->get(".1.3.6.1.2.1.47.1.1.1.1.7.$index"); 
			$hardwarerev = $snmp->get(".1.3.6.1.2.1.47.1.1.1.1.8.$index"); 
			$firmwarerev = $snmp->get(".1.3.6.1.2.1.47.1.1.1.1.9.$index"); 
			$softwarerev = $snmp->get(".1.3.6.1.2.1.47.1.1.1.1.10.$index"); 
			$serialnum = $snmp->get(".1.3.6.1.2.1.47.1.1.1.1.11.$index"); 
			$mfgname = $snmp->get(".1.3.6.1.2.1.47.1.1.1.1.12.$index"); 
			$modelname = $snmp->get(".1.3.6.1.2.1.47.1.1.1.1.13.$index"); 
		
			//showNotice("$name $mfgname $modelname $hardwarerev $firmwarerev $softwarerev $serialnum");

			echo("<tr><td>$name</td><td>$mfgname</td><td>$modelname</td><td>$hardwarerev</td><td>$firmwarerev</td><td>$softwarerev</td><td>$serialnum</td>");

			/* set SW version to first module software version */
			if($key == 0 ) {
				$attrs[5]['value'] = $softwarerev; /* SW version */
				$attrs[5]['comment'] = 'entity MIB';
			}

		}
	}

	echo '</table>';

	/* add AC ports */
	$powersupply = array_keys($entPhysicalClass, '6'); /* 6 powerSupply */
	$count = 1;
	foreach($powersupply as $oid) {

		/* get index */
		if(!preg_match('/\.(\d+)$/',$oid, $matches)) 
			continue;

		$index = $matches[1]; 
		$descr = $snmp->get(".1.3.6.1.2.1.47.1.1.1.1.2.$index"); 

 		$ports['AC-'.$count] = array('porttypeid' => '1-16', 'ifDescr' => $descr, 'comment' => 'entity MIB', 'uncheck' => '');
		$count++;
	}
}

/* -------------------------------------------------- */

/*
 * regex processor function
 * needs 'oid' and  'regex'
 * uses first back reference as attribute value
 */
function snmpgeneric_pf_regex(&$snmp, &$sysObjectID, $attr_id) {

	$attr = &$sysObjectID['attr'][$attr_id];

	if (isset($attr['oid']) && isset($attr['regex'])) {

		$oid = $attr['oid'];
		$regex = $attr['regex'];

		$raw_value = $snmp->get($oid);

		$value = preg_replace($regex,'\\1', $raw_value);
	
		/* return array of attr_id => attr_value) */
		$attr['value'] = $value;

	}

} /* snmpgeneric_pf_regex */

/* -------------------------------------------------- */

$sg_portiifoptions= getPortIIFOptions();
$sg_portiifoptions[-1] = 'sfp'; /* generic sfp */

$sg_portoifoptions= getPortOIOptions();

/* -------------------------------------------------- */
/* -------------------------------------------------- */

function snmpgeneric_tabhandler($object_id) {

	if(isset($_POST['snmpconfig'])) {
		if($_POST['snmpconfig'] == '1') {
			snmpgeneric_list($object_id);
		}	
	} else {
		snmpgeneric_snmpconfig($object_id);
	}
} /* snmpgeneric_tabhandler */

/* -------------------------------------------------- */

//function snmpgeneric_tabtrigger() {
//     return 'std';
//} /* snmpgeneric_tabtrigger */

/* -------------------------------------------------- */

function snmpgeneric_snmpconfig($object_id) {

	$object = spotEntity ('object', $object_id);
	//$object['attr'] = getAttrValues($object_id);
        $endpoints = findAllEndpoints ($object_id, $object['name']);

	addJS('function showsnmpv3(element) {
				if(element.value != \''.SNMPgeneric::VERSION_3.'\')
					style = \'none\';
				else
					style = \'\';

				elements = document.getElementsByName(\'snmpv3\');
				for(i=0;i<elements.length;i++) {
					elements[i].style.display=style;
				}
			};',TRUE);

	foreach( $endpoints as $key => $value) {
		$endpoints[$value] = $value;
		unset($endpoints[$key]);
	}

	foreach( getObjectIPv4Allocations($object_id) as $ip => $value) {

		if(!in_array($ip, $endpoints))
			$endpoints[$ip] = $ip;
	}

	/* try to find first FQDN or IP */
	$selectvalue = NULL;
	foreach($endpoints as $value) {
		if(preg_match('/^[^ .]+(\.[^ .]+)+\.?/',$value)) {
			$selectvalue = $value;
			break;
		}
	}

//	sg_var_dump_html($endpoints);	

	$snmpcomm = getConfigVar('DEFAULT_SNMP_COMMUNITY');
	if(empty($snmpcomm))
		$snmpcomm = mySNMP::SNMP_COMMUNITY;
			
	echo '<h1 align=center>SNMP Config</h1>';
	echo '<p align=center> SNMPv3 untested !!!</p>';
	echo '<form method=post name="snmpconfig" action='.$_SERVER['REQUEST_URI'].' />';


        echo '<table cellspacing=0 cellpadding=5 align=center class=widetable>
	<tr><th class=tdright>Host:</th><td>';
	
	echo getSelect ($endpoints, array ('name' => 'host'), $selectvalue, FALSE);

	echo'</td></tr>
        <tr>
                <th class=tdright><label for=snmpversion>Version:</label></th>
                <td class=tdleft><select id="snmpversion" name=version value=v1 onchange="showsnmpv3(this)">
			<option value='.SNMPgeneric::VERSION_1.'>v1</options>
			<option value='.SNMPgeneric::VERSION_2C.' selected>v2c</options>
			<option value='.SNMPgeneric::VERSION_3.'>v3</options>
		</td>
        </tr>
        <tr>
                <th class=tdright><label for=community>Community / Security Name:</label></th>
                <td class=tdleft><input type=text name=community value='.$snmpcomm.' ></td>
        </tr>
        <tr name="snmpv3" style="display:none;">
		<th></th>
                <td class=tdleft><p><label>Fields below are for SNMPv3 only</label></p></td>
        </tr>
        <tr name="snmpv3" style="display:none;">
                <th class=tdright><label">Security Level:</label></th>
                <td class=tdleft><select name="sec_level">
                        <option value="noAuthNoPriv" selected="selected">noAuth and no Priv</option>
                        <option value="authNoPriv" >auth without Priv</option>
                        <option value="authPriv" >auth with Priv</option>
                </select></td>
        </tr>
        <tr name="snmpv3" style="display:none;">
                <th class=tdright><label>Auth Type:</label></th>
                <td class=tdleft>
                <input name=auth_protocol type=radio value=MD5 /><label>MD5</label>
                <input name=auth_protocol type=radio value=SHA /><label>SHA</label>
                </td>
        </tr>
        <tr name="snmpv3" style="display:none;">
                <th class=tdright><label>Auth Key:</label></th>
                <td class=tdleft><input type=text id=auth_passphrase name=auth_passphrase></td>
        </tr>
        <tr name="snmpv3" style="display:none;">
                <th class=tdright><label>Priv Type:</label></th>
                <td class=tdleft>
                <input name=priv_protocol type=radio value=DES /><label>DES</label>
                <input name=priv_protocol type=radio value=AES /><label>AES</label>
                </td>
        </tr>
        <tr name="snmpv3" style="display:none;">
                <th class=tdright><label>Priv Key</label></th>
                <td class=tdleft><input type=text name=priv_passphrase></td>
        </tr>
	</tr>
	<td colspan=2>

        <input type=hidden name=snmpconfig value=1>
	<input type=submit value="Show List"></td></tr>

        </table></form>';

	
}

function snmpgeneric_list($object_id) {

    	global $sg_create_noconnector_ports, $sg_known_sysObjectIDs, $sg_portoifoptions, $sg_ifType_ignore;

	if(isset($_POST['snmpconfig'])) {
		$snmpconfig = $_POST;	
	} else {
		showError("Missing SNMP Config");
		return;
	}

	addJS('function setchecked(classname) { var boxes = document.getElementsByClassName(classname);
				 value = document.getElementById(classname).checked;
				 for(i=0;i<boxes.length;i++) {
					if(boxes[i].disabled == false)
						boxes[i].checked=value;
				 }
		};', TRUE);

	$object = spotEntity ('object', $object_id);
	$object['attr'] = getAttrValues($object_id);

	$snmpdev = new mySNMP($snmpconfig['version'], $snmpconfig['host'], $snmpconfig['community']);

	if($snmpconfig['version'] == SNMPgeneric::VERSION_3 ) {
		$snmpdev->setSecurity( $snmpconfig['sec_level'],
					$snmpconfig['auth_protocol'],
					$snmpconfig['auth_passphrase'],
					$snmpconfig['priv_protocol'],
					$snmpconfig['priv_passphrase']
					);
	}

	if($snmpdev->getErrno()) {
		showError($snmpdev->getError());
		return;
	}

	/* SNMP connect successfull */

	showSuccess("SNMP v".$snmpconfig['version']." connect to ${snmpconfig['host']} successfull");

	echo '<form name=CreatePorts method=post action='.$_SERVER['REQUEST_URI'].'&module=redirect&op=create>';

	echo "<table>";
	echo "<tr><th>OID</th><th>Value</th></tr>";

	$systemoids = array('sysDescr', 'sysObjectID', 'sysUpTime', 'sysContact', 'sysName', 'sysLocation');
	foreach ($systemoids as $shortoid) {

		$value = $snmpdev->{$shortoid};

		if($shortoid == 'sysUpTime') {
			/* in hundredths of a second */
			$secs = (int)($value / 100);
			$days = (int)($secs / (60 * 60 * 24));
			$secs -= $days * 60 *60 * 24;
			$hours = (int)($secs / (60 * 60));
			$secs -= $hours * 60 * 60;
			$mins = (int)($secs / (60));
			$secs -= $mins * 60;
			$value = "$value ($days $hours:$mins:$secs)";
		}

		echo "<tr><td title=\"".$snmpdev->lastgetoid."\">$shortoid</td><td>$value</td></tr>";
	}
	echo "</table>";

	/* sysObjectID Attributes and Ports */

	/* get sysObjectID */
	$sysObjectID['raw_value'] = $snmpdev->sysObjectID;
	$sysObjectID['value'] = preg_replace('/^.*enterprises\.([\.[:digit:]]+)$/','\\1', $sysObjectID['raw_value']);

	/* array_merge doesn't work with numeric keys !! */
	$sysObjectID['attr'] = array();
	$sysObjectID['port'] = array();
		
	$sysobjid = $sysObjectID['value'];

	$count = 1;

	while($count) {

		if(isset($sg_known_sysObjectIDs[$sysobjid])) {
			$sysObjectID = $sysObjectID + $sg_known_sysObjectIDs[$sysobjid];
	
			if(isset($sg_known_sysObjectIDs[$sysobjid]['attr']))
				$sysObjectID['attr'] = $sysObjectID['attr'] + $sg_known_sysObjectIDs[$sysobjid]['attr'];
	
			if(isset($sg_known_sysObjectIDs[$sysobjid]['port']))
				$sysObjectID['port'] = $sysObjectID['port'] + $sg_known_sysObjectIDs[$sysobjid]['port'];
	
			if(isset($sg_known_sysObjectIDs[$sysobjid]['text'])) {
				showSuccess("found sysObjectID ($sysobjid) ".$sg_known_sysObjectIDs[$sysobjid]['text']);
			}
		}

		$sysobjid = preg_replace('/\.[[:digit:]]+$/','',$sysobjid, 1, $count);
		
		/* add default sysobjectid */
		if($count == 0 && $sysobjid != 'default') {
			$sysobjid = 'default';
			$count = 1;
		}
	}

	$sysObjectID['vendor_number'] = $sysobjid;

	/* sort attributes maintain numeric keys */
	ksort($sysObjectID['attr']);

	foreach($sysObjectID['attr'] as $attr_id => &$attr) {

		if(isset($object['attr'][$attr_id])) {

			$newattrvalues = array();

			switch(TRUE) {

				case isset($attr['pf']):
					if(function_exists($attr['pf'])) {

						$attr['pf']($snmpdev, $sysObjectID, $attr_id);

					} else {
						showWarning("Missing processor function ".$attr['pf']." for attribute $attr_id");
					}

					break;

				case isset($attr['oid']):
					$attrvalue = $snmpdev->get($attr['oid']);
				 	$attr['value'] = $attrvalue;	

					if(isset($attr['regex'])) {
						if(!preg_match($attr['regex'], $attrvalue)) {
							if(!isset($attr['uncheck']))
								$attr['uncheck'] = "regex doesn't match";
						} else
							unset($attr['uncheck']);
					}

					break;

			}

		} else {
			showWarning("Object has no attribute id: $attr_id");
			unset($sysObjectID['attr'][$attr_id]);
		}

	}

	/* sort again in case there where attribs added ,maintain numeric keys */
	ksort($sysObjectID['attr']);

	/* print attributes */
	echo '<br>Attributes<br><table>';
	echo '<tr><th><input type="checkbox" id="attribute" checked="checked" onclick="setchecked(this.id)"></td>';
	echo '<th>Name</th><th>Current Value</th><th>new value</th></tr>';

	foreach($sysObjectID['attr'] as $attr_id => &$attr) {			

		if(isset($object['attr'][$attr_id]) && isset($attr['value'])) {

			$value = $attr['value'];

			$val_key = (isset($object['attr'][$attr_id]['key']) ? ' ('.$object['attr'][$attr_id]['key'].')' : '' );
			$comment = '';

			if(isset($attr['comment'])) {
				if(!empty($attr['comment']))
					$comment = $attr['comment'];
			}

			if(isset($attr['uncheck'])) {
				$checked = '';
				$comment .= ', '.$attr['uncheck'];
			} else {
				$checked = ' checked="checked"';
			}

			$updateattrcheckbox = '<b style="background-color:#00ff00">'
					 .'<input style="background-color:#00ff00" class="attribute" type="checkbox" name="updateattr['.$attr_id.']" value="'.$value.'"'
					.$checked.'></b>';

			$comment = trim($comment,', ');

			echo "<tr><td>$updateattrcheckbox</td><td title=\"id: $attr_id\">"
				.$object['attr'][$attr_id]['name'].'</td><td style="background-color:#d8d8d8">'
				.$object['attr'][$attr_id]['value'].$val_key.'</td><td>'.$value.'</td>'
				.'<td style="color:#888888">'.$comment.'</td></tr>';
		}
	}

	echo '</table>';

	//sg_var_dump_html($sysObjectID['attr']);

	/* ports */

	$objectports = getPortsNameL2address($object_id);

	$newporttypeoptions = getNewPortTypeOptions();

//	sg_var_dump_html($sysObjectID['port']);

	if(!empty($sysObjectID['port'])) {

		echo '<br>Vendor / Device specific ports<br>';
		echo '<table><tr><th><input type="checkbox" id="moreport" checked="checked" onclick="setchecked(this.id)"></th><th>ifName</th><th>porttypeid</th></tr>';
	
		foreach($sysObjectID['port'] as $name => $port) {

			if(array_key_exists($name,$objectports))
				$disableport = TRUE;
			else
				$disableport = FALSE;

			$comment = '';

			if(isset($port['comment'])) {
				if(!empty($port['comment']))
					$comment = $port['comment'];
			}
			if(isset($port['uncheck'])) {
				$checked = '';
				$comment .= ', '.$port['uncheck'];
			} else {
				$checked = ' checked="checked"';
			}

			$portcreatecheckbox = '<b style="background-color:'.($disableport ? '#ff0000' : '#00ff00')
					.'"><input style="background-color:'.($disableport ? '#ff0000' : '#00ff00').'" class="moreport" type="checkbox" name="portcreate['.$name.']" value="'.$name.'"'
					.($disableport ? ' disabled="disbaled"' : $checked ).'></b>';

			$formfield = '<input type="hidden" name="ifName['.$name.']" value="'.$name.'">';
			echo "<tr>$formfield<td>$portcreatecheckbox</td><td>$name</td>";

			if(isset($port['disabled'])) {
				$disabledselect = array('disabled' => "disabled");
			} else
				$disabledselect = array();


			foreach($port as $key => $value) {

				if($key == 'uncheck' || $key == 'comment')
					continue;
	
				/* TODO iif_name */
				if($key == 'porttypeid')
					$displayvalue = getNiftySelect($newporttypeoptions,
							 array('name' => "porttypeid[$name]") + $disabledselect, $value);
											/* disabled formfied won't be submitted ! */
				else 
					$displayvalue = $value;

				$formfield = '<input type="hidden" name="'.$key.'['.$name.']" value="'.$value.'">';
				echo "$formfield<td>$displayvalue</td>";
			}

			$comment = trim($comment,', ');
			echo "<td style=\"color:#888888\">$comment</td></tr>";
		}
		
		echo '</table>';
	}

	/* snmp ports */

	$ifsnmp = new ifSNMP($snmpdev);

	echo "<br><br>ifNumber: ".$ifsnmp->ifNumber."<br>";

	$portcompat = getPortInterfaceCompat();

	$ifsnmp->printifInfoTableHeader("<th>add port</th><th>add ip</th><th>porttypeid</th><th>comment</th></tr>");

	echo '<tr><td colspan="12"></td>
		<td><input type="checkbox" id="ports" onclick="setchecked(this.id)"></td>
		<td><input type="checkbox" id="ipaddr" onclick="setchecked(this.id)"></td></tr>';

	foreach($ifsnmp as $if) {

		$createport = TRUE;
		$disableport = FALSE;
		$ignoreport = FALSE;

		$hrefs = array();

		$comment = "";

		if(trim($ifsnmp->ifName($if)) == '') {
			$comment .= "no ifName";
			$createport = FALSE;
		} else {

			if(array_key_exists($ifsnmp->ifName($if),$objectports)){
				$comment .= "Name exists";
				$createport = FALSE;
				$disableport = TRUE;
			}
		}

		if($ifsnmp->ifPhysAddress($if) != '' ) {

			$l2port =  sg_checkL2Address($ifsnmp->ifPhysAddress($if));

			//if(alreadyUsedL2Address($ifsnmp->ifPhysAddress($if), $object_id)) {

			if(!empty($l2port)) {
				$l2object_id = key($l2port);

				$porthref = makeHref(array('page'=>'object', 'tab' => 'ports',
								 'object_id' => $l2object_id, 'hl_port_id' => $l2port[$l2object_id]));

				$comment .= ", L2Address exists";
				$hrefs['ifPhysAddress'] = $porthref;
				$createport = FALSE;
				$disableport = TRUE;
			}
		}


		$porttypeid = guessRToif_id($ifsnmp->ifType($if), $ifsnmp->ifDescr($if));

		if(in_array($ifsnmp->ifType($if),$sg_ifType_ignore)) {
			$comment .= ", ignore if type";
			$createport = FALSE;
			$ignoreport = TRUE;
		}
		
		/* ignore ports without an Connector */
		if(!$sg_create_noconnector_ports && ($ifsnmp->ifConnectorPresent($if) == 2)) {
			$comment .= ", no Connector";
			$createport = FALSE;
		}

		
		/* Allocate IPs */
		$createipaddr = FALSE;		
		$disableipaddr = FALSE;

		$ipaddr = $ifsnmp->ipaddress($if);
	
		if( $ipaddr != '' ) {

			/* TODO getIPAdressNetworkId */

			$address = getIPAddress($ipaddr);

			/* only if ip not already allocated */
			if(empty($address['allocs'])) {
				if(!$ignoreport)
					$createipaddr = TRUE;
			} else {
				$disableipaddr = TRUE;

				$ipobject_id = $address['allocs'][0]['object_id'];

				$ipaddrhref = makeHref(array('page'=>'object',
								 'object_id' => $ipobject_id, 'hl_ipv4_addr' => $ipaddr));

				$hrefs['ipaddress'] = $ipaddrhref;
			}
					
			if($ipaddr == '127.0.0.1') {
				$createipaddr = FALSE;
			}
		}
		

		/* checkboxes for add port and add ip */
	 	/* FireFox needs <b style=..>, IE and Opera work with <td style=..> */	
		$portcreatecheckbox = '<b style="background-color:'.($disableport ? '#ff0000' : '#00ff00').'"><input class="ports" style="background-color:'.($disableport ? '#ff0000' : '#00ff00')
					.'" type="checkbox" name="portcreate['.$if.']" value="'.$if.'"'
					.($disableport ? ' disabled="disbaled"' : '').($createport ? ' checked="checked"' : '').'></b>';
		
		if(!empty($ipaddr))
			$ipaddrcreatecheckbox = '<b style="background-color:'.($disableipaddr ? '#ff0000' : '#00ff00').'"><input class="ipaddr" style="background-color:'.($disableipaddr ? '#ff0000' : '#00ff00')
					.'" type="checkbox" name="ipaddrcreate['.$if.']" value="'.$if.'"'
					.($disableipaddr ? ' disabled="disabled"' : '').($createipaddr ? ' checked="checked"' : '').'></b>';
		else
			$ipaddrcreatecheckbox = '';
		
		/* port type id */
		/* add port type to newporttypeoptions if missing */
		if(strpos(serialize($newporttypeoptions),$porttypeid) === FALSE) {

			$portids = explode('-',$porttypeid);
			$oif_name = $sg_portoifoptions[$portids[1]];

			$newporttypeoptions['auto'] = array($porttypeid => "*$oif_name");  
		}

		$selectoptions = array('name' => "porttypeid[$if]");

		if($disableport)
			$selectoptions['disabled'] = "disabled";

		$porttypeidselect = getNiftySelect($newporttypeoptions, $selectoptions, $porttypeid);

		$comment = trim($comment,', ');

		$ifsnmp->printifInfoTableRow($if,"<td>$portcreatecheckbox</td><td>$ipaddrcreatecheckbox</td><td>$porttypeidselect</td><td nowrap=\"nowrap\">$comment</td>", $hrefs);

	}

	/* preserve snmpconfig */
	foreach($_POST as $key => $value) {
		echo '<input type=hidden name='.$key.' value='.$value.' />';
	}

	echo '<tr><td colspan=15 align="right"><p><input type=submit value="Create Ports and IPs"></p></td></tr></table></form>';

}

/* -------------------------------------------------- */
function snmpgeneric_opcreate() {

	$object_id = $_REQUEST['object_id'];
	$attr = getAttrValues($object_id);

//	sg_var_dump_html($_REQUEST);
//	sg_var_dump_html($attr);

	if(isset($_POST['updateattr']))
		$updateattr = TRUE;
	else
		$updateattr = FALSE;

	if(isset($_POST['portcreate']))
		$portcreate = TRUE;
	else
		$portcreate = FALSE;

	if(isset($_POST['ipaddrcreate']))
		$ipaddrcreate = TRUE;
	else
		$ipaddrcreate = FALSE;

	
	/* commitUpdateAttrValue ($object_id, $attr_id, $new_value); */
	if($updateattr)
		foreach($_POST['updateattr'] as $attr_id => $value) {
		//	if(empty($attr[$attr_id]['value']))
				if(!empty($value)) {
					commitUpdateAttrValue ($object_id, $attr_id, $value);
					showSuccess("Attribute ".$attr[$attr_id]['name']." set to $value");
				}
		}

	/* create ports */
	if($portcreate)
		foreach($_POST['portcreate'] as $if => $value) {

			$ifName = (isset($_POST['ifName'][$if]) ? trim($_POST['ifName'][$if]) : '' );
			$ifPhysAddress = (isset($_POST['ifPhysAddress'][$if]) ? trim($_POST['ifPhysAddress'][$if]) : '' );
			$ifAlias = (isset($_POST['ifAlias'][$if]) ? trim($_POST['ifAlias'][$if]) : '' );
			$ifDescr = (isset($_POST['ifDescr'][$if]) ? trim($_POST['ifDescr'][$if]) : '' );

			$visible_label = (empty($ifAlias) ? '' : $ifAlias.'; ').$ifDescr;

			if(empty($ifName)) {
				showError('Port without ifName '.$_POST['porttypeid'][$if].', '.$visible_label.', '.$ifPhysAddress);
			} else {
 				commitAddPort ($object_id, $ifName, $_POST['porttypeid'][$if], $visible_label, $ifPhysAddress);
				showSuccess('Port created '.$ifName.', '.$_POST['porttypeid'][$if].', '.$visible_label.', '.$ifPhysAddress);
			}
		}

	/* allocate ip adresses */
	if($ipaddrcreate) {
		foreach($_POST['ipaddrcreate'] as $if => $value) {	

			$ipaddr = $_POST['ipaddress'][$if];

			bindIpToObject($ipaddr, $object_id,$_POST['ifName'][$if], 1); /* connected */
			showSuccess("$ipaddr allocated"); 
		}
	}

} /* snmpgeneric_opcreate */

/* -------------------------------------------------- */

/* returns RT interface type depending on ifType, ifDescr, .. */
function guessRToif_id($ifType,$ifDescr = NULL) {
	global $sg_ifType2oif_id;
	global $sg_portiifoptions;
	global $sg_portoifoptions;

	/* default value */
	$retval = '24'; /* 1000BASE-T */

	if(isset($sg_ifType2oif_id[$ifType])) {
		$retval = $sg_ifType2oif_id[$ifType];
	}

	if(strpos($retval,'-') === FALSE)
		$retval = "1-$retval";

	/* no ethernetCsmacd */
	if($ifType != 6) 
		return $retval;


	/* try to identify outer and inner interface type from ifDescr */

	/**********************
	 * ifDescr samples
	 *
	 * Enterasys C3
	 *
	 * Unit: 1 1000BASE-T RJ45 Gigabit Ethernet Frontpanel Port 45 - no sfp inserted
	 * Unit: 1 1000BASE-T RJ45 Gigabit Ethernet Frontpanel Port 47 - sfp 1000BASE-SX inserted
	 *
	 *
	 * Enterasys S4
	 *
         * Enterasys Networks, Inc. 1000BASE Gigabit Ethernet Port; No GBIC/MGBIC Inserted
	 * Enterasys Networks, Inc. 1000BASE-SX Mini GBIC w/LC connector
	 * Enterasys Networks, Inc. 10GBASE SFP+ 10-Gigabit Ethernet Port; No SFP+ Inserted
	 * Enterasys Networks, Inc. 10GBASE-SR SFP+ 10-Gigabit Ethernet Port (850nm Short Wavelength, 33/82m MMF, LC)
	 * Enterasys Networks, Inc. 1000BASE Gigabit Ethernet Port; Unknown GBIC/MGBIC Inserted
 	 *
	 */

	foreach($sg_portiifoptions as $iif_id => $iif_type) {
		
		/* TODO better matching */


		/* find iif_type */
		if(preg_match('/(.*?)('.preg_quote($iif_type).')(.*)/i',$ifDescr,$matches)) {

			$oif_type = "empty ".$iif_type;

			$no = preg_match('/ no $/i', $matches[1]);

			if(preg_match('/(\d+[G]?)BASE[^ ]+/i', $matches[1], $basematch)) {
				$oif_type=$basematch[0];
			} else {
				if(preg_match('/(\d+[G]?)BASE[^ ]+/i', $matches[3], $basematch)) {
					$oif_type=$basematch[0];
				}
			}

			if($iif_id == -1) {
				/* 2 => SFP-100 or 4 => SFP-1000 */

				if(isset($basematch[1])) {
					switch($basematch[1]) {
						case '100' :
							$iif_id = 2;
							$iif_type = "SFP-100";
							break;
						default:
						case '1000' :
							$iif_id = 4;	
							$iif_type = "SFP-1000";
							break;
					}
				}
				
			}

			if($no) {
				$oif_type = "empty ".$iif_type;
			}

			$oif_type = preg_replace('/BASE/',"Base",$oif_type);

			$oif_id = array_search($oif_type,$sg_portoifoptions);

			if($oif_id != '') {
				$retval = "$iif_id-$oif_id";
			}

			/* TODO check port compat */

			/* stop foreach */
			break;
		}
	}

	if(strpos($retval,'-') === FALSE)
		$retval = "1-$retval";

	return $retval;

}

/* --------------------------------------------------- */

/* returns object_id and port_id to a given l2address */
function sg_checkL2Address ($address)
{
        $result = usePreparedSelectBlade
        (
                'SELECT object_id,id FROM Port WHERE BINARY l2address = ?',
                array ($address)
        );
        $row = $result->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_COLUMN);
        return $row;
}

/* returns Ports Name and L2Address as associated array Name => L2Address */
function getPortsNameL2address($my_object_id)
{
        $result = usePreparedSelectBlade
        (
                'SELECT name,l2address FROM Port WHERE object_id = ? ORDER BY name',
                array ($my_object_id)
        );
        $row = $result->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_COLUMN);

        return $row;
}

/* returns oi_id and name */
function getPortOIOptions()
{
        $result = usePreparedSelectBlade
        (
		'SELECT dict_key,dict_value from Dictionary where chapter_id = 2',
                array ()
        );
        $row = $result->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE|PDO::FETCH_COLUMN);
        return $row;
}



/* ------------------------------------------------------- */
class SNMPgeneric {

	protected $host;
	protected $version;

	/* SNMPv1 and SNMPv2c */
	protected $community;

	/* SNMPv3 */
	protected $sec_level;
	protected $auth_protocol;
	protected $auth_passphrase;
	protected $priv_protocol;
	protected $priv_passphrase;
//	protected $contextName;
//	protected $contextEngineID;

	const VERSION_1 = 1;
	const VERSION_2C = 2;
	const VERSION_3 = 3;


	protected $result;

	function __construct($version, $host, $community) {
		
		$this->host = $host;
		$this->version = $version;
		$this->community = $community;	

		//snmp_set_valueretrieval(SNMP_VALUE_LIBRARY);

		/* Return values without SNMP type hint */
		snmp_set_valueretrieval(SNMP_VALUE_PLAIN);

	//	snmp_set_oid_output_format(SNMP_OID_OUTPUT_FULL);
		
	//	snmp_set_quick_print(1);

	}

	function __destruct() {
	}

	function setSecurity($sec_level, $auth_protocol = 'md5', $auth_passphrase = '', $priv_protocol = 'des', $priv_passphrase = '') {
		$this->sec_level = $sec_level;
		$this->auth_protocol = $auth_protocol;
		$this->auth_passphrase = $auth_passphrase;
		$this->priv_protocol = $priv_protocol;
		$this->priv_passphrase = $priv_passphrase;
	}

	function walk( $oid, $suffix_as_key = FALSE) {

		switch($this->version) {
			case self::VERSION_1:
				if($suffix_as_key){
					$this->result = snmpwalk($this->host,$this->community,$oid);
				} else {
					$this->result = snmprealwalk($this->host,$this->community,$oid);
				}
				break;

			case self::VERSION_2C:
				if($suffix_as_key){
					$this->result = snmp2_walk($this->host,$this->community,$oid);
				} else {
					$this->result = snmp2_real_walk($this->host,$this->community,$oid);
				}
				break;

			case self::VERSION_3:
				if($suffix_as_key){
					$this->result = snmp3_walk($this->host,$this->community, $this->sec_level, $this->auth_protocol, $this->auth_passphrase, $this->priv_protocol, $this->priv_passphrase,$oid);
				} else {
					$this->result = snmp3_real_walk($this->host,$this->community, $this->sec_level, $this->auth_protocol, $this->auth_passphrase, $this->priv_protocol, $this->priv_passphrase,$oid);
				}
				break;
		}

		return $this->result;

	}

	private function __snmpget($object_id) {

		$retval = FALSE;
		
		switch($this->version) {
			case self::VERSION_1:
				$retval = snmpget($this->host,$this->community,$object_id);
				break;

			case self::VERSION_2C:
				$retval = snmp2_get($this->host,$this->community,$object_id);
				break;

			case self::VERSION_3:
				$retval = snmp3_get($this->host,$this->community, $this->sec-level, $this->auth_protocol, $this->auth_passphrase, $this->priv_protocol, $this->priv_passphrase,$object_id);
				break;
		}

		return $retval;
	}

	function get($object_id, $preserve_keys = false) {

		if(is_array($object_id)) {

			if( $preserve_keys ) {
				foreach($object_id as $oid) {
					$this->result[$oid] = $this->__snmpget($oid);
				}
			} else {
				foreach($object_id as $oid) {
					$result_oid = preg_replace('/.\d$/','',$oid);
					$this->result[$result_oid] = $this->__snmpget($oid);
				}
			}
		} else {
			$this->result = $this->__snmpget($object_id);
		}

		return $this->result;
		
	}

	function close() {
	}

	function getErrno() {
		return ($this->result === FALSE);
	}

	function getError() {
		$var = error_get_last();
		return $var['message'];
	}
} /* SNMPgeneric */

/* ------------------------------------------------------- */
/*
 * SNMP with system OIDs 
 */
class mySNMP extends SNMPgeneric implements Iterator {

	const SNMP_VERSION = SNMPgeneric::VERSION_2C;
	const SNMP_COMMUNITY = 'public';

	public $lastgetoid;

	//private $sysInfo;
	private $system;

	/* is system table available ? */
	private $systemerror = TRUE;

	function __construct($version, $host, $community) {
		parent::__construct($version, $host, $community);

		/* .iso.org.dod.internet.mgmt.mib-2.system */
		$this->system = $this->walk(".1.3.6.1.2.1.1");

		$this->systemerror = $this->getErrno();
		
	}

	/* get value from system cache */
	private function _getvalue($object_id) {

		/* TODO better matching  */

		if( isset($this->system["SNMPv2-MIB::$object_id"])) {
			$this->lastgetoid = "SNMPv2-MIB::$object_id";
			return $this->system["SNMPv2-MIB::$object_id"];
		} else {
			if( isset($this->system[".iso.org.dod.internet.mgmt.mib-2.system.$object_id"])) {
				$this->lastgetoid = ".iso.org.dod.internet.mgmt.mib-2.system.$object_id";
				return $this->system[".iso.org.dod.internet.mgmt.mib-2.system.$object_id"];
			} else {
				if( isset($this->system[$object_id])) {
					$this->lastgetoid = $object_id;
					return $this->system[$object_id];
				} else {
					foreach($this->system as $key => $value) {
						if(strpos($key, $object_id)) {
							$this->lastgetoid = $key;
							return $value;
						}
					}
				}
			}
		}

		return NULL;
	}

	function get($object_id, $preserve_keys = false) {

		if(!$this->systemerror)
			$retval = $this->_getvalue($object_id);
		else
			$retval = NULL;

		if($retval === NULL) {
			$this->lastgetoid = $object_id;
			$retval = parent::get($object_id,$preserve_keys);
		}

		return $retval;

	}
/*
	function get_new($object_id, $preserve_keys = false) {
		$result = parent::get($object_id,$preserve_keys);
		return $this->removeDatatype($result);
	}

	function walk_new($object_id) {
		$result = parent::walk($object_id);
		return $this->removeDatatype($result);
	}

*/
	/* use snmp_set_valueretrieval(SNMP_VALUE_PLAIN) instead */
/*	function removeDatatype($val) {
		return preg_replace('/^\w+: /','',$val);
	}
*/
	/* make something like $class->sysDescr work */
	function __get($name) {
		if($this->systemerror) {
			return;
		}
		
		$retval = $this->_getvalue($name);

		if($retval === NULL) {

			$trace = debug_backtrace();
        		trigger_error(
            			'Undefinierte Eigenschaft für __call(): ' . $name .
            			' in ' . $trace[0]['file'] .
            			' Zeile ' . $trace[0]['line'],
            			E_USER_NOTICE);
		}

		return $retval;
	}


	/* Iteration through all system OIDs */
	/* Iterator */

	function current() {
		if($this->systemerror)
			return;

		return current($this->system);
	}

	function key() {
		if($this->systemerror)
			return;

		return key($this->system);
	}

	function next() {
		return next($this->system);
	}

	function valid() {
		return ($this->current() !== FALSE) && ($this->systemerror !== TRUE);
	}

	function rewind() {
		if($this->systemerror)
			return;

		reset($this->system);
	}

	/* END Iterator */

} /* mySNMP */

/* ------------------------------------------------------- */

class ifSNMP implements Iterator {
	private $snmpdevice;
	private $ifNumber = 0;
	private $ifTable;

	private $interfaceserror = TRUE;

	function __construct(&$snmpdevice) {
		$this->snmpdevice = $snmpdevice;	

		$this->interfaceserror = $this->snmpdevice->getErrno();

		if($this->interfaceserror) {
			return;
		}
		
		$this->ifNumber = intval($this->snmpdevice->get('ifNumber.0'));
		
		$this->interfaceserror = $this->snmpdevice->getErrno();

		if(!$this->interfaceserror) {
			
			$this->getifTable();
		}
		
	}

	function getifTable() {
		$this->ifTable['ifIndex'] = $this->snmpdevice->walk('ifIndex',TRUE);
		$this->ifTable['ifDescr'] = $this->snmpdevice->walk('ifDescr',TRUE);
		$this->ifTable['ifAlias'] = $this->snmpdevice->walk('ifAlias',TRUE);
		$this->ifTable['ifName'] =  $this->snmpdevice->walk('ifName',TRUE);
		
		$this->ifTable['ifType'] =  $this->snmpdevice->walk('ifType',TRUE);

		$this->ifTable['ifSpeed'] =  $this->snmpdevice->walk('ifSpeed',TRUE);

		/* notation changes when SNMP_VALUE_PLAIN is set string -> hex!! */
		$this->ifTable['ifPhysAddress'] =  $this->snmpdevice->walk('ifPhysAddress',TRUE);

		$this->ifTable['ifOperStatus'] =  $this->snmpdevice->walk('ifOperStatus',TRUE);

		$this->ifTable['ifInOctets'] =  $this->snmpdevice->walk('ifInOctets',TRUE);
		$this->ifTable['ifOutOctets'] =  $this->snmpdevice->walk('ifOutOctets',TRUE);

		$this->ifTable['ifConnectorPresent'] =  $this->snmpdevice->walk('ifConnectorPresent',TRUE);

		/* ip address */
		$ipAdEntIfIndex =  $this->snmpdevice->walk('ipAdEntIfIndex');

		foreach($ipAdEntIfIndex as $oid => $value) {
			$ipaddr = preg_replace('/.*\.([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/','$1',$oid);
			$this->ifTable['ipaddress'][ array_search($value,$this->ifTable['ifIndex']) ] = $ipaddr;
		}
	}

	function printifInfoTableHeader($suffix = "") {
		if($this->interfaceserror) {
			return;
		}

		echo "<table>";
		echo "<tr>";
		foreach ($this->ifTable as $key => $value) {
			
			switch($key) {
				case 'ifOperStatus':
					$displayvalue = 'if Oper Status';
					break;
				case 'ifConnectorPresent':
					$displayvalue = 'if Con Pres';
					break;
				default:
					$displayvalue = $key;
			}

			echo "<th title=\"$key\">$displayvalue</th>";
		}
		echo "$suffix</tr>";
	}

	private $formfieldlist = array('ifName', 'ifDescr', 'ifAlias', 'ifPhysAddress', 'ipaddress');

	function printifInfoTableRow($ifIndex, $suffix = "", $hrefs = NULL) {
		if($this->interfaceserror) {
			return;
		}

		echo "<tr".($ifIndex % 2 ? ' style="background-color:#d8d8d8"' : '' ).">";

		foreach ($this->ifTable as $key => $value) {

			$textfield = FALSE;

			/* minimize posted data to necessary fields */
			if(in_array($key,$this->formfieldlist)) {

				/* $value would contain raw values; $this->{$key}($ifIndex) post processed values */
				$fieldvalue = $this->{$key}($ifIndex);

				if(!empty($fieldvalue)) {
					if($key == 'ifDescr' || $key == 'ifAlias') {	
				 		$formfield = '<input readonly="readonly" type="text" size="15" name="'.$key.'['.$ifIndex.']" value="'
								.$this->$key($ifIndex).'">';
						$textfield = TRUE;
					} else {
						$formfield = '<input type="hidden" name="'.$key.'['.$ifIndex.']" value="'.$fieldvalue.'">';
						echo $formfield;
					}
				} else {
					if($key == 'ifName') {
						/* create textfield set to ifDescr */
				 		$formfield = '<input type="text" size="8" name="'.$key.'['.$ifIndex.']" value="'
								.$this->ifDescr($ifIndex).'">';
						$textfield = TRUE;
					}

				}

			}
		

			if($textfield)
				$displayvalue=$formfield;
			else {
				$displayvalue = $this->{$key}($ifIndex);

				if(isset($hrefs) && isset($hrefs[$key])) {
					$displayvalue = "<a href=".$hrefs[$key].">$displayvalue</a>";
				}
			}
			
			echo "<td nowrap=\"nowrap\">$displayvalue</td>";
		}
		echo "$suffix</tr>";
	}

	function formatMACAddr($addr) {

		$retval = '';

		/* TODO test origin format */
		if(strlen($addr)== 6 ) {
			$retval =  unpack('H12',$addr);
			$retval = $retval[1];
		}

		/* often used as loopback on Enterasys switches */
		if($retval == '000000000000') {
			$retval = '';
		}

		return $retval;
	}

	function ifPhysAddress($index) {

		if(isset($this->ifTable['ifPhysAddress'][$index-1])) {
			return strtoupper($this->formatMACAddr($this->ifTable['ifPhysAddress'][$index-1]));
		}
	}

	function ipaddress($index) {
		if(isset($this->ifTable['ipaddress'][$index-1])) {
			return $this->ifTable['ipaddress'][$index-1];
		}

	}

	function __get($name) {

		switch($name) {
			case 'ifNumber': 
				return $this->{$name};
				break;
		}
	
		$trace = debug_backtrace();
        	trigger_error(
            		'Undefinierte Eigenschaft für __get(): ' . $name .
            		' in ' . $trace[0]['file'] .
            		' Zeile ' . $trace[0]['line'],
            		E_USER_NOTICE);

       		return NULL;
	}

	/* $obj->ifDescr(3) = $ifTable[$name][$arg]*/
	function __call($name,$args) {
		
		if($this->interfaceserror)
			return;
	
		if(isset($this->ifTable[$name])) {
			if(isset($this->ifTable[$name][$args[0]-1])) {
				return $this->ifTable[$name][$args[0]-1];
			}
		} else {
	
			/* for debug */
			$trace = debug_backtrace();
        		trigger_error(
            			'Undefinierte Methode für __call(): ' . $name .
            			' in ' . $trace[0]['file'] .
            			' Zeile ' . $trace[0]['line'],
        	    		E_USER_NOTICE);
		}

        	return NULL;

	} /* __call */

	/* Iterator */

	private $IteratorIndex = 1;

	function current() {
		return $this->IteratorIndex;
	}

	function key() {
	}

	function next() {
		$this->IteratorIndex++;
	}

	function valid() {
		return ($this->IteratorIndex<=$this->ifNumber);
	}

	function rewind() {
		$this->IteratorIndex = 1;
	}

	/* END Iterator */
}

/* ------------------------------------------------------- */
/* ------------------------------------------------------- */
/* for debugging */
function sg_var_dump_html(&$var) {
	
	echo "<pre>------------------Start Var Dump -------------------------\n";
	var_dump($var);
	echo "\n---------------------END Var Dump ------------------------</pre>";
}
?>
