sub ReadCurrentFile {
    my $ip = shift || return;
    my(@p);

    my $cmd = "grep '$ip ' $Currentfile";
    my $cf = `$cmd`; chomp $cf;
    &Error("Unable to find $ip in $Currentfile") unless $cf;

    $cf =~ s/ \(([^\)]*)\)\t/\tname: $1\t/;
    $cf =~ s/: / => '/g;
    $cf =~ s/\t/', /g;
    $cf .= "'";
    $cf =~ s/ //g;

    my %site = ( eval($cf) );
    my $ports = $site{'Ports'};
    $ports =~ s/^Ports: //;
    foreach (split(/,\s*/, $ports)) {
      @p = split /\//;
      $site{'ports'} .= $p[0].',';
    }
    chop $site{'ports'};

# $Configfile: (ipmask portmask)
    my $done = 0;
    foreach (&ReadConfigfile()) {
      ($ipmask, $portmask) = split / /;
      foreach (&GenerateSiteList($ipmask)) {
        next unless $_ eq $ip;
        $site{'portlist'} = join(',',&GeneratePortList($portmask));
        $done = 1;
        last;
      }
      last if $done;
    }

    my %info = &GetStoredInfo($ip);
    foreach (keys %info) { $site{$_} = $info{$_}; }

    $site{'status'} = ($site{'Status'} eq "Down") ? $Stat_fail : ($site{'ports'} eq $site{'portlist'}) ? $Stat_ok : $Stat_warn;
    $site{'ip'}     = $ip;
    $site{'sip'}    = &sip($ip);
    $site{'alias'}  = $site{'Alias_8'};

    return %site;
}

sub ReadHistoryFile {
    my($ip) = shift;
    my($f) = &ip2file($ip);
    my $starttime = shift;

    my(%history) = ();
    my($time, $host, $status, @p);
    local(*F);

    my %info = &GetStoredInfo($ip);

# $Configfile: (ipmask portmask)
    my $done = 0;
    foreach (&ReadConfigfile()) {
      ($ipmask, $portmask) = split / /;
      foreach (&GenerateSiteList($ipmask)) {
        next unless $_ eq $ip;
        $info{'portlist'} = join(',',&GeneratePortList($portmask));
        $done = 1;
        last;
      }
      last if $done;
    }

	open(F, "<$f.hist") || &Error("Unable to open $f.hist for reading.");
	while (<F>) {
      chomp;
      ($time, $host, $status) = split /\t/;
      next unless $time > $starttime;
      ($history{$time}{'ip'}, $history{$time}{'name'}) = $host =~ m/^Host: ([^ ]+) \(([^\)]+)\).*$/;
      $history{$time}{'sip'}    = &sip($history{$time}{'ip'});
      $history{$time}{'line'}   = $_;
      if ($status =~ /^Status/) {
        $history{$time}{'status'} = ($status =~ /Down/) ? $Stat_fail : $Stat_ok;
        $history{$time}{'ports'}  = "";
      } else {
        $status =~ s/^Ports: //;
        foreach (split(/,\s*/, $status)) {
          @p = split /\//;
          $history{$time}{'ports'} .= $p[0].',';
        }
        chop $history{$time}{'ports'};
        $history{$time}{'status'} = ($history{$time}{'ports'} eq $info{'portlist'}) ? $Stat_ok : $Stat_warn;
      }
      $history{$time}{'status'} = ($status =~ /Down/) ? $Stat_fail : ($history{$time}{'ports'} ne $info{'portlist'}) ? $Stat_warn : $Stat_ok;
    }
    close(F);
    return %history;
}

sub ReadConfigfile {
    local(*F);
    my(@out) = ();
	open(F, "<$Configfile") || &Error("Unable to open Configfile: $Configfile for reading.");
	@out = <F>;
	close(F);
    chomp @out;
    return wantarray ? @out : join("\n",@out);
}

sub ip2file {
    return $Basedir . '/' . join('/', split(/\./, shift));
}

sub GenerateSiteList {
    my(@sites) = ();
    my($ip1, $ip2, $ip3, $ip4, @ips);

    my($ipmask) = shift || return;
    @ips = split(/\./, $ipmask);
    return unless $#ips == 3;
    foreach $i (0..3) {
      $ips[$i] =~ s/\-/\.\./g;
      $ips[$i] =~ s/\*/0\.\.255/g;
      $ips[$i] =~ s/^00?(\d)/$1/g;
      $ips[$i] =~ s/(\D)00?(\d)/$1$2/g;
    }
    foreach $ip1 (eval($ips[0])) {
      next unless $ip1 =~ /^\d+$/;
      foreach $ip2 (eval($ips[1])) {
        next unless $ip2 =~ /^\d+$/;
        foreach $ip3 (eval($ips[2])) {
          next unless $ip3 =~ /^\d+$/;
          foreach $ip4 (eval($ips[3])) {
            next unless $ip4 =~ /^\d+$/;
            push(@sites, $ip1.'.'.$ip2.'.'.$ip3.'.'.$ip4);
          }
        }
      }
    }
            
    return wantarray ? @sites : join("\n",@sites);
}

sub GeneratePortList {
    my($portmask) = shift;
    my(@ports);
    if ($portmask =~ /\*/) {
      $portmask = "1..65535";
    } else {
      $portmask =~ s/^[^0-9\., -]//g;
      $portmask =~ s/-/../g;
    }
    foreach (eval($portmask)) {
      push(@ports, $_);
    }
    return sort {$a <=> $b} @ports;
}

sub sint {
    my($val) = shift;
    my($w) = shift || 3;
    my($c) = sprintf("%${w}d",$val);
    $c =~ s/ /0/g;
    return $c;
}

sub sip {
    my(@ips) = split(/\./, shift);
    my($ip) = &sint($ips[0]).'.'.&sint($ips[1]).'.'.&sint($ips[2]).'.'.&sint($ips[3]);
    return $ip;
}


sub CreateDir {
	my $filename = shift || &Error("Unable to create a null directory.");
    my @dirs = split(/\//, $filename);
    pop @dirs;     #Filename part
    unshift @dirs; #Root part
    my $dir = "";
    foreach (@dirs) {
      $dir .= "/" . $_;
      mkdir($dir,0775) unless -d $dir;
      &Error("Unable to create directory: $dir") unless -d $dir;
    }
    return 1;
}

sub colorStatus {
    my($stat) = shift;
	  if ($stat == $Stat_ok) {
	    return $Color_ok, $Text_ok, "OK";
      } elsif ( $stat == $Stat_warn) {
        return $Color_warn, $Text_warn, "WARN";
      } else {
	    return $Color_fail, $Text_fail, "FAIL";
	  }
}

sub GetStoredInfo {
    my($ip) = shift || return 0;
    my %site = ();
    my($cmd);

# $Infofile: (key => val format)
    if (-f $Infofile) {
      $cmd = "grep 'ip => \"$ip\"' $Infofile";
      my $cc = `$cmd`; chomp $cc;
      %site = ( eval($cc) );
    }

    my %tmpl = ( eval($Templatetext) );
    foreach (keys %tmpl) {
      $site{$_} = $tmpl{$_} unless exists $site{$_};
    }

    return %site;
}

sub SaveStoredInfo {
    my($ip) = shift || return;
    local(*F);
    my($cmd, $out, @result);

    %site = &GetStoredInfo($ip);

    delete $site{''};
    delete $site{'ip'};
    my $output = "ip => \"".$ip."\", ";

    foreach (keys %site) {
      $site{$_} = $in{$_} if exists $in{$_};
      $output .= $_ . " => \"" . $site{$_} . "\", ";
    }
    chop $output; chop $output;
    $output =~ s#/#\\/#g;

    my $gotit = 0;

    if (-f $Infofile) {
      $cmd = "grep 'ip => \"".$ip."\"' ".$Infofile;
      $gotit = `$cmd`; chomp $gotit;
      if ($gotit) {
        $cmd = "sed 's/ip => \"".$ip."\".*/".$output."/' ".$Infofile;
        print "<pre>$cmd</pre>\n" if $DEBUG;
        @result = `$cmd`;
      } else {
        $cmd = "cat ".$Infofile;
        print "<pre>$cmd</pre>\n" if $DEBUG;
        @result = `$cmd`;
        push(@result, $output);
      }
    } else {
        push(@result, $output);
    }

    open(F, ">$Infofile");
    foreach (@result) {
      chomp;
      ($out = $_) =~ s/([^\\])\@/$1\\\@/g;
      $out =~ s/([^\\])\$/$1\\\$/g;
      $out =~ s/([^\\])\&/$1\\\&/g;
      print F $out, "\n";
    }
    close(F);
}

sub ReadServices {
    open(F, "<$Servicesfile") || &Error("Unable to open the services file: $Servicesfile");
    while (<F>) {
      $Services{$2} = $1 if m/\s*([^:\s]+)\s*:\s*(.*)$/;
    }
    $Services{'0'} = "alive";
    close(F);
}

sub GetOS {
    my($ip) = shift;
    $ip =~ s/\*/1\-254/g;
    &Error("GetOS: Invalid IP mask: $ip") unless $ip =~ /^[\d,\.-]+$/;
    my($os) = "";
    my(@result) = ();

    my $cmd = $Nmapcmd." -v -oM - -O -sT '".$ip."' 2>/dev/null";
    @result = `$cmd`;

    foreach (grep(/^Host: /,@result)) {
      chomp;
      next unless $_;
      ($os = $_) =~ s/^.*OS: ([^\t]+).*$/$1/;
    }

    return $os;
}

sub GetICON {
    my($os) = shift || return "unk";
    my($icon) = "unk";

    if ($os =~ /Mac/) {
      $icon = "mac01";
    } elsif ($os =~ /print|phaser|laser|inkjet/i) {
      $icon = "printr01";
    } elsif ($os =~ /Linux|Solaris|Sun|SCO|Unix|Open|Net|IRIX|MVS|UX|BSD|UNIX|OSF/) {
      $icon = "server01";
      $icon = "server02" if $_ =~ /telnet|X11/i;
    } elsif ($os =~ /Windows/) {
      $icon = "pc02";
    } elsif ($os =~ /SNMP|SMTP|Router|router|Cisco|RAS|switch|Gate|Bridge/) {
      $icon = "router01";
    } elsif ($_ =~ /http/) {
        $icon = "web01";
    } elsif ($_ =~ /ftp/) {
        $icon = "ftp01";
    } else {
      $icon = "unk";
    }
    return $icon;
}

sub Header {
    my($title, $type, $extra) = @_;
    $type ||= "basic";
#    my $autocheck = "<span style=\"".$Fxs.";color:gray\">Auto check: </span><span style=\"".
#                       $Fss.";font-weight:bold;color:".
#                       ($Autointerval > 0 ? "green\">ON" : "red\">OFF")."</span>";
    my $auto  = ($Autointerval > 0) ? "on" : "off";
    my $nauto = ($Autointerval > 0) ? "off" : "on";
    my $autocheck = "<a href=\"".$nPULSEurl."?a=auto&s=".$nauto."\">".
                    "<img src=\"/images/serv_".$auto.".gif\" ".
                    "width=26 height=43 border=0></a>";
    $extra = ($extra ? "<div style=\"text-align:right;margin:0\"><big>$extra</big>&nbsp;</div>" : "");
    my $select = "<select name=s style=\"font-size:7pt;color:black\">";
    foreach ("compact","basic") {
      $selected = ($type eq $_) ? " selected" : "";
      $select .= "<option".$selected." value=\"".$_."\">".ucfirst($_)."</option>";
    }
    $select .= "</select>";
    my $demomode = $DEMO?"&nbsp;<em><small>DEMO</small></em>":"";
    $DoneHeader = 1;
    my($date) = `date +'%c'`;
    return <<EOH;
<html>
 <head>
  <title>$title</title>
   <META HTTP-EQUIV="Expires" CONTENT="-1">
   <style language="text/css">
    BODY {$Fsn;font-weight:normal}
    A   {font-weight:normal;text-decoration:none;}
    A:hover  {text-decoration:underline;}
  </style>
 </head>
 <body bgcolor="#000000" text="#ffffff" link="#9999ff" vlink="#9999ff" alink="#ff0000" style="margin:0;" MARGINWIDTH=0 MARGINHEIGHT=0>
    <form method=get action="npulse.cgi">
    <input type="hidden" name=a value="display">
    <table style="border-style:outset;border-width:0 0 2 0" cellspacing=0 cellpadding=0 width="100%">
     <tr>
      <td width=104><img src="images/alogo.gif" width=80 height=49 border=0></td>
      <td width="100%" valign="bottom">$demomode &nbsp;</td>
      <td align="right" style="background-color:#BDBDBD;margin:0">
       <table border=1 cellspacing=0 cellpadding=0>
        <tr valign="bottom">
         <td><a href="$nPULSEurl" onMouseOver="home.src='images/home_on.gif'" onMouseOut="home.src='images/home.gif'"><img name=home src="images/home.gif" width=63 height=43 border=0></a></td>
         <td><a href="$nPULSEurl?a=recheck" onMouseOver="recheck.src='images/recheck_on.gif'" onMouseOut="recheck.src='images/recheck.gif'"><img name=recheck src="images/recheck.gif" width=63 height=43 border=0></a></td>
         <td><a href="$nPULSEurl?a=setup" onMouseOver="setup.src='images/setup_on.gif'" onMouseOut="setup.src='images/setup.gif'"><img name=setup src="images/setup.gif" width=63 height=43 border=0></a></td>
         <td><a href="$nPULSEurl?a=pref" onMouseOver="prefs.src='images/prefs_on.gif'" onMouseOut="prefs.src='images/prefs.gif'"><img name=prefs src="images/prefs.gif" width=63 height=43 border=0></a></td>
         <td><a href="$nPULSEurl?a=display&s=help" onMouseOver="help.src='images/help_on.gif'" onMouseOut="help.src='images/help.gif'"><img name=help src="images/help.gif" width=63 height=43 border=0></a></td>
         <td nowrap align=center style="font-size:7pt;color:black;text-align:center">
         $select<input type=submit value="Go" style="font-size:6pt;color:black;border:0"></td>
        </tr>
       </table>
      <td nowrap valign="top" align="right"><span style="$Fxs;color:gray">Auto<br>check:</span></td>
      <td>$autocheck</td>
     </tr>
    </table>
    $extra
    </form>
EOH
}

sub Footer {
	return <<EOF;
  <hr><div style="$Fxs">Copyright &copy;2000, <a href="http://www.horsburgh.com/">Horsburgh.com</a>. All Rights Reserved.</div>
 </body>
</html>
EOF
}

sub Error {
	my($msg) = shift;
    my($pages) = shift || 1;
    print &Header($Myname,"","ERROR") unless $DoneHeader;
	print <<EOE;
  $msg
  <p><a href="javascript:top.history.go(-$pages)">Continue</a></p>
EOE
	print &Footer();
	exit;
}

1;
