#! /usr/bin/perl
#line 2
use 5.010;
use strict;
use warnings;
use if $ENV{DEBUG} // '' eq 'dnsvi' => 'Smart::Comments';
use File::Temp;
use Getopt::Long;
use Pod::Usage;

use blib;
use DNS::Vi;

sub main {
    my %o = (
        key    => undef,
        server => undef,
        debug  => undef,
	editor => $ENV{EDITOR}//'vi',
    );

    GetOptions(
        'k|key=s'    => \$o{key},
        's|server=s' => \$o{server},
        'd|debug!'   => \$o{debug},
	'editor=s'   => \$o{editor},
      )
      && @ARGV == 1
      or pod2usage();

    my $zone = shift @ARGV;

    $o{server} = (split ' ', `dig +short soa $zone`)[0]
	if not defined $o{server};

    my @dig = (
        dig => 'AXFR',
        defined $o{key} ? (-k => $o{key}) : (),
        defined $o{server} ? ("\@$o{server}") : (),
        $zone
    );

    my @zone1 = grep {
        not $_->{rrset}{rrtype} ~~
          [qw(RRSIG NSEC3 NSEC3PARAM NSEC DNSKEY TSIG)]
    } parse($_ = `@dig`) or die $_;

    my $tmp = File::Temp->new();
    $tmp->print(nice @zone1);
    $tmp->flush();
    system $o{editor} => $tmp->filename;
    $tmp->seek(0, 0);
    my @zone2 = parse(<$tmp>);
    my ($add, $del) = delta(\@zone1, \@zone2);

    if ((@$add + @$del) == 0) {
	say 'Nothing changed';
	return 0;
    }

    my $orig_soa =
      (grep { $_->{rrtype} eq 'SOA' } map { $_->{rrset} } @zone1)[0];

    my @cmds = (
	"server $o{server}",
        "prereq yxrrset @{$orig_soa}{qw{label rrtype data}}",
        (map { "update delete $_" } @$del),
        (map { "update add $_" } @$add),
	'show',
	'send',
	'answer',
    );

    print <<_EOF, join "\n" => @cmds, '', '';
# The following commands are about to be sent via nsupdate
# to the master server:

_EOF
    print '# Please confirm (yes/NO): ';
    return 1 if <STDIN> !~ /^y/i;

    my @nsupdate = (
        'nsupdate',
        defined $o{debug} ? ('-d') : (),
        defined $o{key} ? (-k => $o{key}) : (),
    );
    open(my $nsupdate, '|-') or do {
        exec @nsupdate;
        die "Can't exec @nsupdate: $!\n";
    };
    say $nsupdate join "\n", @cmds;
    close($nsupdate);
    say "nsupdate returned $?";

    return 0;
}

exit main(@ARGV) if not caller;

__END__

=head1 NAME

 vidns -- editor for dynamically maintained zones

=head1 SYNOPSIS

 vidns [-k key] [-s server] [-d] <zone>

=head1 DESCRIPTION

This tools supports you in maintaining a dynamic
zone.

=head2 OPTIONS

=over

=item B<-s>|B<--server> B<server-name>

The name of the server to contact for the AXFR and the update.
(default: main nameserver from the SOA record)

=item B<-k>|B<--key> B<key-file>

The name of the key file we need for TSIG (the AXFR will use it,
as well as the update).

=back

=head1 PREREQUISITES

We need some tools to be installed:

=over

=item B<dig>

The domain information grabber is used for the zone transfer currently.

=item B<nsupdate>

The nsupdate tool is used to send the updates back to the server.

=back

=cut
