--- loncom/lonnet/perl/lonnet.pm	2011/08/09 00:28:51	1.1126
+++ loncom/lonnet/perl/lonnet.pm	2011/12/05 01:14:21	1.1147
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1126 2011/08/09 00:28:51 raeburn Exp $
+# $Id: lonnet.pm,v 1.1147 2011/12/05 01:14:21 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -76,7 +76,8 @@ use HTTP::Date;
 use Image::Magick;
 
 use vars qw(%perlvar %spareid %pr %prp $memcache %packagetab $tmpdir
-            $_64bit %env %protocol %loncaparevs %serverhomeIDs %needsrelease);
+            $_64bit %env %protocol %loncaparevs %serverhomeIDs %needsrelease
+            %managerstab);
 
 my (%badServerCache, $memcache, %courselogs, %accesshash, %domainrolehash,
     %userrolehash, $processmarker, $dumpcount, %coursedombuf,
@@ -348,7 +349,7 @@ sub get_remote_globals {
 
 sub remote_devalidate_cache {
     my ($lonhost,$name,$id) = @_;
-    my $response = &reply('devalidatecache',&escape($name).':'.&escape($id),$lonhost);
+    my $response = &reply('devalidatecache:'.&escape($name).':'.&escape($id),$lonhost);
     return $response;
 }
 
@@ -1185,6 +1186,257 @@ sub spares_for_offload  {
     return;
 }
 
+sub get_lonbalancer_config {
+    my ($servers) = @_;
+    my ($currbalancer,$currtargets);
+    if (ref($servers) eq 'HASH') {
+        foreach my $server (keys(%{$servers})) {
+            my %what = (
+                         spareid => 1,
+                         perlvar => 1,
+                       );
+            my ($result,$returnhash) = &get_remote_globals($server,\%what);
+            if ($result eq 'ok') {
+                if (ref($returnhash) eq 'HASH') {
+                    if (ref($returnhash->{'perlvar'}) eq 'HASH') {
+                        if ($returnhash->{'perlvar'}->{'lonBalancer'} eq 'yes') {
+                            $currbalancer = $server;
+                            $currtargets = {};
+                            if (ref($returnhash->{'spareid'}) eq 'HASH') {
+                                if (ref($returnhash->{'spareid'}->{'primary'}) eq 'ARRAY') {
+                                    $currtargets->{'primary'} = $returnhash->{'spareid'}->{'primary'};
+                                }
+                                if (ref($returnhash->{'spareid'}->{'default'}) eq 'ARRAY') {
+                                    $currtargets->{'default'} = $returnhash->{'spareid'}->{'default'};
+                                }
+                            }
+                            last;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return ($currbalancer,$currtargets);
+}
+
+sub check_loadbalancing {
+    my ($uname,$udom) = @_;
+    my ($is_balancer,$dom_in_use,$homeintdom,$rule_in_effect,
+        $offloadto,$otherserver);
+    my $lonhost = $perlvar{'lonHostID'};
+    my $uprimary_id = &Apache::lonnet::domain($udom,'primary');
+    my $uintdom = &Apache::lonnet::internet_dom($uprimary_id);
+    my $intdom = &Apache::lonnet::internet_dom($lonhost);
+    my $serverhomedom = &host_domain($lonhost);
+
+    my $cachetime = 60*60*24;
+
+    if (($uintdom ne '') && ($uintdom eq $intdom)) {
+        $dom_in_use = $udom;
+        $homeintdom = 1;
+    } else {
+        $dom_in_use = $serverhomedom;
+    }
+    my ($result,$cached)=&is_cached_new('loadbalancing',$dom_in_use);
+    unless (defined($cached)) {
+        my %domconfig =
+            &Apache::lonnet::get_dom('configuration',['loadbalancing'],$dom_in_use);
+        if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
+            $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'loadbalancing'},$cachetime);
+        }
+    }
+    if (ref($result) eq 'HASH') {
+        my $currbalancer = $result->{'lonhost'};
+        my $currtargets = $result->{'targets'};
+        my $currrules = $result->{'rules'};
+        if ($currbalancer ne '') {
+            my @hosts = &current_machine_ids();
+            if (grep(/^\Q$currbalancer\E$/,@hosts)) {
+                $is_balancer = 1;
+            }
+        }
+        if ($is_balancer) {
+            if (ref($currrules) eq 'HASH') {
+                if ($homeintdom) {
+                    if ($uname ne '') {
+                        if (($currrules->{'_LC_adv'} ne '') || ($currrules->{'_LC_author'} ne '')) {
+                            my ($is_adv,$is_author) = &is_advanced_user($udom,$uname);
+                            if (($currrules->{'_LC_author'} ne '') && ($is_author)) {
+                                $rule_in_effect = $currrules->{'_LC_author'};
+                            } elsif (($currrules->{'_LC_adv'} ne '') && ($is_adv)) {
+                                $rule_in_effect = $currrules->{'_LC_adv'}
+                            }
+                        }
+                        if ($rule_in_effect eq '') {
+                            my %userenv = &userenvironment($udom,$uname,'inststatus');
+                            if ($userenv{'inststatus'} ne '') {
+                                my @statuses = map { &unescape($_); } split(/:/,$userenv{'inststatus'});
+                                my ($othertitle,$usertypes,$types) =
+                                    &Apache::loncommon::sorted_inst_types($udom);
+                                if (ref($types) eq 'ARRAY') {
+                                    foreach my $type (@{$types}) {
+                                        if (grep(/^\Q$type\E$/,@statuses)) {
+                                            if (exists($currrules->{$type})) {
+                                                $rule_in_effect = $currrules->{$type};
+                                            }
+                                        }
+                                    }
+                                }
+                            } else {
+                                if (exists($currrules->{'default'})) {
+                                    $rule_in_effect = $currrules->{'default'};
+                                }
+                            }
+                        }
+                    } else {
+                        if (exists($currrules->{'default'})) {
+                            $rule_in_effect = $currrules->{'default'};
+                        }
+                    }
+                } else {
+                    if ($currrules->{'_LC_external'} ne '') {
+                        $rule_in_effect = $currrules->{'_LC_external'};
+                    }
+                }
+                $offloadto = &get_loadbalancer_targets($rule_in_effect,$currtargets,
+                                                       $uname,$udom);
+            }
+        }
+    } elsif (($homeintdom) && ($udom ne $serverhomedom)) {
+        my ($result,$cached)=&is_cached_new('loadbalancing',$serverhomedom);
+        unless (defined($cached)) {
+            my %domconfig =
+                &Apache::lonnet::get_dom('configuration',['loadbalancing'],$serverhomedom);
+            if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
+                $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'loadbalancing'},$cachetime);
+            }
+        }
+        if (ref($result) eq 'HASH') {
+            my $currbalancer = $result->{'lonhost'};
+            my $currtargets = $result->{'targets'};
+            my $currrules = $result->{'rules'};
+
+            if ($currbalancer eq $lonhost) {
+                $is_balancer = 1;
+                if (ref($currrules) eq 'HASH') {
+                    if ($currrules->{'_LC_internetdom'} ne '') {
+                        $rule_in_effect = $currrules->{'_LC_internetdom'};
+                    }
+                }
+                $offloadto = &get_loadbalancer_targets($rule_in_effect,$currtargets,
+                                                       $uname,$udom);
+            }
+        } else {
+            if ($perlvar{'lonBalancer'} eq 'yes') {
+                $is_balancer = 1;
+                $offloadto = &this_host_spares($dom_in_use);
+            }
+        }
+    } else {
+        if ($perlvar{'lonBalancer'} eq 'yes') {
+            $is_balancer = 1;
+            $offloadto = &this_host_spares($dom_in_use);
+        }
+    }
+    my $lowest_load = 30000;
+    if (ref($offloadto) eq 'HASH') {
+        if (ref($offloadto->{'primary'}) eq 'ARRAY') {
+            foreach my $try_server (@{$offloadto->{'primary'}}) {
+                ($otherserver,$lowest_load) =
+                    &compare_server_load($try_server,$otherserver,$lowest_load);
+            }
+        }
+        my $found_server = ($otherserver ne '' && $lowest_load < 100);
+
+        if (!$found_server) {
+            if (ref($offloadto->{'default'}) eq 'ARRAY') {
+                foreach my $try_server (@{$offloadto->{'default'}}) {
+                    ($otherserver,$lowest_load) =
+                        &compare_server_load($try_server,$otherserver,$lowest_load);
+                }
+            }
+        }
+    } elsif (ref($offloadto) eq 'ARRAY') {
+        if (@{$offloadto} == 1) {
+            $otherserver = $offloadto->[0];
+        } elsif (@{$offloadto} > 1) {
+            foreach my $try_server (@{$offloadto}) {
+                ($otherserver,$lowest_load) =
+                    &compare_server_load($try_server,$otherserver,$lowest_load);
+            }
+        }
+    }
+    return ($is_balancer,$otherserver);
+}
+
+sub get_loadbalancer_targets {
+    my ($rule_in_effect,$currtargets,$uname,$udom) = @_;
+    my $offloadto;
+    if ($rule_in_effect eq '') {
+        $offloadto = $currtargets;
+    } else {
+        if ($rule_in_effect eq 'homeserver') {
+            my $homeserver = &homeserver($uname,$udom);
+            if ($homeserver ne 'no_host') {
+                $offloadto = [$homeserver];
+            }
+        } elsif ($rule_in_effect eq 'externalbalancer') {
+            my %domconfig =
+                &Apache::lonnet::get_dom('configuration',['loadbalancing'],$udom);
+            if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
+                if ($domconfig{'loadbalancing'}{'lonhost'} ne '') {
+                    if (&hostname($domconfig{'loadbalancing'}{'lonhost'}) ne '') {
+                        $offloadto = [$domconfig{'loadbalancing'}{'lonhost'}];
+                    }
+                }
+            } else {
+                my %servers = &dom_servers($udom);
+                my ($remotebalancer,$remotetargets) = &get_lonbalancer_config(\%servers);
+                if (&hostname($remotebalancer) ne '') {
+                    $offloadto = [$remotebalancer];
+                }
+            }
+        } elsif (&hostname($rule_in_effect) ne '') {
+            $offloadto = [$rule_in_effect];
+        }
+    }
+    return $offloadto;
+}
+
+sub internet_dom_servers {
+    my ($dom) = @_;
+    my (%uniqservers,%servers);
+    my $primaryserver = &hostname(&domain($dom,'primary'));
+    my @machinedoms = &machine_domains($primaryserver);
+    foreach my $mdom (@machinedoms) {
+        my %currservers = %servers;
+        my %server = &get_servers($mdom);
+        %servers = (%currservers,%server);
+    }
+    my %by_hostname;
+    foreach my $id (keys(%servers)) {
+        push(@{$by_hostname{$servers{$id}}},$id);
+    }
+    foreach my $hostname (sort(keys(%by_hostname))) {
+        if (@{$by_hostname{$hostname}} > 1) {
+            my $match = 0;
+            foreach my $id (@{$by_hostname{$hostname}}) {
+                if (&host_domain($id) eq $dom) {
+                    $uniqservers{$id} = $hostname;
+                    $match = 1;
+                }
+            }
+            unless ($match) {
+                $uniqservers{$by_hostname{$hostname}[0]} = $hostname;
+            }
+        } else {
+            $uniqservers{$by_hostname{$hostname}[0]} = $hostname;
+        }
+    }
+    return %uniqservers;
+}
+
 # ---------------------- Find the homebase for a user from domain's lib servers
 
 my %homecache;
@@ -1668,6 +1920,7 @@ sub get_domain_defaults {
         $domdefaults{'auth_arg_def'} = $domconfig{'defaults'}{'auth_arg_def'};
         $domdefaults{'timezone_def'} = $domconfig{'defaults'}{'timezone_def'};
         $domdefaults{'datelocale_def'} = $domconfig{'defaults'}{'datelocale_def'};
+        $domdefaults{'portal_def'} = $domconfig{'defaults'}{'portal_def'};
     } else {
         $domdefaults{'lang_def'} = &domain($domain,'lang_def');
         $domdefaults{'auth_def'} = &domain($domain,'auth_def');
@@ -1961,7 +2214,7 @@ sub is_cached_new {
     my ($name,$id,$debug) = @_;
     $id=&make_key($name,$id);
     if (exists($remembered{$id})) {
-	if ($debug) { &Apache::lonnet::logthis("Earyl return $id of $remembered{$id} "); }
+	if ($debug) { &Apache::lonnet::logthis("Early return $id of $remembered{$id} "); }
 	$accessed{$id}=[&gettimeofday()];
 	$hits++;
 	return ($remembered{$id},1);
@@ -2177,10 +2430,11 @@ sub subscribe {
 sub repcopy {
     my $filename=shift;
     $filename=~s/\/+/\//g;
-    if ($filename=~m|^/home/httpd/html/adm/|) { return 'ok'; }
-    if ($filename=~m|^/home/httpd/html/lonUsers/|) { return 'ok'; }
-    if ($filename=~m|^/home/httpd/html/userfiles/| or
-	$filename=~m -^/*(uploaded|editupload)/-) { 
+    my $londocroot = $perlvar{'lonDocRoot'};
+    if ($filename=~m{^\Q$londocroot/adm/\E}) { return 'ok'; }
+    if ($filename=~m{^\Q$londocroot/lonUsers/\E}) { return 'ok'; }
+    if ($filename=~m{^\Q$londocroot/userfiles/\E} or
+	$filename=~m{^/*(uploaded|editupload)/}) {
 	return &repcopy_userfile($filename);
     }
     $filename=~s/[\n\r]//g;
@@ -2207,7 +2461,7 @@ sub repcopy {
         unless ($home eq $perlvar{'lonHostID'}) {
            my @parts=split(/\//,$filename);
            my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";
-           if ($path ne "$perlvar{'lonDocRoot'}/res") {
+           if ($path ne "$londocroot/res") {
                &logthis("Malconfiguration for replication: $filename");
 	       return 'bad_request';
            }
@@ -3085,7 +3339,7 @@ sub courseacclog {
     my $fnsymb=shift;
     unless ($env{'request.course.id'}) { return ''; }
     my $what=$fnsymb.':'.$env{'user.name'}.':'.$env{'user.domain'};
-    if ($fnsymb=~/(problem|exam|quiz|assess|survey|form|task|page)$/) {
+    if ($fnsymb=~/$LONCAPA::assess_re/) {
         $what.=':POST';
         # FIXME: Probably ought to escape things....
 	foreach my $key (keys(%env)) {
@@ -3735,7 +3989,7 @@ sub hashref2str {
       $result.='=';
       #print("Got a ref of ".(ref($key))." skipping.");
     } else {
-	if ($key) {$result.=&escape($key).'=';} else { last; }
+	if (defined($key)) {$result.=&escape($key).'=';} else { last; }
     }
 
     if(ref($hashref->{$key}) eq 'ARRAY') {
@@ -5345,12 +5599,16 @@ sub is_advanced_user {
     my ($udom,$uname) = @_;
     if ($udom ne '' && $uname ne '') {
         if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'})) {
-            return $env{'user.adv'};  
+            if (wantarray) {
+                return ($env{'user.adv'},$env{'user.author'});
+            } else {
+                return $env{'user.adv'};
+            }
         }
     }
     my %roleshash = &get_my_roles($uname,$udom,'userroles',undef,undef,undef,1);
     my %allroles;
-    my $is_adv;
+    my ($is_adv,$is_author);
     foreach my $role (keys(%roleshash)) {
         my ($trest,$tdomain,$trole,$sec) = split(/:/,$role);
         my $area = '/'.$tdomain.'/'.$trest;
@@ -5364,6 +5622,9 @@ sub is_advanced_user {
             } elsif ($trole ne 'gr') {
                 &standard_roleprivs(\%allroles,$trole,$tdomain,$spec,$trest,$area);
             }
+            if ($trole eq 'au') {
+                $is_author = 1;
+            }
         }
     }
     foreach my $role (keys(%allroles)) {
@@ -5378,6 +5639,9 @@ sub is_advanced_user {
             }
         }
     }
+    if (wantarray) {
+        return ($is_adv,$is_author);
+    }
     return $is_adv;
 }
 
@@ -5648,6 +5912,15 @@ sub allowed {
         }
     }
 
+# User who is not author or co-author might still be able to edit
+# resource of an author in the domain (e.g., if Domain Coordinator).
+    if (($priv eq 'eco') && ($thisallowed eq '') && ($env{'request.course.id'}) &&
+        (&allowed('mdc',$env{'request.course.id'}))) {
+        if ($env{"user.priv.cm./$uri/"}=~/\Q$priv\E\&([^\:]*)/) {
+            $thisallowed.=$1;
+        }
+    }
+
 # Course: uri itself is a course
     my $courseuri=$uri;
     $courseuri=~s/\_(\d)/\/$1/;
@@ -5918,7 +6191,27 @@ sub allowed {
     }
    return 'F';
 }
-
+#
+#   Removes the versino from a URI and
+#   splits it in to its filename and path to the filename.
+#   Seems like File::Basename could have done this more clearly.
+#   Parameters:
+#      $uri   - input URI
+#   Returns:
+#     Two element list consisting of 
+#     $pathname  - the URI up to and excluding the trailing /
+#     $filename  - The part of the URI following the last /
+#  NOTE:
+#    Another realization of this is simply:
+#    use File::Basename;
+#    ...
+#    $uri = shift;
+#    $filename = basename($uri);
+#    $path     = dirname($uri);
+#    return ($filename, $path);
+#
+#     The implementation below is probably faster however.
+#
 sub split_uri_for_cond {
     my $uri=&deversion(&declutter(shift));
     my @uriparts=split(/\//,$uri);
@@ -6814,6 +7107,13 @@ sub assignrole {
                     return 'refused';
                 }
             }
+        } elsif ($role eq 'au') {
+            if ($url ne '/'.$udom.'/') {
+                &logthis('Attempt by '.$env{'user.name'}.':'.$env{'user.domain'}.
+                         ' to assign author role for '.$uname.':'.$udom.
+                         ' in domain: '.$url.' refused (wrong domain).');
+                return 'refused';
+            }
         }
         $mrole=$role;
     }
@@ -7961,26 +8261,33 @@ sub dirlist {
 
     if($udom) {
         if($uname) {
+            my $uhome = &homeserver($uname,$udom);
+            if ($uhome eq 'no_host') {
+                return ([],'no_host');
+            }
             $listing = &reply('ls3:'.&escape('/'.$uri).':'.$getpropath.':'
                               .$getuserdir.':'.&escape($dirRoot)
-                              .':'.&escape($uname).':'.&escape($udom),
-                              &homeserver($uname,$udom));
+                              .':'.&escape($uname).':'.&escape($udom),$uhome);
             if ($listing eq 'unknown_cmd') {
-                $listing = &reply('ls2:'.$dirRoot.'/'.$uri,
-                                  &homeserver($uname,$udom));
+                $listing = &reply('ls2:'.$dirRoot.'/'.$uri,$uhome);
             } else {
                 @listing_results = map { &unescape($_); } split(/:/,$listing);
             }
             if ($listing eq 'unknown_cmd') {
-                $listing = &reply('ls:'.$dirRoot.'/'.$uri,
-				  &homeserver($uname,$udom));
+                $listing = &reply('ls:'.$dirRoot.'/'.$uri,$uhome);
                 @listing_results = split(/:/,$listing);
             } else {
                 @listing_results = map { &unescape($_); } split(/:/,$listing);
             }
-            return @listing_results;
+            if (($listing eq 'no_such_host') || ($listing eq 'con_lost') || 
+                ($listing eq 'rejected') || ($listing eq 'refused') ||
+                ($listing eq 'no_such_dir') || ($listing eq 'empty')) {
+                return ([],$listing);
+            } else {
+                return (\@listing_results);
+            }
         } elsif(!$alternateRoot) {
-            my %allusers;
+            my (%allusers,%listerror);
 	    my %servers = &get_servers($udom,'library');
  	    foreach my $tryserver (keys(%servers)) {
                 $listing = &reply('ls3:'.&escape("/res/$udom").':::::'.
@@ -7999,32 +8306,31 @@ sub dirlist {
 		    @listing_results =
 			map { &unescape($_); } split(/:/,$listing);
 		}
-		if ($listing_results[0] ne 'no_such_dir' && 
-		    $listing_results[0] ne 'empty'       &&
-		    $listing_results[0] ne 'con_lost') {
+                if (($listing eq 'no_such_host') || ($listing eq 'con_lost') ||
+                    ($listing eq 'rejected') || ($listing eq 'refused') ||
+                    ($listing eq 'no_such_dir') || ($listing eq 'empty')) {
+                    $listerror{$tryserver} = $listing;
+                } else {
 		    foreach my $line (@listing_results) {
 			my ($entry) = split(/&/,$line,2);
 			$allusers{$entry} = 1;
 		    }
 		}
             }
-            my $alluserstr='';
+            my @alluserslist=();
             foreach my $user (sort(keys(%allusers))) {
-                $alluserstr.=$user.'&user:';
+                push(@alluserslist,$user.'&user');
             }
-            $alluserstr=~s/:$//;
-            return split(/:/,$alluserstr);
+            return (\@alluserslist);
         } else {
-            return ('missing user name');
+            return ([],'missing username');
         }
     } elsif(!defined($getpropath)) {
-        my @all_domains = sort(&all_domains());
-        foreach my $domain (@all_domains) {
-            $domain = $perlvar{'lonDocRoot'}.'/res/'.$domain.'/&domain';
-        }
-        return @all_domains;
+        my $path = $perlvar{'lonDocRoot'}.'/res/'; 
+        my @all_domains = map { $path.$_.'/&domain'; } (sort(&all_domains()));
+        return (\@all_domains);
     } else {
-        return ('missing domain');
+        return ([],'missing domain');
     }
 }
 
@@ -8037,11 +8343,13 @@ sub GetFileTimestamp {
     my ($studentDomain,$studentName,$filename,$getuserdir)=@_;
     $studentDomain = &LONCAPA::clean_domain($studentDomain);
     $studentName   = &LONCAPA::clean_username($studentName);
-    my ($fileStat) = 
-        &Apache::lonnet::dirlist($filename,$studentDomain,$studentName, 
-                                 undef,$getuserdir);
-    my @stats = split('&', $fileStat);
-    if($stats[0] ne 'empty' && $stats[0] ne 'no_such_dir') {
+    my ($fileref,$error) = &dirlist($filename,$studentDomain,$studentName,
+                                    undef,$getuserdir);
+    if (($error eq 'empty') || ($error eq 'no_such_dir')) {
+        return -1;
+    }
+    if (ref($fileref) eq 'ARRAY') {
+        my @stats = split('&',$fileref->[0]);
         # @stats contains first the filename, then the stat output
         return $stats[10]; # so this is 10 instead of 9.
     } else {
@@ -8073,12 +8381,15 @@ sub stat_file {
     if ($file =~ /^userfiles\//) {
         $getpropath = 1;
     }
-    my ($result) = &dirlist($file,$udom,$uname,$getpropath);
-    my @stats = split('&', $result);
-    
-    if($stats[0] ne 'empty' && $stats[0] ne 'no_such_dir') {
-	shift(@stats); #filename is first
-	return @stats;
+    my ($listref,$error) = &dirlist($file,$udom,$uname,$getpropath);
+    if (($error eq 'empty') || ($error eq 'no_such_dir')) {
+        return ();
+    } else {
+        if (ref($listref) eq 'ARRAY') {
+            my @stats = split('&',$listref->[0]);
+	    shift(@stats); #filename is first
+	    return @stats;
+        }
     }
     return ();
 }
@@ -8399,15 +8710,7 @@ sub EXT {
    } elsif ($realm eq 'request') {
 # ------------------------------------------------------------- request.browser
         if ($space eq 'browser') {
-	    if ($qualifier eq 'textremote') {
-		if (&Apache::lonlocal::mt('textual_remote_display') eq 'on') {
-		    return 1;
-		} else {
-		    return 0;
-		}
-	    } else {
-		return $env{'browser.'.$qualifier};
-	    }
+            return $env{'browser.'.$qualifier};
 # ------------------------------------------------------------ request.filename
         } else {
             return $env{'request.'.$spacequalifierrest};
@@ -8691,7 +8994,7 @@ sub metadata {
         ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ m{^/*uploaded/.+\.sequence$})) {
 	return undef;
     }
-    if (($uri =~ /^~/ || $uri =~ m{home/$match_username/public_html/}) 
+    if (($uri =~ /^priv/ || $uri=~/home\/httpd\/html\/priv/) 
 	&& &Apache::lonxml::get_state('target') =~ /^(|meta)$/) {
 	return undef;
     }
@@ -8728,7 +9031,7 @@ sub metadata {
         my %metathesekeys=();
         unless ($filename=~/\.meta$/) { $filename.='.meta'; }
 	my $metastring;
-	if ($uri =~ /^~/ || $uri =~ m{home/$match_username/public_html/}) {
+	if ($uri =~ /^priv/ || $uri=~/home\/httpd\/html\/priv/) {
 	    my $which = &hreflocation('','/'.($liburi || $uri));
 	    $metastring = 
 		&Apache::lonnet::ssi_body($which,
@@ -9425,19 +9728,44 @@ sub getCODE {
     }
     return undef;
 }
-
+#
+#  Determines the random seed for a specific context:
+#
+# parameters:
+#   symb      - in course context the symb for the seed.
+#   course_id - The course id of the form domain_coursenum.
+#   domain    - Domain for the user.
+#   course    - Course for the user.
+#   cenv      - environment of the course.
+#
+# NOTE:
+#   All parameters are picked out of the environment if missing
+#   or not defined.
+#   If a symb cannot be determined the current time is used instead.
+#
+#  For a given well defined symb, courside, domain, username,
+#  and course environment, the seed is reproducible.
+#
 sub rndseed {
-    my ($symb,$courseid,$domain,$username)=@_;
+    my ($symb,$courseid,$domain,$username, $cenv)=@_;
     my ($wsymb,$wcourseid,$wdomain,$wusername)=&whichuser();
     if (!defined($symb)) {
 	unless ($symb=$wsymb) { return time; }
     }
-    if (!$courseid) { $courseid=$wcourseid; }
-    if (!$domain) { $domain=$wdomain; }
-    if (!$username) { $username=$wusername }
-    my $which=&get_rand_alg();
+    if (!defined $courseid) { 
+	$courseid=$wcourseid; 
+    }
+    if (!defined $domain) { $domain=$wdomain; }
+    if (!defined $username) { $username=$wusername }
 
+    my $which;
+    if (defined($cenv->{'rndseed'})) {
+	$which = $cenv->{'rndseed'};
+    } else {
+	$which =&get_rand_alg($courseid);
+    }
     if (defined(&getCODE())) {
+
 	if ($which eq '64bit5') {
 	    return &rndseed_CODE_64bit5($symb,$courseid,$domain,$username);
 	} elsif ($which eq '64bit4') {
@@ -9761,8 +10089,9 @@ sub getfile {
 
 sub repcopy_userfile {
     my ($file)=@_;
-    if ($file =~ m -^/*(uploaded|editupload)/-) { $file=&filelocation("",$file); }
-    if ($file =~ m|^/home/httpd/html/lonUsers/|) { return 'ok'; }
+    my $londocroot = $perlvar{'lonDocRoot'};
+    if ($file =~ m{^/*(uploaded|editupload)/}) { $file=&filelocation("",$file); }
+    if ($file =~ m{^\Q$londocroot/lonUsers/\E}) { return 'ok'; }
     my ($cdom,$cnum,$filename) = 
 	($file=~m|^\Q$perlvar{'lonDocRoot'}\E/+userfiles/+($match_domain)/+($match_name)/+(.*)|);
     my $uri="/uploaded/$cdom/$cnum/$filename";
@@ -9891,13 +10220,7 @@ sub filelocation {
 	$file=~s-^/adm/coursedocs/showdoc/-/-;
     }
 
-    if ($file=~m:^/~:) { # is a contruction space reference
-        $location = $file;
-        $location =~ s:/~(.*?)/(.*):/home/$1/public_html/$2:;
-    } elsif ($file=~m{^/home/$match_username/public_html/}) {
-	# is a correct contruction space reference
-        $location = $file;
-    } elsif ($file =~ m-^\Q$Apache::lonnet::perlvar{'lonTabDir'}\E/-) {
+    if ($file =~ m-^\Q$Apache::lonnet::perlvar{'lonTabDir'}\E/-) {
         $location = $file;
     } elsif ($file=~/^\/*(uploaded|editupload)/) { # is an uploaded file
         my ($udom,$uname,$filename)=
@@ -9916,11 +10239,12 @@ sub filelocation {
 	$location = $perlvar{'lonDocRoot'}.'/'.$file;
     } else {
         $file=~s/^\Q$perlvar{'lonDocRoot'}\E//;
-        $file=~s:^/res/:/:;
+        $file=~s:^/(res|priv)/:/:;
+        my $space=$1;
         if ( !( $file =~ m:^/:) ) {
             $location = $dir. '/'.$file;
         } else {
-            $location = '/home/httpd/html/res'.$file;
+            $location = $perlvar{'lonDocRoot'}.'/'.$space.$file;
         }
     }
     $location=~s://+:/:g; # remove duplicate /
@@ -9945,11 +10269,9 @@ sub hreflocation {
     }
     if ($file=~m-^\Q$perlvar{'lonDocRoot'}\E-) {
 	$file=~s-^\Q$perlvar{'lonDocRoot'}\E--;
-    } elsif ($file=~m-/home/($match_username)/public_html/-) {
-	$file=~s-^/home/($match_username)/public_html/-/~$1/-;
     } elsif ($file=~m-^\Q$perlvar{'lonUsersDir'}\E-) {
-	$file=~s-^/home/httpd/lonUsers/($match_domain)/./././($match_name)/userfiles/
-	    -/uploaded/$1/$2/-x;
+	$file=~s{^/home/httpd/lonUsers/($match_domain)/./././($match_name)/userfiles/}
+	        {/uploaded/$1/$2/}x;
     }
     if ($file=~ m{^/userfiles/}) {
 	$file =~ s{^/userfiles/}{/uploaded/};
@@ -9957,6 +10279,10 @@ sub hreflocation {
     return $file;
 }
 
+
+
+
+
 sub current_machine_domains {
     return &machine_domains(&hostname($perlvar{'lonHostID'}));
 }
@@ -10145,6 +10471,7 @@ sub get_dns {
     while (%alldns) {
 	my ($dns) = keys(%alldns);
 	my $ua=new LWP::UserAgent;
+        $ua->timeout(30);
 	my $request=new HTTP::Request('GET',"$alldns{$dns}://$dns$url");
 	my $response=$ua->request($request);
         delete($alldns{$dns});
@@ -10660,6 +10987,22 @@ BEGIN {
     }
 }
 
+# ---------------------------------------------------------- Read managers table
+{
+    if (-e "$perlvar{'lonTabDir'}/managers.tab") {
+        if (open(my $config,"<$perlvar{'lonTabDir'}/managers.tab")) {
+            while (my $configline=<$config>) {
+                chomp($configline);
+                next if ($configline =~ /^\#/);
+                if (($configline =~ /^[\w\-]+$/) || ($configline =~ /^[\w\-]+\:[\w\-]+$/)) {
+                    $managerstab{$configline} = 1;
+                }
+            }
+            close($config);
+        }
+    }
+}
+
 # ------------- set up temporary directory
 {
     $tmpdir = LONCAPA::tempdir();
@@ -11512,7 +11855,82 @@ or lonTabs/domain.tab.
 
 =item *
 
-dirlist($uri) : return directory list based on URI
+dirlist() : return directory list based on URI (first arg).
+
+Inputs: 1 required, 5 optional.
+
+=over
+
+=item 
+$uri - path to file in filesystem (starts: /res or /userfiles/). Required.
+
+=item
+$userdomain - domain of user/course to be listed. Extracted from $uri if absent. 
+
+=item
+$username -  username of user/course to be listed. Extracted from $uri if absent. 
+
+=item
+$getpropath - boolean: 1 if prepend path using &propath(). 
+
+=item
+$getuserdir - boolean: 1 if prepend path for "userfiles".
+
+=item 
+$alternateRoot - path to prepend in place of path from $uri.
+
+=back
+
+Returns: Array of up to two items.
+
+=over
+
+a reference to an array of files/subdirectories
+
+=over
+
+Each element in the array of files/subdirectories is a & separated list of
+item name and the result of running stat on the item.  If dirlist was requested
+for a file instead of a directory, the item name will be ''. For a directory 
+listing, if the item is a metadata file, the element will end &N&M 
+(where N amd M are either 0 or 1, corresponding to obsolete set (1), or
+default copyright set (1).  
+
+=back
+
+a scalar containing error condition (if encountered).
+
+=over
+
+=item 
+no_host (no homeserver identified for $username:$domain).
+
+=item 
+no_such_host (server contacted for listing not identified as valid host).
+
+=item 
+con_lost (connection to remote server failed).
+
+=item 
+refused (invalid $username:$domain received on lond side).
+
+=item 
+no_such_dir (directory at specified path on lond side does not exist). 
+
+=item 
+empty (directory at specified path on lond side is empty).
+
+=over
+
+This is currently not encountered because the &ls3, &ls2, 
+&ls (_handler) routines on the lond side do not filter out
+. and .. from a directory listing. 
+
+=back
+
+=back
+
+=back
 
 =item *