Make ldap config file clearer
[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] || $text{'config_none'};
126                 $field = &ui_opt_textbox($c, $config{$c}, $p[3] || 20, $none,
127                                          $p[6], 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         $label = "<a name=$c>$label</a>";
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 1;
356