version 1.1.1.32, 2002/07/07 04:31:41 |
version 1.1.1.36, 2002/09/30 19:48:52 |
|
|
# cvsweb - a CGI interface to CVS trees. |
# cvsweb - a CGI interface to CVS trees. |
# |
# |
# Written in their spare time by |
# Written in their spare time by |
# Bill Fenner <fenner@FreeBSD.org> (original work) |
# Bill Fenner <fenner@FreeBSD.org> (original work) |
# extended by Henner Zeller <zeller@think.de>, |
# extended by Henner Zeller <zeller@think.de>, |
# Henrik Nordstrom <hno@hem.passagen.se> |
# Henrik Nordstrom <hno@hem.passagen.se> |
# Ken Coar <coar@Apache.Org> |
# Ken Coar <coar@Apache.Org> |
# Dick Balaska <dick@buckosoft.com> |
# Dick Balaska <dick@buckosoft.com> |
# Akinori MUSHA <knu@FreeBSD.org> |
# Akinori MUSHA <knu@FreeBSD.org> |
# Jens-Uwe Mager <jum@helios.de> |
# Jens-Uwe Mager <jum@helios.de> |
# Ville Skyttä <scop@FreeBSD.org> |
# Ville Skyttä <scop@FreeBSD.org> |
|
# Vassilii Khachaturov <vassilii@tarunz.org> |
# |
# |
# Based on: |
# Based on: |
# * Bill Fenners cvsweb.cgi revision 1.28 available from: |
# * Bill Fenners cvsweb.cgi revision 1.28 available from: |
|
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
# SUCH DAMAGE. |
# SUCH DAMAGE. |
# |
# |
# $FreeBSD: projects/cvsweb/cvsweb.cgi,v 1.112 2002/07/06 18:15:19 scop Exp $ |
# $FreeBSD: projects/cvsweb/cvsweb.cgi,v 1.119.2.6 2002/09/26 20:56:05 scop Exp $ |
# $zId: cvsweb.cgi,v 1.112 2001/07/24 13:03:16 hzeller Exp $ |
# $zId: cvsweb.cgi,v 1.112 2001/07/24 13:03:16 hzeller Exp $ |
# $Idaemons: /home/cvs/cvsweb/cvsweb.cgi,v 1.84 2001/10/07 20:50:10 knu Exp $ |
# $Idaemons: /home/cvs/cvsweb/cvsweb.cgi,v 1.84 2001/10/07 20:50:10 knu Exp $ |
# |
# |
|
|
$module $use_descriptions %descriptions @mytz $dwhere $moddate |
$module $use_descriptions %descriptions @mytz $dwhere $moddate |
$use_moddate $has_zlib $gzip_open |
$use_moddate $has_zlib $gzip_open |
$allow_tar @tar_options @gzip_options @zip_options @cvs_options |
$allow_tar @tar_options @gzip_options @zip_options @cvs_options |
$LOG_FILESEPARATOR $LOG_REVSEPARATOR |
@annotate_options $LOG_FILESEPARATOR $LOG_REVSEPARATOR |
$tmpdir $HTML_DOCTYPE $HTML_META |
$tmpdir $HTML_DOCTYPE $HTML_META |
); |
); |
|
|
Line 148 sub forbidden_module($); |
|
Line 149 sub forbidden_module($); |
|
##### Start of Configuration Area ######## |
##### Start of Configuration Area ######## |
delete $ENV{PATH}; |
delete $ENV{PATH}; |
|
|
$cvsweb_revision = '2.0.4'; |
$cvsweb_revision = '2.0.6'; |
|
|
use File::Basename (); |
use File::Basename (); |
|
|
Line 343 $input{only_with_tag} = $input{only_on_branch} |
|
Line 344 $input{only_with_tag} = $input{only_on_branch} |
|
|
|
# Prevent cross-site scripting |
# Prevent cross-site scripting |
foreach (@unsafevars) { |
foreach (@unsafevars) { |
if (defined($input{$_}) && $input{$_} =~ /[^\w\-.]/) { |
# Colons are needed in diffs between tags. |
|
if (defined($input{$_}) && $input{$_} =~ /[^\w\-.:]/) { |
fatal("500 Internal Error", |
fatal("500 Internal Error", |
'Malformed query (%s=%s)', |
'Malformed query (%s=%s)', |
$_, $input{$_}); |
$_, $input{$_}); |
Line 466 if ($input{'cvsroot'} && $CVSROOT{$input{'cvsroot'}}) |
|
Line 468 if ($input{'cvsroot'} && $CVSROOT{$input{'cvsroot'}}) |
|
$cvsroot = $CVSROOT{$cvstree}; |
$cvsroot = $CVSROOT{$cvstree}; |
|
|
# create icons out of description |
# create icons out of description |
my $k; |
foreach my $k (keys %ICONS) { |
foreach $k (keys %ICONS) { |
|
no strict 'refs'; |
no strict 'refs'; |
my ($itxt, $ipath, $iwidth, $iheight) = @{$ICONS{$k}}; |
my ($itxt, $ipath, $iwidth, $iheight) = @{$ICONS{$k}}; |
if ($ipath) { |
if ($ipath) { |
Line 479 foreach $k (keys %ICONS) { |
|
Line 480 foreach $k (keys %ICONS) { |
|
${"${k}icon"} = $itxt; |
${"${k}icon"} = $itxt; |
} |
} |
} |
} |
undef $k; |
|
|
|
my $config_cvstree = "$config-$cvstree"; |
my $config_cvstree = "$config-$cvstree"; |
|
|
Line 810 if (-d $fullname) { |
|
Line 810 if (-d $fullname) { |
|
my $filesexists; |
my $filesexists; |
my $filesfound; |
my $filesfound; |
|
|
foreach (sort { &fileSortCmp } @dir) { |
foreach my $file (sort { &fileSortCmp } @dir) { |
if ($_ eq '.') { |
|
next; |
|
} |
|
|
|
|
next if ($file eq '.'); |
|
|
# ignore CVS lock and stale NFS files |
# ignore CVS lock and stale NFS files |
next if (/^#cvs\.|^,|^\.nfs/); |
next if ($file =~ /^#cvs\.|^,|^\.nfs/); |
|
|
# Check whether to show the CVSROOT path |
# Check whether to show the CVSROOT path |
next if ($input{'hidecvsroot'} && ($_ eq 'CVSROOT')); |
next if ($input{'hidecvsroot'} && $file eq 'CVSROOT'); |
|
|
# Check whether the module is in the restricted list |
# Check whether the module is in the restricted list |
next if ($_ && &forbidden_module($_)); |
next if ($file && &forbidden_module($file)); |
|
|
# Ignore non-readable files |
# Ignore non-readable files |
next if ($input{'hidenonreadable'} && !(-r "$fullname/$_")); |
next if ($input{'hidenonreadable'} && !(-r "$fullname/$file")); |
|
|
if (s|^Attic/||) { |
if ($file =~ s|^Attic/||) { |
$attic = " (in the Attic) " . $hideAtticToggleLink; |
$attic = " (in the Attic) " . $hideAtticToggleLink; |
} else { |
} else { |
$attic = ""; |
$attic = ""; |
} |
} |
|
|
if ($_ eq '..' || -d "$fullname/$_") { |
if ($file eq '..' || -d "$fullname/$file") { |
next if ($_ eq '..' && $where eq '/'); |
next if ($file eq '..' && $where eq '/'); |
my ($rev, $date, $log, $author, $filename); |
my ($rev, $date, $log, $author, $filename) = |
($rev, $date, $log, $author, $filename) = |
@{$fileinfo{$file}} |
@{$fileinfo{$_}} |
if (defined($fileinfo{$file})); |
if (defined($fileinfo{$_})); |
|
printf "<tr style=\"background-color: %s\">\n<td>", |
printf "<tr style=\"background-color: %s\">\n<td>", |
$tabcolors[$dirrow % 2] if $dirtable; |
$tabcolors[$dirrow % 2] if $dirtable; |
|
|
if ($_ eq '..') { |
if ($file eq '..') { |
$url = "../$query"; |
$url = "../$query"; |
if ($nofilelinks) { |
if ($nofilelinks) { |
print $backicon; |
print $backicon; |
Line 851 if (-d $fullname) { |
|
Line 849 if (-d $fullname) { |
|
} |
} |
print ' ', &link("Parent Directory", $url); |
print ' ', &link("Parent Directory", $url); |
} else { |
} else { |
$url = './' . urlencode($_) . "/$query"; |
$url = './' . urlencode($file) . "/$query"; |
print "<a name=\"$_\"></a>"; |
print "<a name=\"$file\"></a>"; |
|
|
if ($nofilelinks) { |
if ($nofilelinks) { |
print $diricon; |
print $diricon; |
} else { |
} else { |
print &link($diricon, $url); |
print &link($diricon, $url); |
} |
} |
print ' ', &link("$_/", $url), $attic; |
print ' ', &link("$file/", $url), $attic; |
|
|
if ($_ eq "Attic") { |
if ($file eq "Attic") { |
print " "; |
print " "; |
print &link( |
print &link( |
"[Don't hide]", |
"[Don't hide]", |
Line 904 if (-d $fullname) { |
|
Line 902 if (-d $fullname) { |
|
} |
} |
} else { |
} else { |
my ($dwhere) = |
my ($dwhere) = |
($where ne "/" ? $where : "") . $_; |
($where ne "/" ? $where : "") . $file; |
|
|
if ($use_descriptions |
if ($use_descriptions |
&& defined $descriptions{$dwhere}) |
&& defined $descriptions{$dwhere}) |
Line 931 if (-d $fullname) { |
|
Line 929 if (-d $fullname) { |
|
print "<br>\n"; |
print "<br>\n"; |
} |
} |
$dirrow++; |
$dirrow++; |
} elsif (s/,v$//) { |
} elsif ($file =~ s/,v$//) { |
$fileurl = ($attic ? "Attic/" : "") . urlencode($_); |
|
|
# Skip forbidden files now so we'll give no hint |
|
# about their existence. This should probably have |
|
# been done earlier, but it's straightforward here. |
|
next if forbidden_file("$fullname/$file"); |
|
|
|
$fileurl = ($attic ? "Attic/" : "") . urlencode($file); |
$url = './' . $fileurl . $query; |
$url = './' . $fileurl . $query; |
my $rev = ''; |
|
my $date = ''; |
|
my $log = ''; |
|
my $author = ''; |
|
$filesexists++; |
$filesexists++; |
next if (!defined($fileinfo{$_})); |
next if (!defined($fileinfo{$file})); |
($rev, $date, $log, $author) = @{$fileinfo{$_}}; |
my ($rev, $date, $log, $author) = @{$fileinfo{$file}}; |
$filesfound++; |
$filesfound++; |
printf "<tr style=\"background-color: %s\">\n<td>", |
printf "<tr style=\"background-color: %s\">\n<td>", |
$tabcolors[$dirrow % 2] if $dirtable; |
$tabcolors[$dirrow % 2] if $dirtable; |
print "<a name=\"$_\"></a>"; |
print "<a name=\"$file\"></a>"; |
|
|
if ($nofilelinks) { |
if ($nofilelinks) { |
print $fileicon; |
print $fileicon; |
} else { |
} else { |
print &link($fileicon, $url); |
print &link($fileicon, $url); |
} |
} |
print ' ', &link($_, $url), $attic; |
print ' ', &link(htmlquote($file), $url), $attic; |
print "</td>\n<td> " if ($dirtable); |
print "</td>\n<td> " if ($dirtable); |
download_link($fileurl, $rev, $rev, |
download_link($fileurl, $rev, $rev, |
$defaultViewable ? "text/x-cvsweb-markup" : |
$defaultViewable ? "text/x-cvsweb-markup" : |
Line 1104 if (-d $fullname) { |
|
Line 1104 if (-d $fullname) { |
|
# View Files |
# View Files |
############################### |
############################### |
elsif (-f $fullname . ',v') { |
elsif (-f $fullname . ',v') { |
|
|
|
if (forbidden_file($fullname)) { |
|
fatal('403 Forbidden', |
|
'Access forbidden. This file is mentioned in @ForbiddenFiles'); |
|
return; |
|
} |
|
|
if (defined($input{'rev'}) || $doCheckout) { |
if (defined($input{'rev'}) || $doCheckout) { |
&doCheckout($fullname, $input{'rev'}); |
&doCheckout($fullname, $input{'rev'}); |
gzipclose(); |
gzipclose(); |
Line 1251 sub findLastModifiedSubdirs(@) { |
|
Line 1258 sub findLastModifiedSubdirs(@) { |
|
$filename = "$dirname/$filename"; |
$filename = "$dirname/$filename"; |
my ($file) = "$fullname/$filename"; |
my ($file) = "$fullname/$filename"; |
next if ($filename !~ /,v$/ || !-f $file); |
next if ($filename !~ /,v$/ || !-f $file); |
|
|
|
# Skip forbidden files. |
|
(my $f = $file) =~ s/,v$//; |
|
next if forbidden_file($f); |
|
|
$filename =~ s/,v$//; |
$filename =~ s/,v$//; |
my $modtime = -M $file; |
my $modtime = -M $file; |
|
|
Line 1393 sub spacedHtmlText($;$) { |
|
Line 1405 sub spacedHtmlText($;$) { |
|
return $_; |
return $_; |
} |
} |
|
|
|
# Note that this doesn't htmlquote the first argument... |
sub link($$) { |
sub link($$) { |
my ($name, $url) = @_; |
my ($name, $url) = @_; |
|
|
Line 1587 sub doAnnotate($$) { |
|
Line 1600 sub doAnnotate($$) { |
|
$ENV{QUERY_STRING}); |
$ENV{QUERY_STRING}); |
} |
} |
|
|
if (&forbidden_file($fullname)) { |
|
fatal("403 Forbidden", |
|
'Access forbidden. This file is mentioned in @ForbiddenFiles'); |
|
return; |
|
} |
|
|
|
($pathname = $where) =~ s/(Attic\/)?[^\/]*$//; |
($pathname = $where) =~ s/(Attic\/)?[^\/]*$//; |
($filename = $where) =~ s/^.*\///; |
($filename = $where) =~ s/^.*\///; |
|
|
Line 1600 sub doAnnotate($$) { |
|
Line 1607 sub doAnnotate($$) { |
|
$| = 1; |
$| = 1; |
$| = 0; # Flush |
$| = 0; # Flush |
|
|
|
# Work around a mod_perl bug (?) in order to make open2() work. |
|
# Search for "untie STDIN" in mod_perl mailing list archives. |
|
my $old_stdin; |
|
if ($is_mod_perl && ($old_stdin = tied *STDIN)) { |
|
local $^W = undef; |
|
untie *STDIN; |
|
} |
|
|
# this annotate version is based on the |
# this annotate version is based on the |
# cvs annotate-demo Perl script by Cyclic Software |
# cvs annotate-demo Perl script by Cyclic Software |
# It was written by Cyclic Software, http://www.cyclic.com/, and is in |
# It was written by Cyclic Software, http://www.cyclic.com/, and is in |
# the public domain. |
# the public domain. |
# we could abandon the use of rlog, rcsdiff and co using |
# we could abandon the use of rlog, rcsdiff and co using |
# the cvsserver in a similiar way one day (..after rewrite) |
# the cvsserver in a similiar way one day (..after rewrite) |
$pid = open2($reader, $writer, $CMD{cvs}, @cvs_options, "server") |
$pid = open2($reader, $writer, $CMD{cvs}, @annotate_options, 'server') |
or fatal("500 Internal Error", |
or fatal("500 Internal Error", |
'Fatal Error - unable to open cvs for annotation'); |
'Fatal Error - unable to open cvs for annotation'); |
|
|
|
# Re-tie STDIN if we fiddled around with it earlier, just to be sure. |
|
tie(*STDIN, ref($old_stdin), $old_stdin) if ($old_stdin && !tied(*STDIN)); |
|
|
# OK, first send the request to the server. A simplified example is: |
# OK, first send the request to the server. A simplified example is: |
# Root /home/kingdon/zwork/cvsroot |
# Root /home/kingdon/zwork/cvsroot |
# Argument foo/xx |
# Argument foo/xx |
Line 1753 sub doAnnotate($$) { |
|
Line 1771 sub doAnnotate($$) { |
|
} else { |
} else { |
print "</pre>"; |
print "</pre>"; |
} |
} |
|
html_footer(); |
|
|
close($reader) or warn "cannot close: $!"; |
close($reader) or warn "cannot close: $!"; |
wait; |
wait; |
} |
} |
Line 1777 sub doCheckout($$) { |
|
Line 1797 sub doCheckout($$) { |
|
$ENV{QUERY_STRING}); |
$ENV{QUERY_STRING}); |
} |
} |
|
|
if (&forbidden_file($fullname)) { |
|
fatal("403 Forbidden", |
|
'Access forbidden. This file is mentioned in @ForbiddenFiles'); |
|
return; |
|
} |
|
|
|
# get mimetype |
# get mimetype |
if (defined($input{"content-type"}) |
if (defined($input{"content-type"}) |
&& ($input{"content-type"} =~ /\S\/\S/)) |
&& ($input{"content-type"} =~ /\S\/\S/)) |
Line 2101 sub getDirLogs($$@) { |
|
Line 2115 sub getDirLogs($$@) { |
|
push (@files, &safeglob("$DirName/*,v")); |
push (@files, &safeglob("$DirName/*,v")); |
push (@files, &safeglob("$DirName/Attic/*,v")) |
push (@files, &safeglob("$DirName/Attic/*,v")) |
if (!$input{'hideattic'}); |
if (!$input{'hideattic'}); |
foreach $file (@otherFiles) { |
foreach my $file (@otherFiles) { |
push (@files, "$DirName/$file"); |
push (@files, "$DirName/$file"); |
} |
} |
|
|
Line 3317 sub chooseCVSRoot() { |
|
Line 3331 sub chooseCVSRoot() { |
|
print "CVS Root: <b>[$cvstree]</b>"; |
print "CVS Root: <b>[$cvstree]</b>"; |
} |
} |
|
|
print " <label for=\"path\" accesskey=\"P\">Module path or alias:"; |
print " <label for=\"mpath\" accesskey=\"M\">Module path or alias:"; |
print "</label>\n"; |
print "</label>\n"; |
print "<input type=\"text\" id=\"path\" name=\"path\" value=\"\" size=\"15\">\n"; |
print "<input type=\"text\" id=\"mpath\" name=\"path\" value=\"\" size=\"15\">\n"; |
print "<input type=\"submit\" value=\"Go\" accesskey=\"G\">"; |
print "<input type=\"submit\" value=\"Go\" accesskey=\"O\">"; |
|
|
if (2 <= @CVSROOT) { |
if (2 <= @CVSROOT) { |
print "</td>\n</tr>\n</table>"; |
print "</td>\n</tr>\n</table>"; |
Line 3331 sub chooseCVSRoot() { |
|
Line 3345 sub chooseCVSRoot() { |
|
} |
} |
|
|
sub chooseMirror() { |
sub chooseMirror() { |
my ($mirror, $moremirrors); |
|
$moremirrors = 0; |
|
|
|
# This code comes from the original BSD-cvsweb |
# This code comes from the original BSD-cvsweb |
# and may not be useful for your site; If you don't |
# and may not be useful for your site; If you don't |
# set %MIRRORS this won't show up, anyway |
# set %MIRRORS this won't show up, anyway. |
# |
scalar(%MIRRORS) or return; |
# Should perhaps exlude the current site somehow.. |
|
if (keys %MIRRORS) { |
|
print "\nThis CVSweb is mirrored in:\n"; |
|
|
|
foreach $mirror (keys %MIRRORS) { |
# Should perhaps exclude the current site somehow... |
print ", " if ($moremirrors); |
print "\n<p>\nThis CVSweb is mirrored in\n"; |
print &link(htmlquote($mirror), $MIRRORS{$mirror}); |
|
$moremirrors = 1; |
my @tmp = map(&link(htmlquote($_), $MIRRORS{$_}), |
} |
sort keys %MIRRORS); |
print "<p>\n"; |
my $tmp = pop(@tmp); |
|
|
|
if (scalar(@tmp)) { |
|
print join(', ', @tmp), ' and '; |
} |
} |
|
|
|
print "$tmp.\n</p>\n"; |
} |
} |
|
|
sub fileSortCmp() { |
sub fileSortCmp() { |
Line 3376 sub fileSortCmp() { |
|
Line 3390 sub fileSortCmp() { |
|
|
|
if ($comp == 0) { |
if ($comp == 0) { |
|
|
# Directories first, then sorted on name if no other sort critera |
# Directories first, then files under version control, |
# available. |
# then other, "rogue" files. |
my $ad = ((-d "$fullname/$a") ? "D" : "F"); |
# Sort by filename if no other criteria available. |
my $bd = ((-d "$fullname/$b") ? "D" : "F"); |
|
|
my $ad = ((-d "$fullname/$a") ? 'D' |
|
: (defined($fileinfo{$af}) ? 'F' : 'R')); |
|
my $bd = ((-d "$fullname/$b") ? 'D' |
|
: (defined($fileinfo{$bf}) ? 'F' : 'R')); |
($c = $a) =~ s|.*/||; |
($c = $a) =~ s|.*/||; |
($d = $b) =~ s|.*/||; |
($d = $b) =~ s|.*/||; |
$comp = ("$ad$c" cmp "$bd$d"); |
$comp = ("$ad$c" cmp "$bd$d"); |
Line 3439 sub download_link($$$;$) { |
|
Line 3457 sub download_link($$$;$) { |
|
# currently, the best way is to comment out the size parameters |
# currently, the best way is to comment out the size parameters |
# ($extern_window...) in cvsweb.conf. |
# ($extern_window...) in cvsweb.conf. |
if ($use_java_script) { |
if ($use_java_script) { |
my @attr = qw(resizeable scrollbars); |
my @attr = qw(resizable scrollbars); |
|
|
push @attr, qw(status toolbar) |
push @attr, qw(status toolbar) |
if (defined($mimetype) && $mimetype eq "text/html"); |
if (defined($mimetype) && $mimetype eq "text/html"); |
Line 3456 sub download_link($$$;$) { |
|
Line 3474 sub download_link($$$;$) { |
|
# the same window *twice*. |
# the same window *twice*. |
printf |
printf |
q` onclick="window.open('%s','cvs_checkout','%s');return false"`, |
q` onclick="window.open('%s','cvs_checkout','%s');return false"`, |
hrefquote($fullurl), join (',', @attr); |
hrefquote("$fullurl$barequery"), join (',', @attr); |
} |
} |
} |
} |
print "><b>$textlink</b></a>"; |
print "><b>$textlink</b></a>"; |
|
|
} |
} |
|
|
sub html_footer() { |
sub html_footer() { |
print "<hr noshade>\n<address>$address</address>\n</body>\n</html>\n"; |
print "<hr noshade>\n<address>$address</address>\n" if $address; |
|
print "</body>\n</html>\n"; |
} |
} |
|
|
sub link_tags($) { |
sub link_tags($) { |