More hacking on help search
[webmin.git] / webmin_search.cgi
1 #!/usr/local/bin/perl
2 # Search Webmin modules and help pages and text and config.info
3
4 BEGIN { push(@INC, ".."); };
5 use WebminCore;
6
7 &init_config();
8 &ReadParse();
9
10 $prod = &get_product_name();
11 $ucprod = ucfirst($prod);
12 &ui_print_header(undef, &text('wsearch_title', $ucprod), "", undef, 0, 1);
13
14 $re = $in{'search'};
15 if ($re !~ /\S/) {
16         &error($text{'wsearch_esearch'});
17         }
18 $re =~ s/^\s+//;
19 $re =~ s/\s+$//;
20
21 # Search module names first
22 $count = 0;
23 @mods = sort { $b->{'longdesc'} cmp $a->{'longdesc'} }
24              grep { !$_->{'clone'} } &get_available_module_infos();
25 foreach $m (@mods) {
26         if ($m->{'desc'} =~ /\Q$re\E/i || $m->{'dir'} =~ /\Q$re\E/i) {
27                 &match_row(
28                         $m,
29                         "<a href='$m->{'dir'}/'>$m->{'desc'}</a>",
30                         $text{'wsearch_mtitle'},
31                         undef,
32                         0,
33                         );
34                 }
35         }
36
37 # Then do module configs
38 foreach $m (@mods) {
39         %access = &get_module_acl(undef, $m);
40         next if ($access{'noconfig'});
41         $file = $prod eq 'webmin' ? "$m->{'dir'}/config.info"
42                                   : "$m->{'dir'}/uconfig.info";
43         %info = ( );
44         @info_order = ( );
45         &read_file($file, \%info, \@info_order);
46         foreach $o (@lang_order_list) {
47                 &read_file("$file.$o", \%info);
48                 }
49         $section = undef;
50         foreach $c (@info_order) {
51                 @p = split(/,/, $info{$c});
52                 if ($p[1] == 11) {
53                         $section = $c;
54                         }
55                 if ($p[0] =~ /\Q$re\E/i) {
56                         &match_row(
57                             $m,
58                             "<a href='config.cgi?module=$m->{'dir'}&".
59                              "section=".&urlize($section)."#$c'>$p[0]</a>",
60                             $text{'wsearch_config_'.$prod},
61                             $p[0],
62                             1,
63                             );
64                         $cgis[0]}
65                 }
66         }
67
68 # Then do help pages
69 %lang_order_list = map { $_, 1 } @lang_order_list;
70 foreach $m (@mods) {
71         $helpdir = &module_root_directory($m->{'dir'})."/help";
72         %donepage = ( );
73         opendir(DIR, $helpdir);
74         foreach $f (sort { length($b) <=> length($a) } readdir(DIR)) {
75                 # Work out if we should grep this help page - don't do the same
76                 # page twice for different languages
77                 $grep = 0;
78                 if ($f =~ /^(\S+)\.([^\.]+)\.html$/) {
79                         ($page, $lang) = ($1, $2);
80                         if ($lang_order_list{$lang} && !$donepage{$page}++) {
81                                 $grep = 1;
82                                 }
83                         }
84                 elsif ($f =~ /^(\S+)\.html$/) {
85                         $page = $1;
86                         if (!$donepage{$page}++) {
87                                 $grep = 1;
88                                 }
89                         }
90
91                 # If yes, search it
92                 if ($grep) {
93                         $data = &read_file_contents("$helpdir/$f");
94                         if ($data =~ /<header>([^<]*)<\/header>/) {
95                                 $title = $1;
96                                 }
97                         else {
98                                 $title = $f;
99                                 }
100                         $data =~ s/\s+/ /g;
101                         $data =~ s/<p>/\n\n/gi;
102                         $data =~ s/<br>/\n/gi;
103                         $data =~ s/<[^>]+>//g;
104                         if ($data =~ /\Q$re\E/i) {
105                                 @cgis = &find_cgi_text(
106                                         [ "hlink\\(.*'$page'",
107                                           "hlink\\(.*\"$page\"",
108                                         ], $m, 1);
109                                 if ($page =~ /^config_(\S+)$/) {
110                                         # Special config.info page link
111                                         # XXX where?
112                                         }
113                                 elsif (@cgis == 0) {
114                                         $link = "";
115                                         }
116                                 else {
117                                         $link = &ui_links_row([
118                                             map { my $s = $_;
119                                                   $s =~ s/^\Q$m->{'dir'}\E\///;
120                                                   "<a href='$_'>$s</a>" } @cgis
121                                             ]);
122                                         $link =~ s/<br>//;
123                                         $link = &text('wsearch_on', $link);
124                                         }
125                                 &match_row(
126                                     $m,
127                                     &hlink($title, $page, $m->{'dir'}).
128                                       " ".$link,
129                                     $text{'wsearch_help'},
130                                     $data,
131                                     1,
132                                     );
133                                 }
134                         }
135                 }
136         closedir(DIR);
137         }
138
139 # Then do text strings
140 MODULE: foreach $m (@mods) {
141         %mtext = &load_language($m->{'dir'});
142         foreach $k (keys %mtext) {
143                 if ($mtext{$k} =~ /\Q$re\E/i) {
144                         @cgis = &find_cgi_text(
145                                 [ "\$text{'$k'}",
146                                   "\$text{\"$k\"}",
147                                   "\$text{$k}" ], $m);
148                         if (@cgis == 0) {
149                                 $link = "<a href='$m->{'dir'}/'>$m->{'desc'}</a>";
150                                 }
151                         else {
152                                 $link = &ui_links_row([
153                                     map { my $s = $_;
154                                           $s =~ s/^\Q$m->{'dir'}\E\///;
155                                           "<a href='$_'>$s</a>" } @cgis ]);
156                                 $link =~ s/<br>//;
157                                 }
158                         &match_row(
159                             $m,
160                             $link,
161                             $text{'wsearch_text'},
162                             $mtext{$k},
163                             @cgis ? 1 : 0,
164                             );
165                         #next MODULE;
166                         }
167                 }
168         }
169
170 if (!$count) {
171         print "<b>",&text('wsearch_enone',
172                 "<tt>".&html_escape($re)."</tt>"),"</b><p>\n";
173         }
174
175 &ui_print_footer();
176
177 # Returns text with the search term bolded, and truncated to 60 characters
178 sub highlight_text
179 {
180 local ($str, $len) = @_;
181 $len ||= 90;
182 local $hlen = $len / 2;
183 $str =~ s/<[^>]*>//g;
184 if ($str =~ /(.*)(\Q$re\E)(.*)/i) {
185         local ($before, $match, $after) = ($1, $2, $3);
186         if (length($before) > $hlen) {
187                 $before = "...".substr($before, length($before)-$hlen);
188                 }
189         if (length($after) > $hlen) {
190                 $after = substr($after, 0, $hlen)."...";
191                 }
192         $str = $before."<b>".&html_escape($match)."</b>".$after;
193         }
194 return $str;
195 }
196
197 sub match_row
198 {
199 local ($m, $link, $what, $text, $module_link) = @_;
200 print "<font size=+1>$link</font>\n";
201 if ($module_link) {
202         print " (".&text('wsearch_inmod',
203                          "<a href='$m->{'dir'}/'>$m->{'desc'}</a>").")";
204         }
205 print "<br>\n";
206 if ($text) {
207         print &highlight_text($text),"<br>\n";
208         }
209 print "<font color=#4EBF37>$m->{'desc'} - $what</font><br>&nbsp;<br>\n";
210 $count++;
211 }
212
213 # find_cgi_text(&regexps, module, re-mode)
214 # Returns the relative URLs of CGIs that matches some regexps, in the given
215 # module.
216 sub find_cgi_text
217 {
218 local ($res, $m, $remode) = @_;
219 local $mdir = &module_root_directory($m);
220 local @rv;
221 foreach my $f (glob("$mdir/*.cgi")) {
222         local $found = 0;
223         open(CGI, $f);
224         LINE: while(my $line = <CGI>) {
225                 foreach my $r (@$res) {
226                         if (!$remode && index($line, $r) >= 0 ||
227                             $remode && $line =~ /$r/) {
228                                 $found++;
229                                 last LINE;
230                                 }
231                         }
232                 }
233         close(CGI);
234         if ($found) {
235                 local $url = $f;
236                 $url =~ s/^\Q$root_directory\E\///;
237                 push(@rv, $url);
238                 }
239         }
240 return @rv;
241 }
242