Index: trunk/DNSDB.pm
===================================================================
--- trunk/DNSDB.pm	(revision 23)
+++ trunk/DNSDB.pm	(revision 24)
@@ -26,4 +26,5 @@
 	&addDomain &delDomain &domainName
 	&addGroup &delGroup &getChildren &groupName
+	&addUser &delUser
 	&getSOA	&getRecLine &getDomRecs
 	&addRec &updateRec &delRec
@@ -37,4 +38,5 @@
 		&addDomain &delDomain &domainName
 		&addGroup &delGroup &getChildren &groupName
+		&addUser &delUser
 		&getSOA &getRecLine &getDomRecs
 		&addRec &updateRec &delRec
@@ -379,5 +381,7 @@
 ## DNSDB::getChildren()
 # Get a list of all groups whose parent^n is group <n>
-# Takes a database handle, group ID, and reference to an array to put the group IDs in
+# Takes a database handle, group ID, reference to an array to put the group IDs in,
+# and an optional flag to return only immediate children or all children-of-children
+# default to returning all children
 # Calls itself
 sub getChildren {
@@ -386,11 +390,12 @@
   my $rootgroup = shift;
   my $groupdest = shift;
+  my $immed = shift || 'all';
 
   # special break for default group;  otherwise we get stuck.
   if ($rootgroup == 1) {
     # by definition, group 1 is the Root Of All Groups
-    my $sth = $dbh->prepare("SELECT group_id FROM groups");
+    my $sth = $dbh->prepare("SELECT group_id FROM groups WHERE NOT (group_id=1)".
+	($immed ne 'all' ? " AND parent_group_id=1" : ''));
     $sth->execute;
-    my @grouplist;
     while (my @this = $sth->fetchrow_array) {
       push @$groupdest, @this;
@@ -403,5 +408,5 @@
     while (my ($group) = $sth->fetchrow_array) {
       push @$groupdest, $group;
-      getChildren($dbh,$group,$groupdest);
+      getChildren($dbh,$group,$groupdest) if $immed eq 'all';
     }
   }
@@ -423,4 +428,61 @@
   return $groupname if $groupname;
 } # end groupName
+
+
+## DNSDB::addUser()
+#
+sub addUser {
+  $errstr = '';
+  my $dbh = shift;
+  return ('FAIL',"Need database handle") if !$dbh;
+  my $username = shift;
+  return ('FAIL',"Missing username") if !defined($username);
+  my $group = shift;
+  return ('FAIL',"Missing group") if !defined($group);
+  my $pass = shift;
+  return ('FAIL',"Missing password") if !defined($pass);
+
+  my $state = shift;
+  return ('FAIL',"Need account status") if !defined($state);
+  my $fname = shift || '';
+  my $lname = shift || '';
+
+  my $user_id;
+
+  # Allow transactions, and raise an exception on errors so we can catch it later.
+  # Use local to make sure these get "reset" properly on exiting this block
+  local $dbh->{AutoCommit} = 0;
+  local $dbh->{RaiseError} = 1;
+
+  # Wrap all the SQL in a transaction
+  eval {
+    # insert the user...
+    my $sth = $dbh->prepare("INSERT INTO users (email,group_id,password,status) VALUES (?,?,?,?)");
+    $sth->execute($username,$group,$pass,$state);
+die "user fail\n";
+
+    # get the ID...
+    $sth = $dbh->prepare("select user_id from users where username=?");
+    $sth->execute($username);
+    ($user_id) = $sth->fetchrow_array();
+
+    # once we get here, we should have suceeded.
+    $dbh->commit;
+  }; # end eval
+
+  if ($@) {
+    my $msg = $@;
+    eval { $dbh->rollback; };
+    return ('FAIL',$msg);
+  } else {
+    return ('OK',$user_id);
+  }
+} # end addUser
+
+
+## DNSDB::delUser()
+#
+sub delUser {
+} # end delUser
 
 
@@ -574,5 +636,6 @@
 
   my $fields = ($defrec eq 'y' ? 'group_id' : 'domain_id').",host,type,val,ttl";
-  my $vallist = "$id,'$host',$rectype,'$val',$ttl";
+  my $vallen = "?,?,?,?,?";
+  my @vallist = ($id,$host,$rectype,$val,$ttl);
 
   my $dist;
@@ -581,21 +644,28 @@
     return ('FAIL',"Need distance for $typemap{$rectype} record") if !defined($dist);
     $fields .= ",distance";
-    $vallist .= ",$dist";
+    $vallen .= ",?";
+    push @vallist, $dist;
   }
   my $weight;
   my $port;
   if ($rectype == $reverse_typemap{SRV}) {
+    # check for _service._protocol.  NB:  RFC2782 does not say "MUST"...  nor "SHOULD"...
+    # it just says (paraphrased) "... is prepended with _ to prevent DNS collisions"
+    return ('FAIL',"SRV records must begin with _service._protocol")
+	if $host !~ /^_[A-Za-z]+\._[A-Za-z]+\.[a-z0-9-]+/;
     $weight = shift;
     $port = shift;
     return ('FAIL',"Need weight and port for SRV record") if !defined($weight) or !defined($port);
     $fields .= ",weight,port";
-    $vallist .= ",$weight,$port";
-  }
-
-  my $sql = "insert into ".($defrec eq 'y' ? 'default_' : '')."records ($fields) values ($vallist)";
+    $vallen .= ",?,?";
+    push @vallist, ($weight,$port);
+  }
+
+  my $sql = "insert into ".($defrec eq 'y' ? 'default_' : '')."records ($fields) values ($vallen)";
+##fixme: use array for values, replace "vallist" with series of ?,?,? etc
 # something is bugging me about this...
 #warn "DEBUG: $sql";
   my $sth = $dbh->prepare($sql);
-  $sth->execute;
+  $sth->execute(@vallist);
 
   return ('FAIL',$sth->errstr) if $sth->err;
