--- loncom/interface/loncommon.pm	2005/02/17 08:29:42	1.250
+++ loncom/interface/loncommon.pm	2005/06/06 20:31:24	1.267
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.250 2005/02/17 08:29:42 albertel Exp $
+# $Id: loncommon.pm,v 1.267 2005/06/06 20:31:24 www Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -55,7 +55,7 @@ redundancy from other modules and increa
 package Apache::loncommon;
 
 use strict;
-use Apache::lonnet();
+use Apache::lonnet;
 use GDBM_File;
 use POSIX qw(strftime mktime);
 use Apache::Constants qw(:common :http :methods);
@@ -311,8 +311,8 @@ END
 }
 
 sub lastresurl {
-    if ($ENV{'environment.lastresurl'}) {
-	return $ENV{'environment.lastresurl'}
+    if ($env{'environment.lastresurl'}) {
+	return $env{'environment.lastresurl'}
     } else {
 	return '/res';
     }
@@ -329,9 +329,9 @@ sub storeresurl {
 
 sub studentbrowser_javascript {
    unless (
-            (($ENV{'request.course.id'}) && 
-             (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})))
-         || ($ENV{'request.role'}=~/^(au|dc|su)/)
+            (($env{'request.course.id'}) && 
+             (&Apache::lonnet::allowed('srm',$env{'request.course.id'})))
+         || ($env{'request.role'}=~/^(au|dc|su)/)
           ) { return ''; }  
    return (<<'ENDSTDBRW');
 <script type="text/javascript" language="Javascript" >
@@ -360,14 +360,14 @@ ENDSTDBRW
 
 sub selectstudent_link {
    my ($form,$unameele,$udomele)=@_;
-   if ($ENV{'request.course.id'}) {  
-       unless (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) {
+   if ($env{'request.course.id'}) {  
+       unless (&Apache::lonnet::allowed('srm',$env{'request.course.id'})) {
 	   return '';
        }
        return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele.
         '","'.$udomele.'");'."'>".&mt('Select User')."</a>";
    }
-   if ($ENV{'request.role'}=~/^(au|dc|su)/) {
+   if ($env{'request.role'}=~/^(au|dc|su)/) {
        return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele.
         '","'.$udomele.'",1);'."'>".&mt('Select User')."</a>";
    }
@@ -547,7 +547,7 @@ END
     $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
     foreach my $value (sort(keys(%$hashref))) {
         $result.="    <option value=\"$value\" ";
-        $result.=" selected=\"true\" " if ($value eq $firstdefault);
+        $result.=" selected=\"selected\" " if ($value eq $firstdefault);
         $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
     }
     $result .= "</select>\n";
@@ -557,7 +557,7 @@ END
     my $seconddefault = $hashref->{$firstdefault}->{'default'};
     foreach my $value (sort(keys(%select2))) {
         $result.="    <option value=\"$value\" ";        
-        $result.=" selected=\"true\" " if ($value eq $seconddefault);
+        $result.=" selected=\"selected\" " if ($value eq $seconddefault);
         $result.=">".&mt($select2{$value})."</option>\n";
     }
     $result .= "</select>\n";
@@ -593,8 +593,8 @@ sub help_open_topic {
     my ($topic, $text, $stayOnPage, $width, $height) = @_;
     $text = "" if (not defined $text);
     $stayOnPage = 0 if (not defined $stayOnPage);
-    if ($ENV{'browser.interface'} eq 'textual' ||
-	$ENV{'environment.remote'} eq 'off' ) {
+    if ($env{'browser.interface'} eq 'textual' ||
+	$env{'environment.remote'} eq 'off' ) {
 	$stayOnPage=1;
     }
     $width = 350 if (not defined $width);
@@ -659,8 +659,8 @@ sub help_open_menu {
     my ($color,$topic,$component_help,$function,$faq,$bug,$stayOnPage,$width,$height,$text) = @_;
     $text = "" if (not defined $text);
     $stayOnPage = 0 if (not defined $stayOnPage);
-    if ($ENV{'browser.interface'} eq 'textual' ||
-        $ENV{'environment.remote'} eq 'off' ) {
+    if ($env{'browser.interface'} eq 'textual' ||
+        $env{'environment.remote'} eq 'off' ) {
         $stayOnPage=1;
     }
     $width = 620 if (not defined $width);
@@ -673,7 +673,6 @@ sub help_open_menu {
     foreach (\$color,\$function,\$topic,\$component_help,\$faq,\$bug,\$origurl) {
         $$_ = &Apache::lonnet::escape($$_);
     }
-
     if (!$stayOnPage) {
          $link = "javascript:helpMenu('open')";
     } else {
@@ -684,20 +683,22 @@ sub help_open_menu {
     my $template;
     if ($text ne "") {
 	$template .= 
-  "<table bgcolor='#773311' cellspacing='1' cellpadding='1' border='0'><tr>".
-  "<td bgcolor='#886622'><a href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>";
+  "<table bgcolor='#CC3300' cellspacing='1' cellpadding='1' border='0'><tr>".
+  "<td bgcolor='#CC6600'><a href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>";
     }
+    my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
     my $html=&Apache::lonxml::xmlbegin();
     my $helpicon=&lonhttpdurl("/adm/lonIcons/helpgateway.gif");
     $template .= <<"ENDTEMPLATE";
  <script type="text/javascript">
-//<!-- BEGIN LON-CAPA Internal
+// <!-- BEGIN LON-CAPA Internal
+// <![CDATA[
 function helpMenu(target) {
     var caller = this;
     if (target == 'open') {
         var newWindow = null;
         try {
-            newWindow =  window.open("/adm/rat/empty.html","helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" )
+            newWindow =  window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" )
         }
         catch(error) {
             writeHelp(caller);
@@ -711,12 +712,13 @@ function helpMenu(target) {
     return;
 }
 function writeHelp(caller) {
-    caller.document.write('$html<head><title>LON-CAPA Help Menu</title><meta http-equiv="pragma" content="no-cache"></head>')
-    caller.document.write("<frameset rows='105,*' border='0'><frame name='bannerframe'  src='$banner_link'><frame name='bodyframe' src='$details_link'></frameset>")
-    caller.document.write("</html>")
+    caller.document.writeln('$html<head><title>LON-CAPA Help Menu</title><meta http-equiv="pragma" content="no-cache"></head>')
+    caller.document.writeln("<frameset rows='105,*' border='0'><frame name='bannerframe'  src='$banner_link'><frame name='bodyframe' src='$details_link'></frameset>")
+    caller.document.writeln("</html>")
     caller.document.close()
     caller.focus()
 }
+// ]]>
 // END LON-CAPA Internal -->
  </script>
  <a href="$link" title="$title"><img src="$helpicon" border="0" alt="(Help Menu)" /></a>
@@ -740,12 +742,12 @@ ENDTEMPLATE
 
 sub help_open_bug {
     my ($topic, $text, $stayOnPage, $width, $height) = @_;
-    unless ($ENV{'user.adv'}) { return ''; }
+    unless ($env{'user.adv'}) { return ''; }
     unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
     $text = "" if (not defined $text);
     $stayOnPage = 0 if (not defined $stayOnPage);
-    if ($ENV{'browser.interface'} eq 'textual' ||
-	$ENV{'environment.remote'} eq 'off' ) {
+    if ($env{'browser.interface'} eq 'textual' ||
+	$env{'environment.remote'} eq 'off' ) {
 	$stayOnPage=1;
     }
     $width = 600 if (not defined $width);
@@ -785,12 +787,12 @@ ENDTEMPLATE
 
 sub help_open_faq {
     my ($topic, $text, $stayOnPage, $width, $height) = @_;
-    unless ($ENV{'user.adv'}) { return ''; }
+    unless ($env{'user.adv'}) { return ''; }
     unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
     $text = "" if (not defined $text);
     $stayOnPage = 0 if (not defined $stayOnPage);
-    if ($ENV{'browser.interface'} eq 'textual' ||
-	$ENV{'environment.remote'} eq 'off' ) {
+    if ($env{'browser.interface'} eq 'textual' ||
+	$env{'environment.remote'} eq 'off' ) {
 	$stayOnPage=1;
     }
     $width = 350 if (not defined $width);
@@ -833,6 +835,98 @@ ENDTEMPLATE
 
 =pod
 
+=item * change_content_javascript():
+
+This and the next function allow you to create small sections of an
+otherwise static HTML page that you can update on the fly with
+Javascript, even in Netscape 4.
+
+The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
+must be written to the HTML page once. It will prove the Javascript
+function "change(name, content)". Calling the change function with the
+name of the section 
+you want to update, matching the name passed to C<changable_area>, and
+the new content you want to put in there, will put the content into
+that area.
+
+B<Note>: Netscape 4 only reserves enough space for the changable area
+to contain room for the original contents. You need to "make space"
+for whatever changes you wish to make, and be B<sure> to check your
+code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
+it's adequate for updating a one-line status display, but little more.
+This script will set the space to 100% width, so you only need to
+worry about height in Netscape 4.
+
+Modern browsers are much less limiting, and if you can commit to the
+user not using Netscape 4, this feature may be used freely with
+pretty much any HTML.
+
+=cut
+
+sub change_content_javascript {
+    # If we're on Netscape 4, we need to use Layer-based code
+    if ($env{'browser.type'} eq 'netscape' &&
+	$env{'browser.version'} =~ /^4\./) {
+	return (<<NETSCAPE4);
+	function change(name, content) {
+	    doc = document.layers[name+"___escape"].layers[0].document;
+	    doc.open();
+	    doc.write(content);
+	    doc.close();
+	}
+NETSCAPE4
+    } else {
+	# Otherwise, we need to use semi-standards-compliant code
+	# (technically, "innerHTML" isn't standard but the equivalent
+	# is really scary, and every useful browser supports it
+	return (<<DOMBASED);
+	function change(name, content) {
+	    element = document.getElementById(name);
+	    element.innerHTML = content;
+	}
+DOMBASED
+    }
+}
+
+=pod
+
+=item * changable_area($name, $origContent):
+
+This provides a "changable area" that can be modified on the fly via
+the Javascript code provided in C<change_content_javascript>. $name is
+the name you will use to reference the area later; do not repeat the
+same name on a given HTML page more then once. $origContent is what
+the area will originally contain, which can be left blank.
+
+=cut
+
+sub changable_area {
+    my ($name, $origContent) = @_;
+
+    if ($env{'browser.type'} eq 'netscape' &&
+	$env{'browser.version'} =~ /^4\./) {
+	# If this is netscape 4, we need to use the Layer tag
+	return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
+    } else {
+	return "<span id='$name'>$origContent</span>";
+    }
+}
+
+=pod
+
+=back
+
+=head1 Excel and CSV file utility routines
+
+=over 4
+
+=cut
+
+###############################################################
+###############################################################
+
+=pod
+
 =item * csv_translate($text) 
 
 Translate $text to allow it to be output as a 'comma separated values' 
@@ -849,7 +943,6 @@ sub csv_translate {
     return $text;
 }
 
-
 ###############################################################
 ###############################################################
 
@@ -873,6 +966,10 @@ Currently supported formats:
 
 =item h3
 
+=item h4
+
+=item i
+
 =item date
 
 =back
@@ -895,6 +992,7 @@ sub define_excel_formats {
     $format->{'h1'}   = $workbook->add_format(bold=>1, size=>18);
     $format->{'h2'}   = $workbook->add_format(bold=>1, size=>16);
     $format->{'h3'}   = $workbook->add_format(bold=>1, size=>14);
+    $format->{'h4'}   = $workbook->add_format(bold=>1, size=>12);
     $format->{'i'}    = $workbook->add_format(italic=>1);
     $format->{'date'} = $workbook->add_format(num_format=>
                                             'mm/dd/yyyy hh:mm:ss');
@@ -906,84 +1004,83 @@ sub define_excel_formats {
 
 =pod
 
-=item * change_content_javascript():
-
-This and the next function allow you to create small sections of an
-otherwise static HTML page that you can update on the fly with
-Javascript, even in Netscape 4.
+=item * create_workbook
 
-The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
-must be written to the HTML page once. It will prove the Javascript
-function "change(name, content)". Calling the change function with the
-name of the section 
-you want to update, matching the name passed to C<changable_area>, and
-the new content you want to put in there, will put the content into
-that area.
+Create an Excel worksheet.  If it fails, output message on the
+request object and return undefs.
 
-B<Note>: Netscape 4 only reserves enough space for the changable area
-to contain room for the original contents. You need to "make space"
-for whatever changes you wish to make, and be B<sure> to check your
-code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
-it's adequate for updating a one-line status display, but little more.
-This script will set the space to 100% width, so you only need to
-worry about height in Netscape 4.
+Inputs: Apache request object
 
-Modern browsers are much less limiting, and if you can commit to the
-user not using Netscape 4, this feature may be used freely with
-pretty much any HTML.
+Returns (undef) on failure, 
+    Excel worksheet object, scalar with filename, and formats 
+    from &Apache::loncommon::define_excel_formats on success
 
 =cut
 
-sub change_content_javascript {
-    # If we're on Netscape 4, we need to use Layer-based code
-    if ($ENV{'browser.type'} eq 'netscape' &&
-	$ENV{'browser.version'} =~ /^4\./) {
-	return (<<NETSCAPE4);
-	function change(name, content) {
-	    doc = document.layers[name+"___escape"].layers[0].document;
-	    doc.open();
-	    doc.write(content);
-	    doc.close();
-	}
-NETSCAPE4
-    } else {
-	# Otherwise, we need to use semi-standards-compliant code
-	# (technically, "innerHTML" isn't standard but the equivalent
-	# is really scary, and every useful browser supports it
-	return (<<DOMBASED);
-	function change(name, content) {
-	    element = document.getElementById(name);
-	    element.innerHTML = content;
-	}
-DOMBASED
+###############################################################
+###############################################################
+sub create_workbook {
+    my ($r) = @_;
+        #
+    # Create the excel spreadsheet
+    my $filename = '/prtspool/'.
+        $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
+        time.'_'.rand(1000000000).'.xls';
+    my $workbook  = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
+    if (! defined($workbook)) {
+        $r->log_error("Error creating excel spreadsheet $filename: $!");
+        $r->print('<p>'.&mt("Unable to create new Excel file.  ".
+                            "This error has been logged.  ".
+                            "Please alert your LON-CAPA administrator").
+                  '</p>');
+        return (undef);
     }
+    #
+    $workbook->set_tempdir('/home/httpd/perl/tmp');
+    #
+    my $format = &Apache::loncommon::define_excel_formats($workbook);
+    return ($workbook,$filename,$format);
 }
 
+###############################################################
+###############################################################
+
 =pod
 
-=item * changable_area($name, $origContent):
+=item * create_text_file
 
-This provides a "changable area" that can be modified on the fly via
-the Javascript code provided in C<change_content_javascript>. $name is
-the name you will use to reference the area later; do not repeat the
-same name on a given HTML page more then once. $origContent is what
-the area will originally contain, which can be left blank.
+Create a file to write to and eventually make available to the usre.
+If file creation fails, outputs an error message on the request object and 
+return undefs.
 
-=cut
+Inputs: Apache request object, and file suffix
 
-sub changable_area {
-    my ($name, $origContent) = @_;
+Returns (undef) on failure, 
+    Filehandle and filename on success.
 
-    if ($ENV{'browser.type'} eq 'netscape' &&
-	$ENV{'browser.version'} =~ /^4\./) {
-	# If this is netscape 4, we need to use the Layer tag
-	return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
-    } else {
-	return "<span id='$name'>$origContent</span>";
+=cut
+
+###############################################################
+###############################################################
+sub create_text_file {
+    my ($r,$suffix) = @_;
+    if (! defined($suffix)) { $suffix = 'txt'; };
+    my $fh;
+    my $filename = '/prtspool/'.
+        $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
+        time.'_'.rand(1000000000).'.'.$suffix;
+    $fh = Apache::File->new('>/home/httpd'.$filename);
+    if (! defined($fh)) {
+        $r->log_error("Couldn't open $filename for output $!");
+        $r->print("Problems occured in creating the output file.  ".
+                  "This error has been logged.  ".
+                  "Please alert your LON-CAPA administrator.");
     }
+    return ($fh,$filename)
 }
 
-=pod
+
+=pod 
 
 =back
 
@@ -1045,7 +1142,7 @@ sub multiple_select_form {
     $output.="\n<select name='$name' size='$size' multiple='1'>";
     foreach (sort(keys(%hash))) {
         $output.='<option value="'.$_.'" ';
-        $output.='selected ' if ($selected{$_});
+        $output.='selected="selected" ' if ($selected{$_});
         $output.='>'.$hash{$_}."</option>\n";
     }
     $output.="</select>\n";
@@ -1076,7 +1173,7 @@ sub select_form {
     }
     foreach (@keys) {
         $selectform.="<option value=\"$_\" ".
-            ($_ eq $def ? 'selected' : '').
+            ($_ eq $def ? 'selected="selected" ' : '').
                 ">".&mt($hash{$_})."</option>\n";
     }
     $selectform.="</select>";
@@ -1113,7 +1210,7 @@ sub select_level_form {
     my $selectform = "<select name=\"$name\" size=\"1\">\n";
     for (my $i=0; $i<=18; $i++) {
         $selectform.="<option value=\"$i\" ".
-            ($i==$deflevel ? 'selected' : '').
+            ($i==$deflevel ? 'selected="selected" ' : '').
                 ">".&gradeleveldescription($i)."</option>\n";
     }
     $selectform.="</select>";
@@ -1143,7 +1240,7 @@ sub select_dom_form {
     my $selectdomain = "<select name=\"$name\" size=\"1\">\n";
     foreach (@domains) {
         $selectdomain.="<option value=\"$_\" ".
-            ($_ eq $defdom ? 'selected="selected"' : '').
+            ($_ eq $defdom ? 'selected="selected" ' : '').
                 ">$_</option>\n";
     }
     $selectdomain.="</select>";
@@ -1807,13 +1904,13 @@ if the user does not
 sub nickname {
     my ($uname,$udom)=@_;
     my %names;
-    if ($uname eq $ENV{'user.name'} &&
-	$udom eq $ENV{'user.domain'}) {
-	%names=('nickname'   => $ENV{'environment.nickname'}  ,
-		'firstname'  => $ENV{'environment.firstname'} ,
-		'middlename' => $ENV{'environment.middlename'},
-		'lastname'   => $ENV{'environment.lastname'}  ,
-		'generation' => $ENV{'environment.generation'});
+    if ($uname eq $env{'user.name'} &&
+	$udom eq $env{'user.domain'}) {
+	%names=('nickname'   => $env{'environment.nickname'}  ,
+		'firstname'  => $env{'environment.firstname'} ,
+		'middlename' => $env{'environment.middlename'},
+		'lastname'   => $env{'environment.lastname'}  ,
+		'generation' => $env{'environment.generation'});
     } else {
 	%names=&Apache::lonnet::get('environment',
 				    ['nickname','firstname','middlename',
@@ -1844,8 +1941,8 @@ Gets a users screenname and returns it a
 
 sub screenname {
     my ($uname,$udom)=@_;
-    if ($uname eq $ENV{'user.name'} &&
-	$udom eq $ENV{'user.domain'}) {return $ENV{'environment.screenname'};}
+    if ($uname eq $env{'user.name'} &&
+	$udom eq $env{'user.domain'}) {return $env{'environment.screenname'};}
     my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname);
     return $names{'screenname'};
 }
@@ -1903,8 +2000,6 @@ sub track_student_link {
     return qq{<a href="$link" title="$title" $target>$linktext</a>};
 }
 
-
-
 =pod
 
 =back
@@ -2093,8 +2188,8 @@ sub display_languages {
 	$languages{$_}=1;
     }
     &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
-    if ($ENV{'form.displaylanguage'}) {
-	foreach (split(/\s*(\,|\;|\:)\s*/,$ENV{'form.displaylanguage'})) {
+    if ($env{'form.displaylanguage'}) {
+	foreach (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) {
 	    $languages{$_}=1;
         }
     }
@@ -2103,24 +2198,24 @@ sub display_languages {
 
 sub preferred_languages {
     my @languages=();
-    if ($ENV{'course.'.$ENV{'request.course.id'}.'.languages'}) {
+    if ($env{'course.'.$env{'request.course.id'}.'.languages'}) {
 	@languages=(@languages,split(/\s*(\,|\;|\:)\s*/,
-	         $ENV{'course.'.$ENV{'request.course.id'}.'.languages'}));
+	         $env{'course.'.$env{'request.course.id'}.'.languages'}));
     }
-    if ($ENV{'environment.languages'}) {
-	@languages=split(/\s*(\,|\;|\:)\s*/,$ENV{'environment.languages'});
+    if ($env{'environment.languages'}) {
+	@languages=split(/\s*(\,|\;|\:)\s*/,$env{'environment.languages'});
     }
     my $browser=(split(/\;/,$ENV{'HTTP_ACCEPT_LANGUAGE'}))[0];
     if ($browser) {
 	@languages=(@languages,split(/\s*(\,|\;|\:)\s*/,$browser));
     }
-    if ($Apache::lonnet::domain_lang_def{$ENV{'user.domain'}}) {
+    if ($Apache::lonnet::domain_lang_def{$env{'user.domain'}}) {
 	@languages=(@languages,
-		$Apache::lonnet::domain_lang_def{$ENV{'user.domain'}});
+		$Apache::lonnet::domain_lang_def{$env{'user.domain'}});
     }
-    if ($Apache::lonnet::domain_lang_def{$ENV{'request.role.domain'}}) {
+    if ($Apache::lonnet::domain_lang_def{$env{'request.role.domain'}}) {
 	@languages=(@languages,
-		$Apache::lonnet::domain_lang_def{$ENV{'request.role.domain'}});
+		$Apache::lonnet::domain_lang_def{$env{'request.role.domain'}});
     }
     if ($Apache::lonnet::domain_lang_def{
 	                          $Apache::lonnet::perlvar{'lonDefDomain'}}) {
@@ -2353,7 +2448,7 @@ sub submlink {
 	    &Apache::lonxml::whichuser($symb);
 	if (!$symb) { $symb=$cursymb; }
     }
-    if (!$symb) { $symb=&symbread(); }
+    if (!$symb) { $symb=&Apache::lonnet::symbread(); }
     $symb=&Apache::lonnet::escape($symb);
     if ($target) { $target="target=\"$target\""; }
     return '<a href="/adm/grades?&command=submission&'.
@@ -2399,7 +2494,7 @@ sub pprmlink {
 	    &Apache::lonxml::whichuser($symb);
 	if (!$symb) { $symb=$cursymb; }
     }
-    if (!$symb) { $symb=&symbread(); }
+    if (!$symb) { $symb=&Apache::lonnet::symbread(); }
     $symb=&Apache::lonnet::escape($symb);
     if ($target) { $target="target=\"$target\""; }
     return '<a href="/adm/parmset?&command=set&'.
@@ -2442,9 +2537,9 @@ sub maketime {
 sub findallcourses {
     my %courses=();
     my $now=time;
-    foreach (keys %ENV) {
+    foreach (keys %env) {
 	if ($_=~/^user\.role\.\w+\.\/(\w+)\/(\w+)/) {
-	    my ($starttime,$endtime)=$ENV{$_};
+	    my ($starttime,$endtime)=$env{$_};
             my $active=1;
             if ($starttime) {
 		if ($now<$starttime) { $active=0; }
@@ -2481,9 +2576,9 @@ sub determinedomain {
    if (! $domain) {
         # Determine domain if we have not been given one
         $domain = $Apache::lonnet::perlvar{'lonDefDomain'};
-        if ($ENV{'user.domain'}) { $domain=$ENV{'user.domain'}; }
-        if ($ENV{'request.role.domain'}) { 
-            $domain=$ENV{'request.role.domain'}; 
+        if ($env{'user.domain'}) { $domain=$env{'user.domain'}; }
+        if ($env{'request.role.domain'}) { 
+            $domain=$env{'request.role.domain'}; 
         }
     }
     return $domain;
@@ -2528,7 +2623,7 @@ Returns: value of designparamter $which
 ##############################################
 sub designparm {
     my ($which,$domain)=@_;
-    if ($ENV{'browser.blackwhite'} eq 'on') {
+    if ($env{'browser.blackwhite'} eq 'on') {
 	if ($which=~/\.(font|alink|vlink|link)$/) {
 	    return '#000000';
 	}
@@ -2539,8 +2634,8 @@ sub designparm {
 	    return '#CCCCCC';
 	}
     }
-    if ($ENV{'environment.color.'.$which}) {
-	return $ENV{'environment.color.'.$which};
+    if ($env{'environment.color.'.$which}) {
+	return $env{'environment.color.'.$which};
     }
     $domain=&determinedomain($domain);
     if ($designhash{$domain.'.'.$which}) {
@@ -2606,16 +2701,16 @@ sub bodytag {
 # Accessibility font enhance
     unless ($addentries) { $addentries=''; }
     my $addstyle='';
-    if ($ENV{'browser.fontenhance'} eq 'on') {
+    if ($env{'browser.fontenhance'} eq 'on') {
 	$addstyle=' font-size: x-large;';
     }
  # role and realm
     my ($role,$realm)
-       =&Apache::lonnet::plaintext((split(/\./,$ENV{'request.role'}))[0]);
+       =&Apache::lonnet::plaintext((split(/\./,$env{'request.role'}))[0]);
 # realm
-    if ($ENV{'request.course.id'}) {
+    if ($env{'request.course.id'}) {
 	$realm=
-         $ENV{'course.'.$ENV{'request.course.id'}.'.description'};
+         $env{'course.'.$env{'request.course.id'}.'.description'};
     }
     unless ($realm) { $realm='&nbsp;'; }
 # Set messages
@@ -2632,25 +2727,32 @@ a:focus { color: red; background: yellow
 <body bgcolor="$pgbg" text="$font" alink="$alink" vlink="$vlink" link="$link"
 style="margin-top: 0px;$addstyle" $addentries>
 END
+    if ($env{'environment.texengine'} eq 'jsMath') {
+	$bodytag.='<script type="text/javascript">
+                     function NoFontMessage () {}
+                   </script>'."\n".
+	    '<script src="/adm/jsMath/jsMath.js"></script>'."\n";
+    }
+
     my $upperleft='<img src="http://'.$ENV{'HTTP_HOST'}.':'.
                    $lonhttpdPort.$img.'" alt="'.$function.'" />';
     if ($bodyonly) {
         return $bodytag;
-    } elsif ($ENV{'browser.interface'} eq 'textual') {
+    } elsif ($env{'browser.interface'} eq 'textual') {
 # Accessibility
           
         return $bodytag.&Apache::lonmenu::menubuttons($forcereg,'web',
                                                       $forcereg).
                '<h1>LON-CAPA: '.$title.'</h1>';
-    } elsif ($ENV{'environment.remote'} eq 'off') {
+    } elsif ($env{'environment.remote'} eq 'off') {
 # No Remote
 	my $roleinfo=(<<ENDROLE);
 <td bgcolor="$tabbg" align="right">
 <font size="2" face="Arial, Helvetica, sans-serif">
-    $ENV{'environment.firstname'}
-    $ENV{'environment.middlename'}
-    $ENV{'environment.lastname'}
-    $ENV{'environment.generation'}
+    $env{'environment.firstname'}
+    $env{'environment.middlename'}
+    $env{'environment.lastname'}
+    $env{'environment.generation'}
     </font>&nbsp;
 <br />
 <font size="2" face="Arial, Helvetica, sans-serif">$role</font>&nbsp;
@@ -2664,9 +2766,9 @@ ENDROLE
             $titleinfo = $customtitle;
         }
 
-	if ($ENV{'request.state'} eq 'construct') {
+	if ($env{'request.state'} eq 'construct') {
 	    my ($uname,$thisdisfn)=
-		($ENV{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|);
+		($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|);
 	    my $formaction='/priv/'.$uname.'/'.$thisdisfn;
 	    $formaction=~s/\/+/\//g;
             unless ($customtitle) {  #this is for resources; directories have customtitle, and crumbs and select recent are created in lonpubdir.pm  
@@ -2694,7 +2796,7 @@ ENDROLE
                          'cellspacing="3" cellpadding="3">'.
                          '<tr><td rowspan="3" bgcolor="'.$tabbg.'">'.
                          $titleinfo.'</td>'.$roleinfo.'</tr></table>';
-        if ($ENV{'request.state'} eq 'construct') {
+        if ($env{'request.state'} eq 'construct') {
             $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg,$titletable);
 	} else {
             $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg).
@@ -2713,11 +2815,11 @@ ENDROLE
     #
     # Extra info if you are the DC
     my $dc_info = '';
-    if ($ENV{'user.adv'} && exists($ENV{'user.role.dc./'.
-                        $ENV{'course.'.$ENV{'request.course.id'}.
+    if ($env{'user.adv'} && exists($env{'user.role.dc./'.
+                        $env{'course.'.$env{'request.course.id'}.
                                  '.domain'}.'/'})) {
-        my $cid = $ENV{'request.course.id'};
-        $dc_info.= $cid.' '.$ENV{'course.'.$cid.'.internal.coursecode'};
+        my $cid = $env{'request.course.id'};
+        $dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
         $dc_info = '('.$dc_info.')';
     }
     #
@@ -2731,12 +2833,12 @@ $upperleft</td>
 <tr>
 <td rowspan="3" bgcolor="$tabbg">
 $titleinfo $dc_info
-<td bgcolor="$tabbg" align="right">
+</td><td bgcolor="$tabbg" align="right">
 <font size="2" face="Arial, Helvetica, sans-serif">
-    $ENV{'environment.firstname'}
-    $ENV{'environment.middlename'}
-    $ENV{'environment.lastname'}
-    $ENV{'environment.generation'}
+    $env{'environment.firstname'}
+    $env{'environment.middlename'}
+    $env{'environment.lastname'}
+    $env{'environment.generation'}
     </font>&nbsp;
 </td>
 </tr>
@@ -2750,6 +2852,40 @@ ENDBODY
 }
 
 ###############################################
+###############################################
+
+=pod
+
+=back
+
+=head1 HTTP Helpers
+
+=over 4
+
+=item * &endbodytag()
+
+Returns a uniform footer for LON-CAPA web pages.
+
+Inputs: 
+
+=over 4
+
+=back
+
+Returns: A uniform footer for LON-CAPA web pages.  
+
+=cut
+
+sub endbodytag {
+    my $endbodytag='</body>';
+    if ($env{'environment.texengine'} eq 'jsMath') {
+	$endbodytag='<script type="text/javascript">jsMath.Process()</script>'.
+	    "\n".$endbodytag;
+    }
+    return $endbodytag;
+}
+
+###############################################
 
 =pod
 
@@ -2763,13 +2899,13 @@ Returns either 'student','coordinator','
 ###############################################
 sub get_users_function {
     my $function = 'student';
-    if ($ENV{'request.role'}=~/^(cc|in|ta|ep)/) {
+    if ($env{'request.role'}=~/^(cc|in|ta|ep)/) {
         $function='coordinator';
     }
-    if ($ENV{'request.role'}=~/^(su|dc|ad|li)/) {
+    if ($env{'request.role'}=~/^(su|dc|ad|li)/) {
         $function='admin';
     }
-    if (($ENV{'request.role'}=~/^(au|ca)/) ||
+    if (($env{'request.role'}=~/^(au|ca)/) ||
         ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) {
         $function='author';
     }
@@ -2837,8 +2973,9 @@ sub get_posted_cgi {
     my $r=shift;
 
     my $buffer;
-    
-    $r->read($buffer,$r->header_in('Content-length'),0);
+    if ($r->header_in('Content-length')) {
+	$r->read($buffer,$r->header_in('Content-length'),0);
+    }
     unless ($buffer=~/^(\-+\w+)\s+Content\-Disposition\:\s*form\-data/si) {
 	my @pairs=split(/&/,$buffer);
 	my $pair;
@@ -2863,8 +3000,8 @@ sub get_posted_cgi {
 		if ($name) {
 		    chomp($value);
 		    if ($fname) {
-			$ENV{"form.$name.filename"}=$fname;
-			$ENV{"form.$name.mimetype"}=$fmime;
+			$env{"form.$name.filename"}=$fname;
+			$env{"form.$name.mimetype"}=$fmime;
 		    } else {
 			$value=~s/\s+$//s;
 		    }
@@ -2896,7 +3033,7 @@ sub get_posted_cgi {
 	    }
 	}
     }
-    $ENV{'request.method'}=$ENV{'REQUEST_METHOD'};
+    $env{'request.method'}=$ENV{'REQUEST_METHOD'};
     $r->method_number(M_GET);
     $r->method('GET');
     $r->headers_in->unset('Content-length');
@@ -2906,14 +3043,14 @@ sub get_posted_cgi {
 
 =item * get_unprocessed_cgi($query,$possible_names)
 
-Modify the %ENV hash to contain unprocessed CGI form parameters held in
+Modify the %env hash to contain unprocessed CGI form parameters held in
 $query.  The parameters listed in $possible_names (an array reference),
-will be set in $ENV{'form.name'} if they do not already exist.
+will be set in $env{'form.name'} if they do not already exist.
 
 Typically called with $ENV{'QUERY_STRING'} as the first parameter.  
 $possible_names is an ref to an array of form element names.  As an example:
 get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
-will result in $ENV{'form.uname'} and $ENV{'form.udom'} being set.
+will result in $env{'form.uname'} and $env{'form.udom'} being set.
 
 =cut
 
@@ -2927,7 +3064,7 @@ sub get_unprocessed_cgi {
       $value =~ tr/+/ /;
       $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
       &Apache::lonxml::debug("Seting :$name: to :$value:");
-      unless (defined($ENV{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
+      unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
     }
   }
 }
@@ -2941,7 +3078,7 @@ returns cache-controlling header code
 =cut
 
 sub cacheheader {
-    unless ($ENV{'request.method'} eq 'GET') { return ''; }
+    unless ($env{'request.method'} eq 'GET') { return ''; }
     my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
     my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
                 <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
@@ -2960,7 +3097,7 @@ specifies header code to not have cache
 sub no_cache {
     my ($r) = @_;
     if ($ENV{'REQUEST_METHOD'} ne 'GET' &&
-	$ENV{'request.method'} ne 'GET') { return ''; }
+	$env{'request.method'} ne 'GET') { return ''; }
     my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime(time));
     $r->no_cache(1);
     $r->header_out("Expires" => $date);
@@ -2969,6 +3106,7 @@ sub no_cache {
 
 sub content_type {
     my ($r,$type,$charset) = @_;
+    if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; }
     unless ($charset) {
 	$charset=&Apache::lonlocal::current_encoding;
     }
@@ -2984,7 +3122,7 @@ sub content_type {
 
 =item * add_to_env($name,$value) 
 
-adds $name to the %ENV hash with value
+adds $name to the %env hash with value
 $value, if $name already exists, the entry is converted to an array
 reference and $value is added to the array.
 
@@ -2992,18 +3130,18 @@ reference and $value is added to the arr
 
 sub add_to_env {
   my ($name,$value)=@_;
-  if (defined($ENV{$name})) {
-    if (ref($ENV{$name})) {
+  if (defined($env{$name})) {
+    if (ref($env{$name})) {
       #already have multiple values
-      push(@{ $ENV{$name} },$value);
+      push(@{ $env{$name} },$value);
     } else {
       #first time seeing multiple values, convert hash entry to an arrayref
-      my $first=$ENV{$name};
-      undef($ENV{$name});
-      push(@{ $ENV{$name} },$first,$value);
+      my $first=$env{$name};
+      undef($env{$name});
+      push(@{ $env{$name} },$first,$value);
     }
   } else {
-    $ENV{$name}=$value;
+    $env{$name}=$value;
   }
 }
 
@@ -3011,7 +3149,7 @@ sub add_to_env {
 
 =item * get_env_multiple($name) 
 
-gets $name from the %ENV hash, it seemlessly handles the cases where multiple
+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
@@ -3021,12 +3159,12 @@ returns an array of values
 sub get_env_multiple {
     my ($name) = @_;
     my @values;
-    if (defined($ENV{$name})) {
+    if (defined($env{$name})) {
         # exists is it an array
-        if (ref($ENV{$name})) {
-            @values=@{ $ENV{$name} };
+        if (ref($env{$name})) {
+            @values=@{ $env{$name} };
         } else {
-            $values[0]=$ENV{$name};
+            $values[0]=$env{$name};
         }
     }
     return(@values);
@@ -3044,25 +3182,25 @@ sub get_env_multiple {
 =item * upfile_store($r)
 
 Store uploaded file, $r should be the HTTP Request object,
-needs $ENV{'form.upfile'}
+needs $env{'form.upfile'}
 returns $datatoken to be put into hidden field
 
 =cut
 
 sub upfile_store {
     my $r=shift;
-    $ENV{'form.upfile'}=~s/\r/\n/gs;
-    $ENV{'form.upfile'}=~s/\f/\n/gs;
-    $ENV{'form.upfile'}=~s/\n+/\n/gs;
-    $ENV{'form.upfile'}=~s/\n+$//gs;
+    $env{'form.upfile'}=~s/\r/\n/gs;
+    $env{'form.upfile'}=~s/\f/\n/gs;
+    $env{'form.upfile'}=~s/\n+/\n/gs;
+    $env{'form.upfile'}=~s/\n+$//gs;
 
-    my $datatoken=$ENV{'user.name'}.'_'.$ENV{'user.domain'}.
-	'_enroll_'.$ENV{'request.course.id'}.'_'.time.'_'.$$;
+    my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}.
+	'_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$;
     {
         my $datafile = $r->dir_config('lonDaemons').
                            '/tmp/'.$datatoken.'.tmp';
         if ( open(my $fh,">$datafile") ) {
-            print $fh $ENV{'form.upfile'};
+            print $fh $env{'form.upfile'};
             close($fh);
         }
     }
@@ -3074,8 +3212,8 @@ sub upfile_store {
 =item * load_tmp_file($r)
 
 Load uploaded file from tmp, $r should be the HTTP Request object,
-needs $ENV{'form.datatoken'},
-sets $ENV{'form.upfile'} to the contents of the file
+needs $env{'form.datatoken'},
+sets $env{'form.upfile'} to the contents of the file
 
 =cut
 
@@ -3084,13 +3222,13 @@ sub load_tmp_file {
     my @studentdata=();
     {
         my $studentfile = $r->dir_config('lonDaemons').
-                              '/tmp/'.$ENV{'form.datatoken'}.'.tmp';
+                              '/tmp/'.$env{'form.datatoken'}.'.tmp';
         if ( open(my $fh,"<$studentfile") ) {
             @studentdata=<$fh>;
             close($fh);
         }
     }
-    $ENV{'form.upfile'}=join('',@studentdata);
+    $env{'form.upfile'}=join('',@studentdata);
 }
 
 =pod
@@ -3099,15 +3237,15 @@ sub load_tmp_file {
 
 Separate uploaded file into records
 returns array of records,
-needs $ENV{'form.upfile'} and $ENV{'form.upfiletype'}
+needs $env{'form.upfile'} and $env{'form.upfiletype'}
 
 =cut
 
 sub upfile_record_sep {
-    if ($ENV{'form.upfiletype'} eq 'xml') {
+    if ($env{'form.upfiletype'} eq 'xml') {
     } else {
 	my @records;
-	foreach my $line (split(/\n/,$ENV{'form.upfile'})) {
+	foreach my $line (split(/\n/,$env{'form.upfile'})) {
 	    if ($line=~/^\s*$/) { next; }
 	    push(@records,$line);
 	}
@@ -3119,30 +3257,35 @@ sub upfile_record_sep {
 
 =item * record_sep($record)
 
-Separate a record into fields $record should be an item from the upfile_record_sep(), needs $ENV{'form.upfiletype'}
+Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'}
 
 =cut
 
+sub takeleft {
+    my $index=shift;
+    return substr('0000'.$index,-4,4);
+}
+
 sub record_sep {
     my $record=shift;
     my %components=();
-    if ($ENV{'form.upfiletype'} eq 'xml') {
-    } elsif ($ENV{'form.upfiletype'} eq 'space') {
+    if ($env{'form.upfiletype'} eq 'xml') {
+    } elsif ($env{'form.upfiletype'} eq 'space') {
         my $i=0;
         foreach (split(/\s+/,$record)) {
             my $field=$_;
             $field=~s/^(\"|\')//;
             $field=~s/(\"|\')$//;
-            $components{$i}=$field;
+            $components{&takeleft($i)}=$field;
             $i++;
         }
-    } elsif ($ENV{'form.upfiletype'} eq 'tab') {
+    } elsif ($env{'form.upfiletype'} eq 'tab') {
         my $i=0;
         foreach (split(/\t/,$record)) {
             my $field=$_;
             $field=~s/^(\"|\')//;
             $field=~s/(\"|\')$//;
-            $components{$i}=$field;
+            $components{&takeleft($i)}=$field;
             $i++;
         }
     } else {
@@ -3160,7 +3303,7 @@ sub record_sep {
                 $field=~s/^\s*$delimiter//;
                 $field=~s/$delimiter\s*$//;
             }
-            $components{$i}=$field;
+            $components{&takeleft($i)}=$field;
 	    $i++;
         }
     }
@@ -3269,7 +3412,7 @@ sub csv_print_select_table {
 	$r->print('<option value="none"></option>');
 	foreach (sort({$a <=> $b} keys(%sone))) {
 	    $r->print('<option value="'.$_.'"'.
-                      ($_ eq $defaultcol ? ' selected ' : '').
+                      ($_ eq $defaultcol ? ' selected="selected" ' : '').
                       '>Column '.($_+1).'</option>');
 	}
 	$r->print('</select></td></tr>'."\n");
@@ -3313,13 +3456,13 @@ sub csv_samples_select_table {
 	foreach (@$d) {
 	    my ($value,$display,$defaultcol)=@{ $_ };
 	    $r->print('<option value="'.$value.'"'.
-                      ($i eq $defaultcol ? ' selected ':'').'>'.
+                      ($i eq $defaultcol ? ' selected="selected" ':'').'>'.
                       $display.'</option>');
 	}
 	$r->print('</select></td><td>');
-	if (defined($sone{$_})) { $r->print($sone{$_}."</br>\n"); }
-	if (defined($stwo{$_})) { $r->print($stwo{$_}."</br>\n"); }
-	if (defined($sthree{$_})) { $r->print($sthree{$_}."</br>\n"); }
+	if (defined($sone{$_})) { $r->print($sone{$_}."<br />\n"); }
+	if (defined($stwo{$_})) { $r->print($stwo{$_}."<br />\n"); }
+	if (defined($sthree{$_})) { $r->print($sthree{$_}."<br />\n"); }
 	$r->print('</td></tr>');
 	$i++;
     }
@@ -3827,34 +3970,34 @@ Returns: both routines return nothing
 sub store_course_settings {
     # save to the environment
     # appenv the same items, just to be safe
-    my $courseid = $ENV{'request.course.id'};
-    my $coursedom = $ENV{'course.'.$courseid.'.domain'};
+    my $courseid = $env{'request.course.id'};
+    my $coursedom = $env{'course.'.$courseid.'.domain'};
     my ($prefix,$Settings) = @_;
     my %SaveHash;
     my %AppHash;
     while (my ($setting,$type) = each(%$Settings)) {
         my $basename = 'internal.'.$prefix.'.'.$setting;
         my $envname = 'course.'.$courseid.'.'.$basename;
-        if (exists($ENV{'form.'.$setting})) {
+        if (exists($env{'form.'.$setting})) {
             # Save this value away
             if ($type eq 'scalar' &&
-                (! exists($ENV{$envname}) || 
-                 $ENV{$envname} ne $ENV{'form.'.$setting})) {
-                $SaveHash{$basename} = $ENV{'form.'.$setting};
-                $AppHash{$envname}   = $ENV{'form.'.$setting};
+                (! exists($env{$envname}) || 
+                 $env{$envname} ne $env{'form.'.$setting})) {
+                $SaveHash{$basename} = $env{'form.'.$setting};
+                $AppHash{$envname}   = $env{'form.'.$setting};
             } elsif ($type eq 'array') {
                 my $stored_form;
-                if (ref($ENV{'form.'.$setting})) {
+                if (ref($env{'form.'.$setting})) {
                     $stored_form = join(',',
                                         map {
                                             &Apache::lonnet::escape($_);
-                                        } sort(@{$ENV{'form.'.$setting}}));
+                                        } sort(@{$env{'form.'.$setting}}));
                 } else {
                     $stored_form = 
-                        &Apache::lonnet::escape($ENV{'form.'.$setting});
+                        &Apache::lonnet::escape($env{'form.'.$setting});
                 }
                 # Determine if the array contents are the same.
-                if ($stored_form ne $ENV{$envname}) {
+                if ($stored_form ne $env{$envname}) {
                     $SaveHash{$basename} = $stored_form;
                     $AppHash{$envname}   = $stored_form;
                 }
@@ -3863,7 +4006,7 @@ sub store_course_settings {
     }
     my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
                                           $coursedom,
-                                          $ENV{'course.'.$courseid.'.num'});
+                                          $env{'course.'.$courseid.'.num'});
     if ($put_result !~ /^(ok|delayed)/) {
         &Apache::lonnet::logthis('unable to save form parameters, '.
                                  'got error:'.$put_result);
@@ -3874,20 +4017,20 @@ sub store_course_settings {
 }
 
 sub restore_course_settings {
-    my $courseid = $ENV{'request.course.id'};
+    my $courseid = $env{'request.course.id'};
     my ($prefix,$Settings) = @_;
     while (my ($setting,$type) = each(%$Settings)) {
-        next if (exists($ENV{'form.'.$setting}));
+        next if (exists($env{'form.'.$setting}));
         my $envname = 'course.'.$courseid.'.internal.'.$prefix.
             '.'.$setting;
-        if (exists($ENV{$envname})) {
+        if (exists($env{$envname})) {
             if ($type eq 'scalar') {
-                $ENV{'form.'.$setting} = $ENV{$envname};
+                $env{'form.'.$setting} = $env{$envname};
             } elsif ($type eq 'array') {
-                $ENV{'form.'.$setting} = [ 
+                $env{'form.'.$setting} = [ 
                                            map { 
                                                &Apache::lonnet::unescape($_); 
-                                           } split(',',$ENV{$envname})
+                                           } split(',',$env{$envname})
                                            ];
             }
         }