# /*   $Id: bcnulib.pl,v 1.17 2000/05/05 13:06:44 jap Exp $
#
# *    Copyright (c) 1998 John Phillips
# *
# *    You may distribute under the terms of the Artistic License
# *
# */
#
############################################################################

sub header {

local ($title,$errlevel,$refmins)=@_;

$refresh=($refmins*60);

$BCNUHOST=$ALTHOST if $ALTHOST;

if ($errlevel == 9) {
	$HEADING="<TH WIDTH=600 BGCOLOR=$RED>Errors detected - ";
	$SOUND=$SIREN if $sound;
	$DEFBG=$RED
        }
elsif ($errlevel == 5 || $errlevel == 6 ) {
        $HEADING="<TH WIDTH=600 BGCOLOR=$ORANGE>Warning - ";
	$SOUND=$WARNSND if $sound;
	$DEFBG=$ORANGE
        }
elsif ($errlevel == 2) {
        $HEADING="<TH WIDTH=600 BGCOLOR=$VIOLET>Errors Ignored - ";
	$DEFBG=$VIOLET
        }
else    {
       	$HEADING="<TH WIDTH=600 BGCOLOR=$GREEN>No problems reported - ";
	$SOUND="";
	$DEFBG=$GREEN
        }

$hd1 = <<"Endofhd";
<HTML><HEAD><TITLE>BCNU($BCNUHOST) monitor @ $now</TITLE>
<META HTTP-EQUIV=REFRESH CONTENT=$refresh>
<script Language="JavaScript">
//<!-- Hide me from other browsers
var timerID = null;
var timerRunning = false;
var starttime= new Date();
function stopclock (){
   if(timerRunning)
           clearTimeout(timerID);
   timerRunning = false;
}
function startclock () {
   // Make sure the clock is stopped
   stopclock();
   showtime();
}
function showtime () {
   var now = new Date();
   var diff = Math.floor((now-starttime)/1000);
   document.clock.face.value = ($refresh - diff);
// backup for meta tag reload, which sometimes doesn't work:
   if ( diff > $refresh ) { window.location.reload(); }
   timerID = setTimeout("showtime()",1000);
   timerRunning = true;
}
// -->
</SCRIPT>
</HEAD>
<BODY BGCOLOR=$DEFBG onLoad="startclock()">
$SOUND<CENTER>
<TABLE border=0><TR>
<!-- TD valign=top>
<!-- IMG BORDER=0 WIDTH=204 HEIGHT=94 SRC=$BCNUURL/images/bcnu.gif ALT="bcnu image">
$HEADING View: $title</TH>
<TD ALIGN=right VALIGN=TOP>

Endofhd

if ($loginmsg =~ "Logged in") {
	$logbutton="Logout";
	}
else	{
	$logbutton="Login";
}

$hd2 = <<"Endofhd" unless $BCNUSTATIC;

<TABLE BORDER=0>
<FORM ACTION=\"$BCNUURL/cgi-bin/bcnu.cgi\" METHOD="POST"> 
<TR><TH ALIGN=RIGHT>$loginmsg</TH>
<TD><INPUT TYPE="text" NAME="loginid" SIZE=8 VALUE='$loginid'></TD>
<TH ALIGN=RIGHT>Password</TH>
<TD><INPUT TYPE="password" NAME="password" SIZE=8 VALUE=""></TD>
<TD>&nbsp;</TD><TD align=right>
<INPUT TYPE="submit" NAME='$logbutton' VALUE='$logbutton'>
</TR>
</FORM>
</TABLE>

Endofhd

if ( ! $BCNUSTATIC && -r "$BCNUHOME/flags/bcnud.ack") {
	$hd2 .= "<TR><TD><TH ALIGN=CENTER BGCOLOR=$RED>There are unacknowledged alerts</TD></TR>";
}

$hd3 = <<"Endofhd";
</TABLE>$navigate
<CENTER>
<TABLE BORDER=1>

Endofhd

$hd = $hd1.$hd2.$hd3;
return ($hd);
}

sub agent_head
{

$ag = "<TR><TH $DEFCELL>System</TH>";
foreach $agent (@agents) {
        (@ag) = split("[_\.-]",$agent);
#        if ( @ag !=2 ) {
#                $ag .= "<TH $DEFCELL>@ag[0]</TH>";
                $ag .= "<TH $DEFCELL>@ag</TH>";
#	        }
        }
$ag .= "</tr>\n";

return ($ag);
}

sub footer {

$ft =  <<"Endofft";
</TABLE></CENTER>
<p>

<BR>
<CENTER><B><form name="clock">Last update $now, reload in
<input type="text" name="face" size=3 value="$refresh"> seconds</form></B></center>
<CENTER><A HREF=http://bcnu.sourceforge.net><B>BCNU</B></A><B> Build 1.22 1.17 2000/03/16 14:38:15</B></center>

Endofft
#<HR>Best with<P>
#<a href=http://www.microsoft.com/><IMG border=0 src=$BCNUURL/images/ie.gif></a>
#<a href=http://www.netscape.com/><IMG border=0 src=$BCNUURL/images/ns.gif></a>

return ($ft);
}

sub showkey {

$key  =  <<"Endofkey";
<TABLE><TR><TH colspan=2 $DEFCELL>KEY
<TR><TD >$NORMAL><TD >Normal
<TR><TD >$WORRY><TD >Warning
<TR><TD >$SAD><TD >Error
<TR><TD >$ATTACH><TD >Attachment
<TR><TD >$IMGIGNORE><TD >Ignore/Notice
</TABLE>

Endofkey

return ($key);
}

sub navigate {

if ($MONITORONLY) {	# static pages only
$nav  = <<"Endofnav";
<CENTER><TABLE>
<TR><TD colspan=3 ALIGN=CENTER BGCOLOR=#8080FF>
 <A href=$BCNUURL/summ.htm>Summary</a> |
 <A href=$BCNUURL/status.htm>Status only</a> |
 <A href=$BCNUURL/docs/help.html>Help</a>
</TABLE></CENTER>
Endofnav
return ($nav);
}

if ($BCNUSTATIC) {	# static pages only
$nav  = <<"Endofnav";
<CENTER><TABLE>
<TR><TD colspan=3 ALIGN=CENTER BGCOLOR=#8080FF>
 <A href=$BCNUURL/summ.htm>Summary</a> |
 <A href=$BCNUURL/status.htm>Status only</a> |
 <A href=$BCNUURL/platforms.htm>Platforms</a> |
 <A href=$BCNUURL/docs/help.html>Help</a> |
 <A href=$BCNUURL/cgi-bin/bcnu.cgi><B>(Dynamic)</B></a>
</TABLE></CENTER>


Endofnav
}

else {
if ($view) {
	$showview="<A href=$BCNUURL/cgi-bin/bcnu.cgi?view=$view>($view) view</a> |";
	}
$nav  = <<"Endofnav";
<CENTER><TABLE>
<TR><TD ALIGN=CENTER BGCOLOR=#8080FF>
$showview
 <A href=$BCNUURL/cgi-bin/bcnu.cgi>Summary</a> |
 <A href=$BCNUURL/cgi-bin/bcnu.cgi?status=only>Status only</a> |
 <A href=$BCNUURL/cgi-bin/bcnu.cgi?platform=only>Platforms</a> |
 <A href=$BCNUURL/cgi-bin/bcnuqry.cgi>Query</a> |
 <A href=$BCNUURL/docs/help.html>Help</a> |
 <A href=$BCNUURL/summ.htm><B>(Static)</B></a>
</TABLE></CENTER>


Endofnav

}
return($nav);
}

sub mainhost {

local ($host) =@_;

	if ($AGENTS) {
		$line{$host} = "<TR $BASEROW><TD $ECELL ALIGN=LEFT><A HREF=$BCNUURL/hosts/$host.htm>$host</a></TD>\n";
		}
	else	{
		$line{$host} = "<TR $BASEROW><TD $ECELL ALIGN=LEFT><A HREF=$BCNUURL/cgi-bin/bcnuagent.cgi?host=$host>$host</a></TD>\n";
		}
        foreach $agent (@agents) {
#                if ($agent =~ /$IGNOREPAT/) {
#                        $ignoreag=1;
#                        }
#                else {
                        $ignoreag=0 ;
#                        }

		if  (&agentread($host,$agent)) {

# check if the av agent has sent a blackout alert i.e. normal shutdown
		if ($ag eq "av" && $type == 1) {
			$flagav{$host}++;
			}

# Has the alert been updated recently
                if ( -M "$DATA/hosts/$host/$agent" > $LASTTIME ) {
                        $CELL=$WARNCELL;
                        }
# should I ignore errors for this?
                if ( -r "$BCNUHOME/flags/$host.ignore") {
			$errlevel{$host}=$type;
			$type = 2 if $type > 0;
			$flagignore{$host}="notice=$host";
			$ignoremsg{$host}="Notice errors/warnings for $host";
		}

# set the blackout on for systems which have been shut down

		if ($flagav{$host}) {
			$type=1;
			}

		if ($AGENTS) {
			$AGLINK="<A HREF=$BCNUURL/hosts/$host.$ag.htm>";
			}
		else
			{
			$AGLINK="<A HREF=$BCNUURL/cgi-bin/bcnuagent.cgi?host=$host&agent=$ag>";
		}

                if ( $type == 9 ) {
                           $IMG="$SAD ALT=\"$msg:$time\" >";
                           $line{$host} .= "<TD $CELL>$AGLINK $IMG </A></TD>\n" unless $ignoreag;
                           $errlevel{$host}=9;
                           $errlevel=9;
                        }
                elsif ($type == 5 || $type == 6 ) {
                           $IMG="$WORRY ALT=\"$msg:$time\" >";
                           $line{$host} .= "<TD $CELL>$AGLINK $IMG </A></TD>\n" unless $ignoreag;
                           $errlevel{$host}=5 if $errlevel{$host}==0;
                           $errlevel=5 if $errlevel==0;
                        }
                elsif ($type == 1) {
                           $IMG="$NORMAL ALT=\"$msg:$time\" >";
                           $line{$host} .= "<TD $BLACKCELL>$AGLINK $IMG </A></TD>\n" unless $ignoreag;
                        }
                elsif ($type == 2) {
                           $IMG="$IMGIGNORE ALT=\"$msg:$time\" >";
                           $line{$host} .= "$IGNORE<TD $IGNORECELL>$AGLINK $IMG </A></TD>\n" unless $ignoreag;
			}
                else    {
                           $IMG="$NORMAL ALT=\"$msg:$time\" >";
                           $line{$host} .= "<TD $CELL>$AGLINK $IMG </A></a></TD>\n" unless $ignoreag;
                        }

                   }
              else {
                   $line{$host} .= "<TD $CELL>&nbsp</TD>\n" unless $ignoreag;
                   }
        $CELL=$BASECELL;
        }
}

sub agenthost {

local ($host) =@_;

	$agdisp = "<TR><TH $DEFCELL>System<TH $DEFCELL>Status<TH $DEFCELL>Agent<TH $DEFCELL>Date/Time<TH $DEFCELL>Message</TR>\n";

        foreach $agent (@agents) {

		$agdisp .= &agentdisp($host,$agent);
                
		}
return ($agdisp);
}

sub agentdetail {

local ($host,$agent,$hist) =@_;

	$agdisp = "<TR><TH $DEFCELL>System<TH $DEFCELL>Status<TH $DEFCELL>Agent<TH $DEFCELL>Date/Time<TH $DEFCELL>Message</TR>\n";

	$agdisp .= &agentdisp($host,$agent,$hist);

	$agdisp .= "</TABLE><H1>Agent Details</H1><TABLE BORDER=1>\n";

	$agdisp .= "<TR><TH $DEFCELL>Msg type<TH $DEFCELL>Level<TH $DEFCELL>For Host<TH $DEFCELL>Host type<TH $DEFCELL>From Host<TH $DEFCELL>bcnud From Host<TH $DEFCELL>bcnud Received</TR>\n";
	$agdisp .= "<TR><TD $ECELL>$stat<TD $ECELL>$bcnu_status{$type}<TD $ECELL>$host<TD $ECELL>$bcnu_host_type{$htype}<TD $ECELL>$h2<TD $ECELL>$bhost<TD $ECELL>$btime</TR>\n";

if ($bfile) {
	if (open (BFILE, "$bfilename")) {
        	@incfile =(<BFILE>);
	        close (BFILE);
	        }
	else {
	        @incfile="Unable to open $bfilename";
	}
	$agdisp .= "<TR><TD $BGCELL COLSPAN=7 >Contents of $bfilename\n";
	$agdisp .= "<TR><TD COLSPAN=7 $ECELL><PRE>@incfile</pre></td></TR></TABLE>\n";
}	
        
return ($agdisp);
}

sub agentdisp {

local ($host,$agent,$hist) =@_;

	$histhost=&agentread($host,$agent,$hist);

$BG="";                
		if ( $type == 9 ) {
                           $IMG="$SAD>";
                           $errlevel=9;
                        }
                elsif ($type == 5 || $type == 6) {
                           $IMG="$WORRY>";
                           $errlevel=5 if $errlevel==0;
                        }
                elsif ($type == 1) {
                           $IMG="$NORMAL>";
			   $BG="$BLACKCELL";
                        }
                elsif ($type == 2) {
                           $IMG="$IMGIGNORE>";
			}
                else    {
                           $IMG="$NORMAL>";
                        }

		if ($hist)	{
			$dtime=$time;
			$dtime =~ s/ /+/;
                	$agdet = "<TR BGCOLOR=#ffff80 ><TD $ECELL ALIGN=LEFT>$histhost<TD $CELL>$IMG<TD $CELL><A HREF=$BCNUURL/cgi-bin/bcnuqry.cgi?host=$histhost&agent=$ag&dtime=$dtime&logfile=$inlogfile>$ag</a><TD $CELL>$time<TD $CELL>$msg</TR>\n";
		}
		else	{
	                
			if ($bfile) {
        	              $ADD="$ATTACH ALT=\"attachment\">";
                	        }
			else	{
			$ADD="";
			}
			if ($AGENTDETAIL) {
                		$agdet = "<TR BGCOLOR=#ffff80 ALIGN=LEFT ><TD $ECELL ALIGN=LEFT><A HREF=$BCNUURL/hosts/$host.htm>$host</a><TD $CELL $BG>$IMG$ADD<TD $CELL><A HREF=$BCNUURL/hosts/$host.$ag.htm>$ag</a><TD $CELL>$time<TD $CELL>$msg</TR>\n";
			}
			else	{
                		$agdet = "<TR BGCOLOR=#ffff80 ALIGN=LEFT ><TD $ECELL ALIGN=LEFT><A HREF=$BCNUURL/cgi-bin/bcnuagent.cgi?host=$host>$host</a><TD $CELL $BG>$IMG$ADD<TD $CELL><A HREF=$BCNUURL/cgi-bin/bcnuagent.cgi?host=$host&agent=$ag>$ag</a><TD $CELL>$time<TD $CELL>$msg</TR>\n";
			}
		}

return ($agdet);
}

sub agentread {

local ($host,$agent,$hist) =@_;

if ( $hist ) {
	$rec=$hist;
	chop $rec;
	}
else	{
	if ( -r "$DATA/hosts/$host/$agent") {
		open (PAGE, "$DATA/hosts/$host/$agent") || &bcnuerror("$host", "can't open directory $host/$agent");
		$rec = (<PAGE>);
		close (PAGE);
		chop $rec;
		}
	else {
		return 0;
		}
	}
		
($stat,$type,$host,$h2,$ag,$time,$msg,$bhost,$btime,$bfile,$bfilename,$htype) = split (":",$rec);

$platform{$host}=&max($htype,$platform{$host});

#&debuggit("host = $htype, platform = $platform{$host}\n");

return ($host);

}

sub bcnuerror {

local ($object,$errmsg) =@_;

print &printhdr;
print &header("$object",9,60);
print "</TABLE><H1>$errmsg</H1>\n";
print &footer();
exit;
}


sub getagents {

local ($host) =@_;

opendir(HDIR,"$DATA/hosts/$host");
	@agents=readdir(HDIR);
	foreach $agent (sort @agents) {
	        next if $agent =~ /\.$/;
	        $mon{$agent}++;
	}
	@agents = (sort keys (%mon));
}

sub authhdr {

return "Status:401 Unauthorised\nWWW-Authenticate: Basic realm=\"bcnu\"\n";

}

sub viewhosts {

local ($view) =@_;
if (open(INVIEW,"$BCNUHOME/www/views/$view")) {
        (@hosts)=split(" ",<INVIEW>);
        close(INVIEW);
	$numhosts=@hosts;
	foreach $host (sort @hosts) {
	        next if $host =~ /\.$/;
	        &sumgetagents($host);
	        }
	@agents = (sort keys (%mon));
	}
else	{
	&gethosts;
	}
}

sub gethosts {

opendir(DIR,"$DATA/hosts") ||  &bcnuerror("Host", "can't open directory $DATA/hosts");
@hosts=grep (/\w$/,readdir(DIR));

if ($TURBOAGENT) {
	opendir(DIR,"$DATA/agents") ||  &bcnuerror("Agents", "can't open directory $DATA/agents");
	@agents=sort(grep (/\w$/,readdir(DIR)));
	}
else {
	foreach $host (sort @hosts) {
	        next if $host =~ /\.$/;
		&sumgetagents($host);
        	}
	@agents = (sort keys (%mon));

	}
return(@hosts);
}

sub sumgetagents {

local ($host) =@_;

if ( -r "$BCNUHOME/flags/$host.ignore") {
	$hoststat{$host}=2;
	if (open(IGNORE,"$BCNUHOME/flags/$host.ignore")) {
        	$flagignore=<IGNORE>;
	        chop $flagignore;
	        ($done,$login,$reason) = split(":",$flagignore);
	        close(IGNORE);
		$lasterr{"$host-2"}="$login - $reason";
		$platform{$host}=$def_host_type;
	}
	return;
}

if ( &agentread($host,"av")) {
	if ($type == 1) {
		$hoststat{$host}=1;
		return;
	}

}
opendir(HDIR,"$DATA/hosts/$host");
	@agents=(grep (/\w$/,readdir(HDIR)));
	foreach $agent (sort @agents) {
	        $mon{$agent}++;
		&agentread($host,$agent);
		$hoststat{$host}=&max($hoststat{$host},$type);
		$errlevel=&max($errlevel,$type);
		$lasterr{"$host-$type"}="$time $msg";
# Has the alert been updated recently
                if ( -M "$DATA/hosts/$host/$agent" > $LASTTIME ) {
                        $hoststat{$host}=&max($hoststat{$host},3);
                        }
	}
}

sub sumhost {

local ($host) =@_;


if ($AGENTS) {
#	$cell{$host} = "<A HREF=$BCNUURL/hosts/$host.htm>\n";
	$ANCHOR = "<A HREF=$BCNUURL/hosts/$host.htm>\n";
	}
else	{
#	$cell{$host} = "<A HREF=$BCNUURL/cgi-bin/bcnuagent.cgi?host=$host>\n";
	$ANCHOR = "<A HREF=$BCNUURL/cgi-bin/bcnuagent.cgi?host=$host>\n";
	}

$type=$hoststat{$host};

if ( $type == 9 ) {
	$IMG="$SAD ALT=\"Last error: $lasterr{\"$host-$type\"}\" >";
	$cell{$host} .= "<TD $CELL WIDTH=70>$ANCHOR $IMG";
	}
elsif ($type == 5 || $type == 6) {
	$IMG="$WORRY ALT=\"Last warning: $lasterr{\"$host-$type\"}\" >";
	$cell{$host} .= "<TD $CELL WIDTH=70>$ANCHOR $IMG";
	}
elsif ($type == 1) {		# blackouts
	$IMG="$NORMAL ALT=\"Blackout\" >";
	$cell{$host} .= "<TD $BLACKCELL WIDTH=70>$ANCHOR $IMG";
	$DARK=1
	}
elsif ($type == 2) {		# Ignore
	$IMG="$IMGIGNORE ALT=\"$lasterr{\"$host-$type\"}\" >";
	$cell{$host} .= "<TD $IGNORECELL WIDTH=70>$ANCHOR $IMG";
	$DARK=1;
	}
elsif ($type == 3) {		# No report recently
	$IMG="$NORMAL ALT=\"No report recently\" >";
	$cell{$host} .= "<TD $WARNCELL WIDTH=70>$ANCHOR $IMG";
	}
else    {
	$IMG="$NORMAL ALT=\"OK\" >";
	$cell{$host} .= "<TD $CELL WIDTH=70>$ANCHOR$IMG";
	}
if ($DARK) {
	$cell{$host} .= "<BR><TABLE BGCOLOR=#FFFFFF><TD>$host</TABLE></a></TD>";
	$DARK=0;
	}
else	{
	$cell{$host} .= "<BR>$host</a></TD>\n";
	}

}

sub max {

local ($f1,$f2) =@_;

return ($f2) if $f2 > $f1;
return ($f1);

}


sub readack {

$acks=0;
open (ACK,"$BCNUHOME/flags/bcnud.ack") || return $acks;

while (<ACK>)
        {
        ($host,$ag,$date,$time,@msg) = split(" ",$_);
	$rec=":9:$host:$host:$ag:$date $time:"."@msg".":::::";
	@record{$host.$ag.$date.$time} = $rec;
	$refdate=$date;
	$refdate =~ s/-//g;
	$loghash{$host.$ag.$date.$time} = $refdate;
	$acks++;
	}
close (ACK);
return $acks;
}

sub genackform {

$ackform = <<"Endofform";

<INPUT TYPE="text" NAME="reason" SIZE=15>
<INPUT TYPE="checkbox" NAME="ackchk" VALUE="$histhost+$ag+$dtime">

Endofform

}

sub cklogin {

$loginid=$in{"loginid"} if defined $in{"loginid"};
$password=$in{"password"};
$login=$in{"Login"};
$logout=$in{"Logout"};

if ($login) {
	if (&validlogin($loginid,$password)) {
		$cookie{"bcnulogin"} = "$loginid";
#		&set_cookie(time()+28800, "$BCNUURL/cgi-bin/"); # cookie expires in 8 hours
		&set_cookie(-1, "$BCNUURL/cgi-bin/"); # cookie expires when browser shuts
		$loginmsg="Logged in";
		}
	else
		{
		&delete_cookie("bcnulogin","$BCNUURL/cgi-bin/");
		undef $loginid;
		$loginmsg="Bad login";
		}
	}
elsif ($logout) {
		&delete_cookie("bcnulogin","$BCNUURL/cgi-bin/");
		undef $loginid;
		$loginmsg="Login";
	}
}

sub validlogin	{

local ($login,$password) =@_;

if ( ! $BCNUPASSWD ) {
	return(1);
}

open (INPASSWD,$BCNUPASSWD) || &bcnuerror("$host", "Can't open password file $BCNUPASSWD.\n");

while (<INPASSWD>) {
	chop;
	($pwlogin,$pwpassword) = split(":");

	if ($pwlogin eq $login) {
		$ckpass=crypt($password,$pwpassword);
		if ($ckpass eq $pwpassword) {
			return(1);
			}
		
		}
	}	
close(INPASSWD);
return (0);
}


sub weback {

open (WEBACK,">>$BCNUHOME/logs/weback.log") ||  &bcnuerror("Acknowledge","Can't open $BCNUHOME/logs/weback.log");

print WEBACK "$now: Login $loginid: @_\n";

close (WEBACK);

}
sub debuggit {

open (DEBUG,">>/tmp/debug.out") || die "can't open debug file";

print DEBUG "$host $agent:$hoststat{$host}\n";
print DEBUG "@_\n";

close (DEBUG);

}

###########################################################################
# methodparse
# Reads in GET or POST data, converts it to unescaped text, and puts
# one key=value in each member of the list "@in"
# Also creates key/value pairs in %in, using '\0' to separate multiple
# selections

# Based on cgi-lib which is Copyright S.E.Brenner@bioc.cam.ac.uk

sub methodparse {
  if (@_) {
    local (*in) = @_;
  }

  local ($i, $loc, $key, $val);

  # Read in text
  if ($ENV{'REQUEST_METHOD'} eq "GET") {
    $in = $ENV{'QUERY_STRING'};
  } elsif ($ENV{'REQUEST_METHOD'} eq "POST") {
    for ($i = 0; $i < $ENV{'CONTENT_LENGTH'}; $i++) {
      $in .= getc;
    }
  } 

  @in = split(/&/,$in);

  foreach $i (0 .. $#in) {
    # Convert plus's to spaces
    $in[$i] =~ s/\+/ /g;
    $in[$i] =~ s/'//g;		# fixed for slackware by Scott Griffith
    $in[$i] =~ s/\\//g;		# fixed for slackware by Scott Griffith

    # Convert %XX from hex numbers to alphanumeric
    $in[$i] =~ s/%(..)/pack("c",hex($1))/ge;

    # Split into key and value.
    $loc = index($in[$i],"=");
    $key = substr($in[$i],0,$loc);
    $val = substr($in[$i],$loc+1);
#    $in{$key} .= '\0' if (defined($in{$key})); # \0 is the multiple separator
# changed to ! by jp as \0 doesn't work
    $in{$key} .= '!' if (defined($in{$key})); # \0 is the multiple separator
    $in{$key} .= $val;
  }

}

sub printhdr {
  return "Content-type: text/html\n\n";
}

# PrintVariables
# Nicely formats variables in an associative array passed as a parameter
# And returns the HTML string.

sub PrintVariables {
  local (%in) = @_;
  local ($old, $out);
  $old = $*;  $* =1;
  $output .=  "<DL COMPACT>";
  foreach $key (sort keys(%in)) {
    ($out = $in{$key}) =~ s/\n/<BR>/g;
    $output .=  "<DT><B>$key</B><DD><i>$out</I><BR>";
  }
  $output .=  "</DL>";
  $* = $old;

  return $output;
}

# PrintVariablesShort
# Nicely formats variables in an associative array passed as a parameter
# Using one line per pair (unless value is multiline)
# And returns the HTML string.

sub PrintVariablesShort {
  local (%in) = @_;
  local ($old, $out);
  $old = $*;  $* =1;
  foreach $key (sort keys(%in)) {
    if (($out = $in{$key}) =~ s/\n/<BR>/g) {
      $output .= "<DL COMPACT><DT><B>$key</B> is <DD><i>$out</I></DL>";
    } else {
      $output .= "<B>$key</B> is <i>$out</I><BR>";
    }
  }
  $* = $old;

  return $output;
}

#####################
return 1;
