--- loncom/lonnet/perl/lonnet.pm	2011/06/12 14:18:12	1.1115
+++ loncom/lonnet/perl/lonnet.pm	2011/08/09 01:35:24	1.1129
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1115 2011/06/12 14:18:12 raeburn Exp $
+# $Id: lonnet.pm,v 1.1129 2011/08/09 01:35:24 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -95,6 +95,7 @@ use Math::Random;
 use File::MMagic;
 use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::Configuration;
+
 use File::Copy;
 
 my $readit;
@@ -305,6 +306,52 @@ sub get_server_homeID {
     return &do_cache_new('serverhomeID',$hostname,$serverhomeID,$cachetime);
 }
 
+sub get_remote_globals {
+    my ($lonhost,$whathash,$ignore_cache) = @_;
+    my ($result,%returnhash,%whatneeded);
+    if (ref($whathash) eq 'HASH') {
+        foreach my $what (sort(keys(%{$whathash}))) {
+            my $hashid = $lonhost.'-'.$what;
+            my ($response,$cached);
+            unless ($ignore_cache) {
+                ($response,$cached)=&is_cached_new('lonnetglobal',$hashid);
+            }
+            if (defined($cached)) {
+                $returnhash{$what} = $response;
+            } else {
+                $whatneeded{$what} = 1;
+            }
+        }
+        if (keys(%whatneeded) == 0) {
+            $result = 'ok';
+        } else {
+            my $requested = &freeze_escape(\%whatneeded);
+            my $rep=&reply('readlonnetglobal:'.$requested,$lonhost);
+            if (($rep=~/^(refused|rejected|error)/) || ($rep eq 'con_lost') ||
+                ($rep eq 'unknown_cmd')) {
+                $result = $rep;
+            } else {
+                $result = 'ok';
+                my @pairs=split(/\&/,$rep);
+                foreach my $item (@pairs) {
+                    my ($key,$value)=split(/=/,$item,2);
+                    my $what = &unescape($key);
+                    my $hashid = $lonhost.'-'.$what;
+                    $returnhash{$what}=&thaw_unescape($value);
+                    &do_cache_new('lonnetglobal',$hashid,$returnhash{$what},600);
+                }
+            }
+        }
+    }
+    return ($result,\%returnhash);
+}
+
+sub remote_devalidate_cache {
+    my ($lonhost,$name,$id) = @_;
+    my $response = &reply('devalidatecache',&escape($name).':'.&escape($id),$lonhost);
+    return $response;
+}
+
 # -------------------------------------------------- Non-critical communication
 sub subreply {
     my ($cmd,$server)=@_;
@@ -772,26 +819,33 @@ sub spareserver {
         my %udomdefaults = &Apache::lonnet::get_domain_defaults($udom);
         $remotesessions = $udomdefaults{'remotesessions'};
     }
-    foreach my $try_server (@{ $spareid{'primary'} }) {
-        if ($uint_dom) {
-             next unless (&spare_can_host($udom,$uint_dom,$remotesessions,
-                                          $try_server));
+    my $spareshash = &this_host_spares($udom);
+    if (ref($spareshash) eq 'HASH') {
+        if (ref($spareshash->{'primary'}) eq 'ARRAY') {
+            foreach my $try_server (@{ $spareshash->{'primary'} }) {
+                if ($uint_dom) {
+                    next unless (&spare_can_host($udom,$uint_dom,$remotesessions,
+                                                 $try_server));
+                }
+	        ($spare_server, $lowest_load) =
+	            &compare_server_load($try_server, $spare_server, $lowest_load);
+            }
         }
-	($spare_server, $lowest_load) =
-	    &compare_server_load($try_server, $spare_server, $lowest_load);
-    }
-
-    my $found_server = ($spare_server ne '' && $lowest_load < 100);
 
-    if (!$found_server) {
-	foreach my $try_server (@{ $spareid{'default'} }) {
-            if ($uint_dom) {
-                next unless (&spare_can_host($udom,$uint_dom,$remotesessions,
-                                             $try_server));
-            }
-	    ($spare_server, $lowest_load) =
-		&compare_server_load($try_server, $spare_server, $lowest_load);
-	}
+        my $found_server = ($spare_server ne '' && $lowest_load < 100);
+
+        if (!$found_server) {
+            if (ref($spareshash->{'default'}) eq 'ARRAY') { 
+	        foreach my $try_server (@{ $spareshash->{'default'} }) {
+                    if ($uint_dom) {
+                        next unless (&spare_can_host($udom,$uint_dom,
+                                                     $remotesessions,$try_server));
+                    }
+	            ($spare_server, $lowest_load) =
+		        &compare_server_load($try_server, $spare_server, $lowest_load);
+                }
+	    }
+        }
     }
 
     if (!$want_server_name) {
@@ -842,9 +896,18 @@ sub compare_server_load {
 # --------------------------- ask offload servers if user already has a session
 sub find_existing_session {
     my ($udom,$uname) = @_;
-    foreach my $try_server (@{ $spareid{'primary'} },
-			    @{ $spareid{'default'} }) {
-	return $try_server if (&has_user_session($try_server, $udom, $uname));
+    my $spareshash = &this_host_spares($udom);
+    if (ref($spareshash) eq 'HASH') {
+        if (ref($spareshash->{'primary'}) eq 'ARRAY') {
+            foreach my $try_server (@{ $spareshash->{'primary'} }) {
+                return $try_server if (&has_user_session($try_server, $udom, $uname));
+            }
+        }
+        if (ref($spareshash->{'default'}) eq 'ARRAY') {
+            foreach my $try_server (@{ $spareshash->{'default'} }) {
+                return $try_server if (&has_user_session($try_server, $udom, $uname));
+            }
+        }
     }
     return;
 }
@@ -866,21 +929,34 @@ sub choose_server {
     my %domconfhash = &Apache::loncommon::get_domainconf($udom);
     my %servers = &get_servers($udom);
     my $lowest_load = 30000;
-    my ($login_host,$hostname);
+    my ($login_host,$hostname,$portal_path);
     foreach my $lonhost (keys(%servers)) {
         my $loginvia;
         if ($checkloginvia) {
             $loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost};
-        }
-        if ($loginvia eq '') {
+            if ($loginvia) {
+                my ($server,$path) = split(/:/,$loginvia);
+                ($login_host, $lowest_load) =
+                    &compare_server_load($server, $login_host, $lowest_load);
+                if ($login_host eq $server) {
+                    $portal_path = $path;
+                }
+            } else {
+                ($login_host, $lowest_load) =
+                    &compare_server_load($lonhost, $login_host, $lowest_load);
+                if ($login_host eq $lonhost) {
+                    $portal_path = '';
+                }
+            }
+        } else {
             ($login_host, $lowest_load) =
-            &compare_server_load($lonhost, $login_host, $lowest_load);
+                &compare_server_load($lonhost, $login_host, $lowest_load);
         }
     }
     if ($login_host ne '') {
-        $hostname = $servers{$login_host};
+        $hostname = &hostname($login_host);
     }
-    return ($login_host,$hostname);
+    return ($login_host,$hostname,$portal_path);
 }
 
 # --------------------------------------------- Try to change a user's password
@@ -1021,15 +1097,19 @@ sub can_host_session {
     }
     if ($canhost) {
         if (ref($hostedsessions) eq 'HASH') {
+            my $uprimary_id = &Apache::lonnet::domain($udom,'primary');
+            my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id);
             if (ref($hostedsessions->{'excludedomain'}) eq 'ARRAY') {
-                if (grep(/^\Q$udom\E$/,@{$hostedsessions->{'excludedomain'}})) {
+                if (($uint_dom ne '') && 
+                    (grep(/^\Q$uint_dom\E$/,@{$hostedsessions->{'excludedomain'}}))) {
                     $canhost = 0;
                 } else {
                     $canhost = 1;
                 }
             }
             if (ref($hostedsessions->{'includedomain'}) eq 'ARRAY') {
-                if (grep(/^\Q$udom\E$/,@{$hostedsessions->{'includedomain'}})) {
+                if (($uint_dom ne '') && 
+                    (grep(/^\Q$uint_dom\E$/,@{$hostedsessions->{'includedomain'}}))) {
                     $canhost = 1;
                 } else {
                     $canhost = 0;
@@ -1060,6 +1140,302 @@ sub spare_can_host {
     return $canhost;
 }
 
+sub this_host_spares {
+    my ($dom) = @_;
+    my ($dom_in_use,$lonhost_in_use,$result);
+    my @hosts = &current_machine_ids();
+    foreach my $lonhost (@hosts) {
+        if (&host_domain($lonhost) eq $dom) {
+            $dom_in_use = $dom;
+            $lonhost_in_use = $lonhost;
+            last;
+        }
+    }
+    if ($dom_in_use ne '') {
+        $result = &spares_for_offload($dom_in_use,$lonhost_in_use);
+    }
+    if (ref($result) ne 'HASH') {
+        $lonhost_in_use = $perlvar{'lonHostID'};
+        $dom_in_use = &host_domain($lonhost_in_use);
+        $result = &spares_for_offload($dom_in_use,$lonhost_in_use);
+        if (ref($result) ne 'HASH') {
+            $result = \%spareid;
+        }
+    }
+    return $result;
+}
+
+sub spares_for_offload  {
+    my ($dom_in_use,$lonhost_in_use) = @_;
+    my ($result,$cached)=&is_cached_new('spares',$dom_in_use);
+    if (defined($cached)) {
+        return $result;
+    } else {
+        my $cachetime = 60*60*24;
+        my %domconfig =
+            &Apache::lonnet::get_dom('configuration',['usersessions'],$dom_in_use);
+        if (ref($domconfig{'usersessions'}) eq 'HASH') {
+            if (ref($domconfig{'usersessions'}{'spares'}) eq 'HASH') {
+                if (ref($domconfig{'usersessions'}{'spares'}{$lonhost_in_use}) eq 'HASH') {
+                    return &do_cache_new('spares',$dom_in_use,$domconfig{'usersessions'}{'spares'}{$lonhost_in_use},$cachetime);
+                }
+            }
+        }
+    }
+    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{'usersessions'}{'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{'usersessions'}{'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;
@@ -2560,7 +2936,7 @@ sub finishuserfileupload {
 	    return '/adm/notfound.html';
 	}
         if ($context eq 'overwrite') {
-            my $source =  $perlvar{'lonDaemons'}.'/tmp/overwrites/'.$docudom.'/'.$docuname.'/'.$fname;
+            my $source =  LONCAPA::tempdir().'/overwrites/'.$docudom.'/'.$docuname.'/'.$fname;
             my $target = $filepath.'/'.$file;
             if (-e $source) {
                 my @info = stat($source);
@@ -3762,7 +4138,7 @@ sub tmpreset {
   if ($domain eq 'public' && $stuname eq 'public') {
       $stuname=$ENV{'REMOTE_ADDR'};
   }
-  my $path=$perlvar{'lonDaemons'}.'/tmp';
+  my $path=LONCAPA::tempdir();
   my %hash;
   if (tie(%hash,'GDBM_File',
 	  $path.'/tmpstore_'.$stuname.'_'.$domain.'_'.$namespace.'.db',
@@ -3801,7 +4177,7 @@ sub tmpstore {
   }
   my $now=time;
   my %hash;
-  my $path=$perlvar{'lonDaemons'}.'/tmp';
+  my $path=LONCAPA::tempdir();
   if (tie(%hash,'GDBM_File',
 	  $path.'/tmpstore_'.$stuname.'_'.$domain.'_'.$namespace.'.db',
 	  &GDBM_WRCREAT(),0640)) {
@@ -3847,7 +4223,7 @@ sub tmprestore {
   $namespace=~s/\//\_/g;
   $namespace=~s/\W//g;
   my %hash;
-  my $path=$perlvar{'lonDaemons'}.'/tmp';
+  my $path=LONCAPA::tempdir();
   if (tie(%hash,'GDBM_File',
 	  $path.'/tmpstore_'.$stuname.'_'.$domain.'_'.$namespace.'.db',
 	  &GDBM_READER(),0640)) {
@@ -3984,6 +4360,8 @@ sub restore {
 }
 
 # ---------------------------------------------------------- Course Description
+#
+#  
 
 sub coursedescription {
     my ($courseid,$args)=@_;
@@ -4013,7 +4391,8 @@ sub coursedescription {
 	return %returnhash;
     }
 
-    # get the data agin
+    # get the data again
+
     if (!$args->{'one_time'}) {
 	$envhash{'course.'.$normalid.'.last_cache'}=time;
     }
@@ -4021,6 +4400,10 @@ sub coursedescription {
     if ($chome ne 'no_host') {
        %returnhash=&dump('environment',$cdomain,$cnum);
        if (!exists($returnhash{'con_lost'})) {
+	   my $username = $env{'user.name'}; # Defult username
+	   if(defined $args->{'user'}) {
+	       $username = $args->{'user'};
+	   }
            $returnhash{'home'}= $chome;
 	   $returnhash{'domain'} = $cdomain;
 	   $returnhash{'num'} = $cnum;
@@ -4031,8 +4414,8 @@ sub coursedescription {
                $envhash{'course.'.$normalid.'.'.$name}=$value;
            }
            $returnhash{'url'}=&clutter($returnhash{'url'});
-           $returnhash{'fn'}=$perlvar{'lonDaemons'}.'/tmp/'.
-	       $env{'user.name'}.'_'.$cdomain.'_'.$cnum;
+           $returnhash{'fn'}=LONCAPA::tempdir() .
+	       $username.'_'.$cdomain.'_'.$cnum;
            $envhash{'course.'.$normalid.'.home'}=$chome;
            $envhash{'course.'.$normalid.'.domain'}=$cdomain;
            $envhash{'course.'.$normalid.'.num'}=$cnum;
@@ -5213,12 +5596,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;
@@ -5232,6 +5619,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)) {
@@ -5246,6 +5636,9 @@ sub is_advanced_user {
             }
         }
     }
+    if (wantarray) {
+        return ($is_adv,$is_author);
+    }
     return $is_adv;
 }
 
@@ -5982,7 +6375,7 @@ sub fetch_enrollment_query {
                 $$replyref{$key} = $value;
             }
         } else {
-            my $pathname = $perlvar{'lonDaemons'}.'/tmp';
+            my $pathname = LONCAPA::tempdir();
             foreach my $line (@responses) {
                 my ($key,$value) = split(/=/,$line);
                 $$replyref{$key} = $value;
@@ -6012,7 +6405,7 @@ sub fetch_enrollment_query {
 
 sub get_query_reply {
     my $queryid=shift;
-    my $replyfile=$perlvar{'lonDaemons'}.'/tmp/'.$queryid;
+    my $replyfile=LONCAPA::tempdir().$queryid;
     my $reply='';
     for (1..100) {
 	sleep 2;
@@ -7449,7 +7842,7 @@ sub save_selected_files {
 sub clear_selected_files {
     my ($user) = @_;
     my $filename = $user."savedfiles";
-    open (OUT, '>'.$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename);
+    open (OUT, '>'.LONCAPA::tempdir().$filename);
     print (OUT undef);
     close (OUT);
     return ("ok");    
@@ -7459,7 +7852,7 @@ sub files_in_path {
     my ($user, $path) = @_;
     my $filename = $user."savedfiles";
     my %return_files;
-    open (IN, '<'.$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename);
+    open (IN, '<'.LONCAPA::tempdir().$filename);
     while (my $line_in = <IN>) {
         chomp ($line_in);
         my @paths_and_file = split (m!/!, $line_in);
@@ -7481,7 +7874,7 @@ sub files_not_in_path {
     my $filename = $user."savedfiles";
     my @return_files;
     my $path_part;
-    open(IN, '<'.$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename);
+    open(IN, '<'.LONCAPA::.$filename);
     while (my $line = <IN>) {
         #ok, I know it's clunky, but I want it to work
         my @paths_and_file = split(m|/|, $line);
@@ -9775,7 +10168,7 @@ sub filelocation {
         my @ids=&current_machine_ids();
         foreach my $id (@ids) { if ($id eq $home) { $is_me=1; } }
         if ($is_me) {
-  	    $location=&propath($udom,$uname).'/userfiles/'.$filename;
+  	    $location=propath($udom,$uname).'/userfiles/'.$filename;
         } else {
   	  $location=$Apache::lonnet::perlvar{'lonDocRoot'}.'/userfiles/'.
   	      $udom.'/'.$uname.'/'.$filename;
@@ -10530,7 +10923,7 @@ BEGIN {
 
 # ------------- set up temporary directory
 {
-    $tmpdir = $perlvar{'lonDaemons'}.'/tmp/';
+    $tmpdir = LONCAPA::tempdir();
 
 }
 
@@ -11024,11 +11417,32 @@ revokecustomrole($udom,$uname,$url,$role
 
 =item *
 
-coursedescription($courseid) : returns a hash of information about the
+coursedescription($courseid,$options) : returns a hash of information about the
 specified course id, including all environment settings for the
 course, the description of the course will be in the hash under the
 key 'description'
 
+$options is an optional parameter that if supplied is a hash reference that controls
+what how this function works.  It has the following key/values:
+
+=over 4
+
+=item freshen_cache
+
+If defined, and the environment cache for the course is valid, it is 
+returned in the returned hash.
+
+=item one_time
+
+If defined, the last cache time is set to _now_
+
+=item user
+
+If defined, the supplied username is used instead of the current user.
+
+
+=back
+
 =item *
 
 resdata($name,$domain,$type,@which) : request for current parameter
@@ -11421,11 +11835,12 @@ splitting on '&', supports elements that
 
 =head2 Logging Routines
 
-=over 4
 
 These routines allow one to make log messages in the lonnet.log and
 lonnet.perm logfiles.
 
+=over 4
+
 =item *
 
 logtouch() : make sure the logfile, lonnet.log, exists
@@ -11441,6 +11856,7 @@ logperm() : append a permanent message t
 file never gets deleted by any automated portion of the system, only
 messages of critical importance should go in here.
 
+
 =back
 
 =head2 General File Helper Routines