<?php

//
// Common functions
//

function nfsend_connect ( ) {
	global $VARDIR;

	if ( isset($_SESSION['nfsend']) ) {
		$nfsend = $_SESSION['nfsend'];
	} else {
		$sock = "$VARDIR/run/nfsen.comm";
		$nfsend = socket_create(AF_UNIX, SOCK_STREAM, 0);
		// $nfsend = fsockopen( $sock, 0, $errno, $errstr, 10 );
		socket_set_option($nfsend, SOL_SOCKET, SO_REUSEADDR,1);

		if (!$nfsend) {
			$errstr = socket_strerror(socket_last_error());
			SetMessage('error', "nfsend connect() error: $errstr");
			unset($_SESSION['nfsend']);
			return FALSE;
		}
		if ( !socket_connect($nfsend, $sock) ) {
			$errstr = socket_strerror(socket_last_error($nfsend));
			socket_close($nfsend);
			SetMessage('error', "nfsend connect() error: $errstr");
			unset($_SESSION['nfsend']);
			return FALSE;
		}

		$timeout = array('sec' => 2, 'usec' => 0); 
		socket_set_option($nfsend, SOL_SOCKET,SO_RCVTIMEO,$timeout); 

		$hello_string = @socket_read($nfsend, 256, PHP_NORMAL_READ);
		if ( ! $hello_string ) {
			$errno = socket_last_error($nfsend);
			if ( errno ) {
				$errstr = socket_strerror(socket_last_error($nfsend));
			} else {
				$errstr = "timeout";
			}
			socket_close($nfsend);
			SetMessage('error', "nfsend read() error: $errstr");
			unset($_SESSION['nfsend']);
			return FALSE;
		}

// print "<h3>string: $hello_string</h3>";
		list($status, $extra) = split (' ', $hello_string, 2);
// print "<h3>HELLO Status: $status Extra: $extra</h3>";
		if ( $status != 220 ) {
			SetMessage('error', "nfsend connect error: $extra");
			socket_close($nfsend);
			unset($_SESSION['nfsend']);
			return FALSE;
		}
	}

	$_SESSION['nfsend'] = $nfsend;
	return TRUE;

} // End of nfsend_connect

function nfsend_disconnect ( ) {

	if ( !isset($_SESSION['nfsend']) ) {
		return;
	}
	$nfsend = $_SESSION['nfsend'];

	// try to quit politely
	if ( @socket_write($nfsend, "quit\n") == FALSE ) {
		@socket_close($nfsend);
		unset($_SESSION['nfsend']);
		return;
	}

	// read answer - even if not important at this stage
	do {
		$confirmed = @socket_read($nfsend, 256, PHP_NORMAL_READ);
	}	while ($confirmed && (strncasecmp($confirmed, ".", 1) == 0 ));

	@socket_close($nfsend);
	unset($_SESSION['nfsend']);

} // End of nfsend_disconnect

function nfsend_query ( $command, $direct_out ) {

	if ( !isset($_SESSION['nfsend']) ) {
// print "<h3>No socket - open connection first</h3>";
		nfsend_connect();
	}
	$nfsend = $_SESSION['nfsend'];

	if ( !$nfsend ) {
		SetMessage('error', "nfsend - connection failed!");
		return FALSE;
	}

// print "<h3>WRITE: $command</h3>";
	if ( @socket_write($nfsend, "$command\n") == FALSE ) {
		$errstr = socket_strerror(socket_last_error($nfsend));
// print "<h3>1st write() failed: reason: " . socket_strerror(socket_last_error($nfsend)) . "</h3>\n";
		nfsend_connect();
		$nfsend = $_SESSION['nfsend'];
		if ( @socket_write($nfsend, "$command\n") == FALSE ) {
		$errstr = socket_strerror(socket_last_error($nfsend));
			SetMessage('error', "nfsend socket_write() communication error: $errstr");
			@socket_close($nfsend);
			unset($_SESSION['nfsend']);
			return FALSE;
		}
	}

	$lines = array();
	$done = 0;
	while ( !$done ) {
		$answer = socket_read($nfsend, 1024, PHP_NORMAL_READ);
		if ( !$answer ) {
			$errno = socket_last_error($nfsend);
			if ( $errno ) {
				$errstr = socket_strerror(socket_last_error($nfsend));
			} else {
				$errstr = "timeout";
			}
			SetMessage('error', "nfsend socket_read() communication error: $errstr");

			@socket_close($nfsend);
			unset($_SESSION['nfsend']);
			return FALSE;
		}
		$answer = rtrim($answer);

		if ( strncasecmp($answer, ".", 1) == 0 ) {
// print "<h3>Skip line: '$answer'</h3>\n";
			continue;
		}
		if ( strncasecmp($answer, "ok ", 3) == 0 ) {
// print "<h3>Status ok: '$answer'</h3>\n";
			$done = 1;
			continue;
		}
		if ( strncasecmp($answer, "err ", 4) == 0 ) {
			$done = 1;
			$msg = substr($answer, 4);
			SetMessage('error', "nfsend: $msg");
			return FALSE;
		}
		if ( strncasecmp($answer, "warn ", 5) == 0 ) {
			$msg = substr($answer, 5);
			SetMessage('warning', "nfsend: $msg");
			continue;
		}
		if ( strncasecmp($answer, "alert ", 6) == 0 ) {
			$msg = substr($answer, 6);
			SetMessage('alert', "nfsend: $msg");
			continue;
		}

		if ( $direct_out ) {
			print "$answer\n";
		} else {
			$lines[] = $answer;
		}
// print "<h3>Add line: '$answer'</h3>";

	}

	return $direct_out ? TRUE : $lines;

} // End of nfsend_query

function UNIX2ISO ($time) {

	$tmp = localtime($time);
	$tstring  = $tmp[5] + 1900;
	$tmp[4]  += 1;
	$tstring .= $tmp[4] < 10 ? "0" . $tmp[4] : $tmp[4];
	$tstring .= $tmp[3] < 10 ? "0" . $tmp[3] : $tmp[3];
	$tstring .= $tmp[2] < 10 ? "0" . $tmp[2] : $tmp[2];
	$tstring .= $tmp[1] < 10 ? "0" . $tmp[1] : $tmp[1];

	return $tstring;

} // End of UNIX2ISO

function ISO2UNIX ($time) {

	// 2004 02 13 12 45 /
	preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/", $time, $matches);
	$unixtime = mktime ( $matches[4], $matches[5], 0, $matches[2], $matches[3], $matches[1]);

	return $unixtime;

} // End of ISO2UNIX

function DISPLAY2UNIX($str) {

	$_tmp = preg_replace("/-/", "", $str);

	$_len = strlen($_tmp);
	if ( $_len < 12 || $_len > 12 )
		return -1;

	if ( preg_match("/[^\d]+/", $_tmp ))
		return -1;

	if ( is_numeric($_tmp) && $_tmp > 197001010000 && $_tmp < 203801191414 ) {
		$_tmp = ISO2UNIX($_tmp);
	} else
		$_tmp = -1;

	return $_tmp;

} // End of DISPLAY2UNIX

function UNIX2DISPLAY($time) {
	// converts any UNIX time in display readable format:
	// 2004-02-13-12-45
	
	$iso = UNIX2ISO($time);

	return preg_replace("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/", "$1-$2-$3-$4-$5", $iso);

} // End of UNIX2DISPLAY

function ScaleValue ( $value, $rateval ) {

	if ( $rateval != 1 ) {
		$value = $value / $rateval;
		$rate_label = '/s';	// make bits
	} else {
		$rate_label = '';
	}

	$_1KB = 1024.0;
	$_1MB = 1024.0 * $_1KB;
	$_1GB = 1024.0 * $_1MB;
	$_1TB = 1024.0 * $_1GB;

	$scaled = 0;
	if ( $value >= $_1TB ) {
		$scaled = $value / $_1TB;
		$unit = "T";
	} elseif ( $value >= $_1GB ) {
		$scaled = $value / $_1GB;
		$unit = "G";
	} elseif ( $value >= $_1MB ) {
		$scaled = $value / $_1MB;
		$unit = "M";
	} elseif ( $value >= $_1KB ) {
		$scaled = $value / $_1KB;
		$unit = "K";
	} else {
		$scaled = $value;
		$unit = " ";
	}
	if ( $scaled > 0 )
		$str = sprintf("%5.1f %s%s", $scaled, $unit, $rate_label);
	else
		$str = "$value ${unit}${rate_label}";

	return preg_replace("/^\s+/", "", $str);
	

} // End of ScaleValue


function ScaleBytes ( $value, $rateval ) {

	if ( $rateval != 1 ) {
		$value = $value / $rateval * 8;
		$rate_label = '/s';	// make bits
		$Bit_Byte   = 'b';
	} else {
		$rate_label = '';
		$Bit_Byte   = 'B';
	}

	$_1KB = 1024.0;
	$_1MB = 1024.0 * $_1KB;
	$_1GB = 1024.0 * $_1MB;
	$_1TB = 1024.0 * $_1GB;

	$scaled = 0;
	if ( $value >= $_1TB ) {
		$scaled = $value / $_1TB;
		$unit = "T";
	} elseif ( $value >= $_1GB ) {
		$scaled = $value / $_1GB;
		$unit = "G";
	} elseif ( $value >= $_1MB ) {
		$scaled = $value / $_1MB;
		$unit = "M";
	} elseif ( $value >= $_1KB ) {
		$scaled = $value / $_1KB;
		$unit = "K";
	} else {
		$scaled = $value;
		$unit = " ";
	}
	if ( $scaled > 0 )
		$str = sprintf("%5.1f %s%s%s", $scaled, $unit, $Bit_Byte, $rate_label);
	else
		$str = "$value ${unit}${Bit_Byte}${rate_label}";

	return preg_replace("/^\s+/", "", $str);
	
} // End of ScaleBytes

function SubdirHierarchy( $t ) {
	global $SUBDIRLAYOUT;

	if ( $SUBDIRLAYOUT == 0 ) 
		return '';

	$subdir_def = array (
		"",
		"%Y/%m/%d",
		"%Y/%m/%d/%H",
		"%Y/%W/%u",
		"%Y/%W/%u/%H",
		"%Y/%j",
		"%Y/%j/%H",
		"%Y-%m-%d",		# %F not supported by PHP
		"%Y-%m-%d/%H"
	);

	return strftime ($subdir_def[$SUBDIRLAYOUT], $t);

} // End of SubdirHierarchy

//
// Plugin related functions
//

function Plugin_Error( $plugin_id ) {
	
	print "<h3>Plugin Error! Can't run plugin</h3>\n";

} // End of Plugin_Error

function GetPlugins () {

	if ( array_key_exists('PluginList', $_SESSION ) ) {
		if ( array_key_exists('PluginListUpdate', $_SESSION ) && 
		( time() - $_SESSION['PluginListUpdate'] < 600 ) ) {
			return $_SESSION['PluginList'];
		}
	}

	$plugins = nfsend_query("frontend", 0);
	if ( !is_array($plugins) ) {
		$plugins = array();
	}
	$_SESSION['PluginList'] = $plugins;
	$_SESSION['PluginListUpdate'] = time();

	return $plugins;

} // End of GetPlugins

//
// Profile related functions
//

function GetProfiles () {

	if ( array_key_exists('ProfileList', $_SESSION ) ) {
		if ( array_key_exists('ProfileListUpdate', $_SESSION ) && 
		( time() - $_SESSION['ProfileListUpdate'] < 600 ) ) {
			return $_SESSION['ProfileList'];
		}
	}

	$profiles = nfsend_query("query", 0);
	if ( is_array($profiles) ) {
		$profiles[] = "New Profile ...";
	} else {
		$profiles = array();
		$profiles[] = "&lt;No profiles available&gt;";
	}
	$_SESSION['ProfileList'] = $profiles;
	$_SESSION['ProfileListUpdate'] = time();

	return $profiles;

} // End of GetProfiles

function ReadProfile ($profile) {
	global $PROFILESTATDIR;

	$cmd = "list profile=$profile";
	$result = nfsend_query($cmd, 0);
	if ( !is_array($result) ) {
		return false;
	}

	$profileinfo = array();
	foreach ( $result as $line ) {
		// Skip rubish lines
		if ( !preg_match("/|/", $line) ) {
			continue;
		}

		list ($key, $value) = explode("|", $line);
		if ( $key == 'description' ) {
			// replace escape chars in description and remove '#' tag on each line
			$value = preg_replace("/\\\\012/", "\n", $value);
			$value = preg_replace("/\\\\047/",  "'", $value);
			$value = preg_replace("/\\\\174/",  "|", $value);
			$value = preg_replace("/\\\\134/", "\\", $value);
			$value = preg_replace("/^# /", "", $value);
			$value = preg_replace("/\n# /", "\n", $value);
			$profileinfo['comment'] = explode("\n", $value);
		} else 
			$profileinfo[$key] = $value;
	}
	return $profileinfo;

} // End of ReadProfile

function ShowMessages () {

	if ( array_key_exists('warning', $_SESSION ) ) {
		foreach ( $_SESSION['warning'] as $msg ) {
			print "<h3 class='warnstring'>WARNING: $msg!</h3>\n";
		}
		unset($_SESSION['warning']);
	}

	if ( array_key_exists('error', $_SESSION ) ) {
		foreach ( $_SESSION['error'] as $msg ) {
			print "<h3 class='errstring'>ERROR: $msg!</h3>\n";
		}
		unset($_SESSION['error']);
	}
	if ( array_key_exists('alert', $_SESSION ) ) {
		foreach ( $_SESSION['alert'] as $msg ) {
			print "<h3 class='alertstring'>ALERT: $msg!</h3>\n";
		}
		unset($_SESSION['alert']);
	}

} // End of ShowMessages

function SetMessage ($type, $message) {

	if ( $type != 'alert' && $type != 'warning' && $type != 'error' ) {
		$type = 'error';
		$message = 'Internal error, setting message';
	}
	if ( !array_key_exists($type, $_SESSION ) ) {
		$_SESSION[$type] = array();
	}
	$_SESSION[$type][] = $message;

} // End of SetWarning

function ReadStat($source) {

	global $PROFILEDATADIR;

	// indices into array
	// 1  Ident: swiix1
	// 2  Flows: 2010696
	// 3  Flows_tcp: 2010696
	// 4  Flows_udp: 0
	// 5  Flows_icmp: 0
	// 6  Flows_other: 0
	// 7  Packets: 32534108
	// 8  Packets_tcp: 32534108
	// 9  Packets_udp: 0
	// 10 Packets_icmp: 0
	// 11 Packets_other: 0
	// 12 Bytes: 19871469109
	// 13 Bytes_tcp: 19871469109
	// 14 Bytes_udp: 0
	// 15 Bytes_icmp: 0
	// 16 Bytes_other: 0
	// 17 First: 1075887894
	// 18 Last: 1075889096


	$profile = $_SESSION['profile'];
	if ( $_SESSION['tleft'] != $_SESSION['tright'] ) {
		$t = $_SESSION['tleft'];
		$tslot1   = UNIX2ISO($t);
		$subdirs1 = SubdirHierarchy($t);
	
		$t = $_SESSION['tright'];
		$tslot2 = UNIX2ISO($t);
		$subdirs2 = SubdirHierarchy($t);
		if ( strlen($subdirs1) == 0 )
			$datafile = "-R $PROFILEDATADIR/$profile/$source/nfcapd.$tslot1:nfcapd.$tslot2";
		else
			$datafile = "-R $PROFILEDATADIR/$profile/$source/$subdirs1/nfcapd.$tslot1:$subdirs2/nfcapd.$tslot2";
	
	} else {
		$t=$_SESSION['tleft'];
		$tslot = UNIX2ISO($t);
		$subdirs = SubdirHierarchy($t);
		$datafile = "-r $PROFILEDATADIR/$profile/$source/$subdirs/nfcapd.$tslot";
	}

	$statinfo = nfsend_query("nfdump args=$datafile -I", 0);
	if ( !is_array($statinfo) ) {
		return array();
	}

	// old style nfdump files
	if ( count ($statinfo) > 19 ) {
		array_unshift($statinfo, $t);
	}
	$SumStat = array();
	foreach ( $statinfo as $line ) {
		if ( strstr($line, ':') ) {
			list ($dummy, $value) = explode(": ", $line);
			$SumStat[] = $value;
		}
	}

	return $SumStat;

} // End of ReadStat 

function FindMaxValue() {

	global $PROFILEDATADIR;

	$profile = $_SESSION['profile'];
	$max_value = 0;
	$max_timeslot = 0;

	$index = 2;
	if ( $_SESSION['type'] == 'flows' ) 
		$index = 2;
	if ( $_SESSION['type'] == 'packets' ) 
		$index = 7;
	if ( $_SESSION['type'] == 'traffic' ) 
		$index = 12;

	$index_offset = 0;
	if ( $_SESSION['proto'] == 'TCP' )
		$index_offset = 1;
	if ( $_SESSION['proto'] == 'UDP' )
		$index_offset = 2;
	if ( $_SESSION['proto'] == 'ICMP' )
		$index_offset = 3;
	if ( $_SESSION['proto'] == 'other' )
		$index_offset = 4;

	$index = $index + $index_offset;
	$_tmparray = explode(':', $_SESSION['graph_sources']);

	for ( $t=$_SESSION['tleft'] - 3600; $t <= $_SESSION['tleft'] + 3600; $t += 300 ) {
		$tslot = UNIX2ISO($t);
		$subdirs = SubdirHierarchy($t);

		$sum = 0;
		foreach ( $_tmparray as $source ) {
			$statfile = "$PROFILEDATADIR/$profile/$source/$subdirs/nfcapd.$tslot";
			if ( !is_file($statfile) )
				continue;

			$tmp = nfsend_query("nfdump args=-r $statfile -I", 0);
			if ( !is_array($tmp) ) {
				return 0;
			}

			// old style nfdump files
			if ( count ($tmp) > 19 ) {
				array_unshift($tmp, "Time: $t");
			}
			$statinfo = array();
			foreach ( $tmp as $line ) {
				list ($dummy, $value) = explode(": ", $line);
				$statinfo[] = $value;
			}

			if ( $_SESSION['linegraph'] ) {
				if ( $statinfo[$index] > $sum ) 
					$sum = $statinfo[$index];
			} else {
				$sum += $statinfo[$index];
			}
		}
		if ( $sum > $max_value ) {
			$max_value = $sum;
			$max_timeslot = $t;
		}
	}

	return $max_timeslot;

} // End of FindMaxValue

function DefaultFilters () {

	global $VARDIR;

	$FilterDir = "$VARDIR/filters";
	$dh = opendir($FilterDir);

	if ( !$dh ) {
		// No filter dir. return silently => no default filters
		return;
	}
	
	$filters = array();
	while (($entry = readdir($dh)) !== false) {
		if ( is_file("$FilterDir/$entry") ) {
			$filters[] = $entry;
		}
	}
	closedir($dh);
	$_SESSION['defaultfilters'] = $filters;

} // End of DefaultFilters

/*
 * Parse the expire input string and set new_expire as the number of hours
 * for this profiles new expire value.
 * valid form:
 *	<num>				number of hours
 * 	<num> h|hour|hours	number of hours
 *	<num> d|day|days	number of days
 *	<num> d|day|days <num> h|hour|hours	combination days and hours
 * returns the number of hours of new expire or -1 if string unparsable
 */
function ParseExpire ($str) {

	$new_expire = 0;
	$valid		= 0;	// we found a valid string

	$str = preg_replace( array( '/^\s+/s', '/\s+$/s'), array( '', ''), $str);
	// a single number: add 'h'
	if ( is_numeric($str) ) {
		$str = (int)$str;
		$str .= "h";
	}

	// normalize the input string. Replace 'never' with 0h
	$str  = preg_replace("/never/i", "0h", $str);

	// normalize the input string. Replace all day, days with 'd'
	$str  = preg_replace("/days/i", "d", $str);
	$str  = preg_replace("/day/i", "d", $str);

	// normalize the input string. Replace all hour, hours with 'h'
	$str  = preg_replace("/hours/i", "h", $str);
	$str  = preg_replace("/hour/i", "h", $str);

	// now parse the string
	preg_match("/(\d+\.{0,1}\d*)\s*d/", $str, $matches);
	if ( count($matches) == 2 ) { 	// at least 2 entries are required
		$new_expire = (int)($matches[1] * 24);
		$valid = 1;
	}
	preg_match("/(\d+)\s*h/", $str, $matches);
	if ( count($matches) == 2 ) {	// at least 2 entries are required
		$new_expire += $matches[1];
		$valid = 1;
	}
	
	return $valid ? $new_expire : -1;

} // End of ParseExpire

/*
 * parse new max size.
 * valid form:
 *	<num>	defaults to num MB
 * 	<num><scale>	<scale> : K[B], M[B], G[B], and T[B]
 * returns the number of bytes of new max size or -1 if string unparsable
 */
function ParseMaxSize ($str) {

	$valid		 = 0;	// we found a valid string

	$str = preg_replace( array( '/^\s+/s', '/\s+$/s'), array( '', ''), $str);
	if ( $str == 'unlimited' ) 
		$str = "0";

	// a single number: add 'M'
	if ( is_numeric($str) ) {
		$str = (int)$str;
		$str .= "M";
	}

	// normalize the input string. Strip 'B'
	$str  = preg_replace("/B/", "", $str);

	preg_match("/(\d+\.{0,1}\d*)\s*([K|M|G|T])/", $str, $matches);
	if ( count($matches) == 3 ) {	// at least 3 entries are required
		if ( is_numeric($matches[1]) ) {
			$valid = 1;
		}
	}

	$str = preg_replace("/\s+/", '', $str);
	
	return $valid ? $str : '';

} // End of ParseMaxSize

?>
