]> git.deb.at Git - deb/packages.git/blob - lib/Packages/DoSearchContents.pm
f66ba875a98c7fa54f2ddbb6930c87c6766b4c5a
[deb/packages.git] / lib / Packages / DoSearchContents.pm
1 package Packages::DoSearchContents;
2
3 use strict;
4 use warnings;
5
6 use Benchmark;
7 use DB_File;
8 use URI::Escape;
9 use HTML::Entities;
10 use Exporter;
11 our @ISA = qw( Exporter );
12 our @EXPORT = qw( do_search_contents );
13
14 use Deb::Versions;
15 use Packages::Search qw( :all );
16 use Packages::CGI;
17 use Packages::DB;
18 use Packages::Config qw( $DBDIR $SEARCH_URL $SEARCH_CGI $SEARCH_PAGE
19                          @SUITES @ARCHIVES $ROOT );
20
21 sub do_search_contents {
22     my ($params, $opts, $html_header, $menu, $page_content) = @_;
23
24     if ($params->{errors}{keywords}) {
25         fatal_error( "keyword not valid or missing" );
26     } elsif (length($opts->{keywords}) < 2) {
27         fatal_error( "keyword too short (keywords need to have at least two characters)" );
28     }
29
30     $$menu = "";
31     
32     my $keyword = $opts->{keywords};
33     my $searchon = $opts->{searchon};
34     my $exact = $opts->{exact};
35
36     # for URL construction
37     my $keyword_esc = uri_escape( $keyword );
38     my $suites_param = join ',', @{$params->{values}{suite}{no_replace}};
39     my $sections_param = join ',', @{$params->{values}{section}{no_replace}};
40     my $archs_param = join ',', @{$params->{values}{arch}{no_replace}};
41
42     # for output
43     my $keyword_enc = encode_entities $keyword || '';
44     my $searchon_enc = encode_entities $searchon;
45     my $suites_enc = encode_entities( join( ', ', @{$params->{values}{suite}{no_replace}} ) );
46     my $sections_enc = encode_entities( join( ', ', @{$params->{values}{section}{no_replace}} ) );
47     my $archs_enc = encode_entities( join( ', ',  @{$params->{values}{arch}{no_replace}} ) );
48     
49     my $st0 = new Benchmark;
50     my (@results, @non_results);
51
52     unless (@Packages::CGI::fatal_errors) {
53
54         my $nres = 0;
55
56         my $kw = lc $keyword;
57         # full filename search is tricky
58         my $ffn = $searchon eq 'filenames';
59
60         my $suite = 'stable'; #fixme
61
62         my $reverses = tie my %reverses, 'DB_File', "$DBDIR/contents/reverse_$suite.db",
63             O_RDONLY, 0666, $DB_BTREE
64             or die "Failed opening reverse DB: $!";
65
66         if ($ffn) {
67             open FILENAMES, '-|', 'fgrep', '--', "$kw", "$DBDIR/contents/filenames_$suite.txt"
68                 or die "Failed opening filename table: $!";
69             while (<FILENAMES>) {
70                 chomp;
71                 last unless &searchfile(\@results, reverse($_)."/", \$nres, $reverses);
72             }
73             close FILENAMES;
74         } else {
75
76             $kw = reverse $kw;
77             
78             # exact filename searching follows trivially:
79             $kw = "$kw/" if $exact;
80
81             print "ERROR: Exact and fullfilenamesearch don't go along" if $ffn and $exact;
82
83             &searchfile(\@results, $kw, \$nres, $reverses);
84         }
85         $reverses = undef;
86         untie %reverses;
87
88     
89         my $st1 = new Benchmark;
90         my $std = timediff($st1, $st0);
91         debug( "Search took ".timestr($std) );
92     }
93     
94     my $suite_wording = $suites_enc eq "all" ? "all suites"
95         : "suite(s) <em>$suites_enc</em>";
96     my $section_wording = $sections_enc eq 'all' ? "all sections"
97         : "section(s) <em>$sections_enc</em>";
98     my $arch_wording = $archs_enc eq 'any' ? "all architectures"
99         : "architecture(s) <em>$archs_enc</em>";
100     my $wording = $opts->{exact} ? "exact filenames" : "filenames that contain";
101     $wording = "paths that end with" if $searchon eq "contents";
102     msg( "You have searched for ${wording} <em>$keyword_enc</em> in $suite_wording, $section_wording, and $arch_wording." );
103
104     if ($Packages::Search::too_many_hits) {
105         error( "Your search was too wide so we will only display exact matches. At least <em>$Packages::Search::too_many_hits</em> results have been omitted and will not be displayed. Please consider using a longer keyword or more keywords." );
106     }
107     
108     $$page_content = '';
109     if (!@Packages::CGI::fatal_errors && !@results) {
110         $$page_content .= "No results";
111     }
112
113     %$html_header = ( title => 'Package Contents Search Results' ,
114                       lang => 'en',
115                       title_tag => 'Debian Package Contents Search Results',
116                       print_title => 1,
117                       print_search_field => 'packages',
118                       search_field_values => { 
119                           keywords => $keyword_enc,
120                           searchon => 'contents',
121                           arch => $archs_enc,
122                           suite => $suites_enc,
123                           section => $sections_enc,
124                           exact => $opts->{exact},
125                           debug => $opts->{debug},
126                       },
127                       );
128
129     if (@results) {
130         $$page_content .= scalar @results . " results displayed:<br>";
131         foreach (@results) {
132             $$page_content .= "<tt>$_</tt><br>\n";
133         }
134     }
135 } # sub do_search_contents
136
137 sub searchfile
138 {
139     my ($results, $kw, $nres, $reverses) = @_;
140
141     my ($key, $value) = ($kw, "");
142     for (my $status = $reverses->seq($key, $value, R_CURSOR);
143         $status == 0;
144         $status =  $reverses->seq( $key, $value, R_NEXT)) {
145
146         # FIXME: what's the most efficient "is prefix of" thingy? We only want to know
147         # whether $kw is or is not a prefix of $key
148         last unless index($key, $kw) == 0;
149
150         my @hits = split /\0/o, $value;
151         push @$results, reverse($key)." is found in @hits";
152         last if ($$nres)++ > 100;
153     }
154
155 # FIXME: use too_many_hits
156     return $$nres<100;
157 }
158
159
160 1;