#!/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', 'prefix=s', 'inc=s', 'suffix=s', 'zone=s', 'startip=i', 'first', 'min=i', 'subnet=s', 'noseq', 'number=i', 'f', 'print') || die "\nTry: $0 --help for more information.\n\n";

if ($opt_help) { 
 
    print <<"EndOfHelp";
Usage: $script [OPTION]

  --prefix=s  Prefix portion of host names to be generated.  Optional.
  --inc=s     The portion of the host name that will be incremented.
              Set this to the inital value for the series.  The string
              must match the following pattern: m/^[a-zA-Z]*[0-9]*$/.
              This option must be non-null.
  --suffix=s  Suffix portion of host names to be generated.  Optional.
  --zone=s    The DNS zone to add the hosts to.
  --startip=i The first IP address for the hosts.
  --first     This option allows the script to find a starting IP address
              for the hosts.
  --min=i     The lowest number you want to assign automatically
              when using --first.
  --subnet=s  The subnet the hosts are being assigned to.
  --noseq     The IP addresses that are generated do not have to
              occur sequentially.
  --number=i  The total number of hosts to generate.
  --help      This page.
  --f         Force the addition of the records overriding warnings.
  --print     Prints the list of hosts to be entered without entering them.

EndOfHelp
    
    exit;

} # End if - help

if (! $opt_zone) {

    die "\nYou must enter a zone.\nTry: $script --help for more information.\n\n";

} else {

    $opt_zone = &verify_name ($opt_zone);
    $forward = 1 if (($x = &verify_zone ($opt_zone)) eq 'PRIMARY') || ($x eq 'SEC_W_GLUE');

}

if (! (defined ($opt_subnet))) {

    die "\nYou must enter a subnet to add the hosts to.\n\n";

} else {

    $opt_subnet = &reverse_ip if $opt_subnet =~ m/\.in-addr\.arpa\.?$/o;    
    $opt_subnet = &verify_subnet ($opt_subnet);
    $r_subnet = &reverse_ip ($opt_subnet);
    $reverse = 1 if (($x = &verify_zone ($r_subnet)) eq 'PRIMARY') || ($x eq 'SEC_W_GLUE');

}

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

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

    if (! $forward) {

	print "\tForward (A) entries in $opt_zone\n";

    }

    if (! $reverse) {

	print "\tReverse (PTR) entries in $opt_subnet\n";

    }

    die "\nYou can use --f to add just forward or backwards records.\nUse new_primary to add zones.\n\n";

}

if ($opt_prefix) {

    die "\nPrefix contains illegal DNS characters.\n\n" unless $opt_prefix =~ m/^[-a-zA-Z0-9_]+$/o;
    $opt_prefix =~ tr/A-Z/a-z/;

}

if (! defined ($opt_inc)) {

    die "\nYou must enter a string to increment.\nTry: $script --help for more information.\n\n";

} else {

    die "\nIncrement portion doesn't match patten.\nTry: $script --help for more information.\n\n" unless $opt_inc =~ m/^[a-zA-Z]*[0-9]*$/o;
    $opt_inc =~ tr/A-Z/a-z/;

}

if ($opt_suffix) {

    die "\Suffix contains illegal DNS characters.\n\n" unless $opt_suffix =~ m/^[-a-zA-Z0-9_]+$/o;
    $opt_suffix =~ tr/A-Z/a-z/;

}

if ((! (defined ($opt_first))) && (! (defined ($opt_startip)))) {

    die "\nYou must enter a starting IP number or use --first.\n\n";

}

if (defined ($opt_startip)) {

    die "\nStarting IP value is out of range.\n\n" if (($opt_startip < 1) || ($opt_startip > 256));
    $opt_startip = $opt_startip + 0;

}

if (! (defined ($opt_number))) {

    die "\nYou must enter a number of hosts to generate.\n\n";

} else {

    $opt_number = $opt_number + 0;
    die "\nNumber of hosts to make must be between 1 and 255.\n\n" if (($opt_number < 1) || ($opt_number > 255));
    die "\nNumber specified will push IP addrersses out of range.\n\n" if ($opt_number + $opt_startip > 255);

}

$output = '';

if (defined ($reverse)) {

    &rcs_co ($opt_subnet, '.primary');
    @r_file = &read_file ($opt_subnet, '.primary');
    %free_num = &allocated_subnet_hash ($opt_subnet);
    %free_num = &free_subnet_hosts ($opt_subnet, %free_num);
    @free_num = sort numb (keys %free_num) if defined ($opt_first);

    undef @ips;

    for ($i = 0; $i < $opt_number; $i++) {

	if (defined ($opt_first)) {
	    
	    undef $ip;

	    for ($j = 0; $j < $#free_num; $j++) {

		$ip = $free_num[$j] if $free_num[$j] >= $opt_min;
		last if defined ($ip);
	    
	    }
	
	    $opt_seq = $ip - 1 if ! (defined ($opt_seq));

	    if (! defined ($ip)) {

		$output .= "Insufficient IP space.\n";
		$i = $opt_number;

	    } else {

		push (@ips, $ip);

		if (! (defined ($opt_noseq))) {

		    if ($opt_seq + 1 != $ip) {

			undef @ips;
			undef $opt_seq;
			$i = -1;

		    } else {

			$opt_seq = $ip;

		    }

		}

		undef $free_num[$j];

	    }
	    
	} else {

	    $output .= "There is already a PTR record for $opt_startip in $opt_subnet.\n" unless defined ($free_num{$opt_startip});

	    push (@ips, "$opt_startip");
	    $opt_startip ++;
    
	}
    
    }

} else {

    undef @ips;

    for ($i = $opt_startip; $i < $opt_startip + $opt_number; $i++) {

	push (@ips, $i);
	
    }

}

if (defined ($forward)) {

    &rcs_co ($opt_zone, '.primary');
    @f_file = &read_file ($opt_zone, '.primary');

    undef @hosts;

    for ($i = 0; $i < $opt_number; $i++) {

	undef (@f_recs);
	$host = "$opt_prefix$opt_inc$opt_suffix";
	@f_recs = &find_record (&build_record ($host, 'A', '', ''), @f_file);

	if ($#f_recs >= 0) {

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

		$output .= $rec;

	    }

	    $output .= "\n";

	}

	push (@hosts, "$host");
	$opt_inc ++;

    }

} else {

    undef @hosts;

    for ($i = 0; $i < $opt_number; $i++) {

	$host = "$opt_prefix$opt_inc$opt_suffix";
	push (@hosts, "$host");
	$opt_inc ++;

    }

}

if ($output ne '') {


    $output .= "\nFor info try:\n";
    $output .= "\tshow_primary $opt_zone\n";
    $output .= "\tshow_primary $opt_subnet\n";
    $output .= "\tsubinfo $opt_zone\n";
    $output .= "\tsubinfo $opt_subnet\n";
    $output .= "\n";

} elsif (defined ($opt_print)) {

    $output .= "Zone: $opt_zone\n";
    $output .= "Subnet: $opt_subnet [$r_subnet]\n\n";

    for ($i = 0; $i < $opt_number; $i++) {

	$host = "$hosts[$i].$opt_zone";
	$ip = "$opt_subnet.$ips[$i]";
	$output .= "$host [$ip]\n";

    }

} else {

    if ($forward) {

	for ($i = 0; $i < $opt_number; $i++) {

	    $record = &build_record ($hosts[$i], 'A', "$opt_subnet.$ips[$i]", '');
	    ($result, @f_file) = &add_record ($record, @f_file);
    
	    if ($result eq 'ADDED') {
	    
		$output .= "Record Added: $hosts[$i] $opt_subnet.$ips[$i] added to $opt_zone\n";
		$f_change = 1;

	    } elsif ($result eq 'DUPLICATE') {
	
		$output .= "Duplicate Record: $hosts[$i] $opt_subnet.$ips[$i] is already in $opt_zone\n";
	
	    } else {
	
		$output .= "Error: This isn't supposed to happen...\n";
	
	    }
	    
	}

	&write_file ($opt_zone, '.primary', @f_file);

    }
    
    if ($reverse) {

	for ($i = 0; $i < $opt_number; $i++) {

	    $record = &build_record ($ips[$i], 'PTR', "$hosts[$i].$opt_zone", '');
	    ($result, @r_file) = &add_record ($record, @r_file);
    
	    if ($result eq 'ADDED') {
	
		$output .= "Record Added: $ips[$i] $hosts[$i].$opt_zone added to $r_subnet\n";
		$r_change = 1;

	    } elsif ($result eq 'DUPLICATE') {
	
		$output .= "Duplicate Record: $ips[$i] $hosts[$i].$opt_zone added to $r_subnet\n";
	
	    } else {
	
		$output .= "Error: This isn't supposed to happen...\n";
	
	    }

	}

	&write_file ($r_subnet, '.primary', @r_file);

    }

}

print "\n$output\n";

&rcs_ci ($opt_zone, '.primary', "Script $script: added $opt_number A records: $hosts[0] to $hosts[$#hosts]", $f_change) if $forward;
&rcs_ci ($opt_subnet, '.primary', "Script $script: added $opt_number PTR records: $ips[0] to $ips[$#ips]", $r_change) if $reverse;

exit;
