The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package API::DirectAdmin::DNS;

use Modern::Perl '2010';
use Carp;

use base 'API::DirectAdmin::Component';

our $VERSION = 0.06;

# Return zone dump
# params: domain
sub dumpzone {
    my ($self, $params ) = @_;
    
    my %add_params = (
	noparse => 1,
    );
    
    my %params = (%$params, %add_params);
    
    my $zone = $self->directadmin->query(
        params         => \%params,
        command        => 'CMD_API_DNS_CONTROL',
        allowed_fields => 'domain noparse',
    );

    return _parse_zone($zone, $params->{domain}. '.', '') unless ref $zone eq 'HASH';
    return $zone;
}

# Add records A, MX, CNAME, NS, PTR, TXT, AAAA
# params: domain, type, name, value
sub add_record {
    my ($self, $params ) = @_;

    my %add_params = (
	action => 'add',
    );
    
    my %params = (%$params, %add_params);

    return $self->directadmin->query(
        params         => \%params,
        command        => 'CMD_API_DNS_CONTROL',
	method	       => 'POST',
        allowed_fields => "type name action value domain",
    );
}

# Remove records A, MX, CNAME, NS, PTR, TXT, AAAA, SRV
# params: domain, type, name, value
sub remove_record {
    my ($self, $params ) = @_;
    
    my %add_params = (
	action => 'select',
	lc $params->{type} . 'recs0' => "name=$params->{name}&value=$params->{value}",
    );
    
    delete $params->{type};
    
    my %params = (%$params, %add_params);

    return $self->directadmin->query(
        params         => \%params,
        command        => 'CMD_API_DNS_CONTROL',
	method	       => 'POST',
	allowed_fields => 'domain 
			   action 
			   name 
			   value 
			   arecs0 
			   mxrecs0 
			   txtrecs0 
			   aaaarecs0 
			   nsrecs0 
			   cnamerecs0 
			   srvrecs0 
			   ptrrecs0',
    );
}

# Special parser for zone dump
# Cropped code from Parse::DNS::Zone
sub _parse_zone {
    my ($zonetext, $origin) = @_;
    
    my $mrow;
    my $prev;
    my %zone;

    my $zentry = qr/^
	    (\S+)\s+ # name
	    (
		    (?: (?: IN | CH | HS ) \s+ \d+ \s+ ) |
		    (?: \d+ \s+ (?: IN | CH | HS ) \s+ ) |
		    (?: (?: IN | CH | HS ) \s+ ) |
		    (?: \d+ \s+ ) |
	    )? # <ttl> <class> or <class> <ttl>
	    (\S+)\s+ # type
	    (.*) # rdata
    $/ix;

    foreach ( split /\n+/, $zonetext ) {

	    chomp;
	    s/;.*$//;
	    next if /^\s*$/;
	    s/\s+/ /g;
	    
	    s/^\@ /$origin /g;
	    s/ \@ / $origin /g;
	    s/ \@$/ $origin/g;

	    # handles mutlirow entries, with ()
	    if($mrow) {
		    $mrow.=$_;
		    
		    next if(! /\)/); 

		    # End of multirow 
		    $mrow=~s/[\(\)]//g;
		    $mrow=~s/\n//mg;
		    $mrow=~s/\s+/ /g;
		    $mrow .= "\n";	

		    $_ = $mrow;
		    undef $mrow;
	    } elsif(/^.*\([^\)]*$/) {
		    # Start of multirow
		    $mrow.=$_;
		    next;
	    }

	    if(/^ /) {
		    s/^/$prev/;
	    }

	    $origin = $1, next if(/^\$ORIGIN ([\w\-\.]+)\s*$/i);

	    my($name,$ttlclass,$type,$rdata) = /$zentry/;

	    my($ttl, $class);
	    if(defined $ttlclass) {
		    ($ttl) = $ttlclass=~/(\d+)/o;
		    ($class) = $ttlclass=~/(CH|IN|HS)/io;

		    $ttlclass=~s/\d+//;
		    $ttlclass=~s/(?:CH|IN|HS)//;
		    $ttlclass=~s/\s//g;
		    if($ttlclass) {
			    next;
		    }
	    }

	    $ttl = defined $ttl ? $ttl : 14400;

	    next if (!$name || !$type || !$rdata);

	    $prev=$name;
	    $name.=".$origin" if $name ne $origin && $name !~ /\.$/;

	    if($type =~ /^(?:cname|afsdb|mx|ns)$/i and 
	       $rdata ne $origin and $rdata !~ /\.$/) {
		    $rdata.=".$origin";
	    }

	    push(@{$zone{lc $name}{lc $type}{rdata}}, $rdata);
	    push(@{$zone{lc $name}{lc $type}{ttl}}, $ttl);
	    push(@{$zone{lc $name}{lc $type}{class}}, $class);
    }

    return \%zone;
}

1;