Handle hostnames with upper-case letters
[webmin.git] / frox / frox-lib.pl
1 # Common functions for editing the Frox config file
2
3 BEGIN { push(@INC, ".."); };
4 use WebminCore;
5 &init_config();
6 @ui_tds = ( undef, "nowrap" );
7
8 # get_config()
9 # Returns an array reference containing the contents of the Frox config file
10 sub get_config
11 {
12     if (!scalar(@get_config_cache)) {
13             local $lnum = 0;
14             open(CONF, $config{'frox_conf'});
15             while(<CONF>) {
16                 s/\r|\n//g;
17                 s/^\s*#.$//g;
18                 if (/^\s*(\S+)\s*(.*)/) {
19                     push(@get_config_cache,
20                               { 'name' => $1,
21                                 'value' => $2,
22                                 'words' => [ split(/\s+/, $2) ],
23                                 'line' => $lnum,
24                                 'index' => scalar(@get_config_cache) });
25                 }
26                 $lnum++;
27             }
28             close(CONF);
29     }
30     return \@get_config_cache;
31 }
32
33 # find(name, &config)
34 sub find
35 {
36     local @rv;
37     foreach $c (@{$_[1]}) {
38         if (lc($c->{'name'}) eq lc($_[0])) {
39             push(@rv, $c);
40         }
41     }
42     return wantarray ? @rv : $rv[0];
43 }
44
45 # find_value(name, &config)
46 sub find_value
47 {
48     local @rv = &find($_[0], $_[1]);
49     if (wantarray) {
50         return map { $_->{'value'} } @rv;
51         }
52     else {
53         return $rv[0]->{'value'};
54         }
55 }
56
57 # save_directive(&config, name, &values)
58 # Update the config file with some new values for an option
59 sub save_directive
60 {
61 local ($conf, $name, $values) = @_;
62 local $lref = &read_file_lines($config{'frox_conf'});
63 local @old = &find($name, $conf);
64 local @new = @$values;
65 local $i;
66 local $changed;
67 for($i=0; $i<@old || $i<@new; $i++) {
68         if ($i<@old && $i<@new) {
69                 # Updating some directive
70                 $lref->[$old[$i]->{'line'}] = $name." ".$new[$i];
71                 $old[$i]->{'value'} = $new[$i];
72                 $changed = $old[$i];
73                 }
74         elsif ($i<@old) {
75                 # Removing some directive (need to renumber)
76                 splice(@$lref, $old[$i]->{'line'}, 1);
77                 splice(@$conf, $old[$i]->{'index'}, 1);
78                 &renumber($conf, 'line', $old[$i]->{'line'}, -1);
79                 &renumber($conf, 'index', $old[$i]->{'index'}, -1);
80                 }
81         elsif ($i<@new) {
82                 # Adding some directive (perhaps after same)
83                 local $nd = { 'name' => $name,
84                               'value' => $new[$i] };
85                 local ($j, $cmtline);
86                 for($j=0; $j<@$lref; $j++) {
87                         if ($lref->[$j] =~ /^\s*#+\s*(\S+)/ && $1 eq $name) {
88                                 $cmtline = $j;
89                                 }
90                         }
91                 if ($changed) {
92                         # Adding after same
93                         $nd->{'line'} = $changed->{'line'}+1;
94                         $nd->{'index'} = $changed->{'index'}+1;
95                         &renumber($conf, 'line', $changed->{'line'}, 1);
96                         &renumber($conf, 'index', $changed->{'index'}, 1);
97                         splice(@$lref, $changed->{'line'}+1, 0,
98                                $name." ".$new[$i]);
99                         splice(@$conf, $changed->{'index'}+1, 0, $nd);
100                         $changed = $nd;
101                         }
102                 elsif (defined($cmtline)) {
103                         # Adding after comment of same directive
104                         local ($aftercmt) = grep { $_->{'line'} > $cmtline } @$conf;
105                         $nd->{'line'} = $cmtline;
106                         $nd->{'index'} = $aftercmt ? $aftercmt->{'index'} : 0;
107                         &renumber($conf, 'line', $nd->{'line'}-1, 1);
108                         &renumber($conf, 'index', $nd->{'index'}-1, 1);
109                         splice(@$lref, $cmtline+1, 0,
110                                $name." ".$new[$i]);
111                         splice(@$conf, $nd->{'index'}, 0, $nd);
112                         $changed = $nd;
113                         }
114                 else {
115                         # Adding at end
116                         $nd->{'line'} = scalar(@$lref);
117                         $nd->{'index'} = scalar(@$conf);
118                         push(@$lref, $name." ".$new[$i]);
119                         push(@$conf, $nd);
120                         }
121                 }
122         }
123 }
124
125 # renumber(&conf, field, pos, offset)
126 sub renumber
127 {
128 local ($conf, $field, $pos, $offset) = @_;
129 local $c;
130 foreach $c (@$conf) {
131         if ($c->{$field} > $pos) {
132                 $c->{$field} += $offset;
133                 }
134         }
135 }
136
137 # config_textbox(&config, name, size, cols, [prefix])
138 # Returns HTML for a table row for some text field
139 sub config_textbox
140 {
141 local ($conf, $name, $size, $cols, $prefix) = @_;
142 $cols ||= 1;
143 local $val = join(" ", &find_value($name, $conf));
144 $val =~ s/\s*'(.*)'\s*$/$1/;
145 return &ui_table_row($text{'edit_'.$name},
146                      &ui_textbox($name, $val, $size)." ".$prefix,
147                      $cols, \@ui_tds);
148 }
149
150 # save_textbox(config, name, [function], [split])
151 sub save_textbox
152 {
153 local ($conf, $name, $func, $split) = @_;
154 local @vals = $split ? split(/\s+/, $in{$name}) : ( $in{$name} );
155 local $v;
156 foreach $v (@vals) {
157         &error_check($name, $func, $v);
158         $v = "'$v'" if ($v =~ /\s/);
159         }
160 &save_directive($conf, $name, \@vals);
161 }
162
163 # config_opt_textbox(&config, name, size, cols, [default])
164 # Returns HTML for a table row for some optional text field
165 sub config_opt_textbox
166 {
167 local ($conf, $name, $size, $cols, $default) = @_;
168 $cols ||= 1;
169 local $val = join(" ", &find_value($name, $conf));
170 $val =~ s/\s*'(.*)'\s*$/$1/;
171 return &ui_table_row($text{'edit_'.$name},
172                      &ui_radio($name."_def", $val ? 0 : 1,
173                                [ [ 1, $default || $text{'default'} ],
174                                  [ 0, " " ] ])." ".
175                      &ui_textbox($name, $val, $size), $cols, \@ui_tds);
176 }
177
178 # save_opt_textbox(config, name, [function], [split])
179 sub save_opt_textbox
180 {
181 local ($conf, $name, $func, $split) = @_;
182 if ($in{$name."_def"}) {
183         &save_directive($conf, $name, [ ]);
184         }
185 else {
186         &save_textbox(@_);
187         }
188 }
189
190 # config_yesno(&config, name, [yes], [no], [default])
191 # Returns HTML for a table row for yes/no checkboxes
192 sub config_yesno
193 {
194 local ($conf, $name, $yes, $no, $default) = @_;
195 local $val = &find_value($name, $conf);
196 $val ||= $default;
197 return &ui_table_row($text{'edit_'.$name},
198                      &ui_radio($name, $val =~ /yes|on|true/i ? 1 : 0,
199                                [ [ 1, $yes || $text{'yes'} ],
200                                  [ 0, $no || $text{'no'} ] ]), 1, \@ui_tds).
201        &ui_hidden($name."_default", $default);
202 }
203
204 # save_yesno(&config, name, default)
205 sub save_yesno
206 {
207 local ($conf, $name, $default) = @_;
208 local $val = &find_value($name, $conf);
209 $val ||= $in{$name."_default"};
210 local $curr = $val =~ /yes|on|true/i ? 1 : 0;
211 if ($curr ne $in{$name}) {
212         &save_directive($conf, $name, [ $in{$name} ? "yes" : "no" ]);
213         }
214 }
215
216 # config_exists(&config, name, [yes], [no])
217 # Returns HTML for a table row for yes/no checkboxes, based on the existance
218 # of some config item
219 sub config_exists
220 {
221 local ($conf, $name, $yes, $no) = @_;
222 local $exists = &find($name, $conf);
223 return &ui_table_row($text{'edit_'.$name},
224                      &ui_radio($name, $exists ? 1 : 0,
225                                [ [ 1, $yes || $text{'yes'} ],
226                                  [ 0, $no || $text{'no'} ] ]), 1, \@ui_tds);
227 }
228
229 # save_exists(&config, name)
230 sub save_exists
231 {
232 local ($conf, $name) = @_;
233 &save_directive($conf, $name, $in{$name} ? [ "" ] : [ ]);
234 }
235
236 # config_user(&config, name)
237 # Returns HTML for a table row for a username field
238 sub config_user
239 {
240 local ($conf, $name) = @_;
241 local $val = &find_value($name, $conf);
242 return &ui_table_row($text{'edit_'.$name},
243                      &ui_user_textbox($name, $val, $size), 1, \@ui_tds);
244 }
245
246 # save_user(&config, name)
247 # Saves a username field
248 sub save_user
249 {
250 local ($conf, $name) = @_;
251 defined(getpwnam($in{$name})) ||
252         &error($text{'edit_'.$name}." : ".$text{'edit_euser'});
253 &save_directive($conf, $name, [ $in{$name} ]);
254 }
255
256 # config_group(&config, name)
257 # Returns HTML for a table row for a groupname field
258 sub config_group
259 {
260 local ($conf, $name) = @_;
261 local $val = &find_value($name, $conf);
262 return &ui_table_row($text{'edit_'.$name},
263                      &ui_group_textbox($name, $val, $size), 1, \@ui_tds);
264 }
265
266 # save_group(&config, name)
267 # Saves a group name field
268 sub save_group
269 {
270 local ($conf, $name) = @_;
271 defined(getgrnam($in{$name})) ||
272         &error($text{'edit_'.$name}." : ".$text{'edit_egroup'});
273 &save_directive($conf, $name, [ $in{$name} ]);
274 }
275
276 # config_opt_range(&config, name, cols, default)
277 # Returns HTML for a row containing a two-part range input field
278 sub config_opt_range
279 {
280 local ($conf, $name, $cols, $default) = @_;
281 $cols ||= 1;
282 local $val = &find_value($name, $conf);
283 local ($v1, $v2) = split(/\-/, $val);
284 return &ui_table_row($text{'edit_'.$name},
285                      &ui_radio($name."_def", $val ? 0 : 1,
286                                [ [ 1, $default || $text{'default'} ],
287                                  [ 0, " " ] ])." ".
288                      $text{'edit_from'}." ".
289                      &ui_textbox($name."_from", $v1, 6)." ".
290                      $text{'edit_to'}." ".
291                      &ui_textbox($name."_to", $v2, 6), $cols, \@ui_tds);
292 }
293
294 # save_opt_range(config, name)
295 sub save_opt_range
296 {
297 local ($conf, $name, $func, $split) = @_;
298 if ($in{$name."_def"}) {
299         &save_directive($conf, $name, [ ]);
300         }
301 else {
302         local $v1 = $in{$name."_from"};
303         local $v2 = $in{$name."_to"};
304         $v1 =~ /^\d+$/ && $v1 > 0 && $v2 < 65535 ||
305                 &error($text{'edit_'.$name}." : ".$text{'edit_efrom'});
306         $v2 =~ /^\d+$/ && $v2 > 0 && $v2 < 65536 ||
307                 &error($text{'edit_'.$name}." : ".$text{'edit_eto'});
308         $v1 < $v2 || &error($text{'edit_'.$name}." : ".$text{'edit_erange'});
309         &save_directive($conf, $name, [ $v1."-".$v2 ]);
310         }
311 }
312
313 # error_check(name, func, value)
314 sub error_check
315 {
316 local ($name, $func, $val) = @_;
317 return if (!$func);
318 local $err = &$func($val);
319 &error($text{'edit_'.$name}." : ".$err) if ($err);
320 }
321
322 # is_frox_running()
323 # Returns the PID if Frox is running, 0 if not
324 sub is_frox_running
325 {
326 local $conf = &get_config();
327 local $pidfile = &find_value("PidFile", $conf);
328 if ($pidfile) {
329         open(PID, $pidfile) || return 0;
330         chop($pid = <PID>);
331         close(PID);
332         return $pid && kill(0, $pid) ? $pid : 0;
333         }
334 else {
335         local ($pid) = &find_byname("frox");
336         return $pid;
337         }
338 }
339
340 # restart_frox()
341 # Apply the current frox configuration, or return an error message
342 sub restart_frox
343 {
344 if ($config{'apply_cmd'}) {
345         $out = &backquote_logged("($config{'apply_cmd'}) 2>&1 </dev/null");
346         if ($?) {
347                 return "<pre>$out</pre>";
348                 }
349         }
350 else {
351         $pid = &is_frox_running();
352         $pid || return $text{'stop_egone'};
353         &kill_logged('HUP', $pid) || return $text{'stop_egone'};
354         }
355 return undef;
356 }
357
358 1;
359