=0A=
#=0A=
# Based on:=0A=
# * Bill Fenners cvsweb.cgi revision 1.28 available from:=0A=
# http://www.FreeBSD.org/cgi/cvsweb.cgi/www/en/cgi/cvsweb.cgi=0A=
#=0A=
# Copyright (c) 1996-1998 Bill Fenner=0A=
# (c) 1998-1999 Henner Zeller=0A=
# (c) 1999 Henrik Nordstr=F6m=0A=
# All rights reserved.=0A=
#=0A=
# Redistribution and use in source and binary forms, with or without=0A=
# modification, are permitted provided that the following conditions=0A=
# are met:=0A=
# 1. Redistributions of source code must retain the above copyright=0A=
# notice, this list of conditions and the following disclaimer.=0A=
# 2. Redistributions in binary form must reproduce the above copyright=0A=
# notice, this list of conditions and the following disclaimer in the=0A=
# documentation and/or other materials provided with the distribution.=0A=
#=0A=
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND=0A=
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE=0A=
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR =
PURPOSE=0A=
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE=0A=
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR =
CONSEQUENTIAL=0A=
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS=0A=
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)=0A=
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, =
STRICT=0A=
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY =
WAY=0A=
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF=0A=
# SUCH DAMAGE.=0A=
#=0A=
# $Id: cvsweb.cgi,v 1.112 2001/07/24 13:03:16 hzeller Exp $=0A=
#=0A=
###=0A=
require 5.000;=0A=
=0A=
use strict;=0A=
=0A=
use vars qw (=0A=
$config $allow_version_select $verbose=0A=
%CVSROOT %CVSROOTdescr %MIRRORS %DEFAULTVALUE %ICONS %MTYPES=0A=
%alltags @tabcolors %fileinfo %tags @branchnames %nameprinted=0A=
%symrev %revsym @allrevisions %date %author @revdisplayorder=0A=
@revisions %state %difflines %log %branchpoint @revorder=0A=
$checkoutMagic $doCheckout $scriptname $scriptwhere=0A=
$where $Browser $nofilelinks $maycompress @stickyvars=0A=
%input $query $barequery $sortby $bydate $byrev $byauthor=0A=
$bylog $byfile $hr_default $logsort $cvstree $cvsroot=0A=
$mimetype $defaultTextPlain $defaultViewable $allow_compress=0A=
$GZIPBIN $backicon $diricon $fileicon $fullname $newname=0A=
$cvstreedefault $body_tag $logo $defaulttitle $address=0A=
$backcolor $long_intro $short_instruction $shortLogLen=0A=
$show_author $dirtable $tablepadding $columnHeaderColorDefault=0A=
$columnHeaderColorSorted $hr_breakable $hr_funout $hr_ignwhite=0A=
$hr_ignkeysubst $diffcolorHeading $diffcolorEmpty $diffcolorRemove=0A=
$diffcolorChange $diffcolorAdd $diffcolorDarkChange $difffontface=0A=
$difffontsize $inputTextSize $mime_types $allow_annotate=0A=
$allow_markup $use_java_script $open_extern_window=0A=
$extern_window_width $extern_window_height $edit_option_form=0A=
$checkout_magic $show_subdir_lastmod $show_log_in_markup $v=0A=
$navigationHeaderColor $tableBorderColor $markupLogColor=0A=
$tabstop $state $annTable $sel $curbranch @HideModules @DissallowRead=0A=
$module $use_descriptions %descriptions @mytz $dwhere $moddate=0A=
$use_moddate $has_zlib $gzip_open=0A=
);=0A=
=0A=
##### prototype declarations ########=0A=
sub printDiffSelect($);=0A=
sub findLastModifiedSubdirs(@);=0A=
sub htmlify($);=0A=
sub spacedHtmlText($);=0A=
sub link($$);=0A=
sub revcmp($$);=0A=
sub fatal($$);=0A=
sub redirect($);=0A=
sub safeglob($);=0A=
sub getMimeTypeFromSuffix($);=0A=
sub doAnnotate ($$);=0A=
sub doCheckout($$);=0A=
sub cvswebMarkup($$$);=0A=
sub viewable($);=0A=
sub doDiff($$$$$$);=0A=
sub getDirLogs($$@);=0A=
sub readLog($;$);=0A=
sub printLog($;$);=0A=
sub doLog($);=0A=
sub flush_diff_rows ($$$$);=0A=
sub human_readable_diff($);=0A=
sub navigateHeader ($$$$$);=0A=
sub plural_write ($$);=0A=
sub readableTime ($$);=0A=
sub clickablePath($$);=0A=
sub chooseCVSRoot();=0A=
sub chooseMirror();=0A=
sub fileSortCmp();=0A=
sub download_url($$$);=0A=
sub download_link($$$$);=0A=
sub toggleQuery($$);=0A=
sub urlencode($);=0A=
sub http_header(;$);=0A=
sub html_header($);=0A=
sub html_footer();=0A=
sub link_tags($);=0A=
sub forbidden_module($);=0A=
sub forbidden_file($);=0A=
sub checkForbidden($@);=0A=
sub gzipclose();=0A=
sub MAGIC1();=0A=
sub MAGIC2();=0A=
sub OSCODE();=0A=
=0A=
##### Start of Configuration Area ########=0A=
# =3D=3D EDIT this =3D=3D =0A=
# User configuration is stored in=0A=
$config =3D $ENV{'CVSWEB_CONFIG'} || '/opt/apachessl/conf/cvsweb.conf';=0A=
=0A=
# =3D=3D Configuration defaults =3D=3D=0A=
# Defaults for configuration variables that shouldn't need=0A=
# to be configured..=0A=
$allow_version_select =3D 1;=0A=
=0A=
##### End of Configuration Area ########=0A=
=0A=
######## Configuration variables #########=0A=
# These are defined to allow checking with perl -cw=0A=
%CVSROOT =3D %MIRRORS =3D %DEFAULTVALUE =3D %ICONS =3D %MTYPES =3D=0A=
%tags =3D %alltags =3D @tabcolors =3D %fileinfo =3D ();=0A=
$cvstreedefault =3D $body_tag =3D $logo =3D $defaulttitle =3D $address =3D=0A=
$backcolor =3D $long_intro =3D $short_instruction =3D $shortLogLen =3D=0A=
$show_author =3D $dirtable =3D $tablepadding =3D =
$columnHeaderColorDefault =3D=0A=
$columnHeaderColorSorted =3D $hr_breakable =3D $hr_funout =3D =
$hr_ignwhite =3D=0A=
$hr_ignkeysubst =3D $diffcolorHeading =3D $diffcolorEmpty =3D =
$diffcolorRemove =3D=0A=
$diffcolorChange =3D $diffcolorAdd =3D $diffcolorDarkChange =3D =
$difffontface =3D=0A=
$difffontsize =3D $inputTextSize =3D $mime_types =3D $allow_annotate =3D=0A=
$allow_markup =3D $use_java_script =3D $open_extern_window =3D=0A=
$extern_window_width =3D $extern_window_height =3D $edit_option_form =3D=0A=
$checkout_magic =3D $show_subdir_lastmod =3D $show_log_in_markup =3D $v =3D=0A=
$navigationHeaderColor =3D $tableBorderColor =3D $markupLogColor =3D =0A=
$tabstop =3D $use_moddate =3D $moddate =3D $gzip_open =3D undef;=0A=
=0A=
##### End of configuration variables #####=0A=
=0A=
use Time::Local;=0A=
use IPC::Open2;=0A=
=0A=
# Check if the zlib C library interface is installed, and if yes=0A=
# we can avoid using the extra gzip process.=0A=
eval {=0A=
require Compress::Zlib;=0A=
};=0A=
$has_zlib =3D !$@;=0A=
=0A=
$verbose =3D $v;=0A=
$checkoutMagic =3D "~checkout~";=0A=
$where =3D defined($ENV{'PATH_INFO'}) ? $ENV{'PATH_INFO'} : "";=0A=
$doCheckout =3D ($where =3D~ /^\/$checkoutMagic/);=0A=
$where =3D~ s|^/($checkoutMagic)?||;=0A=
$where =3D~ s|/+$||;=0A=
($scriptname =3D $ENV{'SCRIPT_NAME'}) =3D~ s|^/?|/|;=0A=
$scriptname =3D~ s|/+$||;=0A=
if ($where) {=0A=
$scriptwhere =3D $scriptname . '/' . urlencode($where);=0A=
}=0A=
else {=0A=
$scriptwhere =3D $scriptname;=0A=
}=0A=
$scriptwhere =3D~ s|/+$||;=0A=
=0A=
# in lynx, it it very annoying to have two links=0A=
# per file, so disable the link at the icon=0A=
# in this case:=0A=
$Browser =3D $ENV{'HTTP_USER_AGENT'};=0A=
$nofilelinks =3D ($Browser =3D~ m'^Lynx/');=0A=
=0A=
# newer browsers accept gzip content encoding=0A=
# and state this in a header=0A=
# (netscape did always but didn't state it)=0A=
# It has been reported that these=0A=
# braindamaged MS-Internet Exploders claim that they=0A=
# accept gzip .. but don't in fact and=0A=
# display garbage then :-/=0A=
# Turn off gzip if running under mod_perl and no zlib is available,=0A=
# piping does not work as expected inside the server.=0A=
$maycompress =3D (((defined($ENV{'HTTP_ACCEPT_ENCODING'})=0A=
&& $ENV{'HTTP_ACCEPT_ENCODING'} =3D~ m|gzip|)=0A=
|| $Browser =3D~ m%^Mozilla/3%)=0A=
&& ($Browser !~ m/MSIE/)=0A=
&& !(defined($ENV{'MOD_PERL'}) && !$has_zlib));=0A=
=0A=
# put here the variables we need in order=0A=
# to hold our state - they will be added (with=0A=
# their current value) to any link/query string=0A=
# you construct=0A=
@stickyvars =3D qw(cvsroot hideattic sortby logsort f only_with_tag);=0A=
=0A=
if (-f $config) {=0A=
do "$config";=0A=
}=0A=
else {=0A=
&fatal("500 Internal Error",=0A=
'Configuration not found. Set the variable $config '=0A=
. 'in cvsweb.cgi, or the environment variable '=0A=
. 'CVSWEB_CONFIG, to your cvsweb.conf '=0A=
. 'configuration file first.');=0A=
}=0A=
=0A=
undef %input;=0A=
if ($query =3D $ENV{'QUERY_STRING'}) {=0A=
foreach (split(/&/, $query)) {=0A=
y/+/ /;=0A=
s/%(..)/sprintf("%c", hex($1))/ge; # unquote %-quoted=0A=
if (/(\S+)=3D(.*)/) {=0A=
$input{$1} =3D $2 if ($2 ne "");=0A=
}=0A=
else {=0A=
$input{$_}++;=0A=
}=0A=
}=0A=
}=0A=
=0A=
# For backwards compability, set only_with_tag to only_on_branch if set. =0A=
$input{only_with_tag} =3D $input{only_on_branch}=0A=
if (defined($input{only_on_branch}));=0A=
=0A=
foreach (keys %DEFAULTVALUE)=0A=
{=0A=
# replace not given parameters with the default parameters=0A=
if (!defined($input{$_}) || $input{$_} eq "") {=0A=
# Empty Checkboxes in forms return -- nothing. So we define a helper=0A=
# variable in these forms (copt) which indicates that we just set=0A=
# parameters with a checkbox=0A=
if (!defined($input{"copt"})) {=0A=
# 'copt' isn't defined --> empty input is not the result=0A=
# of empty input checkbox --> set default=0A=
$input{$_} =3D $DEFAULTVALUE{$_} if (defined($DEFAULTVALUE{$_}));=0A=
}=0A=
else {=0A=
# 'copt' is defined -> the result of empty input checkbox=0A=
# -> set to zero (disable) if default is a boolean (0|1).=0A=
$input{$_} =3D 0=0A=
if (defined($DEFAULTVALUE{$_})=0A=
&& ($DEFAULTVALUE{$_} eq "0" || $DEFAULTVALUE{$_} eq "1"));=0A=
}=0A=
}=0A=
}=0A=
=0A=
$barequery =3D "";=0A=
foreach (@stickyvars) {=0A=
# construct a query string with the sticky non default parameters set=0A=
if (defined($input{$_}) && ($input{$_} ne "") && =0A=
(!defined($DEFAULTVALUE{$_}) || $input{$_} ne $DEFAULTVALUE{$_})) {=0A=
if ($barequery) {=0A=
$barequery =3D $barequery . "&";=0A=
}=0A=
my $thisval =3D urlencode($_) . "=3D" . urlencode($input{$_});=0A=
$barequery .=3D $thisval;=0A=
}=0A=
}=0A=
# is there any query ?=0A=
if ($barequery) {=0A=
$query =3D "?$barequery";=0A=
$barequery =3D "&" . $barequery;=0A=
}=0A=
else {=0A=
$query =3D "";=0A=
}=0A=
=0A=
# get actual parameters=0A=
$sortby =3D $input{"sortby"};=0A=
$bydate =3D 0;=0A=
$byrev =3D 0;=0A=
$byauthor =3D 0;=0A=
$bylog =3D 0;=0A=
$byfile =3D 0;=0A=
if ($sortby eq "date") {=0A=
$bydate =3D 1;=0A=
}=0A=
elsif ($sortby eq "rev") {=0A=
$byrev =3D 1;=0A=
}=0A=
elsif ($sortby eq "author") {=0A=
$byauthor =3D 1;=0A=
}=0A=
elsif ($sortby eq "log") {=0A=
$bylog =3D 1;=0A=
}=0A=
else {=0A=
$byfile =3D 1;=0A=
}=0A=
=0A=
$hr_default =3D $input{'f'} eq 'h';=0A=
=0A=
$logsort =3D $input{"logsort"};=0A=
=0A=
=0A=
## Default CVS-Tree=0A=
if (!defined($CVSROOT{$cvstreedefault})) {=0A=
&fatal("500 Internal Error",=0A=
"\$cvstreedefault points to a repository =
($cvstreedefault)"=0A=
. "not defined in %CVSROOT "=0A=
. "(edit your configuration file $config)");=0A=
}=0A=
$cvstree =3D $cvstreedefault;=0A=
$cvsroot =3D $CVSROOT{"$cvstree"};=0A=
=0A=
# alternate CVS-Tree, configured in cvsweb.conf=0A=
if ($input{'cvsroot'}) {=0A=
if ($CVSROOT{$input{'cvsroot'}}) {=0A=
$cvstree =3D $input{'cvsroot'};=0A=
$cvsroot =3D $CVSROOT{"$cvstree"};=0A=
}=0A=
}=0A=
=0A=
# create icons out of description=0A=
foreach my $k (keys %ICONS) {=0A=
no strict 'refs';=0A=
my ($itxt,$ipath,$iwidth,$iheight) =3D @{$ICONS{$k}};=0A=
if ($ipath) {=0A=
$ {"${k}icon"} =3D "
";=0A=
}=0A=
else {=0A=
$ {"${k}icon"} =3D $itxt;=0A=
}=0A=
}=0A=
=0A=
# Do some special configuration for cvstrees=0A=
do "$config-$cvstree" if (-f "$config-$cvstree");=0A=
=0A=
$fullname =3D $cvsroot . '/' . $where;=0A=
$mimetype =3D &getMimeTypeFromSuffix ($fullname);=0A=
$defaultTextPlain =3D ($mimetype eq "text/plain");=0A=
$defaultViewable =3D $allow_markup && viewable($mimetype);=0A=
=0A=
# search for GZIP if compression allowed=0A=
# We've to find out if the GZIP-binary exists .. otherwise=0A=
# ge get an Internal Server Error if we try to pipe the=0A=
# output through the nonexistent gzip .. =0A=
# any more elegant ways to prevent this are welcome!=0A=
if ($allow_compress && $maycompress && !$has_zlib) {=0A=
foreach (split(/:/, $ENV{PATH})) {=0A=
if (-x "$_/gzip") {=0A=
$GZIPBIN =3D "$_/gzip";=0A=
last;=0A=
}=0A=
}=0A=
}=0A=
=0A=
if (-d $fullname) {=0A=
#=0A=
# ensure, that directories always end with (exactly) one '/'=0A=
# to allow relative URL's. If they're not, make a redirect.=0A=
##=0A=
my $pathinfo =3D defined($ENV{'PATH_INFO'}) ? $ENV{'PATH_INFO'} : "";=0A=
if (!($pathinfo =3D~ m|/$|) || ($pathinfo =3D~ m |/{2,}$|)) {=0A=
redirect ($scriptwhere . '/' . $query);=0A=
}=0A=
else {=0A=
$where .=3D '/';=0A=
$scriptwhere .=3D '/';=0A=
}=0A=
}=0A=
=0A=
if (!-d $cvsroot) {=0A=
&fatal("500 Internal Error",'$CVSROOT not found!The server on =
which the CVS tree lives is probably down. Please try again in a few =
minutes.');=0A=
}=0A=
=0A=
#=0A=
# See if the module is in our forbidden list.=0A=
#=0A=
$where =3D~ m:([^/]*):;=0A=
$module =3D $1;=0A=
if ($module && &forbidden_module($module)) {=0A=
&fatal("403 Forbidden", "Access to $where forbidden.");=0A=
}=0A=
##############################=0A=
# View a directory=0A=
###############################=0A=
elsif (-d $fullname) {=0A=
my $dh =3D do {local(*DH);};=0A=
opendir($dh, $fullname) || &fatal("404 Not Found","$where: $!");=0A=
my @dir =3D readdir($dh);=0A=
closedir($dh);=0A=
my @subLevelFiles =3D findLastModifiedSubdirs(@dir)=0A=
if ($show_subdir_lastmod);=0A=
getDirLogs($cvsroot,$where,@subLevelFiles);=0A=
=0A=
if ($where eq '/') {=0A=
html_header("$defaulttitle");=0A=
print $long_intro;=0A=
}=0A=
else {=0A=
html_header("$where");=0A=
print $short_instruction;=0A=
}=0A=
=0A=
my $descriptions;=0A=
if (($use_descriptions) && open (DESC, =
"<$cvsroot/CVSROOT/descriptions")) {=0A=
while () {=0A=
chomp;=0A=
my ($dir,$description) =3D /(\S+)\s+(.*)/;=0A=
$descriptions{$dir} =3D $description;=0A=
}=0A=
}=0A=
=0A=
print "\n";=0A=
# give direct access to dirs=0A=
if ($where eq '/') {=0A=
chooseMirror();=0A=
chooseCVSRoot();=0A=
}=0A=
else {=0A=
print "
Current directory: ", &clickablePath($where,0), =
"\n";=0A=
=0A=
print "
Current tag: ", $input{only_with_tag}, "\n" if=0A=
$input{only_with_tag};=0A=
=0A=
}=0A=
=0A=
=0A=
print "
\n";=0A=
# Using " . "\n";=0A=
=0A=
if ($filesexists && !$filesfound) {=0A=
print "NOTE: There are $filesexists files, but none =
matches the current tag ($input{only_with_tag})\n";=0A=
}=0A=
if ($input{only_with_tag} && (!%tags || !$tags{$input{only_with_tag}})) =
{=0A=
%tags =3D %alltags=0A=
}=0A=
if (scalar %tags =0A=
|| $input{only_with_tag} =0A=
|| $edit_option_form=0A=
|| defined($input{"options"})) {=0A=
print "
";=0A=
}=0A=
=0A=
if (scalar %tags || $input{only_with_tag}) {=0A=
print "\n";=0A=
}=0A=
my $formwhere =3D $scriptwhere;=0A=
$formwhere =3D~ s|Attic/?$|| if ($input{'hideattic'});=0A=
=0A=
if ($edit_option_form || defined($input{"options"})) {=0A=
print "\n";=0A=
}=0A=
print &html_footer;=0A=
print "