Index: /trunk/cgi-bin/IPDB.pm
===================================================================
--- /trunk/cgi-bin/IPDB.pm	(revision 105)
+++ /trunk/cgi-bin/IPDB.pm	(revision 106)
@@ -21,11 +21,17 @@
 $VERSION	= 2.0;
 @ISA		= qw(Exporter);
-@EXPORT_OK	= qw(&initIPDBGlocals &connectDB &finish &checkDBSanity &allocateBlock
-			&deleteBlock &mailNotify);
+@EXPORT_OK    = qw(
+	%disp_alloctypes %list_alloctypes @citylist @poplist @masterblocks
+	&initIPDBGlobals &connectDB &finish &checkDBSanity &allocateBlock &deleteBlock
+	&mailNotify
+	);
 
 @EXPORT		= (); # Export nothing by default.
-%EXPORT_TAGS	= ( ALL => [qw( &initIPDBGlocals &connectDB &finish &checkDBSanity
-				&allocateBlock &deleteBlock &mailNotify)]
-		  );
+%EXPORT_TAGS	= ( ALL => [qw(
+		%disp_alloctypes %list_alloctypes @citylist @poplist @masterblocks
+		&initIPDBGlobals &connectDB &finish &checkDBSanity &allocateBlock
+		&deleteBlock &mailNotify
+		)]
+	);
 
 ##
@@ -36,4 +42,5 @@
 our @citylist;
 our @poplist;
+our @masterblocks;
 
 # Let's initialize the globals.
@@ -44,10 +51,12 @@
   my $sth;
 
-  # Initialize alloctypes list
-  $sth = $dbh->prepare("select type,dispname from alloctypes");
+  # Initialize alloctypes hashes
+  $sth = $dbh->prepare("select * from alloctypes order by listorder");
   $sth->execute;
-  return (undef,$sth->errstr) if $sth->err;
   while (my @data = $sth->fetchrow_array) {
-    $disp_alloctypes{$data[0]} = $data[1];
+    $disp_alloctypes{$data[0]} = $data[2];
+    if ($data[3] < 900) {
+      $list_alloctypes{$data[0]} = $data[1];
+    }
   }
 
@@ -56,12 +65,18 @@
   $sth->execute;
   return (undef,$sth->errstr) if $sth->err;
-  my $i = 0;
-  my $j = 0;
   while (my @data = $sth->fetchrow_array) {
-    $citylist[$i++] = $data[0];
+    push @citylist, $data[0];
     if ($data[1] eq 'y') {
-      $poplist[$j++] = $data[0];
+      push @poplist, $data[0];
     }
   }
+
+  # Master block list
+  $sth = $dbh->prepare("select * from masterblocks order by cidr");
+  $sth->execute;
+  for (my $i=0; my @data = $sth->fetchrow_array(); $i++) {
+    $masterblocks[$i] = new NetAddr::IP $data[0];
+  }
+  return (undef,$sth->errstr) if $sth->err;
 
   return (1,"OK");
@@ -117,11 +132,13 @@
 
 
+## IPDB::checkDBSanity()
 # Quick check to see if the db is responding.  A full integrity
 # check will have to be a separate tool to walk the IP allocation trees.
 sub checkDBSanity {
-  my $dbh = connectDB();
+  my ($dbh) = $_[0];
 
   if (!$dbh) {
-    print "Cannot connect to the database!";
+    print "No database handle, or connection has been closed.";
+    return -1;
   } else {
     # it connects, try a stmt.
@@ -134,8 +151,9 @@
     } else {
       print "Connected to the database, but could not execute test statement.  ".$sth->errstr();
+      return -1;
     }
   }
   # Clean up after ourselves.
-  $dbh->disconnect;
+#  $dbh->disconnect;
 } # end checkDBSanity
 
@@ -187,5 +205,5 @@
       return ('FAIL',$msg);
     } else {
-      return ('OK',"OK");
+      return ('OK',"$cidr");
     }
 
Index: /trunk/cgi-bin/consistency-check.pl
===================================================================
--- /trunk/cgi-bin/consistency-check.pl	(revision 105)
+++ /trunk/cgi-bin/consistency-check.pl	(revision 106)
@@ -11,8 +11,8 @@
 
 use DBI;
-use IPDB qw(:ALL);
+use IPDB 2.0 qw(:ALL);
 use NetAddr::IP;
 
-$dbh = connectDB;
+($dbh,$errstr) = connectDB("ipdb", "ipdb", "ipdbpwd");
 
 # Schlep up the masters
Index: /trunk/cgi-bin/main.cgi
===================================================================
--- /trunk/cgi-bin/main.cgi	(revision 105)
+++ /trunk/cgi-bin/main.cgi	(revision 106)
@@ -14,5 +14,5 @@
 use DBI;
 use CommonWeb qw(:ALL);
-use IPDB qw(:ALL);
+use IPDB 2.0 qw(:ALL);
 use POSIX qw(ceil);
 use NetAddr::IP;
@@ -32,5 +32,15 @@
 syslog "debug", "$authuser active";
 
-checkDBSanity();
+# Why not a global DB handle?  (And a global statement handle, as well...)
+# Use the connectDB function, otherwise we end up confusing ourselves
+my $ip_dbh;
+my $sth;
+my $errstr;
+($ip_dbh,$errstr) = connectDB("ipdb", "ipdb", "ipdbpwd");
+if (!$ip_dbh) {
+  printAndExit("Failed to connect to database: $errstr\n");
+}
+checkDBSanity($ip_dbh);
+initIPDBGlobals($ip_dbh);
 
 #prototypes
@@ -41,68 +51,30 @@
 			# Only usage passes "select count(*) ..."
 
+# Global variables
 my $RESULTS_PER_PAGE = 50;
 my %webvar = parse_post();
 cleanInput(\%webvar);
 
-my %full_alloc_types = (
-	"ci","Static cable IP",
-	"di","Static DSL IP",
-	"si","Server pool IP",
-	"mi","Static dialup IP",
-	"wi","Static wireless IP",
-	"cp","Cable pool",
-	"dp","DSL pool",
-	"sp","Server pool",
-	"mp","Static dialup pool",
-	"wp","Static wireless pool",
-	"dn","Dialup netblock",
-	"dy","Dynamic DSL netblock",
-	"dc","Dynamic cable netblock",
-	"cn","Customer netblock",
-	"ee","End-use netblock",
-	"rr","Routed netblock",
-	"ii","Internal netblock",
-	"mm","Master block"
-);
-
-# Other global variables
-my @masterblocks;
-my @citylist;
-my @poplist;
-my %allocated;	# Count for allocated blocks in a master block
-my %free;	# Count for free blocks (routed and unrouted) in a master block
-my %bigfree;	# Tracking largest free block in a master block
-my %routed;	# Number of routed blocks in a master block
-
-# Why not a global DB handle?  (And a global statement handle, as well...)
-# We already know the DB is happy, (checkDBSanity) otherwise we wouldn't be here.
-# Use the connectDB function, otherwise we end up confusing ourselves
-my $ip_dbh = connectDB;
-my $sth;
+# Stuff that gets loaded from the database
+#my @citylist;
+#my @poplist;
+#my %allocated;	# Count for allocated blocks in a master block
+#my %free;	# Count for free blocks (routed and unrouted) in a master block
+#my %bigfree;	# Tracking largest free block in a master block
+#my %routed;	# Number of routed blocks in a master block
 
 # Slurp up the master block list - we need this several places
 # While we're at it, initialize the related hashes.
-$sth = $ip_dbh->prepare("select * from masterblocks order by cidr");
-$sth->execute;
-for (my $i=0; my @data = $sth->fetchrow_array(); $i++) {
-  $masterblocks[$i] = new NetAddr::IP $data[0];
-  $allocated{"$masterblocks[$i]"} = 0;
-  $free{"$masterblocks[$i]"} = 0;
-  $bigfree{"$masterblocks[$i]"} = 128;	# Larger number means smaller block.
-					# Set to 128 to prepare for IPv6
-  $routed{"$masterblocks[$i]"} = 0;
-}
-
-# Initialize the city and poplist arrays
-$sth = $ip_dbh->prepare("select * from cities order by city");
-$sth->execute;
-my $i = 0;
-my $j = 0;
-while (my @data = $sth->fetchrow_array) {
-  $citylist[$i++] = $data[0];
-  if ($data[1] eq 'y') {
-    $poplist[$j++] = $data[0];
-  }
-}
+#$sth = $ip_dbh->prepare("select * from masterblocks order by cidr");
+#$sth->execute;
+#for (my $i=0; my @data = $sth->fetchrow_array(); $i++) {
+#  $masterblocks[$i] = new NetAddr::IP $data[0];
+#  $allocated{"$masterblocks[$i]"} = 0;
+#  $free{"$masterblocks[$i]"} = 0;
+#  $bigfree{"$masterblocks[$i]"} = 128;	# Larger number means smaller block.
+#					# Set to 128 to prepare for IPv6
+#  $routed{"$masterblocks[$i]"} = 0;
+#}
+
 
 
@@ -149,8 +121,9 @@
     eval { $ip_dbh->rollback; };
     syslog "err", "Could not add master block '$webvar{cidr}' to database: '$@'";
-    printAndExit("Could not add master block $webvar{cidr} to database: $@");
-  }
-
-  print "Success!</div>\n";
+    printError("Could not add master block $webvar{cidr} to database: $@");
+  } else {
+    print "Success!</div>\n";
+    syslog "info", "$authuser added master block $webvar{cidr}";
+  }
 
   printFooter;
@@ -217,10 +190,10 @@
 
 
-#end main()
-
-# Shut up error log warning about not disconnecting.  Maybe.
-$ip_dbh->disconnect;
-# Just in case something waaaayyy down isn't in place properly...
-exit 0;
+
+# Clean up IPDB globals, DB handle, etc.
+finish;
+# Just in case something waaaayyy down isn't in place
+# properly... we exit explicitly.
+exit;
 
 
@@ -374,5 +347,5 @@
     }
     my @row = (qq(<a href="/ip/cgi-bin/main.cgi?action=edit&block=$data[0]">$data[0]</a>),
-	$data[1], $full_alloc_types{$data[2]}, $data[3], $data[4]);
+	$data[1], $disp_alloctypes{$data[2]}, $data[3], $data[4]);
     # Allow listing of pool if desired/required.
     if ($data[2] =~ /^[cdsmw]p$/) {
@@ -438,4 +411,9 @@
   startTable('Master netblock', 'Routed netblocks', 'Allocated netblocks',
 	'Free netblocks', 'Largest free block');
+
+  my %allocated;
+  my %free;
+  my %routed;
+  my %bigfree;
 
 # Snag the allocations.
@@ -516,4 +494,9 @@
   print qq(<center><div class="heading">Summarizing routed blocks for ).
 	qq($webvar{block}:</div></center><br>\n);
+
+  my %allocated;
+  my %free;
+  my %routed;
+  my %bigfree;
 
   my $master = new NetAddr::IP $webvar{block};
@@ -663,5 +646,5 @@
 
     my @row = ("<a href=\"/ip/cgi-bin/main.cgi?action=edit&block=$data[0]\">$data[0]</a>",
-	$data[3], $full_alloc_types{$data[2]}, $data[1], $data[4]);
+	$data[3], $disp_alloctypes{$data[2]}, $data[1], $data[4]);
     # If the allocation is a pool, allow listing of the IPs in the pool.
     if ($data[2] =~ /^[cdsmw]p$/) {
@@ -730,5 +713,5 @@
 
   print qq(<center><div class="heading">Listing pool IPs for $cidr<br>\n).
-	qq(($full_alloc_types{$type} in $data[3])</div></center><br>\n);
+	qq(($disp_alloctypes{$type} in $data[3])</div></center><br>\n);
   print qq(<div class="indent"><b>Reserved IPs:</b><br>\n);
   print qq(<div class="indent"><table><tr class=color1><td>Network IP:</td><td>).
@@ -773,5 +756,6 @@
 
 
-# Should this maybe just be a full static page?  It just spews out some predefined HTML.
+# Show "Add new allocation" page.  Note that the actual page may
+# be one of two templates, and the lists come from the database.
 sub assignBlock {
   printHeader('');
@@ -788,4 +772,13 @@
     $html =~ s|\$\$BLOCK\$\$|$block|g;
     $html =~ s|\$\$MASKBITS\$\$|$block->masklen|;
+    my $typelist = '';
+    $sth = $ip_dbh->prepare("select type,listname from alloctypes where listorder < 500 and type not like '_i' order by listorder");
+    $sth->execute;
+    my @data = $sth->fetchrow_array;
+    $typelist .= "<option value='$data[0]' selected>$data[1]</option>\n";
+    while (my @data = $sth->fetchrow_array) {
+      $typelist .= "<option value='$data[0]'>$data[1]</option>\n";
+    }
+    $html =~ s|\$\$TYPELIST\$\$|$typelist|g;
   } else {
     open HTML, "../assign.html"
@@ -804,4 +797,13 @@
     }
     $html =~ s|\$\$POPLIST\$\$|$pops|g;
+    my $typelist = '';
+    $sth = $ip_dbh->prepare("select type,listname from alloctypes where listorder < 900 order by listorder");
+    $sth->execute;
+    my @data = $sth->fetchrow_array;
+    $typelist .= "<option value='$data[0]' selected>$data[1]</option>\n";
+    while (my @data = $sth->fetchrow_array) {
+      $typelist .= "<option value='$data[0]'>$data[1]</option>\n";
+    }
+    $html =~ s|\$\$TYPELIST\$\$|$typelist|g;
   }
   my $cities = '';
@@ -907,5 +909,5 @@
 	  $city = $webvar{pop};
 	  $failmsg = "No suitable free block found.<br>\nYou will have to route another".
-	    " superblock to $webvar{city}<br>\nfrom one of the master blocks in Sudbury or".
+	    " superblock to $webvar{pop}<br>\nfrom one of the master blocks in Sudbury or".
 	    " chose a smaller blocksize.";
 	}
@@ -955,5 +957,5 @@
   # Stick in the allocation data
   $html =~ s|\$\$ALLOC_TYPE\$\$|$webvar{alloctype}|g;
-  $html =~ s|\$\$TYPEFULL\$\$|$full_alloc_types{$webvar{alloctype}}|g;
+  $html =~ s|\$\$TYPEFULL\$\$|$disp_alloctypes{$webvar{alloctype}}|g;
   $html =~ s|\$\$ALLOC_FROM\$\$|$alloc_from|g;
   $html =~ s|\$\$CIDR\$\$|$cidr|g;
@@ -981,190 +983,30 @@
   validateInput();
 
-  # Set some things that may be needed
-  # Don't set $cidr here as it may not even be a valid IP address.
-  my $alloc_from = new NetAddr::IP $webvar{alloc_from};
-
-# dynDSL (dy), sIP DSL(dp), and server pools (sp) are nominally allocated to Sudbury
-# no matter what else happens.
-#  if ($webvar{alloctype} =~ /^([sd]p|dy)$/) { $webvar{city} = "Sudbury"; }
-# OOPS.  forgot about North Bay DSL.
-#### Gotta make this cleaner and more accurate
-#  if ($webvar{alloctype} eq "sp") { $webvar{city} = "Sudbury"; }
-
-# Same ordering as confirmation page
-
-  if ($webvar{alloctype} =~ /^[cdsmw]i$/) {
-    my ($base,$tmp) = split //, $webvar{alloctype};	# split into individual chars
-
-    # We'll just have to put up with the oddities caused by SQL (un)sort order
-    $sth = $ip_dbh->prepare("select * from poolips where pool='$webvar{alloc_from}'".
-	" and available='y' order by ip");
-    $sth->execute;
-
-    my @data = $sth->fetchrow_array;
-    my $cidr = $data[1];
-
-    $sth = $ip_dbh->prepare("update poolips set custid='$webvar{custid}',".
-	"city='$webvar{city}',available='n',description='$webvar{desc}',".
-	"circuitid='$webvar{circid}'".
-	" where ip='$cidr'");
-    $sth->execute;
-    if ($sth->err) {
-      syslog "err", "Allocation of $cidr to $webvar{custid} by $authuser failed: ".
-	"'".$sth->errstr."'";
-      printAndExit("Allocation of $cidr to $webvar{custid} failed: '".$sth->errstr."'");
-    }
-    print qq(<div class="center"><div class="heading">The IP $cidr has been allocated to customer $webvar{custid}</div></div>);
-    syslog "notice", "$authuser allocated $cidr to $webvar{custid}";
-# Notify tech@example.com
-    mailNotify('tech@example.com','$full_alloc_types{$webvar{alloctype}} allocation',
-	"$full_alloc_types{$webvar{alloctype}} $cidr allocated to customer $webvar{custid}");
-
-  } else { # end IP-from-pool allocation
-
-    # Set $cidr here as it may not be a valid IP address elsewhere.
-    my $cidr = new NetAddr::IP $webvar{fullcidr};
-
-# Allow transactions, and make errors much easier to catch.
-# Much as I would like to error-track specifically on each ->execute,
-# that's a LOT of code, and some SQL blocks MUST be atomic at a
-# multi-statement level.  :/
-    local $ip_dbh->{AutoCommit} = 0;	# These need to be local so we don't
-    local $ip_dbh->{RaiseError} = 1;	# step on our toes by accident.
-
-    if ($webvar{fullcidr} eq $webvar{alloc_from}) {
-      # Easiest case- insert in one table, delete in the other, and go home.  More or less.
-      # insert into allocations values (cidr,custid,type,city,desc) and
-      # delete from freeblocks where cidr='cidr'
-      # For data safety on non-transaction DBs, we delete first.
-
-      eval {
-	if ($webvar{alloctype} eq 'rr') {
-	  $sth = $ip_dbh->prepare("update freeblocks set routed='y',city='$webvar{city}'".
-	    " where cidr='$webvar{fullcidr}'");
-	  $sth->execute;
-	  $sth = $ip_dbh->prepare("insert into routed values ('$webvar{fullcidr}',".
-	    $cidr->masklen.",'$webvar{city}')");
-	  $sth->execute;
-	} else {
-	  # common stuff for end-use, dialup, dynDSL, pools, etc, etc.
-
-	  # city has to be reset for DSL/server pools;  nominally to Sudbury.
-	  ## Gotta rethink this;  DSL pools can be in North Bay as well.  :/
-	  #if ($webvar{alloctype} =~ /^[sd]p$/) { $webvar{city} = 'Sudbury'; }
-
-	  $sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{fullcidr}'");
-	  $sth->execute;
-
-	  $sth = $ip_dbh->prepare("insert into allocations values ('$webvar{fullcidr}',".
-	    "'$webvar{custid}','$webvar{alloctype}','$webvar{city}','$webvar{desc}',".
-	    "'$webvar{notes}',".$cidr->masklen.",'$webvar{circid}')");
-	  $sth->execute;
-	} # routing vs non-routing netblock
-	$ip_dbh->commit;
-      };  # end of eval
-      if ($@) {
-	carp "Transaction aborted because $@";
-	eval { $ip_dbh->rollback; };
-	syslog "err", "Allocation of '$webvar{fullcidr}' to '$webvar{custid}' as ".
-		"'$webvar{alloctype}' by $authuser failed: '$@'";
-	printAndExit("Allocation of $cidr as $full_alloc_types{$webvar{alloctype}} failed.\n");
-      }
-
-      # If we get here, the DB transaction has succeeded.
-      syslog "notice", "$authuser allocated '$webvar{fullcidr}' to '$webvar{custid}' as '$webvar{alloctype}'";
-
-# How to log SQL without munging too many error-checking wrappers in?
-#      syslog "info", "
-# We don't.  GRRR.
-
-    } else { # webvar{fullcidr} != webvar{alloc_from}
-      # Hard case.  Allocation is smaller than free block.
-      my $wantmaskbits = $cidr->masklen;
-      my $maskbits = $alloc_from->masklen;
-
-      my @newfreeblocks;	# Holds free blocks generated from splitting the source freeblock.
-
-      my $i=0;
-      while ($maskbits++ < $wantmaskbits) {
-	my @subblocks = $alloc_from->split($maskbits);
-	$newfreeblocks[$i++] = $subblocks[1];
-      } # while
-
-      # Begin SQL transaction block
-      eval {
-	# Delete old freeblocks entry
-	$sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{alloc_from}'");
-	$sth->execute();
-
-	# now we have to do some magic for routing blocks
-	if ($webvar{alloctype} eq 'rr') {
-	  # Insert the new freeblocks entries
-	  # Note that non-routed blocks are assigned to <NULL>
-	  $sth = $ip_dbh->prepare("insert into freeblocks values (?, ?, '<NULL>','n')");
-	  foreach my $block (@newfreeblocks) {
- 	    $sth->execute("$block", $block->masklen);
-	  }
-	  # Insert the entry in the routed table
-	  $sth = $ip_dbh->prepare("insert into routed values ('$cidr',".
-	    $cidr->masklen.",'$webvar{city}')");
-	  $sth->execute;
-	  # Insert the (almost) same entry in the freeblocks table
-	  $sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',".
-	    $cidr->masklen.",'$webvar{city}','y')");
-	  $sth->execute;
-
-	} else { # done with alloctype == rr
-
-	  # Insert the new freeblocks entries
-	  $sth = $ip_dbh->prepare("insert into freeblocks values (?, ?, ?,'y')");
-	  foreach my $block (@newfreeblocks) {
- 	    $sth->execute("$block", $block->masklen, $webvar{city});
-	  }
-	  # Insert the allocations entry
-	  $sth = $ip_dbh->prepare("insert into allocations values ('$webvar{fullcidr}',".
-	    "'$webvar{custid}','$webvar{alloctype}','$webvar{city}',".
-	    "'$webvar{desc}','$webvar{notes}',".$cidr->masklen.",'$webvar{circid}')");
-	  $sth->execute;
-	} # done with netblock alloctype != rr
-        $ip_dbh->commit;
-      }; # end eval
-      if ($@) {
-	carp "Transaction aborted because $@";
-	eval { $ip_dbh->rollback; };
-        syslog "err", "Allocation of '$webvar{fullcidr}' to '$webvar{custid}' as ".
-                "'$webvar{alloctype}' by $authuser failed: '$@'";
-        printAndExit("Allocation of $cidr as $full_alloc_types{$webvar{alloctype}} failed.\n");
-      }
-      syslog "notice", "$authuser allocated '$webvar{fullcidr}' to '$webvar{custid}' as '$webvar{alloctype}'";
-
-    } # end fullcidr != alloc_from
-
-    # Begin SQL transaction block
-    eval {
-      # special extra handling for pools.
-      # Note that this must be done for ANY pool allocation!
-      if ( my ($pooltype) = ($webvar{alloctype} =~ /^([cdsmw])p$/) ) {
-	# have to insert all pool IPs into poolips table as "unallocated".
-	$sth = $ip_dbh->prepare("insert into poolips values ('$webvar{fullcidr}',".
-	  " ?, '6750400', '$webvar{city}', '$pooltype', 'y', '', '', '')");
-	my @poolip_list = $cidr->hostenum;
-	for (my $i=1; $i<=$#poolip_list; $i++) {
-	  $sth->execute($poolip_list[$i]->addr);
-	}
-      } # end pool special
-      $ip_dbh->commit;
-    }; # end eval
-    if ($@) {
-      carp "Transaction aborted because $@";
-      eval { $ip_dbh->rollback; };
-      syslog "err", "Initialization of pool '$webvar{fullcidr}' by $authuser failed: '$@'";
-      printAndExit("$full_alloc_types{$webvar{alloctype}} $webvar{fullcidr} not completely initialized.");
-    }
-    syslog "notice", "$full_alloc_types{$webvar{alloctype}} '$webvar{fullcidr}' successfully initialized by $authuser";
-
-    print qq(<div class="center"><div class="heading">The block $webvar{fullcidr} was sucessfully added as type '$webvar{alloctype}' ($full_alloc_types{$webvar{alloctype}})</div></div>);
-
-  } # end static-IP vs netblock allocation
+  # $code is "success" vs "failure", $msg contains OK for a
+  # successful netblock allocation, the IP allocated for static
+  # IP, or the error message if an error occurred.
+  my ($code,$msg) = allocateBlock($ip_dbh, $webvar{fullcidr}, $webvar{alloc_from},
+	$webvar{custid}, $webvar{alloctype}, $webvar{city}, $webvar{desc}, $webvar{notes},
+	$webvar{circid});
+
+  if ($code) {
+    syslog "err", "Allocation of '$webvar{fullcidr}' to '$webvar{custid}' as ".
+	"'$webvar{alloctype}' by $authuser failed: '$msg'";
+    printAndExit("Allocation of $webvar{fullcidr} as $disp_alloctypes{$webvar{alloctype}}".
+	" failed: $msg\n");
+  } else {
+    if ($webvar{alloctype} =~ /^.i$/) {
+      print qq(<div class="center"><div class="heading">The IP $msg has been allocated to customer $webvar{custid}</div></div>);
+      # Notify tech@example.com
+      mailNotify('tech@example.com',"$disp_alloctypes{$webvar{alloctype}} allocation",
+	"$disp_alloctypes{$webvar{alloctype}} $msg allocated to customer $webvar{custid}");
+    } else {
+      print qq(<div class="center"><div class="heading">The block $webvar{fullcidr} was ).
+	"sucessfully added as type '$webvar{alloctype}' ".
+	"($disp_alloctypes{$webvar{alloctype}})</div></div>";
+    }
+    syslog "notice", "$authuser allocated '$webvar{fullcidr}' to '$webvar{custid}' as ".
+	"'$webvar{alloctype}'";
+  }
 
   printFooter();
@@ -1181,5 +1023,5 @@
   chomp $webvar{alloctype};
   # We have different handling for customer allocations and "internal" or "our" allocations
-  if ($webvar{alloctype} =~ /^(ci|di|cn|mi)$/) {
+  if ($webvar{alloctype} =~ /^(ci|di|cn|mi|wi)$/) {
     if (!$webvar{custid}) {
       printAndExit("Please enter a customer ID.");
@@ -1194,12 +1036,17 @@
     $webvar{custid} = "6750400";
     if ($webvar{alloctype} eq 'rr') {
-      if ($webvar{city} !~ /^(?:Huntsville|North Bay|Ottawa|Pembroke|Sault Ste. Marie|Sudbury|Timmins|Thunder Bay|Toronto)$/) {
+      my $flag;
+      foreach (@poplist) {
+        if (/^$webvar{city}$/) {
+	  $flag = 'y'; last;
+	}
+      }
+      if (!$flag) {
 	printAndExit("Please choose a valid POP location for a routed netblock.  Valid ".
-		"POP locations are currently:<br>\n Elliot Lake - Huntsville - North Bay -".
-		" Ottawa -". 
-		" Pembroke - Sault Ste. Marie - Sudbury - Timmins - Thunder Bay - Toronto");
+		"POP locations are currently:<br>\n".join (" - ", @poplist));
       }
     }
   } else {
+print "$webvar{alloctype}";
     # Danger! Danger!  alloctype should ALWAYS be set by a dropdown.  Anyone
     # managing to call things in such a way as to cause this deserves a cryptic error.
@@ -1269,5 +1116,5 @@
     $html =~ s/\$\$TYPESELECT\$\$/$blockoptions/g;
   } else {
-    $html =~ s/\$\$TYPESELECT\$\$/$full_alloc_types{$data[2]}<input type=hidden name=alloctype value="$data[2]">/g;
+    $html =~ s/\$\$TYPESELECT\$\$/$disp_alloctypes{$data[2]}<input type=hidden name=alloctype value="$data[2]">/g;
   }
 
@@ -1330,5 +1177,5 @@
   $html =~ s/\$\$CITY\$\$/$webvar{city}/g;
   $html =~ s/\$\$ALLOCTYPE\$\$/$webvar{alloctype}/g;
-  $html =~ s/\$\$TYPEFULL\$\$/$full_alloc_types{$webvar{alloctype}}/g;
+  $html =~ s/\$\$TYPEFULL\$\$/$disp_alloctypes{$webvar{alloctype}}/g;
   $html =~ s/\$\$CUSTID\$\$/$webvar{custid}/g;
   $webvar{circid} = desanitize($webvar{circid});
@@ -1346,6 +1193,5 @@
 
 # Delete an allocation.
-sub remove
-{
+sub remove {
   printHeader('');
   #show confirm screen.
@@ -1413,5 +1259,5 @@
   $html =~ s|Please confirm|Please confirm <b>removal</b> of|;
   $html =~ s|\$\$BLOCK\$\$|$cidr|g;
-  $html =~ s|\$\$TYPEFULL\$\$|$full_alloc_types{$alloctype}|g;
+  $html =~ s|\$\$TYPEFULL\$\$|$disp_alloctypes{$alloctype}|g;
   $html =~ s|\$\$ALLOCTYPE\$\$|$alloctype|g;
   $html =~ s|\$\$CITY\$\$|$city|g;
@@ -1442,147 +1288,18 @@
   printHeader('');
 
-  # Enable transactions and exception-on-errors... but only for this sub
-  local $ip_dbh->{AutoCommit} = 0;
-  local $ip_dbh->{RaiseError} = 1;
-
-  if ($webvar{alloctype} =~ /^[cdsmw]i$/) {
-
-    eval {
-      $sth = $ip_dbh->prepare("select * from poolips where ip='$webvar{block}'");
-      $sth->execute;
-      my @data = $sth->fetchrow_array;
-      $sth = $ip_dbh->prepare("select city from allocations where cidr='$data[0]'");
-      $sth->execute;
-      @data = $sth->fetchrow_array;
-      $sth = $ip_dbh->prepare("update poolips set custid='6750400', available='y',".
-	" city='$data[0]', description='' where ip='$webvar{block}'");
-      $sth->execute;
-      $ip_dbh->commit;
-    };
-    if ($@) {
-      carp "Transaction aborted because $@";
-      eval { $ip_dbh->rollback; };
-      syslog "err", "$authuser could not deallocate static IP '$webvar{block}': '$@'";
-      printAndExit("Could not deallocate static IP $webvar{block}: $@");
-    }
+  my ($code,$msg) = deleteBlock($ip_dbh, $webvar{block}, $webvar{alloctype});
+
+  if ($code eq 'OK') {
     print "<div class=heading align=center>Success!  $webvar{block} deallocated.</div>\n";
-    syslog "notice", "$authuser deallocated static IP $webvar{block}";
-
-  } elsif ($webvar{alloctype} eq 'mm') { # end alloctype = [cdsmw]i
-
-    eval {
-      $sth = $ip_dbh->prepare("delete from masterblocks where cidr='$webvar{block}'");
-      $sth->execute;
-      $sth = $ip_dbh->prepare("delete from freeblocks where cidr='$webvar{block}'");
-      $sth->execute;
-      $ip_dbh->commit;
-    };
-    if ($@) {
-      carp "Transaction aborted because $@";
-      eval { $ip_dbh->rollback; };
-      syslog "err", "$authuser could not remove master block '$webvar{block}': '$@'";
-      printAndExit("Could not remove master block $webvar{block}: $@");
-    }
-    print "<div class=heading align=center>Success!  Master $webvar{block} removed.</div>\n";
-    syslog "notice", "$authuser removed master block $webvar{block}";
-
-  } else { # end alloctype master block case
-
-    ## This is a big block; but it HAS to be done in a chunk.  Any removal
-    ## of a netblock allocation may result in a larger chunk of free
-    ## contiguous IP space - which may in turn be combined into a single
-    ## netblock rather than a number of smaller netblocks.
-
-    eval {
-
-      my $cidr = new NetAddr::IP $webvar{block};
-      if ($webvar{alloctype} eq 'rr') {
-
-	$sth = $ip_dbh->prepare("delete from routed where cidr='$webvar{block}'");
-	$sth->execute;
-	# Make sure block getting deleted is properly accounted for.
-	$sth = $ip_dbh->prepare("update freeblocks set routed='n',city='<NULL>'".
-		" where cidr='$webvar{block}'");
-	$sth->execute;
-	# Set up query to start compacting free blocks.
-	$sth = $ip_dbh->prepare("select * from freeblocks where ".
-		"maskbits<=".$cidr->masklen." and routed='n' order by maskbits desc");
-
-      } else { # end alloctype routing case
-
-	$sth = $ip_dbh->prepare("delete from allocations where cidr='$webvar{block}'");
-	$sth->execute;
-	# Special case - delete pool IPs
-	if ($webvar{alloctype} =~ /^[cdsmw]p$/) {
-	  # We have to delete the IPs from the pool listing.
-	  $sth = $ip_dbh->prepare("delete from poolips where pool='$webvar{block}'");
-	  $sth->execute;
-	}
-
-	# Set up query for compacting free blocks.
-	$sth = $ip_dbh->prepare("select * from freeblocks where cidr << ".
-		"(select cidr from routed where cidr >> '$cidr') ".
-		" and maskbits<=".$cidr->masklen." and routed='y' order by maskbits desc");
-
-      } # end alloctype general case
-
-      # Now we look for larger-or-equal-sized free blocks in the same master (routed)
-      # (super)block. If there aren't any, we can't combine blocks anyway.  If there
-      # are, we check to see if we can combine blocks.
-      # Execute the statement prepared in the if-else above.
-
-      $sth->execute;
-
-# NetAddr::IP->compact() attempts to produce the smallest inclusive block
-# from the caller and the passed terms.
-# EG:  if you call $cidr->compact($ip1,$ip2,$ip3) when $cidr, $ip1, $ip2,
-#	and $ip3 are consecutive /27's starting on .0 (.0-.31, .32-.63,
-#	.64-.95, and .96-.128), you will get an array containing a single
-#	/25 as element 0 (.0-.127).  Order is not important;  you could have
-#	$cidr=.32/27, $ip1=.96/27, $ip2=.0/27, and $ip3=.64/27.
-
-      my (@together, @combinelist);
-      my $i=0;
-      while (my @data = $sth->fetchrow_array) {
-	my $testIP = new NetAddr::IP $data[0];
-	@together = $testIP->compact($cidr);
-	my $num = @together;
-	if ($num == 1) {
-	  $cidr = $together[0];
-	  $combinelist[$i++] = $testIP;
-	}
-      }
-
-      # Clear old freeblocks entries - if any.  $i==0 if not.
-      if ($i>0) {
-	$sth = $ip_dbh->prepare("delete from freeblocks where cidr=?");
-	foreach my $block (@combinelist) {
-	  $sth->execute("$block");
-	}
-      }
-
-      # insert "new" freeblocks entry
-      if ($webvar{alloctype} eq 'rr') {
-	$sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',".$cidr->masklen.
-		",'<NULL>','n')");
-      } else {
-	$sth = $ip_dbh->prepare("insert into freeblocks values ('$cidr',".$cidr->masklen.
-		",(select city from routed where cidr >>= '$cidr'),'y')");
-      }
-      $sth->execute;
-
-      # If we got here, we've succeeded.  Whew!
-      $ip_dbh->commit;
-    }; # end eval
-    if ($@) {
-      carp "Transaction aborted because $@";
-      eval { $ip_dbh->rollback; };
-      syslog "err", "$authuser could not deallocate netblock '$webvar{block}': '$@'";
-      printAndExit("Could not deallocate netblock $webvar{block}: $@");
-    }
-    print "<div class=heading align=center>Success!  $webvar{block} deleted.</div>\n";
     syslog "notice", "$authuser deallocated '$webvar{alloctype}'-type netblock $webvar{block}";
-
-  } # end alloctype != netblock
+  } else {
+    if ($webvar{alloctype} =~ /^.i$/) {
+      syslog "err", "$authuser could not deallocate static IP '$webvar{block}': '$msg'";
+      printAndExit("Could not deallocate static IP $webvar{block}: $msg");
+    } else {
+      syslog "err", "$authuser could not deallocate netblock '$webvar{block}': '$msg'";
+      printAndExit("Could not deallocate netblock $webvar{block}: $msg");
+    }
+  }
 
   printFooter;
