--- loncom/interface/lonfeedback.pm	2004/11/19 19:11:33	1.141
+++ loncom/interface/lonfeedback.pm	2005/04/07 06:56:23	1.157
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Feedback
 #
-# $Id: lonfeedback.pm,v 1.141 2004/11/19 19:11:33 raeburn Exp $
+# $Id: lonfeedback.pm,v 1.157 2005/04/07 06:56:23 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -35,6 +35,7 @@ use Apache::lonmsg();
 use Apache::loncommon();
 use Apache::lontexconvert();
 use Apache::lonlocal; # must not have ()
+use Apache::lonnet;
 use Apache::lonhtmlcommon();
 use Apache::lonnavmaps;
 use Apache::lonenc();
@@ -61,17 +62,22 @@ sub discussion_visible {
     if (not &discussion_open($status)) {
 	my $hidden=&Apache::lonnet::EXT('resource.0.discusshide');
 	if (lc($hidden) eq 'yes' or $hidden eq '' or !defined($hidden))  {
-	    if (!$ENV{'request.role.adv'}) { return 0; }
+	    if (!$env{'request.role.adv'}) { return 0; }
 	}
     }
     return 1;
 }
 
 sub list_discussion {
-    my ($mode,$status,$ressymb)=@_;
-    my $outputtarget=$ENV{'form.grade_target'};
-    if (defined($ENV{'form.export'})) {
-	if($ENV{'form.export'}) {
+    my ($mode,$status,$ressymb,$imsextras)=@_;
+    my $outputtarget=$env{'form.grade_target'};
+    if (defined($env{'form.export'})) {
+	if($env{'form.export'}) {
+            $outputtarget = 'export';
+        }
+    }
+    if (defined($imsextras)) {
+        if ($$imsextras{'caller'} eq 'imsexport') {
             $outputtarget = 'export';
         }
     }
@@ -79,12 +85,12 @@ sub list_discussion {
     my @bgcols = ("#cccccc","#eeeeee");
     my $discussiononly=0;
     if ($mode eq 'board') { $discussiononly=1; }
-    unless ($ENV{'request.course.id'}) { return ''; }
-    my $crs='/'.$ENV{'request.course.id'};
-    my $cid=$ENV{'request.course.id'};
-    if ($ENV{'request.course.sec'}) {
-	$crs.='_'.$ENV{'request.course.sec'};
-    }                 
+    unless ($env{'request.course.id'}) { return ''; }
+    my $crs='/'.$env{'request.course.id'};
+    my $cid=$env{'request.course.id'};
+    if ($env{'request.course.sec'}) {
+	$crs.='_'.$env{'request.course.sec'};
+    }
     $crs=~s/\_/\//g;
     unless ($ressymb) {	$ressymb=&Apache::lonnet::symbread(); }
     unless ($ressymb) { return ''; }
@@ -107,7 +113,7 @@ sub list_discussion {
     my $toggkey = $ressymb.'_readtoggle';
     my $readkey = $ressymb.'_read';
     $ressymb=$encsymb;
-    my %dischash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$lastkey,$showkey,$markkey,$visitkey,$ondispkey,$userpickkey,$toggkey,$readkey],$ENV{'user.domain'},$ENV{'user.name'});
+    my %dischash = &Apache::lonnet::get('nohist_'.$env{'request.course.id'}.'_discuss',[$lastkey,$showkey,$markkey,$visitkey,$ondispkey,$userpickkey,$toggkey,$readkey],$env{'user.domain'},$env{'user.name'});
     my %discinfo = ();
     my $showonlyunread = 0;
     my $showunmark = 0; 
@@ -120,11 +126,22 @@ sub list_discussion {
 
 # Retain identification of "NEW" posts identified in last display, if continuing 'previous' browsing of posts.
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','totposters']);
-    my $sortposts = $ENV{'form.sortposts'};
-    my $statusfilter = $ENV{'form.statusfilter'};
-    my $sectionpick = $ENV{'form.sectionpick'};
-    my $totposters = $ENV{'form.totposters'};
-    $previous = $ENV{'form.previous'};
+    my $sortposts = $env{'form.sortposts'};
+    my $statusfilter = $env{'form.statusfilter'};
+    my @sectionpick = ();
+    if ($env{'form.sectionpick'} =~ /,/) {
+        @sectionpick = split/,/,$env{'form.sectionpick'};
+    } else {
+        $sectionpick[0] = $env{'form.sectionpick'};
+    }
+    my @rolefilter = ();
+    if ($env{'form.rolefilter'} =~ /,/) {
+        @rolefilter = split/,/,$env{'form.rolefilter'};
+    } else {
+        $rolefilter[0] = $env{'form.rolefilter'};
+    }
+    my $totposters = $env{'form.totposters'};
+    $previous = $env{'form.previous'};
     if ($previous > 0) {
         $prevread = $previous;
     } elsif (defined($dischash{$lastkey})) {
@@ -136,22 +153,27 @@ sub list_discussion {
 # Get information about students and non-students in course for filtering display of posts
     my %roleshash = ();
     my %roleinfo = ();
-    if ($ENV{'form.rolefilter'}) {
-        %roleshash = &Apache::lonnet::dump('nohist_userroles',$ENV{'course.'.$ENV{'request.course.id'}.'.domain'},$ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+    if ($env{'form.rolefilter'}) {
+        %roleshash = &Apache::lonnet::dump('nohist_userroles',$env{'course.'.$env{'request.course.id'}.'.domain'},$env{'course.'.$env{'request.course.id'}.'.num'});
         foreach (keys %roleshash) {
             my ($role,$uname,$udom,$sec) = split/:/,$_;
+            if ($role =~ /^cr/) {
+                $role = 'cr';
+            }
             my ($end,$start) = split/:/,$roleshash{$_};
             my $now = time;
             my $status = 'Active';
             if (($now < $start) || ($end > 0 && $now > $end)) {
                 $status = 'Expired';
             }
-            push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status;
+            if ($uname && $udom) { 
+                push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status;
+            }
         }
         my ($classlist) = &Apache::loncoursedata::get_classlist(
-                              $ENV{'request.course.id'},
-                              $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-                              $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+                              $env{'request.course.id'},
+                              $env{'course.'.$env{'request.course.id'}.'.domain'},
+                              $env{'course.'.$env{'request.course.id'}.'.num'});
         my $sec_index = &Apache::loncoursedata::CL_SECTION();
         my $status_index = &Apache::loncoursedata::CL_STATUS();
         while (my ($student,$data) = each %$classlist) {
@@ -162,10 +184,10 @@ sub list_discussion {
     }
 
 # Get discussion display default settings for user
-    if ($ENV{'environment.discdisplay'} eq 'unread') {
+    if ($env{'environment.discdisplay'} eq 'unread') {
         $showonlyunread = 1;
     }
-    if ($ENV{'environment.discmarkread'} eq 'ondisp') {
+    if ($env{'environment.discmarkread'} eq 'ondisp') {
         $markondisp = 1;
     }
 
@@ -215,16 +237,16 @@ sub list_discussion {
     my $maxdepth=0;
 
     my $target='';
-    unless ($ENV{'browser.interface'} eq 'textual' ||
-	    $ENV{'environment.remote'} eq 'off' ) {
+    unless ($env{'browser.interface'} eq 'textual' ||
+	    $env{'environment.remote'} eq 'off' ) {
 	$target='target="LONcom"';
     }
 
     my $now = time;
     $discinfo{$visitkey} = $visit;
 
-    &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
-    &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$encsymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$ENV{'form.rolefilter'},$sectionpick,$statusfilter,$toggkey,$outputtarget);
+    &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',\%discinfo,$env{'user.domain'},$env{'user.name'});
+    &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$encsymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,\@rolefilter,\@sectionpick,$statusfilter,$toggkey,$outputtarget);
 
     my $discussion='';
     my $manifestfile;
@@ -235,7 +257,7 @@ sub list_discussion {
 
     my $function = &Apache::loncommon::get_users_function();
     my $color = &Apache::loncommon::designparm($function.'.tabbg',
-                                                    $ENV{'user.domain'});
+                                                    $env{'user.domain'});
     my %lt = &Apache::lonlocal::texthash(
         'cuse' => 'Current discussion settings',
         'allposts' => 'All posts',
@@ -301,23 +323,34 @@ sub list_discussion {
     if ($visible) {
 # Print the discusssion
         if ($outputtarget eq 'tex') {
-            $discussion.='<tex>\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'.
+            $discussion.='<tex>{\tiny \vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'.
                          '\textbf{DISCUSSIONS}\makebox[2 cm][b]{\hrulefill}'.
                          '\vskip 0 mm\noindent\textbf{'.$lt{'cuse'}.'}:\vskip 0 mm'.
                          '\noindent\textbf{'.$lt{'disa'}.'}: \textit{'.$currdisp.'}\vskip 0 mm'.
-                         '\noindent\textbf{'.$lt{'npce'}.'}: \textit{'.$currmark.'}</tex>';
+                         '\noindent\textbf{'.$lt{'npce'}.'}: \textit{'.$currmark.'}}</tex>';
         } elsif ($outputtarget eq 'export') {
 # Create temporary directory if this is an export
             my $now = time;
-            $tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports';
-            if (!-e $tempexport) {
-                mkdir($tempexport,0700);
-            }
-            $tempexport .= '/'.$now;
-            if (!-e $tempexport) {
-                mkdir($tempexport,0700);
+            if ((defined($imsextras)) && ($$imsextras{'caller'} eq 'imsexport')) {
+                $tempexport = $$imsextras{'tempexport'};
+                if (!-e $tempexport) {
+                    mkdir($tempexport,0700);
+                }
+                $tempexport .= '/'.$$imsextras{'count'};
+                if (!-e $tempexport) {
+                    mkdir($tempexport,0700);
+                }
+            } else {
+                $tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports';
+                if (!-e $tempexport) {
+                    mkdir($tempexport,0700);
+                }
+                $tempexport .= '/'.$now;
+                if (!-e $tempexport) {
+                    mkdir($tempexport,0700);
+                }
+                $tempexport .= '/'.$env{'user.domain'}.'_'.$env{'user.name'};
             }
-            $tempexport .= '/'.$ENV{'user.domain'}.'_'.$ENV{'user.name'};
             if (!-e $tempexport) {
                 mkdir($tempexport,0700);
             }
@@ -397,7 +430,7 @@ imscp_v1p1.xsd http://www.imsglobal.org/
             if ($numhidden > 0) {
                 my $colspan = $maxdepth+1;
                 $discussion.="\n".'<tr><td bgcolor="#CCCCCC" colspan="'.$colspan.'">'.
-                         '<a href="/adm/feedback?allposts='.$ressymb;
+                         '<a href="/adm/feedback?allposts=1&amp;symb='.$ressymb;
                 if ($newpostsflag) {
                     $discussion .= '&previous='.$prevread;
                 }
@@ -435,13 +468,12 @@ imscp_v1p1.xsd http://www.imsglobal.org/
                  }
             }
         } else {
-            $sortposts = 'ascdate';
             @showposts =  (sort { $a <=> $b } keys %alldiscussion);
         }
         my $currdepth = 0;
         my $firstidx = $alldiscussion{$showposts[0]};
         foreach (@showposts) {
-            unless (($sortposts eq 'thread') || ($sortposts eq 'ascdate' && $ENV{'environment.threadeddiscussion'}) || ($outputtarget eq 'export')) {
+            unless (($sortposts eq 'thread') || (($sortposts eq '') && ($env{'environment.threadeddiscussion'})) || ($outputtarget eq 'export')) {
                 $alldiscussion{$_} = $_;
             }
             unless ( ($notshown{$alldiscussion{$_}} eq '1') || ($shown{$alldiscussion{$_}} == 0) ) {
@@ -481,8 +513,8 @@ imscp_v1p1.xsd http://www.imsglobal.org/
         $imsitems{$alldiscussion{$_}}{'isvisible'}.'" identifieref="RES-'.$ressymb.'-'.$alldiscussion{$_}.'">'.
         '<title>'.$imsitems{$alldiscussion{$_}}{'title'}.'</title>';
                         $imsresources .= "\n".
-    '<resource identifier="RES-'.$ressymb.'-'.$alldiscussion{$_}.'" type="webcontent" href="'.$postfilename.'">'.
-      '<file href="'.$alldiscussion{$_}.'.html">'."\n".
+    '<resource identifier="RES-'.$ressymb.'-'.$alldiscussion{$_}.'" type="webcontent" href="'.$postfilename.'">'."\n".
+      '<file href="'.$postfilename.'">'."\n".
       $imsfiles{$alldiscussion{$_}}{$imsitems{$alldiscussion{$_}}{'currversion'}}."\n".
     '</resource>';
                     }
@@ -539,13 +571,54 @@ END
             $discussion .= <<END;
                    </font></td>
                    <td>&nbsp;</td>
-                   <td>
+                   <td align="left">
                     <font size="-1"><b><a href="$chglink">$lt{'chgt'}</a>?</font></b>
                    </td>
                   </tr>
                  </table>
                 </td>
 END
+            if ($sortposts) {
+                my %sort_types = ();
+                my %role_types = ();
+                my %status_types = ();
+                &sort_filter_names(\%sort_types,\%role_types,\%status_types);
+
+                $discussion .= '<td><font size="-1"><b>'.&mt('Sorted by').'</b>: '.$sort_types{$sortposts}.'<br />';
+                if (defined($env{'form.totposters'})) {
+                    $discussion .= &mt('Posts by').':';
+                    if ($totposters > 0) {
+                        foreach my $poster (@posters) {
+                            $poster =~ s/:/\@/;
+                            $discussion .= ' '.$poster.',';
+                        }
+                        $discussion =~ s/,$//;
+                    } else {
+                        $discussion .= &mt('None selected');
+                    }
+                } else {
+                    my $filterchoice ='';
+                    if (@sectionpick > 0) {
+                        $filterchoice = '<i>'.&mt('sections').'</i>-&nbsp;'.$env{'form.sectionpick'};
+                        $filterchoice .= '&nbsp;&nbsp;&nbsp; ';
+                    }
+                    if (@rolefilter > 0) {
+                        $filterchoice .= '<i>'.&mt('roles').'</i>-';
+                        foreach (@rolefilter) {
+                            $filterchoice .= '&nbsp;'.$role_types{$_}.',';
+                        }
+                        $filterchoice =~ s/,$//;
+                        $filterchoice .= '<br />&nbsp;&nbsp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp&nbsp;';
+                    }
+                    if ($statusfilter) {
+                        $filterchoice .= '<i>'.&mt('status').'</i>-&nbsp;'.$status_types{$statusfilter};
+                    }
+                    if ($filterchoice) {
+                        $discussion .= '<b>'.&mt('Filters').'</b>:&nbsp;'.$filterchoice;
+                    }
+                    $discussion .= '</font></td>';
+                }
+            }
             if ($dischash{$toggkey}) {
                 my $storebutton = &mt('Store read/unread changes');
                 $discussion.='<td align="right">'.
@@ -578,27 +651,25 @@ END
 </manifest>
                 |;
                 close($manifestfile);
+                if ((defined($imsextras)) && ($$imsextras{'caller'} eq 'imsexport')) {
+                    $discussion = $copyresult;
+                } else {
 
 #Create zip file in prtspool
 
-                my $imszipfile = '/prtspool/'.
-                $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
-                     time.'_'.rand(1000000000).'.zip';
-    # zip can cause an sh launch which can pass along all of %ENV
-    # which can be too large for /bin/sh to handle
-                my %oldENV=%ENV;
-                undef(%ENV);
-                my $cwd = &getcwd(); 
-                my $imszip = '/home/httpd/'.$imszipfile;
-                chdir $tempexport;
-                open(OUTPUT, "zip -r $imszip *  2> /dev/null |");
-                close(OUTPUT);
-                chdir $cwd;
-                %ENV=%oldENV;
-                undef(%oldENV);
-                $discussion .= 'Download the zip file from <a href="'.$imszipfile.'">Discussion Posting Archive</a><br />';
-                if ($copyresult) {
-                    $discussion .= 'The following errors occurred during export - <br />'.$copyresult;
+                    my $imszipfile = '/prtspool/'.
+                    $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
+                         time.'_'.rand(1000000000).'.zip';
+                    my $cwd = &getcwd(); 
+                    my $imszip = '/home/httpd/'.$imszipfile;
+                    chdir $tempexport;
+                    open(OUTPUT, "zip -r $imszip *  2> /dev/null |");
+                    close(OUTPUT);
+                    chdir $cwd;
+                    $discussion .= 'Download the zip file from <a href="'.$imszipfile.'">Discussion Posting Archive</a><br />';
+                    if ($copyresult) {
+                        $discussion .= 'The following errors occurred during export - <br />'.$copyresult;
+                    }
                 }
             } else {
                 $discussion .= '<br />Unfortunately you will not be able to retrieve an archive of the discussion posts at this time, because there was a problem creating a manifest file.<br />';
@@ -614,10 +685,10 @@ END
         my @currdelold = ();
         my $comment = '';
         my $subject = '';
-        if ($ENV{'form.origpage'}) {
+        if ($env{'form.origpage'}) {
             &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['addnewattach','deloldattach','delnewattach','timestamp','idx','subject','comment']);
-            $subject = &Apache::lonnet::unescape($ENV{'form.subject'});
-            $comment = &Apache::lonnet::unescape($ENV{'form.comment'});
+            $subject = &Apache::lonnet::unescape($env{'form.subject'});
+            $comment = &Apache::lonnet::unescape($env{'form.comment'});
             my @keepold = ();
             &process_attachments(\@currnewattach,\@currdelold,\@keepold);
             if (@currnewattach > 0) {
@@ -638,8 +709,8 @@ to course faculty</font><br />
 <b>Title:</b>&nbsp;<input type="text" name="subject" value="$subject" size="30" /><br /><br />
 <textarea name="comment" cols="80" rows="14" wrap="hard">$comment</textarea>
 ENDDISCUSS
-            if ($ENV{'form.origpage'}) {
-                $discussion.='<input type="hidden" name="origpage" value="'.$ENV{'form.origpage'}.'" />'."\n";
+            if ($env{'form.origpage'}) {
+                $discussion.='<input type="hidden" name="origpage" value="'.$env{'form.origpage'}.'" />'."\n";
                 foreach (@currnewattach) {
                     $discussion.='<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n";
                 }
@@ -668,12 +739,12 @@ ENDDISCUSS
     } else {
         if (&discussion_open($status) &&
             &Apache::lonnet::allowed('pch',
-    	        $ENV{'request.course.id'}.
-	        ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
+    	        $env{'request.course.id'}.
+	        ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
 	    if ($outputtarget ne 'tex') {
 		$discussion.='<table bgcolor="#BBBBBB"><tr><td><a href="/adm/feedback?replydisc='.
 		    $ressymb.':::" '.$target.'>'.
-		    '<img src="/adm/lonMisc/chat.gif" border="0" />'.
+		    '<img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').'" border="0" />'.
 		    &mt('Post Discussion').'</a></td></tr></table>';
 	    }
 	}
@@ -683,19 +754,23 @@ ENDDISCUSS
 
 sub build_posting_display {
     my ($usernamesort,$subjectsort,$namesort,$notshown,$newitem,$dischash,$shown,$alldiscussion,$imsitems,$imsfiles,$roleinfo,$discussionitems,$replies,$depth,$posters,$maxdepth,$visible,$newpostsflag,$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$ressymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$statusfilter,$toggkey,$outputtarget) = @_;
-
     my @original=();
     my @index=();
     my $symb=&Apache::lonenc::check_decrypt($ressymb);
-    my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
-			  $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-			  $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+    my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+			  $env{'course.'.$env{'request.course.id'}.'.domain'},
+			  $env{'course.'.$env{'request.course.id'}.'.num'});
 
     if ($contrib{'version'}) {
         my $oldest = $contrib{'1:timestamp'};
         if ($prevread eq '0') {
             $prevread = $oldest-1;
         }
+        my ($skiptest,$rolematch,$roleregexp,$secregexp,$statusregexp);
+        if ($sortposts) {
+            ($skiptest,$roleregexp,$secregexp,$statusregexp) = &filter_regexp($rolefilter,$sectionpick,$statusfilter);
+            $rolematch = $roleregexp.':'.$secregexp.':'.$statusregexp;
+        } 
 	for (my $id=1;$id<=$contrib{'version'};$id++) {
 	    my $idx=$id;
             my $posttime = $contrib{$idx.':timestamp'};
@@ -708,7 +783,7 @@ sub build_posting_display {
 	    my $origindex='0.';
             my $numoldver=0;
 	    if ($contrib{$idx.':replyto'}) {
-                if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
+                if ( (($env{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
 # this is a follow-up message
 		    $original[$idx]=$original[$contrib{$idx.':replyto'}];
 		    $$depth[$idx]=$$depth[$contrib{$idx.':replyto'}]+1;
@@ -816,8 +891,8 @@ sub build_posting_display {
                             } else {
                                 @{$$namesort{$lastname}{$firstname}} = ("$idx");
                             }
-                            if ($ENV{'course.'.$ENV{'request.course.id'}.'.allow_discussion_post_editing'} =~ m/yes/i) {
-                                if (($ENV{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($ENV{'user.name'} eq $contrib{$idx.':sendername'})) {
+                            if ($env{'course.'.$env{'request.course.id'}.'.allow_discussion_post_editing'} =~ m/yes/i) {
+                                if (($env{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($env{'user.name'} eq $contrib{$idx.':sendername'})) {
                                     $sender.=' <a href="/adm/feedback?editdisc='.
                                          $ressymb.':::'.$idx;
                                     if ($newpostsflag) {
@@ -880,8 +955,8 @@ sub build_posting_display {
 		        }
 		        if (&discussion_open($status) &&
 			        &Apache::lonnet::allowed('pch',
-						 $ENV{'request.course.id'}.
-						 ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
+						 $env{'request.course.id'}.
+						 ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
 			    $sender.=' <a href="/adm/feedback?replydisc='.
 			            $ressymb.':::'.$idx;
                             if ($newpostsflag) {
@@ -894,16 +969,16 @@ sub build_posting_display {
                             $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$ressymb);
 		        }
                         if ($$dischash{$readkey}=~/\.$idx\./) { 
-                            $ctlink = '<b>'.&mt('Mark unread').'?</b>&nbsp;<input type="checkbox" name="postunread_'.$idx.'" />';
+                            $ctlink = '<label><b>'.&mt('Mark unread').'?</b>&nbsp;<input type="checkbox" name="postunread_'.$idx.'" /></label>';
                         } else {
-                            $ctlink = '<b>'.&mt('Mark read').'?</b>&nbsp;<input type="checkbox" name="postread_'.$idx.'" />';
+                            $ctlink = '<label><b>'.&mt('Mark read').'?</b>&nbsp;<input type="checkbox" name="postread_'.$idx.'" /></label>';
                         }
                     }
 #figure out at what position this needs to print
                 }
                 if ($outputtarget eq 'export' || $message) {
 		    my $thisindex=$idx;
-		    if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
+		    if ( (($env{'environment.threadeddiscussion'}) && ($sortposts eq '')) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
 			$thisindex=$origindex.substr('00'.$$replies[$$depth[$idx]],-2,2);
 		    }
 		    $$alldiscussion{$thisindex}=$idx;
@@ -944,46 +1019,33 @@ sub build_posting_display {
                             my $uname = $contrib{$idx.':sendername'};
                             my $udom = $contrib{$idx.':senderdomain'};
                             my $poster = $uname.':'.$udom;
-                            my $rolematch = '';
-                            my $skiptest = 1;
-                            if ($totposters > 0) {
-                                if (grep/^$poster$/,@{$posters}) {
-                                    $$shown{$idx} = 1;
-                                }
-                            } else {
-                                if ($rolefilter) {
-                                    if ($rolefilter eq 'all') {
-                                        $rolematch = '([^:]+)';
-                                    } else {
-                                        $rolematch = $rolefilter;
-                                        $skiptest = 0;
-                                    }
-                                }
-                                if ($sectionpick) {
-                                    if ($sectionpick eq 'all') {
-                                        $rolematch .= ':([^:]*)';
-                                    } else {
-                                        $rolematch .= ':'.$sectionpick;
-                                        $skiptest = 0;
-                                }
-                                if ($statusfilter) {
-                                    if ($statusfilter eq 'all') {
-                                        $rolematch .= ':([^:]+)';
-                                    } else {
-                                        $rolematch .= ':'.$statusfilter;
-                                        $skiptest = 0;
+                            if (defined($env{'form.totposters'})) {
+                                if ($totposters == 0) {
+                                    $$shown{$idx} = 0;
+                                } elsif ($totposters > 0) {
+                                    if (grep/^$poster$/,@{$posters}) {
+                                        $$shown{$idx} = 1;
                                     }
                                 }
+                            } elsif ($sortposts) {
                                 if ($skiptest) {
                                     $$shown{$idx} = 1;
                                 } else {
                                     foreach my $role (@{$$roleinfo{$poster}}) {
-                                        if ($role =~ m/^$rolematch$/) {
+                                        if ($role =~ /^cc:/) {
+                                            my $cc_regexp = $roleregexp.':[^:]*:'.$statusregexp;
+                                            if ($role =~ /$cc_regexp/) {
+                                                $$shown{$idx} = 1;
+                                                last;
+                                            }
+                                        } elsif ($role =~ /^$rolematch$/) {
                                             $$shown{$idx} = 1;
                                             last;
                                         }
                                     }
                                 }
+                            } else {
+                                $$shown{$idx} = 1;
                             }
                         }
                         unless ($$notshown{$idx} == 1) {
@@ -1033,6 +1095,60 @@ sub build_posting_display {
     }
 }
 
+sub filter_regexp {
+    my ($rolefilter,$sectionpick,$statusfilter) = @_;
+    my ($roleregexp,$secregexp,$statusregexp);
+    my $skiptest = 1;
+    if (@{$rolefilter} > 0) {
+        my @okrolefilter = ();
+        foreach (@{$rolefilter}) {
+            unless ($_ eq '') {
+                push @okrolefilter, $_;
+            }
+        }
+        if (@okrolefilter > 0) {
+            if (grep/^all$/,@okrolefilter) {
+                $roleregexp='[^:]+';
+            } else {
+                if (@okrolefilter == 1) {
+                    $roleregexp=$okrolefilter[0];
+                } else {
+                    $roleregexp='('.join('|',@okrolefilter).')';
+                }
+                $skiptest = 0;
+            }
+        }
+    }
+    if (@{$sectionpick} > 0) {
+        my @oksectionpick = ();
+        foreach (@{$sectionpick}) {
+            unless ($_ eq '') {
+                 push @oksectionpick, $_;
+            }
+        }
+        if ((@oksectionpick > 0) && (!grep/^all$/,@oksectionpick)) {
+            if (@oksectionpick == 1) {
+                $secregexp = $oksectionpick[0];
+            } else {
+                $secregexp .= '('.join('|',@oksectionpick).')';
+            }
+            $skiptest = 0;
+        } else {
+            $secregexp .= '[^:]*';
+        }
+    }
+    if (defined($statusfilter) && $statusfilter ne '') {
+        if ($statusfilter eq 'all') {
+            $statusregexp = '[^:]+';
+        } else {
+            $statusregexp = $statusfilter;
+            $skiptest = 0;
+        }
+    }
+    return ($skiptest,$roleregexp,$secregexp,$statusregexp);
+}
+
+
 sub get_post_contents {
     my ($contrib,$idx,$seeid,$type,$messages,$subjects,$allattachments,$attachtxt,$imsfiles,$screenname,$plainname,$numver) = @_;
     my $discussion = '';
@@ -1171,7 +1287,7 @@ sub replicate_attachments {
 
 sub mail_screen {
   my ($r,$feedurl,$options) = @_;
-  if (exists($ENV{'form.origpage'})) {
+  if (exists($env{'form.origpage'})) {
       &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','currnewattach','addnewattach','deloldattach','delnewattach','timestamp','idx','anondiscuss','discuss']);
   }
   my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion',
@@ -1205,11 +1321,11 @@ sub mail_screen {
    }
 END
   my $anonscript;
-  if (exists($ENV{'form.origpage'})) {
+  if (exists($env{'form.origpage'})) {
       $anonscript = (<<END);
   function setposttype() {
-      var anondisc = $ENV{'form.anondiscuss'};
-      var disc = $ENV{'form.discuss'};
+      var anondisc = $env{'form.anondiscuss'};
+      var disc = $env{'form.discuss'};
       if (anondisc == 1) {
           document.mailform.anondiscuss.checked = true
       }
@@ -1226,15 +1342,15 @@ END
   }
 END
   }
-  if (($ENV{'form.replydisc'}) || ($ENV{'form.editdisc'})) {
-      if ($ENV{'form.replydisc'}) {
-          ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'});
+  if (($env{'form.replydisc'}) || ($env{'form.editdisc'})) {
+      if ($env{'form.replydisc'}) {
+          ($symb,$idx)=split(/\:\:\:/,$env{'form.replydisc'});
       } else {
-          ($symb,$idx)=split(/\:\:\:/,$ENV{'form.editdisc'});
+          ($symb,$idx)=split(/\:\:\:/,$env{'form.editdisc'});
       }
-      my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
-					   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-					   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+      my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+					   $env{'course.'.$env{'request.course.id'}.'.domain'},
+					   $env{'course.'.$env{'request.course.id'}.'.num'});
       unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) {
           if ($contrib{$idx.':history'}) {
               if ($contrib{$idx.':history'} =~ /:/) {
@@ -1244,7 +1360,7 @@ END
                   $numoldver = 1;
               }
           }
-          if ($ENV{'form.replydisc'}) {
+          if ($env{'form.replydisc'}) {
               if ($contrib{$idx.':history'}) {
                   if ($contrib{$idx.':history'} =~ /:/) {
                       my @oldversions = split/:/,$contrib{$idx.':history'};
@@ -1280,7 +1396,7 @@ END
               if (defined($contrib{$idx.':replyto'})) {
                   $parentmsg = $contrib{$idx.':replyto'};
               }
-              unless (exists($ENV{'form.origpage'})) {
+              unless (exists($env{'form.origpage'})) {
                   my $anonflag = 0;
                   if ($contrib{$idx.':anonymous'}) {
                       $anonflag = 1;
@@ -1302,21 +1418,22 @@ END
               }
           }
       }
-      if ($ENV{'form.previous'}) {
-          $prevtag = '<input type="hidden" name="previous" value="'.$ENV{'form.previous'}.'" />';
+      if ($env{'form.previous'}) {
+          $prevtag = '<input type="hidden" name="previous" value="'.$env{'form.previous'}.'" />';
       }
   }
 
-  if ($ENV{'form.origpage'}) {
-      $subject = &Apache::lonnet::unescape($ENV{'form.subject'});
-      $comment = &Apache::lonnet::unescape($ENV{'form.comment'});
+  if ($env{'form.origpage'}) {
+      $subject = &Apache::lonnet::unescape($env{'form.subject'});
+      $comment = &Apache::lonnet::unescape($env{'form.comment'});
       &process_attachments(\@currnewattach,\@currdelold,\@keepold);
   }
   my $latexHelp=&Apache::loncommon::helpLatexCheatsheet();
   my $htmlheader=&Apache::lonhtmlcommon::htmlareaheaders();
   my $send=&mt('Send');
+  my $html=&Apache::lonxml::xmlbegin();
   $r->print(<<END);
-<html>
+$html
 <head>
 <title>The LearningOnline Network with CAPA</title>
 <meta http-equiv="pragma" content="no-cache"></meta>
@@ -1377,13 +1494,13 @@ enctype="multipart/form-data">
 $prevtag
 <input type="hidden" name="postdata" value="$feedurl" />
 END
-  if ($ENV{'form.replydisc'}) {
+  if ($env{'form.replydisc'}) {
       $r->print(<<END);
-<input type="hidden" name="replydisc" value="$ENV{'form.replydisc'}" />
+<input type="hidden" name="replydisc" value="$env{'form.replydisc'}" />
 END
-  } elsif ($ENV{'form.editdisc'}) {
+  } elsif ($env{'form.editdisc'}) {
      $r->print(<<END);
-<input type="hidden" name="editdisc" value ="$ENV{'form.editdisc'}" />
+<input type="hidden" name="editdisc" value ="$env{'form.editdisc'}" />
 <input type="hidden" name="parentmsg" value ="$parentmsg" />
 END
   }
@@ -1400,8 +1517,8 @@ Title: <input type="text" name="subject"
 </textarea></p>
 <p>
 END
-    if ( ($ENV{'form.editdisc'}) || ($ENV{'form.replydisc'}) ) {
-        if ($ENV{'form.origpage'}) {
+    if ( ($env{'form.editdisc'}) || ($env{'form.replydisc'}) ) {
+        if ($env{'form.origpage'}) {
             foreach (@currnewattach) {
                 $r->print('<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n");
             }
@@ -1409,7 +1526,7 @@ END
                 $r->print('<input type="hidden" name="deloldattach" value="'.$_.'" />'."\n");
             }
         }
-        if ($ENV{'form.editdisc'}) {
+        if ($env{'form.editdisc'}) {
             if ($attachmenturls) {
                 &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\%attachments,\%currattach,\@currdelold);
                 $attachnum = scalar(keys %currattach);
@@ -1431,11 +1548,11 @@ END
 </p>
 </form>
 END
-    if ($ENV{'form.editdisc'} || $ENV{'form.replydisc'}) {
+    if ($env{'form.editdisc'} || $env{'form.replydisc'}) {
         my $now = time;
         my $ressymb = $symb;
         my $postidx = '';
-        if ($ENV{'form.editdisc'}) {
+        if ($env{'form.editdisc'}) {
             $postidx = $idx;
         }
         if (@currnewattach > 0) {
@@ -1477,7 +1594,7 @@ sub print_display_options {
 
     my $function = &Apache::loncommon::get_users_function();
     my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
-                                                    $ENV{'user.domain'});
+                                                    $env{'user.domain'});
     my $bodytag=&Apache::loncommon::bodytag('Discussion options',
                                           '','');
 
@@ -1540,8 +1657,9 @@ sub print_display_options {
         $currtogg = $lt{'toggon'};
         $disctogg = 'toggon';
     }
+    my $html=&Apache::lonxml::xmlbegin();
     $r->print(<<END);
-<html>
+$html
 <head>
 <title>$lt{'dido'}</title>
 <meta http-equiv="pragma" content="no-cache" />
@@ -1632,18 +1750,18 @@ $lt{'sdpf'}<br/> $lt{'prca'}  <ol><li>$l
        <tr bgcolor="#dddddd">
        <td>$lt{'disa'}</td>
        <td>$lt{$discdisp}</td>
-       <td><input type="checkbox" name="discdisp" onClick="discdispChk('0')" />&nbsp;$lt{'chgt'} "$dispchangeA"
+       <td><label><input type="checkbox" name="discdisp" onClick="discdispChk('0')" />&nbsp;$lt{'chgt'} "$dispchangeA"</label>
            <br />
-           <input type="checkbox" name="discdisp" onClick="discdispChk('1')" />&nbsp;$lt{'chgt'} "$dispchangeB"
+           <label><input type="checkbox" name="discdisp" onClick="discdispChk('1')" />&nbsp;$lt{'chgt'} "$dispchangeB"</label>
        </td>
       </tr><tr bgcolor="#eeeeee">
        <td>$lt{'npmr'}</td>
        <td>$lt{$discmark}</td>
-       <td><input type="checkbox" name="discmark" />$lt{'chgt'} "$markchange"</td>
+       <td><label><input type="checkbox" name="discmark" />$lt{'chgt'} "$markchange"</label></td>
       </tr><tr bgcolor="#dddddd">
        <td>$lt{'dotm'}</td>
        <td>$lt{$disctogg}</td>
-       <td><input type="checkbox" name="disctogg" onClick="discdispChk('2')" />$lt{'chgt'} "$toggchange"</td>
+       <td><label><input type="checkbox" name="disctogg" onClick="discdispChk('2')" />$lt{'chgt'} "$toggchange"</label></td>
       </tr>
      </table>
     </td>
@@ -1681,30 +1799,13 @@ sub print_sortfilter_options {
     my $section_sel = '';
     my $numsections = 0;
     my $numvisible = 5;
-    my ($classlist) = &Apache::loncoursedata::get_classlist(
-                              $ENV{'request.course.id'},
-                              $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-                              $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
-                                                                                   
-    my $sec_index = &Apache::loncoursedata::CL_SECTION();
-    my $status_index = &Apache::loncoursedata::CL_STATUS();
     my %sectioncount = ();
-    while (my ($student,$data) = each %$classlist) {
-        my ($section,$status) = ($data->[$sec_index],
-                                 $data->[$status_index]);
-        unless ($section eq '' || $section =~ /^\s*$/) {
-            if (!defined($sectioncount{$section})) {
-                $sectioncount{$section} = 1;
-                $numsections ++;
-            } else {
-                $sectioncount{$section} ++;
-            }
-        }
-    }
-                                                                                   
-    if ($ENV{'request.course.sec'} !~ /^\s*$/) {
-        @sections = ($ENV{'request.course.sec'});
-        $numvisible = 1;
+
+    $numsections = &Apache::loncommon::get_sections($env{'course.'.$env{'request.course.id'}.'.domain'},$env{'course.'.$env{'request.course.id'}.'.num'},\%sectioncount);
+
+    if ($env{'request.course.sec'} !~ /^\s*$/) {  #Restrict section choice to current section 
+        @sections = ('all',$env{'request.course.sec'});
+        $numvisible = 2;
     } else {
         @sections = sort {$a cmp $b} keys(%sectioncount);
         unshift(@sections,'all'); # Put 'all' at the front of the list
@@ -1718,7 +1819,7 @@ sub print_sortfilter_options {
                                                                                    
     my $function = &Apache::loncommon::get_users_function();
     my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
-                                                    $ENV{'user.domain'});
+                                                    $env{'user.domain'});
     my $bodytag=&Apache::loncommon::bodytag('Discussion options',
                                           '','');
     my %lt = &Apache::lonlocal::texthash(
@@ -1726,19 +1827,49 @@ sub print_sortfilter_options {
         'diop' => 'Display Options',
         'curr' => 'Current setting ',
         'actn' => 'Action',
-        'prca' => 'Options can be set that control the sort order of the posts, in addition to which posts are displayed.',
+        'prca' => 'Set options that control the sort order of posts, and/or which posts are displayed.',
         'soor' => 'Sort order',
-        'disp' => 'Specific user roles',
-        'actv' => 'Specific role status',
+        'spur' => 'Specific user roles',
+        'sprs' => 'Specific role status',
         'spse' => 'Specific sections',
         'psub' => 'Pick specific users (by name)',
         'shal' => 'Show a list of current posters'
     );
+
+    my %sort_types = ();
+    my %role_types = ();
+    my %status_types = ();
+    &sort_filter_names(\%sort_types,\%role_types,\%status_types);
+    my $html=&Apache::lonxml::xmlbegin();
     $r->print(<<END);
-<html>
+$html
 <head>
 <title>$lt{'diso'}</title>
 <meta http-equiv="pragma" content="no-cache" />
+<script type="text/javascript">
+function verifyFilter() {
+    var rolenum = 0
+    for (var i=0; i<document.modifyshown.rolefilter.length; i++) {
+        if (document.modifyshown.rolefilter.options[i].selected == true) {
+            rolenum ++
+        }
+    }
+    if (rolenum == 0) {
+        document.modifyshown.rolefilter.options[0].selected = true
+    }
+
+    var secnum = 0
+    for (var i=0; i<document.modifyshown.sectionpick.length; i++) {
+        if (document.modifyshown.sectionpick.options[i].selected == true) {
+            secnum ++
+        }
+    }
+    if (secnum == 0) {
+        document.modifyshown.sectionpick.options[0].selected = true
+    }
+    document.modifyshown.submit();
+}
+</script>
 </head>
 $bodytag
 <form name="modifyshown" method="post" action="/adm/feedback">
@@ -1748,60 +1879,61 @@ $bodytag
  <tr>
   <td><b>$lt{'soor'}</b></td>
   <td>&nbsp;</td>
-  <td><b>$lt{'disp'}</b></td>
+  <td><b>$lt{'sprs'}</b></td>
   <td>&nbsp;</td>
-  <td><b>$lt{'actv'}</b></td>
+  <td><b>$lt{'spur'}</b></td>
   <td>&nbsp;</td>
   <td><b>$lt{'spse'}</b></td>
   <td>&nbsp;</td>
   <td><b>$lt{'psub'}</b></td>
  </tr>
  <tr>
-  <td>
+  <td align="center">
    <select name="sortposts">
-    <option value="ascdate" />Date order - oldest first
-    <option value="descdate" />Date order - newest first
-    <option value="thread" />Threaded
-    <option value="subject" />By subject
-    <option value="username" />By domain and username
-    <option value="lastfirst" />By last name, first name
+    <option value="ascdate" selected="selected" />$sort_types{'ascdate'}
+    <option value="descdate" />$sort_types{'descdate'}
+    <option value="thread" />$sort_types{'thread'}
+    <option value="subject" />$sort_types{'subject'}
+    <option value="username" />$sort_types{'username'}
+    <option value="lastfirst" />$sort_types{'lastfirst'}
    </select>
   </td>
   <td>&nbsp;</td>
-  <td>
-   <select name="rolefilter" multiple="true" size="5">
-    <option value="all" />All users
-    <option value="st" />Students
-    <option value="cc" />Course Coordinators
-    <option value="in" />Instructors
-    <option value="ta" />TAs
-    <option value="pr" />Exam proctors
-    <option value="cr" />Custom roles
+  <td align="center">
+   <select name="statusfilter">
+    <option value="all" selected="selected" />$status_types{'all'}
+    <option value="Active" />$status_types{'Active'}
+    <option value="Expired" />$status_types{'Expired'}
    </select>
   </td>
   <td>&nbsp;</td>
-  <td>
-   <select name="statusfilter">
-    <option value="all" />Roles of any status
-    <option value="Active" />Only active roles
-    <option value="Expired" />Only inactive roles
+  <td align="center">
+   <select name="rolefilter" multiple="true" size="5">
+    <option value="all" />$role_types{'all'}
+    <option value="st" />$role_types{'st'}
+    <option value="cc" />$role_types{'cc'}
+    <option value="in" />$role_types{'in'}
+    <option value="ta" />$role_types{'ta'}
+    <option value="ep" />$role_types{'ep'}
+    <option value="ad" />$role_types{'ad'}
+    <option value="cr" />$role_types{'cr'}
    </select>
   </td>
   <td>&nbsp;</td>
-  <td>
+  <td align="center">
    <select name="sectionpick" multiple="true" size="$numvisible">
     $section_sel
    </select>
   </td>
   <td>&nbsp;</td>
-  <td><input type="checkbox" name="posterlist" value="$symb" />$lt{'shal'}</td>
+  <td><label><input type="checkbox" name="posterlist" value="$symb" />$lt{'shal'}</label></td>
  </tr>
 </table>
 <br />
 <br />
 <input type="hidden" name="previous" value="$previous" />
 <input type="hidden" name="applysort" value="$symb" />
-<input type="button" name="sub" value="Store Changes" onClick="javascript:document.modifyshown.submit()" />
+<input type="button" name="sub" value="Store Changes" onClick="verifyFilter()" />
 <br />
 <br />
 </form>
@@ -1813,16 +1945,19 @@ END
 sub print_showposters {
     my ($r,$symb,$previous,$feedurl,$sortposts) = @_;
 
+    &Apache::loncommon::content_type($r,'text/html');
+    $r->send_http_header;
+
     &Apache::lonenc::check_encrypt(\$symb);
-    my $crs='/'.$ENV{'request.course.id'};
-    if ($ENV{'request.course.sec'}) {
-        $crs.='_'.$ENV{'request.course.sec'};
+    my $crs='/'.$env{'request.course.id'};
+    if ($env{'request.course.sec'}) {
+        $crs.='_'.$env{'request.course.sec'};
     }
     $crs=~s/\_/\//g;
     my $seeid=&Apache::lonnet::allowed('rin',$crs);
-    my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
-                          $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-                          $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+    my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+                          $env{'course.'.$env{'request.course.id'}.'.domain'},
+                          $env{'course.'.$env{'request.course.id'}.'.num'});
     my %namesort = ();
     my %postcounts = ();
     my %lt=&Apache::lonlocal::texthash(
@@ -1861,8 +1996,9 @@ sub print_showposters {
             }
         }
     }
+    my $html=&Apache::lonxml::xmlbegin();
     $r->print(<<END);
-<html>
+$html
 <head>
 <title>$lt{'diso'}</title>
 <meta http-equiv="pragma" content="no-cache" />
@@ -1889,7 +2025,7 @@ END
                     next;
                 } else {
                     $count ++;
-                    $r->print('<tr bgcolor="#ffffe6"><td align="right">'.$count.'</td><td align="center"><input name="stuinfo" type="checkbox" value="'.$_.'" /></td><td>'.$last.', '.$first.' ('.$uname.','.$udom.')</td><td>'.$postcounts{$_}.'</td></tr>');
+                    $r->print('<tr bgcolor="#ffffe6"><td align="right">'.$count.'</td><td align="center"><label><input name="stuinfo" type="checkbox" value="'.$_.'" /></td><td>'.$last.', '.$first.' ('.$uname.','.$udom.')</label></td><td>'.$postcounts{$_}.'</td></tr>');
                 }
             }
         }
@@ -1970,17 +2106,20 @@ sub get_post_attachments {
     return;
 }
 
-sub fail_redirect {;
+sub fail_redirect {
   my ($r,$feedurl) = @_;
   if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
+  my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
+  my $html=&Apache::lonxml::xmlbegin();
   $r->print (<<ENDFAILREDIR);
-<html>
-<head><title>Feedback not sent</title>
+$html
+<head>
+<title>Feedback not sent</title>
 <meta http-equiv="pragma" content="no-cache" />
 <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
 </head>
 <body bgcolor="#FFFFFF">
-<img align="right" src="/adm/lonIcons/lonlogos.gif" />
+<img align="right" src="$logo" />
 <b>Sorry, no recipients  ...</b>
 <br /><a href="$feedurl">Continue</a>
 </body>
@@ -1989,7 +2128,7 @@ ENDFAILREDIR
 }
 
 sub redirect_back {
-  my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status,$previous,$sort,$rolefilter,$statusfilter,$secpick,$numpicks) = @_;
+  my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$numpicks) = @_;
   my $sorttag = '';
   my $roletag = '';
   my $statustag = '';
@@ -2020,30 +2159,55 @@ sub redirect_back {
           $feedurl .= '?'.$sortqry;
       }
       $sorttag = '<input type="hidden" name="sortposts" value="'.$sort.'" />';
-      if ( (defined($numpicks)) && ($numpicks > 0) ) {
+      if (defined($numpicks)) {
           my $userpickqry = 'totposters='.$numpicks;
           $feedurl .= '&'.$userpickqry;
           $userpicktag = '<input type="hidden" name="totposters" value="'.$numpicks.'" />';
       } else {
-          my $roleqry = 'rolefilter='.$rolefilter;
-          $feedurl .= '&'.$roleqry;
-          $roletag = '<input type="hidden" name="rolefilter" value="'.$rolefilter.'" />';
+          if (ref($sectionpick) eq 'ARRAY') {
+              $feedurl .= '&sectionpick=';
+              $sectag .=  '<input type="hidden" name="sectionpick" value="';
+              foreach (@{$sectionpick}) {
+                  $feedurl .= $_.',';
+                  $sectag .= $_.',';
+              }
+              $feedurl =~ s/,$//;
+              $sectag =~ s/,$//;
+              $sectag .= '" />';
+          } else {
+              $feedurl .= '&sectionpick='.$sectionpick;
+              $sectag = '<input type="hidden" name="sectionpick" value="'.$sectionpick.'" />';
+          }
+          if (ref($rolefilter) eq 'ARRAY') {
+              $feedurl .= '&rolefilter=';
+              $roletag .=  '<input type="hidden" name="rolefilter" value="';
+              foreach (@{$rolefilter}) {
+                  $feedurl .= $_.',';
+                  $roletag .= $_.',';
+              }
+              $feedurl =~ s/,$//;
+              $roletag =~ s/,$//;
+              $roletag .= '" />';
+          } else {
+              $feedurl .= '&rolefilter='.$rolefilter;
+              $roletag = '<input type="hidden" name="rolefilter" value="'.$rolefilter.'" />';
+          }
           $feedurl .= '&statusfilter='.$statusfilter;
           $statustag ='<input type="hidden" name="statusfilter" value="'.$statusfilter.'" />';
-          $feedurl .= '&sectionpick='.$secpick;
-          $sectag = '<input type="hidden" name="sectionpick" value="'.$secpick.'" />';
       }
   }
   $feedurl=&Apache::lonenc::check_encrypt($feedurl);
+  my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
+  my $html=&Apache::lonxml::xmlbegin();
   $r->print (<<ENDREDIR);
-<html>
+$html
 <head>
 <title>Feedback sent</title>
 <meta http-equiv="pragma" content="no-cache" />
 <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
 </head>
 <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'>
-<img align="right" src="/adm/lonIcons/lonlogos.gif" />
+<img align="right" src="$logo" />
 $typestyle
 <b>Sent $sendsomething message(s), and $sendposts post(s).</b>
 <font color="red">$status</font>
@@ -2065,9 +2229,11 @@ sub no_redirect_back {
   my ($r,$feedurl) = @_;
   my $nofeed=&mt('Sorry, no feedback possible on this resource  ...');
   my $continue=&mt('Continue');
+  my $html=&Apache::lonxml::xmlbegin();
   $r->print (<<ENDNOREDIR);
-<html>
-<head><title>Feedback not sent</title>
+$html
+<head>
+<title>Feedback not sent</title>
 <meta http-equiv="pragma" content="no-cache" />
 ENDNOREDIR
 
@@ -2076,10 +2242,11 @@ ENDNOREDIR
 		&Apache::lonenc::check_encrypt($feedurl).'">');
   }
   $feedurl=&Apache::lonenc::check_encrypt($feedurl);
+  my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
   $r->print (<<ENDNOREDIRTWO);
 </head>
 <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { self.close(); }'>
-<img align="right" src="/adm/lonIcons/lonlogos.gif" />
+<img align="right" src="$logo" />
 <b>$nofeed</b>
 <br /><a href="$feedurl">$continue</a>
 </body>
@@ -2091,44 +2258,46 @@ sub screen_header {
     my ($feedurl,$symb) = @_;
     my $msgoptions='';
     my $discussoptions='';
-    unless (($ENV{'form.replydisc'}) || ($ENV{'form.editdisc'})) {
+    unless (($env{'form.replydisc'}) || ($env{'form.editdisc'})) {
 	if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/)) {
 	    $msgoptions= 
-		'<p><input type="checkbox" name="author" /> '.
-		&mt('Feedback to resource author').'</p>';
+		'<p><label><input type="checkbox" name="author" /> '.
+		&mt('Feedback to resource author').'</label></p>';
 	}
 	if (&feedback_available(1)) {
 	    $msgoptions.=
-		'<br /><input type="checkbox" name="question" /> '.
-		&mt('Question about resource content');
+		'<p><label><input type="checkbox" name="question" /> '.
+		&mt('Question about resource content').'</label></p>';
 	}
 	if (&feedback_available(0,1)) {
 	    $msgoptions.=
-		'<br /><input type="checkbox" name="course" /> '.
-		&mt('Question/Comment/Feedback about course content');
+		'<p><label><input type="checkbox" name="course" /> '.
+		&mt('Question/Comment/Feedback about course content').
+		'</label></p>';
 	}
 	if (&feedback_available(0,0,1)) {
 	    $msgoptions.=
-		'<br /><input type="checkbox" name="policy" /> '.
-		&mt('Question/Comment/Feedback about course policy');
+		'<p><label><input type="checkbox" name="policy" /> '.
+		&mt('Question/Comment/Feedback about course policy').
+		'</label></p>';
 	}
     }
-    if ($ENV{'request.course.id'}) {
+    if ($env{'request.course.id'}) {
 	if (&discussion_open(undef,$symb) &&
 	    &Apache::lonnet::allowed('pch',
-				     $ENV{'request.course.id'}.
-				     ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
-	    $discussoptions='<input type="checkbox" name="discuss" onClick="this.form.anondiscuss.checked=false;" '.
-		($ENV{'form.replydisc'}?' checked="1"':'').' /> '.
+				     $env{'request.course.id'}.
+				     ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
+	    $discussoptions='<label><input type="checkbox" name="discuss" onClick="this.form.anondiscuss.checked=false;" '.
+		($env{'form.replydisc'}?' checked="1"':'').' /> '.
 		&mt('Contribution to course discussion of resource');
-	    $discussoptions.='<br /><input type="checkbox" name="anondiscuss" onClick="this.form.discuss.checked=false;" /> '.
+	    $discussoptions.='</label><br /><label><input type="checkbox" name="anondiscuss" onClick="this.form.discuss.checked=false;" /> '.
 		&mt('Anonymous contribution to course discussion of resource').
-		' <i>('.&mt('name only visible to course faculty').')</i>';
+		' <i>('.&mt('name only visible to course faculty').')</i></label>';
         }
     }
-    if ($msgoptions) { $msgoptions='<h2><img src="/adm/lonMisc/feedback.gif" />'.&mt('Sending Messages').'</h2>'.$msgoptions; }
+    if ($msgoptions) { $msgoptions='<h2><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/feedback.gif').'" />'.&mt('Sending Messages').'</h2>'.$msgoptions; }
     if ($discussoptions) { 
-	$discussoptions='<h2><img src="/adm/lonMisc/chat.gif" />'.&mt('Discussion Contributions').'</h2>'.$discussoptions; }
+	$discussoptions='<h2><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').'" />'.&mt('Discussion Contributions').'</h2>'.$discussoptions; }
     return $msgoptions.$discussoptions;
 }
 
@@ -2151,15 +2320,15 @@ sub clear_out_html {
 # Always allow the <m>-tag
   my %html=(M=>1);
 # Check if more is allowed
-  my $cid=$ENV{'request.course.id'};
-  if (($ENV{"course.$cid.allow_limited_html_in_feedback"} =~ m/yes/i) ||
+  my $cid=$env{'request.course.id'};
+  if (($env{"course.$cid.allow_limited_html_in_feedback"} =~ m/yes/i) ||
       ($override)) {
       # allows <B> <I> <P> <A> <LI> <OL> <UL> <EM> <BR> <TT> <STRONG> 
       # <BLOCKQUOTE> <DIV .*> <DIV> <IMG> <M> <SPAN> <H1> <H2> <H3> <H4> <SUB>
       # <SUP>
       %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1,
 	     BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, DIV=>1, IMG=>1,
-	     M=>1, SUB=>1, SUP=>1, SPAN=>1, 
+	     M=>1, ALGEBRA=>1, SUB=>1, SUP=>1, SPAN=>1, 
 	     H1=>1, H2=>1, H3=>1, H4=>1, H5=>1);
   }
 # Do the substitution of everything that is not explicitly allowed
@@ -2195,7 +2364,7 @@ sub secapply {
     my ($adr,$sections)=($rec=~/^([^\(]+)\(([^\)]+)\)/);
     if ($sections) {
 	foreach (split(/\;/,$sections)) {
-            if (($_ eq $ENV{'request.course.sec'}) ||
+            if (($_ eq $env{'request.course.sec'}) ||
                 ($defaultflag && ($_ eq '*'))) {
                 return $adr; 
             }
@@ -2210,33 +2379,33 @@ sub decide_receiver {
   my ($feedurl,$author,$question,$course,$policy,$defaultflag) = @_;
   my $typestyle='';
   my %to=();
-  if ($ENV{'form.author'}||$author) {
+  if ($env{'form.author'}||$author) {
     $typestyle.='Submitting as Author Feedback<br>';
     $feedurl=~/^\/res\/(\w+)\/(\w+)\//;
     $to{$2.':'.$1}=1;
   }
-  if ($ENV{'form.question'}||$question) {
+  if ($env{'form.question'}||$question) {
     $typestyle.='Submitting as Question<br>';
     foreach (split(/\,/,
-		   $ENV{'course.'.$ENV{'request.course.id'}.'.question.email'})
+		   $env{'course.'.$env{'request.course.id'}.'.question.email'})
 	     ) {
 	my $rec=&secapply($_,$defaultflag);
         if ($rec) { $to{$rec}=1; }
     } 
   }
-  if ($ENV{'form.course'}||$course) {
+  if ($env{'form.course'}||$course) {
     $typestyle.='Submitting as Comment<br />';
     foreach (split(/\,/,
-		   $ENV{'course.'.$ENV{'request.course.id'}.'.comment.email'})
+		   $env{'course.'.$env{'request.course.id'}.'.comment.email'})
 	     ) {
 	my $rec=&secapply($_,$defaultflag);
         if ($rec) { $to{$rec}=1; }
     } 
   }
-  if ($ENV{'form.policy'}||$policy) {
+  if ($env{'form.policy'}||$policy) {
     $typestyle.='Submitting as Policy Feedback<br />';
     foreach (split(/\,/,
-		   $ENV{'course.'.$ENV{'request.course.id'}.'.policy.email'})
+		   $env{'course.'.$env{'request.course.id'}.'.policy.email'})
 	     ) {
 	my $rec=&secapply($_,$defaultflag);
         if ($rec) { $to{$rec}=1; }
@@ -2296,40 +2465,40 @@ sub adddiscuss {
 	$realsymb=&Apache::lonnet::symbread($filename);
     }
     if (&discussion_open(undef,$realsymb) &&
-	&Apache::lonnet::allowed('pch',$ENV{'request.course.id'}.
-        ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
+	&Apache::lonnet::allowed('pch',$env{'request.course.id'}.
+        ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
 
     my %contrib=('message'      => $email,
-                 'sendername'   => $ENV{'user.name'},
-                 'senderdomain' => $ENV{'user.domain'},
-                 'screenname'   => $ENV{'environment.screenname'},
-                 'plainname'    => $ENV{'environment.firstname'}.' '.
-		                   $ENV{'environment.middlename'}.' '.
-                                   $ENV{'environment.lastname'}.' '.
-                                   $ENV{'enrironment.generation'},
+                 'sendername'   => $env{'user.name'},
+                 'senderdomain' => $env{'user.domain'},
+                 'screenname'   => $env{'environment.screenname'},
+                 'plainname'    => $env{'environment.firstname'}.' '.
+		                   $env{'environment.middlename'}.' '.
+                                   $env{'environment.lastname'}.' '.
+                                   $env{'enrironment.generation'},
                  'attachmenturl'=> $attachmenturl,
                  'subject'      => $subject);
-    if ($ENV{'form.replydisc'}) {
-	$contrib{'replyto'}=(split(/\:\:\:/,$ENV{'form.replydisc'}))[1];
+    if ($env{'form.replydisc'}) {
+	$contrib{'replyto'}=(split(/\:\:\:/,$env{'form.replydisc'}))[1];
     }
     if ($anon) {
 	$contrib{'anonymous'}='true';
     }
     if (($symb) && ($email)) {
-        if ($ENV{'form.editdisc'}) {
+        if ($env{'form.editdisc'}) {
             my %newcontrib = ();
             $contrib{'ip'}=$ENV{'REMOTE_ADDR'};
             $contrib{'host'}=$Apache::lonnet::perlvar{'lonHostID'};
             $contrib{'timestamp'} = time;
             $contrib{'history'} = '';
             my $numoldver = 0;
-            my ($oldsymb,$oldidx)=split(/\:\:\:/,$ENV{'form.editdisc'});
+            my ($oldsymb,$oldidx)=split(/\:\:\:/,$env{'form.editdisc'});
 	    &Apache::lonenc::check_decrypt(\$oldsymb);
             $oldsymb=~s|(bulletin___\d+___)adm/wrapper/|$1|;
 # get timestamp for last post and history
-            my %oldcontrib=&Apache::lonnet::restore($oldsymb,$ENV{'request.course.id'},
-                     $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-                     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+            my %oldcontrib=&Apache::lonnet::restore($oldsymb,$env{'request.course.id'},
+                     $env{'course.'.$env{'request.course.id'}.'.domain'},
+                     $env{'course.'.$env{'request.course.id'}.'.num'});
             if (defined($oldcontrib{$oldidx.':replyto'})) {
                 $contrib{'replyto'} = $oldcontrib{$oldidx.':replyto'};
             }
@@ -2364,22 +2533,22 @@ sub adddiscuss {
                 my $key = $oldidx.':'.&Apache::lonnet::escape($oldsymb).':'.$_;                                                                               
                 $newcontrib{$key} = $contrib{$_};
             }
-            my $put_reply = &Apache::lonnet::putstore($ENV{'request.course.id'},
+            my $put_reply = &Apache::lonnet::putstore($env{'request.course.id'},
                   \%newcontrib,
-                  $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-                  $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+                  $env{'course.'.$env{'request.course.id'}.'.domain'},
+                  $env{'course.'.$env{'request.course.id'}.'.num'});
             $status='Editing class discussion'.($anon?' (anonymous)':'');
         } else {
            $status='Adding to class discussion'.($anon?' (anonymous)':'').': '.
-           &Apache::lonnet::store(\%contrib,$symb,$ENV{'request.course.id'},
-                     $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+           &Apache::lonnet::store(\%contrib,$symb,$env{'request.course.id'},
+                     $env{'course.'.$env{'request.course.id'}.'.domain'},
+		     $env{'course.'.$env{'request.course.id'}.'.num'});
         }
         my %storenewentry=($symb => time);
         $status.='<br />'.&mt('Updating discussion time').': '.
         &Apache::lonnet::put('discussiontimes',\%storenewentry,
-                     $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+                     $env{'course.'.$env{'request.course.id'}.'.domain'},
+		     $env{'course.'.$env{'request.course.id'}.'.num'});
     }
     my %record=&Apache::lonnet::restore('_discussion');
     my ($temp)=keys %record;
@@ -2402,16 +2571,18 @@ sub show_preview {
     my $r=shift;
     &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;
-    my $message=&clear_out_html($ENV{'form.comment'});
+    my $message=&clear_out_html($env{'form.comment'});
     $message=~s/\n/\<br \/\>/g;
     $message=&Apache::lonspeller::markeduptext($message);
     $message=&Apache::lontexconvert::msgtexconverted($message);
-    my $subject=&clear_out_html($ENV{'form.subject'});
+    my $subject=&clear_out_html($env{'form.subject'});
     $subject=~s/\n/\<br \/\>/g;
     $subject=&Apache::lontexconvert::msgtexconverted($subject);
-    $r->print('<table border="2"><tr><td>'.
-       '<b>Subject:</b> '.$subject.'<br /><br />'.
-       $message.'</td></tr></table>');
+    my $html=&Apache::lonxml::xmlbegin();
+    $r->print($html.'<head>'.
+	      '</head><body><table border="2"><tr><td>'.
+	      '<b>Subject:</b> '.$subject.'<br /><br />'.
+	      $message.'</td></tr></table></body></html>');
 }
 
 sub generate_preview_button {
@@ -2428,12 +2599,12 @@ ENDPREVIEW
 
 sub modify_attachments {
     my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_;
-    my $orig_subject = &Apache::lonnet::unescape($ENV{'form.subject'});
+    my $orig_subject = &Apache::lonnet::unescape($env{'form.subject'});
     my $subject=&clear_out_html($orig_subject);
     $subject=~s/\n/\<br \/\>/g;
     $subject=&Apache::lontexconvert::msgtexconverted($subject);
-    my $timestamp=$ENV{'form.timestamp'};
-    my $numoldver=$ENV{'form.numoldver'};
+    my $timestamp=$env{'form.timestamp'};
+    my $numoldver=$env{'form.numoldver'};
     my $bodytag=&Apache::loncommon::bodytag('Discussion Post Attachments',
                                           '','');
     my $msg = '';
@@ -2443,8 +2614,9 @@ sub modify_attachments {
         &extract_attachments($attachmenturls,$idx,$numoldver,\$msg,\%attachments,\%currattach,$currdelold);
     }
     &Apache::lonenc::check_encrypt(\$symb);
+    my $html=&Apache::lonxml::xmlbegin();
     $r->print(<<END);
-<html>
+$html
 <head>
 <title>Managing Attachments</title>
 <script>
@@ -2469,7 +2641,7 @@ END
                 foreach my $id (@currold) {
                     my $attachurl = &HTML::Entities::decode($attachments{$id}{'filename'}); 
                     $attachurl =~ m#/([^/]+)$#;
-                    $r->print('<input type="checkbox" name="deloldattach" value="'.$id.'" />&nbsp;'.$1.'<br />'."\n");
+                    $r->print('<label><input type="checkbox" name="deloldattach" value="'.$id.'" />&nbsp;'.$1.'</label><br />'."\n");
                 }
                 $r->print("<br />");
             }
@@ -2479,7 +2651,7 @@ END
         $r->print("The following attachments have been uploaded for inclusion with this posting.<br />Check the checkboxes for any you wish to remove<br />\n");
         foreach (@{$currnewattach}) {
             $_ =~ m#/([^/]+)$#;
-            $r->print('<input type="checkbox" name="delnewattach" value="'.$_.'" />&nbsp;'.$1.'<br />'."\n");
+            $r->print('<label><input type="checkbox" name="delnewattach" value="'.$_.'" />&nbsp;'.$1.'</label><br />'."\n");
         }
         $r->print("<br />"); 
     }
@@ -2488,14 +2660,14 @@ END
    </td>
   </tr>
  </table>
-<input type="hidden" name="subject" value="$ENV{'form.subject'}" />
-<input type="hidden" name="comment" value="$ENV{'form.comment'}" />
-<input type="hidden" name="timestamp" value="$ENV{'form.timestamp'}" />
-<input type="hidden" name="idx" value="$ENV{'form.idx'}" />
-<input type="hidden" name="numoldver" value="$ENV{'form.numoldver'}" />
-<input type="hidden" name="origpage" value="$ENV{'form.origpage'}" />
-<input type="hidden" name="anondiscuss" value="$ENV{'form.anondiscuss'}" />
-<input type="hidden" name="discuss" value="$ENV{'form.discuss'}" />
+<input type="hidden" name="subject" value="$env{'form.subject'}" />
+<input type="hidden" name="comment" value="$env{'form.comment'}" />
+<input type="hidden" name="timestamp" value="$env{'form.timestamp'}" />
+<input type="hidden" name="idx" value="$env{'form.idx'}" />
+<input type="hidden" name="numoldver" value="$env{'form.numoldver'}" />
+<input type="hidden" name="origpage" value="$env{'form.origpage'}" />
+<input type="hidden" name="anondiscuss" value="$env{'form.anondiscuss'}" />
+<input type="hidden" name="discuss" value="$env{'form.discuss'}" />
 END
     foreach (@{$currnewattach}) {
         $r->print('<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n");
@@ -2514,27 +2686,27 @@ END
 
 sub process_attachments {
     my ($currnewattach,$currdelold,$keepold) = @_;
-    if (exists($ENV{'form.currnewattach'})) {
-        if (ref($ENV{'form.currnewattach'}) eq 'ARRAY') {
-            @{$currnewattach} = @{$ENV{'form.currnewattach'}};
+    if (exists($env{'form.currnewattach'})) {
+        if (ref($env{'form.currnewattach'}) eq 'ARRAY') {
+            @{$currnewattach} = @{$env{'form.currnewattach'}};
         } else {
-            $$currnewattach[0] = $ENV{'form.currnewattach'};
+            $$currnewattach[0] = $env{'form.currnewattach'};
         }
     }
-    if (exists($ENV{'form.deloldattach'})) {
-        if (ref($ENV{'form.deloldattach'}) eq 'ARRAY') {
-            @{$currdelold} = @{$ENV{'form.deloldattach'}};
+    if (exists($env{'form.deloldattach'})) {
+        if (ref($env{'form.deloldattach'}) eq 'ARRAY') {
+            @{$currdelold} = @{$env{'form.deloldattach'}};
         } else {
-            $$currdelold[0] = $ENV{'form.deloldattach'};
+            $$currdelold[0] = $env{'form.deloldattach'};
         }
     }
-    if (exists($ENV{'form.delnewattach'})) {
+    if (exists($env{'form.delnewattach'})) {
         my @currdelnew = ();
         my @currnew = ();
-        if (ref($ENV{'form.delnewattach'}) eq 'ARRAY') {
-            @currdelnew = @{$ENV{'form.delnewattach'}};
+        if (ref($env{'form.delnewattach'}) eq 'ARRAY') {
+            @currdelnew = @{$env{'form.delnewattach'}};
         } else {
-            $currdelnew[0] = $ENV{'form.delnewattach'};
+            $currdelnew[0] = $env{'form.delnewattach'};
         }
         foreach my $newone (@{$currnewattach}) {
             my $delflag = 0;
@@ -2550,11 +2722,11 @@ sub process_attachments {
         }
         @{$currnewattach} = @currnew;
     }
-    if (exists($ENV{'form.keepold'})) {
-        if (ref($ENV{'form.keepold'}) eq 'ARRAY') {
-            @{$keepold} = @{$ENV{'form.keepold'}};
+    if (exists($env{'form.keepold'})) {
+        if (ref($env{'form.keepold'}) eq 'ARRAY') {
+            @{$keepold} = @{$env{'form.keepold'}};
         } else {
-            $$keepold[0] = $ENV{'form.keepold'};
+            $$keepold[0] = $env{'form.keepold'};
         }
     }
 }
@@ -2656,10 +2828,10 @@ sub construct_attachmenturl {
     my $newattachmenturl;
     my $startnum = 0;
     my $currver = 0;
-    if (($ENV{'form.editdisc'}) && ($idx)) {
-        my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
-                       $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-                       $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+    if (($env{'form.editdisc'}) && ($idx)) {
+        my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+                       $env{'course.'.$env{'request.course.id'}.'.domain'},
+                       $env{'course.'.$env{'request.course.id'}.'.num'});
         $oldattachmenturl = $contrib{$idx.':attachmenturl'};
         if ($contrib{$idx.':history'}) {
             if ($contrib{$idx.':history'} =~ /:/) {
@@ -2723,7 +2895,34 @@ sub has_discussion {
         }
     }
     return;
-} 
+}
+
+sub sort_filter_names {
+    my ($sort_types,$role_types,$status_types) = @_;
+    %{$sort_types} = (
+                     ascdate => 'Date order - oldest first',
+                     descdate => 'Date order - newest first',
+                     thread => 'Threaded',
+                     subject => 'By subject',
+                     username => 'By domain and username',
+                     lastfirst => 'By last name, first name'
+                   );
+    %{$role_types} = (
+                     all => 'All roles',
+                     st  => 'Students',
+                     cc  => 'Course Coordinators',
+                     in  => 'Instructors',
+                     ta  => 'TAs',
+                     ep  => 'Exam proctors',
+                     ad  => 'Administrators',
+                     cr  => 'Custom roles'
+                   );
+    %{$status_types} = (
+                     all     => 'Roles of any status',
+                     Active => 'Only active roles',
+                     Expired => 'Only inactive roles'
+                   );
+}
   
 sub handler {
   my $r = shift;
@@ -2737,12 +2936,13 @@ sub handler {
 
   &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
          ['hide','unhide','deldisc','postdata','preview','replydisc','editdisc','cmd','symb','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navtime','navmaps','navurl','sortposts','applysort','rolefilter','statusfilter','sectionpick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export']);
-  if ($ENV{'form.discsymb'}) {
-      my ($symb,$feedurl) = &get_feedurl_and_clean_symb($ENV{'form.discsymb'});
+
+  if ($env{'form.discsymb'}) {
+      my ($symb,$feedurl) = &get_feedurl_and_clean_symb($env{'form.discsymb'});
       my $readkey = $symb.'_read';
       my $chgcount = 0;
-      my %readinghash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$readkey],$ENV{'user.domain'},$ENV{'user.name'});
-      foreach my $key (keys %ENV) {
+      my %readinghash = &Apache::lonnet::get('nohist_'.$env{'request.course.id'}.'_discuss',[$readkey],$env{'user.domain'},$env{'user.name'});
+      foreach my $key (keys %env) {
           if ($key =~ m/^form\.postunread_(\d+)/) {
               if ($readinghash{$readkey} =~ /\.$1\./) {
                   $readinghash{$readkey} =~ s/\.$1\.//;
@@ -2756,32 +2956,33 @@ sub handler {
           }
       }
       if ($chgcount > 0) {
-          &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',
-			  \%readinghash,$ENV{'user.domain'},$ENV{'user.name'});
+          &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',
+			  \%readinghash,$env{'user.domain'},$env{'user.name'});
       }
       &redirect_back($r,$feedurl,&mt('Marked postings read/unread').'<br />',
-		     '0','0','',$ENV{'form.previous'},'','','',);
+		     '0','0','',$env{'form.previous'},'','','',);
       return OK;
   }
-  if ($ENV{'form.allversions'}) {
+  if ($env{'form.allversions'}) {
       &Apache::loncommon::content_type($r,'text/html');
       $r->send_http_header;
+      my $html=&Apache::lonxml::xmlbegin();
       my $bodytag=&Apache::loncommon::bodytag('Discussion Post Versions');
-      $r->print (<<END);
-<html>
+      $r->print(<<END);
+$html
 <head>
 <title>Post Versions</title>
 <meta http-equiv="pragma" content="no-cache" />
 </head>
 $bodytag
 END
-      my $crs='/'.$ENV{'request.course.id'};
-      if ($ENV{'request.course.sec'}) {
-          $crs.='_'.$ENV{'request.course.sec'};
+      my $crs='/'.$env{'request.course.id'};
+      if ($env{'request.course.sec'}) {
+          $crs.='_'.$env{'request.course.sec'};
       }
       $crs=~s|_|/|g;
       my $seeid=&Apache::lonnet::allowed('rin',$crs);
-      my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.allversions'});
+      my ($symb,$idx)=split(/\:\:\:/,$env{'form.allversions'});
       ($symb)=&get_feedurl_and_clean_symb($symb);
       if ($idx > 0) {
           my %messages = ();
@@ -2790,58 +2991,58 @@ END
           my %allattachments = ();
           my %imsfiles = ();
           my ($screenname,$plainname);
-          my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
-                           $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-                           $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+          my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+                           $env{'course.'.$env{'request.course.id'}.'.domain'},
+                           $env{'course.'.$env{'request.course.id'}.'.num'});
           $r->print(&get_post_contents(\%contrib,$idx,$seeid,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname));
       }
       return OK;
   }
-  if ($ENV{'form.posterlist'}) {
-      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.applysort'});
-      &print_showposters($r,$symb,$ENV{'form.previous'},$feedurl,
-			 $ENV{'form.sortposts'});
+  if ($env{'form.posterlist'}) {
+      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.applysort'});
+      &print_showposters($r,$symb,$env{'form.previous'},$feedurl,
+			 $env{'form.sortposts'});
       return OK;
   }
-  if ($ENV{'form.userpick'}) {
+  if ($env{'form.userpick'}) {
       my @posters = &Apache::loncommon::get_env_multiple('form.stuinfo');
-      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.userpick'});
+      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.userpick'});
       my $numpicks = @posters;
       my %discinfo;
       $discinfo{$symb.'_userpick'} = join('&',@posters);
-      &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',
-			   \%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
+      &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',
+			   \%discinfo,$env{'user.domain'},$env{'user.name'});
       &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0',
-		     '',$ENV{'form.previous'},$ENV{'form.sortposts'},'','','',
+		     '',$env{'form.previous'},$env{'form.sortposts'},'','','',
 		     $numpicks);
       return OK;
   }
-  if ($ENV{'form.applysort'}) {
-      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.applysort'});
+  if ($env{'form.applysort'}) {
+      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.applysort'});
       &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0',
-		     '',$ENV{'form.previous'},$ENV{'form.sortposts'},
-		     $ENV{'form.rolefilter'},$ENV{'form.statusfilter'},
-		     $ENV{'form.secpick'});
+		     '',$env{'form.previous'},$env{'form.sortposts'},
+		     $env{'form.rolefilter'},$env{'form.statusfilter'},
+		     $env{'form.sectionpick'});
       return OK;
-  } elsif ($ENV{'form.cmd'} eq 'sortfilter') {
-      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.symb'});
-      &print_sortfilter_options($r,$symb,$ENV{'form.previous'},$feedurl);
+  } elsif ($env{'form.cmd'} eq 'sortfilter') {
+      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
+      &print_sortfilter_options($r,$symb,$env{'form.previous'},$feedurl);
       return OK;
-  } elsif ($ENV{'form.navtime'}) {
+  } elsif ($env{'form.navtime'}) {
       my %discinfo = ();
       my @resources = ();
-      if (defined($ENV{'form.navmaps'})) {
-          if ($ENV{'form.navmaps'} =~ /:/) {
-              @resources = split/:/,$ENV{'form.navmaps'};
+      if (defined($env{'form.navmaps'})) {
+          if ($env{'form.navmaps'} =~ /:/) {
+              @resources = split/:/,$env{'form.navmaps'};
           } else {
-              @resources = ("$ENV{'form.navmaps'}");
+              @resources = ("$env{'form.navmaps'}");
           }
       } else {
           &has_discussion(\@resources);
       }
       my $numitems = @resources;
       my $feedurl = '/adm/navmaps';
-      if ($ENV{'form.navurl'}) { $feedurl .= '?'.$ENV{'form.navurl'}; }
+      if ($env{'form.navurl'}) { $feedurl .= '?'.$env{'form.navurl'}; }
       my %lt = &Apache::lonlocal::texthash(
           'mnpa' => 'Marked "New" posts as read in a total of',
           'robb' => 'resources/bulletin boards.',
@@ -2857,26 +3058,28 @@ END
               }
           }
           my $lastkey = $ressymb.'_lastread';
-          $discinfo{$lastkey} = $ENV{'form.navtime'};
+          $discinfo{$lastkey} = $env{'form.navtime'};
       }
       my $textline = "<b>$lt{'mnpa'} $numitems $lt{'robb'}</b>";
       if ($numitems > 0) {
-          &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',
-			     \%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
+          &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',
+			     \%discinfo,$env{'user.domain'},$env{'user.name'});
       } else {
           $textline = "<b>$lt{'twnp'}</b>";
       }
       &Apache::loncommon::content_type($r,'text/html');
       $r->send_http_header;
+      my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
+      my $html=&Apache::lonxml::xmlbegin();
       $r->print (<<ENDREDIR);
-<html>
+$html
 <head>
 <title>New posts marked as read</title>
 <meta http-equiv="pragma" content="no-cache" />
 <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
 </head>
 <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'>
-<img align="right" src="/adm/lonIcons/lonlogos.gif" />
+<img align="right" src="$logo" />
 $textline
 <form name="reldt" action="$feedurl" target="loncapaclient">
 </form>
@@ -2885,70 +3088,70 @@ $textline
 </html>
 ENDREDIR
       return OK;
-  } elsif ($ENV{'form.modifydisp'}) {
-      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.modifydisp'});
+  } elsif ($env{'form.modifydisp'}) {
+      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.modifydisp'});
       my ($dispchgA,$dispchgB,$markchg,$toggchg) = 
-	  split(/_/,$ENV{'form.changes'});
-      &print_display_options($r,$symb,$ENV{'form.previous'},$dispchgA,
+	  split(/_/,$env{'form.changes'});
+      &print_display_options($r,$symb,$env{'form.previous'},$dispchgA,
 			     $dispchgB,$markchg,$toggchg,$feedurl);
       return OK;
-  } elsif ($ENV{'form.markondisp'} || $ENV{'form.markonread'} ||
-	   $ENV{'form.allposts'}   || $ENV{'form.onlyunread'} ||
-	   $ENV{'form.onlyunmark'} || $ENV{'form.toggoff'}    ||
-	   $ENV{'form.toggon'}     || $ENV{'form.markread'}) {
-      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.symb'});
+  } elsif ($env{'form.markondisp'} || $env{'form.markonread'} ||
+	   $env{'form.allposts'}   || $env{'form.onlyunread'} ||
+	   $env{'form.onlyunmark'} || $env{'form.toggoff'}    ||
+	   $env{'form.toggon'}     || $env{'form.markread'}) {
+      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
       my %discinfo;
 # ------------------------ Modify setting for read/unread toggle for each post 
-      if ($ENV{'form.toggoff'}) { $discinfo{$symb.'_readtoggle'}=0; }
-      if ($ENV{'form.toggon'})  { $discinfo{$symb.'_readtoggle'}=1; }
+      if ($env{'form.toggoff'}) { $discinfo{$symb.'_readtoggle'}=0; }
+      if ($env{'form.toggon'})  { $discinfo{$symb.'_readtoggle'}=1; }
 # --------- Modify setting for identification of 'NEW' posts in this discussion
-      if ($ENV{'form.markondisp'}) {
+      if ($env{'form.markondisp'}) {
 	  $discinfo{$symb.'_lastread'} = time;
 	  $discinfo{$symb.'_markondisp'} = 1;
       }
-      if ($ENV{'form.markonread'}) {
-	  if ( $ENV{'form.previous'} > 0 ) {
-	      $discinfo{$symb.'_lastread'} = $ENV{'form.previous'};
+      if ($env{'form.markonread'}) {
+	  if ( $env{'form.previous'} > 0 ) {
+	      $discinfo{$symb.'_lastread'} = $env{'form.previous'};
 	  }
 	  $discinfo{$symb.'_markondisp'} = 0;
       }
 # --------------------------------- Modify display setting for this discussion 
-      if ($ENV{'form.allposts'}) {
+      if ($env{'form.allposts'}) {
 	  $discinfo{$symb.'_showonlyunread'} = 0;
 	  $discinfo{$symb.'_showonlyunmark'} = 0;
       }
-      if ($ENV{'form.onlyunread'}) { $discinfo{$symb.'_showonlyunread'} = 1;  }
-      if ($ENV{'form.onlyunmark'}) { $discinfo{$symb.'_showonlyunmark'} = 1;  }
+      if ($env{'form.onlyunread'}) { $discinfo{$symb.'_showonlyunread'} = 1;  }
+      if ($env{'form.onlyunmark'}) { $discinfo{$symb.'_showonlyunmark'} = 1;  }
 # ----------------------------------------------------- Mark new posts not NEW 
-      if ($ENV{'form.markread'})   { $discinfo{$symb.'_lastread'} = time; }
-      &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',
-			   \%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
-      my $previous=$ENV{'form.previous'};
-      if ($ENV{'form.markondisp'}) { $previous=undef; }
+      if ($env{'form.markread'})   { $discinfo{$symb.'_lastread'} = time; }
+      &Apache::lonnet::put('nohist_'.$env{'request.course.id'}.'_discuss',
+			   \%discinfo,$env{'user.domain'},$env{'user.name'});
+      my $previous=$env{'form.previous'};
+      if ($env{'form.markondisp'}) { $previous=undef; }
       &redirect_back($r,$feedurl,&mt('Changed display status').'<br />',
 		     '0','0','',$previous);
       return OK;
-  } elsif (($ENV{'form.hide'}) || ($ENV{'form.unhide'})) {
+  } elsif (($env{'form.hide'}) || ($env{'form.unhide'})) {
 # ----------------------------------------------------------------- Hide/unhide
-      my $entry=$ENV{'form.hide'}?$ENV{'form.hide'}:$ENV{'form.unhide'};
+      my $entry=$env{'form.hide'}?$env{'form.hide'}:$env{'form.unhide'};
       my ($symb,$idx)=split(/\:\:\:/,$entry);
       ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
 
-      my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
-                          $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-		          $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+      my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+                          $env{'course.'.$env{'request.course.id'}.'.domain'},
+		          $env{'course.'.$env{'request.course.id'}.'.num'});
 
       my $currenthidden=$contrib{'hidden'};
       my $currentstudenthidden=$contrib{'studenthidden'};
 
-      my $crs='/'.$ENV{'request.course.id'};
-      if ($ENV{'request.course.sec'}) {
-	  $crs.='_'.$ENV{'request.course.sec'};
+      my $crs='/'.$env{'request.course.id'};
+      if ($env{'request.course.sec'}) {
+	  $crs.='_'.$env{'request.course.sec'};
       }
       $crs=~s/\_/\//g;
       my $seeid=&Apache::lonnet::allowed('rin',$crs);
 
-      if ($ENV{'form.hide'}) {
+      if ($env{'form.hide'}) {
 	  $currenthidden.='.'.$idx.'.';
 	  unless ($seeid) {
 	      $currentstudenthidden.='.'.$idx.'.';
@@ -2957,20 +3160,20 @@ ENDREDIR
 	  $currenthidden=~s/\.$idx\.//g;
       }
       my %newhash=('hidden' => $currenthidden);
-      if ( ($ENV{'form.hide'}) && (!$seeid) ) {
+      if ( ($env{'form.hide'}) && (!$seeid) ) {
 	  $newhash{'studenthidden'} = $currentstudenthidden;
       }
 
-      &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'},
-                           $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-			   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+      &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
+                           $env{'course.'.$env{'request.course.id'}.'.domain'},
+			   $env{'course.'.$env{'request.course.id'}.'.num'});
 
       &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />',
-		     '0','0','',$ENV{'form.previous'});
+		     '0','0','',$env{'form.previous'});
       return OK;
-  } elsif ($ENV{'form.cmd'}=~/^(threadedoff|threadedon)$/) {
-      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($ENV{'form.symb'});
-      if ($ENV{'form.cmd'} eq 'threadedon') {
+  } elsif ($env{'form.cmd'}=~/^(threadedoff|threadedon)$/) {
+      my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
+      if ($env{'form.cmd'} eq 'threadedon') {
 	  &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'});
 	  &Apache::lonnet::appenv('environment.threadeddiscussion' => 'on');
       } else {
@@ -2978,59 +3181,59 @@ ENDREDIR
 	  &Apache::lonnet::delenv('environment\.threadeddiscussion');
       }
       &redirect_back($r,$feedurl,&mt('Changed discussion view mode').'<br />',
-		     '0','0','',$ENV{'form.previous'});
+		     '0','0','',$env{'form.previous'});
       return OK;
-  } elsif ($ENV{'form.deldisc'}) {
+  } elsif ($env{'form.deldisc'}) {
 # --------------------------------------------------------------- Hide for good
-      my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.deldisc'});
+      my ($symb,$idx)=split(/\:\:\:/,$env{'form.deldisc'});
       ($symb,my $feedurl)=&get_feedurl_and_clean_symb($symb);
-      my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
-                          $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-		          $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+      my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+                          $env{'course.'.$env{'request.course.id'}.'.domain'},
+		          $env{'course.'.$env{'request.course.id'}.'.num'});
       my %newhash=('deleted' => $contrib{'deleted'}.".$idx.");
-      &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'},
-			   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-			   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+      &Apache::lonnet::store(\%newhash,$symb,$env{'request.course.id'},
+			   $env{'course.'.$env{'request.course.id'}.'.domain'},
+			   $env{'course.'.$env{'request.course.id'}.'.num'});
       &redirect_back($r,$feedurl,&mt('Changed discussion status').'<br />',
-		     '0','0','',$ENV{'form.previous'});
+		     '0','0','',$env{'form.previous'});
       return OK;
-  } elsif ($ENV{'form.preview'}) {
+  } elsif ($env{'form.preview'}) {
 # -------------------------------------------------------- User wants a preview
       &show_preview($r);
       return OK;
-  } elsif ($ENV{'form.attach'}) {
+  } elsif ($env{'form.attach'}) {
 # -------------------------------------------------------- Work on attachments
       &Apache::loncommon::content_type($r,'text/html');
       $r->send_http_header;
       &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','addnewattach','delnewattach','timestamp','numoldver','idx','anondiscuss','discuss']);
       my (@currnewattach,@currdelold,@keepold);
       &process_attachments(\@currnewattach,\@currdelold,\@keepold);
-      if (exists($ENV{'form.addnewattach.filename'})) {
-          unless (length($ENV{'form.addnewattach'})>131072) {
-              my $subdir = 'feedback/'.$ENV{'form.timestamp'};
+      if (exists($env{'form.addnewattach.filename'})) {
+          unless (length($env{'form.addnewattach'})>131072) {
+              my $subdir = 'feedback/'.$env{'form.timestamp'};
               my $newattachment=&Apache::lonnet::userfileupload('addnewattach',undef,$subdir);
 	      push @currnewattach, $newattachment;
           }
       }
       my $attachmenturls;
-      my ($symb) = &get_feedurl_and_clean_symb($ENV{'form.attach'});
-      my $idx = $ENV{'form.idx'};
+      my ($symb) = &get_feedurl_and_clean_symb($env{'form.attach'});
+      my $idx = $env{'form.idx'};
       if ($idx) {
-          my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
-                         $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
-                         $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+          my %contrib=&Apache::lonnet::restore($symb,$env{'request.course.id'},
+                         $env{'course.'.$env{'request.course.id'}.'.domain'},
+                         $env{'course.'.$env{'request.course.id'}.'.num'});
           $attachmenturls = $contrib{$idx.':attachmenturl'};
       }
       &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx,
 			  $attachmenturls);
       return OK;
-  } elsif ($ENV{'form.export'}) {
+  } elsif ($env{'form.export'}) {
       &Apache::loncommon::content_type($r,'text/html');
       $r->send_http_header;
-      my ($symb,$feedurl) = &get_feedurl_and_clean_symb($ENV{'form.export'});
+      my ($symb,$feedurl) = &get_feedurl_and_clean_symb($env{'form.export'});
       my $mode='board';
       my $status='OPEN';
-      my $previous=$ENV{'form.previous'};
+      my $previous=$env{'form.previous'};
       if ($feedurl =~ /\.(problem|exam|quiz|assess|survey|form|library)$/) {
           $mode='problem';
           $status=$Apache::inputtags::status[-1];
@@ -3041,28 +3244,28 @@ ENDREDIR
       return OK;
   } else {
 # ------------------------------------------------------------- Normal feedback
-      my $feedurl=$ENV{'form.postdata'};
+      my $feedurl=$env{'form.postdata'};
       $feedurl=~s/^http\:\/\///;
       $feedurl=~s/^$ENV{'SERVER_NAME'}//;
       $feedurl=~s/^$ENV{'HTTP_HOST'}//;
       $feedurl=~s/\?.+$//;
 
       my $symb;
-      if ($ENV{'form.replydisc'}) {
-	  $symb=(split(/\:\:\:/,$ENV{'form.replydisc'}))[0];
+      if ($env{'form.replydisc'}) {
+	  $symb=(split(/\:\:\:/,$env{'form.replydisc'}))[0];
 	  my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
 	  $feedurl=&Apache::lonnet::clutter($url);
-      } elsif ($ENV{'form.editdisc'}) {
-	  $symb=(split(/\:\:\:/,$ENV{'form.editdisc'}))[0];
+      } elsif ($env{'form.editdisc'}) {
+	  $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
 	  my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
 	  $feedurl=&Apache::lonnet::clutter($url);
-      } elsif ($ENV{'form.origpage'}) {
+      } elsif ($env{'form.origpage'}) {
 	  $symb=""; 
       } else {
 	  $symb=&Apache::lonnet::symbread($feedurl);
       }
       unless ($symb) {
-	  $symb=$ENV{'form.symb'};
+	  $symb=$env{'form.symb'};
 	  if ($symb) {
 	      my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
 	      $feedurl=&Apache::lonnet::clutter($url);
@@ -3088,9 +3291,9 @@ ENDREDIR
 	   ($feedurl=~m:^/res:) && ($feedurl!~m:^/res/adm:)
 	   ) 
 	  || 
-	  ($ENV{'request.course.id'} && ($feedurl!~m:^/adm:))
+	  ($env{'request.course.id'} && ($feedurl!~m:^/adm:))
 	  ||
-	  ($ENV{'request.course.id'} && ($symb=~/^bulletin\_\_\_/))
+	  ($env{'request.course.id'} && ($symb=~/^bulletin\_\_\_/))
 	  ) {
 	  &Apache::loncommon::content_type($r,'text/html');
 	  $r->send_http_header;
@@ -3098,7 +3301,7 @@ ENDREDIR
 	  &no_redirect_back($r,$feedurl);
       }
 # --------------------------------------------------- Print login screen header
-      unless ($ENV{'form.sendit'}) {
+      unless ($env{'form.sendit'}) {
 	  &Apache::loncommon::content_type($r,'text/html');
 	  $r->send_http_header;
 	  my $options=&screen_header($feedurl,$symb);
@@ -3112,8 +3315,8 @@ ENDREDIR
       
 # Get previous user input
       my $prevattempts=&Apache::loncommon::get_previous_attempt(
-                                   $symb,$ENV{'user.name'},$ENV{'user.domain'},
-				   $ENV{'request.course.id'});
+                                   $symb,$env{'user.name'},$env{'user.domain'},
+				   $env{'request.course.id'});
 
 # Get output from resource
       my $usersaw=&resource_output($feedurl);
@@ -3121,20 +3324,20 @@ ENDREDIR
 # Get resource answer (need to allow student to view grades for this to work)
       &Apache::lonnet::appenv(('allowed.vgr'=>'F'));
       my $useranswer=&Apache::loncommon::get_student_answers(
-                                   $symb,$ENV{'user.name'},$ENV{'user.domain'},
-		                   $ENV{'request.course.id'});
+                                   $symb,$env{'user.name'},$env{'user.domain'},
+		                   $env{'request.course.id'});
       &Apache::lonnet::delenv('allowed.vgr');
 # Get attachments, if any, and not too large
       my $attachmenturl='';
-      if (($ENV{'form.origpage'}) || ($ENV{'form.editdisc'}) ||
-	  ($ENV{'form.replydisc'})) {
+      if (($env{'form.origpage'}) || ($env{'form.editdisc'}) ||
+	  ($env{'form.replydisc'})) {
 	  my ($symb,$idx);
-	  if ($ENV{'form.replydisc'}) {
-	      ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'});
-	  } elsif ($ENV{'form.editdisc'}) {
-	      ($symb,$idx)=split(/\:\:\:/,$ENV{'form.editdisc'});
-	  } elsif ($ENV{'form.origpage'}) {
-	      $symb = $ENV{'form.symb'};
+	  if ($env{'form.replydisc'}) {
+	      ($symb,$idx)=split(/\:\:\:/,$env{'form.replydisc'});
+	  } elsif ($env{'form.editdisc'}) {
+	      ($symb,$idx)=split(/\:\:\:/,$env{'form.editdisc'});
+	  } elsif ($env{'form.origpage'}) {
+	      $symb = $env{'form.symb'};
 	  }
 	  &Apache::lonenc::check_decrypt(\$symb);
 	  my @currnewattach = ();
@@ -3143,13 +3346,13 @@ ENDREDIR
 	  &process_attachments(\@currnewattach,\@deloldattach,\@keepold);
 	  $symb=~s|(bulletin___\d+___)adm/wrapper/|$1|;
 	  $attachmenturl=&construct_attachmenturl(\@currnewattach,\@keepold,$symb,$idx);
-      } elsif ($ENV{'form.attachment.filename'}) {
-	  unless (length($ENV{'form.attachment'})>131072) {
+      } elsif ($env{'form.attachment.filename'}) {
+	  unless (length($env{'form.attachment'})>131072) {
 	      $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,'feedback');
 	  }
       }
 # Filter HTML out of message (could be nasty)
-      my $message=&clear_out_html($ENV{'form.comment'});
+      my $message=&clear_out_html($env{'form.comment'});
 
 # Assemble email
       my ($email,$citations)=&assemble_email($feedurl,$message,$prevattempts,
@@ -3165,16 +3368,16 @@ ENDREDIR
 # Discussion? Store that.
 
       my $numpost=0;
-      if ($ENV{'form.discuss'} || $ENV{'form.anondiscuss'}) {
-	  my $subject = &clear_out_html($ENV{'form.subject'});
-	  my $anonmode=(defined($ENV{'form.anondiscuss'}));
+      if ($env{'form.discuss'} || $env{'form.anondiscuss'}) {
+	  my $subject = &clear_out_html($env{'form.subject'});
+	  my $anonmode=(defined($env{'form.anondiscuss'}));
 	  $typestyle.=&adddiscuss($symb,$message,$anonmode,$attachmenturl,
 				  $subject);
 	  $numpost++;
       }
 	  
 # Receipt screen and redirect back to where came from
-      &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status,$ENV{'form.previous'});
+      &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status,$env{'form.previous'});
   }
   return OK;
 }