--- loncom/interface/loncommon.pm	2005/05/30 19:50:43	1.263
+++ loncom/interface/loncommon.pm	2005/12/01 23:04:08	1.300
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.263 2005/05/30 19:50:43 www Exp $
+# $Id: loncommon.pm,v 1.300 2005/12/01 23:04:08 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -152,19 +152,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);
@@ -379,7 +380,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 +403,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 +417,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(...)
@@ -673,7 +702,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,8 +712,8 @@ 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();
@@ -713,9 +741,9 @@ 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()
 }
@@ -1124,27 +1152,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;
@@ -1540,10 +1590,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;
 }
 
@@ -1575,14 +1626,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;
 }
 
@@ -1607,9 +1659,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;
 }
@@ -1634,9 +1686,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;
 }
@@ -1650,9 +1702,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;
 }
@@ -1868,12 +1920,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'},
@@ -1904,19 +1955,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;'; 
@@ -1929,6 +1968,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
 
@@ -1985,24 +2038,23 @@ 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>};
 }
 
-
-
 =pod
 
 =back
@@ -2485,7 +2537,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
 
@@ -2690,7 +2742,7 @@ 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)=@_;
     $title=&mt($title);
     $function = &get_users_function() if (!$function);
     my $img=&designparm($function.'.img',$domain);
@@ -2726,15 +2778,17 @@ sub bodytag {
 <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; }
 </style>
 <body bgcolor="$pgbg" text="$font" alink="$alink" vlink="$vlink" link="$link"
 style="margin-top: 0px;$addstyle" $addentries>
 END
+    &Apache::lontexconvert::jsMath_reset();
     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::jsMath_header();
     }
 
     my $upperleft='<img src="http://'.$ENV{'HTTP_HOST'}.':'.
@@ -2797,13 +2851,21 @@ ENDROLE
         }
         my $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 ($notopbar) {
+                $bodytag .= $titletable;
+            } else {
+                $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg,$titletable);
+            }
 	} else {
-            $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg).
+            if ($notopbar) {
+                $bodytag .= $titletable;
+            } else {
+                $bodytag .= &Apache::lonmenu::menubuttons($forcereg,'web',$forcereg).
                         $titletable;
+            }
         }
         return $bodytag;
     }
@@ -2881,10 +2943,7 @@ Returns: A uniform footer for LON-CAPA w
 
 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;
     return $endbodytag;
 }
 
@@ -2919,6 +2978,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
@@ -2937,11 +3050,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) {
@@ -2971,6 +3083,272 @@ sub get_sections {
     return $numsections;
 }
 
+###############################################
+                                                                                  
+=pod
+                                                                                  
+=item coursegroups
+
+Retrieve information about groups in a course,
+
+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
+whther 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 %content=();
+    while ($token=$parser->get_token) {
+        if ($token->[0] eq 'S')  {
+            my $entry=$token->[1];
+            if ($entry eq 'functions') {
+                %{$content{$entry}} = ();
+                $tool = $entry;
+            } 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);
+                } else {
+                    $content{$entry}=$value;
+                }
+            }
+        } elsif ($token->[0] eq 'E') {
+            if ($token->[1] eq 'functions') {
+                $tool = '';
+            }
+        }
+    }
+    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 (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;
+		    }
+                }
+                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);
+		    }
+                }
+            }
+        }
+    }
+    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;
+}
+
+###############################################
 
 sub get_posted_cgi {
     my $r=shift;
@@ -3066,7 +3444,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) };
     }
   }
@@ -3109,6 +3486,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;
@@ -3554,7 +3935,7 @@ the routine &Apache::lonnet::transfer_pr
 my $uniq=0;
 sub get_cgi_id {
     $uniq=($uniq+1)%100000;
-    return (time.'_'.$uniq);
+    return (time.'_'.$$.'_'.$uniq);
 }
 
 ############################################################
@@ -3974,13 +4355,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' &&
@@ -4008,8 +4390,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);
@@ -4024,7 +4405,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') {