Fixed config type 10
[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         print "<td nowrap>\n";
96         if ($p[1] == 0) {
97                 # Text value
98                 $field = &ui_textbox($c, $config{$c}, $p[2] || 40, 0, $p[3]).
99                          " ".$p[4];
100                 }
101         elsif ($p[1] == 1) {
102                 # One of many
103                 local $len = 0;
104                 for($i=2; $i<@p; $i++) {
105                         $p[$i] =~ /^(\S*)\-(.*)$/;
106                         $len += length($2);
107                         }
108                 local @opts;
109                 for($i=2; $i<@p; $i++) {
110                         $p[$i] =~ /^(\S*)\-(.*)$/;
111                         push(@opts, [ $1, $2.($len > 50 ? "<br>" : "") ]);
112                         }
113                 $field = &ui_radio($c, $config{$c}, \@opts);
114                 }
115         elsif ($p[1] == 2) {
116                 # Many of many
117                 local %sel;
118                 map { $sel{$_}++ } split(/,/, $config{$c});
119                 for($i=2; $i<@p; $i++) {
120                         $p[$i] =~ /^(\S*)\-(.*)$/;
121                         $field .= &ui_checkbox($c, $1, $2, $sel{$1});
122                         }
123                 }
124         elsif ($p[1] == 3) {
125                 # Optional value
126                 local $none = $p[2] ? $p[2] : $text{'config_none'};
127                 $field = &ui_opt_textbox($c, $config{$c}, $p[3] || 20, $none,
128                                          undef, 0, undef, $p[4])." ".$p[5];
129                 }
130         elsif ($p[1] == 4) {
131                 # One of many menu
132                 local @opts;
133                 for($i=2; $i<@p; $i++) {
134                         $p[$i] =~ /^(\S*)\-(.*)$/;
135                         push(@opts, [ $1, $2 ]);
136                         }
137                 $field = &ui_select($c, $config{$c}, \@opts);
138                 }
139         elsif ($p[1] == 5) {
140                 # User chooser
141                 if ($p[2]) {
142                         $field = &ui_radio($c."_def", $config{$c} ? 0 : 1,
143                                            [ [ 1, $p[2] ], [ 0, " " ] ]);
144                         }
145                 if ($p[3]) {
146                         $field .= &ui_textbox($c, $config{$c}, 30)." ".
147                                   &user_chooser_button($c, 1);
148                         }
149                 else {
150                         $field .= &unix_user_input($c, $config{$c});
151                         }
152                 }
153         elsif ($p[1] == 6) {
154                 # Group chooser
155                 if ($p[2]) {
156                         $field = &ui_radio($c."_def", $config{$c} ? 0 : 1,
157                                            [ [ 1, $p[2] ], [ 0, " " ] ]);
158                         }
159                 if ($p[3]) {
160                         $field .= &ui_textbox($c, $config{$c}, 30)." ".
161                                   &group_chooser_button($c, 1);
162                         }
163                 else {
164                         $field .= &unix_group_input($c, $config{$c});
165                         }
166                 }
167         elsif ($p[1] == 7) {
168                 # Directory chooser
169                 $field = &ui_textbox($c, $config{$c}, 40)." ".
170                          &file_chooser_button($c, 1);
171                 }
172         elsif ($p[1] == 8) {
173                 # File chooser
174                 $field = &ui_textbox($c, $config{$c}, 40)." ".
175                          &file_chooser_button($c, 0);
176                 }
177         elsif ($p[1] == 9) {
178                 # Text area
179                 local $cols = $p[2] || 40;
180                 local $rows = $p[3] || 5;
181                 local $sp = $p[4] ? eval "\"$p[4]\"" : " ";
182                 $field = &ui_textarea($c, join("\n", split(/$sp/, $config{$c})),
183                                       $rows, $cols);
184                 }
185         elsif ($p[1] == 10) {
186                 # Radios with freetext option
187                 local $len = 20;
188                 for($i=2; $i<@p; $i++) {
189                         if ($p[$i] =~ /^(\S*)\-(.*)$/) {
190                                 $len += length($2);
191                                 }
192                         else {
193                                 $len += length($p[$i]);
194                                 }
195                         }
196                 local $fv = $config{$c};
197                 local @opts;
198                 for($i=2; $i<@p; $i++) {
199                         ($p[$i] =~ /^(\S*)\-(.*)$/) || next;
200                         push(@opts, [ $1, $2.($len > 50 ? "<br>" : "") ]);
201                         $fv = undef if ($config{$c} eq $1);
202                         }
203                 push(@opts, [ "free", $p[$#p] !~ /^(\S*)\-(.*)$/ ? $p[$#p]
204                                                                  : " " ]);
205                 $field = &ui_radio($c, $fv ? "free" : $config{$c}, \@opts)." ".
206                          &ui_textbox($c."_free", $fv, 20);
207                 }
208         elsif ($p[1] == 12) {
209                 # Password field
210                 $field = &ui_radio($c."_nochange", 1,
211                                    [ [ 1, $text{'config_nochange'} ],
212                                      [ 0, $text{'config_setto'} ] ])." ".
213                          &ui_password($c, undef, $p[2] || 40, 0, $p[3]);
214                 }
215         elsif ($p[1] == 13) {
216                 # Multiple selections from menu
217                 local @sel = split(/,/, $config{$c});
218                 local @opts;
219                 for($i=2; $i<@p; $i++) {
220                         $p[$i] =~ /^(\S*)\-(.*)$/;
221                         push(@opts, [ $1, $2 ]);
222                         }
223                 $field = &ui_select($c, \@sel, \@opts, 5, 1);
224                 }
225         elsif ($p[1] == 15) {
226                 # Input generated by function
227                 $module || &error($text{'config_ewebmin'});
228                 &foreign_require($module, "config_info.pl");
229                 $field = &foreign_call($module, "show_".$p[2],
230                                        $config{$c}, @p);
231                 }
232         elsif ($p[1] == 16) {
233                 # Password free text
234                 $field = &ui_password($c, undef, $p[2] || 40, 0, $p[3]);
235                 }
236         print &ui_table_row($label, $field, 1, [ "width=30% nowrap" ]);
237         }
238 }
239
240 # parse_config(&config, info-file, [module], [&canconfig], [section])
241 # Updates the specified configuration with values from %in
242 sub parse_config
243 {
244 local ($config, $file, $module, $canconfig, $section) = @_;
245
246 # Read the .info file
247 local (%info, @info_order, $o);
248 &read_file($file, \%info, \@info_order);
249 foreach $o (@lang_order_list) {
250         &read_file("$file.$o", \%info, \@info_order);
251         }
252 @info_order = &unique(@info_order);
253
254 if ($section) {
255         # Limit to settings in one section
256         @info_order = &config_in_section($section, \@info_order, \%info);
257         }
258
259 # Actually parse the inputs
260 local $c;
261 foreach $c (@info_order) {
262         next if ($canconfig && !$canconfig->{$c});
263         local @p = split(/,/, $info{$c});
264         if ($p[1] == 14) {
265                 $_[2] || &error($text{'config_ewebmin'});
266                 &foreign_require($_[2], "config_info.pl");
267                 local @newp = &foreign_call($_[2], $p[2]);
268                 $newp[0] ||= $p[0];
269                 @p = @newp;
270                 }
271         if ($p[1] == 16 && $gconfig{'config_16_insecure'}) {
272                 # Don't allow mode 16
273                 $p[1] = 12;
274                 }
275         if ($p[1] == 0 || $p[1] == 7 || $p[1] == 8 || $p[1] == 16) {
276                 # Free text input
277                 $config->{$c} = $in{$c};
278                 }
279         elsif ($p[1] == 1 || $p[1] == 4) {
280                 # One of many
281                 $config->{$c} = $in{$c};
282                 }
283         elsif ($p[1] == 5 || $p[1] == 6) {
284                 # User or group
285                 $config->{$c} = ($p[2] && $in{$c."_def"} ? "" : $in{$c});
286                 }
287         elsif ($p[1] == 2 || $p[1] == 13) {
288                 # Many of many
289                 $in{$c} =~ s/\0/,/g;
290                 $config->{$c} = $in{$c};
291                 }
292         elsif ($p[1] == 3) {
293                 # Optional free text
294                 if ($in{$c."_def"}) { $config->{$c} = ""; }
295                 else { $config->{$c} = $in{$c}; }
296                 }
297         elsif ($p[1] == 9) {
298                 # Multilines of free text
299                 local $sp = $p[4] ? eval "\"$p[4]\"" : " ";
300                 $in{$c} =~ s/\r//g;
301                 $in{$c} =~ s/\n/$sp/g;
302                 $in{$c} =~ s/\s+$//;
303                 $config->{$c} = $in{$c};
304                 }
305         elsif ($p[1] == 10) {
306                 # One of many or free text
307                 if ($in{$c} eq 'free') {
308                         $config->{$c} = $in{$c.'_free'};
309                         }
310                 else {
311                         $config->{$c} = $in{$c};
312                         }
313                 }
314         elsif ($p[1] == 12) {
315                 # Optionally changed password
316                 if (!$in{"${c}_nochange"}) {
317                         $config->{$c} = $in{$c};
318                         }
319                 }
320         elsif ($p[1] == 15) {
321                 # Parse custom HTML field
322                 $_[2] || &error($text{'config_ewebmin'});
323                 &foreign_require($_[2], "config_info.pl");
324                 local $pkg = $_[2];
325                 $pkg =~ s/[^A-Za-z0-9]/_/g;
326                 eval "\%${pkg}::in = \%in";
327                 $config->{$c} = &foreign_call($_[2], "parse_".$p[2],
328                                             $config->{$c}, @p);
329                 }
330         }
331 }
332
333 # config_in_section(&section, &order, &config-info)
334 # Returns a list of config names that are in some section
335 sub config_in_section
336 {
337 local ($section, $info_order, $info) = @_;
338 my @new_order = ( );
339 my $in_section = 0;
340 foreach my $c (@$info_order) {
341         local @p = split(/,/, $info->{$c});
342         if ($p[1] == 11 && $c eq $section) {
343                 $in_section = 1;
344                 }
345         elsif ($p[1] == 11 && $c ne $section) {
346                 $in_section = 0;
347                 }
348         elsif ($in_section) {
349                 push(@new_order, $c);
350                 }
351         }
352 return @new_order;
353 }
354
355
356
357 1;
358