Work on including links to text in 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                                 &match_row(
106                                     $m,
107                                     &hlink($title, $page, $m->{'dir'}),
108                                     $text{'wsearch_help'},
109                                     $data,
110                                     1,
111                                     );
112                                 }
113                         }
114                 }
115         closedir(DIR);
116         }
117
118 # Then do text strings
119 MODULE: foreach $m (@mods) {
120         %mtext = &load_language($m->{'dir'});
121         foreach $k (keys %mtext) {
122                 if ($mtext{$k} =~ /\Q$re\E/i) {
123                         @cgis = &find_cgi_text(
124                                 [ "\$text{'$k'}",
125                                   "\$text{\"$k\"}",
126                                   "\$text{$k}" ], $m);
127                         if (@cgis == 0) {
128                                 $link = "<a href='$m->{'dir'}/'>$m->{'desc'}</a>";
129                                 }
130                         else {
131                                 $link = &ui_links_row([
132                                     map { "<a href='$_'>$_</a>" } @cgis ]);
133                                 $link =~ s/<br>//;
134                                 }
135                         &match_row(
136                             $m,
137                             $link,
138                             $text{'wsearch_text'},
139                             $mtext{$k},
140                             @cgis ? 1 : 0,
141                             );
142                         #next MODULE;
143                         }
144                 }
145         }
146
147 if (!$count) {
148         print "<b>",&text('wsearch_enone',
149                 "<tt>".&html_escape($re)."</tt>"),"</b><p>\n";
150         }
151
152 &ui_print_footer();
153
154 # Returns text with the search term bolded, and truncated to 60 characters
155 sub highlight_text
156 {
157 local ($str, $len) = @_;
158 $len ||= 90;
159 local $hlen = $len / 2;
160 if ($str =~ /(.*)(\Q$re\E)(.*)/i) {
161         local ($before, $match, $after) = ($1, $2, $3);
162         if (length($before) > $hlen) {
163                 $before = "...".substr($before, length($before)-$hlen);
164                 }
165         if (length($after) > $hlen) {
166                 $after = substr($after, 0, $hlen)."...";
167                 }
168         $str = $before."<b>".&html_escape($match)."</b>".$after;
169         }
170 return $str;
171 }
172
173 sub match_row
174 {
175 local ($m, $link, $what, $text, $module_link) = @_;
176 print "<font size=+1>$link</font>\n";
177 if ($module_link) {
178         print " (".&text('wsearch_inmod',
179                          "<a href='$m->{'dir'}/'>$m->{'desc'}</a>").")";
180         }
181 print "<br>\n";
182 if ($text) {
183         print &highlight_text($text),"<br>\n";
184         }
185 print "<font color=#4EBF37>$m->{'desc'} - $what</font><br>&nbsp;<br>\n";
186 $count++;
187 }
188
189 # find_cgi_text(&regexps, module)
190 # Returns the relative URLs of CGIs that matches some regexps, in the given
191 # module.
192 sub find_cgi_text
193 {
194 local ($res, $m) = @_;
195 local $mdir = &module_root_directory($m);
196 local @rv;
197 foreach my $f (glob("$mdir/*.cgi")) {
198         local $found = 0;
199         open(CGI, $f);
200         LINE: while(my $line = <CGI>) {
201                 foreach my $r (@$res) {
202                         if (index($line, $r) >= 0) {
203                                 $found++;
204                                 last LINE;
205                                 }
206                         }
207                 }
208         close(CGI);
209         if ($found) {
210                 local $url = $f;
211                 $url =~ s/^\Q$root_directory\E\///;
212                 push(@rv, $url);
213                 }
214         }
215 return @rv;
216 }
217