#!/usr/bin/perl
####################################################
# npulse.cgi
# Network Monitoring Program
#
# Author: Steve Horsburgh  (npulse@horsburgh.com)
# Version: 0.2 alpha
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
# 
####################################################
$|=1;
require 5.002;
require "./preferences.pl";
require "$Libdir/util.pl";
#------------------------------------------------------------------#
#-- Main Program --------------------------------------------------#
#------------------------------------------------------------------#

$DoneHeader = 0;
$cmdline = $ENV{'HTTP_HOST'}?0:1;

if ($cmdline) {
  foreach (@ARGV) {
    $in{$1} = $2 if m/\s*([^=\s]+)\s*=\s*(.*)$/;
  }
} else {
  require $Cgilib;
  print &PrintHeader();
  &ReadParse();
}

use locale;
foreach ('site','a','s') {
  $in{$_} =~ s/[^\w\.\d-]//g if defined $in{$_};   # Trap bad/imposter characters
}

$in{'a'} = "display" unless $in{'a'};

%allowedactions = (
                    display => "$Libdir/gendisp.pl",
                    pref    => "$Libdir/prefs.pl",
                    setup   => "$Libdir/editor.pl",
                    recheck => "$Libdir/gendisp.pl",
                    detail  => "$Libdir/detail.pl",
                    create  => "$Libdir/gendisp.pl",
                    auto    => "$Libdir/prefs.pl"
                  );

# $allowedactions    = 'pref setup recheck detail create ';
$allowedsubactions = 'single traceroute quickport fullport history lookup discover save updateinfo compact basic help on off ';

delete $in{'s'} unless ($in{'s'} && (index(lc($allowedsubactions),lc($in{'s'})) >= 0));

if (exists $allowedactions{lc($in{'a'})}) {
  require $allowedactions{lc($in{'a'})} if $allowedactions{lc($in{'a'})};
  &{uc($in{'a'})};
}

require $allowedactions{'create'} unless lc($in{'a'}) eq 'create';
&CREATE();  #Default action
exit;

#------------------------------------------------------------------#
#-- Main Routines -------------------------------------------------#
#------------------------------------------------------------------#

sub PREF {
    local($type) = $in{'s'} || "edit";
    print &PREFS(lc($type));
    exit;
}

sub SETUP {
    &{uc($in{'s'})} if $in{'s'} =~ /discover|lookup/i;
    &EDITOR();
    exit;
}

sub RECHECK {
    local($ip) = shift;
    return if $DEMO;

    my $cmd = $Autorecheck." ".$Vardir."/auto".$$.".pid 0 '".$ip."'";
    system($cmd);

    return;
}

sub DETAIL {
    &ReadServices();
    local($result) = &{uc($in{'s'})} if $in{'s'} =~ /single|traceroute|quickport|fullport|history|updateinfo/i;
    &DisplayDETAIL($in{'site'}, $result) unless $in{'s'} =~ /single/i;

    exit;
}

sub CREATE {
    local(*F);
    my(%s, $sip, $host, $status, $line, $ip, $name, @p, $ipmask, $portmask, $portlist, @cfglist);

# $Infofile: (key => val, ... format)

    if (-f $Infofile) {
      open(F, "<$Infofile") || &Error("Infofile error");
      while (<F>) {
        %s = ( eval ($_) );
        $sip = &sip($s{'ip'});
        foreach $k (keys %s) {
          $mySite{$sip}{$k} = $s{$k};
        }
      }
      close(F);
    }

# $Configfile: (ipmask portmask)
    @cfglist = &ReadConfigfile();
    foreach (@cfglist) {
      ($ipmask, $portmask) = split / /;
      $portlist = join(',',&GeneratePortList($portmask));
      foreach (&GenerateSiteList($ipmask)) {
        $mySite{&sip($_)}{'portlist'} = $portlist;
      }
    }

# $Currentfile:
# Host: 192.168.10.1 ()\tStatus: Down
# or
# Host: 192.168.10.1 (pwawpz.localdomain)\tPorts: 21/open/tcp//ftp///, ....

    open(F, "<$Currentfile") || return;
    while (<F>) {
      chomp;
      ($host, $status) = split /\t/;
      $line = $_;
      ($ip, $name) = $line =~ /^Host: ([\d\.]+) \((.*)\).*$/;
      $sip = &sip($ip);
      $mySite{$sip}{'line'}   = $line;
      $mySite{$sip}{'ip'}     = $ip;
      $mySite{$sip}{'name'}   = $name;
      if ($status =~ /^Status/) {
        $mySite{$sip}{'status'} = ($status =~ /Up/) ? $Stat_ok : $Stat_fail;
        $mySite{$sip}{'ports'}  = "";
      } else {
        $status =~ s/^Ports: //;
        foreach (split(/,\s*/, $status)) {
          @p = split /\//;
          $mySite{$sip}{'ports'} .= $p[0].',';
        }
        chop $mySite{$sip}{'ports'};
        $mySite{$sip}{'status'} = ($mySite{$sip}{'ports'} eq $mySite{$sip}{'portlist'}) ? $Stat_ok : $Stat_warn;
      }
    }
    close(F);

    foreach (@cfglist) {
      ($ipmask, $portmask) = split / /;
      &Generate(&GenerateSiteList($ipmask));
    }
    &WriteHTMLfiles();

    if (lc($in{'s'}) eq "single") {
      &DETAIL();
    } else {
      local($type) = $in{'disp'};
      print (($type eq "compact") ? &DisplayHTML($Compactresultfile) : &DisplayHTML($Basicresultfile));
    }
    exit;
}

sub AUTO {
    &Error("Auto Check mode is not available in DEMO mode.") if $DEMO;
    my($cmd, $enabled);
    my $pidfile = $Vardir."/autorecheck.pid";

    if ($in{'s'} =~ /on/i) {
      $enabled = "start";
      if ( -f $pidfile ) {
        open(F, "<$pidfile") || &Error("Unable to open pidfile: $pidfile");
        $pid = <F>;
        close(F);
        chomp $pid;
        kill 'TERM', $pid;
        $enabled = "restart";
      }
      &Error("Unable to $enabled Auto Check.") if -f $pidfile;
      $enabled .= "ed";
      $Autointerval ||= 20;
      $Autointerval = abs($Autointerval);
      $cmd = $Autorecheck." ".$pidfile." ".$Autointerval;
      system($cmd);
    } elsif ($in{'s'} =~ /off/i) {
      &Error("Auto Check is already off.") unless -f $pidfile;
      open(F, "<$pidfile") || &Error("Unable to open pidfile: $pidfile");
      $pid = <F>;
      close(F);
      chomp $pid;
      kill 'TERM', $pid;
      $Autointerval = -abs($Autointerval);
      $enabled = "disabled";
    }
    $in{'a'} = "pref";
    $in{'Autointerval'} = $Autointerval;
    &PREFS("save");
    print &Header($Myname,"","");
    print <<EOA;
<p> Auto Check has been $enabled </p>
<p><a href="javascript:top.history.go(-1)">Continue</a></p>
EOA
    print &Footer();
    exit;
}

sub DISPLAY {
    if ($in{'s'}) {
      print &DisplayHTML( ($in{'s'} =~ /help/i)    ? "help.html" :
                          ($in{'s'} =~ /compact/i) ? "compact.html" : "basic.html");
      
    } else {
      print &Header($Myname,$in{'s'},"");
      print <<EOF;
<p> Welcome to the nPULSE web-based network monitoring program for Linux and Unix. 
If you have already set up nPULSE, then jump right into the <a href="compact.html">Compact</a> or 
<a href="basic.html">Basic</a> monitoring page. 
For help, check out the <a href="help.html">Help Page</a>.</p>
<p>Otherwise you should manually <a href="npulse.cgi?a=setup&s=edit">setup</a> 
nPULSE and manually run a first run check of the network. 
(See the README file for more information.)</p>
<hr><p><small>This software is a "proof of principle" prototype. The concept is to use
freely available software (under the GPL agreement) together with
proprietary "glue" software to solve real-world problems. nPULSE accomplishes
this by using the following freeware products:</small></p>
<blockquote><table>
<tr><td><small>PERL</small></td><td><small>Perl 5.002 or greater</small></td></tr>
<tr><td><small>NMAP</small></td><td><small>Network exploration tool V2.51 or greater</small></td></tr>
<tr><td><small>TRACEROUTE&nbsp;</small></td><td><small>Packet tracking tool</small></td></tr>
<tr><td><small>MINISERV</small></td><td><small>Web Server (written entirely in Perl)</small></td></tr>
<tr><td><small>HTML</small></td><td><small>nPULSE is Web-enabled and Web-driven</small></td></tr>
<tr><td><small>SH</small></td><td><small>Install scripts are in 'sh' shell script</small></td></tr>
</table></blockquote>
<p><small>The glue that holds the whole thing together is a set of custom Perl routines
and a single CGI program.</small></p>
EOF
    print &Footer();
    }
    exit;
}
