#!/usr/local/bin/perl
# index.cgi
# Display a list of domains and links to options

require './bind8-lib.pl';
%access = &get_module_acl();

$need_create = !(-r $config{'chroot'}.$config{'named_conf'});
if (!$need_create) {
	# file exists.. but check if it is valid. Some systems have a
	# default invalid config file!
	$conf = &get_config();
	if (($opts = &find("options", $conf)) &&
	    ($dir = &find("directory", $opts->{'members'})) &&
	    !(-d $config{'chroot'}.$dir->{'value'})) {
		# bogus config file!
		$need_create = 1;
		}
	}

# Check if bind is installed
if (!(-x $config{'named_path'})) {
	&header($text{'index_title'}, "", undef, 1, 1, 0,
		&help_search_link("bind", "doc", "google"));
	print "<hr>\n";
	print "<p>",&text('index_enamed', "<tt>$config{'named_path'}</tt>",
			  "$gconfig{'webprefix'}/config.cgi?$module_name"),"<p>\n";
	print "<hr>\n";
	&footer("/", $text{"index"});
	exit;
	}

# Check if BIND is the right version.. Only BIND 8/9 offers the -f option
# Is there a better way to do this?
$out = `$config{'named_path'} -help 2>&1`;
if ($out !~ /\[-f\]/ && $out !~ /\[-f\|/) {
	&header($text{'index_title'}, "", undef, 1, 1, 0,
		&help_search_link("bind", "doc", "google"));
	print "<hr>\n";
	print "<p>",&text('index_eversion', "<tt>$config{'named_path'}</tt>",
			  "/dnsadmin/", "<tt>$config{'named_path'} -help</tt>",
			  "<pre>$out</pre>"),"<p>\n";
	print "<hr>\n";
	&footer("/", $text{"index"});
	exit;
	}

# Try to get the version number
$out = `$config{'named_path'} -v 2>&1`;
if ($out =~ /(bind|named)\s+([0-9\.]+)/i) {
	$bind_version = $2;
	}
open(VERSION, ">$module_config_directory/version");
print VERSION "$bind_version\n";
close(VERSION);

&header($text{'index_title'}, "", undef, 1, 1, 0,
	&help_search_link("bind", "doc", "google"), undef, undef,
	&text('index_version', $bind_version));
print "<hr>\n";

# If the named.boot file does not exist, offer to create it
if ($need_create) {
	print &text('index_eempty',
		    "<tt>$config{'chroot'}$config{'named_conf'}</tt>"),"<p>\n";
	print "<form action=\"dns_boot.cgi\">\n";
	print "<input type=radio name=real value=0> $text{'index_local'}<p>\n";
	print "<input type=radio name=real value=1 checked> ",
	      "$text{'index_download'}<p>\n";
	print "<input type=radio name=real value=2> $text{'index_webmin'}<p>\n";
	print "<center><input type=submit value=\"$text{'index_create'}\">",
	      "</center></form>\n";
	print "<hr>\n";
	&footer("/", $text{"index"});
	exit;
	}

if ($access{'defaults'}) {
	# display global options
	print "<h3>$text{'index_opts'}</h3>\n";
	@olinks = ("conf_servers.cgi", "conf_logging.cgi", "conf_acls.cgi",
		   "conf_files.cgi", "conf_forwarding.cgi", "conf_net.cgi",
		   "conf_misc.cgi", "conf_controls.cgi", "conf_keys.cgi",
		   "conf_zonedef.cgi");
	@otitles = map { /conf_(\S+).cgi/; $text{$1."_title"} } @olinks;
	@oicons = map { /^conf_(\S+).cgi/; "images/$1.gif"; } @olinks;
	&icons_table(\@olinks, \@otitles, \@oicons, 5);
	print "<hr>\n";
	}

$conf = &get_config();
@views = &find("view", $conf);
foreach $v (@views) {
	@vz = &find("zone", $v->{'members'});
	map { $view{$_} = $v } @vz;
	push(@zones, @vz);
	}
push(@zones, &find("zone", $conf));
foreach $z (@zones) {
	$tv = &find("type", $z->{'members'});
	$hashint++ if ($tv->{'value'} eq 'hint');
	}
@zones = grep { &can_edit_zone(\%access, $_) &&
		(!$access{'ro'} || $_->{'value'} ne '.') } @zones;
if (@zones > $config{'max_zones'}) {
	print "<h3>$text{'index_zones'}</h3>\n";
	print "<p>$text{'index_toomany'}<p>\n";
	print "<form action=find_zones.cgi>\n";
	print "<b>$text{'index_find'}</b>\n";
	print "<input name=search size=20>\n";
	print "<input type=submit value='$text{'index_search'}'></form>\n";
	}
elsif (@zones && (!@views || !$config{'by_view'})) {
	# Show all zones
	print "<h3>$text{'index_zones'}</h3>\n";
	&show_buttons();
	foreach $z (@zones) {
		$v = $z->{'value'};
		$tv = &find("type", $z->{'members'});
		next if (!$tv);
		$t = $tv->{'value'};
		local $zn = $v eq "." ? "<i>$text{'index_root'}</i>"
				      : &ip6int_to_net(&arpa_to_ip($v));
		if ($view{$z}) {
			local $vw = $view{$z};
			push(@zlinks, "edit_$t.cgi?index=$z->{'index'}".
				      "&view=$vw->{'index'}");
			push(@ztitles, $zn." ".
			       &text('index_view', "<tt>$vw->{'value'}</tt>"));
			}
		else {
			push(@zlinks, "edit_$t.cgi?index=$z->{'index'}");
			push(@ztitles, $zn);
			}
		push(@zsort, $t eq 'hint' ? undef : @ztitles[$#ztitles]);
		push(@zicons, "images/$t.gif");
		push(@ztypes, $text{"index_$t"});
		$len++;
		}

	# sort list of zones
	@zorder = sort { lc($zsort[$a]) cmp lc($zsort[$b]) } (0 .. $len-1);
	@zlinks = map { $zlinks[$_] } @zorder;
	@ztitles = map { $ztitles[$_] } @zorder;
	@zicons = map { $zicons[$_] } @zorder;
	@ztypes = map { $ztypes[$_] } @zorder;

	if ($config{'show_list'}) {
		# display as list
		$mid = int((@zlinks+1)/2);
		print "<table width=100%><tr><td width=50% valign=top>\n";
		&zones_table([ @zlinks[0 .. $mid-1] ],
			     [ @ztitles[0 .. $mid-1] ],
			     [ @ztypes[0 .. $mid-1] ]);
		print "</td><td width=50% valign=top>\n";
		if ($mid < @zlinks) {
			&zones_table([ @zlinks[$mid .. $#zlinks] ],
				     [ @ztitles[$mid .. $#ztitles] ],
				     [ @ztypes[$mid .. $#ztypes] ]);
			}
		print "</td></tr></table>\n";
		}
	else {
		# display as icons
		&icons_table(\@zlinks, \@ztitles, \@zicons, 5);
		}
	}
elsif (@zones) {
	# Show zones under views
	print "<h3>$text{'index_zones'}</h3>\n";
	&show_buttons();
	foreach $vw (@views) {
		local (@zorder, @zlinks, @ztitles, @zicons, @ztypes, $len);
		local @zv = grep { $view{$_} eq $vw } @zones;
		next if (!@zv);
		print "<b>",&text('index_inview',
				  "<tt>$vw->{'value'}</tt>"),"</b><br>\n";
		foreach $z (@zv) {
			$v = $z->{'value'};
			$tv = &find("type", $z->{'members'});
			next if (!$tv);
			$t = $tv->{'value'};
			local $zn = $v eq "." ? "<i>$text{'index_root'}</i>"
					      : &ip6int_to_net(&arpa_to_ip($v));
			push(@zlinks, "edit_$t.cgi?index=$z->{'index'}".
				      "&view=$vw->{'index'}");
			push(@ztitles, $zn);
			push(@zsort, $t eq 'hint' ? undef : @ztitles[$#ztitles]);
			push(@zicons, "images/$t.gif");
			push(@ztypes, $text{"index_$t"});
			$len++;
			}

		# sort list of zones
		@zorder = sort { lc($zsort[$a]) cmp lc($zsort[$b]) }
			       (0 .. $len-1);
		@zlinks = map { $zlinks[$_] } @zorder;
		@ztitles = map { $ztitles[$_] } @zorder;
		@zicons = map { $zicons[$_] } @zorder;
		@ztypes = map { $ztypes[$_] } @zorder;

		&icons_table(\@zlinks, \@ztitles, \@zicons, 5);
		}
	}
else {
	print "<b>$text{'index_none'}</b><p>\n";
	}
&show_buttons();

if ($access{'views'} && $bind_version >= 9) {
	# Display list of views
	print "<hr>\n";
	foreach $v (@views) {
		push(@vlinks, "edit_view.cgi?index=$v->{'index'}");
		push(@vtitles, $v->{'value'});
		push(@vicons, "images/view.gif");
		}
	if (@views) {
		print "<h3>$text{'index_views'}</h3>\n";
		print "<a href=\"view_form.cgi\">$text{'index_addview'}</a><br>\n"
			if (!$access{'ro'});
		&icons_table(\@vlinks, \@vtitles, \@vicons, 5);
		}
	else {
		print "<b>$text{'index_vnone'}</b><p>\n";
		}
	print "<a href=\"view_form.cgi\">$text{'index_addview'}</a><p>\n"
		if (!$access{'ro'});
	}

# get pid (if any)
if (($opts = &find("options", $conf)) &&
    ($pidopt = &find("pid-file", $opts->{'members'}))) {
	# read from PID file
	$pidfile = $pidopt->{'value'};
	if ($pidfile !~ /^\//) {
		local $dir = &find("directory", $opts->{'members'});
		$pidfile = $dir->{'value'}."/".$pidfile;
		}
	}
else {
	# use default file
	$pidfile = $config{'pid_file'} ? $config{'pid_file'}
				       : "/var/run/named.pid";
	}

# read the PID
if (open(PID, $config{'chroot'}.$pidfile)) {
	<PID> =~ /(\d+)/;
	$pid = $1;
	close(PID);
	}

if (!$access{'ro'} && $access{'apply'}) {
	if ($pid && kill(0, $pid)) {
		# named is running
		print "<hr>\n";
		print "<table width=100%><tr>\n";
		print "<form action=restart.cgi>\n";
		print "<td><input type=hidden name=pid value=$pid>\n";
		print "<input type=submit value=\"$text{'index_apply'}\">\n";
		print "</td> <td>$text{'index_applymsg'}</td>\n";
		print "</form></tr>\n";

		&foreign_require("servers", "servers-lib.pl");
		@servers = grep { $_->{'user'} } &servers::list_servers();
		if (@servers && $access{'remote'}) {
			print "<tr><form action=restart_slave.cgi>\n";
			print "<td nowrap><input type=submit ",
			      "value=\"$text{'index_sapply'}\">\n";
			print "<select name=slave>\n";
			foreach $s (@servers) {
				printf "<option value=%s %s>%s\n",
				    $s->{'host'},
				    $config{'default_slave'} eq $s->{'host'} ?
					'selected' : '',
				    $s->{'desc'} ? $s->{'desc'} : $s->{'host'};
				}
			print "</select></td>\n";
			print "<td>$text{'index_sapplymsg'}</td>\n";
			print "</form></tr>\n";
			}
		print "</table>\n";
		}
	else {
		# named is not running
		print "<hr>\n";
		print "<form action=start.cgi>\n";
		print "<table width=100%><tr><td>\n";
		print "<input type=submit value=\"$text{'index_start'}\">\n";
		print "</td> <td>$text{'index_startmsg'}</td> </tr></table>\n";
		print "</form>\n";
		}
	}

print "<hr>\n";
&footer("/", $text{"index"});

sub dump_config
{
local($c);
foreach $c (@{$_[0]}) {
	print "$_[1]$c->{'name'} ",
		join(',', @{$c->{'values'}});
	if ($c->{'type'}) {
		print " {\n";
		&dump_config($c->{'members'}, "$_[1]\t");
		print "$_[1]}\n";
		}
	else { print "\n"; }
	}
}

sub zones_table
{
local($i);
print "<table border width=100%>\n";
print "<tr $tb> <td><b>$text{'index_zone'}</b></td> ",
      "<td><b>$text{'index_type'}</b></td> </tr>\n";
for($i=0; $i<@{$_[0]}; $i++) {
	print "<tr $cb>\n";
	print "<td><a href=\"$_[0]->[$i]\">$_[1]->[$i]</a></td>\n";
	print "<td>$_[2]->[$i]</td>\n";
	print "</tr>\n";
	}
print "</table>\n";
}

sub show_buttons
{
if ($access{'master'} && !$access{'ro'}) {
	print "<a href=\"master_form.cgi\">$text{'index_addmaster'}</a>\n";
	print "&nbsp;&nbsp;\n";
	}
if ($access{'slave'} && !$access{'ro'}) {
	print "<a href=\"slave_form.cgi\">$text{'index_addslave'}</a>\n";
	print "&nbsp;&nbsp;\n";
	print "<a href=\"stub_form.cgi\">$text{'index_addstub'}</a>\n";
	print "&nbsp;&nbsp;\n";
	}
if ($access{'forward'} && !$access{'ro'}) {
	print "<a href=\"forward_form.cgi\">$text{'index_addfwd'}</a>\n";
	print "&nbsp;&nbsp;\n";
	}
if ($access{'master'} && !$access{'ro'} &&
    $hashint < (@views ? scalar(@views) : 1)) {
	print "<a href=\"hint_form.cgi\">$text{'index_addhint'}</a>\n";
	print "&nbsp;&nbsp;\n";
	}
print "<br>\n";
}

