#!/usr/local/bin/perl -w
###############################################################################
# 
# File:         v2html-cgi
# RCS:          $Header: v2html-cgi,v 3.1 1999/09/21 18:38:43 cc Exp $
# Description:  CGI script for helping v2html generated html
# Author:       Costas Calamvokis
# Created:      Wed Sep  3 08:52:08 1997
# Modified:     Tue Sep 21 11:34:21 1999 (Costas Calamvokis) v2html@burbleland.com
# Language:     Perl
#
# Copyright 1998 Costas Calamvokis
# Copyright 1997 Hewlett-Packard Company
#
#  This file nay be copied, modified and distributed only in accordance
#  with the terms of the limited licence contained in the accompanying
#  file LICENCE.TXT.
#
###############################################################################

#
# Currently does:
#  Expanding/compressing hierarchies:
#   - Takes a query like ?k=9437645&x=XXXXCCXC&in=hierarchy.html
#    and generates html of the hierarchy in in accoring to the string
#    x, each character in the string x represents one list in the .html
#    file which can either be eXpanded or Compressed.
#   - After each module it also generates a [X] or [C] link which when
#      clicked causes this script to be called again with a new string
#      which results in that module being expanded or compressed.
#   - This is made much easier by v2html which marks each list that is
#       with a candidate for expansion/compression with a 
#       number when it generates the html code.
#

# only have one file error message to avoid leaking information
#  through errors (uncomment the helpful error during debugging)
$file_error_message= "v2html-cgi error.<P>\n";

print "Content-Type: text/html\n\n";

# environment variables that should be set by the web server
&check_input('QUERY_STRING',%ENV);
&check_input('SCRIPT_NAME',%ENV);
&check_input('PATH_INFO',%ENV);
&check_input('PATH_TRANSLATED',%ENV);

# Get the arguements specified in the URL
%args= getcgivars();

# query variables that should be set in the URL 
#  (eg .. ?k=9999x=CXCX&in=hierarchy.html
&check_input('x',%args);
&check_input('f',%args);
&check_input('in',%args);
&check_input('k',%args);

$k             = $args{'k'};
$expand_string =$args{'x'};
$infile        = $args{'in'};
$framed        = $args{'f'};

# remove the / from script name if it is there
$ENV{'SCRIPT_NAME'} =~ s#^/## ; 

# set up the cgi script and path info that we'll put in the expand/compress
#  links
$cgi_script_and_path_info= "/" . $ENV{'SCRIPT_NAME'} . $ENV{'PATH_INFO'};


$marker = "  <!-- v2html_handle --> ";
$printing=1; # start out printing the file
$ul_id=0;

# Work out the hierarchy file to read
$file=$ENV{'PATH_TRANSLATED'} . $infile;

# Remove any .. in the file name so people can't look at files
#  that are not under the web root
$file=~ s/\.\.//g;

# open the hierarchy file
unless (open(F,"<$file")) { 
    print $file_error_message;
    # this less cryptic message could give intruders clues about your files
    #print "Couldn't open $ENV{'PATH_TRANSLATED'}$infile\n";
    exit;
}


# check that the hierarchy file starts with "<!- v2html hierarchy" comment
#  and that the key is correct
$_ = <F>;
&security_check_hierarchy($_);


# Have a look for the briefcase icons - if they don't exist
#  use [C] and [X]
&find_icons;

# set up the extra infomation needed to do framed output
if ($framed eq "1") {     $target='target="upper"'; }
else                {     $target='';               }

#
# main loop
#
while (<F>) {
    # print the place to find the .v.html files at the bottom of the
    #  header - if we don't do this then it'll look for them under
    #  the cgi-bin directory
    if (m&</head>&) {
	print "<base href=\"http://$ENV{'SERVER_NAME'}" .
	    ":$ENV{'SERVER_PORT'}$ENV{'PATH_INFO'}\">\n";    
    }

    if ($printing) {
	if (m&<ul> <!-- ul_id=([0-9]+) -->&) {
	    if (&check_expand_string($1)) {
		# This is expanded now, so print compressor
		print $marker .
		    "<A name=\"ul_id_$1\"></A>\n";
		print $marker .
		    "<A $target href=\"$cgi_script_and_path_info?k=$k&x=" . 
			&new_expand_string($1,"C") . 
			    "&in=$infile&f=$framed#ul_id_$1\"> $icon_c</A>\n";
		# keep printing
		print $_;
	    }
	    else {
		$ul_id=$1;
		# This is compressed now, so print expander
		print $marker .
		    "<A name=\"ul_id_$ul_id\"></A>\n";
		print $marker .
		    "<A $target href=\"$cgi_script_and_path_info?k=$k&x=" . 
			&new_expand_string($ul_id,"X") . 
			    "&in=$infile&f=$framed#ul_id_$1\"> $icon_x</A>\n";
		# stop printing
		$printing=0;
	    }
	}
	else {
	    # print everything else except compressors and expanders
	    #  which are generated fresh each time
	    if (! m/$marker/) {
		print $_;
	    }
	}
    }
    else {
	# not printing, look for the end of the ul_id which stopped the
	#  print.
	if (m&</ul> <!-- ul_id=$ul_id -->&) {
	    $printing=1;
	}
    }

    

}

exit;

###########################################################################
# Subroutines
###########################################################################

#
# Takes one arguement - the number in the character string to
#  look at.
# Returns 1 if the list is expanded and 0 if it is compressed
#  if the number is off the end of the expand string then it
#  returns 1
#
sub check_expand_string {
    local($u) = @_;
    local($c);

    if ($expand_string eq 'A') {
	return 1;
    }
    elsif (length($expand_string)>$u) {
	$c = substr($expand_string,$u,1);
	if ($c eq 'X'){ 
	    return 1;
	}
	else {
	    return 0;
	}
    }
    else {
	return 0;
    }

}

#
# Generate a new expand_string for a compressor or an expander link
#  Takes two arguments, the number of the list and the new character
#  to put in ('C' for compressor, 'X' for expander)
#
sub new_expand_string {
    local($u,$c) = @_;
    local($new_string,$l);

    $l = length($expand_string);
    if ($l > $u) {
	$new_string = $expand_string;
	substr($new_string,$u,1) = $c;
    }
    else {
	if ($expand_string eq "A") {
	    $new_string = "X" . "X" x ($u-$l) . $c;
	}
	else {
	    $new_string = $expand_string . "C" x ($u-$l) . $c;
	}
    }

    return $new_string;
}

#
# check that the input array %a has an element $s
#
sub check_input {
    local($s,%a) = @_;
    if (!exists($a{$s})) {
	print "v2html-cgi: fatal error, didn't get required parameter $s.<P>\n";
	if ($s eq 'k') {
	    print " This may be because the hierarchy was generated\n" .
	     " by v2html 2.0. If so regenerate using a newer version<P>\n";
	}
	exit;
    }
}

#
# Read all CGI vars into an associative array.
# If multiple input fields have the same name, they are concatenated into
#   one array element and delimited with the \0 character.
# This is a simple version, that assumes a request method of GET.
#
sub getcgivars {
    local(%in) ;
    local($name, $value) ;

    # Resolve and unencode name/value pairs into %in
    foreach (split('&', $ENV{'QUERY_STRING'})) {
        s/\+/ /g ;
        ($name, $value)= split('=', $_, 2) ;
        $name=~ s/%(..)/sprintf("%c",hex($1))/ge ;
        $value=~ s/%(..)/sprintf("%c",hex($1))/ge ;
        $in{$name}.= "\0" if defined($in{$name}) ;  # concatenate multiple vars
        $in{$name}.= $value ;
    }

    return %in ;

}

#
# Do security checks on the hierarchy file
#  make sure we don't:
#   serve files that are not v2html hierarchies
#   serve files that users can't get access to through the http demon
#    (by checking that the key is right)
#
sub security_check_hierarchy {
    my ($first_line) = @_;

    if ($first_line =~ /^<!-- v2html hierarchy/) {
	if ($first_line =~ /^<!-- v2html hierarchy K=$k /) {
	    print $first_line;
	}
	else {
	    print $file_error_message;
	    # this less cryptic message could give intruders clues about your files
	    #print "$ENV{'PATH_TRANSLATED'}$infile: bad key<P>\n";
	    exit;
	}
    }
    else {
	print $file_error_message;
	# this less cryptic message could give intruders clues about your files
	#print "$ENV{'PATH_TRANSLATED'}$infile is not a v2html hierarchy file\n";
	exit;
    }
}

#
# Look for the briefcase icons - if they don't exist use [C] and [X]
#
sub find_icons {
    
 if (( -r "$ENV{'PATH_TRANSLATED'}/v2html-c.gif" ) &&
     ( -r "$ENV{'PATH_TRANSLATED'}/v2html-x.gif" )) {
     $icon_c = "<IMG align=bottom border=0 SRC=\"v2html-c.gif\">";
     $icon_x = "<IMG align=bottom border=0 SRC=\"v2html-x.gif\">";
 }
 else {
     $icon_c = " [C]";
     $icon_x = " [X]";
 }


}