--- loncom/lonnet/perl/lonnet.pm	2006/07/21 19:42:25	1.766
+++ loncom/lonnet/perl/lonnet.pm	2006/10/13 04:23:15	1.791
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.766 2006/07/21 19:42:25 albertel Exp $
+# $Id: lonnet.pm,v 1.791 2006/10/13 04:23:15 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -52,6 +52,7 @@ use Storable qw(lock_store lock_nstore l
 use Time::HiRes qw( gettimeofday tv_interval );
 use Cache::Memcached;
 use Digest::MD5;
+use Math::Random;
 use lib '/home/httpd/lib/perl';
 use LONCAPA;
 use LONCAPA::Configuration;
@@ -292,10 +293,40 @@ sub error {
     return undef;
 }
 
-# ------------------------------------------- Transfer profile into environment
+sub convert_and_load_session_env {
+    my ($lonidsdir,$handle)=@_;
+    my @profile;
+    {
+	open(my $idf,"$lonidsdir/$handle.id");
+	flock($idf,LOCK_SH);
+	@profile=<$idf>;
+	close($idf);
+    }
+    my %temp_env;
+    foreach my $line (@profile) {
+	if ($line !~ m/=/) {
+	    return 0;
+	}
+	chomp($line);
+	my ($envname,$envvalue)=split(/=/,$line,2);
+	$temp_env{&unescape($envname)} = &unescape($envvalue);
+    }
+    unlink("$lonidsdir/$handle.id");
+    if (tie(my %disk_env,'GDBM_File',"$lonidsdir/$handle.id",&GDBM_WRCREAT(),
+	    0640)) {
+	%disk_env = %temp_env;
+	@env{keys(%temp_env)} = @disk_env{keys(%temp_env)};
+	untie(%disk_env);
+    }
+    return 1;
+}
 
+# ------------------------------------------- Transfer profile into environment
+my $env_loaded;
 sub transfer_profile_to_env {
-    my ($lonidsdir,$handle)=@_;
+    my ($lonidsdir,$handle,$force_transfer) = @_;
+    if (!$force_transfer && $env_loaded) { return; } 
+
     if (!defined($lonidsdir)) {
 	$lonidsdir = $perlvar{'lonIDsDir'};
     }
@@ -303,29 +334,36 @@ sub transfer_profile_to_env {
         ($handle) = ($env{'user.environment'} =~m|/([^/]+)\.id$| );
     }
 
-    my @profile;
+    my $convert;
     {
-	open(my $idf,"$lonidsdir/$handle.id");
+    	open(my $idf,"$lonidsdir/$handle.id");
 	flock($idf,LOCK_SH);
-	@profile=<$idf>;
-	close($idf);
+	if (tie(my %disk_env,'GDBM_File',"$lonidsdir/$handle.id",
+		&GDBM_READER(),0640)) {
+	    @env{keys(%disk_env)} = @disk_env{keys(%disk_env)};
+	    untie(%disk_env);
+	} else {
+	    $convert = 1;
+	}
+    }
+    if ($convert) {
+	if (!&convert_and_load_session_env($lonidsdir,$handle)) {
+	    &logthis("Failed to load session, or convert session.");
+	}
     }
-    my $envi;
-    my %Remove;
-    for ($envi=0;$envi<=$#profile;$envi++) {
-	chomp($profile[$envi]);
-	my ($envname,$envvalue)=split(/=/,$profile[$envi],2);
-	$envname=&unescape($envname);
-	$envvalue=&unescape($envvalue);
-	$env{$envname} = $envvalue;
+
+    my %remove;
+    while ( my $envname = each(%env) ) {
         if (my ($key,$time) = ($envname =~ /^(cgi\.(\d+)_\d+\.)/)) {
             if ($time < time-300) {
-                $Remove{$key}++;
+                $remove{$key}++;
             }
         }
     }
+
     $env{'user.environment'} = "$lonidsdir/$handle.id";
-    foreach my $expired_key (keys(%Remove)) {
+    $env_loaded=1;
+    foreach my $expired_key (keys(%remove)) {
         &delenv($expired_key);
     }
 }
@@ -344,51 +382,13 @@ sub appenv {
             $env{$key}=$newenv{$key};
         }
     }
-
-    my $lockfh;
-    unless (open($lockfh,"$env{'user.environment'}")) {
-	return 'error: '.$!;
-    }
-    unless (flock($lockfh,LOCK_EX)) {
-         &logthis("<font color=\"blue\">WARNING: ".
-                  'Could not obtain exclusive lock in appenv: '.$!);
-         close($lockfh);
-         return 'error: '.$!;
-    }
-
-    my @oldenv;
-    {
-	my $fh;
-	unless (open($fh,"$env{'user.environment'}")) {
-	    return 'error: '.$!;
-	}
-	@oldenv=<$fh>;
-	close($fh);
-    }
-    for (my $i=0; $i<=$#oldenv; $i++) {
-        chomp($oldenv[$i]);
-        if ($oldenv[$i] ne '') {
-	    my ($name,$value)=split(/=/,$oldenv[$i],2);
-	    $name=&unescape($name);
-	    $value=&unescape($value);
-	    unless (defined($newenv{$name})) {
-		$newenv{$name}=$value;
-	    }
-        }
-    }
-    {
-	my $fh;
-	unless (open($fh,">$env{'user.environment'}")) {
-	    return 'error';
-	}
-	my $newname;
-	foreach $newname (keys %newenv) {
-	    print $fh &escape($newname).'='.&escape($newenv{$newname})."\n";
+    if (tie(my %disk_env,'GDBM_File',$env{'user.environment'},&GDBM_WRITER(),
+	    0640)) {
+	while (my ($key,$value) = each(%newenv)) {
+	    $disk_env{$key} = $value;
 	}
-	close($fh);
+	untie(%disk_env);
     }
-	
-    close($lockfh);
     return 'ok';
 }
 # ----------------------------------------------------- Delete from Environment
@@ -400,47 +400,44 @@ sub delenv {
                 "Attempt to delete from environment ".$delthis);
         return 'error';
     }
-    my @oldenv;
-    {
-	my $fh;
-	unless (open($fh,"$env{'user.environment'}")) {
-	    return 'error';
-	}
-	unless (flock($fh,LOCK_SH)) {
-	    &logthis("<font color=\"blue\">WARNING: ".
-		     'Could not obtain shared lock in delenv: '.$!);
-	    close($fh);
-	    return 'error: '.$!;
-	}
-	@oldenv=<$fh>;
-	close($fh);
-    }
-    {
-	my $fh;
-	unless (open($fh,">$env{'user.environment'}")) {
-	    return 'error';
-	}
-	unless (flock($fh,LOCK_EX)) {
-	    &logthis("<font color=\"blue\">WARNING: ".
-		     'Could not obtain exclusive lock in delenv: '.$!);
-	    close($fh);
-	    return 'error: '.$!;
-	}
-	foreach my $cur_key (@oldenv) {
-	    my $unescaped_cur_key = &unescape($cur_key);
-	    if ($unescaped_cur_key=~/^$delthis/) { 
-                my ($key) = split('=',$cur_key,2);
-		$key = &unescape($key);
+    if (tie(my %disk_env,'GDBM_File',$env{'user.environment'},&GDBM_WRITER(),
+	    0640)) {
+	foreach my $key (keys(%disk_env)) {
+	    if ($key=~/^$delthis/) { 
                 delete($env{$key});
-            } else {
-                print $fh $cur_key; 
+                delete($disk_env{$key});
             }
 	}
-	close($fh);
+	untie(%disk_env);
     }
     return 'ok';
 }
 
+=pod
+
+=item * get_env_multiple($name) 
+
+gets $name from the %env hash, it seemlessly handles the cases where multiple
+values may be defined and end up as an array ref.
+
+returns an array of values
+
+=cut
+
+sub get_env_multiple {
+    my ($name) = @_;
+    my @values;
+    if (defined($env{$name})) {
+        # exists is it an array
+        if (ref($env{$name})) {
+            @values=@{ $env{$name} };
+        } else {
+            $values[0]=$env{$name};
+        }
+    }
+    return(@values);
+}
+
 # ------------------------------------------ Find out current server userload
 # there is a copy in lond
 sub userload {
@@ -493,41 +490,60 @@ sub overloaderror {
 
 sub spareserver {
     my ($loadpercent,$userloadpercent,$want_server_name) = @_;
-    my $tryserver;
-    my $spareserver='';
+    my $spare_server;
     if ($userloadpercent !~ /\d/) { $userloadpercent=0; }
-    my $lowestserver=$loadpercent > $userloadpercent?
-	             $loadpercent :  $userloadpercent;
-    foreach $tryserver (keys(%spareid)) {
-	my $loadans=&reply('load',$tryserver);
-	my $userloadans=&reply('userload',$tryserver);
-	if ($loadans !~ /\d/ && $userloadans !~ /\d/) {
-	    next; #didn't get a number from the server
-	}
-	my $answer;
-	if ($loadans =~ /\d/) {
-	    if ($userloadans =~ /\d/) {
-		#both are numbers, pick the bigger one
-		$answer=$loadans > $userloadans?
-		    $loadans :  $userloadans;
-	    } else {
-		$answer = $loadans;
-	    }
-	} else {
-	    $answer = $userloadans;
-	}
-	if (($answer =~ /\d/) && ($answer<$lowestserver)) {
-	    if ($want_server_name) {
-		$spareserver=$tryserver;
-	    } else {
-		$spareserver="http://$hostname{$tryserver}";
-	    }
-	    $lowestserver=$answer;
+    my $lowest_load=($loadpercent > $userloadpercent) ? $loadpercent 
+                                                     :  $userloadpercent;
+    
+    foreach my $try_server (@{ $spareid{'primary'} }) {
+	($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'} }) {
+	    ($spare_server, $lowest_load) =
+		&compare_server_load($try_server, $spare_server, $lowest_load);
 	}
     }
-    return $spareserver;
+
+    if (!$want_server_name) {
+	$spare_server="http://$hostname{$spare_server}";
+    }
+    return $spare_server;
 }
 
+sub compare_server_load {
+    my ($try_server, $spare_server, $lowest_load) = @_;
+
+    my $loadans     = &reply('load',    $try_server);
+    my $userloadans = &reply('userload',$try_server);
+
+    if ($loadans !~ /\d/ && $userloadans !~ /\d/) {
+	next; #didn't get a number from the server
+    }
+
+    my $load;
+    if ($loadans =~ /\d/) {
+	if ($userloadans =~ /\d/) {
+	    #both are numbers, pick the bigger one
+	    $load = ($loadans > $userloadans) ? $loadans 
+		                              : $userloadans;
+	} else {
+	    $load = $loadans;
+	}
+    } else {
+	$load = $userloadans;
+    }
+
+    if (($load =~ /\d/) && ($load < $lowest_load)) {
+	$spare_server = $try_server;
+	$lowest_load  = $load;
+    }
+    return ($spare_server,$lowest_load);
+}
 # --------------------------------------------- Try to change a user's password
 
 sub changepass {
@@ -891,6 +907,7 @@ sub save_cache {
     &purge_remembered();
     #&Apache::loncommon::validate_page();
     undef(%env);
+    undef($env_loaded);
 }
 
 my $to_remember=-1;
@@ -1176,7 +1193,7 @@ sub ssi_body {
     }
     my $output=($filelink=~/^http\:/?&externalssi($filelink):
                                      &ssi($filelink,%form));
-    $output=~s|//(\s*<!--)? BEGIN LON-CAPA Internal.+// END LON-CAPA Internal\s*(-->)?\s||gs;
+    $output=~s|//(\s*<!--)? BEGIN LON-CAPA Internal.+?// END LON-CAPA Internal\s*(-->)?\s||gs;
     $output=~s/^.*?\<body[^\>]*\>//si;
     $output=~s/(.*)\<\/body\s*\>.*?$/$1/si;
     return $output;
@@ -1184,6 +1201,15 @@ sub ssi_body {
 
 # --------------------------------------------------------- Server Side Include
 
+sub absolute_url {
+    my ($host_name) = @_;
+    my $protocol = ($ENV{'SERVER_PORT'} == 443?'https://':'http://');
+    if ($host_name eq '') {
+	$host_name = $ENV{'SERVER_NAME'};
+    }
+    return $protocol.$host_name;
+}
+
 sub ssi {
 
     my ($fn,%form)=@_;
@@ -1195,10 +1221,10 @@ sub ssi {
     $form{'no_update_last_known'}=1;
 
     if (%form) {
-      $request=new HTTP::Request('POST',"http://".$ENV{'HTTP_HOST'}.$fn);
+      $request=new HTTP::Request('POST',&absolute_url().$fn);
       $request->content(join('&',map { &escape($_).'='.&escape($form{$_}) } keys %form));
     } else {
-      $request=new HTTP::Request('GET',"http://".$ENV{'HTTP_HOST'}.$fn);
+      $request=new HTTP::Request('GET',&absolute_url().$fn);
     }
 
     $request->header(Cookie => $ENV{'HTTP_COOKIE'});
@@ -1953,7 +1979,7 @@ sub courseidput {
 }
 
 sub courseiddump {
-    my ($domfilter,$descfilter,$sincefilter,$instcodefilter,$ownerfilter,$coursefilter,$hostidflag,$hostidref,$typefilter)=@_;
+    my ($domfilter,$descfilter,$sincefilter,$instcodefilter,$ownerfilter,$coursefilter,$hostidflag,$hostidref,$typefilter,$regexp_ok)=@_;
     my %returnhash=();
     unless ($domfilter) { $domfilter=''; }
     foreach my $tryserver (keys %libserv) {
@@ -1962,7 +1988,7 @@ sub courseiddump {
 	        foreach (
                  split(/\&/,&reply('courseiddump:'.$hostdom{$tryserver}.':'.
 			       $sincefilter.':'.&escape($descfilter).':'.
-                               &escape($instcodefilter).':'.&escape($ownerfilter).':'.&escape($coursefilter).':'.&escape($typefilter),
+                               &escape($instcodefilter).':'.&escape($ownerfilter).':'.&escape($coursefilter).':'.&escape($typefilter).':'.&escape($regexp_ok),
                                $tryserver))) {
 		    my ($key,$value)=split(/\=/,$_);
                     if (($key) && ($value)) {
@@ -2035,7 +2061,7 @@ sub get_domain_roles {
 
 sub get_first_access {
     my ($type,$argsymb)=@_;
-    my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser();
+    my ($symb,$courseid,$udom,$uname)=&whichuser();
     if ($argsymb) { $symb=$argsymb; }
     my ($map,$id,$res)=&decode_symb($symb);
     if ($type eq 'map') {
@@ -2049,7 +2075,7 @@ sub get_first_access {
 
 sub set_first_access {
     my ($type)=@_;
-    my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser();
+    my ($symb,$courseid,$udom,$uname)=&whichuser();
     my ($map,$id,$res)=&decode_symb($symb);
     if ($type eq 'map') {
 	$res=&symbread($map);
@@ -2845,7 +2871,7 @@ sub set_userprivs {
     if (keys(%{$allgroups}) > 0) {
         foreach my $role (keys %{$allroles}) {
             my ($trole,$area,$sec,$extendedarea);
-            if ($role =~ m|^(\w+)\.(/\w+/\w+)(/?\w*)|) {
+            if ($role =~ m-^(\w+|cr/\w+/\w+/\w+)\.(/\w+/\w+)(/?\w*)-) {
                 $trole = $1;
                 $area = $2;
                 $sec = $3;
@@ -3232,14 +3258,17 @@ sub portfolio_access {
 }
 
 sub get_portfolio_access {
-    my ($udom,$unum,$file_name,$group) = @_;
- 
-    my $current_perms = &get_portfile_permissions($udom,$unum);
-    my %access_controls = &get_access_controls($current_perms,$group,
-					       $file_name);
+    my ($udom,$unum,$file_name,$group,$access_hash) = @_;
+
+    if (!ref($access_hash)) {
+	my $current_perms = &get_portfile_permissions($udom,$unum);
+	my %access_controls = &get_access_controls($current_perms,$group,
+						   $file_name);
+	$access_hash = $access_controls{$file_name};
+    }
+
     my ($public,$guest,@domains,@users,@courses,@groups);
     my $now = time;
-    my $access_hash = $access_controls{$file_name};
     if (ref($access_hash) eq 'HASH') {
         foreach my $key (keys(%{$access_hash})) {
             my ($num,$scope,$end,$start) = ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
@@ -3471,8 +3500,9 @@ sub allowed {
     
     if (defined($env{'allowed.'.$priv})) { return $env{'allowed.'.$priv}; }
 # Free bre access to adm and meta resources
-    if (((($uri=~/^adm\//) && ($uri !~ m|/bulletinboard$|)) 
-	 || ($uri=~/\.meta$/)) && ($priv eq 'bre')) {
+    if (((($uri=~/^adm\//) && ($uri !~ m{/(?:smppg|bulletinboard)$})) 
+	 || (($uri=~/\.meta$/) && ($uri!~m|^uploaded/|) )) 
+	&& ($priv eq 'bre')) {
 	return 'F';
     }
 
@@ -4070,7 +4100,7 @@ sub auto_run {
     my $response = &reply('autorun:'.$cdom,$homeserver);
     return $response;
 }
-                                                                                   
+
 sub auto_get_sections {
     my ($cnum,$cdom,$inst_coursecode) = @_;
     my $homeserver = &homeserver($cnum,$cdom);
@@ -4081,21 +4111,21 @@ sub auto_get_sections {
     }
     return @secs;
 }
-                                                                                   
+
 sub auto_new_course {
     my ($cnum,$cdom,$inst_course_id,$owner) = @_;
     my $homeserver = &homeserver($cnum,$cdom);
     my $response=&unescape(&reply('autonewcourse:'.$inst_course_id.':'.$owner.':'.$cdom,$homeserver));
     return $response;
 }
-                                                                                   
+
 sub auto_validate_courseID {
     my ($cnum,$cdom,$inst_course_id) = @_;
     my $homeserver = &homeserver($cnum,$cdom);
     my $response=&unescape(&reply('autovalidatecourse:'.$inst_course_id.':'.$cdom,$homeserver));
     return $response;
 }
-                                                                                   
+
 sub auto_create_password {
     my ($cnum,$cdom,$authparam) = @_;
     my $homeserver = &homeserver($cnum,$cdom); 
@@ -4189,33 +4219,49 @@ sub auto_photoupdate {
 sub auto_instcode_format {
     my ($caller,$codedom,$instcodes,$codes,$codetitles,$cat_titles,$cat_order) = @_;
     my $courses = '';
-    my $homeserver;
+    my @homeservers;
     if ($caller eq 'global') {
         foreach my $tryserver (keys %libserv) {
             if ($hostdom{$tryserver} eq $codedom) {
-                $homeserver = $tryserver;
-                last;
+                if (!grep/^\Q$tryserver\E$/,@homeservers) {
+                    push(@homeservers,$tryserver);
+                }
             }
         }
-        if (($env{'user.name'}) && ($env{'user.domain'} eq $codedom)) {
-            $homeserver = &homeserver($env{'user.name'},$codedom);
-        }
     } else {
-        $homeserver = &homeserver($caller,$codedom);
+        push(@homeservers,&homeserver($caller,$codedom));
     }
     foreach (keys %{$instcodes}) {
         $courses .= &escape($_).'='.&escape($$instcodes{$_}).'&';
     }
     chop($courses);
-    my $response=&reply('autoinstcodeformat:'.$codedom.':'.$courses,$homeserver);
-    unless ($response =~ /(con_lost|error|no_such_host|refused)/) {
-        my ($codes_str,$codetitles_str,$cat_titles_str,$cat_order_str) = split/:/,$response;
-        %{$codes} = &str2hash($codes_str);
-        @{$codetitles} = &str2array($codetitles_str);
-        %{$cat_titles} = &str2hash($cat_titles_str);
-        %{$cat_order} = &str2hash($cat_order_str);
+    my $ok_response = 0;
+    my $response;
+    while (@homeservers > 0 && $ok_response == 0) {
+        my $server = shift(@homeservers); 
+        $response=&reply('autoinstcodeformat:'.$codedom.':'.$courses,$server);
+        if ($response !~ /(con_lost|error|no_such_host|refused)/) {
+            my ($codes_str,$codetitles_str,$cat_titles_str,$cat_order_str) = 
+                                                            split/:/,$response;
+            %{$codes} = (%{$codes},&str2hash($codes_str));
+            push(@{$codetitles},&str2array($codetitles_str));
+            %{$cat_titles} = (%{$cat_titles},&str2hash($cat_titles_str));
+            %{$cat_order} = (%{$cat_order},&str2hash($cat_order_str));
+            $ok_response = 1;
+        }
+    }
+    if ($ok_response) {
         return 'ok';
+    } else {
+        return $response;
     }
+}
+
+sub auto_validate_class_sec {
+    my ($cdom,$cnum,$owner,$inst_class) = @_;
+    my $homeserver = &homeserver($cnum,$cdom);
+    my $response=&reply('autovalidateclass_sec:'.$inst_class.':'.
+                        &escape($owner).':'.$cdom,$homeserver);
     return $response;
 }
 
@@ -4911,11 +4957,13 @@ sub get_portfile_permissions {
 
 sub get_access_controls {
     my ($current_permissions,$group,$file) = @_;
-    my %access; 
+    my %access;
+    my $real_file = $file;
+    $file =~ s/\.meta$//;
     if (defined($file)) {
         if (ref($$current_permissions{$file."\0".'accesscontrol'}) eq 'HASH') {
             foreach my $control (keys(%{$$current_permissions{$file."\0".'accesscontrol'}})) {
-                $access{$file}{$control} = $$current_permissions{$file."\0".$control};
+                $access{$real_file}{$control} = $$current_permissions{$file."\0".$control};
             }
         }
     } else {
@@ -5255,13 +5303,8 @@ sub GetFileTimestamp {
 
 sub stat_file {
     my ($uri) = @_;
-    $uri = &clutter($uri);
+    $uri = &clutter_with_no_wrapper($uri);
 
-    # we want just the url part without the unneeded accessor url bits
-    if ($uri =~ m-^/adm/-) {
-	$uri=~s-^/adm/wrapper/-/-;
-	$uri=~s-^/adm/coursedocs/showdoc/-/-;
-    }
     my ($udom,$uname,$file,$dir);
     if ($uri =~ m-^/(uploaded|editupload)/-) {
 	($udom,$uname,$file) =
@@ -5493,8 +5536,7 @@ sub EXT {
 	$symbparm=&get_symb_from_alias($symbparm);
     }
     if (!($uname && $udom)) {
-      (my $cursymb,$courseid,$udom,$uname,$publicuser)=
-	  &Apache::lonxml::whichuser($symbparm);
+      (my $cursymb,$courseid,$udom,$uname,$publicuser)= &whichuser($symbparm);
       if (!$symbparm) {	$symbparm=$cursymb; }
     } else {
 	$courseid=$env{'request.course.id'};
@@ -5731,6 +5773,9 @@ sub EXT {
 	if (($uname eq $env{'user.name'})&&($udom eq $env{'user.domain'})) {
 	    return $env{'environment.'.$spacequalifierrest};
 	} else {
+	    if ($uname eq 'anonymous' && $udom eq '') {
+		return '';
+	    }
 	    my %returnhash=&userenvironment($udom,$uname,
 					    $spacequalifierrest);
 	    return $returnhash{$spacequalifierrest};
@@ -5881,7 +5926,7 @@ sub metadata {
         my %metathesekeys=();
         unless ($filename=~/\.meta$/) { $filename.='.meta'; }
 	my $metastring;
-	if ($uri !~ m -^(uploaded|editupload)/-) {
+	if ($uri !~ m -^(editupload)/-) {
 	    my $file=&filelocation('',&clutter($filename));
 	    #push(@{$metaentry{$uri.'.file'}},$file);
 	    $metastring=&getfile($file);
@@ -6145,7 +6190,7 @@ sub gettitle {
 sub get_slot {
     my ($which,$cnum,$cdom)=@_;
     if (!$cnum || !$cdom) {
-	(undef,my $courseid)=&Apache::lonxml::whichuser();
+	(undef,my $courseid)=&whichuser();
 	$cdom=$env{'course.'.$courseid.'.domain'};
 	$cnum=$env{'course.'.$courseid.'.num'};
     }
@@ -6194,9 +6239,6 @@ sub symblist {
 sub symbverify {
     my ($symb,$thisurl)=@_;
     my $thisfn=$thisurl;
-# wrapper not part of symbs
-    $thisfn=~s/^\/adm\/wrapper//;
-    $thisfn=~s/^\/adm\/coursedocs\/showdoc\///;
     $thisfn=&declutter($thisfn);
 # direct jump to resource in page or to a sequence - will construct own symbs
     if ($thisfn=~/\.(page|sequence)$/) { return 1; }
@@ -6479,7 +6521,7 @@ sub latest_rnd_algorithm_id {
 
 sub get_rand_alg {
     my ($courseid)=@_;
-    if (!$courseid) { $courseid=(&Apache::lonxml::whichuser())[1]; }
+    if (!$courseid) { $courseid=(&whichuser())[1]; }
     if ($courseid) {
 	return $env{"course.$courseid.rndseed"};
     }
@@ -6505,7 +6547,7 @@ sub getCODE {
 sub rndseed {
     my ($symb,$courseid,$domain,$username)=@_;
 
-    my ($wsymb,$wcourseid,$wdomain,$wusername)=&Apache::lonxml::whichuser();
+    my ($wsymb,$wcourseid,$wdomain,$wusername)=&whichuser();
     if (!$symb) {
 	unless ($symb=$wsymb) { return time; }
     }
@@ -6546,8 +6588,8 @@ sub rndseed_32bit {
 	my $domainseed=unpack("%32C*",$domain) << 7;
 	my $courseseed=unpack("%32C*",$courseid);
 	my $num=$symbseed+$nameseed+$domainseed+$courseseed+$namechck+$symbchck;
-	#&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
-	#&Apache::lonxml::debug("rndseed :$num:$symb");
+	#&logthis("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
+	#&logthis("rndseed :$num:$symb");
 	if ($_64bit) { $num=(($num<<32)>>32); }
 	return $num;
     }
@@ -6567,8 +6609,8 @@ sub rndseed_64bit {
 	
 	my $num1=$symbchck+$symbseed+$namechck;
 	my $num2=$nameseed+$domainseed+$courseseed;
-	#&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
-	#&Apache::lonxml::debug("rndseed :$num:$symb");
+	#&logthis("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
+	#&logthis("rndseed :$num:$symb");
 	if ($_64bit) { $num1=(($num1<<32)>>32); $num2=(($num2<<32)>>32); }
 	if ($_64bit) { $num1=(($num1<<32)>>32); $num2=(($num2<<32)>>32); }
 	return "$num1,$num2";
@@ -6591,8 +6633,8 @@ sub rndseed_64bit2 {
 	
 	my $num1=$symbchck+$symbseed+$namechck;
 	my $num2=$nameseed+$domainseed+$courseseed;
-	#&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
-	#&Apache::lonxml::debug("rndseed :$num:$symb");
+	#&logthis("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
+	#&logthis("rndseed :$num:$symb");
 	return "$num1,$num2";
     }
 }
@@ -6613,8 +6655,8 @@ sub rndseed_64bit3 {
 	
 	my $num1=$symbchck+$symbseed+$namechck;
 	my $num2=$nameseed+$domainseed+$courseseed;
-	#&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
-	#&Apache::lonxml::debug("rndseed :$num1:$num2:$_64bit");
+	#&logthis("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
+	#&logthis("rndseed :$num1:$num2:$_64bit");
 	if ($_64bit) { $num1=(($num1<<32)>>32); $num2=(($num2<<32)>>32); }
 	
 	return "$num1:$num2";
@@ -6637,8 +6679,8 @@ sub rndseed_64bit4 {
 	
 	my $num1=$symbchck+$symbseed+$namechck;
 	my $num2=$nameseed+$domainseed+$courseseed;
-	#&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
-	#&Apache::lonxml::debug("rndseed :$num1:$num2:$_64bit");
+	#&logthis("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
+	#&logthis("rndseed :$num1:$num2:$_64bit");
 	if ($_64bit) { $num1=(($num1<<32)>>32); $num2=(($num2<<32)>>32); }
 	
 	return "$num1:$num2";
@@ -6662,8 +6704,8 @@ sub rndseed_CODE_64bit {
 	my $courseseed=unpack("%32S*",$courseid.' ');
 	my $num1=$symbseed+$CODEchck;
 	my $num2=$CODEseed+$courseseed+$symbchck;
-	#&Apache::lonxml::debug("$symbseed:$CODEchck|$CODEseed:$courseseed:$symbchck");
-	#&Apache::lonxml::debug("rndseed :$num1:$num2:$symb");
+	#&logthis("$symbseed:$CODEchck|$CODEseed:$courseseed:$symbchck");
+	#&logthis("rndseed :$num1:$num2:$symb");
 	if ($_64bit) { $num1=(($num1<<32)>>32); }
 	if ($_64bit) { $num2=(($num2<<32)>>32); }
 	return "$num1:$num2";
@@ -6681,8 +6723,8 @@ sub rndseed_CODE_64bit4 {
 	my $courseseed=unpack("%32S*",$courseid.' ');
 	my $num1=$symbseed+$CODEchck;
 	my $num2=$CODEseed+$courseseed+$symbchck;
-	#&Apache::lonxml::debug("$symbseed:$CODEchck|$CODEseed:$courseseed:$symbchck");
-	#&Apache::lonxml::debug("rndseed :$num1:$num2:$symb");
+	#&logthis("$symbseed:$CODEchck|$CODEseed:$courseseed:$symbchck");
+	#&logthis("rndseed :$num1:$num2:$symb");
 	if ($_64bit) { $num1=(($num1<<32)>>32); }
 	if ($_64bit) { $num2=(($num2<<32)>>32); }
 	return "$num1:$num2";
@@ -6743,8 +6785,7 @@ sub ireceipt {
     my $return =&recprefix($fucourseid).'-';
     if ($env{"course.$fucourseid.receiptalg"} eq 'receipt2' ||
 	$env{'request.state'} eq 'construct') {
-	&Apache::lonxml::debug("doing receipt2  using parts $cpart, uname $cuname and udom $cudom gets  ".($cpart%$cuname).
-			       " and ".($cpart%$cudom));
+	#&logthis("doing receipt2  using parts $cpart, uname $cuname and udom $cudom gets  ".($cpart%$cuname)." and ".($cpart%$cudom));
 			       
 	$return.= ($cunique%$cuname+
 		   $cunique%$cudom+
@@ -6767,10 +6808,48 @@ sub ireceipt {
 
 sub receipt {
     my ($part)=@_;
-    my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser();
+    my ($symb,$courseid,$domain,$name) = &whichuser();
     return &ireceipt($name,$domain,$courseid,$symb,$part);
 }
 
+sub whichuser {
+    my ($passedsymb)=@_;
+    my ($symb,$courseid,$domain,$name,$publicuser);
+    if (defined($env{'form.grade_symb'})) {
+	my ($tmp_courseid)=&get_env_multiple('form.grade_courseid');
+	my $allowed=&allowed('vgr',$tmp_courseid);
+	if (!$allowed &&
+	    exists($env{'request.course.sec'}) &&
+	    $env{'request.course.sec'} !~ /^\s*$/) {
+	    $allowed=&allowed('vgr',$tmp_courseid.
+			      '/'.$env{'request.course.sec'});
+	}
+	if ($allowed) {
+	    ($symb)=&get_env_multiple('form.grade_symb');
+	    $courseid=$tmp_courseid;
+	    ($domain)=&get_env_multiple('form.grade_domain');
+	    ($name)=&get_env_multiple('form.grade_username');
+	    return ($symb,$courseid,$domain,$name,$publicuser);
+	}
+    }
+    if (!$passedsymb) {
+	$symb=&symbread();
+    } else {
+	$symb=$passedsymb;
+    }
+    $courseid=$env{'request.course.id'};
+    $domain=$env{'user.domain'};
+    $name=$env{'user.name'};
+    if ($name eq 'public' && $domain eq 'public') {
+	if (!defined($env{'form.username'})) {
+	    $env{'form.username'}.=time.rand(10000000);
+	}
+	$name.=$env{'form.username'};
+    }
+    return ($symb,$courseid,$domain,$name,$publicuser);
+
+}
+
 # ------------------------------------------------------------ Serves up a file
 # returns either the contents of the file or 
 # -1 if the file doesn't exist
@@ -7033,6 +7112,15 @@ sub clutter {
     return $thisfn;
 }
 
+sub clutter_with_no_wrapper {
+    my $uri = &clutter(shift);
+    if ($uri =~ m-^/adm/-) {
+	$uri =~ s-^/adm/wrapper/-/-;
+	$uri =~ s-^/adm/coursedocs/showdoc/-/-;
+    }
+    return $uri;
+}
+
 sub freeze_escape {
     my ($value)=@_;
     if (ref($value)) {
@@ -7085,29 +7173,8 @@ BEGIN {
 # ----------------------------------- Read loncapa.conf and loncapa_apache.conf
     unless ($readit) {
 {
-    # FIXME: Use LONCAPA::Configuration::read_conf here and omit next block
-    open(my $config,"</etc/httpd/conf/loncapa.conf");
-
-    while (my $configline=<$config>) {
-        if ($configline=~/\S/ && $configline =~ /^[^\#]*PerlSetVar/) {
-	   my ($dummy,$varname,$varvalue)=split(/\s+/,$configline);
-           chomp($varvalue);
-           $perlvar{$varname}=$varvalue;
-        }
-    }
-    close($config);
-}
-{
-    open(my $config,"</etc/httpd/conf/loncapa_apache.conf");
-
-    while (my $configline=<$config>) {
-        if ($configline =~ /^[^\#]*PerlSetVar/) {
-	   my ($dummy,$varname,$varvalue)=split(/\s+/,$configline);
-           chomp($varvalue);
-           $perlvar{$varname}=$varvalue;
-        }
-    }
-    close($config);
+    my $configvars = LONCAPA::Configuration::read_conf('loncapa.conf');
+    %perlvar = (%perlvar,%{$configvars});
 }
 
 # ------------------------------------------------------------ Read domain file
@@ -7189,7 +7256,9 @@ sub get_iphost {
     while (my $configline=<$config>) {
        chomp($configline);
        if ($configline) {
-          $spareid{$configline}=1;
+	   my ($host,$type) = split(':',$configline,2);
+	   if (!defined($type) || $type eq '') { $type = 'default' };
+	   push(@{ $spareid{$type} }, $host);
        }
     }
     close($config);