# # Copyright 2003, Dick Munroe (munroe@csworks.com), All Rights Reserved # # This program, comes with ABSOLUTELY NO WARRANTY. # This is free software, and you are welcome to redistribute it # under the conditions of the GNU GENERAL PUBLIC LICENSE, version 2. # # Modularian provides a general interface for browsing the contents of # OpenVMS libraries of all types. It does not replace CGIs like # Conan and helpgate which serve different purposes. # # Modularian can run under all CGI environments provided by WASD, i.e., # standard CGI, CGI Plus, and Perl RTE without modification. # # Since libraries (and, in general, things stored in libraries) are # structured, they are returned to the user as ZIP files when # downloaded, preserving OpenVMS file attributes. All file # contents can be displayed in addition to downloaded. # ANALYZE/OBJECT is used to "display" object files inside object # libraries. Text is simply displayed but line numbers are added # to allow easy location of individial lines later on. # # This module requires that the ZIP command be available to it. You # can define this symbol in a HTTPD login command file and point # HTTPD$LOGIN to it. # # It requires access to a scratch directory which must be writeable # by the script persona (HTTP$NOBODY by default). # # It also depends on HTML::Entities and HTML::Table which are # available for download from www.cpan.org. Everything else should # be in your OpenVMS perl distribution. # # Last, but not least, I'm looking for work. My resume is available # from: # # http://www.csworks.com/resume # # my CV (more detailed, but too long for general distribution) is # available from: # # http://www.csworks.com/cv # # Take a look and if you see a match for something you need done, # drop me a line. # # Revision History: # # 1.1 Dick Munroe (munroe@csworks.com) 12-Apr-2003 # Make sure all listing tables use the "same" amount of # room for their columns. # Put a pointer to the source of the package in the # header. # # 1.2 Dick Munroe (munroe@csworks.com) 12-Apr-2003 # Use the right librarian to get modules. # # 1.3 Dick Munroe (munroe@csworks.com) 13-Apr-2003 # Make it run under the OSU DECnet environment. # Which it does but the download functions don't # work. This is probably due to to differences # in how writing to sys$output is handled. # # 1.4 Dick Munroe (munroe@csworks.com) 13-Apr-2003 # And now the download functions can be made to work. # However it is tricky and requires that the script # server that invokes modularian NOT to use # prior to invoking modularian. The output of the # script must be in binary mode. This, in turn, # requires that we tweak the internal state of # CGI.pm at run time to get the generation of # headers right, after which all new lines issued # appear to be lost when printed via print and # printf statements so we have to rely exclusively # on things like
statements and tables for # proper formatting. # # 1.4.1 Dick Munroe (munroe@csworks.com) 14-Apr-2003 # Add documentation, in POD format, below. Use # perldoc format so everything goes in one place. # Make the test for CGIplus a little more robust # (suggestion by Mark Daniels of WASD fame). # # 1.4.2 Dick Munroe (munroe@csworks.com) 14-Apr-2003 # When a $ began a module name, the logic that built the tables # for display screwed up. The current character needs to be # quoted to keep the logic straight. # # 1.4.3 Dick Munroe (munroe@csworks.com) 17-Apr-2003 # Catch the case of trying to execute CGIplus in an RTE. # # 1.5 Dick Munroe (munroe@csworks.com) 10-May-2003 # Use VMS::Librarian if a good enough version exists. # Make sure all versions of the temporary files get # deleted. # # 1.5.1 Dick Munroe (munroe@csworks.com) 14-May-2003 # Get CGIplus from either the WASD root or if it's # been installed, @INC. # my $VERSION = "1.5.1" ; # # The number of times this cgi can be called in a cgiPlus environment # before exiting automatically. This is insurance against leaks in the # cgi or in the perl environment. # # The cgi can be force to terminate before this time by invoking it with # a query parameter of eoj, e.g.: # # http://your.web.server/cgiplus-bin/modularian.pl/path/to/your/library?eoj # my $exitAfter = 500 ; # # The scratch directory used to extract modules and store zip files # before shipping them to the user. # my $theScratchDirectory = "HT_ROOT:[SCRATCH]" ; # # The URL to the graphic image use to display the "view" button for # a module. # my $theViewButtonURL = "/httpd/-/text.gif" ; use strict ; use 5.6.1 ; # # Some things (notably the translated path information) will be different # in the OSU environment. # my $isOSUServer = ($ENV{'SERVER_SOFTWARE'} =~ /OSU/) ; # # To make this work, any script must NOT depend on things in CGIplus # that would break if not running in a CGIplus environment. Since my # routines always use the CGI interface for file transfers and the like, # I can test for this and everything will work just fine. # my $useCGIplus = ($ENV{'CGIPLUSEOF'} ne undef) && ($ENV{'SCRIPT_RTE'} eq undef) ; # # While CGIplus can't be used under some environments, some of the # interfaces it defines are handy so I require CGIplus at all times. # eval { require CGIplus ; } || eval { # # Put the WASD source tree PERL code on the search list and try again. # unshift @INC,"HT_ROOT:[SRC.PERL]" ; require CGIplus ; } || die "Can't find CGIplus.pm" ; # # HTML::Entities and HTML::Tables are available from www.cpan.org # and install quite easily on OpenVMS perl. # use FileHandle ; use File::Basename ; use HTML::Entities ; use HTML::Table ; require VMS::Filespec if ($isOSUServer) ; use VMS::Stdio ; # # VMS::Librarian is currently available from # # http://www.csworks.com/download/librarian.html # # and will, shortly I hope, be available from CPAN and included in # the next release of Perl. # use VMS::Librarian qw(VLIB_READ) ; my $isLibrarian = ($VMS::Librarian::VERSION >= 1.06) ; # # Right now OSU doesn't ship with an image suitable for inclusion # in the view button, so the only thing that will display is the # [view] alternate description. # $theViewButtonURL = "" if ($isOSUServer) ; if ($useCGIplus) { # # If you cannot put a path restriction of the form: # # set /cgi-bin/modularian.pl/* cgiprefix= # set /cgiplus-bin/modularian.pl/* cgiprefix= # # the you will have to uncomment the following line. If you # don't, then the CGI interface won't be able to find any # CGI variables. # #CGIplus::stripWWW(1); CGIplus::process(\&modularian); } else { # # See the comment above, but this time, it's absolutely necessary # to have put the path restrictions in place since the routine # isn't running in the CGIplus environment. # modularian() ; } ; sub modularian { # # This is important. Because the CGIplus environment asserts the # GATEWAY_INTERFACE environment when it RUNS and the CGI checks # the GATEWATE_INTERFACE when it LOADS, CGI.pm must be loaded within # the procedure running under CGIplus or it will believe that it # is using a vanilla CGI interface and it won't reset its internal # state properly. It works by checking for the existance of the # CGI object creation operator (new) and if it is not present, # requiring the module. # # Properly speaking this is most likely a bug in the interaction # between the CGI and CGIplus modules, but this is a decent # work-around (it works and its cheap). # require CGI if (!defined(&CGI::new)) ; # # This is important. If you are running the OSU server, CGIs which # produce binary output MUST NOT BE RUN IN RECORD MODE (you must NOT # send from the script server). If you do it will # put spurious CR/LF pairs into your binary output giving you MAJOR # problems. Since CGI.pm assumes that you're running in record # mode (and simply emits a \n) then the headers don't happen as far # as the OSU server is concerned. # $CGI::CRLF = "\r\n" if ($isOSUServer) ; # # Provide access to all the features of the perl CGI interface. # my $theCGI = new CGI ; my $theAction = $theCGI->param('action') ; my $theArchitecture = $theCGI->param('architecture') ; my $theLibrary = $ENV{'PATH_TRANSLATED'} ; my $theLibraryName = basename($theLibrary) ; my $theLibraryPath = $ENV{'PATH_INFO'} ; my $theModule = $theCGI->param('module') ; my $theModules ; my $theScriptName = $ENV{'SCRIPT_NAME'} ; # # Convert the translate path into VMS format if necessary. # $theLibrary = VMS::Filespec::vmsify($theLibrary) if ($isOSUServer) ; # # Make sure nothing can attack through the parameters. # $theAction =~ s/^([\$_\-A-Za-z0-9]*).*/$1/ ; $theArchitecture =~ s/^([\$_\-A-Za-z0-9]*).*/$1/ ; $theModule =~ s/^([\$_\-A-Za-z0-9]*).*/$1/ ; if ((!defined($theArchitecture)) || ($theArchitecture eq "")) { $theArchitecture = "ALPHA" ; } my $theLibraryType ; my @theTemp ; @theTemp = fileparse($theLibrary,'\..*?') ; $theLibraryType = uc($theTemp[2]) ; if ($theAction eq "library") { # # Return the library itself as a zip file. # my $theResult ; my $theTmpnam = VMS::Stdio::tmpnam() ; my $theZipName = $theScratchDirectory . $theTmpnam . ".zip" ; `zip "-Vj" $theZipName $theLibrary` ; CGIplus::fileStream($theZipName, "application/zip") ; while (unlink($theZipName)) {} ; } elsif ($theAction eq "download") { # # Return a module from the library to the user as a zip file. # my $theExtension = $theLibraryType ; $theExtension =~ s/MLB/MAR/ ; $theExtension =~ s/OLB/OBJ/ ; $theExtension =~ s/TLB/TXT/ ; $theExtension =~ s/HLB/HLP/ ; $theExtension = "." if $theExtension eq $theLibraryType ; my $theResult ; my $theTmpnam = VMS::Stdio::tmpnam() ; my $theTemporaryName = $theScratchDirectory . $theModule . $theExtension ; my $theZipName = $theScratchDirectory . $theTmpnam . ".zip" ; if ($isLibrarian) { my $theObject = VMS::Librarian::factory(LIBNAME => $theLibrary, FUNCTION => VLIB_READ) ; my @theModule = $theObject->get_module(KEY => $theModule) ; my $theStatus = $theObject->write_module(FILENAME => $theTemporaryName, DATA => \@theModule) ; } else { `library/extract=$theModule/output=$theTemporaryName/$theArchitecture $theLibrary` ; } `zip "-Vj" $theZipName $theTemporaryName` ; CGIplus::fileStream($theZipName, "application/zip") ; while (unlink($theTemporaryName)) {} ; while (unlink($theZipName)) {} ; } elsif ($theAction eq "view") { # # View a module. The only type for which views are allowed are # "text" files. # my $theTitle = "Library: $theLibraryName" ; $theTitle .= " Module: $theModule" if ($theModule ne "") ; $theTitle .= " Usage: " . CGIplus::usageCount() if (CGIplus::isCGIplus()) ; print $theCGI->header(-expires=>"Expires: Fri, 13 Jan 1978 14:00:00 GMT", -pragma=>"no-cache", -cache_control=>"no-cache") ; print $theCGI->start_html($theTitle) ; my $theTable = new HTML::Table(-rows=>4, -cols=>3, -width=>'100%', -bgcolor=>'CornflowerBlue') ; $theTable->setColAlign(1, 'LEFT') ; $theTable->setColAlign(2, 'CENTER') ; $theTable->setColAlign(3, 'RIGHT') ; $theTable->setColWidth(1, '33%') ; $theTable->setColWidth(2, '34%') ; $theTable->setColWidth(3, '33%') ; $theTable->setRowHeight(1, 6) ; $theTable->setRowVAlign(2, 'CENTER') ; $theTable->setRowFormat(2, '', '') ; $theTable->setRowVAlign(2, 'CENTER') ; $theTable->setRowHeight(4, 6) ; $theTable->setCellFormat(1,1,'', '') ; $theTable->setCellFormat(1,3,'', '') ; $theTable->setCell(1,1,"Usage: " . CGIplus::usageCount()) if (CGIplus::isCGIplus()) ; $theTable->setCell(1,3,"Modularian $VERSION") ; $theTable->setCell(2,1,"Module: $theModule") ; $theTable->setCell(2,2,$theLibraryName) ; $theTable->setCell(3,1,"") ; $theTable->setCell(3,2,"") ; $theTable->print() ; print "
\n" ;
	if ($theLibraryType eq ".OLB")
	{
	    my $theTmpnam = VMS::Stdio::tmpnam() ;
	    my $theTemporaryName = $theScratchDirectory . $theModule . $theTmpnam ;

	    if ($isLibrarian) 
	    {
		my $theObject = VMS::Librarian::factory(LIBNAME => $theLibrary, FUNCTION => VLIB_READ) ;

		my @theModule = $theObject->get_module(KEY => $theModule) ;

		my $theStatus = $theObject->write_module(FILENAME => $theTemporaryName, DATA => \@theModule) ;
	    }
	    else
	    {
		`library/extract=$theModule/output=$theTemporaryName/$theArchitecture $theLibrary` ;
	    }

	    my $theString = join "",`analyze/object/output=sys\$output $theTemporaryName` ;

	    $theString =~ s/\f.*?\n\n//sg ;
	    $theString =~ s!\n+ANALYZE/OBJECT/OUTPUT.*?$!! ;

	    $theString = encode_entities($theString) ;

	    $theString =~ s!\n!
!go ; print $theString ; while (unlink($theTemporaryName)) {} ; } else { my @theLines ; if ($isLibrarian) { my $theObject = VMS::Librarian::factory(LIBNAME => $theLibrary, FUNCTION => VLIB_READ) ; @theLines = $theObject->get_module(KEY => $theModule) ; } else { @theLines = `library/extract=$theModule/output=sys\$output: $theLibrary` ; } my $theLineCounter ; foreach (@theLines) { $_ =~ s/\n//g ; printf "%04d %s
", ++$theLineCounter, encode_entities($_) ; } } ; print "
\n" ; undef $theTable ; $theTable = new HTML::Table(-rows=>4, -cols=>3, -width=>'100%', -bgcolor=>'CornflowerBlue') ; $theTable->setColAlign(1, 'LEFT') ; $theTable->setColAlign(2, 'CENTER') ; $theTable->setColAlign(3, 'RIGHT') ; $theTable->setColWidth(1, '33%') ; $theTable->setColWidth(2, '34%') ; $theTable->setColWidth(3, '33%') ; $theTable->setRowHeight(1, 6) ; $theTable->setRowVAlign(2, 'CENTER') ; $theTable->setRowVAlign(3, 'CENTER') ; $theTable->setRowFormat(3, '', '') ; $theTable->setRowHeight(4, 6) ; $theTable->setCell(2,1,"") ; $theTable->setCell(2,2,"") ; $theTable->setCell(3,1,"Module: $theModule") ; $theTable->setCell(3,2,$theLibraryName) ; $theTable->setCellFormat(4,1,'', '') ; $theTable->setCellFormat(4,3,'', '') ; $theTable->setCell(4,1,"Usage: " . CGIplus::usageCount()) if (CGIplus::isCGIplus()) ; $theTable->setCell(4,3,"Modularian $VERSION") ; $theTable->print() ; print $theCGI->end_html() ; } else { # # Present the library and it's named modules. Text libraries # allow the user to view the contents interactively as well # as download them. # my $theArchitecture ; my @theModules ; if ($isLibrarian) { print $theLibrary ; my $theObject = VMS::Librarian::factory(LIBNAME => $theLibrary, FUNCTION => VLIB_READ) ; @theModules = $theObject->get_index() ; my $theHeader = $theObject->get_header() ; undef $theObject ; $theArchitecture = (($theHeader->{LBRVER} =~ /^Librarian/) ? "ALPHA" : "VAX") ; } else { $theModules = join "",`library/list $theLibrary` ; $theModules =~ s/^(.*)?\n\n//s ; $theArchitecture = (($1 =~ /Creator:\s+Librarian/) ? "ALPHA" : "VAX") ; @theModules = split "\n",$theModules ; } my $theTitle = "Library: $theLibraryName" ; $theTitle .= " Usage: " . CGIplus::usageCount() if (CGIplus::isCGIplus()) ; print $theCGI->header(-expires=>"Expires: Fri, 13 Jan 1978 14:00:00 GMT", -pragma=>"no-cache", -cache_control=>"no-cache") ; print $theCGI->start_html($theTitle) ; my $theTable = new HTML::Table(-rows=>4, -cols=>3, -width=>'100%', -bgcolor=>'CornflowerBlue') ; $theTable->setColAlign(1, 'LEFT') ; $theTable->setColAlign(2, 'CENTER') ; $theTable->setColAlign(3, 'RIGHT') ; $theTable->setColWidth(1, '33%') ; $theTable->setColWidth(2, '34%') ; $theTable->setColWidth(3, '33%') ; $theTable->setRowHeight(1, 6) ; $theTable->setRowVAlign(2, 'CENTER') ; $theTable->setRowFormat(2, '', '') ; $theTable->setRowVAlign(2, 'CENTER') ; $theTable->setRowHeight(4, 6) ; $theTable->setCellFormat(1,1,'', '') ; $theTable->setCellFormat(1,3,'', '') ; $theTable->setCell(1,1,"Usage: " . CGIplus::usageCount()) if (CGIplus::isCGIplus()) ; $theTable->setCell(1,3,"Modularian $VERSION") ; $theTable->setCell(2,2,$theLibraryName) ; $theTable->setCell(3,2,"") ; $theTable->print() ; my $theModuleTable = undef ; my $theCurrentLetter = "\n" ; my $theCurrentLetterCounter = 0 ; foreach (@theModules) { $theCurrentLetterCounter++ ; if ($_ !~ m/^\Q$theCurrentLetter\E/) { if (defined($theModuleTable)) { $theModuleTable->print() ; undef $theModuleTable ; } $theCurrentLetter = substr $_,0,1 ; $theCurrentLetterCounter = 0 ; $theModuleTable = new HTML::Table(-rows=>1,-cols=>4,-width=>'100%') ; for (my $i = 1; $i <= 4; $i++) { $theModuleTable->setColWidth($i, '25%') ; $theModuleTable->setCell(1,$i,' ') ; } } elsif (($theCurrentLetterCounter % 4) == 0) { $theCurrentLetterCounter = 0 ; $theModuleTable->addRow((" ", " ", " ", " ")) ; } my $theCellContents = new HTML::Table(1,2) ; $theCellContents->setRowVAlign(1,'CENTER') ; my $theString = "" ; $theString .= "\n" ; $theString .= "\"[view]\"\n" ; $theString .= "\n" ; $theCellContents->setCell(1,1,$theString) ; $theString = "" ; $theString .= "\n" ; $theString .= $_,"\n" ; $theString .= "\n" ; $theCellContents->setCell(1,2,$theString) ; $theModuleTable->setCell($theModuleTable->getTableRows(), $theCurrentLetterCounter+1, $theCellContents->getTable()) ; } if (defined($theModuleTable)) { $theModuleTable->print() ; } undef $theModuleTable ; my $theTable = new HTML::Table(-rows=>4, -cols=>3, -width=>'100%', -bgcolor=>'CornflowerBlue') ; $theTable->setColAlign(1, 'LEFT') ; $theTable->setColAlign(2, 'CENTER') ; $theTable->setColAlign(3, 'RIGHT') ; $theTable->setColWidth(1, '33%') ; $theTable->setColWidth(2, '34%') ; $theTable->setColWidth(3, '33%') ; $theTable->setRowHeight(1, 6) ; $theTable->setRowVAlign(2, 'CENTER') ; $theTable->setRowVAlign(3, 'CENTER') ; $theTable->setRowFormat(3, '', '') ; $theTable->setRowHeight(4, 6) ; $theTable->setCell(2,2,"") ; $theTable->setCell(3,2,$theLibraryName) ; $theTable->setCellFormat(4,1,'', '') ; $theTable->setCellFormat(4,3,'', '') ; $theTable->setCell(4,1,"Usage: " . CGIplus::usageCount()) if (CGIplus::isCGIplus()) ; $theTable->setCell(4,3,"Modularian $VERSION") ; $theTable->print() ; print $theCGI->end_html() ; } # # While nothing says there ARE leaks in the perl environment or in this # code, we stop every exitAfter invocations. # if ((CGIplus::usageCount() >= $exitAfter) || ($ENV{'QUERY_STRING'} eq "eoj")) { exit ; } } ; exit() ; =pod =head1 Name Modularian - Browse OpenVMS/VAX and OpenVMS/AXP libraries. =head1 Description Modularian allows web browsers to look at and download the contents of all types of OpenVMS libraries or the libraries themselves. Modularian runs equally well under all WASD CGI environments (cgi, CGIplus, and PerlRTE) as well as under the OSU DECnet CGI environment (with a few caveats, see the installation instructions, below) without modification of Modularian. The interface that Modularian presents is a "directory" of the contents of the library. Modules may be viewed (object modules are displayed as if ANALYZE/OBJECT had been run on the specified module) by pressing the view icon (or text) to the left of the module name. Modules may be downloaded by pressing the name of the module. In order to preserve OpenVMS file attributes, the ZIP utility is used and the modules placed in ZIP archives, preserving the file attributes, before downloading. Of course, the receiver must have UNZIP on their system in order to extract the requested module. =head1 System Requirements The following items are required on the server providing access to Modularian: =over =item * Modularian.pl http://www.csworks.com/download/modularian.pl =item * ZIP ftp://ftp.info-zip.org/pub/infozip/VMS Note that zip is only required if the user wishes to actually use the downloading capabilities of Modularian. =item * Either the WASD web server, version 8.1 or higher http://wasd.vsm.com.au/wasd/ or the OSU DecThreads web server, version 3.4 or higher http://kcgl1.eng.ohio-state.edu/www/doc/serverinfo.html =item * Perl 5.6.1 or higher http://www.perl.org/ =item * CGIplus.pm from the WASD web server distribution. This is used to download files and is used primarily for convenience. Should this requirement prove to be onerous, Modularian will be modified in a later release to eliminate it. The copy of CGIplus.pm in production at www.csworks.com is available at: http://www.csworks.com/download/CGIplus.pm The latest and greatest is always available as part of the current WASD distribution and if problems develop should be downloaded from there (see above). =item * The HTML::Entities and HTML::Table Perl modules from CPAN http://www.cpan.org/ and any modules upon which they, in turn, depend. HTML::Entities is part of the HTML::Parser package. The version of these modules in production at www.csworks.com are available at: http://www.csworks.com/download/html-parser-3_13.zip http://www.csworks.com/download/html-table-1_17.zip Should problems develop, you should download and install the latest versions of these modules from CPAN before contacting the author for support. =item * (Optional) The VMS::Librarian version 1.06 or higher. This is currently only avilable from: http://www.csworks.com/download/librarian.html Hopefully it will be included in a later release of Perl. =item * Since CGI.pm is used by Modularian, the "standard" behavior of WASD and OSU for defining CGI environment variables (prefixing them with "WWW_") must be disabled. An example of this is shown below in the discussion of the installation of Modularian. =back At the receiver's end, UNZIP is needed to extract modules from their ZIP file wrappers. =head1 Installation =head2 WASD =head3 Server Side =over =item 1. Install Perl, if not already installed. =item 2. Install the necessary additional Perl modules (HTML::Entities and HTML::Table), if not already installed. =item 3. Install ZIP, if not already installed. =item 4. Install the WASD web server, if not already installed. =item 5. Start the WASD web server. =item 6. Copy modularian.pl to CGI-BIN:[000000]. =item 7. Enable access to the appropriate libraries in the mapping rules of your server. This topic is actually relatively complex due to the flexibility of WASD. At www.csworks.com, access to modularian is enabled through the x-script capability available when defining MIME types. Here are the relevant lines from the MIME type configuration: [AddType] .MLB application/x-script /modularian VMS MACRO library .OLB application/x-script /modularian VMS object library Then in the mapping configuration at www.csworks.com: set /cgi-bin/modularian.pl/* cgiprefix= set /cgiplus-bin/modularian.pl/* cgiprefix= script+ /modularian* /cgi-bin/modularian.pl* The set is necessary to keep WASD from prefixing the CGI environment variables with "WWW_" by default. At www.csworks.com access to Modularian is provided both through the standard CGI paths and the CGIplus paths. The CGI path is used for testing and the CGIplus path for production work. Mark Daniels provided the following suggestion for providing access: Mapping rules can provide some 'browsing' capability. For instance you can provide a URL such as http://the.server.name/sys\$common/syslib/*.mlb and using a mapping rule such as if (pass:1) redirect /sys$common/syslib/*.mlb \ /cgiplus-bin/modularian.pl/sys$common/syslib/*.mlb allows the selection of a file from the directory listing activating modularian and presto! There are a number of potential uses this sort of functionality can be applied to. Note that whatever method is used to access Modularian, you I suppress the addtion of "WWW_" to the CGI environment variables through use of the set as discussed above. =item 8. Restart WASD so that the new configuration information is being used. =back =head3 Client Side =over =item 1. Install UNZIP. =back =head2 OSU The information here is much sketchier as OSU is not the primary web server in use at Cottage Software Works. If anybody has additional information and/or suggestions, feel free to forward them to the author for inclusion in later versions of Modularian. =head3 Server Side =over =item 1. Install Perl, if not already installed. =item 2. Install the necessary additional Perl modules (HTML::Entities and HTML::Table), if not already installed. =item 3. Install ZIP, if not already installed. =item 4. Install the OSU web server, if not already installed. =item 5. Start the OSU web server. =item 6. Copy modularian.pl to the CGI directory (at csworks.com this is the directory referred to when accessing CGIs stored in /htbin/). =item 7. Edit WWWEXEC.COM and in the section beginning with the label "perl_script:" remove the assertion of DNETRECMODE: $ perl_script: $ tfile = "sys$scratch:perlcgi_" + f$string(f$getjpi("0","PID")) + ".tmp" $! write_net "" Note that if you are already using Perl CGIs at your site this will prevent them from working properly. The issue is discussed more or less fully in the source of Modularian, but the bottom line is that OSU DECnet based CGIs cannot successfully transmit binary data to clients in DNETRECMODE. In a production environment, you should probably use special extensions (such as ".CGI-BIN") or serve Modularian and other CGIs sending binary data out of a special directory and check for this information in WWWEXEC.COM and assert DNETRECMODE appropriately. =back =head3 Client Side =over =item 1. Install UNZIP. =back =head1 Configuring Modularian The Modularian CGI itself can be configured in small ways by editing the source code. There are several variables that affect the running and the display of Modularian. =over =item B<$exitAfter> Default: 500 When running in CGIplus, this controls the number of executions of Modularian before the CGI voluntarily exits. While I don't believe there are any leaks in Perl, the CGIplus environment, or Modularian this protects against this occurance. =item B<$theScratchDirectory> Default: HT_ROOT:[SCRATCH] A scratch directory, writeable by the CGI, in which temporary files can be constructed. =item B<$theViewButtonURL> Default: "/httpd/-/text.gif" (WASD), "" (OSU) The graphic to be displayed for the "view the source" button of the Modularian library display. =back =head1 Author Modularian was written by Dick Munroe (munroe@csworks.com). Any support questions or fixes should be sent to me at this address. On another note, I'm looking for work (contract or permanent). My resume is available at: http://www.csworks.com/resume my CV (much more detailed, but too long for general distribution) is available at: http://www.csworks.com/cv I do a lot more than hack the web and Perl so take a look and if you think there's a match, drop me a note and let us see if we can't work something out. =cut