#!/usr/bin/perl -w
#
# check_wrt54g - Nagios check plugin for testing a Linksys WRT54G
# 
#

#------------- These are used because this gets run under an embedded perl --------
use strict;
use Getopt::Long;
use LWP::UserAgent;
use HTTP::Request::Common qw(POST GET);
use HTTP::Headers;
use Storable;
#----------------------------------------------------------------------------------

# get the command line parameters
my $mode='';
my $host='';
my $urluser='';
my $urlpass='';
my $urlport='';
my $firmware_type='';
my $write_nagios_hosts=0;
my $my_type="WRT54G";
my $supported_modes="dhcp, firmware, uptime, ram , load, connections, connutil";
my $url;

my %wrt54g;

# the maximum number of times we should show previous warning messages
# we do this for states that only happen once and then would disappear eg uptime < last one, or firmware level changes
# we need to do this for the same number of time its take nagios to create a notification otherwise noone will ever get notified of these one time states
my $max_notify_count=3;  # this is a default value

process_parameters(\$mode,\$host,\$urluser,\$urlpass,\$urlport,\$write_nagios_hosts,\$firmware_type,\$max_notify_count,$my_type,$supported_modes);

if (defined($firmware_type)) {
   if ($firmware_type eq '') {
      $firmware_type="LINKSYS"; # ie Linksys
   }
} else {
   $firmware_type="LINKSYS"; # ie Linksys
}

if ( $firmware_type eq "DDWRT" || $firmware_type eq "LINKSYS" ) {
   # this is ok - we know about these types
} else {
   print "Unknown Firmware Type:$firmware_type\n";
   exit 1;
}

#=================================== CONFIG ===========================================

# nagios config dir
my $nagios_config_dir="/etc/nagios";

# nagios internet host config file
my $nagios_internet_hosts_cfg="internet_host_dynamic.cfg";

# the dir where we store all our wrt54g data 
my $nagios_etc_dir="/opt/nagios/etc";

# the dir where we store all our wrt54g data 
# everything in this dir could be deleted as it will be recreated 
my $data_dir="/tmp/nagios_plugin_data/wrt54g";
`mkdir -p "$data_dir"`;

# host template file
my $host_template="internet_host.cfg.template";

# the url on the wrt54g which gives the dhcp ip addresses
my %dhcp_url;
$dhcp_url{'LINKSYS'}=   "http://$host$urlport/Status_Router.asp";
$dhcp_url{'DDWRT'}=     "http://$host$urlport/Status_Router.asp";

# the url on the wrt54g which gives the firmware level
my %firmware_url;
$firmware_url{'LINKSYS'}=  "http://$host$urlport/SysInfo.htm";
$firmware_url{'DDWRT'}=    "http://$host$urlport/SysInfo.htm";

# the url for obtaining the system uptimes
my %uptime_url;
$uptime_url{'LINKSYS'}= "http://$host$urlport/SysInfo1.htm";
$uptime_url{'DDWRT'}=   $dhcp_url{'DDWRT'};

# the file which holds the previous wrt54g data
# we used to use a single data file and lock it
# but that sometimes held checks up and sometimes gave wierd errors
my $wrt54g_data_file="$data_dir/$host.data.$mode.$firmware_type";

# the file which holds the output last retrieved from the wrt54g
my $html_file="$data_dir/$host.html.$mode.$firmware_type.html";

# this is the list of keys we will use for all the wrt54g data we stored between runs
my @wrt54g_field_list= ( );

# get the previous wrt54g data if any
# we will use this as a reference to a hash
my $previous_wrt54g;


#------------
if ($mode eq "dhcp") {
   $url=$dhcp_url{$firmware_type};
} elsif ($mode eq "firmware") {
   $url=$firmware_url{$firmware_type};
} elsif ($mode eq "uptime" || $mode eq "ram" || $mode eq "load" || $mode eq "connutil" || $mode eq "connections") {
   $url=$uptime_url{$firmware_type};
} else {
   custom_nework_device_usage($my_type,$supported_modes);
   exit 1;
}

#===================================  MAIN  ===========================================

my $error_text;
my $error_level=0;

if ($mode eq "connections") {
   # for this mode we ssh to the box
   my $output=`ssh root\@$host sed -n "'s%.* src=\\(192.168.[0-9.]*\\).*%\\1%p' /proc/net/ip_conntrack | sort | uniq -c" 2>&1 | grep 192.168`;
   $output=~s/ / from /g;
   $output=~s/\n/, /g;
   $_=$output;
} else {
   $_=get_html($url,$urluser,$urlpass,$html_file);
}

if ($mode eq "dhcp") {
   ($error_level,$error_text)=&process_dhcp;
} elsif ($mode eq "firmware") {
   ($error_level,$error_text)=&process_firmware;
} elsif ($mode eq "uptime") {
   ($error_level,$error_text)=&process_uptime;
} elsif ($mode eq "ram") {
   ($error_level,$error_text)=&process_ram;
} elsif ($mode eq "load") {
   ($error_level,$error_text)=&process_load;
} elsif ($mode eq "connutil") {
   ($error_level,$error_text)=&process_connutil;
} elsif ($mode eq "connections") {
   ($error_level,$error_text)=&process_connections;
}

print "$error_text\n";
exit $error_level;

#=================================== FUNCTIONS ========================================
#--------------------------------------------------------------------------------------
sub parse_uptime {
# give it an "uptime string" like 5 days, 22:20 and it returns this as seconds
my ($uptime_string)=@_;
my $days=0;
my $hhmm=0;
my $h=0;
my $m=0;
my $s=0;
my $seconds=0;

# make sure its lower case
$uptime_string=lc($uptime_string);

# see if you can find the "day" part
my $day_pos=index($uptime_string,"day");
if ($day_pos>=0) {
   # find the numbers which is days in the string before $day_pos
   substr($uptime_string,0,$day_pos)=~/([0-9]+)/;
   $days=$1;   
}

# this resets the search results for $1 which were hanging around from previous searches
$uptime_string=~/()/;
# now look for the hh:mm section (it may have seconds);
# it is a string that contains a : and is at least 3 characters long
substr($uptime_string,$day_pos+1)=~/([0-9:]{3,})/;
$hhmm=$1;

if ($hhmm eq '') {
   # this resets the search results for $1 which were hanging around from previous searches
   $uptime_string=~/()/;
   # print "could not find hh:mm\n";
   # try finding xx min instead
   substr($uptime_string,$day_pos+1)=~/([0-9]{1,}) min/;
   $hhmm="00:" . $1 || 0;
}

($h,$m,$s)=split(":",$hhmm);

# make sure the variables have a value or 0
$days=$days || 0;
$h=$h || 0;
$m=$m || 0;
$s=$s || 0;

# make sure the variables have a numeric value or 0
if ($days=~ /^\d/) {
} else {
   $days=0;
}

if ($h=~ /^\d/) {
} else {
   $h=0;
}

if ($m=~ /^\d/) {
} else {
   $m=0;
}

if ($s=~ /^\d/) {
} else {
   $s=0;
}

# now convert everything we have to seconds of uptime
$seconds=86400*$days + 3600*$h + 60*$m + $s;
return $seconds;
}
#--------------------------------------------------------------
# taken from webmin-1.260/web-lib-funcs.pl (and modified)
# nice_size(bytes, [min])
# Converts a number of bytes into a number of bytes, kb, mb or gb
sub nice_size {
if (defined($_[0])) {

# we only want reporting starting at KB for this one
#   if ($_[0] > 10*1024*1024*1024) {
#      return int(($_[0]+1024*1024*1024-1)/1024/1024/1024)." GB";
#   } elsif ($_[0] > 10*1024*1024) {
#      return int(($_[0]+1024*1024-1)/1024/1024)." MB";

   if ($_[0] > 10*1024) {
      return int(($_[0]+1024-1)/1024)." kB";
   } else {
      return int($_[0])." bytes";
   }
}
}
#------------------------------------------------------------------------------
sub process_parameters {
my ($mode,$host,$urluser,$urlpass,$urlport,$write_nagios_hosts,$firmware_type,$max_notify_count,$my_type,$supported_modes)=@_;

my $result = GetOptions (
                        "mode=s"          => $mode,
                        "host=s"          => $host,    
                        "user=s"          => $urluser,     
                        "pass=s"          => $urlpass,
                        "ort=s"	         => $urlport,
                        "firmware=s"      => $firmware_type,
                        "write"           => $write_nagios_hosts,
                        "notifycount=s"   => $max_notify_count,
                        );  

if (!$result) {
   print "Parsing Error\n";
   custom_nework_device_usage($my_type,$supported_modes);
   exit 1;
}                         

if (!$mode || !$host || !$urluser || !$urlpass) {
   custom_nework_device_usage($my_type,$supported_modes);
   exit 1;
}

# very basic parameter usage/checking
$$urluser='' if $$urluser eq '-';
$$urlpass='' if $$urlpass eq '-';

if ( $$urlport ne '' ) {
	$$urlport=":$$urlport";
}

}
#--------------------------------------------------------------------------------------
sub get_html {
# get a URL and write it to a file and return it
my ($url,$urluser,$urlpass,$html_file)=@_;

my $ua = new LWP::UserAgent;
my $h = HTTP::Headers->new();

if ($urluser) {
   $h->authorization_basic($urluser, $urlpass);
}

my $req = HTTP::Request->new('GET', $url, $h);

my $res = $ua->request($req);

# save the html retrieved from the wrt54g also
open(DATA,">$html_file");
print DATA "URL: $url\n";
print DATA $res->content . "\n";
close(DATA);

return $res->content;
}
#------------------------------------------------------------------------------
sub custom_nework_device_usage {
my ($my_type,$mode_list)=@_;

print <<END;
Usage: -m MODE -h HOSTNAME -u USER -p PASS [-w] [-o PORT] [-f FIRMWARE]
where
MODE        is one of $mode_list
            (not all modes supported on all firmware types)
HOSTNAME    the hostname of the $my_type you want to CHECK
USER        the admin user name for the $my_type web interface
PASS        the admin password for the $my_type web interface
-w          write nagios hosts file if mode=dhcp result OK
PORT        the remote admin http port eg 38080
FIRMWARE    the type of firmware running eg DDWRT
END
}
#------------------------------------------------------------------------------
sub process_dhcp {
# now from the content extract
# 1: WAN IP Address
# 2: Subnet Mask
# 3: WAN Default Gateway
# 4: DHCP Server
# 5: DNS Server(s) - slightly trickier since there may be one or more

# set the fieldlist we expect
@wrt54g_field_list=( 'wan_ip','wan_subnet_mask','wan_default_router','wan_dns1','wan_dns2', 'dhcp_notify_count','dhcp_notify_text' );
$previous_wrt54g=get_the_previous_data($wrt54g_data_file,\@wrt54g_field_list,\%wrt54g);

# It is possible for the wrt54g to run a fixed IP Address on the WAN Port
# I have never developed the code to test for this

if ($firmware_type eq "DDWRT") {
   # check for DDWRT firmware
   #---------------------------- WAN_IP ---------------------------------------
   /wan_ipaddr.>([0-9\.]{7,15})<.*wan_netmask/s;
   $wrt54g{'wan_ip'}=$1 || 'NO_VALUE';
   
   #---------------------------- SUBNET MASK ---------------------------------------
   /wan_netmask.>([0-9\.]{7,15})<.*wan_gateway/s;
   $wrt54g{'wan_subnet_mask'}=$1 || 'NO_VALUE';
   
   #---------------------------- DEFAULT ROUTER ---------------------------------------
   /wan_gateway.>([0-9\.]{7,15})<.*wan_dns0/s;
   $wrt54g{'wan_default_router'}=$1 || 'NO_VALUE';
   
   #---------------------------- DHCP SERVER ---------------------------------------
   # NOT AVAILABLE FROM WRT54G
   #/DHCP Server.*>([0-9\.]{7,15})<.*DNS Server/s;
   #$wrt54g{'wan_dhcp'}=$1 || 'NO_VALUE';
   
   #---------------------------- DNS SERVERS ---------------------------------------
   # at this point in time assume 2 dns servers separated by
   /wan_dns0.>([0-9\.]{7,15})<.*wan_dns1/s;
   $wrt54g{'wan_dns1'}=$1 || 'NO_VALUE';
   
   /wan_dns1.>([0-9\.]{7,15})<.*wan_dns2/s;
   $wrt54g{'wan_dns2'}=$1 || 'NO_VALUE';
} else {
   # check for standard firmware
   #---------------------------- WAN_IP ---------------------------------------
   /share\.ipaddr.*>([0-9\.]{7,15})<.*share\.submask/s;
   $wrt54g{'wan_ip'}=$1 || 'NO_VALUE';
   
   #---------------------------- SUBNET MASK ---------------------------------------
   /share\.submask.*>([0-9\.]{7,15})<.*share\.defgateway/s;
   $wrt54g{'wan_subnet_mask'}=$1 || 'NO_VALUE';
   
   #---------------------------- DEFAULT ROUTER ---------------------------------------
   /share\.defgateway.*>([0-9\.]{7,15})<.*share\.dns.*1:/s;
   $wrt54g{'wan_default_router'}=$1 || 'NO_VALUE';
   
   #---------------------------- DHCP SERVER ---------------------------------------
   # NOT AVAILABLE FROM WRT54G
   #/DHCP Server.*>([0-9\.]{7,15})<.*DNS Server/s;
   #$wrt54g{'wan_dhcp'}=$1 || 'NO_VALUE';
   
   #---------------------------- DNS SERVERS ---------------------------------------
   # at this point in time assume 2 dns servers separated by <br>
   /share.dns.*1:.*>([0-9\.]{7,15})<.*>([0-9\.]{7,15}).*share.dns.*3:/s;
   $wrt54g{'wan_dns1'}=$1 || 'NO_VALUE';
   $wrt54g{'wan_dns2'}=$2 || 'NO_VALUE';
}


# very basic - no checking - could be improved
my $error_text="WAN_IP:$wrt54g{'wan_ip'}, WAN_SUBNET:$wrt54g{'wan_subnet_mask'}, WAN_DEFAULT_ROUTER:$wrt54g{'wan_default_router'}, DNS1:$wrt54g{'wan_dns1'}, DNS2:$wrt54g{'wan_dns2'}";
my $error_level=0;

return $error_level,$error_text;
}
#------------------------------------------------------------------------------
sub process_firmware {
# now from the content extract the firmware level
my $key='firmware';

# set the fieldlist we expect
@wrt54g_field_list=( $key );
$previous_wrt54g=get_the_previous_data($wrt54g_data_file,\@wrt54g_field_list,\%wrt54g);

/Firmware Version:(.*)/;
$wrt54g{$key}=$1 || 'NO_VALUE';

my ($error_level,$error_text)=do_firmware($key,\@wrt54g_field_list,\%wrt54g,$previous_wrt54g,$wrt54g_data_file,$html_file,$max_notify_count);

return $error_level,$error_text;
}
#------------------------------------------------------------------------------
sub process_uptime {
# now from the content extract
# the uptime data

my @uptime_list = ( 'uptime_system' );
my $differences="";
my $store_in_file=-1;
my $key;

@wrt54g_field_list=@uptime_list;
push @wrt54g_field_list,'uptime_notify_count';
push @wrt54g_field_list,'uptime_notify_text';
$previous_wrt54g=get_the_previous_data($wrt54g_data_file,\@wrt54g_field_list,\%wrt54g);

$key=$uptime_list[0];

if ($firmware_type eq "DDWRT") {
   # check for DDWRT firmware
   /setUptimeValues.. ..:..:.. .. (.*), load/;
   # uptime will look like " 2 days 02:18:30"
   $wrt54g{$key}=$1;
} else {
   # check for standard firmware
   /uptime=(.*);/; # uptime is returned in seconds
   $wrt54g{$key}=convert_seconds($1) || 'NO_VALUE';
}

my ($error_level,$error_text)=do_uptime(\@wrt54g_field_list,\%wrt54g,$previous_wrt54g,$wrt54g_data_file,$html_file,$max_notify_count);

return $error_level,$error_text;
}
#------------------------------------------------------------------------------
sub process_ram {
# now from the content extract
# the ram data

my @ram_list;

if ($firmware_type eq "DDWRT") {
   # check for DDWRT firmware
   @ram_list = ( 'ram_total', 'ram_used', 'ram_free', 'ram_buffers', 'ram_cached', 'ram_util' );
} else {
   # check for standard firmware
   @ram_list = ( 'ram_total', 'ram_free', 'ram_buffer', 'ram_util' );
}

my $key;

if ($firmware_type eq "DDWRT") {
   # check for DDWRT firmware

   # extract from
   # setMemoryValues(",'total:','used:','free:','shared:','buffers:','cached:','Mem:','14516224','13754368','761856','0','1839104','5079040','Swap:','0','0','0','MemTotal:','14176','kB','MemFree:','744','kB','MemShared:','0','kB','Buffers:','1796','kB','Cached:','4960','kB','SwapCached:','0','kB','Active:','3920','kB','Inactive:','2868','kB','HighTotal:','0','kB','HighFree:','0','kB','LowTotal:','14176','kB','LowFree:','744','kB','SwapTotal:','0','kB','SwapFree:','0','kB'");

                           #    1          2        3          4          5           6
                           # 'total:',  'used:',   'free:', 'shared:', 'buffers:','cached:'
   /setMemoryValues.*Mem:.,.([0-9]+).,.([0-9]+).,.([0-9]+).,.([0-9]+).,.([0-9]+).,.([0-9]+).,.Swap:./;
   $key=$ram_list[0];
   $wrt54g{$key}=$1 || 'NO_VALUE';

   $key=$ram_list[1];
   $wrt54g{$key}=$2 || 'NO_VALUE';

   $key=$ram_list[2];
   $wrt54g{$key}=$3 || 'NO_VALUE';

   $key=$ram_list[3];
   $wrt54g{$key}=$5 || 'NO_VALUE';

   $key=$ram_list[4];
   $wrt54g{$key}=$6 || 'NO_VALUE';

} else {
   # check for standard firmware
   /totalram=([0-9]+).*freeram=([0-9]+).*bufferram=([0-9]+);/; # ram is returned in bytes
   
   $key=$ram_list[0];
   $wrt54g{$key}=$1 || 'NO_VALUE';
   
   $key=$ram_list[1];
   $wrt54g{$key}=$2 || 'NO_VALUE';
   
   $key=$ram_list[2];
   $wrt54g{$key}=$3 || 'NO_VALUE';
   
}

if ( $wrt54g{'ram_total'} > 0 ) {
   $wrt54g{'ram_util'}=sprintf("%.1f",100 * ( $wrt54g{'ram_total'} - $wrt54g{'ram_free'} ) / $wrt54g{'ram_total'});
} else {
   $wrt54g{'ram_util'}='0';
}

my $error_text="";
my $error_level=0;

my $data_present=-1;
foreach my $key (@ram_list) {
   my $display_value;
   
   if ($key eq 'ram_util') {
      $display_value=$wrt54g{$key} . "%";
   } else {
      # change the number of bytes to a nice_size
      $display_value=nice_size($wrt54g{$key});
   }
   
   $error_text="${error_text}Current $key:$display_value ";
   if ($wrt54g{$key} ne "NO_VALUE") {
      $data_present++;
   }
}

# if all the data is there
if ($data_present == $#ram_list) {

   if ( $wrt54g{'ram_util'} > 99 ) {
      $error_level=2;
      $error_text="RAM Utilisation EXTREMELY high. $error_text";
   } elsif ( $wrt54g{'ram_util'} > 97 ) {
      $error_level=1;
      $error_text="RAM Utilisation too high. $error_text";
   }
   
} else {
   $error_level=2;
   $error_text="Could not get all ram Data. See $html_file for more details. $error_text";
}

return $error_level,$error_text;
}
#------------------------------------------------------------------------------
sub process_load {
# now from the content extract
# the load data

my @load_list = ( 'load_1min', 'load_5min', 'load_15min' );

my $key;

if ($firmware_type eq "DDWRT") {
   # check for DDWRT firmware

   # extract from
   # setUptimeValues(" 12:46:53 up  1:10, load average: 0.18, 0.14, 0.09");

   /setUptimeValues.*, load average: (.*), (.*), (.*).\)/;
   $key=$load_list[0];
   $wrt54g{$key}=$1 || 'NO_VALUE';

   $key=$load_list[1];
   $wrt54g{$key}=$2 || 'NO_VALUE';

   $key=$load_list[2];
   $wrt54g{$key}=$3 || 'NO_VALUE';

} else {
   # check for standard firmware
   $key=$load_list[0];
   $wrt54g{$key}='NOT_SUPPORTED';

   $key=$load_list[1];
   $wrt54g{$key}='NOT_SUPPORTED';

   $key=$load_list[2];
   $wrt54g{$key}='NOT_SUPPORTED';
}

my $error_text="";
my $error_level=0;

my $data_present=-1;
foreach my $key (@load_list) {

   $error_text="${error_text}Current $key:$wrt54g{$key} ";
   if ($wrt54g{$key} ne "NO_VALUE") {
      $data_present++;
   }
}

# if all the data is there
if ($data_present == $#load_list) {

   if ( $wrt54g{'load_1min'} > 3 ) {
      $error_level=1;
      $error_text="1 Min Load is high. $error_text";
   } elsif ( $wrt54g{'load_5min'} > 2 ) {
      $error_level=1;
      $error_text="5 Min Load is high. $error_text";
   } elsif ( $wrt54g{'load_15min'} > 1.5 ) {
      $error_level=1;
      $error_text="15 Min Load is high. $error_text";
   }
   
} else {
   $error_level=2;
   $error_text="Could not get all load Data. See $html_file for more details. $error_text";
}

return $error_level,$error_text;
}
#------------------------------------------------------------------------------
sub process_connutil {
# now from the content extract
# the conn data

my @conn_list = ( 'conn_max', 'conn_used', 'conn_util' );

my $key;

if ($firmware_type eq "DDWRT") {
   # check for DDWRT firmware

   # extract from
   # setMeterBar("ip_count", val / 1024 * 100, val);
   # and
   # setIpconntrackValues("75");

   /setMeterBar\(\"ip_count\", val . (.*) . 100,/;
   $key=$conn_list[0];
   $wrt54g{$key}=$1 || 'NO_VALUE';

   /setIpconntrackValues\(\"(.*)\"\);/;
   $key=$conn_list[1];
   $wrt54g{$key}=$1 || 'NO_VALUE';

} else {
   # check for standard firmware
 
   $key=$conn_list[0];
   $wrt54g{$key}='NOT_SUPPORTED';
   
   $key=$conn_list[1];
   $wrt54g{$key}='NOT_SUPPORTED';
   
}

if ( $wrt54g{'conn_max'} > 0 ) {
   $wrt54g{'conn_util'}=sprintf("%.1f",100 * ( $wrt54g{'conn_used'} ) / $wrt54g{'conn_max'});
} else {
   $wrt54g{'conn_util'}='0';
}

my $error_text="";
my $error_level=0;

my $data_present=-1;
foreach my $key (@conn_list) {
   my $display_value;
   
   if ($key eq 'conn_util') {
      $display_value=$wrt54g{$key} . "%";
   } else {
      # change the number of bytes to a nice_size
      $display_value=$wrt54g{$key};
   }
   
   $error_text="${error_text}Current $key:$display_value ";
   if ($wrt54g{$key} ne "NO_VALUE") {
      $data_present++;
   }
}

# if all the data is there
if ($data_present == $#conn_list) {

   if ( $wrt54g{'conn_util'} > 95 ) {
      $error_level=1;
      $error_text="IP Connection Utilisation EXTREMELY high. $error_text";
   } elsif ( $wrt54g{'conn_util'} > 90 ) {
      $error_level=2;
      $error_text="IP Connection Utilisation too high. $error_text";
   }
   
} else {
   $error_level=2;
   $error_text="Could not get all conn Data. See $html_file for more details. $error_text";
}

return $error_level,$error_text;
}
#------------------------------------------------------------------------------
sub process_connections {
# now from the content extract
# the conn data

my $error_text="";
my $error_level=0;

if ($firmware_type eq "DDWRT") {
   if ($_ eq "") {
      $error_text="No data returned from ssh. Test ssh connection.";
      $error_level=1;
   } else {
      $error_text="$_";
   }
} else {
   $error_text="NOT SUPPORTED.";
   $error_level=2;
}

return $error_level,$error_text;
}
#--------------------------------------------------------------------------------------
sub get_the_previous_data {
# get the previously stored router data from the data file

# pass in
# the name of the router data file
# an array reference to the field list
# a hash reference to the current router data
my ($router_data_file,$field_list,$router_data)=@_;

# the previous router data is returned as a hash

my $previous_router_data; # used as a hash reference

if (-f $router_data_file) {
   eval { $previous_router_data=retrieve($router_data_file) };
   if ($@) {
      # we seem to have got an error with the retrieve
      print "ERROR: $@  ";
   }
}

# we make sure that the ro318 hash has all the keys we are expecting
# if available, we load them with the previous values, if not we blank them
foreach my $key (@{$field_list}) {
   if (defined($$previous_router_data{$key})) {
      $$router_data{$key}=$$previous_router_data{$key};
   } else {
      # we do not have a previous value - set it to blank
      $$router_data{$key}='';
   }
}

return $previous_router_data;
}
#--------------------------------------------------------------------------------------
sub display_uptime {
# pass in an uptime string
# if it looks like it is in seconds then we convert it to look like days, hours minutes etc
my ($uptime_string)=@_;
my $new_uptime_string=$uptime_string;
if ($uptime_string=~/^[0-9\.]+$/) {
   # its in seconds, so convert it
   my $uptime=$uptime_string;
   my $days=int($uptime/86400);
   $uptime=$uptime%86400;
   my $hours=int($uptime/3600);
   $uptime=$uptime%3600;
   my $mins=int($uptime/60);
   $uptime=$uptime%60;

   my $day_info='';
   if ($days==1) {
      $day_info="$days day";
   } elsif ($days>1) {
      $day_info="$days days";
   }
   $new_uptime_string="$day_info " . sprintf("%02d:%02d:%02d (%ssec)",$hours,$mins,$uptime,$uptime_string);
}
return $new_uptime_string; 
}
#--------------------------------------------------------------------------------------
sub do_uptime {
# once you have the uptime data in the rough format of x days, hh:mm:ss
# pass the values in here for comparison

# pass in
# reference to array @field_list
# reference to hash of router data
# reference to hash of previous router data
# name of file to store router data in 
# name of the file containing the source html data
# value of $max_notify_count
# returns $error_level and $error_text;

my ($field_list,$router_data,$previous_router_data,$data_file,$html_file,$max_notify_count)=@_;

my $error_text="";
my $error_level=0; 

my $differences="";
my $store_in_file=-1;
my $key;
my $data_present=-1;

foreach my $key (@{$field_list}) {
   # do not process fields containing "notify"
   if ($key=~/notify/) {
      # this is a notify field
      # increment the counter anyway
      $data_present++;
   } else {
      $error_text="${error_text}Current $key: " . display_uptime($$router_data{$key}) . ". ";
      if ($$router_data{$key} ne "NO_VALUE") {
         $data_present++;
      }
   }
}

if ($data_present == $#$field_list) {

   # check to see if any of the uptime data is lower than the previous stored value
   foreach my $key (@{$field_list}) {
      if (!defined($$previous_router_data{$key})) {
         $$previous_router_data{$key}="";
      }

      # now we want to compare the 2 times
      # convert them both to a standard time and compare them
      my $previous_value=parse_uptime($$previous_router_data{$key});
      my $current_value=parse_uptime($$router_data{$key});
      
      # if the current uptime is less than previous one ....
      if ( $current_value < $previous_value ) {
         $differences=$differences . "Previous $key: " . display_uptime($$previous_router_data{$key}) . ". ";
      }
   }
   
   if ($differences) {
      $error_level=1;
      $$router_data{'uptime_notify_text'}="Reboot/link failure occurred:$differences.";
      $$router_data{'uptime_notify_count'}=0; # since there are differences its likely that this will be the first warning state
   } else {
      $error_level=0;
   }
   
   $store_in_file=1;
   
   # we only start incrementing the counter if the value is 0 or more
   if ($$router_data{'uptime_notify_count'} eq '') {
      $$router_data{'uptime_notify_count'}=-1;
   }
   
   if ($$router_data{'uptime_notify_count'}>=0) {
      $$router_data{'uptime_notify_count'}++;
   }
   if ($$router_data{'uptime_notify_count'} > $max_notify_count || $$router_data{'uptime_notify_count'} == -1) {
      $$router_data{'uptime_notify_count'}=-1; # this flags to us that we should not use the counter or text anymore
      $$router_data{'uptime_notify_text'}="";
   } else {
      # use the text
      $error_text="$$router_data{'uptime_notify_text'} $error_text";
      $error_level=1;
   }
   
} else {
   $error_level=2;
   $error_text="Could not get all Uptime Data. See $html_file for more details. $error_text";
}

if ($store_in_file) {
   # save the data to a file
   store($router_data,$data_file);
}

return $error_level,$error_text;
}
#--------------------------------------------------------------------------------------
sub do_firmware {
# once you have the firmware data as a string
# pass the values in here for comparison

# pass in
# the hash key to the firmware value
# reference to array @field_list
# reference to hash of router data
# reference to hash of previous router data
# name of file to store router data in 
# name of the file containing the source html data
# value of $max_notify_count
# returns $error_level and $error_text;

my ($key,$field_list,$router_data,$previous_router_data,$data_file,$html_file,$max_notify_count)=@_;

my $error_text="";
my $error_level=0; 

my $differences="";
my $store_in_file=-1;

if ($$router_data{$key} ne "") {
   # we have retrieved the firmware level
   # check this against the last version
   $store_in_file=1;
   if (defined($$previous_router_data{$key})) {
      # the previous version is stored so we can compare it
      if ($$previous_router_data{$key} eq '') {
      $error_text="Reading Firmware for the first time. Version is $$router_data{$key}.";
      } elsif ($$router_data{$key} eq $$previous_router_data{$key}) {
         $error_text="Firmware is OK. Version is $$router_data{$key}.";
      } else {
         $error_level=2;
         $error_text="Firmware level has changed. Old version was $$previous_router_data{$key}, New version is $$router_data{$key}.";
      }
   } else {
      $error_text="Previous Firmware version is not defined. Version is $$router_data{$key}.";
   }
} else {
   $error_level=1;
   $error_text="We could not find the firmware level on the downloaded page. See $html_file for more details.";
}

if ($store_in_file) {
   # save the data to a file
   store($router_data,$data_file);
}

return $error_level,$error_text;
}

