--- loncom/lond	2006/05/30 15:39:56	1.331
+++ loncom/lond	2007/04/10 23:11:30	1.373
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # lond "LON Daemon" Server (port "LOND" 5663)
 #
-# $Id: lond,v 1.331 2006/05/30 15:39:56 www Exp $
+# $Id: lond,v 1.373 2007/04/10 23:11:30 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -33,6 +33,7 @@ use strict;
 use lib '/home/httpd/lib/perl/';
 use LONCAPA;
 use LONCAPA::Configuration;
+use Apache::lonnet;
 
 use IO::Socket;
 use IO::File;
@@ -40,16 +41,15 @@ use IO::File;
 use POSIX;
 use Crypt::IDEA;
 use LWP::UserAgent();
+use Digest::MD5 qw(md5_hex);
 use GDBM_File;
 use Authen::Krb4;
 use Authen::Krb5;
-use lib '/home/httpd/lib/perl/';
 use localauth;
 use localenroll;
 use localstudentphoto;
 use File::Copy;
 use File::Find;
-use LONCAPA::ConfigFileEdit;
 use LONCAPA::lonlocal;
 use LONCAPA::lonssl;
 use Fcntl qw(:flock);
@@ -59,7 +59,7 @@ my $DEBUG = 0;		       # Non zero to ena
 my $status='';
 my $lastlog='';
 
-my $VERSION='$Revision: 1.331 $'; #' stupid emacs
+my $VERSION='$Revision: 1.373 $'; #' stupid emacs
 my $remoteVERSION;
 my $currenthostid="default";
 my $currentdomainid;
@@ -69,7 +69,6 @@ my $clientip;			# IP address of client.
 my $clientname;			# LonCAPA name of client.
 
 my $server;
-my $thisserver;			# DNS of us.
 
 my $keymode;
 
@@ -85,12 +84,6 @@ my $tmpsnum = 0;		# Id of tmpputs.
 
 my $ConnectionType;
 
-my %hostid;			# ID's for hosts in cluster by ip.
-my %hostdom;			# LonCAPA domain for hosts in cluster.
-my %hostname;			# DNSname -> ID's mapping.
-my %hostip;			# IPs for hosts in cluster.
-my %hostdns;			# ID's of hosts looked up by DNS name.
-
 my %managers;			# Ip -> manager names
 
 my %perlvar;			# Will have the apache conf defined perl vars.
@@ -178,19 +171,16 @@ sub ResetStatistics {
 #   $Socket      - Socket open on client.
 #   $initcmd     - The full text of the init command.
 #
-# Implicit inputs:
-#    $thisserver - Our DNS name.
-#
 # Returns:
 #     IDEA session key on success.
 #     undef on failure.
 #
 sub LocalConnection {
     my ($Socket, $initcmd) = @_;
-    Debug("Attempting local connection: $initcmd client: $clientip me: $thisserver");
+    Debug("Attempting local connection: $initcmd client: $clientip");
     if($clientip ne "127.0.0.1") {
 	&logthis('<font color="red"> LocalConnection rejecting non local: '
-		 ."$clientip ne $thisserver </font>");
+		 ."$clientip ne 127.0.0.1 </font>");
 	close $Socket;
 	return undef;
     }  else {
@@ -424,7 +414,7 @@ sub ReadManagerTable {
       if ($host =~ "^#") {                  # Comment line.
          next;
       }
-      if (!defined $hostip{$host}) { # This is a non cluster member
+      if (!defined &Apache::lonnet::get_host_ip($host)) { # This is a non cluster member
 	    #  The entry is of the form:
 	    #    cluname:hostname
 	    #  cluname - A 'cluster hostname' is needed in order to negotiate
@@ -442,7 +432,7 @@ sub ReadManagerTable {
          }
       } else {
          logthis('<font color="green"> existing host'." $host</font>\n");
-         $managers{$hostip{$host}} = $host;  # Use info from cluster tab if clumemeber
+         $managers{&Apache::lonnet::get_host_ip($host)} = $host;  # Use info from cluster tab if clumemeber
       }
    }
 }
@@ -503,30 +493,30 @@ sub AdjustHostContents {
     my $adjusted;
     my $me        = $perlvar{'lonHostID'};
 
- foreach my $line (split(/\n/,$contents)) {
+    foreach my $line (split(/\n/,$contents)) {
 	if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/))) {
 	    chomp($line);
 	    my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon)=split(/:/,$line);
 	    if ($id eq $me) {
-          my $ip = gethostbyname($name);
-          my $ipnew = inet_ntoa($ip);
-         $ip = $ipnew;
+		my $ip = gethostbyname($name);
+		my $ipnew = inet_ntoa($ip);
+		$ip = $ipnew;
 		#  Reconstruct the host line and append to adjusted:
 		
-		   my $newline = "$id:$domain:$role:$name:$ip";
-		   if($maxcon ne "") { # Not all hosts have loncnew tuning params
-		     $newline .= ":$maxcon:$idleto:$mincon";
-		   }
-		   $adjusted .= $newline."\n";
+		my $newline = "$id:$domain:$role:$name:$ip";
+		if($maxcon ne "") { # Not all hosts have loncnew tuning params
+		    $newline .= ":$maxcon:$idleto:$mincon";
+		}
+		$adjusted .= $newline."\n";
 		
-      } else {		# Not me, pass unmodified.
-		   $adjusted .= $line."\n";
-      }
+	    } else {		# Not me, pass unmodified.
+		$adjusted .= $line."\n";
+	    }
 	} else {                  # Blank or comment never re-written.
 	    $adjusted .= $line."\n";	# Pass blanks and comments as is.
 	}
- }
- return $adjusted;
+    }
+    return $adjusted;
 }
 #
 #   InstallFile: Called to install an administrative file:
@@ -835,16 +825,14 @@ sub AdjustOurHost {
     #   Use the config line to get my hostname.
     #   Use gethostbyname to translate that into an IP address.
     #
-    my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon) = split(/:/,$ConfigLine);
-    my $BinaryIp = gethostbyname($name);
-    my $ip       = inet_ntoa($ip);
+    my ($id,$domain,$role,$name,$maxcon,$idleto,$mincon) = split(/:/,$ConfigLine);
     #
     #  Reassemble the config line from the elements in the list.
     #  Note that if the loncnew items were not present before, they will
     #  be now even if they would be empty
     #
     my $newConfigLine = $id;
-    foreach my $item ($domain, $role, $name, $ip, $maxcon, $idleto, $mincon) {
+    foreach my $item ($domain, $role, $name, $maxcon, $idleto, $mincon) {
 	$newConfigLine .= ":".$item;
     }
     #  Replace the line:
@@ -890,11 +878,11 @@ sub EditFile {
 
     #  Split the command into it's pieces:  edit:filetype:script
 
-    my ($request, $filetype, $script) = split(/:/, $request,3);	# : in script
+    my ($cmd, $filetype, $script) = split(/:/, $request,3);	# : in script
 
     #  Check the pre-coditions for success:
 
-    if($request != "edit") {	# Something is amiss afoot alack.
+    if($cmd != "edit") {	# Something is amiss afoot alack.
 	return "error:edit request detected, but request != 'edit'\n";
     }
     if( ($filetype ne "hosts")  &&
@@ -1034,7 +1022,7 @@ sub ping_handler {
 sub pong_handler {
     my ($cmd, $tail, $replyfd) = @_;
 
-    my $reply=&reply("ping",$clientname);
+    my $reply=&Apache::lonnet::reply("ping",$clientname);
     &Reply( $replyfd, "$currenthostid:$reply\n", "$cmd:$tail"); 
     return 1;
 }
@@ -1144,7 +1132,7 @@ sub load_handler {
 sub user_load_handler {
     my ($cmd, $tail, $replyfd) = @_;
 
-    my $userloadpercent=&userload();
+    my $userloadpercent=&Apache::lonnet::userload();
     &Reply($replyfd, "$userloadpercent\n", "$cmd:$tail");
     
     return 1;
@@ -1252,7 +1240,7 @@ sub push_file_handler {
 #
 sub du_handler {
     my ($cmd, $ududir, $client) = @_;
-    my ($ududir) = split(/:/,$ududir); # Make 'telnet' testing easier.
+    ($ududir) = split(/:/,$ududir); # Make 'telnet' testing easier.
     my $userinput = "$cmd:$ududir";
 
     if ($ududir=~/\.\./ || $ududir!~m|^/home/httpd/|) {
@@ -1270,6 +1258,7 @@ sub du_handler {
 	my $code=sub { 
 	    if ($_=~/\.\d+\./) { return;} 
 	    if ($_=~/\.meta$/) { return;}
+	    if (-d $_)         { return;}
 	    $total_size+=(stat($_))[7];
 	};
 	chdir($ududir);
@@ -1576,17 +1565,24 @@ sub change_password_handler {
     #  uname - Username.
     #  upass - Current password.
     #  npass - New password.
+    #  context - Context in which this was called 
+    #            (preferences or reset_by_email).
    
-    my ($udom,$uname,$upass,$npass)=split(/:/,$tail);
+    my ($udom,$uname,$upass,$npass,$context)=split(/:/,$tail);
 
     $upass=&unescape($upass);
     $npass=&unescape($npass);
     &Debug("Trying to change password for $uname");
 
     # First require that the user can be authenticated with their
-    # old password:
-
-    my $validated = &validate_user($udom, $uname, $upass);
+    # old password unless context was 'reset_by_email':
+    
+    my $validated;
+    if ($context eq 'reset_by_email') {
+        $validated = 1;
+    } else {
+        $validated = &validate_user($udom, $uname, $upass);
+    }
     if($validated) {
 	my $realpasswd  = &get_auth_type($udom, $uname); # Defined since authd.
 	
@@ -1605,7 +1601,7 @@ sub change_password_handler {
 			 ."to change password");
 		&Failure( $client, "non_authorized\n",$userinput);
 	    }
-	} elsif ($howpwd eq 'unix') {
+	} elsif ($howpwd eq 'unix' && $context ne 'reset_by_email') {
 	    my $result = &change_unix_password($uname, $npass);
 	    &logthis("Result of password change for $uname: ".
 		     $result);
@@ -1844,12 +1840,13 @@ sub update_resource_handler {
 	    my $now=time;
 	    my $since=$now-$atime;
 	    if ($since>$perlvar{'lonExpire'}) {
-		my $reply=&reply("unsub:$fname","$clientname");
+		my $reply=&Apache::lonnet::reply("unsub:$fname","$clientname");
 		&devalidate_meta_cache($fname);
 		unlink("$fname");
+		unlink("$fname.meta");
 	    } else {
 		my $transname="$fname.in.transfer";
-		my $remoteurl=&reply("sub:$fname","$clientname");
+		my $remoteurl=&Apache::lonnet::reply("sub:$fname","$clientname");
 		my $response;
 		alarm(120);
 		{
@@ -1894,22 +1891,12 @@ sub devalidate_meta_cache {
     my ($url) = @_;
     use Cache::Memcached;
     my $memcache = new Cache::Memcached({'servers'=>['127.0.0.1:11211']});
-    $url = &declutter($url);
+    $url = &Apache::lonnet::declutter($url);
     $url =~ s-\.meta$--;
     my $id = &escape('meta:'.$url);
     $memcache->delete($id);
 }
 
-sub declutter {
-    my $thisfn=shift;
-    $thisfn=~s/^\Q$perlvar{'lonDocRoot'}\E//;
-    $thisfn=~s/^\///;
-    $thisfn=~s|^adm/wrapper/||;
-    $thisfn=~s|^adm/coursedocs/showdoc/||;
-    $thisfn=~s/^res\///;
-    $thisfn=~s/\?.+$//;
-    return $thisfn;
-}
 #
 #   Fetch a user file from a remote server to the user's home directory
 #   userfiles subdir.
@@ -2124,13 +2111,21 @@ sub token_auth_user_file_handler {
     
     chomp($session);
     my $reply="non_auth\n";
-    if (open(ENVIN,$perlvar{'lonIDsDir'}.'/'.
-	     $session.'.id')) {
-	while (my $line=<ENVIN>) {
-	    my ($envname)=split(/=/,$line,2);
-	    $envname=&unescape($envname);
-	    if ($envname=~ m|^userfile\.\Q$fname\E|) { $reply="ok\n"; }
+    my $file = $perlvar{'lonIDsDir'}.'/'.$session.'.id';
+    if (open(ENVIN,"$file")) {
+	flock(ENVIN,LOCK_SH);
+	tie(my %disk_env,'GDBM_File',"$file",&GDBM_READER(),0640);
+	if (exists($disk_env{"userfile.$fname"})) {
+	    $reply="ok\n";
+	} else {
+	    foreach my $envname (keys(%disk_env)) {
+		if ($envname=~ m|^userfile\.\Q$fname\E|) {
+		    $reply="ok\n";
+		    last;
+		}
+	    }
 	}
+	untie(%disk_env);
 	close(ENVIN);
 	&Reply($client, $reply, "$cmd:$tail");
     } else {
@@ -2593,7 +2588,7 @@ sub get_profile_entry_encrypted {
 
     my $userinput = "$cmd:$tail";
    
-    my ($cmd,$udom,$uname,$namespace,$what) = split(/:/,$userinput);
+    my ($udom,$uname,$namespace,$what) = split(/:/,$tail);
     chomp($what);
     my $qresult = read_profile($udom, $uname, $namespace, $what);
     my ($first) = split(/:/, $qresult);
@@ -3038,10 +3033,10 @@ sub restore_handler {
     my ($cmd, $tail, $client) = @_;
 
     my $userinput = "$cmd:$tail";	# Only used for logging purposes.
-
-    my ($cmd,$udom,$uname,$namespace,$rid) = split(/:/,$userinput);
+    my ($udom,$uname,$namespace,$rid) = split(/:/,$tail);
     $namespace=~s/\//\_/g;
-    $namespace=~s/\W//g;
+    $namespace = &LONCAPA::clean_username($namespace);
+
     chomp($rid);
     my $qresult='';
     my $hashref = &tie_user_hash($udom, $uname, $namespace, &GDBM_READER());
@@ -3214,7 +3209,7 @@ sub reply_query_handler {
 
     my $userinput = "$cmd:$tail";
 
-    my ($cmd,$id,$reply)=split(/:/,$userinput); 
+    my ($id,$reply)=split(/:/,$tail); 
     my $store;
     my $execdir=$perlvar{'lonDaemons'};
     if ($store=IO::File->new(">$execdir/tmp/$id")) {
@@ -3278,19 +3273,20 @@ sub put_course_id_handler {
 	foreach my $pair (@pairs) {
             my ($key,$courseinfo) = split(/=/,$pair,2);
             $courseinfo =~ s/=/:/g;
-
-            my @current_items = split(/:/,$hashref->{$key});
+            my @current_items = split(/:/,$hashref->{$key},-1);
             shift(@current_items); # remove description
             pop(@current_items);   # remove last access
             my $numcurrent = scalar(@current_items);
-
-            my @new_items = split(/:/,$courseinfo);
+            if ($numcurrent > 3) {
+                $numcurrent = 3;
+            }
+            my @new_items = split(/:/,$courseinfo,-1);
             my $numnew = scalar(@new_items);
             if ($numcurrent > 0) {
-                if ($numnew == 1) { # flushcourselogs() from 1.1 or earlier
-                    $courseinfo .= ':'.join(':',@current_items);
-                } elsif ($numnew == 2) { # flushcourselogs() from 1.2.X
-                    $courseinfo .= ':'.$current_items[$numcurrent-1];
+                if ($numnew <= $numcurrent) { # flushcourselogs() from pre 2.2 
+                    for (my $j=$numcurrent-$numnew; $j>=0; $j--) {
+                        $courseinfo .= ':'.$current_items[$numcurrent-$j-1];
+                    }
                 }
             }
 	    $hashref->{$key}=$courseinfo.':'.$now;
@@ -3334,12 +3330,11 @@ sub put_course_id_handler {
 #                 institutional code - optional supplied code to filter 
 #                            the dump. Only courses with an institutional code 
 #                            that match the supplied code will be returned.
-#                 owner    - optional supplied username of owner to filter
-#                            the dump.  Only courses for which the course 
-#                            owner matches the supplied username will be
-#                            returned. Implicit assumption that owner
-#                            is a user in the domain in which the
-#                            course database is defined.
+#                 owner    - optional supplied username and domain of owner to
+#                            filter the dump.  Only courses for which the course
+#                            owner matches the supplied username and/or domain
+#                            will be returned. Pre-2.2.0 legacy entries from 
+#                            nohist_courseiddump will only contain usernames.
 #     $client  - The socket open on the client.
 # Returns:
 #    1     - Continue processing.
@@ -3350,7 +3345,8 @@ sub dump_course_id_handler {
 
     my $userinput = "$cmd:$tail";
 
-    my ($udom,$since,$description,$instcodefilter,$ownerfilter,$coursefilter) =split(/:/,$tail);
+    my ($udom,$since,$description,$instcodefilter,$ownerfilter,$coursefilter,
+        $typefilter,$regexp_ok) =split(/:/,$tail);
     if (defined($description)) {
 	$description=&unescape($description);
     } else {
@@ -3361,26 +3357,45 @@ sub dump_course_id_handler {
     } else {
         $instcodefilter='.';
     }
+    my ($ownerunamefilter,$ownerdomfilter);
     if (defined($ownerfilter)) {
         $ownerfilter=&unescape($ownerfilter);
+        if ($ownerfilter ne '.' && defined($ownerfilter)) {
+            if ($ownerfilter =~ /^([^:]*):([^:]*)$/) {
+                 $ownerunamefilter = $1;
+                 $ownerdomfilter = $2;
+            } else {
+                $ownerunamefilter = $ownerfilter;
+                $ownerdomfilter = '';
+            }
+        }
     } else {
         $ownerfilter='.';
     }
+
     if (defined($coursefilter)) {
         $coursefilter=&unescape($coursefilter);
     } else {
         $coursefilter='.';
     }
+    if (defined($typefilter)) {
+        $typefilter=&unescape($typefilter);
+    } else {
+        $typefilter='.';
+    }
+    if (defined($regexp_ok)) {
+        $regexp_ok=&unescape($regexp_ok);
+    }
 
     unless (defined($since)) { $since=0; }
     my $qresult='';
     my $hashref = &tie_domain_hash($udom, "nohist_courseids", &GDBM_WRCREAT());
     if ($hashref) {
 	while (my ($key,$value) = each(%$hashref)) {
-	    my ($descr,$lasttime,$inst_code,$owner);
+	    my ($descr,$lasttime,$inst_code,$owner,$type);
             my @courseitems = split(/:/,$value);
             $lasttime = pop(@courseitems);
-	    ($descr,$inst_code,$owner)=@courseitems;
+	    ($descr,$inst_code,$owner,$type)=@courseitems;
 	    if ($lasttime<$since) { next; }
             my $match = 1;
 	    unless ($description eq '.') {
@@ -3391,14 +3406,49 @@ sub dump_course_id_handler {
             }
             unless ($instcodefilter eq '.' || !defined($instcodefilter)) {
                 my $unescapeInstcode = &unescape($inst_code);
-                unless (eval('$unescapeInstcode=~/\Q$instcodefilter\E/i')) {
-                    $match = 0;
+                if ($regexp_ok) {
+                    unless (eval('$unescapeInstcode=~/$instcodefilter/')) {
+                        $match = 0;
+                    }
+                } else {
+                    unless (eval('$unescapeInstcode=~/\Q$instcodefilter\E/i')) {
+                        $match = 0;
+                    }
                 }
 	    }
             unless ($ownerfilter eq '.' || !defined($ownerfilter)) {
                 my $unescapeOwner = &unescape($owner);
-                unless (eval('$unescapeOwner=~/\Q$ownerfilter\E/i')) {
-                    $match = 0;
+                if (($ownerunamefilter ne '') && ($ownerdomfilter ne '')) {
+                    if ($unescapeOwner =~ /:/) {
+                        if (eval('$unescapeOwner !~ 
+                             /\Q$ownerunamefilter\E:\Q$ownerdomfilter\E$/i')) {
+                            $match = 0;
+                        } 
+                    } else {
+                        if (eval('$unescapeOwner!~/\Q$ownerunamefilter\E/i')) {
+                            $match = 0;
+                        }
+                    }
+                } elsif ($ownerunamefilter ne '') {
+                    if ($unescapeOwner =~ /:/) {
+                        if (eval('$unescapeOwner!~/\Q$ownerunamefilter\E:[^:]+$/i')) {
+                             $match = 0;
+                        }
+                    } else {
+                        if (eval('$unescapeOwner!~/\Q$ownerunamefilter\E/i')) {
+                            $match = 0;
+                        }
+                    }
+                } elsif ($ownerdomfilter ne '') {
+                    if ($unescapeOwner =~ /:/) {
+                        if (eval('$unescapeOwner!~/^[^:]+:\Q$ownerdomfilter\E/')) {
+                             $match = 0;
+                        }
+                    } else {
+                        if ($ownerdomfilter ne $udom) {
+                            $match = 0;
+                        }
+                    }
                 }
             }
             unless ($coursefilter eq '.' || !defined($coursefilter)) {
@@ -3407,6 +3457,18 @@ sub dump_course_id_handler {
                     $match = 0;
                 }
             }
+            unless ($typefilter eq '.' || !defined($typefilter)) {
+                my $unescapeType = &unescape($type);
+                if ($type eq '') {
+                    if ($typefilter ne 'Course') {
+                        $match = 0;
+                    }
+                } else { 
+                    unless (eval('$unescapeType=~/^\Q$typefilter\E$/')) {
+                        $match = 0;
+                    }
+                }
+            }
             if ($match == 1) {
                 $qresult.=$key.'='.$descr.':'.$inst_code.':'.$owner.'&';
             }
@@ -3429,6 +3491,99 @@ sub dump_course_id_handler {
 &register_handler("courseiddump", \&dump_course_id_handler, 0, 1, 0);
 
 #
+# Puts an unencrypted entry in a namespace db file at the domain level 
+#
+# Parameters:
+#    $cmd      - The command that got us here.
+#    $tail     - Tail of the command (remaining parameters).
+#    $client   - File descriptor connected to client.
+# Returns
+#     0        - Requested to exit, caller should shut down.
+#     1        - Continue processing.
+#  Side effects:
+#     reply is written to $client.
+#
+sub put_domain_handler {
+    my ($cmd,$tail,$client) = @_;
+
+    my $userinput = "$cmd:$tail";
+
+    my ($udom,$namespace,$what) =split(/:/,$tail,3);
+    chomp($what);
+    my @pairs=split(/\&/,$what);
+    my $hashref = &tie_domain_hash($udom, "$namespace", &GDBM_WRCREAT(),
+                                   "P", $what);
+    if ($hashref) {
+        foreach my $pair (@pairs) {
+            my ($key,$value)=split(/=/,$pair);
+            $hashref->{$key}=$value;
+        }
+        if (&untie_domain_hash($hashref)) {
+            &Reply($client, "ok\n", $userinput);
+        } else {
+            &Failure($client, "error: ".($!+0)." untie(GDBM) Failed ".
+                     "while attempting putdom\n", $userinput);
+        }
+    } else {
+        &Failure( $client, "error: ".($!+0)." tie(GDBM) Failed ".
+                  "while attempting putdom\n", $userinput);
+    }
+
+    return 1;
+}
+&register_handler("putdom", \&put_domain_handler, 0, 1, 0);
+
+# Unencrypted get from the namespace database file at the domain level.
+# This function retrieves a keyed item from a specific named database in the
+# domain directory.
+#
+# Parameters:
+#   $cmd             - Command request keyword (get).
+#   $tail            - Tail of the command.  This is a colon separated list
+#                      consisting of the domain and the 'namespace' 
+#                      which selects the gdbm file to do the lookup in,
+#                      & separated list of keys to lookup.  Note that
+#                      the values are returned as an & separated list too.
+#   $client          - File descriptor open on the client.
+# Returns:
+#   1       - Continue processing.
+#   0       - Exit.
+#  Side effects:
+#     reply is written to $client.
+#
+
+sub get_domain_handler {
+    my ($cmd, $tail, $client) = @_;
+
+    my $userinput = "$client:$tail";
+
+    my ($udom,$namespace,$what)=split(/:/,$tail,3);
+    chomp($what);
+    my @queries=split(/\&/,$what);
+    my $qresult='';
+    my $hashref = &tie_domain_hash($udom, "$namespace", &GDBM_READER());
+    if ($hashref) {
+        for (my $i=0;$i<=$#queries;$i++) {
+            $qresult.="$hashref->{$queries[$i]}&";
+        }
+        if (&untie_domain_hash($hashref)) {
+            $qresult=~s/\&$//;
+            &Reply($client, "$qresult\n", $userinput);
+        } else {
+            &Failure( $client, "error: ".($!+0)." untie(GDBM) Failed ".
+                      "while attempting getdom\n",$userinput);
+        }
+    } else {
+        &Failure($client, "error: ".($!+0)." tie(GDBM) Failed ".
+                 "while attempting getdom\n",$userinput);
+    }
+
+    return 1;
+}
+&register_handler("getdom", \&get_domain_handler, 0, 1, 0);
+
+
+#
 #  Puts an id to a domains id database. 
 #
 #  Parameters:
@@ -3799,15 +3954,23 @@ sub tmp_put_handler {
 
     my $userinput = "$cmd:$what";	# Reconstruct for logging.
 
-
-    my $store;
+    my ($record,$context) = split(/:/,$what);
+    if ($context ne '') {
+        chomp($context);
+        $context = &unescape($context);
+    }
+    my ($id,$store);
     $tmpsnum++;
-    my $id=$$.'_'.$clientip.'_'.$tmpsnum;
+    if ($context eq 'resetpw') {
+        $id = &md5_hex(&md5_hex(time.{}.rand().$$));
+    } else {
+        $id = $$.'_'.$clientip.'_'.$tmpsnum;
+    }
     $id=~s/\W/\_/g;
-    $what=~s/\n//g;
+    $record=~s/\n//g;
     my $execdir=$perlvar{'lonDaemons'};
     if ($store=IO::File->new(">$execdir/tmp/$id.tmp")) {
-	print $store $what;
+	print $store $record;
 	close $store;
 	&Reply($client, "$id\n", $userinput);
     } else {
@@ -4024,7 +4187,8 @@ sub enrollment_enabled_handler {
     my $userinput = $cmd.":".$tail; # For logging purposes.
 
     
-    my $cdom = split(/:/, $tail);   # Domain we're asking about.
+    my ($cdom) = split(/:/, $tail, 2);   # Domain we're asking about.
+
     my $outcome  = &localenroll::run($cdom);
     &Reply($client, "$outcome\n", $userinput);
 
@@ -4080,6 +4244,7 @@ sub validate_course_owner_handler {
     my $userinput = "$cmd:$tail";
     my ($inst_course_id, $owner, $cdom) = split(/:/, $tail);
 
+    $owner = &unescape($owner);
     my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom);
     &Reply($client, "$outcome\n", $userinput);
 
@@ -4120,16 +4285,47 @@ sub validate_course_section_handler {
 &register_handler("autovalidatecourse", \&validate_course_section_handler, 0, 1, 0);
 
 #
-#   Create a password for a new auto-enrollment user.
-#   I think/guess, this password allows access to the institutions 
-#   AIS class list server/services.  Stuart can correct this comment
-#   when he finds out how wrong I am.
+#   Validate course owner's access to enrollment data for specific class section. 
+#   
+#
+# Formal Parameters:
+#    $cmd     - The command request that got us dispatched.
+#    $tail    - The tail of the command.   In this case this is a colon separated
+#               set of words that will be split into:
+#               $inst_class  - Institutional code for the specific class section   
+#               $courseowner - The escaped username:domain of the course owner 
+#               $cdom        - The domain of the course from the institution's
+#                              point of view.
+#    $client  - The socket open on the client.
+# Returns:
+#    1 - continue processing.
+#
+
+sub validate_class_access_handler {
+    my ($cmd, $tail, $client) = @_;
+    my $userinput = "$cmd:$tail";
+    my ($inst_class,$courseowner,$cdom) = split(/:/, $tail);
+    $courseowner = &unescape($courseowner);
+    my $outcome;
+    eval {
+	local($SIG{__DIE__})='DEFAULT';
+	$outcome=&localenroll::check_section($inst_class,$courseowner,$cdom);
+    };
+    &Reply($client,"$outcome\n", $userinput);
+
+    return 1;
+}
+&register_handler("autovalidateclass_sec", \&validate_class_access_handler, 0, 1, 0);
+
+#
+#   Create a password for a new LON-CAPA user added by auto-enrollment.
+#   Only used for case where authentication method for new user is localauth
 #
 # Formal Parameters:
 #    $cmd     - The command request that got us dispatched.
 #    $tail    - The tail of the command.   In this case this is a colon separated
 #               set of words that will be split into:
-#               $authparam - An authentication parameter (username??).
+#               $authparam - An authentication parameter (localauth parameter).
 #               $cdom      - The domain of the course from the institution's
 #                            point of view.
 #    $client  - The socket open on the client.
@@ -4236,10 +4432,10 @@ sub get_institutional_code_format_handle
 						    \%cat_titles,
 						    \%cat_order);
     if ($formatreply eq 'ok') {
-	my $codes_str = &hash2str(%codes);
-	my $codetitles_str = &array2str(@codetitles);
-	my $cat_titles_str = &hash2str(%cat_titles);
-	my $cat_order_str = &hash2str(%cat_order);
+	my $codes_str = &Apache::lonnet::hash2str(%codes);
+	my $codetitles_str = &Apache::lonnet::array2str(@codetitles);
+	my $cat_titles_str = &Apache::lonnet::hash2str(%cat_titles);
+	my $cat_order_str = &Apache::lonnet::hash2str(%cat_order);
 	&Reply($client,
 	       $codes_str.':'.$codetitles_str.':'.$cat_titles_str.':'
 	       .$cat_order_str."\n",
@@ -4256,6 +4452,38 @@ sub get_institutional_code_format_handle
 &register_handler("autoinstcodeformat",
 		  \&get_institutional_code_format_handler,0,1,0);
 
+sub get_institutional_defaults_handler {
+    my ($cmd, $tail, $client)   = @_;
+    my $userinput               = "$cmd:$tail";
+
+    my $dom = $tail;
+    my %defaults_hash;
+    my @code_order;
+    my $outcome;
+    eval {
+        local($SIG{__DIE__})='DEFAULT';
+        $outcome = &localenroll::instcode_defaults($dom,\%defaults_hash,
+                                                   \@code_order);
+    };
+    if (!$@) {
+        if ($outcome eq 'ok') {
+            my $result='';
+            while (my ($key,$value) = each(%defaults_hash)) {
+                $result.=&escape($key).'='.&escape($value).'&';
+            }
+            $result .= 'code_order='.&escape(join('&',@code_order));
+            &Reply($client,$result."\n",$userinput);
+        } else {
+            &Reply($client,"error\n", $userinput);
+        }
+    } else {
+        &Failure($client,"unknown_cmd\n",$userinput);
+    }
+}
+&register_handler("autoinstcodedefaults",
+                  \&get_institutional_defaults_handler,0,1,0);
+
+
 # Get domain specific conditions for import of student photographs to a course
 #
 # Retrieves information from photo_permission subroutine in localenroll.
@@ -4383,6 +4611,35 @@ sub student_photo_handler {
 }
 &register_handler("studentphoto", \&student_photo_handler, 0, 1, 0);
 
+sub inst_usertypes_handler {
+    my ($cmd, $domain, $client) = @_;
+    my $res;
+    my $userinput = $cmd.":".$domain; # For logging purposes.
+    my (%typeshash,@order,$result);
+    eval {
+	local($SIG{__DIE__})='DEFAULT';
+	$result=&localenroll::inst_usertypes($domain,\%typeshash,\@order);
+    };
+    if ($result eq 'ok') {
+        if (keys(%typeshash) > 0) {
+            foreach my $key (keys(%typeshash)) {
+                $res.=&escape($key).'='.&escape($typeshash{$key}).'&';
+            }
+        }
+        $res=~s/\&$//;
+        $res .= ':';
+        if (@order > 0) {
+            foreach my $item (@order) {
+                $res .= &escape($item).'&';
+            }
+        }
+        $res=~s/\&$//;
+    }
+    &Reply($client, "$res\n", $userinput);
+    return 1;
+}
+&register_handler("inst_usertypes", \&inst_usertypes_handler, 0, 1, 0);
+
 # mkpath makes all directories for a file, expects an absolute path with a
 # file or a trailing / if just a dir is passed
 # returns 1 on success 0 on failure
@@ -4646,7 +4903,7 @@ sub catchexception {
     $SIG{__DIE__}='DEFAULT';
     &status("Catching exception");
     &logthis("<font color='red'>CRITICAL: "
-     ."ABNORMAL EXIT. Child $$ for server $thisserver died through "
+     ."ABNORMAL EXIT. Child $$ for server ".$perlvar{'lonHostID'}." died through "
      ."a crash with this error msg->[$error]</font>");
     &logthis('Famous last words: '.$status.' - '.$lastlog);
     if ($client) { print $client "error: $error\n"; }
@@ -4757,67 +5014,6 @@ sub HUPSMAN {                      # sig
 }
 
 #
-#    Kill off hashes that describe the host table prior to re-reading it.
-#    Hashes affected are:
-#       %hostid, %hostdom %hostip %hostdns.
-#
-sub KillHostHashes {
-    foreach my $key (keys %hostid) {
-	delete $hostid{$key};
-    }
-    foreach my $key (keys %hostdom) {
-	delete $hostdom{$key};
-    }
-    foreach my $key (keys %hostip) {
-	delete $hostip{$key};
-    }
-    foreach my $key (keys %hostdns) {
-	delete $hostdns{$key};
-    }
-}
-#
-#   Read in the host table from file and distribute it into the various hashes:
-#
-#    - %hostid  -  Indexed by IP, the loncapa hostname.
-#    - %hostdom -  Indexed by  loncapa hostname, the domain.
-#    - %hostip  -  Indexed by hostid, the Ip address of the host.
-sub ReadHostTable {
-
-    open (CONFIG,"$perlvar{'lonTabDir'}/hosts.tab") || die "Can't read host file";
-    my $myloncapaname = $perlvar{'lonHostID'};
-    Debug("My loncapa name is : $myloncapaname");
-    my %name_to_ip;
-    while (my $configline=<CONFIG>) {
-	if ($configline !~ /^\s*\#/ && $configline !~ /^\s*$/ ) {
-	    my ($id,$domain,$role,$name)=split(/:/,$configline);
-	    $name=~s/\s//g;
-	    my $ip;
-	    if (!exists($name_to_ip{$name})) {
-		$ip = gethostbyname($name);
-		if (!$ip || length($ip) ne 4) {
-		    &logthis("Skipping host $id name $name no IP found\n");
-		    next;
-		}
-		$ip=inet_ntoa($ip);
-		$name_to_ip{$name} = $ip;
-	    } else {
-		$ip = $name_to_ip{$name};
-	    }
-	    $hostid{$ip}=$id;         # LonCAPA name of host by IP.
-	    $hostdom{$id}=$domain;    # LonCAPA domain name of host. 
-	    $hostname{$id}=$name;     # LonCAPA name -> DNS name
-	    $hostip{$id}=$ip;         # IP address of host.
-	    $hostdns{$name} = $id;    # LonCAPA name of host by DNS.
-
-	    if ($id eq $perlvar{'lonHostID'}) { 
-		Debug("Found me in the host table: $name");
-		$thisserver=$name; 
-	    }
-	}
-    }
-    close(CONFIG);
-}
-#
 #  Reload the Apache daemon's state.
 #  This is done by invoking /home/httpd/perl/apachereload
 #  a setuid perl script that can be root for us to do this job.
@@ -4848,13 +5044,11 @@ sub UpdateHosts {
     #  either dropped or changed hosts.  Note that the re-read of the table
     #  will take care of new and changed hosts as connections come into being.
 
+    &Apache::lonnet::reset_hosts_info();
 
-    KillHostHashes;
-    ReadHostTable;
-
-    foreach my $child (keys %children) {
+    foreach my $child (keys(%children)) {
 	my $childip = $children{$child};
-	if(!$hostid{$childip}) {
+	if (!defined(&Apache::lonnet::get_hosts_from_ip($childip))) {
 	    logthis('<font color="blue"> UpdateHosts killing child '
 		    ." $child for ip $childip </font>");
 	    kill('INT', $child);
@@ -5014,63 +5208,6 @@ sub status {
     $0='lond: '.$what.' '.$local;
 }
 
-# ----------------------------------------------------------- Send USR1 to lonc
-
-sub reconlonc {
-    my $peerfile=shift;
-    &logthis("Trying to reconnect for $peerfile");
-    my $loncfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
-    if (my $fh=IO::File->new("$loncfile")) {
-	my $loncpid=<$fh>;
-        chomp($loncpid);
-        if (kill 0 => $loncpid) {
-	    &logthis("lonc at pid $loncpid responding, sending USR1");
-            kill USR1 => $loncpid;
-        } else {
-	    &logthis(
-              "<font color='red'>CRITICAL: "
-             ."lonc at pid $loncpid not responding, giving up</font>");
-        }
-    } else {
-      &logthis('<font color="red">CRITICAL: lonc not running, giving up</font>');
-    }
-}
-
-# -------------------------------------------------- Non-critical communication
-
-sub subreply {
-    my ($cmd,$server)=@_;
-    my $peerfile="$perlvar{'lonSockDir'}/".$hostname{$server};
-    my $sclient=IO::Socket::UNIX->new(Peer    =>"$peerfile",
-                                      Type    => SOCK_STREAM,
-                                      Timeout => 10)
-       or return "con_lost";
-    print $sclient "sethost:$server:$cmd\n";
-    my $answer=<$sclient>;
-    chomp($answer);
-    if (!$answer) { $answer="con_lost"; }
-    return $answer;
-}
-
-sub reply {
-  my ($cmd,$server)=@_;
-  my $answer;
-  if ($server ne $currenthostid) { 
-    $answer=subreply($cmd,$server);
-    if ($answer eq 'con_lost') {
-	$answer=subreply("ping",$server);
-        if ($answer ne $server) {
-	    &logthis("sub reply: answer != server answer is $answer, server is $server");
-           &reconlonc("$perlvar{'lonSockDir'}/".$hostname{$server});
-        }
-        $answer=subreply($cmd,$server);
-    }
-  } else {
-    $answer='self_reply';
-  } 
-  return $answer;
-}
-
 # -------------------------------------------------------------- Talk to lonsql
 
 sub sql_reply {
@@ -5139,8 +5276,7 @@ $SIG{USR1} = \&checkchildren;
 $SIG{USR2} = \&UpdateHosts;
 
 #  Read the host hashes:
-
-ReadHostTable;
+&Apache::lonnet::load_hosts_tab();
 
 my $dist=`$perlvar{'lonDaemons'}/distprobe`;
 
@@ -5219,7 +5355,8 @@ sub make_new_child {
 #        my $tmpsnum=0;            # Now global
 #---------------------------------------------------- kerberos 5 initialization
         &Authen::Krb5::init_context();
-	unless (($dist eq 'fedora4') || ($dist eq 'suse9.3')) {
+	unless (($dist eq 'fedora5') || ($dist eq 'fedora4') ||  
+		($dist eq 'fedora6') || ($dist eq 'suse9.3')) {
 	    &Authen::Krb5::init_ets();
 	}
 
@@ -5229,19 +5366,17 @@ sub make_new_child {
 # -----------------------------------------------------------------------------
 	# see if we know client and 'check' for spoof IP by ineffective challenge
 
-	ReadManagerTable;	# May also be a manager!!
-	
 	my $outsideip=$clientip;
 	if ($clientip eq '127.0.0.1') {
-	    $outsideip=$hostip{$perlvar{'lonHostID'}};
+	    $outsideip=&Apache::lonnet::get_host_ip($perlvar{'lonHostID'});
 	}
 
-	my $clientrec=($hostid{$outsideip}     ne undef);
+	my $clientrec=defined(&Apache::lonnet::get_hosts_from_ip($outsideip));
 	my $ismanager=($managers{$outsideip}    ne undef);
 	$clientname  = "[unknonwn]";
 	if($clientrec) {	# Establish client type.
 	    $ConnectionType = "client";
-	    $clientname = $hostid{$outsideip};
+	    $clientname = (&Apache::lonnet::get_hosts_from_ip($outsideip))[-1];
 	    if($ismanager) {
 		$ConnectionType = "both";
 	    }
@@ -5260,7 +5395,7 @@ sub make_new_child {
 	    my $remotereq=<$client>;
 	    chomp($remotereq);
 	    Debug("Got init: $remotereq");
-	    my $inikeyword = split(/:/, $remotereq);
+
 	    if ($remotereq =~ /^init/) {
 		&sethost("sethost:$perlvar{'lonHostID'}");
 		#
@@ -5348,14 +5483,9 @@ sub make_new_child {
  
 	if ($clientok) {
 # ---------------- New known client connecting, could mean machine online again
-	    
-	    foreach my $id (keys(%hostip)) {
-		if ($hostip{$id} ne $clientip ||
-		    $hostip{$currenthostid} eq $clientip) {
-		    # no need to try to do recon's to myself
-		    next;
-		}
-		&reconlonc("$perlvar{'lonSockDir'}/".$hostname{$id});
+	    if (&Apache::lonnet::get_host_ip($currenthostid) ne $clientip 
+		&& $clientip ne '127.0.0.1') {
+		&Apache::lonnet::reconlonc();
 	    }
 	    &logthis("<font color='green'>Established connection: $clientname</font>");
 	    &status('Will listen to '.$clientname);
@@ -5632,7 +5762,8 @@ sub validate_user {
 		my $krbservice = "krbtgt/".$contentpwd."\@".$contentpwd;
 		my $krbserver  = &Authen::Krb5::parse_name($krbservice);
 		my $credentials= &Authen::Krb5::cc_default();
-		$credentials->initialize($krbclient);
+		$credentials->initialize(&Authen::Krb5::parse_name($user.'@'
+                                                                 .$contentpwd));
 		my $krbreturn  = &Authen::Krb5::get_in_tkt_with_password($krbclient,
 									 $krbserver,
 									 $password,
@@ -5645,7 +5776,12 @@ sub validate_user {
 	    #  Authenticate via installation specific authentcation method:
 	    $validated = &localauth::localauth($user, 
 					       $password, 
-					       $contentpwd);
+					       $contentpwd,
+					       $domain);
+	    if ($validated < 0) {
+		&logthis("localauth for $contentpwd $user:$domain returned a $validated");
+		$validated = 0;
+	    }
 	} else {			# Unrecognized auth is also bad.
 	    $validated = 0;
 	}
@@ -5671,8 +5807,7 @@ sub addline {
     my ($fname,$hostid,$ip,$newline)=@_;
     my $contents;
     my $found=0;
-    my $expr='^'.$hostid.':'.$ip.':';
-    $expr =~ s/\./\\\./g;
+    my $expr='^'.quotemeta($hostid).':'.quotemeta($ip).':';
     my $sh;
     if ($sh=IO::File->new("$fname.subscription")) {
 	while (my $subline=<$sh>) {
@@ -5693,7 +5828,7 @@ sub get_chat {
     my @entries=();
     my $namespace = 'nohist_chatroom';
     my $namespace_inroom = 'nohist_inchatroom';
-    if (defined($group)) {
+    if ($group ne '') {
         $namespace .= '_'.$group;
         $namespace_inroom .= '_'.$group;
     }
@@ -5725,7 +5860,7 @@ sub chat_add {
     my $time=time;
     my $namespace = 'nohist_chatroom';
     my $logfile = 'chatroom.log';
-    if (defined($group)) {
+    if ($group ne '') {
         $namespace .= '_'.$group;
         $logfile = 'chatroom_'.$group.'.log';
     }
@@ -5879,7 +6014,7 @@ sub subscribe {
                 # the metadata
 		unless ($fname=~/\.meta$/) { &unsub("$fname.meta",$clientip); }
 		$fname=~s/\/home\/httpd\/html\/res/raw/;
-		$fname="http://$thisserver/".$fname;
+		$fname="http://".&Apache::lonnet::hostname($perlvar{'lonHostID'})."/".$fname;
 		$result="$fname\n";
 	    }
 	} else {
@@ -6033,9 +6168,10 @@ sub sethost {
     }
 
     if (!defined($hostid)) { $hostid=$perlvar{'lonHostID'}; }
-    if ($hostip{$perlvar{'lonHostID'}} eq $hostip{$hostid}) {
+    if (&Apache::lonnet::get_host_ip($perlvar{'lonHostID'}) 
+	eq &Apache::lonnet::get_host_ip($hostid)) {
 	$currenthostid  =$hostid;
-	$currentdomainid=$hostdom{$hostid};
+	$currentdomainid=&Apache::lonnet::host_domain($hostid);
 	&logthis("Setting hostid to $hostid, and domain to $currentdomainid");
     } else {
 	&logthis("Requested host id $hostid not an alias of ".
@@ -6051,96 +6187,6 @@ sub version {
     return "version:$VERSION";
 }
 
-#There is a copy of this in lonnet.pm
-sub userload {
-    my $numusers=0;
-    {
-	opendir(LONIDS,$perlvar{'lonIDsDir'});
-	my $filename;
-	my $curtime=time;
-	while ($filename=readdir(LONIDS)) {
-	    if ($filename eq '.' || $filename eq '..') {next;}
-	    my ($mtime)=(stat($perlvar{'lonIDsDir'}.'/'.$filename))[9];
-	    if ($curtime-$mtime < 1800) { $numusers++; }
-	}
-	closedir(LONIDS);
-    }
-    my $userloadpercent=0;
-    my $maxuserload=$perlvar{'lonUserLoadLim'};
-    if ($maxuserload) {
-	$userloadpercent=100*$numusers/$maxuserload;
-    }
-    $userloadpercent=sprintf("%.2f",$userloadpercent);
-    return $userloadpercent;
-}
-
-# Routines for serializing arrays and hashes (copies from lonnet)
-
-sub array2str {
-  my (@array) = @_;
-  my $result=&arrayref2str(\@array);
-  $result=~s/^__ARRAY_REF__//;
-  $result=~s/__END_ARRAY_REF__$//;
-  return $result;
-}
-                                                                                 
-sub arrayref2str {
-  my ($arrayref) = @_;
-  my $result='__ARRAY_REF__';
-  foreach my $elem (@$arrayref) {
-    if(ref($elem) eq 'ARRAY') {
-      $result.=&arrayref2str($elem).'&';
-    } elsif(ref($elem) eq 'HASH') {
-      $result.=&hashref2str($elem).'&';
-    } elsif(ref($elem)) {
-      #print("Got a ref of ".(ref($elem))." skipping.");
-    } else {
-      $result.=&escape($elem).'&';
-    }
-  }
-  $result=~s/\&$//;
-  $result .= '__END_ARRAY_REF__';
-  return $result;
-}
-                                                                                 
-sub hash2str {
-  my (%hash) = @_;
-  my $result=&hashref2str(\%hash);
-  $result=~s/^__HASH_REF__//;
-  $result=~s/__END_HASH_REF__$//;
-  return $result;
-}
-                                                                                 
-sub hashref2str {
-  my ($hashref)=@_;
-  my $result='__HASH_REF__';
-  foreach (sort(keys(%$hashref))) {
-    if (ref($_) eq 'ARRAY') {
-      $result.=&arrayref2str($_).'=';
-    } elsif (ref($_) eq 'HASH') {
-      $result.=&hashref2str($_).'=';
-    } elsif (ref($_)) {
-      $result.='=';
-      #print("Got a ref of ".(ref($_))." skipping.");
-    } else {
-        if ($_) {$result.=&escape($_).'=';} else { last; }
-    }
-
-    if(ref($hashref->{$_}) eq 'ARRAY') {
-      $result.=&arrayref2str($hashref->{$_}).'&';
-    } elsif(ref($hashref->{$_}) eq 'HASH') {
-      $result.=&hashref2str($hashref->{$_}).'&';
-    } elsif(ref($hashref->{$_})) {
-       $result.='&';
-      #print("Got a ref of ".(ref($hashref->{$_}))." skipping.");
-    } else {
-      $result.=&escape($hashref->{$_}).'&';
-    }
-  }
-  $result=~s/\&$//;
-  $result .= '__END_HASH_REF__';
-  return $result;
-}
 
 # ----------------------------------- POD (plain old documentation, CPAN style)