#!/usr/bin/perl -T
# Packages::Dispatcher -- CGI interface for packages.debian.org
#
-# Copyright (C) 2004-2007 Frank Lichtenheld
+# Copyright (C) 2004-2008 Frank Lichtenheld
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
use URI::Escape;
use Benchmark ':hireswallclock';
use I18N::AcceptLanguage;
+use Date::Parse;
use Deb::Versions;
use Packages::Config qw( $DBDIR $ROOT $TEMPLATEDIR $CACHEDIR
delete $ENV{'LC_ALL'};
delete $ENV{'LC_MESSAGES'};
- my %SUITES_ALIAS = ( oldstable => 'sarge',
- stable => 'etch',
- testing => 'lenny',
+ my %SUITES_ALIAS = ( oldstable => 'etch',
+ stable => 'lenny',
+ testing => 'squeeze',
unstable => 'sid',
- '3.1' => 'sarge',
- '4.0' => 'etch' );
+ '4.0' => 'etch',
+ '5.0' => 'lenny' );
# Read in all the variables set by the form
my $input;
my $homedir = dirname($ENV{SCRIPT_FILENAME}).'/../';
&Packages::Config::init( $homedir );
&Packages::DB::init();
+ my $last_modified = $Packages::DB::db_read_time;
+ my $now = time;
+ my $expires = $last_modified + (365*24*3600);
+ $expires = $now + 3600 if $expires < $now;
+ # allow some fudge, since the db mod time is not the end of
+ # the cron job
+ $last_modified = $now if $now - $last_modified < 3600;
+
+ if ($input->http('If-Modified-Since') and
+ (my $modtime = str2time($input->http('If-Modified-Since'), 'UTC'))) {
+ if ($modtime <= $last_modified) {
+ print $input->header(-status => 304);
+ exit;
+ }
+ }
- my $acc = I18N::AcceptLanguage->new();
- my %all_langs = map { $_ => 1 } (@LANGUAGES, @DDTP_LANGUAGES);
- my @all_langs = sort keys %all_langs;
- my $http_lang = $acc->accepts( $input->http("Accept-Language"),
- \@all_langs ) || 'en';
- debug( "LANGUAGES=@all_langs header=".
+ my %PO_LANGUAGES = map { $_ => 1 } @LANGUAGES;
+ my %DDTP_LANGUAGES = map { $_ => 1 } @DDTP_LANGUAGES;
+ my $acc = I18N::AcceptLanguage->new(defaultLanguage => 'en');
+ my $ddtp_lang = $acc->accepts( $input->http("Accept-Language"),
+ \@DDTP_LANGUAGES );
+ my $po_lang = $acc->accepts( $input->http("Accept-Language"),
+ \@LANGUAGES );
+ debug( "LANGS=@LANGUAGES DDTP_LANGS=@DDTP_LANGUAGES header=".
($input->http("Accept-Language")||'').
- " http_lang=$http_lang", 1 ) if DEBUG;
+ " po_lang=$po_lang ddtp_lang=$ddtp_lang", 1 ) if DEBUG;
# backwards compatibility stuff
debug( "SCRIPT_URL=$ENV{SCRIPT_URL} SCRIPT_URI=$ENV{SCRIPT_URI}" ) if DEBUG;
push @components, 'index' if @components && $path =~ m,/$,;
- my %LANGUAGES = map { $_ => 1 } @all_langs;
+ my %LANGUAGES = map { $_ => 1 } (@LANGUAGES, @DDTP_LANGUAGES);
if (@components > 1 and $LANGUAGES{$components[0]}
and !$input->param('lang')) {
$input->param( 'lang', shift(@components) );
} elsif (@components == 0) {
fatal_error( "We're supposed to display the homepage here, instead of getting dispatch.pl" );
} elsif (@components == 1) {
- $what_to_do = 'search';
+ if ($components[0] eq 'index') {
+ $what_to_do = 'homepage';
+ } else {
+ $what_to_do = 'search';
+ }
} else {
for ($components[-1]) {
set_param_once( $input, \%params_set, 'suite', $s);
} elsif (!$need_pkg && $SECTIONS{$_}) {
set_param_once( $input, \%params_set, 'section', $_);
- } elsif (!$need_pkg && $ARCHIVES{$_}) {
- set_param_once( $input, \%params_set, 'archive', $_);
} elsif (!$need_pkg && $sections_descs{$_}) {
set_param_once( $input, \%params_set, 'subsection', $_);
} elsif (!$need_pkg && ($_ eq 'source')) {
} elsif ($ARCHITECTURES{$_}) {
set_param_once( $input, \%params_set, 'arch', $_)
unless $_ eq 'any';
+ } elsif (!$need_pkg && $ARCHIVES{$_}) {
+ set_param_once( $input, \%params_set, 'archive', $_);
} elsif ($PRIORITIES{$_}) {
set_param_once( $input, \%params_set, 'priority', $_);
} else {
replace => { all => \@ARCHIVES,
default => \@ARCHIVES} },
exact => { default => 0, match => '^(\w+)$', },
- lang => { default => $http_lang, match => '^(\w+)$', },
+ lang => { default => undef, match => '^([\w-]+)$', },
source => { default => 0, match => '^(\d+)$', },
debug => { default => 0, match => '^(\d+)$', },
searchon => { default => 'names', match => '^(\w+)$', },
my %params = Packages::CGI::parse_params( $input, \%params_def, \%opts );
Packages::CGI::init_url( $input, \%params, \%opts );
+ if (defined($opts{lang})) {
+ $opts{po_lang} = $PO_LANGUAGES{$opts{lang}} ? $opts{lang} : 'en';
+ $opts{ddtp_lang} = $DDTP_LANGUAGES{$opts{lang}} ? $opts{lang} : 'en';
+ } else {
+ $opts{po_lang} = $po_lang;
+ $opts{ddtp_lang} = $ddtp_lang;
+ }
my $charset = "UTF-8";
- my $cat = Packages::I18N::Locale->get_handle( $opts{lang} )
- || Packages::I18N::Locale->get_handle( 'en' );
- die "get_handle failed for $opts{lang}" unless $cat;
+ my $cat = Packages::I18N::Locale->get_handle( $opts{po_lang}, 'en' )
+ or die "get_handle failed for $opts{po_lang}";
$opts{cat} = $cat;
$opts{h_suites} = { map { $_ => 1 } @suites };
debug( "Parameter evaluation took ".timestr($petd) ) if DEBUG;
my $template = new Packages::Template( $TEMPLATEDIR, $opts{format},
- { lang => $opts{lang}, charset => $charset,
- cat => $cat,
+ { po_lang => $opts{po_lang}, ddtp_lang => $opts{ddtp_lang},
+ charset => $charset, cat => $cat,
debug => ( DEBUG ? $opts{debug} : 0 ) },
( $CACHEDIR ? { COMPILE_DIR => $CACHEDIR } : {} ) );
#FIXME: ugly hack
unless (($what_to_do eq 'allpackages' and $opts{format} =~ /^(html|txt\.gz)/)
+ || ($what_to_do eq 'index' and $opts{format} eq 'html')
|| -e "$TEMPLATEDIR/$opts{format}/${what_to_do}.tmpl") {
fatal_error( $cat->g("requested format not available for this document"),
"406 requested format not available");
$page_content{params} = \%params;
unless (@Packages::CGI::fatal_errors) {
- print $input->header(-charset => $charset, -type => get_mime($opts{format}) );
+ print $input->header(-charset => $charset,
+ -type => get_mime($opts{format}),
+ -vary => 'negotiate,accept-language',
+ -last_modified => strftime("%a, %d %b %Y %T %z",
+ localtime($last_modified)),
+ -expires => strftime("%a, %d %b %Y %T %z",
+ localtime($expires)),
+ );
#use Data::Dumper;
#print '<pre>'.Dumper(\%ENV, \%page_content, get_all_messages()).'</pre>';
print $template->page( $what_to_do, { %page_content, %{ get_all_messages() } } );