#!/usr/bin/perl
use lib "/usr/local/lib/perl";
#use Sitecard;
use Wireless;
use SystemInfo;

# merged version 0.0.1 - 3.5.2014 Skudlik

my %devs = (
	'10.102.2.130'	=> '5G-SEKTOR jih, ch 100 (5500,20)MHz',
	'10.102.2.162' 	=> '5G-SEKTOR zapad, ch 116 (5580,20)MHz',
	'10.102.108.34' => '5G-SEKTOR kokos.jv, ch 104 (5520,20)MHz',

);

# RO community string (musi byt pro vsechna zarizeni stejny):
my $community = "public";



#*************************************************************



# Default timespan, if the last info is not available
my $DEFAULT_TIMESPAN = 60;

my $wlaninfo = Wireless::currentState();
my $lastinfo = Wireless::lastState();
my $sysinfo = new SystemInfo;

# root 
my $base_dir=$ENV{'BASE_DIR'};
#my $base_dir="/var/vsys";
# Soubor, ktery obsahuje popis APcka
my $description=$base_dir.'/etc/default/description';
# pole s udaji o kartach
my %wlan_list;

# Vypis conntracku
#my $conntrack_command = "count_conntrack --sort --net 10.102.0.0/16 --net 192.168.0.0/16";

my $ap_name;
my $connections_yellow_limit = 100;
my $connections_red_limit = 250;

my $table_style = "evenactive";

# tabulka frekvenci a cisel WiFi kanalu


my %wlan_info;


# Jmeno APcka, v souboru "description" se hleda radek ap_name="jmen AP"
$ap_name = $1 if `cat $description` =~ /ap_name="(.*)"/;
$datetime = localtime;


################################################################################
# HEADER

print <<HEAD
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>

<head>
  <title>$ap_name: Pehled bezdrtovch spojen</title>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2">
  <link rel="stylesheet" TYPE="text/css" href="klfree.css"/>
  <link rel="stylesheet" TYPE="text/css" href="wewimo.css"/>
  <script language="javascript" type="text/javascript">
  // <!--
  
  // --> 
  </script>
</head>
<body>

<div id="top">
<a href="http://www.klfree.net/"><img src="klfree-logo.png" style="float:left"/></a>
<h1>Klfree.Net, $ap_name</h1>
provozuje
<address>
<a href="http://www.klfree.net/">Sdruen Klfree.Net</a> P.O. Box 128, 272 80 Kladno 1
</address>
</div>
<ul id="menu">
<li><a href="index.cgi">Hlavn strnka</a></li>
<li class="selected"><a href="wewimo.html">Bezdrtov st</a></li>
<li><a href="system.html">Stav systmu</a></li>
<li><a href="traffic.html">Dopravn zpravodajstv</a></li>
<li><a href="help.html">Co dlat pi porue</a></li>
</ul>
<p class="note">
Naposledy aktualizovno: $datetime
</p>
<h2>Bezdrtov karty</h2>
<table title="Bezdrtov st" width="100%" style="text-align:center">
<tr>
<th style="width:5em">Sov karta</th>
<th>ESSID</th>
<th>BSSID</th>
<th>Reim</th>
<th>Kanl</th>
<th>Rychlost</th>
<th>SNR</th>
<th>Pijato</th>
<th>Odeslno</th>
</tr>
HEAD
;
# END OF HEADER
################################################################################


my $line = "odd";
my $active = "active";

=item formatRate (rate)
Formats data rate - 2 digits + the units. When undef/0 is passed, it
return "-". 
=cut
sub formatRate($) {
    my ($rate) = @_;
    return "-" unless $rate;
    return sprintf("%.2f", $rate / 128.0);
}

=item formatTotal (total)
Formats the total so that the number does not look so scary. Uses
KB, MB, GB units. 
=cut
sub formatTotal($) {
    my ($total) = @_;
#    if ($total < 100 * 1024) {
#	return "$total";
#    }
#    if ($total < (1024 * 1024) * 10) {
#	return sprintf("%.2f kByte", $total / (1024));
#    }
#    if ($total < (1024 * 1024 * 1024) * 10) {
	return sprintf("%.2f", $total / (1024 * 1024));
#    }
#    return sprintf("%.2f GByte", $total / (1024 * 1024 * 1024));
}
    
# serazeni tak, aby se pole nacetlo podle abecedy
my @ifaces = sort $wlaninfo->devices();

foreach my $i_face (@ifaces) {
    my $wl = $wlaninfo->deviceData($i_face);
    my ($iface, $essid, $bssid, $mode, $channel, $freq, $signal, $rxBytes, $txBytes, $rate); 
	$iface = $i_face;
	$essid = $wl->{essid};
	$bssid = $wl->{ap};
	$mode = $wl->{mode};
	$channel = $wlaninfo->channelNumber($iface, $wl->{freq});
	$freq = $wl->{freq};
	$signal = $wl->{signal};
	$rxBytes = $wl->{rxBytes};
	$txBytes = $wl->{txBytes};
	$rate = $wl->{bitrate};
	
#------------- RADEK TABULKY WIFI KARET --------------
    print <<ROW
<tr class=\"$table_style\">
<td>$iface</td><td class="key" style="text-align:left">$essid</td><td>$bssid</td><td>$mode</td>
<td><b>$channel</b> ($freq GHz)</td><td>$rate Mbit/s</td><td>$signal</td><td>$rxBytes</td><td>$txBytes</td>
</tr>
ROW
;
	if ($table_style eq "evenactive") {
		$table_style = "oddactive";}
	else {$table_style = "evenactive";}
	
}



print <<SECTION2
</table>

<h2>Pipojen stanice</h2>
SECTION2
;

foreach my $iface (@ifaces) {
  my $wl = $wlaninfo->deviceData($iface);
  my $essid = $wl->{'essid'};
  my $bssid = $wl->{ap};
  # nacteni konfiguraku - zjisteni, zda je typ ap
  # FIXME - tohle zajistuje modul "Networks"
  my $iface_type = $wl->{mode};
	  
  #pouze pokud je v $iface_type ap, budeme pokracovat
  if ($iface_type eq "ap" || lc $iface_type eq lc "Master") {
  
	  $table_style = "evenactive";
	  
  #zavolani funkce (z modulu) get_clients - ziskani informaci o vsech clenech
  my %stanice = %{$wlaninfo->clients($iface)};
  my %prevStanice = %{$lastinfo->clients($iface)};
  #pocet stanic
  $count = scalar keys %stanice;
  my $devices = 0;
  map {
    $devices += scalar $sysinfo->ipsForMac($_);	  
  } keys %stanice;
  print <<CLIENTS_HEAD
<h3>Vysla: <b>$essid</b>, $count stanic(e), $devices zazen</h3>
<table title="Bezdrtov st" width="100%" style="text-align:center">
<th width="100">Stanice</th>
<th>Signl/um [dBm]</th>
<th>Rx/Tx<br>[Mb/s]</th>
<th>Rate Up/Down<br>[kb/s]</th>
<th>Total Up/Down<br>[MB]</th>
<th>Poet<br>spojen</th>
<th>Nzev</th>
<th>IP adresa</th>
</tr>
CLIENTS_HEAD
;
  	  
	  # projiti vsech polozek
    foreach my $mac (keys %stanice) {
	if (lc($mac) eq lc($bssid)) {
	    next;
	}
	my $sta = $stanice{$mac};
	my $lastSta = $prevStanice{$mac};
	
		  if ($polozka ne "info") {
	 #ziskani vsech informaci do promenych
	my ($obscured_mac, $rowspan, $wds, $snr, $max_quality, $signal_percent, $signal_lvl, $noise_lvl, $rest_percent, $txRate, $txBytes, $rxBytes, $rxRate, $ips_string, $host_string, $spojeni_string, $signal_img, $noise_img);
	
	# pole pro ip a host
	my @ips; my @hosts; my @pocet_spojeni;

	@ips = ( $sysinfo->ipsForMac($mac) );
	if (@ips == 0) {
	    $active = "inactive";
	} else {
	    $active = "active";
	}
	#nacteni vsech string polozek
	$obscured_mac = $mac;
	$obscured_mac =~ s/(.{12})(.+)/xx:xx:xx:xx:\2/;	# provizorne...
	$rowspan = (scalar @ips) || 1;
	$snr = $sta->{rssi};
	$max_quality = $sta->{maxQuality};
	$signal_percent = ($snr * 100) / $max_quality;
	$rest_percent = 100 - $signal_percent;
	$signal_lvl = $sta->{signal} ? $sta->{signal} : $snr;
	$noise_lvl = $sta->{noise} ? $sta->{noise} : "snr";

	if ($noise_lvl ne "snr") {
	    $noise_img = 110 + $noise_lvl;
	    $signal_img = 110 + $signal_lvl - $noise_img;
	} else {
	    $signal_img = ($snr * 110) / $max_quality;
	    $noise_img = 110 - $signal_img;
	}
 
	$txRate = $sta->{tx_rate};
	$txBytes = $sta->{txBytes};
	$rxBytes = $sta->{rxBytes};
	$lastTx = $lastSta->{txBytes};
	$lastRx = $lastSta->{rxBytes};
	
	my $timeDiff;
	$timeDiff = $lastinfo->timestamp() - $wlaninfo->timestamp();
	if (!$timeDiff) {
	    $timeDiff = $DEFAULT_TIMESPAN;
	}
	$txByteRate = formatRate(($txBytes - $lastTx) / $timeDiff);
	$rxByteRate = formatRate(($rxBytes - $lastRx) / $timeDiff);
	$txString = formatTotal($txBytes);
	$rxString = formatTotal($rxBytes);
	
	my $tmpr;
	@hosts = map {
	    $sysinfo->hostName($_) ? $sysinfo->hostName($_) : "<i>neznm</i>";
	} @ips;
	
	@pocet_spojeni = map {
	    $sysinfo->totalConnections($_);
	} @ips;

print "<tr class='$table_style'>";
print "<td rowspan='$rowspan'>$obscured_mac $wds </td>";

if ($noise_lvl ne "snr") {
    barGraph($signal_lvl -(95 + $noise_lvl),$rowspan,$table_style);
} else  {
    barGraph(-95 + $signal_lvl ,$rowspan);
}
print <<CLIENT

</td>
<td rowspan="$rowspan">
$wl->{bitrate} / $txRate
</td>
<td rowspan="$rowspan">
$rxByteRate / $txByteRate
</td>
<td rowspan="$rowspan">
$rxString / $txString
</td>
CLIENT
;
    if (($ips[0] eq "") || ($ips[0] eq"-") || (@ips == 0)) {
      print <<NO_IPS
<td>
-
</td>
<td>
-
</td>
<td>
-
</td>
</tr>
NO_IPS
;
	if ($table_style eq "evenactive") {
	    $table_style = "oddactive";
	} else {
	    $table_style = "evenactive";
	}	
        next;
    } # No IPs
	my $pocitadlo = 0; my $pc_spojeni;
	foreach $ip (@ips) {
          print "<tr class=\"$table_style\">" if $pocitadlo;
          $first = 0; 
	  $hostname = $hosts[$pocitadlo];
	  $pc_spojeni = $pocet_spojeni[$pocitadlo];
	if ($pc_spojeni eq "") {$pc_spojeni = "-";}
	if (($ip ne '') || ($hostname ne '')) {
      print <<IPS
<td>
$pc_spojeni
</td>
<td>
$hostname
</td>
<td align="left">
$ip
</tr>
IPS
;
	}
    $pocitadlo++;
	}
	if ($table_style eq "evenactive") {
		$table_style = "oddactive";}
	else {$table_style = "evenactive";}
	
}
	}

}
print <<CLIENTS_TAIL
</table>
<br>
CLIENTS_TAIL
;
}



#*************************************************************
print "<br>
<h2>Monitoring Ubiquity</h2>";


# definice MIBs podle specifikace IEEE802dot11:
my $MIBdot11 = ".1.2.840.10036";
my %dot11MIBs = (
	'MIBdot11StationID'	=> ".2.840.10036.1.1.1.1",
	'MIBdot11DesiredSSID'	=> ".2.840.10036.1.1.1.9",
	'MIBdot11CurrentChannel'=> ".2.840.10036.4.5.1.1",
);

# definice MIBs podle specifikace MIKROTIK-EXPERIMENTAL-MIB, Ubiquiti ji pouziva:
my $MIBmtxrWIRtabTable = ".1.3.6.1.4.1.14988.1.1.1.2";
my %mtxMIBs = (
	'MIBsignal' 		=> ".14988.1.1.1.2.1.3",
	'MIBtxbytes' 		=> ".14988.1.1.1.2.1.4",
	'MIBrxbytes' 		=> ".14988.1.1.1.2.1.5",
	'MIBtxpackets' 		=> ".14988.1.1.1.2.1.6",
	'MIBrxpackets' 		=> ".14988.1.1.1.2.1.7",
	'MIBtxrate' 		=> ".14988.1.1.1.2.1.8",
	'MIBrxrate' 		=> ".14988.1.1.1.2.1.9",
);

# preved MAC adresu z dekadickeho vyjadresni SNMP do standardniho ( XX:XX:XX:XX:XX:XX ):
sub convertMAC {
	my $mac = shift;
	$mac =~ s/(\d+)/sprintf("%02x", $1)/ge;
	$mac =~ s/\./:/g;
	return $mac;	
}

# vygeneruj bargraph s urovni signalu:
sub barGraph {
	my $signal = shift;
	my $rowspan = shift;
	my $rowst = shift;
	my $max = -32;
	my $min = -95;
	print '<td rowspan="'.$rowspan.'" width="180"><table style="border: none" border=0><tr class="'.$rowst.'"><td style="border: none" align="center" width="30">'.$signal."</td>\n";

	if ($signal > $max) {$signal = $max;}
	if ($signal < $min) {$signal = $min;}
	my $sigwidth = 2*($signal - $min);
	my $color = '#FF0000';
	if ($signal > -71) {$color = '#FFFF00'};
	if ($signal > -66) {$color = '#00FF00'};
	
	print '<td style="border: none"><table class="signal" width="126" height=14 ><tr>';
	print '<td width="'.$sigwidth.'" style="background-color: '.$color.'"> </td><td> </td></tr></table></tr></table></td>';
}


# ziskej nejake udaje s prostredi routeru:
# root 
my $base_dir=$ENV{'BASE_DIR'};
# Soubor, ktery obsahuje popis APcka
my $description=$base_dir.'/etc/default/description';
# Jmeno APcka, v souboru "description" se hleda radek ap_name="jmen AP"
my $ap_name = $1 if `cat $description` =~ /ap_name="(.*)"/;
my $datetime = localtime;

my $table_style = "evenactive";

while ( my ($ip, $nazev_ap) = each(%devs)) {
	# zpracovani jednoho zarizeni (AP):
	my $result;
	my @lines;



	# IEEE802dot11 MIBs (info o AP):	
	$result = `snmpwalk -v1 -c $community $ip $MIBdot11`;
	@lines = split("\n", $result);

	my %ap;
	foreach $line (@lines) {
		while ( my ($MIBkey, $MIBval) = each(%dot11MIBs) ) {
			if ($line =~ /.$MIBval.+: (.+)/) {	
				$ap{$MIBkey} = $1;
				break;
			}
		}
	}
	
	# Mikrotik-Experimental MIBs (info o klientech):	
	$result = `snmpwalk -v1 -c $community $ip $MIBmtxrWIRtabTable`;
	@lines = split("\n", $result);

	my %clients;

	foreach $line (@lines) {
		#print ("*** $line ***\n");
		
		while ( my ($MIBkey, $MIBval) = each(%mtxMIBs) ) {
			if ($line =~ /.$MIBval\.(\d+\.\d+\.\d+\.\d+\.\d+\.\d+)\.(\d+) = .+: (-?\d+)/) {	
				my $mac = convertMAC($1);
				$clients{convertMAC($1)} {$MIBkey} = $3;

				break;
			}
		}
	}



	# vygeneruj zahlavi tabulky klientu:
	#--------------------------------------------
print <<HEAD

<h3>$nazev_ap ,ESSID: $ap{'MIBdot11DesiredSSID'} kanl: $ap{'MIBdot11CurrentChannel'}</h3>

<table width="100%" style="text-align:center"><tr><th>Stanice</th><th>Sla signlu<br>[dB]</th><th>Rx/Tx<br>[Mbit/s]</th><th>Total Up/Down<br>[MB]</th><th>Pakety Up/Down<br>[paket]</th>
<th>Poet<br>spojen</th>
<th>Nzev</th>
<th>IP adresa</th>
</tr>
HEAD
;
	#--------------------------------------------
	my $client_sum = 0;	
	my $txbytes_sum = 0;	
	my $rxbytes_sum = 0;	
	my $txpkts_sum = 0;	
	my $rxpkts_sum = 0;	

	for my $mac (keys %clients) {

		my @ips; my @hosts; my @pocet_spojeni;

		@ips = ( $sysinfo->ipsForMac($mac) );
		my $tmpr;
		@hosts = map {
		    $sysinfo->hostName($_) ? $sysinfo->hostName($_) : "<i>neznm</i>";
		} @ips;
	
		@pocet_spojeni = map {
		    $sysinfo->totalConnections($_);
		} @ips;

		$rowspan = (scalar @ips) || 1;

		# formatovani vystupu:
		my $station = $mac;
#		$station =~ s/(.{9})(.+)/\1xx:xx:xx/;	# provizorne...
		$station =~ s/(.{12})(.+)/xx:xx:xx:xx:\2/;	# provizorne...
		my $signal = $clients{$mac}{'MIBsignal'};
		my $rxrate = $clients{$mac}{'MIBrxrate'} / 1000000;
		my $txrate = $clients{$mac}{'MIBtxrate'} / 1000000;
		my $rxbytes = sprintf("%0.2f", $clients{$mac}{'MIBrxbytes'} / 1000000);
		my $txbytes = sprintf("%0.2f", $clients{$mac}{'MIBtxbytes'} / 1000000);
		my $rxpkts = $clients{$mac}{'MIBrxpackets'};
		my $txpkts = $clients{$mac}{'MIBtxpackets'};
		print "<tr class='$table_style'>";
		print ("<td rowspan='$rowspan'>$station</td>");
		barGraph($signal,$rowspan,$table_style);
		#print ("<td>$signal</td>");
		print ("<td rowspan='$rowspan'>$rxrate/$txrate</td>");
		print ("<td rowspan='$rowspan'>$rxbytes/$txbytes</td>");
		print ("<td rowspan='$rowspan'>$rxpkts/$txpkts</td>");

		if (($ips[0] eq "") || ($ips[0] eq"-") || (@ips == 0)) {
		    print <<NO_IPS
<td>
-
</td>
<td>
-
</td>
<td>
-
</td>
</tr>
NO_IPS
;
		    if ($table_style eq "evenactive") {
			$table_style = "oddactive";
		    } else {
			$table_style = "evenactive";
		    }	
		    next;
		} # No IPs
		my $pocitadlo = 0; my $pc_spojeni;
		foreach $ip (@ips) {
		    print "<tr class=\"$table_style\">" if $pocitadlo;
		    $first = 0; 
		    $hostname = $hosts[$pocitadlo];
		    $pc_spojeni = $pocet_spojeni[$pocitadlo];
		    if ($pc_spojeni eq "") {$pc_spojeni = "-";}
		    if (($ip ne '') || ($hostname ne '')) {
			print <<IPS
<td>
$pc_spojeni
</td>
<td>
$hostname
</td>
<td align="left">
$ip
</tr>
IPS
;
		    }
		    $pocitadlo++;
		}
		if ($table_style eq "evenactive") {
		    $table_style = "oddactive";}
		else {$table_style = "evenactive";}

		$client_sum++;
		$txbytes_sum += $txbytes;	
		$rxbytes_sum += $rxbytes;	
		$txpkts_sum += $txpkts;	
		$rxpkts_sum += $rxpkts;	
		
		#for my $MIBkey (keys %MIBs) {
		#	print ("*** $MIBkey: $clients{$mac}{$MIBkey}; ***\n");
		#}
	}

	# vygeneruj zapati tabulky klientu:
	#--------------------------------------------
print <<TAIL

<tr><th>$client_sum</th><th></th><th></th><th>$rxbytes_sum/$txbytes_sum</th><th>$rxpkts_sum/$txpkts_sum</th><th></th><th></th><th></th></tr>
</table>
<br>
TAIL
;
	#--------------------------------------------
}


################################################################################
# FOOTER


print <<TAIL
<div style="margin-top:2em">
<font size="-2">
(c) Copyright 2014 Skudlik, Belgarat, K15, Jan Krajdl. Pouziti se ridi <a href="https://goldheart.klfree.czf/twiki/bin/view/SpravaSite/KlFreeDebianLicence">Licenci Klfree-Debian</a>.
</font>
</div>
</body>
</html>
TAIL
;

# END OF FOOTER
################################################################################
