wesnoth/utils/webtgz.pl
Bruno Wolff III 3d7ae7bd28 webtgz.pl wasn't handling escaped data in downloaded file contents.
This was causing problems for binary files.
2005-10-17 13:03:08 +00:00

349 lines
11 KiB
Perl
Executable File

#!/usr/bin/perl
use wml;
use wml_net;
use Archive::Tar;
use CGI qw/:standard -no_xhtml/;
use strict;
my ($host, $port) = ("campaigns.wesnoth.org", 15002);
my $style = 'http://www.wesnoth.org/mw/skins/glamdrol/main.css';
my $socket = eval {&wml_net::connect($host,$port)};
if ($@ ne '') {
print header, start_html(-style=>{'src'=>$style},
-title=>'Error accessing the campaign server.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(escapeHTML($@)), end_html;
exit;
}
if (!defined($socket)) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Error connecting to the campaign server.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p('Error connecting to the campaign server.'), end_html;
exit;
}
my $name = url(-relative=>1);
if ($name =~ m/^(.*)\.tgz$/) {
$name = $1;
}
else {
print header, start_html(-style=>{'src'=>$style},
-title=>'Invalid campaign name URL.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p('Campaigns are only available as gzipped tar archives (.tgz files).'),
end_html;
exit;
}
if ($name =~ m/^\./) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Invalid campaign name.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(em($name),
'is an invalid campaign name because it begins with a period.'),
end_html;
exit;
}
if ($name =~ m;/;) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Invalid campaign name.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(em($name),
'is an invalid campaign name because it contains a forward slash (/).'),
end_html;
exit;
}
if ($name =~ m/^$/) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Invalid campaign name.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(em($name),
'is an invalid campaign name because it is the empty string.'),
end_html;
exit;
}
eval {
&wml_net::write_packet($socket,&wml::read_text("
[request_campaign_list]
name=\"$name\"
[/request_campaign_list]"));
};
if ($@ ne '') {
print header, start_html(-style=>{'src'=>$style},
-title=>'Error accessing the campaign server.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(escapeHTML($@)), end_html;
exit;
}
my $response = eval {&wml_net::read_packet($socket)};
if ($@ ne '') {
print header, start_html(-style=>{'src'=>$style},
-title=>'Error accessing the campaign server.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(escapeHTML($@)), end_html;
exit;
}
if (!defined($response)) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Error accessing the campaign server.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p('Error accessing the campaign server.'), end_html;
exit;
}
if (my $error = &wml::has_child($response, 'error')) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Error accessing the campaign server.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(escapeHTML($error->{'attr'}->{'message'})), end_html;
exit;
}
my $campaign_list = &wml::has_child($response, 'campaigns');
if (!$campaign_list) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Error retrieving campaign list.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p('No', em('campaigns'), 'data returned.'), end_html;
exit;
}
my @campaigns = &wml::get_children($campaign_list,'campaign');
my $version = undef;
my $timestamp = '';
foreach my $campaign (@campaigns) {
foreach my $field ('name', 'version', 'timestamp') {
$campaign->{'attr'}->{$field} = ''
unless defined($campaign->{'attr'}->{$field});
$campaign->{'attr'}->{$field} =~ s/\001[^\003]*\003//g;
$campaign->{'attr'}->{$field} =~ s/[\001-\037\177-\237]/ /g;
}
$campaign->{'attr'}->{'name'} =~ s;\s|/|\\;;g;
if ($name eq $campaign->{'attr'}->{'name'}) {
$version = $campaign->{'attr'}->{'version'};
$timestamp = $campaign->{'attr'}->{'timestamp'};
last;
}
}
undef @campaigns;
if (!defined($version)) {
unlink("version/$name.ver");
unlink("tgz/$name.tgz");
unlink("timestamp/$name.ver");
print header, start_html(-style=>{'src'=>$style},
-title=>'Error retrieving campaign information.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p('No information was retrievable for the campaign', em($name) . '.'),
end_html;
exit;
}
my $cached = 1;
if (open(VERS, "<version/$name.ver")) {
my $vers = <VERS>;
$cached = 0 unless $vers eq $version;
close VERS;
}
else {
$cached = 0;
}
if (open(VERS, "<timestamp/$name.ver")) {
my $ts = <VERS>;
$cached = 0 unless $ts eq $timestamp;
close VERS;
}
else {
$cached = 0;
}
if (!$cached) {
unlink("version/$name.ver");
unlink("tgz/$name.tgz");
unlink("timestamp/$name.ver");
my $archive = Archive::Tar->new();
eval {
&wml_net::write_packet($socket, &wml::read_text("
[request_campaign]
name=\"$name\"
[/request_campaign]"));
};
if ($@ ne '') {
print header, start_html(-style=>{'src'=>$style},
-title=>'Error accessing the campaign server.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(escapeHTML($@)), end_html;
exit;
}
my $response = eval {&wml_net::read_packet($socket)};
if ($@ ne '') {
print header, start_html(-style=>{'src'=>$style},
-title=>'Error accessing the campaign server.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(escapeHTML($@)), end_html;
exit;
}
if (!defined($response)) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Campaign server error while attempting to retrieve campaign.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p('Campaign server error while attempting to retrieve campaign.'),
end_html;
exit;
}
if (my $error = &wml::has_child($response, 'error')) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Campaign server error while attempting to retrieve campaign.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p(escapeHTML($error->{'attr'}->{'message'})), end_html;
exit;
}
$version = $response->{'attr'}->{'version'}
if defined($response->{'attr'}->{'version'});
$timestamp = $response->{'attr'}->{'timestamp'}
if defined($response->{'attr'}->{'timestamp'});
&archive_dir($archive, $response, '');
$archive->write("tgz/$name.$$", 1);
if (!open(VERS, ">version/$name.$$")) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Unable to cache campaign.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p('Unable to cache campaign.'),
end_html;
exit;
}
print VERS $version;
close VERS;
if (!open(VERS, ">timestamp/$name.$$")) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Unable to cache campaign.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p('Unable to cache campaign.'),
end_html;
exit;
}
print VERS $timestamp;
close VERS;
rename "tgz/$name.$$", "tgz/$name.tgz";
rename "version/$name.$$", "version/$name.ver";
rename "timestamp/$name.$$", "timestamp/$name.ver";
undef $archive;
undef $response;
}
if (!open(TGZ, "<tgz/$name.tgz")) {
print header, start_html(-style=>{'src'=>$style},
-title=>'Unable to read cached copy of the campaign.');
print div({id=>'header'}, div({id=>'logo'}, a({href=>'http://www.wesnoth.org/'},
img({alt=>'Wesnoth logo',
src=>'http://wesnoth.org/mw/skins/glamdrol/wesnoth-logo.jpg'}))));
print p('Unable to read cached copy of the campaign.'),
end_html;
exit;
}
print "Content-Type: application/x-gzip\r\n",
"Content-disposition: attachment; filename=\"$name.tgz\"\r\n\r\n";
my $buf;
while (read(TGZ, $buf, 16384)) {
print $buf;
}
exit;
sub archive_dir
{
my ($archive, $doc, $dest) = @_;
my $name = $doc->{'attr'}->{'name'};
my $path;
if ($name ne '') {
if ($dest eq '') {
$path = $name;
}
else {
$path = "$dest/$name";
}
}
else {
$path = $dest;
}
foreach my $dir (&wml::get_children($doc, 'dir')) {
&archive_dir($archive, $dir, $path);
}
foreach my $file (&wml::get_children($doc, 'file')) {
my $filename;
if ($path eq '') {
$filename = $file->{'attr'}->{'name'};
}
else {
$filename = "$path/" . $file->{'attr'}->{'name'};
}
my @contents = split(//, $file->{'attr'}->{'contents'});
my $contents = '';
while(@contents) {
my $char = shift @contents;
if (1 == ord $char) {
$char = chr(ord(shift @contents) - 1);
}
$contents .= $char;
}
$archive->add_data($filename, $contents,
{'uname'=>'root', 'gname'=>'root', 'uid'=>0, 'gid'=>0, 'mode'=>0644});
}
}