#! /usr/bin/perl
#
# (configure the first line to contain YOUR path to perl 5.000+)
#
# CGIscriptor.pl
# Version 2.1
# 15 January 2002
#
# YOU NEED:
#
# perl 5.0 or higher (see: "http://www.perl.org/")
#
# Notes:
#
# This Perl program will run on any WWW server that runs Perl scripts,
# just add a line like the following to your srm.conf file
# (Apache example):
#
# ScriptAlias /SHTML/ "/real-path/CGIscriptor.pl/"
#
# URL's that refer to http://www.your.address/SHTML/... will now be handled
# by CGIscriptor.pl, which can use a private directory tree (default is the
# DOCUMENT_ROOT directory tree, but it can be anywhere, see below).
#
# This file contains all documentation as comments. These comments
# can be removed to speed up loading (e.g., `egrep -v '^#' CGIscriptor.pl` >
# leanScriptor.pl). A bare bones version of CGIscriptor.pl, lacking
# documentation, most comments, access control, example functions etc.
# (but still with the copyright notice and some minimal documentation)
# can be obtained by calling CGIscriptor.pl with the '-slim'
# command line argument, e.g.,
# >CGIscriptor.pl -slim >slimCGIscriptor.pl
#
# CGIscriptor.pl can be run from the command line as
# `CGIscriptor.pl `, inside a perl script with
# 'do CGIscriptor.pl' after setting $ENV{PATH_INFO} and $ENV{QUERY_STRING},
# or CGIscriptor.pl can be loaded with 'require "/real-path/CGIscriptor.pl"'.
# In the latter case, requests are processed by 'Handle_Request();'
# (again after setting $ENV{PATH_INFO} and $ENV{QUERY_STRING}).
#
# Running demo's and more information can be found at
# http://www.fon.hum.uva.nl/rob/OSS/OSS.html
#
# A pocket-size HTTP daemon, CGIservlet.pl, is available from my web site
# or CPAN that can use CGIscriptor.pl as the base of a µWWW server and
# demonstrates its use.
#
# Configuration, copyright notice, and user manual follow the next
# (Changes) section.
#
############################################################################
#
# Changes (document ALL changes with date, name and email here):
# 19 Mar 2002 - Added SRC pseudo-files PREFIX and POSTFIX. These
# switch to prepending or to appending the content
# of the SRC attribute. Default is prefixing. You
# can add as many of these switches as you like.
# 13 Mar 2002 - Do not search for tag content if a tag closes with
# />, i.e.,

#
#
# Save this in a file, hello.html, in the directory you indicated with
# $YOUR_HTML_FILES and access http://your_server/SHTML/hello.html
# (or to whatever name you use as an alias for CGIscriptor.pl).
# This is realy ALL you need to do to get going.
#
# You can use any values that are delivered in CGI-compliant form (i.e.,
# the "?name=value" type URL additions) transparently as "$name" variables
# in your scripts IFF you have declared them in the CGI attribute of
# a META or SCRIPT tag before e.g.:
#
# or
#
# is
#

#
#
# Next question:
#
#
#
# The output could look like the following (in HTML-speak):
#
#

# The Answer to your question
#

What is the capital of the Netherlands?

# is
#

Amsterdam

#

#
# Next question:
#
#
# Note that the function "Answer.pl" does know nothing about CGI or HTML,
# it just prints out answers to arguments. Likewise, the text has no
# provisions for scripts or CGI like constructs. Also, it is completely
# trivial to extend this "program" to use the "Answer" later in the page
# to call up other information or pictures/sounds. The final text never
# shows any cue as to what the original "source" looked like, i.e.,
# where you store your scripts and how they are called.
#
# There are some extra's. The argument of the files called in a SRC= tag
# can access the CGI variables declared in the preceding META tag from
# the @ARGV array. Executable files are called as:
# `file '$ARGV[0]' ... ` (e.g., `Answer.pl \'$Question\'`;)
# The files called from SRC can even be (CGIscriptor) html files which are
# processed in-line. Furthermore, the SRC= tag can contain a perl block
# that is evaluated. That is,
#
# will result in the evaluation of "print do {$Question};" and the VALUE
# of $Question will be printed. Note that these "SRC-blocks" can be
# preceded and followed by other file names, but only a single block is
# allowed in a SRC= tag.
#
# One of the major hassles of dynamic WWW pages is the fact that several
# mutually incompatible browsers and platforms must be supported. For example,
# the way sound is played automatically is different for Netscape and
# Internet Explorer, and for each browser it is different again on
# Unix, MacOS, and Windows. Realy dangerous is processing user-supplied
# (form-) values to construct email addresses, file names, or database
# queries. All Apache WWW-server exploits reported in the media are
# based on faulty CGI-scripts that didn't check their user-data properly.
#
# There is no panacee for these problems, but a lot of work and problems
# can be safed by allowing easy and transparent control over which
# blocks are executed on what CGI-data. CGIscriptor
# supplies such a method in the form of a pair of attributes:
# IF='...condition..' and UNLESS='...condition...'. When added to a
# script tag, the whole block (including the SRC attribute) will be
# ignored if the condition is false (IF) or true (UNLESS).
# For example, the following block will NOT be evaluated if the value
# of the CGI variable FILENAME is NOT a valid filename:
#
#
#
# (the function CGIsafeFileName(String) returns an empty string ("")
# if the String argument is not a valid filename).
# The UNLESS attribute is the mirror image of IF.
#
# A user manual follows the HTML 4 and security paragraphs below.
#
##########################################################################
#
# HTML 4 compliance
#
# In general, CGIscriptor.pl complies with the HTML 4 recommendations of
# the W3C. This means that any software to manage Web sites will be able
# to handle CGIscriptor files, as will web agents.
#
# All script code should be placed between tags, the
# script type is indicated with TYPE="mime-type", the LANGUAGE
# feature is ignored, and a SRC feature is implemented. All CGI specific
# features are delegated to the CGI attribute.
#
# However, the behavior deviates from the W3C recommendations at some
# points. Most notably:
# 0- The scripts are executed at the server side, invissible to the
# client (i.e., the browser)
# 1- The mime-types are personal and idiosyncratic, but can be adapted.
# 2- Code in the body of a tag-pair is still evaluated
# when a SRC feature is present.
# 3- The SRC attribute reads a list of files.
# 4- The files in a SRC attribute are processed according to file type.
# 5- The SRC attribute evaluates inline Perl code.
# 6- Processed META, DIV tags are removed from the output
# document.
# 7- All attributes of the processed META tags, except CONTENT, are ignored
# (i.e., deleted from the output).
# 8- META tags can be placed ANYWHERE in the document.
# 9- Through the SRC feature, META tags can have visible output in the
# document.
# 10- The CGI attribute that declares CGI parameters, can be used
# inside the TAG CONSTRUCT.
#
# The reason for the IF, UNLESS, and SRC attributes (and their Perl code
# evaluation) were build into the META and SCRIPT tags is part laziness,
# part security. The SRC blocks allows more compact documents and easier
# debugging. The values of the CGI variables can be immediately screened
# for security by IF or UNLESS conditions, and even SRC attributes (e.g.,
# email addresses and file names), and a few commands can be called
# without having to add another Perl TAG pair. This is especially important
# for documents that require the use of other (more restricted) "scripting"
# languages and facilities that lag transparent control structures.
#
##########################################################################
#
# SECURITY
#
# Your WWW site is a few keystrokes away from a few hundred million internet
# users. A fair percentage of these users knows more about your computer
# than you do. And some of these just might have bad intentions.
#
# To ensure uncompromized operation of your server and platform, several
# features are incorporated in CGIscriptor.pl to enhance security.
# First of all, you should check the source of this program. No security
# measures will help you when you download programs from anonymous sources.
# If you want to use THIS file, please make sure that it is uncompromized.
# The best way to do this is to contact the source and try to determine
# whether s/he is reliable (and accountable).
#
# BE AWARE THAT ANY PROGRAMMER CAN CHANGE THIS PROGRAM IN SUCH A WAY THAT
# IT WILL SET THE DOORS TO YOUR SYSTEM WIDE OPEN
#
# I would like to ask any user who finds bugs that could compromise
# security to report them to me (and any other bug too,
# Email: Rob.van.Son@hum.uva.nl or rob.van.son@workmail.com).
#
# Security features
#
# 1 Invisibility
# The inner workings of the HTML source files are completely hidden
# from the client. Only the HTTP header and the ever changing content
# of the output distinguish it from the output of a plain, fixed HTML
# file. Names, structures, and arguments of the "embedded" scripts
# are invisible to the client. Error output is suppressed except
# during debugging (user configurable).
#
# 2 Separate directory trees
# Directories containing Inline text and script files can reside on
# separate trees, distinct from those of the HTTP server. This means
# that NEITHER the text files, NOR the script files can be read by
# clients other than through CGIscriptor.pl, UNLESS they are
# EXPLICITELY made available.
#
# 3 Requests are NEVER "evaluated"
# All client supplied values are used as literal values (''-quoted).
# Client supplied ''-quotes are ALWAYS removed. Therefore, as long as the
# embedded scripts do NOT themselves evaluate these values, clients CANNOT
# supply executable commands. Be sure to AVOID scripts like:
#
#
#
#
# These are a recipe for disaster. However, the following quoted
# form should be save (but is still not adviced):
#
#
#
# A special function, SAFEqx(), will automatically do exactly this,
# e.g., SAFEqx('ls -1 $UserValue') will execute `ls -1 \'$UserValue\'`
# with $UserValue interpolated. I recommend to use SAFEqx() instead
# of backticks whenever you can. The OS shell scripts inside
#
#
#
# are handeld by SAFEqx and automatically ''-quoted.
#
# 4 Logging of requests
# All requests can be logged separate from the Host server. The level of
# detail is user configurable: Including or excluding the actual queries.
# This allows for the inspection of (im-) proper use.
#
# 5 Access control: Clients
# The Remote addresses can be checked against a list of authorized
# (i.e., accepted) or non-authorized (i.e., rejected) clients. Both
# REMOTE_HOST and REMOTE_ADDR are tested so clients without a proper
# HOST name can be (in-) excluded by their IP-address. Client patterns
# containing all numbers and dots are considered IP-addresses, all others
# domain names. No wild-cards or regexp's are allowed, only partial
# addresses.
# Matching of names is done from the back to the front (domain first,
# i.e., $REMOTE_HOST =~ /\Q$pattern\E$/is), so including ".edu" will
# accept or reject all clients from the domain EDU. Matching of
# IP-addresses is done from the front to the back (domain first, i.e.,
# $REMOTE_ADDR =~ /^\Q$pattern\E/is), so including "128." will (in-)
# exclude all clients whose IP-address starts with 128.
# There are two special symbols: "-" matches HOSTs with no name and "*"
# matches ALL HOSTS/clients.
# For those needing more expressional power, lines starting with
# "-e" are evaluated by the perl eval() function. E.g.,
# '-e $REMOTE_HOST =~ /\.edu$/is;' will accept/reject clients from the
# domain '.edu'.
#
# 6 Access control: Files
# In principle, CGIscriptor could read ANY file in the directory
# tree as discussed in 1. However, for security reasons this is
# restricted to text files. It can be made more restricted by entering
# a global file pattern (e.g., ".html"). This is done by default.
# For each client requesting access, the file pattern(s) can be made
# more restrictive than the global pattern by entering client specific
# file patterns in the Access Control files (see 5).
# For example: if the ACCEPT file contained the lines
# * DEMO
# .hum.uva.nl LET
# 145.18.230.
# Then all clients could request paths containing "DEMO" or "demo", e.g.
# "/my/demo/file.html" ($PATH_INFO =~ /\Q$pattern\E/), Clients from
# *.hum.uva.nl could also request paths containing "LET or "let", e.g.
# "/my/let/file.html", and clients from the local cluster
# 145.18.230.[0-9]+ could access ALL files.
# Again, for those needing more expressional power, lines starting with
# "-e" are evaluated. For instance:
# '-e $REMOTE_HOST =~ /\.edu$/is && $PATH_INFO =~ m@/DEMO/@is;'
# will accept/reject requests for files from the directory "/demo/" from
# clients from the domain '.edu'.
#
# 7 Query length limiting
# The length of the Query string can be limited. If CONTENT_LENGTH is larger
# than this limit, the request is rejected. The combined length of the
# Query string and the POST input is checked before any processing is done.
# This will prevent clients from overloading the scripts.
# The actual, combined, Query Size is accessible as a variable through
# $CGI_Content_Length.
#
# 8 Illegal filenames, paths, and protected directories
# One of the primary security concerns in handling CGI-scripts is the
# use of "funny" characters in the requests that con scripts in executing
# malicious commands. Examples are inserting ';', null bytes, or
# characters in URL's and filenames, followed by executable commands. A
# special variable $FileAllowedChars stores a string of all allowed
# characters. Any request that translates to a filename with a character
# OUTSIDE this set will be rejected.
# In general, all (readable files) in the DocumentRoot tree are accessible.
# This might not be what you want. For instance, your DocumentRoot directory
# might be the working directory of a CVS project and contain sensitive
# information (e.g., the password to get to the repository). You can block
# access to these subdirectories by adding the corresponding patterns to
# the $BlockPathAccess variable. For instance, $BlockPathAccess = '/CVS/'
# will block any request that contains '/CVS/' or:
# die if $BlockPathAccess && $ENV{'PATH_INFO'} =~ m@$BlockPathAccess@;
#
# 9 The execution of code blocks can be controlled in a transparent way
# by adding IF or UNLESS conditions in the tags themselves. That is,
# a simple check of the validity of filenames or email addresses can
# be done before any code is executed.
#
###############################################################################
#
# USER MANUAL (sort of)
#
# CGIscriptor removes embedded scripts, indicated by an HTML 4 type
# or constructs. CGIscriptor also recognizes XML-type
# constructs. These are usefull when
# the necessary code is already available in the TAG itself (e.g.,
# using external files). The contents of the directive are executed by
# the PERL eval() and `` functions (in a separate name space). The
# result of the eval() function replaces the construct
# in the output file. You can use the values that are delivered in
# CGI-compliant form (i.e., the "?name=value&.." type URL additions)
# transparently as "$name" variables in your directives after they are
# defined in a or
#
# (This will print a "-" if REMOTE_HOST is not known)
# Another way to do this is:
#
#
#
# or
#
#
# This is possible because ALL environment variables are available as
# CGI variables. The environment variables take precedence over CGI
# names in case of a "name clash". For instance:
#
# Will print the current HOME directory (environment) irrespective whether
# there is a CGI variable from the query
# (e.g., Where do you live? )
# THIS IS A SECURITY FEATURE. It prevents clients from changing
# the values of defined environment variables (e.g., by supplying
# a bogus $REMOTE_ADDR). Although $ENV{} is not changed by the META tags,
# it would make the use of declared variables insecure. You can still
# access CGI variables after a name clash with
# CGIscriptor::CGIparseValue().
#
# Some CGI variables are present several times in the query string
# (e.g., from multiple selections). These should be defined as
# @VARIABLENAME=default in the CGI attribute. The list @VARIABLENAME
# will contain ALL VARIABLENAME values from the query, or a single
# default value. If there is an ENVIRONMENT variable of the
# same name, it will be used instead of the default AND the query
# values. The corresponding function is
# CGIscriptor::CGIparseValueList()
#
# CGI variables collected in a @VARIABLENAME list are unordered.
# When more structured variables are needed, a hash table can be used.
# A variable defined as %VARIABLE=default will collect all
# CGI-parameters whose name start with 'VARIABLE' in a hash table with
# the remainder of the name as a key. For instance, %PERSON will
# collect PERSONname='John Doe', PERSONbirthdate='01 Jan 00', and
# PERSONspouse='Alice' into a hash table %PERSON such that $PERSON{'spouse'}
# equals 'Alice'. Any default value or environment value will be stored
# under the "" key. If there is an ENVIRONMENT variable of the same name,
# it will be used instead of the default AND the query values. The
# corresponding function is CGIscriptor::CGIparseValueHash()
#
# This method of first declaring your environment and CGI variables
# before being able to use them in the scripts might seem somewhat
# clumsy, but it protects you from inadvertedly printing out the values of
# system environment variables when their names coincide with those used
# in the CGI forms. It also prevents "clients" from supplying CGI
# parameter values for your private variables.
# THIS IS A SECURITY FEATURE!
#
#
# NON-HTML CONTENT TYPES
#
# Normally, CGIscriptor prints the standard "Content-type: text/html\n\n"
# message before anything is printed. This has been extended to include
# plain text (.txt) files, for which the Content-type (MIME type)
# 'text/plain' is printed. In all other respects, text files are treated
# as HTML files (this can be switched off by removing '.txt' from the
# $FilePattern variable) . When the content type should be something else,
# e.g., with multipart files, use the $RawFilePattern (.xmr, see also next
# item). CGIscriptor will not print a Content-type message for this file
# type (which must supply its OWN Content-type message). Raw files must
# still conform to the and tag specifications.
#
#
# NON-HTML FILES
#
# CGIscriptor is intended to process HTML and text files only. You can
# create documents of any mime-type on-the-fly using "raw" text files,
# e.g., with the .xmr extension. However, CGIscriptor will not process
# binary files of any type, e.g., pictures or sounds. Given the sheer
# number of formats, I do not have any intention to do so. However,
# an escape route has been provided. You can construct a genuine raw
# (.xmr) text file that contains the perl code to service any file type
# you want. If the global $BinaryMapFile variable contains the path to
# this file (e.g., /BinaryMapFile.xmr), this file will be called
# whenever an unsupported (non-HTML) file type is requested. The path
# to the requested binary file is stored in $ENV('CGI_BINARY_FILE')
# and can be used like any other CGI-variable. Servicing binary files
# then becomes supplying the correct Content-type (e.g., print
# "Content-type: image/jpeg\n\n";) and reading the file and writing it
# to STDOUT (e.g., using sysread() and syswrite()).
#
#
# THE META TAG
#
# All attributes of a META tag are ignored, except the
# CONTENT='text/ssperl; CGI=" ... " [SRC=" ... "]' attribute. The string
# inside the quotes following the CONTENT= indication (white-space is
# ignored, "" '' `` (){}[]-quote pairs are allowed, plus their \ versions)
# MUST start with any of the CGIscriptor mime-types (e.g.: text/ssperl or
# text/osshell) and a comma or semicolon.
# The quoted string following CGI= contains a white-space separated list
# of declarations of the CGI (and Environment) values and default values
# used when no CGI values are supplied by the query string.
#
# If the default value is a longer string containing special characters,
# possibly spanning several lines, the string must be enclosed in quotes.
# You may use any pair of quotes or brackets from the list '', "", ``, (),
# [], or {} to distinguish default values (or preceded by \, e.g., \(...\)
# is different from (...)). The outermost pair will always be used and any
# other quotes inside the string are considered to be part of the string
# value, e.g.,
#
# $Value = {['this'
# "and" (this)]}
# will result in $Value getting the default value: ['this'
# "and" (this)]
# (NOTE that the newline is part of the default value!).
#
# Internally, for defining and initializing CGI (ENV) values, the META
# and SCRIPT tags use the functions "defineCGIvariable($name, $default)"
# (scalars) and "defineCGIvariableList($name, $default)" (lists).
# These functions can be used inside scripts as
# "CGIscriptor::defineCGIvariable($name, $default)" and
# "CGIscriptor::defineCGIvariableList($name, $default)".
# "CGIscriptor::defineCGIvariableHash($name, $default)".
#
# The CGI attribute will be processed exactly identical when used inside
# the
# tags. This is quite annoying when you want to use large
# HTML templates where you will fill in values.
#
# For this purpose, CGIscriptor will read the neutral
#

# tag (in Cascading Style Sheet manner) Note that
# "varname" has NO '$' before it, it is a bare name.
# Any text between these

tags will
# be assigned to '$varname' as is (e.g., as a literal).
# No processing or interpolation will be performed.
# There is also NO nesting possible. Do NOT nest a
# inside a

! Moreover, DIV tags do
# NOT ensure a block structure in the final rendering
# (i.e., no empty lines).
#
# Note that

# is handled the XML way. No content is processed,
# but varname is defined, and any SRC directives are
# processed.
#
# You can use $varname like any other variable name.
# However, $varname is NOT a CGI variable and will be
# completely internal to your script. There is NO
# interaction between $varname and the outside world.
#
# To interpolate a DIV derived text, you can use:
# $varname =~ s/([\]])/\\\1/g; # Mark ']'-quotes
# $varname = eval("qq[$varname]"); # Interpolate all values
#
# The DIV tags will process IF, UNLESS, CGI and
# SRC attributes. The SRC files will be pre-pended to the
# body text of the tag. SRC blocks are NOT executed.
#
# CONDITIONAL PROCESSING: THE 'IF' AND 'UNLESS' ATTRIBUTES
#
# It is often necessary to include code-blocks that should be executed
# conditionally, e.g., only for certain browsers or operating system.
# Furthermore, quite often sanity and security checks are necessary
# before user (form) data can be processed, e.g., with respect to
# email addresses and filenames.
#
# Checks added to the code are often difficult to find, interpret or
# maintain and in general mess up the code flow. This kind of confussion
# is dangerous.
# Also, for many of the supported "foreign" scripting languages, adding
# these checks is cumbersome or even impossible.
#
# As a uniform method for asserting the correctness of "context", two
# attributes are added to all supported tags: IF and UNLESS.
# They both evaluate their value and block execution when the
# result is (IF) or (UNLESS) in Perl, e.g.,
# UNLESS='$NUMBER \> 100;' blocks execution if $NUMBER <= 100. Note that
# the backslash in the '\>' is removed and only used to differentiate
# this conditional '>' from the tag-closing '>'. For symmetry, the
# backslash in '\
# ...
#
#
# The IF and UNLESS values must be quoted. The same quotes are supported
# as with the other attributes. The SRC attribute is ignored when IF and
# UNLESS block execution.
#
# NOTE: 'IF' and 'UNLESS' always evaluate perl code.
#
#
# THE MAGIC SOURCE ATTRIBUTE (SRC=)
#
# The SRC attribute inside tags accepts a list of filenames and URL's
# separated by "," comma's (or ";" semicolons).
# ALL the variable values defined in the CGI attribute are available
# in @ARGV as if the file or block was executed from the command line,
# in the exact order in which they were declared in the preceding CGI
# attribute.
#
# First, a SRC={}-block will be evaluated as if the code inside the
# block was part of a construct, i.e.,
# "print do { code };'';" or `code` (i.e., SAFEqx('code)).
# Only a single block is evaluated. Note that this is processed less
# efficiently than blocks. Type of evaluation
# depends on the content-type: Perl for text/ssperl and OS shell for
# text/osshell. For other mime types (scripting languages), anything in
# the source block is put in front of the code block "inside" the tag.
#
# Second, executable files (i.e., -x filename != 0) are evaluated as:
# print `filename \'$ARGV[0]\' \'$ARGV[1]\' ...`
# That is, you can actually call executables savely from the SRC tag.
#
# Third, text files that match the file pattern, used by CGIscriptor to
# check whether files should be processed ($FilePattern), are
# processed in-line (i.e., recursively) by CGIscriptor as if the code
# was inserted in the original source file. Recursions, i.e., calling
# a file inside itself, are blocked. If you need them, you have to code
# them explicitely using "main::ProcessFile($file_path)".
#
# Fourth, Perl text files (i.e., -T filename != 0) are evaluated as:
# "do FileName;'';".
#
# Last, URL's (i.e., starting with 'HTTP://', 'FTP://', 'GOPHER://',
# 'TELNET://', 'WHOIS://' etc.) are loaded
# and printed. The loading and handling of and document header
# is done by a command generated by main::GET_URL($URL [, 0]). You can enter your
# own code (default is curl, wget, or snarf and some post-processing to add a tag).
#
# There are two pseudo-file names: PREFIX and POSTFIX. These implement
# a switch from prefixing the SRC code/files (PREFIX, default) before the
# content of the tag to appending the code after the content of the tag
# (POSTFIX). The switches are done in the order in which the PREFIX and
# POSTFIX labels are encountered. You can mix PREFIX and POSTFIX labels
# in any order with the SRC files. Note that the ORDER of file execution
# is determined for prefixed and postfixed files seperately.
#
# File paths can be preceded by the URL protocol prefix "file://". This
# is simply STRIPPED from the name.
#
# Example:
# The request
# "http://cgi-bin/Action_Forms.pl/Statistics/Sign_Test.html?positive=8&negative=22
# will result in printing "${SS_PUB}/Statistics/Sign_Test.html"
# With QUERY_STRING = "positive=8&negative=22"
#
# on encountering the lines:
#
#

"
#
# This line will be processed as:
# "`${SS_SCRIPT}/Statistics/SignTest.pl '8' '22'`

"
#
# In which "${SS_SCRIPT}/Statistics/SignTest.pl" is an executable script,
# This line will end up printed as:
# "p <= 0.0161

"
#
# Note that the META tag itself will never be printed, and is invisible to
# the outside world.
#
# The SRC files in a DIV tag will be added (pre-pended) to the body
# of the

";
#
return 1;
};
#
# ListDocs(Pattern [,ListType])
#
# usage:
#
#
# This subroutine is very usefull to manage collections of independent
# documents. The resulting list will display the tree-like directory
# structure. If this routine is too slow for online use, you can
# store the result and use a link to that stored file.
#
# List HTML and Text files with title and first header (HTML)
# or filename and first meaningfull line (general text files).
# The listing starts at the ServerRoot directory. Directories are
# listed recursively.
#
# You can change the list type (default is dl).
# e.g.,
#

$Caption\n" if $ListType eq "dl";
$TitleFound = 0;
$Caption = "";
close TextFile;
next File;
};
};
# Print Closing List Marker
print "$ListType>\n";
""; # Empty return value
};
#
# HTMLdocTree(Pattern [,ListType])
#
# usage:
#
#
# The following subroutine is very usefull for checking large document
# trees. Starting from the root (s), it reads all files and prints out
# a nested list of links to all attached files. Non-existing or misplaced
# files are flagged. This is quite a file-i/o intensive routine
# so you would not like it to be accessible to everyone. If you want to
# use the result, save the whole resulting page to disk and use a link
# to this file.
#
# HTMLdocTree takes an HTML file or file pattern and constructs nested lists
# with links to *local* files (i.e., only links to the local server are
# followed). The list entries are the document titles.
# If the list type is

, the first

header is used too.
# For each file matching the pattern, a list is made recursively of all
# HTML documents that are linked from it and are stored in the same directory
# or a sub-directory. Warnings are given for missing files.
# The listing starts for the ServerRoot directory.
# You can change the default list type