Added cron job to cleanup /tmp/.webmin
[webmin.git] / config-lib.pl
1 # config-lib.pl
2 # Common functions for parsing config.info files
3 # Each module has a number of configurable parameters (stored in the config and
4 # config-* files in the module directory). Descriptions and possible values for
5 # each option are stored in the file config.info in the module directory.
6 # Each line of config.info looks like
7 # name=desc,type[,options]
8 #  desc - A description of the parameter
9 #  type - Possible types (and options) are
10 #       0 - Free text
11 #       1 - One of many (options are possibilities)
12 #       2 - Many of many (options are possibilities)
13 #       3 - Optional free text
14 #       4 - Like 1, but uses a pulldown menu
15 #       5 - User name
16 #       6 - Group name
17 #       7 - Directory
18 #       8 - File
19 #       9 - Multiline text
20 #       10 - Like 1, but with free text option
21 #       11 - Section header
22 #       12 - Password free text, with don't change option
23 #       13 - Like 2, but uses a list box
24 #       14 - Parameter is the name of a function in config_info.pl that
25 #            returns an alternate set of config.info values.
26 #       15 - Parameter is the suffix for a pair of functions with show_
27 #            and parse_ prepended.
28 #       16 - Password free text
29
30 # generate_config(&config, info-file, [module], [&can-config], [checkbox-name],
31 #                 [only-section])
32 # Prints HTML for 
33 sub generate_config
34 {
35 local ($configref, $file, $module, $canconfig, $cbox, $section) = @_;
36 local %config = %$configref;
37
38 # Read the .info file in the right language
39 local (%info, @info_order, %einfo, $o);
40 &read_file($file, \%info, \@info_order);
41 %einfo = %info;
42 foreach $o (@lang_order_list) {
43         &read_file("$file.$o", \%info, \@info_order);
44         }
45 @info_order = &unique(@info_order);
46
47 if ($section) {
48         # Limit to settings in one section
49         @info_order = &config_in_section($section, \@info_order, \%info);
50         }
51
52 # Show the parameter editors
53 local $c;
54 foreach $c (@info_order) {
55         local $checkhtml;
56         if ($cbox) {
57                 # Show checkbox to allow configuring
58                 $checkhtml = &ui_checkbox($cbox, $c, "",
59                                           !$canconfig || $canconfig->{$c});
60                 }
61         else {
62                 # Skip those not allowed to be configured
63                 next if ($canconfig && !$canconfig->{$c});
64                 }
65         local @p = split(/,/, $info{$c});
66         local @ep = split(/,/, $einfo{$c});
67         if (scalar(@ep) > scalar(@p)) {
68                 push(@p, @ep[scalar(@p) .. @ep-1]);
69                 }
70         if ($p[1] == 14) {
71                 $module || &error($text{'config_ewebmin'});
72                 &foreign_require($module, "config_info.pl");
73                 local @newp = &foreign_call($module, $p[2], @p);
74                 $newp[0] ||= $p[0];
75                 @p = @newp;
76                 }
77         if ($p[1] == 11) {
78                 # Title row
79                 print &ui_table_row(undef, "<b>$p[0]</b>", 2, [ undef, $tb ]);
80                 next;
81                 }
82         if ($p[1] == 16 && $gconfig{'config_16_insecure'}) {
83                 # Don't allow mode 16
84                 $p[1] = 12;
85                 }
86         local $label;
87         if ($module && -r &help_file($module, "config_$c")) {
88                 $label = $checkhtml." ".
89                          &hlink($p[0], "config_$c", $module);
90                 }
91         else {
92                 $label = $checkhtml." ".$p[0];
93                 }
94         local $field;
95         if ($p[1] == 0) {
96                 # Text value
97                 $field = &ui_textbox($c, $config{$c}, $p[2] || 40, 0, $p[3]).
98                          " ".$p[4];
99                 }
100         elsif ($p[1] == 1) {
101                 # One of many
102                 local $len = 0;
103                 for($i=2; $i<@p; $i++) {
104                         $p[$i] =~ /^(\S*)\-(.*)$/;
105                         $len += length($2);
106                         }
107                 local @opts;
108                 for($i=2; $i<@p; $i++) {
109                         $p[$i] =~ /^(\S*)\-(.*)$/;
110                         push(@opts, [ $1, $2.($len > 50 ? "<br>" : "") ]);
111                         }
112                 $field = &ui_radio($c, $config{$c}, \@opts);
113                 }
114         elsif ($p[1] == 2) {
115                 # Many of many
116                 local %sel;
117                 map { $sel{$_}++ } split(/,/, $config{$c});
118                 for($i=2; $i<@p; $i++) {
119                         $p[$i] =~ /^(\S*)\-(.*)$/;
120                         $field .= &ui_checkbox($c, $1, $2, $sel{$1});
121                         }
122                 }
123         elsif ($p[1] == 3) {
124                 # Optional value
125                 local $none = $p[2] ? $p[2] : $text{'config_none'};
126                 $field = &ui_opt_textbox($c, $config{$c}, $p[3] || 20, $none,
127                                          undef, 0, undef, $p[4])." ".$p[5];
128                 }
129         elsif ($p[1] == 4) {
130                 # One of many menu
131                 local @opts;
132                 for($i=2; $i<@p; $i++) {
133                         $p[$i] =~ /^(\S*)\-(.*)$/;
134                         push(@opts, [ $1, $2 ]);
135                         }
136                 $field = &ui_select($c, $config{$c}, \@opts);
137                 }
138         elsif ($p[1] == 5) {
139                 # User chooser
140                 if ($p[2]) {
141                         $field = &ui_radio($c."_def", $config{$c} ? 0 : 1,
142                                            [ [ 1, $p[2] ], [ 0, " " ] ]);
143                         }
144                 if ($p[3]) {
145                         $field .= &ui_textbox($c, $config{$c}, 30)." ".
146                                   &user_chooser_button($c, 1);
147                         }
148                 else {
149                         $field .= &unix_user_input($c, $config{$c});
150                         }
151                 }
152         elsif ($p[1] == 6) {
153                 # Group chooser
154                 if ($p[2]) {
155                         $field = &ui_radio($c."_def", $config{$c} ? 0 : 1,
156                                            [ [ 1, $p[2] ], [ 0, " " ] ]);
157                         }
158                 if ($p[3]) {
159                         $field .= &ui_textbox($c, $config{$c}, 30)." ".
160                                   &group_chooser_button($c, 1);
161                         }
162                 else {
163                         $field .= &unix_group_input($c, $config{$c});
164                         }
165                 }
166         elsif ($p[1] == 7) {
167                 # Directory chooser
168                 $field = &ui_textbox($c, $config{$c}, 40)." ".
169                          &file_chooser_button($c, 1);
170                 }
171         elsif ($p[1] == 8) {
172                 # File chooser
173                 $field = &ui_textbox($c, $config{$c}, 40)." ".
174                          &file_chooser_button($c, 0);
175                 }
176         elsif ($p[1] == 9) {
177                 # Text area
178                 local $cols = $p[2] || 40;
179                 local $rows = $p[3] || 5;
180                 local $sp = $p[4] ? eval "\"$p[4]\"" : " ";
181                 $field = &ui_textarea($c, join("\n", split(/$sp/, $config{$c})),
182                                       $rows, $cols);
183                 }
184         elsif ($p[1] == 10) {
185                 # Radios with freetext option
186                 local $len = 20;
187                 for($i=2; $i<@p; $i++) {
188                         if ($p[$i] =~ /^(\S*)\-(.*)$/) {
189                                 $len += length($2);
190                                 }
191                         else {
192                                 $len += length($p[$i]);
193                                 }
194                         }
195                 local $fv = $config{$c};
196                 local @opts;
197                 for($i=2; $i<@p; $i++) {
198                         ($p[$i] =~ /^(\S*)\-(.*)$/) || next;
199                         push(@opts, [ $1, $2.($len > 50 ? "<br>" : "") ]);
200                         $fv = undef if ($config{$c} eq $1);
201                         }
202                 push(@opts, [ "free", $p[$#p] !~ /^(\S*)\-(.*)$/ ? $p[$#p]
203                                                                  : " " ]);
204                 $field = &ui_radio($c, $fv ? "free" : $config{$c}, \@opts)." ".
205                          &ui_textbox($c."_free", $fv, 20);
206                 }
207         elsif ($p[1] == 12) {
208                 # Password field
209                 $field = &ui_radio($c."_nochange", 1,
210                                    [ [ 1, $text{'config_nochange'} ],
211                                      [ 0, $text{'config_setto'} ] ])." ".
212                          &ui_password($c, undef, $p[2] || 40, 0, $p[3]);
213                 }
214         elsif ($p[1] == 13) {
215                 # Multiple selections from menu
216                 local @sel = split(/,/, $config{$c});
217                 local @opts;
218                 for($i=2; $i<@p; $i++) {
219                         $p[$i] =~ /^(\S*)\-(.*)$/;
220                         push(@opts, [ $1, $2 ]);
221                         }
222                 $field = &ui_select($c, \@sel, \@opts, 5, 1);
223                 }
224         elsif ($p[1] == 15) {
225                 # Input generated by function
226                 $module || &error($text{'config_ewebmin'});
227                 &foreign_require($module, "config_info.pl");
228                 $field = &foreign_call($module, "show_".$p[2],
229                                        $config{$c}, @p);
230                 }
231         elsif ($p[1] == 16) {
232                 # Password free text
233                 $field = &ui_password($c, undef, $p[2] || 40, 0, $p[3]);
234                 }
235         print &ui_table_row($label, $field, 1, [ "width=30% nowrap" ]);
236         }
237 }
238
239 # parse_config(&config, info-file, [module], [&canconfig], [section])
240 # Updates the specified configuration with values from %in
241 sub parse_config
242 {
243 local ($config, $file, $module, $canconfig, $section) = @_;
244
245 # Read the .info file
246 local (%info, @info_order, $o);
247 &read_file($file, \%info, \@info_order);
248 foreach $o (@lang_order_list) {
249         &read_file("$file.$o", \%info, \@info_order);
250         }
251 @info_order = &unique(@info_order);
252
253 if ($section) {
254         # Limit to settings in one section
255         @info_order = &config_in_section($section, \@info_order, \%info);
256         }
257
258 # Actually parse the inputs
259 local $c;
260 foreach $c (@info_order) {
261         next if ($canconfig && !$canconfig->{$c});
262         local @p = split(/,/, $info{$c});
263         if ($p[1] == 14) {
264                 $_[2] || &error($text{'config_ewebmin'});
265                 &foreign_require($_[2], "config_info.pl");
266                 local @newp = &foreign_call($_[2], $p[2]);
267                 $newp[0] ||= $p[0];
268                 @p = @newp;
269                 }
270         if ($p[1] == 16 && $gconfig{'config_16_insecure'}) {
271                 # Don't allow mode 16
272                 $p[1] = 12;
273                 }
274         if ($p[1] == 0 || $p[1] == 7 || $p[1] == 8 || $p[1] == 16) {
275                 # Free text input
276                 $config->{$c} = $in{$c};
277                 }
278         elsif ($p[1] == 1 || $p[1] == 4) {
279                 # One of many
280                 $config->{$c} = $in{$c};
281                 }
282         elsif ($p[1] == 5 || $p[1] == 6) {
283                 # User or group
284                 $config->{$c} = ($p[2] && $in{$c."_def"} ? "" : $in{$c});
285                 }
286         elsif ($p[1] == 2 || $p[1] == 13) {
287                 # Many of many
288                 $in{$c} =~ s/\0/,/g;
289                 $config->{$c} = $in{$c};
290                 }
291         elsif ($p[1] == 3) {
292                 # Optional free text
293                 if ($in{$c."_def"}) { $config->{$c} = ""; }
294                 else { $config->{$c} = $in{$c}; }
295                 }
296         elsif ($p[1] == 9) {
297                 # Multilines of free text
298                 local $sp = $p[4] ? eval "\"$p[4]\"" : " ";
299                 $in{$c} =~ s/\r//g;
300                 $in{$c} =~ s/\n/$sp/g;
301                 $in{$c} =~ s/\s+$//;
302                 $config->{$c} = $in{$c};
303                 }
304         elsif ($p[1] == 10) {
305                 # One of many or free text
306                 if ($in{$c} eq 'free') {
307                         $config->{$c} = $in{$c.'_free'};
308                         }
309                 else {
310                         $config->{$c} = $in{$c};
311                         }
312                 }
313         elsif ($p[1] == 12) {
314                 # Optionally changed password
315                 if (!$in{"${c}_nochange"}) {
316                         $config->{$c} = $in{$c};
317                         }
318                 }
319         elsif ($p[1] == 15) {
320                 # Parse custom HTML field
321                 $_[2] || &error($text{'config_ewebmin'});
322                 &foreign_require($_[2], "config_info.pl");
323                 local $pkg = $_[2];
324                 $pkg =~ s/[^A-Za-z0-9]/_/g;
325                 eval "\%${pkg}::in = \%in";
326                 $config->{$c} = &foreign_call($_[2], "parse_".$p[2],
327                                             $config->{$c}, @p);
328                 }
329         }
330 }
331
332 # config_in_section(&section, &order, &config-info)
333 # Returns a list of config names that are in some section
334 sub config_in_section
335 {
336 local ($section, $info_order, $info) = @_;
337 my @new_order = ( );
338 my $in_section = 0;
339 foreach my $c (@$info_order) {
340         local @p = split(/,/, $info->{$c});
341         if ($p[1] == 11 && $c eq $section) {
342                 $in_section = 1;
343                 }
344         elsif ($p[1] == 11 && $c ne $section) {
345                 $in_section = 0;
346                 }
347         elsif ($in_section) {
348                 push(@new_order, $c);
349                 }
350         }
351 return @new_order;
352 }
353
354 1;
355