#!/usr/bin/perl

open (STDERR, ">&STDOUT");
select ((select(STDOUT), $| = 1)[0]); # Synchronize STDOUT
select ((select(STDERR), $| = 1)[0]); # with STDERR

($dns_lib = $0) =~ s:(^|/)[^/]*$::;
($script=$0) =~ s:^.*/([^/]*)$:$1:;	# Get the simple name of this script.

push (@INC, $dns_lib);

require 5.0;
require 'dns_lib.perl';

use Getopt::Long;
$Getopt::Long::autoabbrev=1;    # Allow keyword abbreviations (to uniqueness).
$Getopt::Long::getopt_compat=1; # Allow both "--foo=bar" and "+foo=bar" style.
#$Getopt::Long::option_start='(--|-|\+)';       # [Use the defaults]
#$Getopt::Long::order=$Getopt::Long::REQUIRE_ORDER; # Options can't intermingle
$Getopt::Long::order=$Getopt::Long::PERMUTE;    # or options may intermingle.
$Getopt::Long::ignorecase=1;    # Don't consider case in options.
$Getopt::Long::debug=0;         ### Debug ###

$opt_help = ($#ARGV < 0);

&GetOptions ('help', 'f', 'first', 'min=i') || die "\nTry: $script --help for more information.\n\n";

if ($opt_help) { 
 
    print <<"EndOfHelp";
Usage: $script [OPTION] host ip
 
  --help   This page.
  --f      Force the addition of the records overriding warnings.
  --first  Add host to first avaliable number in the allocated piece
           of the subnet.  This is checked against the .subnets file.
  --min=i  The lowest number you want to assign automatically when using --first.

  host     The fully qualified DNS name of the host you want to add.
  ip       The IP address of the host you want to add or the subnet
           you want to add to if --first is used.
 
EndOfHelp
    
    exit;

} # End if - help

$name = $ARGV[0];

if (! $name) {

    die "\nYou must enter a DNS name.  Try: $script --help for more information.\n\n";

} else {

    $name = &verify_name ($name);

}

$ip = $ARGV[1];

if (! $ip) {

    die "\nYou must enter an IP address.  Try: $script --help for more information.\n\n";

} elsif (defined ($opt_first)) {

    die "\nWith --first you must enter a subnet.\nTry: $script --help for more information.\n\n" unless &verify_subnet ($ip);

} else {

    $ip = &verify_ip ($ip, '');
    $ip = &reverse_ip ($ip) if m/\.in-addr\.arpa\.?$/;

}

if ((($x = &verify_zone ($name)) eq 'PRIMARY') || ($x eq 'SEC_W_GLUE')) {

    $forward = 1;
    $f_zone = $name;
    $f_host = '@';

} else {

    ($f_host, $f_zone) = split ('\.', $name, 2);
    $forward = 1 if (($x = &verify_zone ($f_zone)) eq 'PRIMARY') || ($x eq 'SEC_W_GLUE');

}

$r_ip = &reverse_ip ($ip);

if (! $opt_first) {

    ($r_host, $r_zone) = split ('\.', $r_ip, 2);

} else {

    $r_zone = $r_ip;

}

if ((($x = &verify_zone ($r_zone)) eq 'PRIMARY') || ($x eq 'SEC_W_GLUE')) {

    $reverse = 1;
    %free_num = &allocated_subnet_hash ($r_zone);
    %free_num = &free_subnet_hosts ($r_zone, %free_num);

    if ($opt_first) {

	@free_num = sort numb (keys %free_num);

	foreach $num (@free_num) {

	    $r_host = $num if $num >= $opt_min;
	    last if defined ($r_host);
	    
	}

	die "\nNo avaliable numbers above $opt_min.\n\n" unless defined ($r_host);
	$ip = "$ip.$r_host";
	
    }
    
}

if ((! ($reverse && $forward)) && (! defined ($opt_f))) {

    print "\nCannot add:\n\n";

    if (! $forward) {

	print "\tForward (A) entry in $f_zone\n";

    }

    if (! $reverse) {

	print "\tReverse (PTR) entry in $r_zone\n";

    }

    die "\nYou can use --f to add one part.  Use new_primary to add zones.\n\n";

}

$output = '';

if ($forward) {

    &rcs_co ($f_zone, '.primary');
    @f_file = &read_file ($f_zone, '.primary');
    @f_recs = &find_record (&build_record ($f_host, 'A', '', ''), @f_file);
    @f_crecs = &find_record (&build_record ($f_host, 'CNAME', '', ''), @f_file);

}

if ($reverse) {

    &rcs_co ($r_zone, '.primary');
    @r_file = &read_file ($r_zone, '.primary');
    @r_recs = &find_record (&build_record ($r_host, 'PTR', '', ''), @r_file);

}

if (($#f_recs >= 0) || ($#r_recs >= 0) || ($#f_crecs >= 0)) {
    
    $output .= "\nConflicts with existing data.\n";
    
    if ($#f_crecs >= 0) {

	$output .= "\nExisting CNAME Record: $name already has the following CNAME record:\n\n";
    
	foreach $rec (@f_crecs) {

	    $output .= $rec;

	}

	$output .= "\nThe CNAME record will have to be removed first.\n\n";

    }

    if ($#f_recs >= 0) {

	$output .= "\nExisting A Record: $name already has the following A records:\n\n";
    
	foreach $rec (@f_recs) {

	    $output .= $rec;

	}

	$output .= "\nUse add_a --f to add new A record for multihomed hosts.\n\n";

    }

    if ($#r_recs >= 0) {

	$output .= "\nExisting PTR Record: $ip already points to a name:\n\n";

	foreach $rec (@r_recs) {

	    $output .= $rec;

	}

    }

    $output .= "\n\nNo data was entered.\n";

} else {
    
    if ($forward) {

	$f_record = &build_record ($f_host, 'A', $ip, '');
	($result, @f_file) = &add_record ($f_record, @f_file);
    
	if ($result eq 'ADDED') {
	
	    &write_file ($f_zone, '.primary', @f_file);
	    $output .= "\nRecord Added: $f_host [$ip] added to $f_zone\n";
	    $f_change = 1;

	} elsif ($result eq 'DUPLICATE') {
	
	    $output .= "\nDuplicate Record: $f_host [$ip] is already in $f_zone\n";
	
	} else {
	
	    $output .= "\nError: This isn't supposed to happen...\n";
	
	}


    }
    
    if ($reverse) {

	$r_record = &build_record ($r_host, 'PTR', $name, '');
	($result, @r_file) = &add_record ($r_record, @r_file);

	if ($result eq 'ADDED') {
	
	    &write_file ($r_zone, '.primary', @r_file);
	    $output .= "\nRecord Added: $r_host [$name] added to $r_zone\n";
	    $r_change = 1;

	} elsif ($result eq 'DUPLICATE') {
	
	    $output .= "\nDuplicate Record: $r_host [$name] is already in $r_zone\n";
	
	} else {
	
	    $output .= "\nError: This isn't supposed to happen...\n";
	
	}

    }

}

&rcs_ci ($f_zone, '.primary', "Script $script: added A record for $f_host [$ip]", $f_change) if $forward;
&rcs_ci ($r_zone, '.primary', "Script $script: added PTR record for $r_host [$name]", $r_change) if $reverse;

print "$output\n";

exit;

