Index: branches/stable/cgi-bin/IPDB.pm
===================================================================
--- branches/stable/cgi-bin/IPDB.pm	(revision 394)
+++ branches/stable/cgi-bin/IPDB.pm	(revision 445)
@@ -7,5 +7,5 @@
 # Last update by $Author$
 ###
-# Copyright (C) 2004-2006 - Kris Deugau
+# Copyright (C) 2004-2010 - Kris Deugau
 
 package IPDB;
@@ -20,5 +20,5 @@
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
 
-$VERSION	= 2.0;
+$VERSION	= 2; ##VERSION##
 @ISA		= qw(Exporter);
 @EXPORT_OK    = qw(
@@ -53,4 +53,23 @@
 our %IPDBacl;
 
+our $org_name = 'Example Corp';
+our $smtphost = 'smtp.example.com';
+our $domain = 'example.com';
+our $defcustid = '5554242';
+# mostly for rwhois
+##fixme:  leave these blank by default?
+our $rwhoisDataPath = '/usr/local/rwhoisd/etc/rwhoisd';	# to match ./configure defaults from rwhoisd-1.5.9.6
+our $org_street = '123 4th Street';
+our $org_city = 'Anytown';
+our $org_prov_state = 'ON';
+our $org_pocode = 'H0H 0H0';
+our $org_country = 'CA';
+our $org_phone = '000-555-1234';
+our $org_techhandle = 'ISP-ARIN-HANDLE';
+our $org_email = 'noc@example.com';
+our $hostmaster = 'dns@example.com';
+
+our $syslog_facility = 'local2';
+
 # Let's initialize the globals.
 ## IPDB::initIPDBGlobals()
@@ -113,12 +132,12 @@
 # Set up for a PostgreSQL db;  could be any transactional DBMS with the
 # right changes.
-# This definition should be sub connectDB($$$) to be technically correct,
-# but this breaks.  GRR.
 sub connectDB {
-  my ($dbname,$user,$pass) = @_;
+  my $dbname = shift;
+  my $user = shift;
+  my $pass = shift;
+  my $dbhost = shift;
+
   my $dbh;
-  my $DSN = "DBI:Pg:host=ipdb-db;dbname=$dbname";
-#  my $user = 'ipdb';
-#  my $pw   = 'ipdbpwd';
+  my $DSN = "DBI:Pg:".($dbhost ? "host=$dbhost;" : '')."dbname=$dbname";
 
 # Note that we want to autocommit by default, and we will turn it off locally as necessary.
@@ -557,5 +576,5 @@
     # have to insert all pool IPs into poolips table as "unallocated".
     $sth = $dbh->prepare("insert into poolips (pool,ip,custid,city,type)".
-	" values ('$pool', ?, '6750400', '$city', '$type')");
+	" values ('$pool', ?, '$defcustid', '$city', '$type')");
     my @poolip_list = $pool->hostenum;
     if ($class eq 'all') { # (DSL-ish block - *all* IPs available
@@ -614,5 +633,5 @@
     eval {
       $msg = "Unable to deallocate $disp_alloctypes{$type} $cidr";
-      $sth = $dbh->prepare("update poolips set custid='6750400',available='y',".
+      $sth = $dbh->prepare("update poolips set custid='$defcustid',available='y',".
 	"city=(select city from allocations where cidr >>= '$cidr'".
 	" order by masklen(cidr) desc limit 1),".
@@ -704,30 +723,34 @@
       } # end alloctype general case
 
-##TEMP
-## Temporary wrapper to "properly" deallocate sIP PPPoE/DSL "netblocks" in 209.91.185.0/24
-## Note that we should really general-case this.
-my $staticpool = new NetAddr::IP "209.91.185.0/24";
-##TEMP
-if ($cidr->within($staticpool)) {
-##TEMP
-  # We've already deleted the block, now we have to stuff its IPs into the pool.
-  my $sth2 = $dbh->prepare("insert into poolips values ('209.91.185.0/24',?,'6750400','Sudbury','di','y','','','')");
-  $sth2->execute($cidr->addr);
-  foreach my $ip ($cidr->hostenum) {
-    $sth2->execute("$ip");
-  }
-  $cidr--;
-  $sth2->execute($cidr->addr);
-
-##TEMP
-} else {
-##TEMP
-
-      # 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;
+      ## Deallocate legacy blocks stashed in the middle of a static IP pool
+      ## This may be expandable to an even more general case of contained netblock, or other pool types.
+
+      # Find out if the block we're deallocating is within a DSL pool
+      my $sth2 = $dbh->prepare("SELECT cidr,city,type FROM allocations WHERE type LIKE '_p' AND cidr >>= ?");
+      $sth2->execute("$cidr");
+      my ($pool,$poolcity,$pooltype) = $sth2->fetchrow_array;
+
+      if ($pool || $sth2->rows) {
+	# We've already deleted the block, now we have to stuff its IPs into the pool.
+	$pooltype =~ s/p$/i/;	# change type to static IP
+	$sth2 = $dbh->prepare("INSERT INTO poolips (pool,ip,city,type,custid) values ".
+		"('$pool',?,'$poolcity','$pooltype','$defcustid')");
+##fixme:  need to not insert net, gateway, and bcast on "real netblock" pools (DHCPish)
+	# don't insert .0
+	$sth2->execute($cidr->addr) unless $cidr->addr =~ m|\.0$|;
+	foreach my $ip ($cidr->hostenum) {
+	  $sth2->execute("$ip");
+	}
+	$cidr--;
+	# don't insert .255
+	$sth2->execute($cidr->addr) unless $cidr->addr =~ m|\.255$|;
+      } else {	# done returning IPs from a block to a static DSL pool
+
+	# 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
@@ -739,40 +762,38 @@
 #	$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;
+	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.  They should all be within
-      # the $cidr determined above.
-      $sth = $dbh->prepare("delete from freeblocks where cidr <<='$cidr'");
-      $sth->execute;
-
-      # insert "new" freeblocks entry
-      if ($type eq 'rm') {
-	$sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city)".
+
+	# Clear old freeblocks entries - if any.  They should all be within
+	# the $cidr determined above.
+	$sth = $dbh->prepare("delete from freeblocks where cidr <<='$cidr'");
+	$sth->execute;
+
+	# insert "new" freeblocks entry
+	if ($type eq 'rm') {
+	  $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city)".
 		" values ('$cidr',".$cidr->masklen.",'<NULL>')");
-      } else {
-	# Magic hackery to insert "correct" data for deallocation of
-	# non-contained blocks allocated from within a container.
-	$type = 'pr' if $con_type && $con_type eq 'pc';
-
-	$sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)".
+	} else {
+	  # Magic hackery to insert "correct" data for deallocation of
+	  # non-contained blocks allocated from within a container.
+	  $type = 'pr' if $con_type && $con_type eq 'pc';
+
+	  $sth = $dbh->prepare("insert into freeblocks (cidr,maskbits,city,routed)".
 		" values ('$cidr',".$cidr->masklen.
 		",(select city from routed where cidr >>= '$cidr'),'".
 		(($type =~ /^(.)r$/) ? "$1" : 'y')."')");
-      }
-      $sth->execute;
-
-##TEMP
-}
-##TEMP
+	}
+	$sth->execute;
+
+      } # done returning IPs to the appropriate place
 
       # If we got here, we've succeeded.  Whew!
@@ -780,4 +801,5 @@
     }; # end eval
     if ($@) {
+      $msg = $@;
       eval { $dbh->rollback; };
       return ('FAIL', $msg);
@@ -806,17 +828,50 @@
 ## IPDB::mailNotify()
 # Sends notification mail to recipients regarding an IPDB operation
-sub mailNotify ($$$) {
-  my ($recip,$subj,$message) = @_;
-  my $mailer = Net::SMTP->new("smtp.example.com", Hello => "ipdb.example.com");
-
-  $mailer->mail('ipdb@example.com');
-  $mailer->to($recip);
-  $mailer->data("From: \"IP Database\" <ipdb\@example.com>\n",
+sub mailNotify {
+  my $dbh = shift;
+  my ($action,$subj,$message) = @_;
+
+##fixme: need to redesign the breakdown/processing for $action for proper handling of all cases
+
+# split action into parts for fiddlement.  nb: there are almost certainly better ways to do this.
+  my @actionbits = split //, $action;
+
+  # want to notify anyone who has specifically requested notify on *this* type ($action as passed),
+  # on "all static IP types" or "all pool types" (and other last-char-in-type groupings), on eg "all DSL types",
+  # and "all events with this action"
+  my @actionsets = ($action);
+##fixme: ick, eww.  really gotta find a better way to handle this...
+  push @actionsets, ($actionbits[0].'.'.$actionbits[2],
+	$actionbits[0].$actionbits[1].'.', $actionbits[0].'a') if $action =~ /^.{3}$/;
+
+  my $mailer = Net::SMTP->new($smtphost, Hello => "ipdb.$domain");
+
+  # get recip list from db
+  my $sth = $dbh->prepare("SELECT reciplist FROM notify WHERE action=?");
+
+  my %reciplist;
+  foreach (@actionsets) {
+    $sth->execute($_);
+##fixme - need to handle db errors
+    my ($recipsub) = $sth->fetchrow_array;
+    next if !$recipsub;
+    foreach (split(/,/, $recipsub)) {
+      $reciplist{$_}++;
+    }
+  }
+
+  return if !%reciplist;
+
+  foreach my $recip (keys %reciplist) {
+    $mailer->mail("ipdb\@$domain");
+    $mailer->to($recip);
+    $mailer->data("From: \"$org_name IP Database\" <ipdb\@$domain>\n",
 	"To: $recip\n",
 	"Date: ".strftime("%a, %d %b %Y %H:%M:%S %z",localtime)."\n",
 	"Subject: {IPDB} $subj\n",
 	"X-Mailer: IPDB Notify v".sprintf("%.1d",$IPDB::VERSION)."\n",
-	"Organization: Example Corp\n",
+	"Organization: $org_name\n",
 	"\n$message\n");
+  }
   $mailer->quit;
 }
