--- loncom/lonnet/perl/lonnet.pm	2011/08/09 01:35:24	1.1129
+++ loncom/lonnet/perl/lonnet.pm	2012/01/08 23:23:58	1.1151
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1129 2011/08/09 01:35:24 raeburn Exp $
+# $Id: lonnet.pm,v 1.1151 2012/01/08 23:23:58 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;
 }
 
@@ -929,7 +930,7 @@ sub choose_server {
     my %domconfhash = &Apache::loncommon::get_domainconf($udom);
     my %servers = &get_servers($udom);
     my $lowest_load = 30000;
-    my ($login_host,$hostname,$portal_path);
+    my ($login_host,$hostname,$portal_path,$isredirect);
     foreach my $lonhost (keys(%servers)) {
         my $loginvia;
         if ($checkloginvia) {
@@ -940,12 +941,14 @@ sub choose_server {
                     &compare_server_load($server, $login_host, $lowest_load);
                 if ($login_host eq $server) {
                     $portal_path = $path;
+                    $isredirect = 1;
                 }
             } else {
                 ($login_host, $lowest_load) =
                     &compare_server_load($lonhost, $login_host, $lowest_load);
                 if ($login_host eq $lonhost) {
                     $portal_path = '';
+                    $isredirect = ''; 
                 }
             }
         } else {
@@ -956,7 +959,7 @@ sub choose_server {
     if ($login_host ne '') {
         $hostname = &hostname($login_host);
     }
-    return ($login_host,$hostname,$portal_path);
+    return ($login_host,$hostname,$portal_path,$isredirect);
 }
 
 # --------------------------------------------- Try to change a user's password
@@ -1242,7 +1245,7 @@ sub check_loadbalancing {
         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{'usersessions'}{'loadbalancing'},$cachetime);
+            $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'loadbalancing'},$cachetime);
         }
     }
     if (ref($result) eq 'HASH') {
@@ -1308,7 +1311,7 @@ sub check_loadbalancing {
             my %domconfig =
                 &Apache::lonnet::get_dom('configuration',['loadbalancing'],$serverhomedom);
             if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
-                $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'usersessions'}{'loadbalancing'},$cachetime);
+                $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'loadbalancing'},$cachetime);
             }
         }
         if (ref($result) eq 'HASH') {
@@ -1919,6 +1922,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');
@@ -2212,7 +2216,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);
@@ -2428,10 +2432,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;
@@ -2458,7 +2463,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';
            }
@@ -3336,7 +3341,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)) {
@@ -3535,6 +3540,7 @@ sub get_my_roles {
     foreach my $entry (keys(%dumphash)) {
         my ($role,$tend,$tstart);
         if ($context eq 'userroles') {
+            next if ($entry =~ /^rolesdef/);
 	    ($role,$tend,$tstart)=split(/_/,$dumphash{$entry});
         } else {
             ($tend,$tstart)=split(/\:/,$dumphash{$entry});
@@ -3986,7 +3992,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') {
@@ -5909,6 +5915,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/;
@@ -6179,7 +6194,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);
@@ -7075,6 +7110,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;
     }
@@ -7476,14 +7518,16 @@ sub modify_student_enrollment {
         $uid    = $tmp{'id'}         if (!defined($uid)    || $uid  eq '');
     }
     my $fullname = &format_name($first,$middle,$last,$gene,'lastname');
+    my $user = "$uname:$udom";
+    my %old_entry = &Apache::lonnet::get('classlist',[$user],$cdom,$cnum);
     my $reply=cput('classlist',
-		   {"$uname:$udom" => 
+		   {$user => 
 			join(':',$end,$start,$uid,$usec,$fullname,$type,$locktype) },
 		   $cdom,$cnum);
-    unless (($reply eq 'ok') || ($reply eq 'delayed')) {
+    if (($reply eq 'ok') || ($reply eq 'delayed')) {
+        &devalidate_getsection_cache($udom,$uname,$cid);
+    } else { 
 	return 'error: '.$reply;
-    } else {
-	&devalidate_getsection_cache($udom,$uname,$cid);
     }
     # Add student role to user
     my $uurl='/'.$cid;
@@ -7491,7 +7535,16 @@ sub modify_student_enrollment {
     if ($usec) {
 	$uurl.='/'.$usec;
     }
-    return &assignrole($udom,$uname,$uurl,'st',$end,$start,undef,$selfenroll,$context);
+    my $result = &assignrole($udom,$uname,$uurl,'st',$end,$start,undef,
+                             $selfenroll,$context);
+    if ($result ne 'ok') {
+        if ($old_entry{$user} ne '') {
+            $reply = &cput('classlist',\%old_entry,$cdom,$cnum);
+        } else {
+            $reply = &del('classlist',[$user],$cdom,$cnum);
+        }
+    }
+    return $result; 
 }
 
 sub format_name {
@@ -8222,26 +8275,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").':::::'.
@@ -8260,32 +8320,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');
     }
 }
 
@@ -8298,11 +8357,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 {
@@ -8334,12 +8395,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 ();
 }
@@ -8660,15 +8724,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};
@@ -8952,7 +9008,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;
     }
@@ -8989,7 +9045,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,
@@ -9345,6 +9401,49 @@ sub get_slot {
     }
     return $slotinfo{$which};
 }
+
+sub get_reservable_slots {
+    my ($cnum,$cdom,$uname,$udom) = @_;
+    my $now = time;
+    my $reservable_info;
+    my $key=join("\0",'reservableslots',$cdom,$cnum,$uname,$udom);
+    if (exists($remembered{$key})) {
+        $reservable_info = $remembered{$key};
+    } else {
+        my %resv;
+        ($resv{'now_order'},$resv{'now'},$resv{'future_order'},$resv{'future'}) =
+        &Apache::loncommon::get_future_slots($cnum,$cdom,$now);
+        $reservable_info = \%resv;
+        $remembered{$key} = $reservable_info;
+    }
+    return $reservable_info;
+}
+
+sub get_course_slots {
+    my ($cnum,$cdom) = @_;
+    my $hashid=$cnum.':'.$cdom;
+    my ($result,$cached) = &Apache::lonnet::is_cached_new('allslots',$hashid);
+    if (defined($cached)) {
+        if (ref($result) eq 'HASH') {
+            return %{$result};
+        }
+    } else {
+        my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum);
+        my ($tmp) = keys(%slots);
+        if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
+            &Apache::lonnet::do_cache_new('allslots',$hashid,\%slots,600);
+            return %slots;
+        }
+    }
+    return;
+}
+
+sub devalidate_slots_cache {
+    my ($cnum,$cdom)=@_;
+    my $hashid=$cnum.':'.$cdom;
+    &devalidate_cache_new('allslots',$hashid);
+}
+
 # ------------------------------------------------- Update symbolic store links
 
 sub symblist {
@@ -9686,19 +9785,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') {
@@ -10022,8 +10146,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";
@@ -10152,13 +10277,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)=
@@ -10177,11 +10296,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 /
@@ -10206,11 +10326,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/};
@@ -10218,6 +10336,10 @@ sub hreflocation {
     return $file;
 }
 
+
+
+
+
 sub current_machine_domains {
     return &machine_domains(&hostname($perlvar{'lonHostID'}));
 }
@@ -10406,6 +10528,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});
@@ -10921,6 +11044,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();
@@ -11773,7 +11912,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 *