%s ',
$config, &htmlify($@)));
@@ -294,6 +296,7 @@ $query = $ENV{QUERY_STRING};
if (defined($query) && $query ne '') {
foreach (split(/&/, $query)) {
+ y/+/ /;
s/%(..)/sprintf("%c", hex($1))/ge; # unquote %-quoted
if (/(\S+)=(.*)/) {
$input{$1} = $2 if ($2 ne "");
@@ -404,7 +407,7 @@ foreach $k (keys %ICONS) {
my ($itxt,$ipath,$iwidth,$iheight) = @{$ICONS{$k}};
if ($ipath) {
${"${k}icon"} = sprintf('',
- htmlquote($ipath), htmlquote($itxt), $iwidth, $iheight)
+ hrefquote($ipath), htmlquote($itxt), $iwidth, $iheight)
}
else {
${"${k}icon"} = $itxt;
@@ -416,17 +419,18 @@ my $config_cvstree = "$config-$cvstree";
# Do some special configuration for cvstrees
if (-f $config_cvstree) {
- do $config_cvstree
+ require $config_cvstree
|| &fatal("500 Internal Error",
sprintf('Error in loading configuration file: %s
%s ',
$config_cvstree, &htmlify($@)));
}
undef $config_cvstree;
-$prcategories = '(?:' . join('|', @prcategories) . ')';
+$re_prcategories = '(?:' . join('|', @prcategories) . ')' if @prcategories;
+$re_prkeyword = quotemeta($prkeyword) if defined($prkeyword);
$prcgi .= '%s' if defined($prcgi) && $prcgi !~ /%s/;
-$fullname = $cvsroot . '/' . $where;
+$fullname = "$cvsroot/$where";
$mimetype = &getMimeTypeFromSuffix ($fullname);
$defaultTextPlain = ($mimetype eq "text/plain");
$defaultViewable = $allow_markup && viewable($mimetype);
@@ -471,10 +475,68 @@ $module = $1;
if ($module && &forbidden_module($module)) {
&fatal("403 Forbidden", "Access to $where forbidden.");
}
+
+#
+# Handle tarball downloads before any headers are output.
+#
+if ($input{tarball}) {
+ &fatal("403 Forbidden", "Downloading tarballs is prohibited.")
+ unless $allow_tar;
+ $where =~ s,/[^/]*$,,;
+ $where =~ s,^/,,;
+ my($basedir) = ($where =~ m,([^/]+)$,);
+
+ if ($basedir eq '' || $where eq '') {
+ &fatal("500 Internal Error", "You cannot download the top level directory.");
+ }
+
+ my $tmpdir = "/tmp/.cvsweb.$$." . int(time);
+
+ mkdir($tmpdir, 0700)
+ or &fatal("500 Internal Error", "Unable to make temporary directory: $!");
+
+ my $fatal = '';
+
+ do {
+ chdir $tmpdir
+ or $fatal = "500 Internal Error", "Unable to cd to temporary directory: $!"
+ && last;
+
+ my $tag = (exists $input{only_with_tag} && length $input{only_with_tag})
+ ? $input{only_with_tag} : "HEAD";
+
+ system "cvs", @cvs_options, "-Qd", $cvsroot, "export", "-r", $tag, $where
+ and $fatal = "500 Internal Error","cvs co failure: $!: $where"
+ && last;
+
+ chdir "$where/.."
+ or $fatal = "500 Internal Error","Cannot find expected directory in checkout"
+ && last;
+
+ $| = 1; # Essential to get the buffering right.
+
+ print "Content-type: application/x-gzip\r\n\r\n";
+
+ system "tar", "-zcf", "-", $basedir, @tar_options
+ and $fatal = "500 Internal Error","tar zc failure: $!: $basedir"
+ && last;
+
+ chdir $tmpdir
+ or $fatal = "500 Internal Error","Unable to cd to temporary directory: $!"
+ && last;
+ } while (0);
+
+ system "rm", "-rf", $tmpdir if -d $tmpdir;
+
+ &fatal($fatal) if $fatal;
+
+ exit;
+}
+
##############################
# View a directory
###############################
-elsif (-d $fullname) {
+if (-d $fullname) {
my $dh = do {local(*DH);};
opendir($dh, $fullname) || &fatal("404 Not Found","$where: $!");
my @dir = readdir($dh);
@@ -812,6 +874,22 @@ elsif (-d $fullname) {
print "\n";
print "\n";
}
+
+ if ($allow_tar) {
+ my($basefile) = ($where =~ m,(?:.*/)?([^/]+),);
+
+ if ($basefile ne '') {
+ print "
\n",
+ "
",
+ &link("Download this directory in tarball",
+ # Mangle the filename so browsers show a reasonable
+ # filename to download.
+ "$basefile.tar.gz$query".
+ ($query ? "&" : "?")."tarball=1"),
+ "
";
+ }
+ }
+
my $formwhere = $scriptwhere;
$formwhere =~ s|Attic/?$|| if ($input{'hideattic'});
@@ -1036,7 +1114,7 @@ sub htmlify($;$) {
if ($extra) {
# get PR #'s as link: "PR#nnnn" "PR: nnnn, ..." "PR nnnn, ..." "bin/nnnn"
- if (defined($prcgi)) {
+ if (defined($prcgi) && defined($re_prcategories) && defined($re_prkeyword)) {
my $prev;
do {
@@ -1044,7 +1122,7 @@ sub htmlify($;$) {
$_ = htmlify_sub {
s{
- (\bPR[:\#]?\s*
+ (\b$re_prkeyword[:\#]?\s*
(?:
\#?
\d+[,\s]\s*
@@ -1059,7 +1137,7 @@ sub htmlify($;$) {
$_ = htmlify_sub {
s{
- (\b$prcategories/(\d+)\b)
+ (\b$re_prcategories/(\d+)\b)
}{
&link($1, sprintf($prcgi, $2))
}egox;
@@ -1070,7 +1148,7 @@ sub htmlify($;$) {
if (defined($mancgi)) {
$_ = htmlify_sub {
s{
- (\b([a-zA-Z][\w_.]+)
+ (\b([a-zA-Z][\w.]+)
(?:
\( ([0-9n]) \)\B
|
@@ -1078,7 +1156,7 @@ sub htmlify($;$) {
)
)
}{
- &link($1, sprintf($mancgi, $3 ne '' ? $3 : $4, $2))
+ &link($1, sprintf($mancgi, defined($3) ? $3 : $4, $2))
}egx;
} $_;
}
@@ -1120,7 +1198,7 @@ sub spacedHtmlText($;$) {
sub link($$) {
my($name, $where) = @_;
- sprintf '%s', htmlquote($where), $name;
+ sprintf '%s', hrefquote($where), $name;
}
sub revcmp($$) {
@@ -1294,7 +1372,7 @@ sub doAnnotate($$) {
# the public domain.
# we could abandon the use of rlog, rcsdiff and co using
# the cvsserver in a similiar way one day (..after rewrite)
- $pid = open2($reader, $writer, "cvs -Rl server") || fatal ("500 Internal Error",
+ $pid = open2($reader, $writer, "cvs @cvs_options -l server") || fatal ("500 Internal Error",
"Fatal Error - unable to open cvs for annotation");
# OK, first send the request to the server. A simplified example is:
@@ -1487,7 +1565,7 @@ sub doCheckout($$) {
# Safely for a child process to read from.
if (! open($fh, "-|")) { # child
open(STDERR, ">&STDOUT"); # Redirect stderr to stdout
- exec("cvs", "-Rld", $cvsroot, "co", "-p", $revopt, $where);
+ exec("cvs", @cvs_options, "-d", $cvsroot, "co", "-p", $revopt, $where);
}
if (eof($fh)) {
@@ -1564,12 +1642,12 @@ sub cvswebMarkup($$$) {
my $url = download_url($fileurl, $revision, $mimetype);
print "";
if ($mimetype =~ /^image/) {
- printf ' ', htmlquote("$url$barequery");
+ printf ' ', hrefquote("$url$barequery");
}
elsif ($mimetype =~ m%^application/pdf%) {
- printf '