#!/s/std/bin/perl
#
# newhh: add a new handheld device to the network. designed to be called as
#        a req script
#
# $Id: newhh.pl,v 1.6 2008/04/03 16:21:58 dparter Exp $
#

use strict;
use warnings;
use Getopt::Std;
use English;
use CSL::DBs;
use CSL::Pg;
use DBI;
use Mail::Internet;

our($opt_n, $opt_l, $opt_u, $opt_m, $opt_d, $opt_r, $opt_t);

my $mac_addr;
my $dbh;
my $schema = 'splat';
my $result;
my $hnumber;
my $hnum;
my $hname;
my $sname;
my $ipaddr;
my $message;
my $msg;


sub usage {
    die "usage: $PROGRAM_NAME [-n] [-t] -u user -m mac_address -l label -d description -r reqnum";
}

sub mac_ok {
    my($mac) = @_;

    return ( $mac =~ /^[a-zA-Z0-9]{2}:[a-zA-Z0-9]{2}:[a-zA-Z0-9]{2}:[a-zA-Z0-9]{2}:[a-zA-Z0-9]{2}:[a-zA-Z0-9]{2}$/ );
}

sub user_ok {
    my($user) = @_;

    if ( getpwnam($user) ) {
	return 1;
    } else {
	return 0;
    }
}

getopts("nu:m:d:l:r:t");

if ( ! ( $opt_u && $opt_m && $opt_d && $opt_l && $opt_r) ) {
    usage();
}

if ( $opt_t ) {
    $schema = 'testing';
}

if ( ! mac_ok($opt_m ) ) {
    die "$PROGRAM_NAME: invalid MAC address: $opt_m";
}

if ( ! user_ok($opt_u) ) {
    die "$PROGRAM_NAME: invluade user name: $opt_u";
}

$mac_addr = lc($opt_m);

$dbh = DBI->connect($CSL::DBs::csdb) || die "error connecting to database: " . $DBI::errstr;

$dbh->{AutoCommit} = 0;  # enable transactions, if possible
$dbh->{RaiseError} = 1;
eval {
    #
    # do the database work here
    #

    # check first to avoid duplicates... allow graceful handling
    $result = $dbh->selectrow_hashref("select * from $schema.mac_addresses where mac_address = ?", undef, $opt_m);
    if ( $result ) {
	die "MAC address $opt_m is already in use by part no. " . $result->{part};
    }

    $result = $dbh->do("insert into $schema.handhelds (label, username, description) values(?, ?, ?)", undef, $opt_l, $opt_u, $opt_d);
    if ( $result != 1 ) {
	die "insert into handhelds table failed: " . $dbh->errstr;
    }
    # get the hnumber... 
    $result = $dbh->selectrow_hashref("select * from $schema.handhelds where label = ? and username = ?", undef, $opt_l, $opt_u);
    $hnumber = $result->{hnumber};
    if ( ! $hnumber ) { 
	die "hnumber select failed";
    }
    $hnum = sprintf("H%06d", $hnumber);
    $sname = $opt_u . "-" . $hnum;
    $hname = $sname . ".cs.wisc.edu";
    $ipaddr = '128.105.47.' . $hnumber;
    $result = $dbh->do("insert into $schema.mac_addresses values(?, 0, ?)", undef, $hnum, $opt_m);
    $result = $dbh->do("insert into $schema.hostnames values(?, 0, ?)", undef, $hnum, $hname);


    $dbh->commit;   # commit the changes if we get this far
};
if ($@) {
    warn "Database Transaction aborted because $@";
    # now rollback to undo the incomplete changes
    # but do it in an eval{} as it may also fail
    eval { $dbh->rollback };
    # add other application on-error-clean-up code here
    die "byebye";
}

#
# all that is left is dns and dhcp...
#


$message .= "Please add the following handheld device to DNS and dhcp:\n\n";
$message .= "DNS: cs.wisc.edu:\n\n";
$message .= $sname . "\tin\ta\t" . $ipaddr . "\n";
$message .= "\t\tin\tmx\t0\tshale.cs.wisc.edu.\n"; 
$message .= "\t\tin\tmx\t0\tlimestone.cs.wisc.edu.\n";
$message .= "\t\tin\tmx\t10\tgranite.cs.wisc.edu.\n";
$message .= "\t\tin\tmx\t10\tgypsum.cs.wisc.edu.\n";
$message .= "\t\tin\tmx\t10\tobsidian.cs.wisc.edu.\n";
$message .= "\n\n";
$message .= "DNS: rev.105.128.in-addr.arpa:\n\n";
$message .= $hnumber . ".47\tin\tptr\t" . $hname . ".\n";
$message .= "\n\n";
$message .= "DHCP:\n\n";
$message .= "host " . $sname . " {\n";
$message .= "\thardware ethernet " . $opt_m . ";\n";
$message .= "\tfixed-address " . $sname . ";\n";
$message .= "}\n";
$message .= "\n\n";
$message .= "CISCO Firewall Rules:\n\n";
$message .= "ip access-list extended handheld-in\n\n";
$message .= "\tpermit tcp host " . $ipaddr . " host 128.105.6.20 eq smtp\n\n"; 
$message .= "\tpermit tcp host " . $ipaddr . " host 128.105.6.20 eq 587\n\n"; 
$message .= "\tpermit ip host " . $ipaddr . " any reflect handheld-traffic\n\n";
$message .= "\tip access-list resequence handheld-in 10 10\n\n";
$message .= "\n\n"; 

$msg = new Mail::Internet;
$msg->head->add('From', getpwuid($<) . '@cs.wisc.edu');
$msg->head->add('To', 'lab@cs.wisc.edu');
$msg->head->add('Subject', '[CSL #' . $opt_r . '] handheld request details: ' . $sname);
$msg->body($message);
$msg->smtpsend;

if ( $opt_t ) {
    print "\n\nChanges have been made to the testing schema, not splat!\n\n";
}
print "Detailed instructions have been added to the req.\n";
