####################################################
# Edit the preferences file
####################################################
sub PREFS {
    my($subaction) = shift || "edit";
    my($return) = shift;
    my($section) = $in{'section'} || "COMMANDS";
    my($line, $arg, $val, %prefs, @args, $s, @data);
    my($output) = "";
    my($result) = "";
    local(*F);
    &DEBUG("Starting: subaction = $subaction");

# Read Preferences file

    if ($in{'submit'} =~ /default/i) {
      ($pfile = $Preferencefile) =~ s/\.pl$/\.def/;
      open(F, "<$pfile") || &Error("Unable to find default preference file");
      open(G, ">$Preferencefile") || &Error("Unable to write to preference file: $Preferencefile");
      my $prefs = "";
      while (<F>) { $prefs .= $_; print G; }
      close(F); close(G);
      undef %in;
      $subaction = "";
      &StopAutoCheck() if $Autointerval > 0;
      eval($prefs);
      &RestartAutoCheck() if $Autointerval > 0;
    }

    open(F, "<$Preferencefile") || &Error("Unable to open settings file: $Preferencefile");
    @data = <F>;
    close(F);

# Make updates and save preferences

    if ($subaction =~ /save/i) {
      $output .= &UserMod("save") if $section =~ /users/i;
      $output .= &MiniServMod("save") if $section =~ /web_server/i;
      $output .= &DefDetailCmds("save") if $section =~ /commands/i;
      open(F, ">$Preferencefile") || &Error("Unable to update settings file: $Preferencefile");
      local $inauto = 1;
      foreach $line (@data) {
        chomp $line;
        $inauto = 0 if $line =~ /# -- END AUTO PREFERENCES/;
        if ($inauto && ($line =~ /^\$/)) {
          ($arg, $val) = $line =~ /^.([^ =]+)\s*=\s*(.+)\s*;$/;
          $val = (defined $in{$arg})?$in{$arg}:eval($val);
          $val =~ s/\@/\\\@/g;
          print F "\$".$arg." = \"".$val."\";\n";
        } else {
          print F $line,"\n";
        }
      }
      close(F);

      &StopAutoCheck() if $Autointerval > 0;

      $output .= "<p><strong>Settings have been updated.</strong></p>";
      @data = ();   # Reread file
      open(F, "<$Preferencefile") || &Error("Unable to open settings file: $Preferencefile");
      @data = <F>;
      close(F);
      my $newprefs = join("",@data);
      eval($newprefs);
      &RestartAutoCheck() if $Autointerval > 0;
    }

# Normal Entry

    $result = &Header($Myname,"",0).$output;

    my $instr = "";
    my $ss = 0;

    foreach (@data) {
      chomp;
      last if $_ =~ /# -- END AUTO PREFERENCES/;
      next if (!$_ or ($_ =~ /^1/) or ($_ =~ /^# -/));
      if( $_ =~ /^#\s*SECTION/ ) {
        ($s = $_) =~ s/^#\s*SECTION\s*(.*)$/$1/;
        $ss = 0;
        next;
      }
      if ($_ =~ /^# sub .+$/) {
        ($line = $_) =~ s/^# sub +//;
        $prefs{$s}{$ss}{'sub'} = $line;
      } elsif ($_ =~ /^#/) {
        ($line = $_) =~ s/^#//;
        $instr .= $line . "\n";
      } else {
        ($arg, $val) = $_ =~ /^.([^ =]+)\s*=\s*(.+)$/;
        if ($instr) {
          $ss++;
          $prefs{$s}{$ss}{'instr'} = $instr;
          $instr = "";
        }
        $prefs{$s}{$ss}{'args'} .= $arg."~~".eval($val)."\n";
      }
    }

    my $sections = "";
    my $ds = "";
    foreach $s (sort keys %prefs) {
      $src = ($s eq $section) ? "item_on.gif" : "item_off.gif";
      ($ds = $s) =~ s/_/ /gs;
      $sections .= "<a href=\"".$nPulseurl."?a=pref&s=edit&section=".$s."\">".
                   "<img src=\"/images/".$src."\" border=0 width=24 height=16>".
                   $ds."</a><br>";
    }

    
    ($ds = $section) =~ s/_/ /gs;
    my $out = "<table border=0>\n<tr>\n<td colspan=5><p style=\"".$Fsn."\">".$ds."</p></td>\n</tr>\n";
      
    foreach $ss (sort {$a <=> $b} keys %{$prefs{$section}}) {
      if ($prefs{$section}{$ss}{'sub'}) {
        $out .= "<tr>\n<td colspan=5><p style=\"".$Fsn."\">".
                &{$prefs{$section}{$ss}{'sub'}}().
                "</p></td>\n</tr>\n";
        $out .= "<tr><td colspan=5><hr noshade></td></tr>\n";
      }
      @args = split(/\n/, $prefs{$section}{$ss}{'args'});
      if ($#args >= 0) {
        ($arg, $val) = split(/~~/,shift(@args));
        $out .= "<tr valign=\"top\"><td rowspan=\"".($#args+2)."\">&nbsp;</td>".
                "<td colspan=2 width=\"100%\" rowspan=\"".($#args+2)."\"><span style=\"".$Fss."\">".
                $prefs{$section}{$ss}{'instr'}."</span></td>".
                "<td style=\"".$Fxs.";text-align:right\" align=\"right\"><span style=\"".$Fxs.
                ";text-align:right;color:#bdbdbd\">".$arg.":</span></td>\n".
                "<td><input style=\"".$Fxs."\" type=text name=\"".$arg."\" size=25 value=\"".$val."\">".
                "</td>\n</tr>\n";
        foreach (@args) {
          ($arg, $val) = split /~~/;
          $out .= "<tr valign=\"top\">\n".
            "<td style=\"".$Fxs.";text-align:right\" align=\"right\"><span style=\"".$Fxs.
            ";text-align:right;color:#bdbdbd\">".$arg.":</span></td>\n".
            "<td><input style=\"".$Fxs."\" type=text name=\"".$arg."\" size=25 value=\"".$val."\">".
            "</td>\n</tr>\n";
        }
        $out .= "<tr><td colspan=5><hr noshade></td></tr>\n";
      }
    }

    $out .= "</table>\n";

    my $sbmt = ($section eq 'SCRIPTS')?"":'<input type=submit name=submit style="'.$Fss.'" value="Save">';
    my $warning = (-f $Vardir.'/autorecheck.pid')?'You may want to <a href="'.$nPulseurl.
                  '?a=auto&s=off"><font color="#ff0000">turn off the "AutoCheck"</font></a> '.
                  'while changing these values.':'';
    $result .= <<EOS;
    <script language=javascript>
    function doit(obj) {
      document.formpref.submit();
    }
    </script>
<form name="formpref" method="get" action="$nPulseurl"><input type=hidden name=a value="pref">
 <p>You can change the following values to alter how nPulse operates. $warning<br>
 <input type=hidden name=s value="save">
 <input type=hidden name=section value="$section">
 <table border=3>
  <tr valign="top">
   <td><div style="$Fsn">SETTINGS</div><div class="$Fss">$sections<p><center><a href="$nPulseurl?a=pref&s=save&section=$section&submit=defaults">Reset Defaults</a></center></div></td>
   <td>$out<br>
    $sbmt
   </td>
  </tr>
 </table>
 </p>
</form>
EOS
    $result .= &Footer();
    return if $return;
    print $result;
    exit;
}

sub UserMod {
    # Display table of current users

    return "<p>You do not have admin priviliges. Sorry.</p>" unless $AdminUser;

    my $subaction = shift;

    my (%users,%certs,%allow,%deny);

	if (open(USERS, "<$Userfile")) {
	  while(<USERS>) {
		s/\r|\n//g;
		my @user = split(/:/, $_);
		$users{$user[0]} = $user[1];
		$certs{$user[0]} = $user[3] if ($user[3]);
		if ($user[4] =~ /^allow\s+(.*)/) {
			$allow{$user[0]} = [ &to_ipaddress(split(/\s+/, $1)) ];
			}
		elsif ($user[4] =~ /^deny\s+(.*)/) {
			$deny{$user[0]} = [ &to_ipaddress(split(/\s+/, $1)) ];
			}
		}
	  close(USERS);
    }
    delete $users{''};

    if ($subaction =~ /save/i) {
      my ($key,$u);
      if ($in{'delete'}) {
        return "<p>You cannot delete the admin user.</p>" if lc($in{'delete'}) eq 'admin';
        delete $users{$in{'delete'}};
      } else {
        foreach $key (keys %in) {
          next unless $in{$key};
          if ($key eq 'newuser') {
            return '<p>User '.$in{$key}.' already defined.</p>' if $users{$in{$key}};
            return '<p>Invalid password for '.$in{$key}.'</p>' unless ($in{$key.'p1'} and ($in{$key.'p1'} eq $in{$key.'p2'}));
            $users{$in{$key}} = crypt($in{$key.'p1'}, "XX");
          } elsif ($key =~ /^upd(.+)p1$/) {
            $u = $1;
            return '<p>Invalid password for '.$u.'</p>' unless ($in{$key} and ($in{$key} eq $in{'upd'.$u.'p2'}));
            $users{$u} = crypt($in{$key}, "XX");
          }
        }
      }
      open(USERS, ">$Userfile") or return "<p>ERROR: Unable to create/modify $Userfile</p>";
      foreach $u (keys %users) {
        print USERS join(":",$u,$users{$u},'0',$certs{$u},($allow{$u}||$deny{$u})),"\n";
      }
      close(USERS);
      
      return &RestartMiniServ()?"":"<p>Warning: miniserv restart error</p>";
    }

    my $html = <<EOU;
  <p style="$Fss">To create a new user enter the username, password, and password again
  (verify) and click save. To change the password of any existing user enter the password,
  and password again next to the username. To delete a user, click on the word 'Delete'
  next to the username. You cannot delete the admin user.</p>
  <table border=1 cellspacing=0 cellpadding=1>
   <tr><td bgcolor="#333399" align="center"><span style="$Fss"><b>UserName</b></span></td>
   <td bgcolor="#333399" nowrap align="center"><span style="$Fss"><b>New Password</b></span></td>
   <td bgcolor="#333399" nowrap align="center"><span style="$Fss"><b>Verify Password</b></span></td></tr>
   <tr><td><input type=text size=15 style="$Fss" name="newuser"></td>
   <td><input type=password size=15 style="$Fss" name="newuserp1"></td>
   <td><input type=password size=15 style="$Fss" name="newuserp2"></td></tr>
   <tr><td><span style="$Fsn">admin</span></td>
   <td><input type=password size=15 style="$Fss" name="updadminp1"></td>
   <td><input type=password size=15 style="$Fss" name="updadminp2"></td></tr>
EOU
    delete $users{admin};
    my $u;
    foreach $u (sort keys %users) {
      $html .= '<tr><td><span style="'.$Fsn.'">'.$u.'</span>'.
               ' <span style="'.$Fxs.'">[</span><a href="'.$nPulseurl.'?a=pref&s=save&section=USERS&delete='.$u.'"><span style="'.$Fxs.'">Delete</span></a><span style="'.$Fxs.'">]</span></td>'.
               '<td><input type=password size=15 style="$Fss" name="upd'.$u.'p1"></td>'.
               '<td><input type=password size=15 style="$Fss" name="upd'.$u.'p2"></td></tr>';
    }
    $html .= "</table>";
    return $html;
}

sub to_ipaddress {
  my (@rv, $i);
  foreach $i (@_) {
    if ($i =~ /(\S+)\/(\S+)/) { push(@rv, $i); }
    else { push(@rv, join('.', unpack("CCCC", inet_aton($i)))); }
  }
  return @rv;
}

sub RestartMiniServ {
  my $pidfile = $Vardir."/miniserv.pid";
  return 0 unless -f $pidfile;
  open(F, "<$pidfile") || return 0;
  my $pid = <F>;
  chomp $pid;
  close(F);
  return kill('HUP', $pid);
}

sub DefDetailCmds {

    return "<p>You do not have admin priviliges. Sorry.</p>" unless $AdminUser;

    my $subaction = shift;

    my %Cmds = &GetUserCmds();

    if ($subaction =~ /save/i) {
      my ($key,$n);
      if ($in{'delete'}) {
        delete $Cmds{$in{'delete'}};
      } else {
        foreach $key (keys %in) {
          next unless $in{$key};
          if ($key eq 'newname') {
            return '<p>Command name '.$in{$key}.' already defined.</p>' if $Cmds{$in{$key}};
            return '<p>Invalid command for '.$in{$key}.'</p>' unless $in{newcmd};
            $Cmds{$in{$key}}{cmd} = &Encode($in{newcmd});
            $Cmds{$in{$key}}{admin} = $in{newchk}?1:0;
          } elsif ($key =~ /^upd(.+)$/) {
            $n = $1;
            return '<p>Invalid command for '.$n.'</p>' unless $in{$key};
            $Cmds{$n}{cmd} = &Encode($in{$key});
            $Cmds{$n}{admin} = $in{'chk'.$n}?1:0;
          }
        }
      }
      open(CMDS, ">$Ucmdfile") or return "<p>ERROR: Unable to create/modify $Ucmdfile</p>";
      foreach $n (keys %Cmds) {
        print CMDS $n,"\t",$Cmds{$n}{admin},"\t",$Cmds{$n}{cmd},"\n";
      }
      close(CMDS);
      return;
    }
    
    my $html = <<EOD;
    <p style="$Fss">To create custom commands for the Detail Pages enter a short name and the
    full command to execute. To delete a command click the delete link next to the name.
    To edit a command, enter the new information in the Full Command box next to the name.
    You may use the special variable \$IP\$ to represent the current
    IP address. For example to Ping a device the command might be: <tt>/usr/sbin/ping -c5 \$IP\$</tt></p>
    <table border=1 cellspacing=0 cellpadding=1>
    <tr><td bgcolor="#333399" align="center"><span style="$Fss"><b>Name</b></span></td>
    <td bgcolor="#333399" nowrap align="center"><span style="$Fss"><b>Full Command</b></span></td>
    <td bgcolor="#333399" nowrap align="center"><span style="$Fss"><b>Admin Only</b></span></td></tr>
    <tr><td><input type=text size=10 style="$Fss" name="newname"></td>
    <td><input type=text size=30 style="$Fss" name="newcmd"></td>
    <td align="center"><input type=checkbox style="$Fss" name="newchk" value=1></td></tr>
EOD
    my $n;
    foreach $n (sort keys %Cmds) {
      $html .= '<tr><td><span style="'.$Fsn.'">'.$n.'</span>'.
               ' <span style="'.$Fxs.'">[</span><a href="'.$nPulseurl.'?a=pref&s=save&section=COMMANDS&delete='.$n.'"><span style="'.$Fxs.'">Delete</span></a><span style="'.$Fxs.'">]</span></td>'.
               '<td><input type=text size=30 style="'.$Fss.'" name="upd'.$n.'" value="'.&Decode($Cmds{$n}{cmd}).'"></td>'.
               '<td align="center"><input type=checkbox style="'.$Fss.'" name="chk'.$n.'" value=1'.($Cmds{$n}{admin}?' checked':'').'></td></tr>';
    }
    $html .= "</table>";
    $html .= <<EOE;
<p><small><span style="$Fss"><b>Sample Custom Commands:</b><br>
<table border=0>
 <tr><td style="$Fss;font-family:courier">/usr/bin/finger \@\$IP\$</td><td style="$Fss">Who is online at the server</td></tr>
 <tr><td style="$Fss;font-family:courier">nmblookup -A \$IP\$</td><td style="$Fss">See what is shared</td></tr>
 <tr><td style="$Fss;font-family:courier">rpcinfo -p \$IP\$</td><td style="$Fss">What rpc's are running</td></tr>
 <tr><td style="$Fss;font-family:courier">showmount -e \$IP\$</td><td style="$Fss">Where are those NFS mounts going?</td></tr>
 <tr><td style="$Fss;font-family:courier">snmpstatus \$IP\$ public</td><td style="$Fss">SNMP Status</td></tr>
 <tr><td style="$Fss;font-family:courier">snmpwalk \$IP\$ public</td><td style="$Fss">More SNMP Status info</td></tr>
 <tr><td style="$Fss;font-family:courier">whisker.pl -h\$IP\$</td><td style="$Fss">Local command</td></tr>
 <tr><td style="$Fss;font-family:courier">nmap -sR -I \$IP\$</td><td style="$Fss">Another rpc scan</td></tr>
 <tr><td style="$Fss;font-family:courier">smbclient -L \$IP\$</td><td style="$Fss">Get a list of shares available on a host</td></tr>
 <tr><td style="$Fss;font-family:courier">/usr/sbin/ntpdate -q \$IP\$</td><td style="$Fss">Check the status of an NTP service</td></tr>
 <tr><td style="$Fss;font-family:courier">rup \$IP\$</td><td style="$Fss">Remote status display</td></tr>
 </table></span></small></p>
EOE
    return $html;
}


sub ScriptPage {
  &Error("Admin-only action") unless $AdminUser;

  my $sname  = $in{'esname'} || $in{'sname'};
  my $port   = $in{'port'};
  my $hosts  = $in{'ipaddresses'};
  
  $hosts =~ s/^\s+//s; $hosts =~ s/\s+$//s;
  $hosts =~ s/\n+/\t/gs;
  $hosts =~ s/ +/\t/gs;
  $hosts =~ s/\t\t+/\t/gs;

  my $script = "";
  my $select = "";

  my(@Scripts,@data);

  if (opendir(SDIR, $Scriptdir)) {
    @Scripts = grep(!/^\./,readdir(SDIR));
    closedir(SDIR);
  }
  foreach (sort @Scripts) {
    $select .= '<option value="'.$_.'">'.$_.'</option>';
  }
  if ($select) {
    $select = '<select name=esname style="'.$Fxs.'"><option selected></option>'.$select.'</select><br>';
  }

  if ($in{'save'}) {
    &Error("Invalid script name: $sname") unless $sname =~ /^[A-Za-z0-9_]+$/;
    open(S, ">$Scriptdir/$sname") or &Error("Unable to write script");
    chomp $in{'script'};
    $in{'script'} =~ s/\r\n/\n/;
    $in{'script'} =~ s/\r/\n/;
    print S "port:",$port,"\nhosts:",$hosts,"\n",$in{'script'},"\n";
    close(S);
  }
  
  if ($in{'edit'} or $in{'save'}) {
    if ($sname and -f "$Scriptdir/$sname") {
      open(S, "<$Scriptdir/$sname") or &Error("Unable to edit script: $sname");
      chomp (@sdata = <S>);
      close(S);
      $port   = shift @sdata; $port  =~ s/^port:\s*//;
      $hosts  = shift @sdata; $hosts =~ s/^hosts:\s*//; $hosts =~ s/\t/\n/gs;
      $script = join("\n",@sdata);
    } else {
      &Error("Unable to find script: $sname");
    }
  } elsif ($in{'delete'}) {
    unlink "$Scriptdir/$sname";
    $sname = "";
  }
  
  return <<EOG;
 </form><font style="$Fsn">Enter your Script Name, Port/Service number, numeric IP addresses for each host,
 and 'send/expect' commands for this script.
 To edit an existing script enter the script name and click on the Edit button below.
 To delete an existing script enter the script name and click on the Delete button below. To execute a
 script click on the <img src="/images/script.gif" width=11 height=13 border=0> image next
 to the port/service on the Details page.<br></font>
 <table border=0 cellspacing=8 cellpadding=0>
  <tr valign="top">
   <td nowrap>
    <form method=get action="$nPulseurl">
    <input type=hidden name=a value=script>
    <table border=0 cellspacing=0><tr><td nowrap><font style="$Fss" color="#ff66ff">Script Name:</font></td><td><input type=text name=sname size=20 style="$Fxs" value="$sname"></td></tr><tr><td></td><td>$select</td></tr></table>
    <font style="$Fss" color="#ff66ff">Port Number:<input type=text size=5 style="$Fxs" name=port value="$port"> <font size=1>[<a target=_blank href="$Htmlprefix/services">list</a>]</font><br>
    <font color="#ff66ff">Commands:</font><br><textarea style="$Fxs" rows=6 cols=40 name=script>$script</textarea><br>
    <font color="#ff66ff">IP Addresses:</font><br><textarea style="$Fxs" rows=6 cols=40 name=ipaddresses>$hosts</textarea><br>
    <input type=submit name=save value="Save"><input type=submit name=edit value="Edit"><input type=submit name=delete value="Delete"></font></form>
   </td>
   <td width=1 bgcolor="#cccccc"><img src="images/dot.gif" width=1 height=50></td>
   <td>
    <font style="$Fss">Script Names can contain only alphanumeric characters (a-zA-Z0-9_). IP addresses
    must be full IP numeric addresses, not ranges.<p>
    Scripts are in the form<blockquote>
    <tt>send: data_to_send<br>
    expect: string_to_match<br>
    send: more_data_to_send<br>
    expect: another_string_to_match</tt></blockquote>
    For example, to see if a HTTP server is responding you might use the following script:<blockquote>
    <tt>send: HEAD / HTTP/1.0<br>
    send: <br>
    expect: 200 OK</tt></blockquote>
    All expect values are case-insensitive with the exception of a special value: EOF which means to wait until an EOF condition occurs.
    For example, to query a HTTP server for all header information you might use the following script:<blockquote>
    <tt>send: HEAD / HTTP/1.0<br>
    send: <br>
    expect: EOF</tt></blockquote>
    </font>
   </td>
  </tr>
 </table>
EOG
}

sub MiniServMod {
    my @AllowedParams = qw(allow log logclear loghost logtime blockhost_failures
                           blockhost_time passdelay syslog session logouttime);
#Access Control
#    allow=ip/mask allow only these ip addresses access (leave blank to allow all addresses)
#
#Logging
#    log=[0 or 1] (dis)(en)able logging
#    logclear=[0 or 1] (dis)(en)able log file clearing
#    loghost=[0 or 1] (dis)(en)able log resolved host names
#    logtime=[168] clear log files every X hours
#
#Authentication
#    blockhost_failures=# Block hosts with more than # failures for blockhost_time seconds
#    blockhost_time=# number of seconds to block a failed host
#    passdelay=[0 or 1] (dis)(en)able password timeouts
#    syslog=[0 or 1] (dis)(en)able logging blocked hosts to syslog 
#    session=[0 or 1] (dis)(en)able session authentication
#    logouttime=# Auto-logout after # minutes of inactivity
#
#Cannot change the following (set during setup.sh execution)
#
#addtype_cgi=internal/cgi
#denyfile=\.pl$
#env_npulse_CONFIG=/usr/local/npulse/etc
#env_npulse_VAR=/usr/local/npulse/log
#keyfile=/usr/local/npulse/etc/miniserv.pem
#logout=/usr/local/npulse/etc/logout-flag
#logfile=/usr/local/npulse/log/miniserv.log
#mimetypes=/usr/local/npulse/etc/mime.types
#pidfile=/usr/local/npulse/log/miniserv.pid
#ppath=
#realm=nPulse Server
#root=/usr/local/npulse
#userfile=/usr/local/npulse/etc/miniserv.users
#host=localhost
#listen=19000
#port=19000
#ssl=[0 or 1]
#localauth=0

    # Display table of current values

    return "<p>You do not have admin priviliges. Sorry.</p>" unless $AdminUser;

    my $subaction = shift;

    my %Params;

	if (open(CONF, "<$Miniconfig")) {
	  while(<CONF>) {
		s/\r|\n//g;
        /^(.*?)=(.*)$/;
        $Params{$1} = $2;
      }
	  close(CONF);
    }
    delete $Params{''};

    if ($subaction =~ /save/i) {
      my ($key,$value);
      foreach $key (@AllowedParams) {
        $value = $in{$key};
        if ($value) {
          $value =~ s/[ \n\r\s]+/ /gs;
          $value =~ s/^ +//s;
          $value =~ s/ +$//s;
          if ($key eq 'allow') {
            next unless $value =~ /^[0-9\.\/ ]+$/;
          } else {
            next unless $value =~ /^[0-9]+$/;
          }
        }
        $Params{$key} = $value;
      }

      open(CONF, ">$Miniconfig") or return "<p>ERROR: Unable to create/modify $Miniconfig</p>";
      my $k;
      foreach $k (sort keys %Params) {
        print CONF $k,'=',$Params{$k},"\n";
      }
      close(CONF);
      
      return &RestartMiniServ()?"":"<p>Warning: miniserv restart error</p>";
    }

    my $log       = $Params{'log'}?"checked":"";
    my $loghost   = $Params{loghost}?"checked":"";
    my $logclear  = $Params{logclear}?"checked":"";
    my $passdelay = $Params{passdelay}?"checked":"";
    my $session   = $Params{session}?"checked":"";
    my $syslog    = $Params{syslog}?"checked":"";

    my $html = <<EOM;
  <p style="$Fss">The following values affect the operation of the nPulse Web Server, miniserv.pl.
  Only experts should attempt to change these values. It is possible to set these values in such
  a way that the server will no longer function. If this happens, stop nPulse and re-run the setup.sh
  routine from the distribution area.</p>
  <table border=0 cellspacing=0 cellpadding=1>
   <tr><td bgcolor="#333399" colspan=3><span style="$Fss"><b>Access Control</b></span></td></tr>
   <tr valign="top">
    <td><span style="$Fss">The nPulse server can be configured to allow access only from certain IP addresses.
     Hostnames (like foo.bar.com) and IP networks (like 10.254.3.0 or 10.254.1.0/255.255.255.128)
     can also be entered. You should limit access to nPulse to trusted addresses, 
     especially if it is accessible from the Internet. Otherwise, anyone who guesses your password 
     will have complete control of nPulse. [To allow all addresses, do not enter any values.]</span></td>
    <td>&nbsp;&nbsp;</td>
    <td nowrap><textarea name=allow rows=6 cols=30 style="$Fss">$Params{allow}</textarea></td>
   </tr>
   <tr><td bgcolor="#333399" colspan=3><span style="$Fss"><b>Logging</b></span></td></tr>
   <tr valign="top">
    <td><span style="$Fss">nPulse can be configured to write a log of server hits, in the standard CLF log file format.
     If logging is enabled, you can also choose whether IP addresses or hostnames are recorded, and 
     how often the log file is cleared. When enabled, logs are written to the file $Params{logfile}.
     You can analyze the log file using any standard web server log file analyzer.</span></td>
    <td>&nbsp;&nbsp;</td>
    <td nowrap><span style="$Fss"><input type=checkbox name=log value=1 $log style="$Fxs">Enable logging<br>
        <input type=checkbox name=loghost value=1 $loghost style="$Fxs">Resolve Host Names<br>
        <input type=checkbox name=logclear value=1 $logclear style="$Fxs">Enable logfile clearing every 
        <input type=text name=logtime size=4 value="$Params{logtime}" style="$Fxs">hours.</span>
    </td>
   </tr>
   <tr><td bgcolor="#333399" colspan=3><span style="$Fss"><b>Authentication</b></span></td></tr>
   <tr valign="top">
    <td><span style="$Fss">When session authentication is enabled, 
     each logged in users' session will be tracked by nPulse, making it possible for idle 
     users to be automatically logged out and for switching users. Be aware that enabling or disabling session 
     authentication may force all users to re-login. When enabled, password timeouts protect your nPulse server from 
     brute-force password cracking attacks by adding a continuously expanding delay between 
     each failed login attempt for the same user.</span></td>
    <td>&nbsp;&nbsp;</td>
    <td nowrap><span style="$Fss">
     <input type=checkbox name=session value=1 $session style="$Fxs">Enable session authentication<br>
     Auto-logout after <input type=text size=4 name=logouttime value="$Params{logouttime}" style="$Fxs"> minutes of inactivity<hr>
     <input type=checkbox name=passdelay value=1 $passdelay>Enable password timeouts<br>
     <input type=checkbox name=syslog value=1 $syslog style="$Fxs">Log blocked hosts to syslog<br>
     Block hosts with more than <input type=text size=2 name=blockhost_failures value="$Params{blockhost_failures}" style="$Fxs">
     failures<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for <input type=text size=2 name=blockhost_time value="$Params{blockhost_time}" style="$Fxs"> seconds<br>
     </span></td>
   </tr>
  </table>
EOM
#    $html .= "<pre>PARAMS\n";
#    foreach (sort keys %Params) {
#      $html .= $_.' = '.$Params{$_}."\n";
#    }
#    $html .= "</pre>";
#
    return $html;
}

1;
