#!/usr/local/bin/perl
# delete_zone.cgi
# Delete an existing master, slave or secondary zone, and it's records file

require './bind8-lib.pl';
&ReadParse();
$conf = &get_config();
if ($in{'view'} ne '') {
	$conf = $conf->[$in{'view'}]->{'members'};
	}
$zconf = $conf->[$in{'index'}];
%access = &get_module_acl();
&can_edit_zone(\%access, $zconf) ||
	&error($text{'master_edelete'});
$access{'ro'} && &error($text{'master_ero'});
$access{'delete'} || &error($text{'master_edeletecannot'});

$rev = ($zconf->{'value'} =~ /in-addr\.arpa/i || $zconf->{'value'} =~ /\.ip6\.int/i);
$type = &find("type", $zconf->{'members'})->{'value'};
if (!$in{'confirm'}) {
	# Ask the user if he is sure ..
	&header($text{'delete_title'}, "");
	print "<hr>\n";

	print "<center><p>\n";
	if ($type eq 'hint') {
		print $text{'delete_mesg2'},"<p>\n";
		}
	else {
		print &text('delete_mesg', "<tt>".&ip6int_to_net(&arpa_to_ip(
			$zconf->{'value'}))."</tt>"),"<p>\n";
		}
	print "<form action=delete_zone.cgi>\n";
	print "<input type=hidden name=index value=$in{'index'}>\n";
	print "<input type=hidden name=view value=$in{'view'}>\n";
	print "<input type=submit name=confirm value='$text{'delete'}'><br>\n";
	if ($type eq 'master') {
		print $text{$rev ? 'delete_fwd' : 'delete_rev'},"\n";
		print "<input type=radio name=rev value=1 checked> $text{'yes'}\n";
		print "<input type=radio name=rev value=0> $text{'no'}<br>\n";

		&foreign_require("servers", "servers-lib.pl");
		@servers = grep { $_->{'user'} } &servers::list_servers();
		if (@servers && $access{'remote'}) {
			print "$text{'delete_slave'} <select name=slave>\n";
			print "<option value=''>&nbsp;\n";
			foreach $s (@servers) {
				printf "<option value=%s %s>%s\n",
				    $s->{'host'},
				    $s->{'host'} eq $config{'default_slave'} ?
					'selected' : '',
				    $s->{'desc'} ? $s->{'desc'} : $s->{'host'};
				}
			print "</select><br>\n";
			}
		}
	print "</form></center>\n";
	print "<hr>\n";
	&footer("", $text{'index_return'});
	exit;
	}

if (!$rev && $in{'rev'} && $type eq 'master') {
	# find and delete reverse records
	local $file = &find("file", $zconf->{'members'})->{'value'};
	&lock_file($config{'chroot'}.$file);
	@recs = &read_zone_file($file, $zconf->{'value'});
	foreach $r (@recs) {
		next if ($r->{'type'} ne "A" && $r->{'type'} ne "AAAA");
		($orevconf, $orevfile, $orevrec) =
			&find_reverse($r->{'values'}->[0], $in{'view'});
		if ($orevrec && &can_edit_reverse($orevconf) &&
		    $r->{'name'} eq $orevrec->{'values'}->[0] &&
		    ($r->{'type'} eq "A" &&
		     $r->{'values'}->[0] eq &arpa_to_ip($orevrec->{'name'})
		     || $r->{'type'} eq "AAAA" &&
		     &expandall_ip6($r->{'values'}->[0]) eq &expandall_ip6(&ip6int_to_net($orevrec->{'name'})))) {
			&lock_file($config{'chroot'}.$orevrec->{'file'});
			&delete_record($orevrec->{'file'} , $orevrec);
			&lock_file($config{'chroot'}.$orevfile);
			@orrecs = &read_zone_file($orevfile,
						  $orevconf->{'value'});
			&bump_soa_record($orevfile, \@orrecs);
			}
		}
	}
elsif ($rev && $in{'rev'} && $type eq 'master') {
	# find and delete forward records
	local $file = &find("file", $zconf->{'members'})->{'value'};
	&lock_file($config{'chroot'}.$file);
	@recs = &read_zone_file($file, $zconf->{'value'});
	foreach $r (@recs) {
		next if ($r->{'type'} ne "PTR");
		($ofwdconf, $ofwdfile, $ofwdrec) =
			&find_forward($r->{'values'}->[0]);
		if ($ofwdrec && &can_edit_zone(\%access, $ofwdconf) &&
		    ($ofwdrec->{'type'} eq "A" &&
		     &arpa_to_ip($r->{'name'}) eq $ofwdrec->{'values'}->[0] 
		     || $ofwdrec->{'type'} eq "AAAA" &&
		     &expandall_ip6(&ip6int_to_net($r->{'name'})) eq &expandall_ip6($ofwdrec->{'values'}->[0])) &&
		    $r->{'values'}->[0] eq $ofwdrec->{'name'}) {
			&lock_file($config{'chroot'}.$ofwdrec->{'file'});
			&delete_record($ofwdrec->{'file'} , $ofwdrec);
			&lock_file($config{'chroot'}.$ofwdfile);
			@ofrecs = &read_zone_file($ofwdfile,
						  $ofwdconf->{'value'});
			&bump_soa_record($ofwdfile, \@ofrecs);
			}
		}
	}

# delete the records file
$f = &find("file", $zconf->{'members'});
if ($f && $type ne 'hint') {
	&lock_file($config{'chroot'}.&absolute_path($f->{'value'}));
	unlink($config{'chroot'}.&absolute_path($f->{'value'}));
	}

# remove the zone directive
&lock_file($config{'chroot'}.$zconf->{'file'});
$lref = &read_file_lines($config{'chroot'}.$zconf->{'file'});
splice(@$lref, $zconf->{'line'}, $zconf->{'eline'} - $zconf->{'line'} + 1);
&flush_file_lines();
&unlock_all_files();
&webmin_log("delete", &find("type", $zconf->{'members'})->{'value'},
	    $zconf->{'value'}, \%in);

# remove from acl files
&read_acl(undef, \%wusers);
foreach $u (keys %wusers) {
	%uaccess = &get_module_acl($u);
	if ($uaccess{'zones'} ne '*') {
		$uaccess{'zones'} = join(' ', grep { $_ ne $zconf->{'value'} }
					      split(/\s+/, $uaccess{'zones'}));
		&save_module_acl(\%uaccess, $u);
		}
	}

# Also delete from slave server
if ($in{'slave'} && $access{'remote'}) {
	&error_setup($text{'delete_err2'});
	&remote_error_setup(\&slave_error_handler);
	&remote_foreign_require($in{'slave'}, "bind8", "bind8-lib.pl");
	$slave_error && &error($slave_error);

	$sparent = &remote_foreign_call($in{'slave'}, "bind8",
					"get_config_parent");
	$sconf = $sparent->{'members'};
	foreach $z (&find("zone", $sconf)) {
		$szconf = $z if ($z->{'value'} eq $zconf->{'value'});
		}
	$szconf || &error($text{'slave_ezone'});
	&remote_foreign_call($in{'slave'}, "bind8", "save_directive", $sparent,
			     [ $szconf ], [ ]);
	&remote_foreign_call($in{'slave'}, "bind8", "flush_file_lines");
	}

&redirect("");

# can_edit_reverse(&zone)
sub can_edit_reverse
{
return $access{'reverse'} || &can_edit_zone(\%access, $_[0]);
}

sub slave_error_handler
{
$slave_error = $_[0];
}

