--- loncom/interface/loncommon.pm	2005/06/06 20:31:24	1.267
+++ loncom/interface/loncommon.pm	2006/04/20 02:24:08	1.344
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.267 2005/06/06 20:31:24 www Exp $
+# $Id: loncommon.pm,v 1.344 2006/04/20 02:24:08 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -58,10 +58,12 @@ use strict;
 use Apache::lonnet;
 use GDBM_File;
 use POSIX qw(strftime mktime);
-use Apache::Constants qw(:common :http :methods);
 use Apache::lonmenu();
 use Apache::lonlocal;
 use HTML::Entities;
+use Apache::lonhtmlcommon();
+use Apache::loncoursedata();
+use Apache::lontexconvert();
 
 my $readit;
 
@@ -152,19 +154,20 @@ BEGIN {
     my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
     opendir(DIR,$designdir);
     while ($filename=readdir(DIR)) {
+	if ($filename!~/\.tab$/) { next; }
 	my ($domain)=($filename=~/^(\w+)\./);
-    {
-        my $designfile = $designdir.'/'.$filename;
-        if ( open (my $fh,"<$designfile") ) {
-            while (<$fh>) {
-                next if /^\#/;
-                chomp;
-                my ($key,$val)=(split(/\=/,$_));
-                if ($val) { $designhash{$domain.'.'.$key}=$val; }
-            }
-            close($fh);
-        }
-    }
+	{
+	    my $designfile = $designdir.'/'.$filename;
+	    if ( open (my $fh,"<$designfile") ) {
+		while (<$fh>) {
+		    next if /^\#/;
+		    chomp;
+		    my ($key,$val)=(split(/\=/,$_));
+		    if ($val) { $designhash{$domain.'.'.$key}=$val; }
+		}
+		close($fh);
+	    }
+	}
 
     }
     closedir(DIR);
@@ -330,7 +333,10 @@ sub storeresurl {
 sub studentbrowser_javascript {
    unless (
             (($env{'request.course.id'}) && 
-             (&Apache::lonnet::allowed('srm',$env{'request.course.id'})))
+             (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
+	      || &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
+					  '/'.$env{'request.course.sec'})
+	      ))
          || ($env{'request.role'}=~/^(au|dc|su)/)
           ) { return ''; }  
    return (<<'ENDSTDBRW');
@@ -361,7 +367,9 @@ ENDSTDBRW
 sub selectstudent_link {
    my ($form,$unameele,$udomele)=@_;
    if ($env{'request.course.id'}) {  
-       unless (&Apache::lonnet::allowed('srm',$env{'request.course.id'})) {
+       if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
+	   && !&Apache::lonnet::allowed('srm',$env{'request.course.id'}.
+					'/'.$env{'request.course.sec'})) {
 	   return '';
        }
        return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele.
@@ -379,7 +387,7 @@ sub coursebrowser_javascript {
    return (<<ENDSTDBRW);
 <script type="text/javascript" language="Javascript" >
     var stdeditbrowser;
-    function opencrsbrowser(formname,uname,udom,desc,extra_element) {
+    function opencrsbrowser(formname,uname,udom,desc,extra_element,multflag) {
         var url = '/adm/pickcourse?';
         var filter;
         if (filter != null) {
@@ -402,6 +410,9 @@ sub coursebrowser_javascript {
                 url += '&domainfilter='+extra_element;
             }
         }
+        if (multflag !=null && multflag != '') {
+            url += '&multiple='+multflag;
+        }
         var title = 'Course_Browser';
         var options = 'scrollbars=1,resizable=1,menubar=0';
         options += ',width=700,height=600';
@@ -413,11 +424,36 @@ ENDSTDBRW
 }
 
 sub selectcourse_link {
-   my ($form,$unameele,$udomele,$desc,$extra_element)=@_;
+   my ($form,$unameele,$udomele,$desc,$extra_element,$multflag)=@_;
     return "<a href='".'javascript:opencrsbrowser("'.$form.'","'.$unameele.
-        '","'.$udomele.'","'.$desc.'","'.$extra_element.'");'."'>".&mt('Select Course')."</a>";
+        '","'.$udomele.'","'.$desc.'","'.$extra_element.'","'.$multflag.'");'."'>".&mt('Select Course')."</a>";
 }
 
+sub check_uncheck_jscript {
+    my $jscript = <<"ENDSCRT";
+function checkAll(field) {
+    if (field.length > 0) {
+        for (i = 0; i < field.length; i++) {
+            field[i].checked = true ;
+        }
+    } else {
+        field.checked = true
+    }
+}
+ 
+function uncheckAll(field) {
+    if (field.length > 0) {
+        for (i = 0; i < field.length; i++) {
+            field[i].checked = false ;
+        }     } else {
+        field.checked = false ;
+    }
+}
+ENDSCRT
+    return $jscript;
+}
+
+
 =pod
 
 =item * linked_select_forms(...)
@@ -687,8 +723,18 @@ sub help_open_menu {
   "<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");
+    my $start_page =
+        &Apache::loncommon::start_page('Help Menu', undef,
+				       {'frameset'    => 1,
+					'js_ready'    => 1,
+					'add_entries' => {
+					    'border' => '0',
+					    'rows'   => "105,*",},});
+    my $end_page =
+        &Apache::loncommon::end_page({'frameset' => 1,
+				      'js_ready' => 1,});
+
     $template .= <<"ENDTEMPLATE";
  <script type="text/javascript">
 // <!-- BEGIN LON-CAPA Internal
@@ -712,9 +758,7 @@ function helpMenu(target) {
     return;
 }
 function writeHelp(caller) {
-    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.writeln('$start_page<frame name="bannerframe"  src="$banner_link" /><frame name="bodyframe" src="$details_link" /> $end_page')
     caller.document.close()
     caller.focus()
 }
@@ -1123,27 +1167,49 @@ sub domain_select {
     } &get_domains;
     if ($multiple) {
 	$domains{''}=&mt('Any domain');
-	return &multiple_select_form($name,$value,4,%domains);
+	return &multiple_select_form($name,$value,4,\%domains);
     } else {
 	return &select_form($name,$value,%domains);
     }
 }
 
+#-------------------------------------------
+
+=pod
+
+=item * multiple_select_form($name,$value,$size,$hash,$order)
+
+Returns a string containing a <select> element int multiple mode
+
+
+Args:
+  $name - name of the <select> element
+  $value - sclara or array ref of values that should already be selected
+  $size - number of rows long the select element is
+  $hash - the elements should be 'option' => 'shown text'
+          (shown text should already have been &mt())
+  $order - (optional) array ref of the order to show the elments in
+
+=cut
+
+#-------------------------------------------
 sub multiple_select_form {
-    my ($name,$value,$size,%hash)=@_;
+    my ($name,$value,$size,$hash,$order)=@_;
     my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
     my $output='';
     if (! defined($size)) {
         $size = 4;
-        if (scalar(keys(%hash))<4) {
-            $size = scalar(keys(%hash));
+        if (scalar(keys(%$hash))<4) {
+            $size = scalar(keys(%$hash));
         }
     }
     $output.="\n<select name='$name' size='$size' multiple='1'>";
-    foreach (sort(keys(%hash))) {
-        $output.='<option value="'.$_.'" ';
-        $output.='selected="selected" ' if ($selected{$_});
-        $output.='>'.$hash{$_}."</option>\n";
+    my @order = ref($order) ? @$order
+                            : sort(keys(%$hash));
+    foreach my $key (@order) {
+        $output.='<option value="'.$key.'" ';
+        $output.='selected="selected" ' if ($selected{$key});
+        $output.='>'.$hash->{$key}."</option>\n";
     }
     $output.="</select>\n";
     return $output;
@@ -1539,10 +1605,11 @@ sub authform_nochange{
               kerb_def_dom => 'MSU.EDU',
               @_,
           );
-    my $result = &mt('[_1] Do not change login data',
+    my $result = '<label>'.&mt('[_1] Do not change login data',
                      '<input type="radio" name="login" value="nochange" '.
                      'checked="checked" onclick="'.
-            "javascript:changed_radio('nochange',$in{'formname'});".'" />');
+            "javascript:changed_radio('nochange',$in{'formname'});".'" />').
+	    '</label>';
     return $result;
 }
 
@@ -1574,14 +1641,15 @@ sub authform_kerberos{
     my $jscall = "javascript:changed_radio('krb',$in{'formname'});";
     my $result .= &mt
         ('[_1] Kerberos authenticated with domain [_2] '.
-         '[_3] Version 4 [_4] Version 5',
-         '<input type="radio" name="login" value="krb" '.
+         '[_3] Version 4 [_4] Version 5 [_5]',
+         '<label><input type="radio" name="login" value="krb" '.
              'onclick="'.$jscall.'" onchange="'.$jscall.'"'.$krbcheck.' />',
-         '<input type="text" size="10" name="krbarg" '.
+         '</label><input type="text" size="10" name="krbarg" '.
              'value="'.$krbarg.'" '.
              'onchange="'.$jscall.'" />',
-         '<input type="radio" name="krbver" value="4" '.$check4.' />',
-         '<input type="radio" name="krbver" value="5" '.$check5.' />');
+         '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
+         '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
+	 '</label>');
     return $result;
 }
 
@@ -1606,9 +1674,9 @@ sub authform_internal{
     my $jscall = "javascript:changed_radio('int',$args{'formname'});";
     my $result.=&mt
         ('[_1] Internally authenticated (with initial password [_2])',
-         '<input type="radio" name="login" value="int" '.$intcheck.
+         '<label><input type="radio" name="login" value="int" '.$intcheck.
              ' onchange="'.$jscall.'" onclick="'.$jscall.'" />',
-         '<input type="text" size="10" name="intarg" '.$intarg.
+         '</label><input type="text" size="10" name="intarg" '.$intarg.
              ' onchange="'.$jscall.'" />');
     return $result;
 }
@@ -1633,9 +1701,9 @@ sub authform_local{
 
     my $jscall = "javascript:changed_radio('loc',$in{'formname'});";
     my $result.=&mt('[_1] Local Authentication with argument [_2]',
-                    '<input type="radio" name="login" value="loc" '.$loccheck.
+                    '<label><input type="radio" name="login" value="loc" '.$loccheck.
                         ' onchange="'.$jscall.'" onclick="'.$jscall.'" />',
-                    '<input type="text" size="10" name="locarg" '.$locarg.
+                    '</label><input type="text" size="10" name="locarg" '.$locarg.
                         ' onchange="'.$jscall.'" />');
     return $result;
 }
@@ -1649,9 +1717,9 @@ sub authform_filesystem{
     my $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
     my $result.= &mt
         ('[_1] Filesystem Authenticated (with initial password [_2])',
-         '<input type="radio" name="login" value="fsys" '.
+         '<label><input type="radio" name="login" value="fsys" '.
          'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
-         '<input type="text" size="10" name="fsysarg" value="" '.
+         '</label><input type="text" size="10" name="fsysarg" value="" '.
                   'onchange="'.$jscall.'" />');
     return $result;
 }
@@ -1867,12 +1935,11 @@ if $first is set to 'lastname' then it r
 
 =cut
 
+
 ###############################################################
 sub plainname {
     my ($uname,$udom,$first)=@_;
-    my %names=&Apache::lonnet::get('environment',
-                    ['firstname','middlename','lastname','generation'],
-					 $udom,$uname);
+    my %names=&getnames($uname,$udom);
     my $name=&Apache::lonnet::format_name($names{'firstname'},
 					  $names{'middlename'},
 					  $names{'lastname'},
@@ -1903,19 +1970,7 @@ 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'});
-    } else {
-	%names=&Apache::lonnet::get('environment',
-				    ['nickname','firstname','middlename',
-				     'lastname','generation'],$udom,$uname);
-    }
+    my %names=&getnames($uname,$udom);
     my $name=$names{'nickname'};
     if ($name) {
        $name='&quot;'.$name.'&quot;'; 
@@ -1928,6 +1983,20 @@ sub nickname {
     return $name;
 }
 
+sub getnames {
+    my ($uname,$udom)=@_;
+    my $id=$uname.':'.$udom;
+    my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id);
+    if ($cached) {
+	return %{$names};
+    } else {
+	my %loadnames=&Apache::lonnet::get('environment',
+                    ['firstname','middlename','lastname','generation','nickname'],
+					 $udom,$uname);
+	&Apache::lonnet::do_cache_new('namescache',$id,\%loadnames);
+	return %loadnames;
+    }
+}
 
 # ------------------------------------------------------------------ Screenname
 
@@ -1984,19 +2053,20 @@ sub syllabuswrapper {
 }
 
 sub track_student_link {
-    my ($linktext,$sname,$sdom,$target) = @_;
-    my $link ="/adm/trackstudent";
+    my ($linktext,$sname,$sdom,$target,$start) = @_;
+    my $link ="/adm/trackstudent?";
     my $title = 'View recent activity';
     if (defined($sname) && $sname !~ /^\s*$/ &&
         defined($sdom)  && $sdom  !~ /^\s*$/) {
-        $link .= "?selected_student=$sname:$sdom";
+        $link .= "selected_student=$sname:$sdom";
         $title .= ' of this student';
-    }
+    } 
     if (defined($target) && $target !~ /^\s*$/) {
         $target = qq{target="$target"};
     } else {
         $target = '';
     }
+    if ($start) { $link.='&amp;start='.$start; }
     return qq{<a href="$link" title="$title" $target>$linktext</a>};
 }
 
@@ -2482,7 +2552,7 @@ sub pgrdlink {
 Inputs: $text $uname $udom $symb $target
 
 Returns: A link to parmset.pm such as to see the PPRM view of a
-student andn resource
+student and a specific resource
 
 =cut
 
@@ -2677,6 +2747,18 @@ Inputs:
 =item * $forcereg, if page should register as content page (relevant for 
             text interface only)
 
+=item * $customtitle, alternate text to use instead of $title
+                      in the title box that appears, this text
+                      is not auto translated like the $title is
+
+=item * $notopbar, if true, keep the 'what is this' info but remove the
+                   navigational links
+
+=item * $bgcolor, used to override the bgcolor on a webpage to a specific value
+
+=item * $notitle, if true keep the nav controls, but remove the title bar
+
+
 =back
 
 Returns: A uniform header for LON-CAPA web pages.  
@@ -2687,23 +2769,26 @@ other decorations will be returned.
 =cut
 
 sub bodytag {
-    my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,$customtitle)=@_;
+    my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,$customtitle,
+	$notopbar,$bgcolor,$notitle)=@_;
+
     $title=&mt($title);
+
     $function = &get_users_function() if (!$function);
-    my $img=&designparm($function.'.img',$domain);
-    my $pgbg=&designparm($function.'.pgbg',$domain);
-    my $tabbg=&designparm($function.'.tabbg',$domain);
-    my $font=&designparm($function.'.font',$domain);
-    my $link=&designparm($function.'.link',$domain);
-    my $alink=&designparm($function.'.alink',$domain);
-    my $vlink=&designparm($function.'.vlink',$domain);
-    my $sidebg=&designparm($function.'.sidebg',$domain);
-# Accessibility font enhance
-    unless ($addentries) { $addentries=''; }
-    my $addstyle='';
-    if ($env{'browser.fontenhance'} eq 'on') {
-	$addstyle=' font-size: x-large;';
-    }
+    my $img =    &designparm($function.'.img',$domain);
+    my $tabbg =  &designparm($function.'.tabbg',$domain);
+    my $font =   &designparm($function.'.font',$domain);
+    my $sidebg = &designparm($function.'.sidebg',$domain);
+    my $pgbg   = $bgcolor || &designparm($function.'.pgbg',$domain);
+
+    my %design = ( 'style'   => 'margin-top: 0px',
+		   'bgcolor' => $pgbg,
+		   'text'    => $font,
+                   'alink'   => &designparm($function.'.alink',$domain),
+		   'vlink'   => &designparm($function.'.vlink',$domain),
+		   'link'    => &designparm($function.'.link',$domain),);
+    @$addentries{keys(%design)} = @design{keys(%design)};
+
  # role and realm
     my ($role,$realm)
        =&Apache::lonnet::plaintext((split(/\./,$env{'request.role'}))[0]);
@@ -2718,32 +2803,30 @@ sub bodytag {
 # Port for miniserver
     my $lonhttpdPort=$Apache::lonnet::perlvar{'lonhttpdPort'};
     if (!defined($lonhttpdPort)) { $lonhttpdPort='8080'; }
+
+    my $extra_body_attr = &make_attr_string($forcereg,$addentries);
+
 # construct main body tag
     my $bodytag = <<END;
-<style type="text/css">
-h1, h2, h3, th { font-family: Arial, Helvetica, sans-serif }
-a:focus { color: red; background: yellow } 
-</style>
-<body bgcolor="$pgbg" text="$font" alink="$alink" vlink="$vlink" link="$link"
-style="margin-top: 0px;$addstyle" $addentries>
+<body $extra_body_attr>
 END
-    if ($env{'environment.texengine'} eq 'jsMath') {
-	$bodytag.='<script type="text/javascript">
-                     function NoFontMessage () {}
-                   </script>'."\n".
-	    '<script src="/adm/jsMath/jsMath.js"></script>'."\n";
-    }
+
+    $bodytag .= &Apache::lontexconvert::init_math_support();
 
     my $upperleft='<img src="http://'.$ENV{'HTTP_HOST'}.':'.
                    $lonhttpdPort.$img.'" alt="'.$function.'" />';
-    if ($bodyonly) {
+    if ($bodyonly 
+	|| ($env{'request.state'} eq 'construct' 
+	    && $env{'environment.remote'} ne 'off' )) {
         return $bodytag;
     } elsif ($env{'browser.interface'} eq 'textual') {
 # Accessibility
           
-        return $bodytag.&Apache::lonmenu::menubuttons($forcereg,'web',
-                                                      $forcereg).
-               '<h1>LON-CAPA: '.$title.'</h1>';
+	$bodytag.=&Apache::lonmenu::menubuttons($forcereg,$forcereg);
+	if (!$notitle) {
+	    $bodytag.='<h1>LON-CAPA: '.$title.'</h1>';
+	}
+	return $bodytag;
     } elsif ($env{'environment.remote'} eq 'off') {
 # No Remote
 	my $roleinfo=(<<ENDROLE);
@@ -2792,15 +2875,28 @@ ENDROLE
             }
 	    $forcereg=1;
         }
-        my $titletable = '<table bgcolor="'.$pgbg.'" width="100%" border="0" '.
+        my $titletable;
+	if (!$notitle) {
+	    $titletable =
+		'<table bgcolor="'.$pgbg.'" width="100%" border="0" '.
                          'cellspacing="3" cellpadding="3">'.
-                         '<tr><td rowspan="3" bgcolor="'.$tabbg.'">'.
+                         '<tr><td bgcolor="'.$tabbg.'">'.
                          $titleinfo.'</td>'.$roleinfo.'</tr></table>';
-        if ($env{'request.state'} eq 'construct') {
-            $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg,$titletable);
+	}
+	if ($env{'request.state'} eq 'construct') {
+            if ($notopbar) {
+                $bodytag .= $titletable;
+            } else {
+                $bodytag .= &Apache::lonmenu::menubuttons($forcereg,$forcereg,
+							  $titletable);
+            }
 	} else {
-            $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg).
+            if ($notopbar) {
+                $bodytag .= $titletable;
+            } else {
+                $bodytag .= &Apache::lonmenu::menubuttons($forcereg,$forcereg).
                         $titletable;
+            }
         }
         return $bodytag;
     }
@@ -2822,7 +2918,12 @@ ENDROLE
         $dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
         $dc_info = '('.$dc_info.')';
     }
+    # Explicit link to get inline menu
+    my $menu='<br /><font size="2" face="Arial, Helvetica, sans-serif">&nbsp;<a href="/adm/remote?action=collapse">'.&mt('Switch to Inline Menu Mode').'</a></font>';
     #
+    if ($notitle) {
+	return $bodytag;
+    }
     return(<<ENDBODY);
 $bodytag
 <table width="100%" cellspacing="0" border="0" cellpadding="0">
@@ -2832,7 +2933,7 @@ $upperleft</td>
 </tr>
 <tr>
 <td rowspan="3" bgcolor="$tabbg">
-$titleinfo $dc_info
+$titleinfo $dc_info $menu
 </td><td bgcolor="$tabbg" align="right">
 <font size="2" face="Arial, Helvetica, sans-serif">
     $env{'environment.firstname'}
@@ -2851,6 +2952,62 @@ $titleinfo $dc_info
 ENDBODY
 }
 
+sub make_attr_string {
+    my ($register,$attr_ref) = @_;
+
+    if ($attr_ref && !ref($attr_ref)) {
+	die("addentries Must be a hash ref ".
+	    join(':',caller(1))." ".
+	    join(':',caller(0))." ");
+    }
+
+    if ($register) {
+	my ($on_load,$on_unload);
+	foreach my $key (keys(%{$attr_ref})) {
+	    if      (lc($key) eq 'onload') {
+		$on_load.=$attr_ref->{$key}.';';
+		delete($attr_ref->{$key});
+
+	    } elsif (lc($key) eq 'onunload') {
+		$on_unload.=$attr_ref->{$key}.';';
+		delete($attr_ref->{$key});
+	    }
+	}
+	$attr_ref->{'onload'}  =
+	    &Apache::lonmenu::loadevents().  $on_load;
+	$attr_ref->{'onunload'}=
+	    &Apache::lonmenu::unloadevents().$on_unload;
+    }
+
+# Accessibility font enhance
+    if ($env{'browser.fontenhance'} eq 'on') {
+	my $style;
+	foreach my $key (keys(%{$attr_ref})) {
+	    if (lc($key) eq 'style') {
+		$style.=$attr_ref->{$key}.';';
+		delete($attr_ref->{$key});
+	    }
+	}
+	$attr_ref->{'style'}=$style.'; font-size: x-large;';
+    }
+
+    if ($env{'browser.blackwhite'} eq 'on') {
+	delete($attr_ref->{'font'});
+	delete($attr_ref->{'link'});
+	delete($attr_ref->{'alink'});
+	delete($attr_ref->{'vlink'});
+	delete($attr_ref->{'bgcolor'});
+	delete($attr_ref->{'background'});
+    }
+
+    my $attr_string;
+    foreach my $attr (keys(%$attr_ref)) {
+	$attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
+    }
+    return $attr_string;
+}
+
+
 ###############################################
 ###############################################
 
@@ -2858,7 +3015,7 @@ ENDBODY
 
 =back
 
-=head1 HTTP Helpers
+=head1 HTML Helpers
 
 =over 4
 
@@ -2866,29 +3023,384 @@ ENDBODY
 
 Returns a uniform footer for LON-CAPA web pages.
 
-Inputs: 
-
-=over 4
+Inputs: none
 
 =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;
+    $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
+    if ( exists( $env{'internal.head.redirect'} ) ) {
+	$endbodytag=
+	    "<br /><a href=\"$env{'internal.head.redirect'}\">".
+	    &mt('Continue').'</a>'.
+	    $endbodytag;
     }
     return $endbodytag;
 }
 
+sub standard_css {
+    return <<END;
+<style type="text/css">
+h1, h2, h3, th { font-family: Arial, Helvetica, sans-serif }
+a:focus { color: red; background: yellow } 
+table.thinborder { border-collapse: collapse; }
+table.thinborder tr th, table.thinborder tr td { border-style: solid; border-width: 1px}
+form, .inline { display: inline; }
+.center { text-align: center; }
+.filename {font-family: monospace;}
+</style>
+END
+}
+
+=pod
+
+=over 4
+
+=item * &headtag()
+
+Returns a uniform footer for LON-CAPA web pages.
+
+Inputs: $title - optional title for the head
+        $head_extra - optional extra HTML to put inside the <head>
+        $args - optional arguments
+            force_register - if is true call registerurl so the remote is 
+                             informed
+            redirect - array ref of seconds before redirect occurs
+                                    url to redirect to
+                           (side effect of setting 
+                               $env{'internal.head.redirect'} to the url 
+                               redirected too)
+=back
+
+=cut
+
+sub headtag {
+    my ($title,$head_extra,$args) = @_;
+    
+    my $result =
+	'<head>'.
+	&standard_css().
+	&font_settings().
+	&Apache::lonhtmlcommon::htmlareaheaders();
+
+    if ($args->{'force_register'}) {
+	$result .= &Apache::lonmenu::registerurl(1);
+    }
+
+    if (ref($args->{'redirect'})) {
+	my ($time,$url) = @{$args->{'redirect'}};
+	$url = &Apache::lonenc::check_encrypt($url);
+	$env{'internal.head.redirect'} = $url;
+	$result.=<<ADDMETA
+<meta http-equiv="pragma" content="no-cache" />
+<meta http-equiv="Refresh" content="$time; url=$url" />
+ADDMETA
+    }
+    if (!defined($title)) {
+	$title = 'The LearningOnline Network with CAPA';
+    }
+    
+    $result .= '<title> LON-CAPA '.&mt($title).'</title>'.$head_extra;
+    return $result;
+}
+
+=pod
+
+=over 4
+
+=item * &font_settings()
+
+Returns neccessary <meta> to set the proper encoding
+
+Inputs: none
+
+=back
+
+=cut
+
+sub font_settings {
+    my $headerstring='';
+    if (($env{'browser.os'} eq 'mac') && (!$env{'browser.mathml'})) { 
+	$headerstring.=
+	    '<meta Content-Type="text/html; charset=x-mac-roman" />';
+    } elsif (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
+	$headerstring.=
+	    '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
+    }
+    return $headerstring;
+}
+
+=pod
+
+=over 4
+
+=item * &xml_begin()
+
+Returns the needed doctype and <html>
+
+Inputs: none
+
+=back
+
+=cut
+
+sub xml_begin {
+    my $output='';
+
+    &Apache::lonhtmlcommon::init_htmlareafields();
+
+    if ($env{'browser.mathml'}) {
+	$output='<?xml version="1.0"?>'
+            #.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n"
+#            .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" '
+            
+#	    .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [<!ENTITY mathns "http://www.w3.org/1998/Math/MathML">] >'
+	    .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">'
+            .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" ' 
+	    .'xmlns="http://www.w3.org/1999/xhtml">';
+    } else {
+	$output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>';
+    }
+    return $output;
+}
+
+=pod
+
+=over 4
+
+=item * &endheadtag()
+
+Returns a uniform </head> for LON-CAPA web pages.
+
+Inputs: none
+
+=back
+
+=cut
+
+sub endheadtag {
+    return '</head>';
+}
+
+=pod
+
+=over 4
+
+=item * &head()
+
+Returns a uniform complete <head>..</head> section for LON-CAPA web pages.
+
+Inputs: $title - optional title for the page
+        $head_extra - optional extra HTML to put inside the <head>
+=back
+
+=cut
+
+sub head {
+    my ($title,$head_extra,$args) = @_;
+    return &headtag($title,$head_extra,$args).&endheadtag();
+}
+
+=pod
+
+=over 4
+
+=item * &start_page()
+
+Returns a complete <html> .. <body> section for LON-CAPA web pages.
+
+Inputs: $title - optional title for the page
+        $head_extra - optional extra HTML to incude inside the <head>
+        $args - additional optional args supported are:
+                  only_body      -> is true will set &bodytag() onlybodytag
+                                    arg on
+                  no_nav_bar     -> is true will set &bodytag() notopbar arg on
+                  add_entries    -> additional attributes to add to the  <body>
+                  domain         -> force to color decorate a page for a 
+                                    specific domain
+                  function       -> force usage of a specific rolish color
+                                    scheme
+                  redirect       -> see &headtag()
+                  bgcolor        -> override the default page bg color
+                  js_ready       -> return a string ready for being used in 
+                                    a javascript writeln
+                  html_encode    -> return a string ready for being used in 
+                                    a html attribute
+                  force_register -> if is true will turn on the &bodytag()
+                                    $forcereg arg
+                  body_title     -> alternate text to use instead of $title
+                                    in the title box that appears, this text
+                                    is not auto translated like the $title is
+                  frameset       -> if true will start with a <frameset>
+                                    rather than <body>
+                  no_title       -> if true the title bar won't be shown
+                  skip_phases    -> hash ref of 
+                                    head -> skip the <html><head> generation
+                                    body -> skip all <body> generation
+
+=back
+
+=cut
+
+sub start_page {
+    my ($title,$head_extra,$args) = @_;
+    #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
+    my %head_args;
+    foreach my $arg ('redirect','force_register') {
+	if (defined($args->{$arg})) {
+	    $head_args{$arg} = $args->{$arg};
+	}
+    }
+
+    $env{'internal.start_page'}++;
+    my $result;
+    if (! exists($args->{'skip_phases'}{'head'}) ) {
+	$result.=
+	    &xml_begin().
+	    &headtag($title,$head_extra,\%head_args).&endheadtag();
+    }
+    
+    if (! exists($args->{'skip_phases'}{'body'}) ) {
+	if ($args->{'frameset'}) {
+	    my $attr_string = &make_attr_string($args->{'force_register'},
+						$args->{'add_entries'});
+	    $result .= "\n<frameset $attr_string>\n";
+	} else {
+	    $result .=
+		&bodytag($title, 
+			 $args->{'function'},       $args->{'add_entries'},
+			 $args->{'only_body'},      $args->{'domain'},
+			 $args->{'force_register'}, $args->{'body_title'},
+			 $args->{'no_nav_bar'},     $args->{'bgcolor'},
+			 $args->{'no_title'});
+	}
+    }
+
+    if ($args->{'js_ready'}) {
+	$result = &js_ready($result);
+    }
+    if ($args->{'html_encode'}) {
+	$result = &html_encode($result);
+    }
+    return $result;
+}
+
+
+=pod
+
+=over 4
+
+=item * &head()
+
+Returns a complete </body></html> section for LON-CAPA web pages.
+
+Inputs:         $args - additional optional args supported are:
+                 js_ready     -> return a string ready for being used in 
+                                 a javascript writeln
+                 html_encode  -> return a string ready for being used in 
+                                 a html attribute
+                 frameset     -> if true will start with a <frameset>
+                                 rather than <body>
+=back
+
+=cut
+
+sub end_page {
+    my ($args) = @_;
+    #&Apache::lonnet::logthis("end_page ".join(':',caller(0)));
+    $env{'internal.end_page'}++;
+    my $result;
+    if ($args->{'discussion'}) {
+	my ($target,$parser);
+	if (ref($args->{'discussion'})) {
+	    ($target,$parser) =($args->{'discussion'}{'target'},
+				$args->{'discussion'}{'parser'});
+	}
+	$result .= &Apache::lonxml::xmlend($target,$parser);
+    }
+
+    if ($args->{'frameset'}) {
+	$result .= '</frameset>';
+    } else {
+	$result .= &endbodytag();
+    }
+    $result .= "\n</html>";
+
+    if ($args->{'js_ready'}) {
+	$result = &js_ready($result);
+    }
+
+    if ($args->{'html_encode'}) {
+	$result = &html_encode($result);
+    }
+
+    return $result;
+}
+
+sub html_encode {
+    my ($result) = @_;
+
+    $result = &HTML::Entities::encode($result,'<>&"');
+    
+    return $result;
+}
+sub js_ready {
+    my ($result) = @_;
+
+    $result =~ s/[\n\r]/ /xmsg;
+    $result =~ s/\\/\\\\/xmsg;
+    $result =~ s/'/\\'/xmsg;
+    $result =~ s{</script>}{</scrip'+'t>}xmsg;
+    
+    return $result;
+}
+
+sub validate_page {
+    if (  exists($env{'internal.start_page'})
+	  &&     $env{'internal.start_page'} > 1) {
+	&Apache::lonnet::logthis('start_page called multiple times '.
+				 $env{'internal.start_page'}.' '.
+				 $ENV{'request.filename'});
+    }
+    if (  exists($env{'internal.end_page'})
+	  &&     $env{'internal.end_page'} > 1) {
+	&Apache::lonnet::logthis('end_page called multiple times '.
+				 $env{'internal.end_page'}.' '.
+				 $env{'request.filename'});
+    }
+    if (     exists($env{'internal.start_page'})
+	&& ! exists($env{'internal.end_page'})) {
+	&Apache::lonnet::logthis('start_page called without end_page '.
+				 $env{'request.filename'});
+    }
+    if (   ! exists($env{'internal.start_page'})
+	&&   exists($env{'internal.end_page'})) {
+	&Apache::lonnet::logthis('end_page called without start_page'.
+				 $env{'request.filename'});
+    }
+}
+
+sub simple_error_page {
+    my ($r,$title,$msg) = @_;
+    my $page =
+	&Apache::loncommon::start_page($title).
+	&mt($msg).
+	&Apache::loncommon::end_page();
+    if (ref($r)) {
+	$r->print($page);
+	return;
+    }
+    return $page;
+}
 ###############################################
 
 =pod
 
+=over 4
+
 =item get_users_function
 
 Used by &bodytag to determine the current users primary role.
@@ -2916,6 +3428,60 @@ sub get_users_function {
 
 =pod
 
+=item check_user_status
+
+Determines current status of supplied role for a
+specific user. Roles can be active, previous or future.
+
+Inputs: 
+user's domain, user's username, course's domain,
+course's number, optional section/group.
+
+Outputs:
+role status: active, previous or future. 
+
+=cut
+
+sub check_user_status {
+    my ($udom,$uname,$cdom,$crs,$role,$secgrp) = @_;
+    my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
+    my @uroles = keys %userinfo;
+    my $srchstr;
+    my $active_chk = 'none';
+    if (@uroles > 0) {
+        if (($role eq 'cc') || ($secgrp eq '') || (!defined($secgrp))) {
+            $srchstr = '/'.$cdom.'/'.$crs.'_'.$role;
+        } else {
+            $srchstr = '/'.$cdom.'/'.$crs.'/'.$secgrp.'_'.$role;         }
+        if (grep/^$srchstr$/,@uroles) {
+            my $role_end = 0;
+            my $role_start = 0;
+            $active_chk = 'active';
+            if ($userinfo{$srchstr} =~ m/^($role)_(\d+)/) {
+                $role_end = $2;
+                if ($userinfo{$srchstr} =~ m/^($role)_($role_end)_(\d+)$/) {
+                    $role_start = $3;
+                }
+            }
+            if ($role_start > 0) {
+                if (time < $role_start) {
+                    $active_chk = 'future';
+                }
+            }
+            if ($role_end > 0) {
+                if (time > $role_end) {
+                    $active_chk = 'previous';
+                }
+            }
+        }
+    }
+    return $active_chk;
+}
+
+###############################################
+
+=pod
+
 =item get_sections
 
 Determines all the sections for a course including
@@ -2934,11 +3500,10 @@ Returns number of sections.
 sub get_sections {
     my ($cdom,$cnum,$sectioncount,$possible_roles) = @_;
     if (!($cdom && $cnum)) { return 0; }
-    my $cid = $cdom.'_'.$cnum;
     my $numsections = 0;
 
     if (!defined($possible_roles) || (grep/^st$/,@$possible_roles)) {
-	my ($classlist) = &Apache::loncoursedata::get_classlist($cid,$cdom,$cnum);
+	my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
 	my $sec_index = &Apache::loncoursedata::CL_SECTION();
 	my $status_index = &Apache::loncoursedata::CL_STATUS();
 	while (my ($student,$data) = each %$classlist) {
@@ -2968,75 +3533,284 @@ sub get_sections {
     return $numsections;
 }
 
+###############################################
+                                                                                  
+=pod
+                                                                                  
+=item coursegroups
 
-sub get_posted_cgi {
-    my $r=shift;
+Retrieve information about groups in a course,
 
-    my $buffer;
-    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;
-	foreach $pair (@pairs) {
-	    my ($name,$value) = split(/=/,$pair);
-	    $value =~ tr/+/ /;
-	    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
-	    $name  =~ tr/+/ /;
-	    $name  =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
-	    &add_to_env("form.$name",$value);
-	}
-    } else {
-	my $contentsep=$1;
-	my @lines = split (/\n/,$buffer);
-	my $name='';
-	my $value='';
-	my $fname='';
-	my $fmime='';
-	my $i;
-	for ($i=0;$i<=$#lines;$i++) {
-	    if ($lines[$i]=~/^$contentsep/) {
-		if ($name) {
-		    chomp($value);
-		    if ($fname) {
-			$env{"form.$name.filename"}=$fname;
-			$env{"form.$name.mimetype"}=$fmime;
-		    } else {
-			$value=~s/\s+$//s;
-		    }
-		    &add_to_env("form.$name",$value);
+Input:
+1. Reference to hash to populate with group information. 
+2. Optional course domain
+3. Optional course number
+4. Optional group name
+
+Course domain and number will be taken from user's
+environment if not supplied. Optional group name will'
+be passed to lonnet::get_coursegroups() as a regexp to
+use in the call to the dump function.
+
+Output
+Returns number of groups in the course (subject to the
+optional group name filter).
+
+Side effects:
+Populates the referenced curr_groups hash, with key,
+value pairs. Keys are group names, corresponding values
+are scalars containing group information in XML. This
+can be sent to &get_group_settings() to be parsed.     
+
+=cut 
+
+###############################################
+
+sub coursegroups {
+    my ($curr_groups,$cdom,$cnum,$group) = @_;
+    my $numgroups;
+    if (!defined($cdom) || !defined($cnum)) {
+        my $cid =  $env{'request.course.id'};
+        $cdom = $env{'course.'.$cid.'.domain'};
+        $cnum = $env{'course.'.$cid.'.num'};
+    }
+    %{$curr_groups} = &Apache::lonnet::get_coursegroups($cdom,$cnum,$group);
+    my ($tmp) = keys(%{$curr_groups});
+    if ($tmp=~/^error:/) {
+        unless ($tmp eq 'error: 2 tie(GDBM) Failed while attempting dump') {
+            &logthis('Error retrieving groups: '.$tmp.' in '.$cnum.':'.
+                                                                   $cdom);
+        }
+        $numgroups = 0;
+    } else {
+        $numgroups = keys(%{$curr_groups});
+    }
+    return $numgroups;
+}
+
+###############################################
+
+=pod
+
+=item get_group_settings
+
+Uses TokeParser to extract group information from the
+XML used to describe course groups.
+
+Input:
+Scalar containing XML  - as retrieved from &coursegroups().
+
+Output:
+Hash containing group information as key=values for (a), and
+hash of hashes for (b)
+
+Keys (in two categories):
+(a) groupname, creator, creation, modified, startdate,enddate.
+Corresponding values are name of the group, creator of the group
+(username:domain), UNIX time for date group was created, and
+settings were last modified, and default start and end access
+times for group members.
+
+(b) functions returned in hash of hashes.
+Outer hash key is functions.
+Inner hash keys are chat,discussion,email,files,homepage,roster.
+Corresponding values are either on or off, depending on
+whether this type of functionality is available for the group.
+
+=cut
+                                                                                 
+###############################################
+
+sub get_group_settings {
+    my ($groupinfo)=@_;
+    my $parser=HTML::TokeParser->new(\$groupinfo);
+    my $token;
+    my $tool = '';
+    my $role = '';
+    my %content=();
+    while ($token=$parser->get_token) {
+        if ($token->[0] eq 'S')  {
+            my $entry=$token->[1];
+            if ($entry eq 'functions' || $entry eq 'autosec') {
+                %{$content{$entry}} = ();
+                $tool = $entry;
+            } elsif ($entry eq 'role') {
+                if ($tool eq 'autosec') {
+                    $role = $token->[2]{id};
+                }
+            } else {
+                my $value=$parser->get_text('/'.$entry);
+                if ($entry eq 'name') {
+                    if ($tool eq 'functions') {
+                        my $function = $token->[2]{id};
+                        $content{$tool}{$function} = $value;
+                    }
+                } elsif ($entry eq 'groupname') {
+                    $content{$entry}=&Apache::lonnet::unescape($value);
+                } elsif (($entry eq 'roles') || ($entry eq 'types') ||
+                         ($entry eq 'sectionpick') || ($entry eq 'defpriv')) {
+                    push(@{$content{$entry}},$value);
+                } elsif ($entry eq 'section') {
+                    if ($tool eq 'autosec'  && $role ne '') {
+                        push(@{$content{$tool}{$role}},$value);
+                    }
+                } else {
+                    $content{$entry}=$value;
+                }
+            }
+        } elsif ($token->[0] eq 'E') {
+            if ($token->[1] eq 'functions' || $token->[1] eq 'autosec') {
+                $tool = '';
+            } elsif ($token->[1] eq 'role') {
+                $role = '';
+            }
+
+        }
+    }
+    return %content;
+}
+
+sub check_group_access {
+    my ($group) = @_;
+    my $access = 1;
+    my $now = time;
+    my ($start,$end) = split(/\./,$env{'user.role.gr/'.$env{'request.course,id'}.'/'.$group});
+    if (($end!=0) && ($end<$now)) { $access = 0; }
+    if (($start!=0) && ($start>$now)) { $access=0; }
+    return $access;
+}
+
+###############################################
+
+=pod
+                                                                                
+=item get_course_users
+                                                                                
+Retrieves usernames:domains for users in the specified course
+with specific role(s), and access status. 
+
+Incoming parameters:
+1. course domain
+2. course number
+3. access status: users must have - either active, 
+previous, future, or all.
+4. reference to array of permissible roles
+5. reference to array of section restrictions (optional)
+6. reference to results object (hash of hashes).
+7. reference to optional userdata hash
+Keys of top level hash are roles.
+Keys of inner hashes are username:domain, with 
+values set to access type.
+Optional userdata hash returns an array with arguments in the 
+same order as loncoursedata::get_classlist() for student data.
+
+Entries for end, start, section and status are blank because
+of the possibility of multiple values for non-student roles.
+
+=cut
+                                                                                
+###############################################
+                                                                                
+sub get_course_users {
+    my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_;
+    my %idx = ();
+
+    $idx{udom} = &Apache::loncoursedata::CL_SDOM();
+    $idx{uname} =  &Apache::loncoursedata::CL_SNAME();
+    $idx{end} = &Apache::loncoursedata::CL_END();
+    $idx{start} = &Apache::loncoursedata::CL_START();
+    $idx{id} = &Apache::loncoursedata::CL_ID();
+    $idx{section} = &Apache::loncoursedata::CL_SECTION();
+    $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
+    $idx{status} = &Apache::loncoursedata::CL_STATUS();
+
+    if (grep(/^st$/,@{$roles})) {
+        my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist($cdom,$cnum);
+        my $now = time;
+        foreach my $student (keys(%{$classlist})) {
+            my $match = 0;
+            if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
+		unless(grep(/^\Q$$classlist{$student}[$idx{section}]\E$/,
+			    @{$sections})) {
+		    next;
 		}
-		if ($i<$#lines) {
-		    $i++;
-		    $lines[$i]=~
-		/Content\-Disposition\:\s*form\-data\;\s*name\=\"([^\"]+)\"/i;
-		    $name=$1;
-		    $value='';
-		    if ($lines[$i]=~/filename\=\"([^\"]+)\"/i) {
-			$fname=$1;
-			if 
-                            ($lines[$i+1]=~/Content\-Type\:\s*([\w\-\/]+)/i) {
-				$fmime=$1;
-				$i++;
-			    } else {
-				$fmime='';
-			    }
-		    } else {
-			$fname='';
-			$fmime='';
+            } 
+            if (defined($$types{'active'})) {
+                if ($$classlist{$student}[$idx{status}] eq 'Active') {
+                    push(@{$$users{st}{$student}},'active');
+                    $match = 1;
+                }
+            }
+            if (defined($$types{'previous'})) {
+                if ($$classlist{$student}[$idx{end}] <= $now) {
+                    push(@{$$users{st}{$student}},'previous');
+                    $match = 1;
+                }
+            }
+            if (defined($$types{'future'})) {
+                if (($$classlist{$student}[$idx{start}] > $now) && ($$classlist{$student}[$idx{end}] > $now) || ($$classlist{$student}[$idx{end}] == 0) || ($$classlist{$student}[$idx{end}] eq '')) {
+                    push(@{$$users{st}{$student}},'future');
+                    $match = 1;
+                }
+            }
+            if ($match && defined($userdata)) {
+                $$userdata{$student} = $$classlist{$student};
+            }
+        }
+    }
+    if ((@{$roles} > 0) && (@{$roles} ne "st")) {
+        my @coursepersonnel = &Apache::lonnet::getkeys('nohist_userroles',$cdom,$cnum);
+        foreach my $person (@coursepersonnel) {
+            my $match = 0;
+            my ($role,$user) = ($person =~ /^([^:]*):([^:]+:[^:]+)/);
+            $user =~ s/:$//;
+            if (($role) && (grep(/^\Q$role\E$/,@{$roles}))) {
+                my ($uname,$udom,$usec) = split(/:/,$user);
+                if ($usec ne '' && (ref($sections) eq 'ARRAY') && 
+		    @{$sections} > 0) {
+		    unless(grep(/^\Q$usec\E$/,@{$sections})) {
+			next;
 		    }
-		    $i++;
-		}
-	    } else {
-		$value.=$lines[$i]."\n";
-	    }
-	}
+                }
+                if ($uname ne '' && $udom ne '') {
+                    my $status = &check_user_status($udom,$uname,$cdom,$cnum,$role);
+                    foreach my $type (keys(%{$types})) { 
+                        if ($status eq $type) {
+                            @{$$users{$role}{$user}} = $type;
+                            $match = 1;
+                        }
+                    }
+                    if ($match && defined($userdata) &&
+                        !exists($$userdata{$uname.':'.$udom})) {
+			&get_user_info($udom,$uname,\%idx,$userdata);
+                    }
+                }
+            }
+        }
+        if (grep(/^ow$/,@{$roles})) {
+            if ((defined($cdom)) && (defined($cnum))) {
+                my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
+                if ( defined($csettings{'internal.courseowner'}) ) {
+                    my $owner = $csettings{'internal.courseowner'};
+                    @{$$users{'ow'}{$owner.':'.$cdom}} = 'any';
+                    if (defined($userdata) && 
+			!exists($$userdata{$owner.':'.$cdom})) {
+			&get_user_info($cdom,$owner,\%idx,$userdata);
+		    }
+                }
+            }
+        }
     }
-    $env{'request.method'}=$ENV{'REQUEST_METHOD'};
-    $r->method_number(M_GET);
-    $r->method('GET');
-    $r->headers_in->unset('Content-length');
+    return;
+}
+
+sub get_user_info {
+    my ($udom,$uname,$idx,$userdata) = @_;
+    $$userdata{$uname.':'.$udom}[$$idx{fullname}] = 
+	&plainname($uname,$udom,'lastname');
+    $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
+    $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
+    return;
 }
 
 =pod
@@ -3063,7 +3837,6 @@ sub get_unprocessed_cgi {
     if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
       $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) };
     }
   }
@@ -3106,6 +3879,10 @@ sub no_cache {
 
 sub content_type {
     my ($r,$type,$charset) = @_;
+    if ($r) {
+	#  Note that printout.pl calls this with undef for $r.
+	&no_cache($r);
+    }
     if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; }
     unless ($charset) {
 	$charset=&Apache::lonlocal::current_encoding;
@@ -3340,6 +4117,22 @@ sub upfile_select_html {
     return $Str;
 }
 
+sub get_samples {
+    my ($records,$toget) = @_;
+    my @samples=({});
+    my $got=0;
+    foreach my $rec (@$records) {
+	my %temp = &record_sep($rec);
+	if (! grep(/\S/, values(%temp))) { next; }
+	if (%temp) {
+	    $samples[$got]=\%temp;
+	    $got++;
+	    if ($got == $toget) { last; }
+	}
+    }
+    return \@samples;
+}
+
 ######################################################
 ######################################################
 
@@ -3357,18 +4150,15 @@ Apache Request ref, $records is an array
 ######################################################
 sub csv_print_samples {
     my ($r,$records) = @_;
-    my (%sone,%stwo,%sthree);
-    %sone=&record_sep($$records[0]);
-    if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
-    if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
-    #
+    my $samples = &get_samples($records,3);
+
     $r->print(&mt('Samples').'<br /><table border="2"><tr>');
-    foreach (sort({$a <=> $b} keys(%sone))) { 
+    foreach (sort({$a <=> $b} keys(%{ $samples->[0] }))) { 
         $r->print('<th>'.&mt('Column&nbsp;[_1]',($_+1)).'</th>'); }
     $r->print('</tr>');
-    foreach my $hash (\%sone,\%stwo,\%sthree) {
+    foreach my $hash (@$samples) {
 	$r->print('<tr>');
-	foreach (sort({$a <=> $b} keys(%sone))) {
+	foreach (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
 	    $r->print('<td>');
 	    if (defined($$hash{$_})) { $r->print($$hash{$_}); }
 	    $r->print('</td>');
@@ -3397,8 +4187,8 @@ $d is an array of 2 element arrays (inte
 ######################################################
 sub csv_print_select_table {
     my ($r,$records,$d) = @_;
-    my $i=0;my %sone;
-    %sone=&record_sep($$records[0]);
+    my $i=0;
+    my $samples = &get_samples($records,1);
     $r->print(&mt('Associate columns with student attributes.')."\n".
 	     '<table border="2"><tr>'.
               '<th>'.&mt('Attribute').'</th>'.
@@ -3410,7 +4200,7 @@ sub csv_print_select_table {
 	$r->print('<td><select name=f'.$i.
 		  ' onchange="javascript:flip(this.form,'.$i.');">');
 	$r->print('<option value="none"></option>');
-	foreach (sort({$a <=> $b} keys(%sone))) {
+	foreach (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
 	    $r->print('<option value="'.$_.'"'.
                       ($_ eq $defaultcol ? ' selected="selected" ' : '').
                       '>Column '.($_+1).'</option>');
@@ -3441,28 +4231,27 @@ $d is an array of 2 element arrays (inte
 ######################################################
 sub csv_samples_select_table {
     my ($r,$records,$d) = @_;
-    my %sone; my %stwo; my %sthree;
     my $i=0;
     #
+    my $samples = &get_samples($records,3);
     $r->print('<table border=2><tr><th>'.
               &mt('Field').'</th><th>'.&mt('Samples').'</th></tr>');
-    %sone=&record_sep($$records[0]);
-    if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
-    if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
-    #
-    foreach (sort keys %sone) {
+
+    foreach my $key (sort(keys(%{ $samples->[0] }))) {
 	$r->print('<tr><td><select name="f'.$i.'"'.
 		  ' onchange="javascript:flip(this.form,'.$i.');">');
-	foreach (@$d) {
-	    my ($value,$display,$defaultcol)=@{ $_ };
+	foreach my $option (@$d) {
+	    my ($value,$display,$defaultcol)=@{ $option };
 	    $r->print('<option value="'.$value.'"'.
                       ($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"); }
+	foreach my $line (0..2) {
+	    if (defined($samples->[$line]{$key})) { 
+		$r->print($samples->[$line]{$key}."<br />\n"); 
+	    }
+	}
 	$r->print('</td></tr>');
 	$i++;
     }
@@ -3551,7 +4340,7 @@ the routine &Apache::lonnet::transfer_pr
 my $uniq=0;
 sub get_cgi_id {
     $uniq=($uniq+1)%100000;
-    return (time.'_'.$uniq);
+    return (time.'_'.$$.'_'.$uniq);
 }
 
 ############################################################
@@ -3971,13 +4760,14 @@ 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 $udom  = $env{'user.domain'};
+    my $uname = $env{'user.name'};
     my ($prefix,$Settings) = @_;
     my %SaveHash;
     my %AppHash;
     while (my ($setting,$type) = each(%$Settings)) {
-        my $basename = 'internal.'.$prefix.'.'.$setting;
-        my $envname = 'course.'.$courseid.'.'.$basename;
+        my $basename = join('.','internal',$courseid,$prefix,$setting);
+        my $envname = 'environment.'.$basename;
         if (exists($env{'form.'.$setting})) {
             # Save this value away
             if ($type eq 'scalar' &&
@@ -4005,8 +4795,7 @@ sub store_course_settings {
         }
     }
     my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
-                                          $coursedom,
-                                          $env{'course.'.$courseid.'.num'});
+                                          $udom,$uname);
     if ($put_result !~ /^(ok|delayed)/) {
         &Apache::lonnet::logthis('unable to save form parameters, '.
                                  'got error:'.$put_result);
@@ -4021,7 +4810,7 @@ sub restore_course_settings {
     my ($prefix,$Settings) = @_;
     while (my ($setting,$type) = each(%$Settings)) {
         next if (exists($env{'form.'.$setting}));
-        my $envname = 'course.'.$courseid.'.internal.'.$prefix.
+        my $envname = 'environment.internal.'.$courseid.'.'.$prefix.
             '.'.$setting;
         if (exists($env{$envname})) {
             if ($type eq 'scalar') {