Handle hostnames with upper-case letters
[webmin.git] / dhcpd / index.cgi
1 #!/usr/local/bin/perl
2 # $Id: index.cgi,v 1.6 2005/04/16 14:30:21 jfranken Exp $
3 # * List all subnets and shared networks
4 #
5 # File modified 2005-04-15 by Johannes Franken <jfranken@jfranken.de>:
6 # * Added support for DNS Zones (list, edit, create zone-directives)
7 # * Added a button to edit key-directives
8 # * Added a button to edit dhcp.conf in a text editor
9
10 require './dhcpd-lib.pl';
11 $display_max = $config{'display_max'} || 1000000000;
12 &ReadParse();
13 $horder = $in{'horder'};
14 $norder = $in{'norder'};
15 if ($horder eq "" && open(INDEX, "$module_config_directory/hindex.".$remote_user)) {
16         chop($horder = <INDEX>);
17         close(INDEX);
18         }
19 if (!$horder) {
20         $horder = 0;
21         }
22 if ($norder eq "" && open(INDEX, "$module_config_directory/nindex.".$remote_user)) {
23         chop($norder = <INDEX>);
24         close(INDEX);
25         }
26 if (!$norder) {
27         $norder = 0;
28         }
29 $nocols = $config{'dhcpd_nocols'} ? $config{'dhcpd_nocols'} : 5;
30 $conf = &get_config();
31 %access = &get_module_acl();
32
33 # Check if dhcpd is installed
34 if (!-x $config{'dhcpd_path'}) {
35         &ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1, 0,
36                 &help_search_link("dhcpd", "man", "doc", "howto", "google"));
37         print &text('index_dhcpdnotfound', $config{'dhcpd_path'},
38                     "$gconfig{'webprefix'}/config.cgi?$module_name"),"<p>\n";
39
40         &foreign_require("software", "software-lib.pl");
41         $lnk = &software::missing_install_link("dhcpd", $text{'index_dhcpd'},
42                         "../$module_name/", $text{'index_title'});
43         print $lnk,"<p>\n" if ($lnk);
44
45         &ui_print_footer("/", $text{'index_return'});
46         exit;
47         }
48
49 # Check if it is the right version
50 @st = stat($config{'dhcpd_path'});
51 if ($st[7] != $config{'dhcpd_size'} || $st[9] != $config{'dhcpd_mtime'}) {
52         # File has changed .. get the version
53         local $ver = &get_dhcpd_version(\$out);
54         if (!$ver) {
55                 &ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1, 0,
56                         &help_search_link("dhcpd", "man", "doc", "howto", "google"));
57                 print (&text('index_dhcpdver2',$config{'dhcpd_path'},
58                              2, 3)),"<p>\n";
59                 print "<pre>$out</pre>\n";
60                 &ui_print_footer("/", $text{'index_return'});
61                 exit;
62                 }
63         $config{'dhcpd_version'} = $ver;
64         $config{'dhcpd_size'} = $st[7];
65         $config{'dhcpd_mtime'} = $st[9];
66         &write_file("$module_config_directory/config", \%config);
67         }
68
69 &ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1, 0,
70         &help_search_link("dhcpd", "man", "doc", "howto", "google"),
71         undef, undef, &text('index_version', $config{'dhcpd_version'}));
72
73 # Create lookup type HTML
74 # XXX change text, add to lookup_*
75 $match = "<select name=match>\n";
76 $match .= "<option value=0 checked>$text{'index_match0'}\n";
77 $match .= "<option value=1>$text{'index_match1'}\n";
78 $match .= "<option value=2>$text{'index_match2'}\n";
79 $match .= "</select>\n";
80
81 # get top-level hosts
82 foreach $h (&find("host", $conf)) {
83         push(@host, $h);
84         }
85 foreach $g (&find("group", $conf)) {
86         push(@group, $g);
87         foreach $h (&find("host", $g->{'members'})) {
88                 push(@host, $h);
89                 $group{$h} = $g->{'index'};
90                 $par{$h} = $g;
91                 push(@{$g->{'hosts'}}, $h->{'values'}->[0]);
92                 }
93         }
94
95 # get subnets and shared nets, and the hosts and groups within them
96 @subn = &find("subnet", $conf);
97 foreach $u (@subn) {
98         $maxsubn = $maxsubn > $u->{'index'} ? $maxsubn : $u->{'index'};
99         foreach $h (&find("host", $u->{'members'})) {
100                 $maxhost = $maxhost > $h->{'index'} ? $maxhost : $h->{'index'};
101                 $subnet{$h} = $u->{'index'};
102                 $par{$h} = $u;
103                 push(@host, $h);
104                 }
105         foreach $g (&find("group", $u->{'members'})) {
106                 $maxgroup = $maxgroup > $g->{'index'} ? $maxgroup : $g->{'index'};
107                 $subnet{$g} = $u->{'index'};
108                 $par{$g} = $u;
109                 push(@group, $g);
110                 foreach $h (&find("host", $g->{'members'})) {
111                         $maxhost = $maxhost > $h->{'index'} ? $maxhost : $h->{'index'};
112                         $subnet{$h} = $u->{'index'};
113                         $group{$h} = $g->{'index'};
114                         $par{$h} = $g;
115                         push(@{$g->{'hosts'}}, $h->{'values'}->[0]);
116                         push(@host, $h);
117                         }
118                 }
119         }
120 @shan = &find("shared-network", $conf);
121 foreach $s (@shan) {
122         $maxshar = $maxshar > $s->{'index'} ? $maxshar : $s->{'index'};
123         foreach $h (&find("host", $s->{'members'})) {
124                 $maxhost = $maxhost > $h->{'index'} ? $maxhost : $h->{'index'};
125                 $shared{$h} = $s->{'index'};
126                 $par{$h} = $s;
127                 push(@host, $h);
128                 }
129         foreach $g (&find("group", $s->{'members'})) {
130                 $maxgroup = $maxgroup > $g->{'index'} ? $maxgroup : $g->{'index'};
131                 $shared{$g} = $s->{'index'};
132                 $par{$g} = $s;
133                 push(@group, $g);
134                 foreach $h (&find("host", $g->{'members'})) {
135                         $maxhost = $maxhost > $h->{'index'} ? $maxhost : $h->{'index'};
136                         $group{$h} = $g->{'index'};
137                         $shared{$h} = $s->{'index'};
138                         $par{$h} = $g;
139                         push(@{$g->{'hosts'}}, $h->{'values'}->[0]);
140                         push(@host, $h);
141                         }
142                 }
143         foreach $u (&find("subnet", $s->{'members'})) {
144                 $maxsubn = $maxsubn > $u->{'index'} ? $maxsubn : $u->{'index'};
145                 $par{$u} = $s;
146                 push(@subn, $u);
147                 $shared{$u} = $s->{'index'};
148                 foreach $h (&find("host", $u->{'members'})) {
149                         $maxhost = $maxhost > $h->{'index'} ? $maxhost : $h->{'index'};
150                         $subnet{$h} = $u->{'index'};
151                         $shared{$h} = $s->{'index'};
152                         $par{$h} = $u;
153                         push(@host, $h);
154                         }
155                 foreach $g (&find("group", $u->{'members'})) {
156                         $maxgroup = $maxgroup > $g->{'index'} ? $maxgroup : $g->{'index'};
157                         $subnet{$g} = $u->{'index'};
158                         $shared{$g} = $s->{'index'};
159                         $par{$g} = $u;
160                         push(@group, $g);
161                         foreach $h (&find("host", $g->{'members'})) {
162                                 $maxhost = $maxhost > $h->{'index'} ? $maxhost : $h->{'index'};
163                                 $subnet{$h} = $u->{'index'};
164                                 $group{$h} = $g->{'index'};
165                                 $shared{$h} = $s->{'index'};
166                                 $par{$h} = $g;
167                                 push(@{$g->{'hosts'}}, $h->{'values'}->[0]);
168                                 push(@host, $h);
169                                 }
170                         }
171                 }
172         }
173 foreach $s (@shan) {
174         $s->{'order'} = (1 + $s->{'index'}) * (2 + $maxsubn);
175         }
176 foreach $s (@subn) {
177         $s->{'order'} = (defined($shared{$s}) ? (1 + $shared{$s}) * (2 + $maxsubn) : 0)
178                         + 1 + $s->{'index'};
179         }
180 if ($norder == 0) {
181         @subn = (@subn, @shan);
182         }
183 elsif ($norder == 1) {
184         @subn = (@subn, @shan);
185         @subn = sort { $a->{'order'} <=> $b->{'order'} } @subn;
186         }
187 elsif ($norder == 2) {
188         @subn = sort { $a->{'values'}->[0] <=> $b->{'values'}->[0] } @subn;
189         @shan = sort { $a->{'values'}->[0] cmp $b->{'values'}->[0] } @shan;
190         @subn = (@subn, @shan);
191         }
192
193 # display subnets and shared nets
194 foreach $u (@subn) {
195         local $can_view = &can('r', \%access, $u);
196         next if !$can_view && $access{'hide'};
197         local ($l, $t, $i);
198         if ($u->{'name'} eq "subnet") {
199                 push(@ulinks, $l = $can_view ? 
200                         "edit_subnet.cgi?idx=$u->{'index'}".
201                         ($shared{$u} ne "" ? "&sidx=$shared{$u}" : "") :
202                         undef);
203                 push(@uicons, $i = "images/subnet.gif");
204                 push(@checkboxids, $u->{'index'}.
205                                    ($shared{$u} ne "" ? "/$shared{$u}" : ""));
206                 }
207         else {
208                 push(@slinks, $l = $can_view ?
209                         "edit_shared.cgi?idx=$u->{'index'}" : undef);
210                 push(@sicons, $i = "images/shared.gif");
211                 push(@checkboxids, $u->{'index'});
212                 }
213         if ($config{'desc_name'} && $u->{'comment'}) {
214                 push(@utitles, $t = &html_escape($u->{'comment'}));
215                 }
216         else {
217                 push(@utitles, $t = &html_escape($u->{'values'}->[0]));
218                 }
219         push(@uslinks, $l);     # so that ordering is preserved
220         push(@ustitles, $t);
221         push(@usicons, $i);
222         }
223 @checkboxes = map { &ui_checkbox("d", $_) } @checkboxids;
224 if ($access{'r_sub'} || $access{'c_sub'} ||
225     $access{'r_sha'} || $access{'c_sha'}) {
226         print &ui_subheading($text{'index_subtitle'});
227         $sp = "";
228         if (@ulinks < $display_max && @slinks < $display_max) {
229                 @links = @uslinks;
230                 @titles = @ustitles;
231                 @icons = @usicons;
232                 }
233         elsif (@ulinks < $display_max) {
234                 @links = @ulinks;
235                 @titles = @utitles;
236                 @icons = @uicons;
237                 }
238         elsif (@slinks < $display_max) {
239                 @links = @slinks;
240                 @titles = @stitles;
241                 @icons = @sicons;
242                 }
243         if (@links) {
244                 # Show table of subnets and shared nets
245                 $show_subnet_delete = 1;
246                 print &ui_form_start("delete_subnets.cgi");
247                 &subnet_add_links();
248                 if ($config{'hostnet_list'} == 0) {
249                         &icons_table(\@links, \@titles, \@icons, $nocols,
250                                      undef, undef, undef, \@checkboxes);
251                         }
252                 else {
253                         &net_table(\@subn, 0, scalar(@subn), \@links, \@titles,
254                                    \@checkboxids);
255                         }
256                 }
257         elsif (!@ulinks && !@slinks) {
258                 # No subnets or shared nets
259                 print "$text{'index_nosubdef'} <p>\n";
260                 }
261         $show_subnet_shared = 1;
262         }
263 &subnet_add_links();
264 if ($show_subnet_delete) {
265         print &ui_form_end([ [ "delete", $text{'index_delete'} ] ]);
266         }
267
268 # Show too-many forms
269 if ($show_subnet_shared) {
270         print "<table>\n";
271         if (@ulinks >= $display_max) {
272                 # Could not show all subnets, so show lookup form
273                 print "<form action=lookup_subnet.cgi>\n";
274                 print "<tr> <td><b>$text{'index_subtoomany'}</b></td>\n";
275                 print "<td><input type=submit value='$text{'index_sublook2'}'></td>\n";
276                 print "<td>$matches</td>\n";
277                 print "<td><input name=subnet size=30></td></tr> </form>\n";
278                 }
279         if (@slinks >= $display_max) {
280                 # Could not show all shared nets, so show lookup form
281                 print "<form action=lookup_shared.cgi>\n";
282                 print "<tr> <td><b>$text{'index_shatoomany'}</b></td>\n";
283                 print "<td><input type=submit value='$text{'index_shalook2'}'></td>\n";
284                 print "<td>$matches</td>\n";
285                 print "<td><input name=shared size=30></td></tr> </form>\n";
286                 }
287         print "</tr></table>\n";
288         }
289
290 print &ui_hr();
291
292 foreach $g (@group) {
293         $parent = (defined($subnet{$g}) ? 1 + $subnet{$g} : 0) +
294                   (defined($shared{$g}) ? (1 + $shared{$g}) * (2 + $maxsubn) : 0);
295         $g->{'order'} = $parent + (1 + $g->{'index'}) / (2 + $maxgroup);
296         }
297 foreach $h (@host) {
298         $parent = (defined($group{$h}) ? (1 + $group{$h}) / (2 + $maxgroup) : 0) +
299                   (defined($subnet{$h}) ? 1 + $subnet{$h} : 0) +
300                   (defined($shared{$h}) ? (1 + $shared{$h}) * (2 + $maxsubn) : 0);
301         $h->{'order'} = $parent + (1 + $h->{'index'}) /
302                         ((1 + @group) * (2 + $maxhost));
303         }
304 if ($horder == 0) {
305         @host = (@host, @group);
306         }
307 elsif ($horder == 1) {
308         @host = (@host, @group);
309         @host = sort { $a->{'line'} <=> $b->{'line'} } @host;
310         }
311 elsif ($horder == 2) {
312         @host = sort { $a->{'values'}->[0] cmp $b->{'values'}->[0] } @host;
313         @host = (@host, @group);
314         }
315 elsif ($horder == 3) {
316         @host = sort { &hardware($a) cmp &hardware($b) } @host;
317         @host = (@host, @group);
318         }
319 elsif ($horder == 4) {
320         @host = sort { &ipaddress($a) cmp &ipaddress($b) } @host;
321         @host = (@host, @group);
322         }
323
324 # display hosts
325 foreach $h (@host) {
326         local $can_view = &can('r', \%access, $h);
327         next if !$can_view && $access{'hide'};
328         if ($h->{'name'} eq 'host') {
329                 # Add icon for a host
330                 push(@hlinks, $l = $can_view ?
331                         "edit_host.cgi?idx=$h->{'index'}".
332                         (defined($group{$h}) ? "&gidx=$group{$h}" : "").
333                         (defined($subnet{$h}) ? "&uidx=$subnet{$h}" : "").
334                         (defined($shared{$h}) ? "&sidx=$shared{$h}" : "") :
335                         undef);
336                 if ($config{'desc_name'} && $h->{'comment'}) {
337                         push(@htitles, &html_escape($h->{'comment'}));
338                         }
339                 else {
340                         push(@htitles, &html_escape($h->{'values'}->[0]));
341                         }
342                 if ($config{'show_ip'}) {
343                         $fv = &fixedaddr($h);
344                         $htitles[$#htitles] .= "<br>".$fv if ($fv);
345                         }
346                 if ($config{'show_mac'}) {
347                         local $hard = &find("hardware", $h->{'members'});
348                         $htitles[$#htitles] .= "<br>$hard->{'values'}->[1]"
349                                 if ($hard);
350                         }
351                 $t = $htitles[$#htitles];
352                 push(@hicons, $i = "images/host.gif");
353                 push(@hgcheckboxids, join("/", $h->{'index'}, $group{$h},
354                                                $subnet{$h}, $shared{$h}));
355                 }
356         else {
357                 # Add icon for a group
358                 push(@glinks, $l = $can_view ?
359                         "edit_group.cgi?idx=$h->{'index'}".
360                         (defined($subnet{$h}) ? "&uidx=$subnet{$h}" : "").
361                         (defined($shared{$h}) ? "&sidx=$shared{$h}" : "") :
362                         undef);
363                 $gm = @{$h->{'hosts'}};
364                 push(@gtitles, $t = &html_escape(&group_name($gm, $h)));
365                 push(@gicons, $i = "images/group.gif");
366                 push(@hgcheckboxids, join("/", $h->{'index'}, $subnet{$h},
367                                                $shared{$h}));
368                 }
369         push(@hglinks, $l);
370         push(@hgtitles, $t);
371         push(@hgicons, $i);
372         }
373 @hgcheckboxes = map { &ui_checkbox("d", $_) } @hgcheckboxids;
374 if ($access{'r_hst'} || $access{'c_hst'} ||
375     $access{'r_grp'} || $access{'c_grp'}) {
376         print &ui_subheading($text{'index_hst'});
377         $sp = "";
378         if (@hlinks < $display_max && @glinks < $display_max) {
379                 @links = @hglinks;
380                 @titles = @hgtitles;
381                 @icons = @hgicons;
382                 }
383         elsif (@hlinks < $display_max) {
384                 @links = @hlinks;
385                 @titles = @htitles;
386                 @icons = @hicons;
387                 }
388         elsif (@glinks < $display_max) {
389                 @links = @glinks;
390                 @titles = @gtitles;
391                 @icons = @gicons;
392                 }
393         if (@links) {
394                 # Some hosts or groups to show
395                 &index_links($horder, "h", 5, $text{'index_hdisplay'},
396                         "norder=$norder");
397                 $show_host_delete = 1;
398                 print &ui_form_start("delete_hosts.cgi");
399                 &host_add_links();
400                 if ($config{'hostnet_list'} == 0) {
401                         &icons_table(\@links, \@titles, \@icons, $nocols,
402                                      undef, undef, undef, \@hgcheckboxes);
403                         }
404                 else {
405                         &host_table(\@host, 0, scalar(@host), \@links, \@titles,
406                                     \@hgcheckboxids);
407                         }
408                 }
409         elsif (!@hlinks && !@glinks) {
410                 # None to show at all
411                 print "$text{'index_nohst'} <p>\n";
412                 }
413         $show_host_group = 1;
414         }
415 &host_add_links();
416 if ($show_host_delete) {
417         print &ui_form_end([ [ "delete", $text{'index_delete'} ] ]);
418         }
419
420 # Show too-many forms
421 if ($show_host_group) {
422         print "<table>\n";
423         if (@hlinks >= $display_max) {
424                 # Could not show all hosts, so show lookup form
425                 print "<form action=lookup_host.cgi>\n";
426                 print "<tr> <td><b>$text{'index_hsttoomany'}</b></td>\n";
427                 print "<td><input type=submit value='$text{'index_hstlook2'}'></td>\n";
428                 print "<td>$matches</td>\n";
429                 print "<td><input name=host size=30></td></tr> </form>\n";
430                 }
431         if (@glinks >= $display_max) {
432                 # Could not show all groups, so show lookup form
433                 print "<form action=lookup_group.cgi>\n";
434                 print "<tr> <td><b>$text{'index_grptoomany'}</b></td>\n";
435                 print "<td><input type=submit value='$text{'index_grplook2'}'></td>\n";
436                 print "<td>$matches</td>\n";
437                 print "<td><input name=group size=30></td></tr> </form>\n";
438                 }
439         print "</tr></table>\n";
440         }
441
442 print &ui_hr();
443
444 ############ START ZONES #####
445
446 if ($config{'dhcpd_version'} >= 3) {
447         print &ui_subheading($text{'zone_key'});
448
449         # get zones
450         @zones = &find("zone", $conf);
451         @zones = sort { $a->{'values'}->[0] <=> $b->{'values'}->[0] } @zones;
452         if (@zones) {
453                 # display zones
454                 print "<a href='edit_zones.cgi?new=1'>","$text{'index_addzone'}</a>&nbsp;&nbsp;\n" if $access{'c_sub'};
455                 foreach $z (@zones) {
456                         # print "ZONE: $z->{'value'} <br>";
457                         push(@zlinks, "edit_zones.cgi?idx=$z->{'index'}");
458                         push(@zicons, "images/files.gif");
459                         push(@ztitles, &html_escape($z->{'values'}->[0]));
460                         }
461                 if ($config{'hostnet_list'} == 0) {
462                         # user wants icons
463                         &icons_table(\@zlinks, \@ztitles, \@zicons, $nocols);
464                         }
465                 else {
466                         # user wants text
467                         &zone_table(\@zones, 0, scalar(@zones), \@zlinks, \@ztitles);
468                         }
469                 }
470         else {
471                 print "<b>$text{'index_nozones'}</b><p>\n";
472                 }
473         print "<a href='edit_zones.cgi?new=1'>","$text{'index_addzone'}</a>&nbsp;&nbsp;\n" if $access{'c_sub'};
474         print &ui_hr();
475
476 }
477
478 # Buttons for global actions
479 print &ui_buttons_start();
480
481 if ($access{'global'}) {
482         # Edit global client options
483         print &ui_buttons_row("edit_options.cgi",
484                 $text{'index_buttego'}, $text{'index_ego'},
485                 &ui_hidden("global", 1));
486         }
487
488 if ($config{'dhcpd_version'} >= 3 && $access{'global'}) {
489         # TSIG keys
490         print &ui_buttons_row("edit_keys.cgi",
491                 $text{'index_buttekey'}, $text{'index_key'});
492         }
493 if (!$access{'noconfig'}) {
494         # Manually edit config file
495         print &ui_buttons_row("edit_text.cgi",
496                 $text{'index_buttetext'}, $text{'index_text'});
497         }
498 if (!$access{'noconfig'}) {
499         # Select network interfaces
500         print &ui_buttons_row("edit_iface.cgi",
501                 $text{'index_buttiface'}, $text{'index_iface'});
502         }
503 if ($access{'r_leases'}) {
504         # Show active leases
505         print &ui_buttons_row("list_leases.cgi",
506                 $text{'index_buttlal'}, $text{'index_lal'});
507         }
508 if ($access{'apply'}) {
509         $pid = &is_dhcpd_running();
510         if ($pid) {
511                 # Apply and stop buttons
512                 print &ui_buttons_row("restart.cgi",
513                         $text{'index_buttapply'}, $text{'index_apply'},
514                         &ui_hidden("pid", $pid));
515                 print &ui_buttons_row("stop.cgi",
516                         $text{'index_stop'}, $text{'index_stopdesc'},
517                         &ui_hidden("pid", $pid));
518                 }
519         else {
520                 # Start button
521                 print &ui_buttons_row("start.cgi",
522                         $text{'index_buttstart'}, $text{'index_start'});
523                 }
524         }
525 print &ui_buttons_end();
526
527 &ui_print_footer("/", $text{'index_return'});
528
529 # Returns canonized hardware address.
530 sub hardware {
531         local ($hconf, $addr);
532         $hconf = $_[0]->{'members'} ? &find("hardware", $_[0]->{'members'}) : undef;
533         if ($hconf) {
534                 $addr = uc($hconf->{'values'}->[1]);
535                 $addr =~ s/(^|\:)([0-9A-F])(?=$|\:)/$1\x30$2/g;
536         }
537         return $hconf ? $addr : undef;
538 }
539
540 # Returns ip address for sorting on
541 sub ipaddress
542 {
543 return undef if (!$_[0]->{'members'});
544 local $iconf = &find("fixed-address", $_[0]->{'members'});
545 return undef if (!$iconf);
546 return sprintf "%3.3d.%3.3d.%3.3d.%3.3d",
547                 split(/\./, $iconf->{'values'}->[0]);
548 }
549
550 sub fixedaddr {
551         local ($fixed, $addr);
552         $fixed = &find("fixed-address", $_[0]->{'members'});
553         if ($fixed) {
554                 $addr = join(" ", grep { $_ ne "," } @{$fixed->{'values'}});
555                 return $addr;
556         } else {
557                 return undef;
558         }
559 }
560
561 sub netmask {
562         return $_[0]->{'values'}->[2];
563 }
564
565 # index_links(current, name, max, txt, ref)
566 sub index_links
567 {
568 local (%linkname, $l);
569 local @links;
570 for (my $l = 0; $l < $_[2]; $l++) {
571         my $msg = $text{"index_$_[1]order$l"};
572         if ($l eq $_[0]) {
573                 push(@links, $msg);
574                 }
575         else {
576                 push(@links, "<a href='?$_[1]order=$l\&$_[4]'>$msg</a>");
577                 }
578         }
579 print "<b>$_[3]</b> ",&ui_links_row(\@links),"\n";
580 open(INDEX, "> $module_config_directory/$_[1]index.".$remote_user);
581 print INDEX "$_[0]\n";
582 close(INDEX);
583 }
584
585 sub host_table
586 {
587 local ($i, $h, $parent);
588 local @tds = ( "width=5" );
589 print &ui_columns_start([ "", $text{'index_hostgroup'},
590                           $text{'index_parent'}, $text{'index_hardware'},
591                           $text{'index_nameip'} ], 100, 0, \@tds);
592 for ($i = $_[1]; $i < $_[2]; $i++) {
593         local @cols;
594         local $firstcol;
595         $h = $_[0]->[$i];
596         if ($h->{'name'} eq 'host') {
597                 $firstcol .= $sp;
598                 }
599         else {
600                 $firstcol .= $text{'index_group'}." ";
601                 $sp = "\&nbsp;\&nbsp;";
602                 }
603         if ($_[3]->[$i]) {
604                 $firstcol .= "<a href=$_[3]->[$i]>$_[4]->[$i]</a>";
605                 }
606         else {
607                 $firstcol .= $_[4]->[$i];
608                 }
609         push(@cols, $firstcol);
610
611         if ($par{$h}->{'name'} eq "group") {            
612             $par_type = $text{'index_togroup'};
613             $parent = &group_name(scalar @{$par{$h}->{'hosts'}});
614         } elsif ($par{$h}->{'name'} eq "subnet") {
615             $par_type = $text{'index_tosubnet'};
616             $parent = $par{$h}->{'values'}->[0];
617         } elsif ($par{$h}->{'name'} eq "shared-network") {
618             $par_type = $text{'index_toshared'};
619             $parent = $par{$h}->{'values'}->[0];
620         }
621
622         if ($config{'desc_name'} && $par{$h}->{'comment'}) {
623             $parent = $par{$h}->{'comment'};
624         }
625         push(@cols, "$par_type:  $parent");
626         push(@cols, $_[3]->[$i] ? &hardware($h) : "");
627         push(@cols, $_[3]->[$i] ? &fixedaddr($h) : "");
628         print &ui_checked_columns_row(\@cols, \@tds, "d", $_[5]->[$i]);
629         }
630 print &ui_columns_end();
631 }
632
633 #&net_table(\@subn, 0, scalar(@subn), \@links, \@titles, \@checkboxids);
634 sub net_table
635 {
636 local ($i, $n);
637 local @tds = ( "width=5" );
638 print &ui_columns_start([ "", $text{'index_net'}, $text{'index_netmask'},
639                           $text{'index_desc'}, $text{'index_parent'} ], 100,
640                         0, \@tds);
641 for ($i = $_[1]; $i < $_[2]; $i++) {
642         local @cols;
643         $n = $_[0]->[$i];
644         local $first;
645         if ($n->{'name'} eq 'subnet') {
646                 $first = $sp;
647                 }
648         else {
649                 $sp = "\&nbsp;\&nbsp;";
650                 }
651         if ($_[3]->[$i]) {
652                 $first .= "<a href=$_[3]->[$i]>$_[4]->[$i]</a>";
653                 }
654         else {
655                 $first .= $_[4]->[$i];
656                 }
657         push(@cols, $first);
658         push(@cols, $_[3]->[$i] ? &netmask($n) : "");
659         push(@cols, $n->{'comment'});
660         push(@cols, $par{$n} ? 
661                 "$text{'index_toshared'} $par{$n}->{'values'}->[0]" : "");
662         print &ui_checked_columns_row(\@cols, \@tds, "d", $_[5]->[$i]);
663         }
664 print &ui_columns_end();
665 }
666
667
668 #&zone_table(\@zones, 0, scalar(@zones), \@zlinks, \@ztitles);
669 sub zone_table
670 {
671 local $i;
672 print "<table border width=95%>\n";
673 print "<tr $tb> <td><b>", $text{'index_zone'}, "</b></td></tr>\n";
674 for ($i = $_[1]; $i < $_[2]; $i++) {
675         print "<tr $cb> <td>\n";
676         print "<a href=$_[3]->[$i]>", $_[4]->[$i], "</a> </td>\n";
677         print "</tr>\n";
678         }
679 print "</table>\n"
680 }
681
682 sub subnet_add_links
683 {
684 local @links;
685 if ($show_subnet_delete) {
686         push(@links, &select_all_link("d"),
687                      &select_invert_link("d"));
688         }
689 push(@links, "<a href='edit_subnet.cgi?new=1'>$text{'index_addsub'}</a>")
690         if $access{'c_sub'};
691 push(@links, "<a href='edit_shared.cgi?new=1'>$text{'index_addnet'}</a>")
692         if $access{'c_sha'};
693 print &ui_links_row(\@links);
694 }
695
696 sub host_add_links
697 {
698 local @links;
699 if ($show_host_delete) {
700         push(@links, &select_all_link("d", 1),
701                      &select_invert_link("d", 1));
702         }
703 push(@links, "<a href='edit_host.cgi?new=1'>$text{'index_addhst'}</a>")
704         if $access{'c_hst'};
705 push(@links, "<a href='edit_group.cgi?new=1'>$text{'index_addhstg'}</a>")
706         if $access{'c_grp'};
707 print &ui_links_row(\@links);
708 }
709