--- loncom/interface/lonfeedback.pm	2006/03/15 22:06:08	1.185
+++ loncom/interface/lonfeedback.pm	2006/07/18 17:31:50	1.210
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Feedback
 #
-# $Id: lonfeedback.pm,v 1.185 2006/03/15 22:06:08 www Exp $
+# $Id: lonfeedback.pm,v 1.210 2006/07/18 17:31:50 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -42,7 +42,10 @@ use Apache::lonenc();
 use Apache::lonrss();
 use HTML::LCParser();
 use Apache::lonspeller();
+use Apache::longroup;
 use Cwd;
+use lib '/home/httpd/lib/perl/';
+use LONCAPA;
 
 sub discussion_open {
     my ($status,$symb)=@_;
@@ -71,7 +74,7 @@ sub discussion_visible {
 }
 
 sub list_discussion {
-    my ($mode,$status,$ressymb,$imsextras)=@_;
+    my ($mode,$status,$ressymb,$imsextras,$group)=@_;
     my $outputtarget=$env{'form.grade_target'};
     if (defined($env{'form.export'})) {
 	if($env{'form.export'}) {
@@ -84,6 +87,11 @@ sub list_discussion {
         }
     }
     if (not &discussion_visible($status)) { return ''; }
+    if ($group ne '' && $mode eq 'board') {
+        if (&check_group_priv($group,'vgb') ne 'ok') {
+            return '';
+        }
+    }
     my @bgcols = ("#cccccc","#eeeeee");
     my $discussiononly=0;
     if ($mode eq 'board') { $discussiononly=1; }
@@ -127,21 +135,13 @@ sub list_discussion {
     my @posters = split/\&/,$dischash{$userpickkey};
 
 # 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']);
+    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','grouppick','totposters']);
     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 @sectionpick = split(/,/,$env{'form.sectionpick'});
+    my @grouppick   = split(/,/,$env{'form.grouppick'});
+    my @rolefilter  = split(/,/,$env{'form.rolefilter'});
+
     my $totposters = $env{'form.totposters'};
     $previous = $env{'form.previous'};
     if ($previous > 0) {
@@ -152,13 +152,15 @@ sub list_discussion {
         }
     }
 
+    my $cdom = $env{'course.'.$cid.'.domain'};
+    my $cnum = $env{'course.'.$cid.'.num'};
+
 # Get information about students and non-students in course for filtering display of posts
     my %roleshash = ();
     my %roleinfo = ();
+    my ($classgroups,$studentgroups);
     if ($env{'form.rolefilter'}) {
-        %roleshash = &Apache::lonnet::dump('nohist_userroles',
-					   $env{'course.'.$cid.'.domain'},
-					   $env{'course.'.$cid.'.num'});
+        %roleshash = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
         foreach (keys %roleshash) {
             my ($role,$uname,$udom,$sec) = split/:/,$_;
             if ($role =~ /^cr/) {
@@ -174,9 +176,8 @@ sub list_discussion {
                 push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status;
             }
         }
-        my ($classlist) = &Apache::loncoursedata::get_classlist(
-                              $env{'course.'.$cid.'.domain'},
-                              $env{'course.'.$cid.'.num'});
+        my ($classlist,$keylist) =
+                         &Apache::loncoursedata::get_classlist($cdom,$cnum);
         my $sec_index = &Apache::loncoursedata::CL_SECTION();
         my $status_index = &Apache::loncoursedata::CL_STATUS();
         while (my ($student,$data) = each %$classlist) {
@@ -184,6 +185,9 @@ sub list_discussion {
                                  $data->[$status_index]);
             push @{$roleinfo{$student}}, 'st:'.$section.':'.$status;
         }
+	($classgroups,$studentgroups) = 
+         &Apache::loncoursedata::get_group_memberships($classlist,$keylist,
+                                                       $cdom,$cnum);
     }
 
 # Get discussion display default settings for user
@@ -223,7 +227,15 @@ sub list_discussion {
     }
     $visit ++;
 
-    my $seeid=&Apache::lonnet::allowed('rin',$crs);
+    my $seeid;
+    if (($group ne '') && ($mode eq 'board') && 
+        ($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|)) {
+        if (&check_group_priv($group,'dgp') eq 'ok') {
+            $seeid = 1;
+        }
+    } else {
+        $seeid=&Apache::lonnet::allowed('rin',$crs);
+    }
     my @discussionitems=();
     my %shown = ();
     my @posteridentity=();
@@ -250,7 +262,7 @@ sub list_discussion {
     $discinfo{$visitkey} = $visit;
 
     &Apache::lonnet::put('nohist_'.$cid.'_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,\%anonhash,$anoncnt);
+    &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,\@grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,\%anonhash,$anoncnt,$group);
 
     my $discussion='';
     my $manifestfile;
@@ -259,6 +271,11 @@ sub list_discussion {
     my $imsresources;
     my $copyresult;
 
+    my $grp_arg;
+    if ($group ne '') {
+        $grp_arg = &grp_args($group);
+    } 
+
     my $function = &Apache::loncommon::get_users_function();
     my $color = &Apache::loncommon::designparm($function.'.tabbg',
                                                     $env{'user.domain'});
@@ -323,6 +340,9 @@ sub list_discussion {
     if ($newpostsflag) {
         $chglink .= '&previous='.$prevread;
     }
+    if ($group ne '') {
+        $chglink.='&'.$grp_arg;
+    }
 
     if ($visible) {
 # Print the discusssion
@@ -394,23 +414,32 @@ imscp_v1p1.xsd http://www.imsglobal.org/
 	    $discussion.='<form name="readchoices" method="post" action="/adm/feedback?chgreads='.$ressymb.'" ><table bgcolor="#AAAAAA" cellpadding="2" cellspacing="2" border="0">';
 	    $discussion .='<tr><td bgcolor="#DDDDBB" colspan="'.$colspan.'">'.
 		'<table border="0" width="100%" bgcolor="#DDDDBB"><tr>';
-	    my $escsymb=&Apache::lonnet::escape($ressymb);
+	    my $escsymb=&escape($ressymb);
 	    if ($visible>2) {
 		$discussion.='<td align="left">'.
 		    '<a href="/adm/feedback?cmd=threadedon&amp;symb='.$escsymb;
 		if ($newpostsflag) {
 		    $discussion .= '&previous='.$prevread;
 		}
+                if ($group ne '') {
+                    $discussion .= '&amp;'.$grp_arg;
+                }
 		$discussion .='">'.&mt('Threaded View').'</a>&nbsp;&nbsp;'.
 		    '<a href="/adm/feedback?cmd=threadedoff&amp;symb='.$escsymb;
 		if ($newpostsflag) {
 		    $discussion .= '&previous='.$prevread;
 		}
+                if ($group ne '') {
+                    $discussion .= '&amp;'.$grp_arg;
+                }
 		$discussion .='">'.&mt('Chronological View').'</a>&nbsp;&nbsp;
                               <a href= "/adm/feedback?cmd=sortfilter&amp;symb='.$escsymb;
                 if ($newpostsflag) {
                     $discussion .= '&previous='.$prevread;
                 }
+                if ($group ne '') {
+                    $discussion .= '&amp;'.$grp_arg;
+                }
                 $discussion .='">'.&mt('Sorting/Filtering options').'</a>&nbsp;&nbsp';
             } else {
                 $discussion .= '<td align="left">';
@@ -419,12 +448,23 @@ imscp_v1p1.xsd http://www.imsglobal.org/
             if ($newpostsflag) {
                 $discussion .= '&previous='.$prevread;
             }
+            if ($group ne '') {
+                $discussion .= '&amp;'.$grp_arg;
+            }
             $discussion .= '">'.&mt('Export').'?</a>&nbsp;&nbsp;</td>';
 	    if ($newpostsflag) {
 		if (!$markondisp) {
-		    $discussion .='<td align="right"><a href="/adm/preferences?action=changediscussions">'.
-			&mt('Preferences on what is marked as NEW').
-			'</a><br /><a href="/adm/feedback?markread=1&amp;symb='.$escsymb.'">'.&mt('Mark NEW posts no longer new').'</a>';
+		    $discussion .='<td align="right"><a href="/adm/preferences?action=changediscussions';
+                    if ($group ne '') {
+                        $discussion .= '&amp;'.$grp_arg;
+                    }
+		    $discussion .= '">'.
+                        &mt('Preferences on what is marked as NEW').
+			'</a><br /><a href="/adm/feedback?markread=1&amp;symb='.$escsymb;
+                    if ($group ne '') {
+                        $discussion .= '&amp;'.$grp_arg;
+                    }
+                    $discussion .= '">'.&mt('Mark NEW posts no longer new').'</a>';
 		} else {
 		    $discussion .= '<td>&nbsp;</td>';
 		}
@@ -441,6 +481,9 @@ imscp_v1p1.xsd http://www.imsglobal.org/
                 if ($newpostsflag) {
                     $discussion .= '&previous='.$prevread;
                 }
+                if ($group ne '') {
+                    $discussion .= '&amp;'.$grp_arg;
+                }
                 $discussion .= '">'.&mt('Show all posts').'</a> '.&mt('to display').' '.
                          $numhidden.' ';
                 if ($showunmark) {
@@ -609,6 +652,10 @@ END
                         $filterchoice = '<i>'.&mt('sections').'</i>-&nbsp;'.$env{'form.sectionpick'};
                         $filterchoice .= '&nbsp;&nbsp;&nbsp; ';
                     }
+                    if (@grouppick > 0) {
+                        $filterchoice = '<i>'.&mt('groups').'</i>-&nbsp;'.$env{'form.grouppick'};
+                        $filterchoice .= '&nbsp;&nbsp;&nbsp; ';
+                    }
                     if (@rolefilter > 0) {
                         $filterchoice .= '<i>'.&mt('roles').'</i>-';
                         foreach (@rolefilter) {
@@ -687,88 +734,126 @@ END
     if ($discussiononly) {
         my $now = time;
         my $attachnum = 0;
-        my $newattachmsg = '';
-        my @currnewattach = ();
-        my @currdelold = ();
+        my $currnewattach;
+        my $currdelold;
         my $comment = '';
         my $subject = '';
         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 = &unescape($env{'form.subject'});
+            $comment = &unescape($env{'form.comment'});
             my @keepold = ();
-            &process_attachments(\@currnewattach,\@currdelold,\@keepold);
-            if (@currnewattach > 0) {
-                $attachnum += @currnewattach;
+            &process_attachments($currnewattach,$currdelold,\@keepold);
+            if (@{$currnewattach} > 0) {
+                $attachnum += @{$currnewattach};
             }
         }
 	if (&discussion_open($status)) {
-	    $discussion.=(<<ENDDISCUSS);
-<form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data">
-<input type="submit" name="discuss" value="Post Discussion" />
-<input type="submit" name="anondiscuss" value="Post Anonymous Discussion" />
-<input type="hidden" name="symb" value="$ressymb" />
-<input type="hidden" name="sendit" value="true" />
-<input type="hidden" name="timestamp" value="$now" />
-<br /><a name="newpost"></a>
-<font size="1">Note: in anonymous discussion, your name is visible only 
-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";
-                foreach (@currnewattach) {
-                    $discussion.='<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n";
-                }
-            }
-            $discussion.="</form>\n";
-            if ($outputtarget ne 'tex') {
-                $discussion.=&generate_attachments_button('',$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,'',$mode);
-                if (@currnewattach > 0) {
-                    $newattachmsg .= '<b>New attachments</b><br />';
-                    if (@currnewattach > 1) {
-                        $newattachmsg .= '<ol>';
-                        foreach my $item (@currnewattach) {
-                            $item =~ m#.*/([^/]+)$#;
-                            $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";
-                        }
-                        $newattachmsg .= '</ol>'."\n";
-                    } else {
-                        $currnewattach[0] =~ m#.*/([^/]+)$#;
-                        $newattachmsg .= '<a href="'.$currnewattach[0].'">'.$1.'</a><br />'."\n";
-                    }
+            if (($group ne '') && ($mode eq 'board')) {  
+                if (&check_group_priv($group,'pgd') eq 'ok') {
+                    $discussion .=
+			&postingform_display($mode,$ressymb,$now,$subject,
+					     $comment,$outputtarget,$attachnum,
+					     $currnewattach,$currdelold,
+					     $group);
                 }
-                $discussion.=$newattachmsg;
-	        $discussion.=&generate_preview_button();
-	    }
+            } else {
+	        $discussion.= 
+		    &postingform_display($mode,$ressymb,$now,$subject,
+					 $comment,$outputtarget,$attachnum,
+					 $currnewattach,$currdelold);
+            }
 	}
     } else {
+	$discussion.='<table bgcolor="#BBBBBB"><tr><td>';
         if (&discussion_open($status) &&
             &Apache::lonnet::allowed('pch',
     	        $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='.
-		    &Apache::lonnet::escape($ressymb).':::" '.$target.'>'.
+		$discussion.='<a href="/adm/feedback?replydisc='.
+		    &escape($ressymb).':::" '.$target.'>'.
 		    '<img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').'" border="0" />'.
-		    &mt('Post Discussion').'</a></td></tr></table>';
-	    }
+		    &mt('Post Discussion').'</a><br />';
+            }
 	}
+	$discussion.='<a href="/adm/feedback?sendmessageonly=1&symb='.
+	    &escape($ressymb).
+	    '"><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/feedback.gif').'" border="0" />'.
+		    &mt('Send Message').'</a></td></tr></table>';
     }
     return $discussion;
 }
 
+sub postingform_display {
+    my ($mode,$ressymb,$now,$subject,$comment,$outputtarget,$attachnum,
+        $currnewattach,$currdelold,$group) = @_;
+    my $newattachmsg;
+    my $postingform = (<<ENDDISCUSS);
+<form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data"> <input type="submit" name="discuss" value="Post Discussion" />
+<input type="submit" name="anondiscuss" value="Post Anonymous Discussion" /> <input type="hidden" name="symb" value="$ressymb" />
+<input type="hidden" name="sendit" value="true" />
+<input type="hidden" name="timestamp" value="$now" />
+<br /><a name="newpost"></a>
+<font size="1">Note: in anonymous discussion, your name is visible only
+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'}) {
+        $postingform .= '<input type="hidden" name="origpage" value="'.
+                        $env{'form.origpage'}.'" />'."\n";
+        foreach my $att (@{$currnewattach}) {
+            $postingform .= '<input type="hidden" name="currnewattach" '.
+                            'value="'.$att.'" />'."\n";
+        }
+    }
+    if (exists($env{'form.ref'})) {
+        $postingform .= '<input type="hidden" name="ref" value="'.
+                        $env{'form.ref'}.'" />';
+    }
+    if ($group ne '') {
+        $postingform .='<input type="hidden" name="group" value="'.$group.'" />';
+    }
+    $postingform .= "</form>\n";
+    if ($outputtarget ne 'tex') {
+        $postingform .= &generate_attachments_button('',$attachnum,$ressymb,
+                                                     $now,$currnewattach,
+                                                     $currdelold,'',$mode);
+        if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {
+            $newattachmsg = '<br /><b>New attachments</b><br />';
+            if (@{$currnewattach} > 1) {
+                $newattachmsg .= '<ol>';
+                foreach my $item (@{$currnewattach}) {
+                    $item =~ m#.*/([^/]+)$#;
+                    $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";
+                }
+                $newattachmsg .= '</ol>'."\n";
+            } else {
+                $$currnewattach[0] =~ m#.*/([^/]+)$#;
+                $newattachmsg .= '<a href="'.$$currnewattach[0].'">'.$1.'</a><br />'."\n";
+            }
+        }
+        $postingform .= $newattachmsg;
+        $postingform .= &generate_preview_button();
+    }
+    return $postingform;
+}
+
 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,$anonhash,$anoncnt) = @_;
+    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,$grouppick,$classgroups,$statusfilter,$toggkey,$outputtarget,$anonhash,$anoncnt,$group) = @_;
     my @original=();
     my @index=();
+    my $skip_group_check = 0;
     my $symb=&Apache::lonenc::check_decrypt($ressymb);
-    my $escsymb=&Apache::lonnet::escape($ressymb);
+    my $escsymb=&escape($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'});
 
+    if ((@{$grouppick} == 0) || (grep(/^all$/,@{$grouppick}))) {
+        $skip_group_check = 1;
+    }
     if ($contrib{'version'}) {
         my $oldest = $contrib{'1:timestamp'};
         if ($prevread eq '0') {
@@ -776,7 +861,8 @@ sub build_posting_display {
         }
         my ($skiptest,$rolematch,$roleregexp,$secregexp,$statusregexp);
         if ($sortposts) {
-            ($skiptest,$roleregexp,$secregexp,$statusregexp) = &filter_regexp($rolefilter,$sectionpick,$statusfilter);
+            ($skiptest,$roleregexp,$secregexp,$statusregexp) = 
+                     &filter_regexp($rolefilter,$sectionpick,$statusfilter);
             $rolematch = $roleregexp.':'.$secregexp.':'.$statusregexp;
         } 
 	for (my $id=1;$id<=$contrib{'version'};$id++) {
@@ -865,7 +951,7 @@ sub build_posting_display {
                                @{$$subjectsort{$subject}} = ("$idx");
                             }
                         }
-		        if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
+		        if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
 			    $sender=&Apache::loncommon::aboutmewrapper(
 					 $plainname,
 					 $contrib{$idx.':sendername'},
@@ -906,14 +992,18 @@ sub build_posting_display {
                             } else {
                                 @{$$namesort{$lastname}{$firstname}} = ("$idx");
                             }
-                            if (&editing_allowed()) {
+                            if (&editing_allowed($escsymb.':::'.$idx,$group)) {
                                 if (($env{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($env{'user.name'} eq $contrib{$idx.':sendername'})) {
                                     $sender.=' <a href="/adm/feedback?editdisc='.
                                          $escsymb.':::'.$idx;
                                     if ($$newpostsflag) {
                                         $sender .= '&previous='.$prevread;
                                     }
-                                    $sender .= '" '.$target.'>'.&mt('Edit').'</a>';                                             
+                                    if ($group ne '') {
+                                        $sender.='&amp;'.&grp_args($group);
+                                    }
+                                    $sender .= '" '.$target.'>'.&mt('Edit').'</a>';
+                                    
                                     unless ($seeid) {
                                         $sender.=" <a href=\"javascript:studentdelete('$escsymb','$idx','$$newpostsflag','$prevread')";
                                         $sender .= '">'.&mt('Delete').'</a>';
@@ -936,6 +1026,9 @@ sub build_posting_display {
                                     if ($$newpostsflag) {
                                         $sender .= '&previous='.$prevread;
                                     }
+                                    if ($group ne '') {
+                                        $sender.='&amp;'.&grp_args($group);
+                                    }
                                     $sender .= '">'.&mt('Hide').'</a>';
 			        }                     
 			        $sender.=' <a href="/adm/feedback?deldisc='.
@@ -943,6 +1036,9 @@ sub build_posting_display {
                                 if ($$newpostsflag) {
                                     $sender .= '&previous='.$prevread;
                                 }
+                                if ($group ne '') {
+                                    $sender .= '&amp;'.&grp_args($group);
+                                }
                                 $sender .= '">'.&mt('Delete').'</a>';
                             }
 		        } else {
@@ -970,16 +1066,27 @@ sub build_posting_display {
                                 @{$$namesort{'__anon'}{'__anon'}} = ("$idx");
                             }
 		        }
-		        if (&discussion_open($status) &&
-			        &Apache::lonnet::allowed('pch',
-						 $env{'request.course.id'}.
-						 ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
-			    $sender.=' <a href="/adm/feedback?replydisc='.
-			            $escsymb.':::'.$idx;
-                            if ($$newpostsflag) {
-                                $sender .= '&previous='.$prevread;
+		        if (&discussion_open($status)) {
+                            if (($group ne '') && 
+                                (&check_group_priv($group,'pgd') eq 'ok')) {
+                                 $sender.=' <a href="/adm/feedback?replydisc='.
+                                          $escsymb.':::'.$idx;
+                                if ($$newpostsflag) {
+                                    $sender .= '&previous='.$prevread;
+                                }
+                                $sender .= '&amp;'.&grp_args($group);
+                                $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
+                            } elsif (&Apache::lonnet::allowed('pch', 
+				 $env{'request.course.id'}.
+				 ($env{'request.course.sec'}?'/'.
+                                  $env{'request.course.sec'}:''))) {
+			         $sender.=' <a href="/adm/feedback?replydisc='.
+			                  $escsymb.':::'.$idx;
+                                if ($$newpostsflag) {
+                                    $sender .= '&previous='.$prevread;
+                                }
+                                $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
                             }
-                            $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
                         }
 		        if ($viewgrades) {
 			        $vgrlink=&Apache::loncommon::submlink('Submissions',
@@ -1036,7 +1143,7 @@ sub build_posting_display {
                             my $uname = $contrib{$idx.':sendername'};
                             my $udom = $contrib{$idx.':senderdomain'};
                             my $poster = $uname.':'.$udom;
-                            if (defined($env{'form.totposters'})) {
+                            if ($env{'form.totposters'} ne '') {
                                 if ($totposters == 0) {
                                     $$shown{$idx} = 0;
                                 } elsif ($totposters > 0) {
@@ -1061,6 +1168,23 @@ sub build_posting_display {
                                         }
                                     }
                                 }
+                                if ($$shown{$idx} && !$skip_group_check) {
+                                    my $showflag = 0;
+                                    if (ref($$classgroups{$poster}{active}) eq 'HASH') {
+                                        foreach my $grp (@{$grouppick}) {
+                                            if (grep/^\Q$grp\E$/,
+                                 keys(%{$$classgroups{$poster}{active}})) {
+                                                $showflag = 1;
+                                                last;
+                                            }
+                                        }
+                                    }
+                                    if ($showflag) {
+                                        $$shown{$idx} = 1;
+                                    } else {
+                                        $$shown{$idx} = 0;
+                                    }
+                                }
                             } else {
                                 $$shown{$idx} = 1;
                             }
@@ -1091,7 +1215,11 @@ sub build_posting_display {
                                 my @postversions = ();
                                 $$discussionitems[$idx] .= &mt('This post has been edited by the author.');
                                 if ($seeid) {
-                                    $$discussionitems[$idx] .= '&nbsp;&nbsp;<a href="/adm/feedback?allversions='.$escsymb.':::'.$idx.'">'.&mt('Display all versions').'</a>';
+                                    $$discussionitems[$idx] .= '&nbsp;&nbsp;<a href="/adm/feedback?allversions='.$escsymb.':::'.$idx;
+                                    if ($group ne '') {
+                                        $$discussionitems[$idx] .= '&amp;'.&grp_args($group);
+                                    }
+                                    $$discussionitems[$idx] .= '">'.&mt('Display all versions').'</a>';
                                 }
                                 $$discussionitems[$idx].='<br/>'.&mt('Earlier version(s) were posted on: ');
                                 if ($contrib{$idx.':history'} =~ m/:/) {
@@ -1154,6 +1282,7 @@ sub filter_regexp {
             $secregexp .= '[^:]*';
         }
     }
+
     if (defined($statusfilter) && $statusfilter ne '') {
         if ($statusfilter eq 'all') {
             $statusregexp = '[^:]+';
@@ -1174,7 +1303,7 @@ sub get_post_contents {
     %{$$imsfiles{$idx}}=();
     if ($type eq 'allversions') {
        unless($seeid) {
-           $discussion=&mt('You do not have privileges to view all versions of posts.').&mt('Please select a different role');
+           $discussion=&mt('You do not have privileges to view all versions of posts.').' '.&mt('Please select a different role.');
            return $discussion;
        } 
     }
@@ -1253,7 +1382,7 @@ END
         }
     }
     if ($type eq 'allversions') {
-        $discussion.=('</ul></body></html>');
+        $discussion.='</ul>';
         return $discussion;
     } else {
         return;
@@ -1301,10 +1430,9 @@ sub replicate_attachments {
 sub mail_screen {
   my ($r,$feedurl,$options) = @_;
   if (exists($env{'form.origpage'})) {
-      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','currnewattach','addnewattach','deloldattach','delnewattach','timestamp','idx','anondiscuss','discuss','blog']);
+      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','currnewattach','addnewattach','deloldattach','delnewattach','timestamp','idx','anondiscuss','discuss','blog','group','ref']);
   }
-  my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion',
-                                          '','onLoad="window.focus();setposttype();"');
+
   my $title=&Apache::lonnet::gettitle($feedurl);
   if (!$title) { $title = $feedurl; }
   my $quote='';
@@ -1324,12 +1452,15 @@ sub mail_screen {
   my $attachnum = 0;
   my $anonchk = (<<END);
   function anonchk() {
-     if (document.mailform.anondiscuss.checked == true) {
-          document.attachment.anondiscuss.value = '1'
-     }
-     if (document.mailform.discuss.checked == true) {
-          document.attachment.discuss.value = '1'
-     }
+      for (var i=0; i < document.mailform.discuss.length; i++) {
+	  if (document.mailform.discuss[i].checked) {
+	      document.attachment.discuss.value = 
+		  document.mailform.discuss[i].value;
+	  }
+      }
+      if (document.mailform.blog.checked) {
+	  document.attachment.blog.value = 1;
+      }
      return
    }
 END
@@ -1337,13 +1468,15 @@ END
   if (exists($env{'form.origpage'})) {
       $anonscript = (<<END);
   function setposttype() {
-      var anondisc = $env{'form.anondiscuss'};
-      var disc = $env{'form.discuss'};
-      if (anondisc == 1) {
-          document.mailform.anondiscuss.checked = true
+      var disc = "$env{'form.discuss'}";
+      for (var i=0; i < document.mailform.discuss.length; i++) {
+	  if (disc == document.mailform.discuss[i].value) {
+	      document.mailform.discuss[i].checked = 1;
+	  }
       }
-      if (disc == 1) {
-          document.mailform.discuss.checked = true
+      var blog = "$env{'form.blog'}";
+      if (blog == 1) {
+          document.mailform.blog.checked=1;
       }
       return
   }
@@ -1410,20 +1543,17 @@ END
                   $parentmsg = $contrib{$idx.':replyto'};
               }
               unless (exists($env{'form.origpage'})) {
-                  my $anonflag = 0;
+                  my $anonflag = 'nonanon';
                   if ($contrib{$idx.':anonymous'}) {
-                      $anonflag = 1;
+                      $anonflag = 'anon';
                   }
                   $anonscript = (<<END);
   function setposttype () {
-      var currtype = $anonflag
-      if (currtype == 1) {
-          document.mailform.elements.discuss.checked = false
-          document.mailform.elements.anondiscuss.checked = true
-      }
-      if (currtype == 0) {
-          document.mailform.elements.anondiscuss.checked = false
-          document.mailform.elements.discuss.checked = true
+      var currtype = "$anonflag";
+      for (var i=0; i<document.mailform.discuss.length; i++) {
+	  if (document.mailform.elements.discuss[i].value == currtype ) {
+	      document.mailform.elements.discuss[i].checked=1;
+	  } 
       }
       return
   }
@@ -1437,54 +1567,30 @@ END
   }
 
   if ($env{'form.origpage'}) {
-      $subject = &Apache::lonnet::unescape($env{'form.subject'});
-      $comment = &Apache::lonnet::unescape($env{'form.comment'});
+      $subject = &unescape($env{'form.subject'});
+      $comment = &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
-<head>
-<title>The LearningOnline Network with CAPA</title>
-<meta http-equiv="pragma" content="no-cache"></meta>
-$htmlheader
+  my $js= <<END;
 <script type="text/javascript">
 //<!--
     function gosubmit() {
         var rec=0;
-        if (typeof(document.mailform.elements.author)!="undefined") {
-          if (document.mailform.elements.author.checked) {
-             rec=1;
-          } 
-        }
-        if (typeof(document.mailform.elements.question)!="undefined") {
-          if (document.mailform.elements.question.checked) {
-             rec=1;
-          } 
-        }
-        if (typeof(document.mailform.elements.course)!="undefined") {
-          if (document.mailform.elements.course.checked) {
-             rec=1;
-          } 
-        }
-        if (typeof(document.mailform.elements.policy)!="undefined") {
-          if (document.mailform.elements.policy.checked) {
-             rec=1;
-          } 
-        }
         if (typeof(document.mailform.elements.discuss)!="undefined") {
-          if (document.mailform.elements.discuss.checked) {
-             rec=1;
-          } 
-        }
-        if (typeof(document.mailform.elements.anondiscuss)!="undefined") {
-          if (document.mailform.elements.anondiscuss.checked) {
-             rec=1;
-          } 
-        }
+	    if (typeof(document.mailform.elements.discuss.length) == "undefined") {
+		if (document.mailform.elements.discuss.checked ) {
+		    rec=1;
+		}
+	    } else {
+		for (var i=0; i<document.mailform.elements.discuss.length; i++) {
+		    if (document.mailform.elements.discuss[i].checked ) {
+			rec=1;
+		    } 
+		}
+	    }
+	}
         if (typeof(document.mailform.elements.blog)!="undefined") {
           if (document.mailform.elements.blog.checked) {
              rec=1;
@@ -1497,15 +1603,22 @@ $htmlheader
 	    }
 	    document.mailform.submit();
         } else {
-            alert('Please check a feedback type.');
+            alert('Please select a feedback type.');
 	}
     }
     $anonchk
     $anonscript
 //-->
 </script>
-</head>
-$bodytag
+END
+
+  my %onload = ('onload' => 'window.focus();setposttype();');
+  my $start_page=
+      &Apache::loncommon::start_page('Resource Feedback and Discussion',$js,
+				     {'add_entries' => \%onload});
+
+  $r->print(<<END);
+$start_page
 <h2><tt>$title</tt></h2>
 <form action="/adm/feedback" method="post" name="mailform"
 enctype="multipart/form-data">
@@ -1559,6 +1672,12 @@ Attachment (128 KB max size): <input typ
 </p>
 END
     }
+    if (exists($env{'form.group'})) {
+        $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
+    }
+    if (exists($env{'form.ref'})) {
+        $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
+    }
     $r->print(<<END);
 <p>
 <input type="hidden" name="sendit" value="1" />
@@ -1579,7 +1698,7 @@ END
         $r->print(&generate_attachments_button($postidx,$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,$numoldver));
         if ($attachnum > 0) {
             if (@currnewattach > 0) {
-                $newattachmsg .= '<b>New attachments</b><br />';
+                $newattachmsg .= '<br /><b>New attachments</b><br />';
                 if (@currnewattach > 1) {
                     $newattachmsg .= '<ol>';
                     foreach my $item (@currnewattach) {
@@ -1602,7 +1721,8 @@ END
     }
     $r->print(&generate_preview_button().
               &Apache::lonhtmlcommon::htmlareaselectactive('comment').
-              '</body></html>');
+	      &Apache::loncommon::end_page());
+
 }
 
 sub print_display_options {
@@ -1613,11 +1733,8 @@ sub print_display_options {
     my $function = &Apache::loncommon::get_users_function();
     my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
                                                     $env{'user.domain'});
-    my $bodytag=&Apache::loncommon::bodytag('Discussion options',
-                                          '','');
 
     my %lt = &Apache::lonlocal::texthash(
-        'dido' => 'Discussion display options',
         'pref' => 'Display Preference',
         'curr' => 'Current setting ',
         'actn' => 'Action',
@@ -1675,13 +1792,9 @@ sub print_display_options {
         $currtogg = $lt{'toggon'};
         $disctogg = 'toggon';
     }
-    my $html=&Apache::lonxml::xmlbegin();
-    $r->print(<<END);
-$html
-<head>
-<title>$lt{'dido'}</title>
-<meta http-equiv="pragma" content="no-cache" />
-<script>
+
+    my $js = <<END;
+<script type="text/javascript">
 function discdispChk(caller) {
     var disctogg = '$toggchg'
     if (caller == 0) {
@@ -1748,46 +1861,53 @@ function setDisp() {
     }
 }
 </script>
-</head>
-$bodytag
-<form name="modifydisp" method="post" action="/adm/feedback">
+END
+
+
+    my $start_page =
+	&Apache::loncommon::start_page('Discussion display options',$js);
+    my $end_page =
+	&Apache::loncommon::end_page();
+    $r->print(<<END);
+$start_page
+<form name="modifydisp" method="POST" action="/adm/feedback">
 $lt{'sdpf'}<br/> $lt{'prca'}  <ol><li>$lt{'whpo'}</li><li>$lt{'unwh'}</li><li>$lt{'wipa'}</li></ol>
 <br />
-<table border="0" cellpadding="0" cellspacing="0">
- <tr>
-  <td width="100%" bgcolor="#000000">
-   <table width="100%" border="0" cellpadding="1" cellspacing="0">
-    <tr>
-     <td width="100%" bgcolor="#000000">
-      <table border="0" cellpadding="3" cellspacing="1" bgcolor="#FFFFFF">
-       <tr bgcolor="$tabcolor">
-        <td><b>$lt{'pref'}</b></td>
-        <td><b>$lt{'curr'}</b></td>
-        <td><b>$lt{'actn'}?</b></td>
+END
+    $r->print(&Apache::loncommon::start_data_table());
+    $r->print(<<END);
+       <tr>
+        <th>$lt{'pref'}</td>
+        <th>$lt{'curr'}</td>
+        <th>$lt{'actn'}?</td>
        </tr>
-       <tr bgcolor="#dddddd">
+END
+    $r->print(&Apache::loncommon::start_data_table_row());
+    $r->print(<<END);
        <td>$lt{'disa'}</td>
        <td>$lt{$discdisp}</td>
        <td><label><input type="checkbox" name="discdisp" onClick="discdispChk('0')" />&nbsp;$lt{'chgt'} "$dispchangeA"</label>
            <br />
            <label><input type="checkbox" name="discdisp" onClick="discdispChk('1')" />&nbsp;$lt{'chgt'} "$dispchangeB"</label>
        </td>
-      </tr><tr bgcolor="#eeeeee">
+END
+    $r->print(&Apache::loncommon::end_data_table_row());
+    $r->print(&Apache::loncommon::start_data_table_row());
+    $r->print(<<END);
        <td>$lt{'npmr'}</td>
        <td>$lt{$discmark}</td>
        <td><label><input type="checkbox" name="discmark" />$lt{'chgt'} "$markchange"</label></td>
-      </tr><tr bgcolor="#dddddd">
+END
+    $r->print(&Apache::loncommon::end_data_table_row());
+    $r->print(&Apache::loncommon::start_data_table_row());
+    $r->print(<<END);
        <td>$lt{'dotm'}</td>
        <td>$lt{$disctogg}</td>
        <td><label><input type="checkbox" name="disctogg" onClick="discdispChk('2')" />$lt{'chgt'} "$toggchange"</label></td>
-      </tr>
-     </table>
-    </td>
-   </tr>
-  </table>
- </td>
-</tr>
-</table>
+END
+    $r->print(&Apache::loncommon::end_data_table_row());
+    $r->print(&Apache::loncommon::end_data_table());
+    $r->print(<<END);
 <br />
 <br />
 <input type="hidden" name="symb" value="$symb" />
@@ -1797,12 +1917,19 @@ $lt{'sdpf'}<br/> $lt{'prca'}  <ol><li>$l
 <input type="hidden" name="$markchg" value=""/>
 <input type="hidden" name="$toggchg" value="" />
 <input type="button" name="sub" value="Store Changes" onClick="javascript:setDisp()" />
+END
+    if (exists($env{'form.group'})) {
+        $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
+    }
+    if (exists($env{'form.ref'})) {
+        $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
+    }
+    $r->print("
 <br />
 <br />
 </form>
-</body>
-</html>
-END
+$end_page
+    ");
     return;
 }
 
@@ -1813,35 +1940,59 @@ sub print_sortfilter_options {
     $r->send_http_header;
 
     &Apache::lonenc::check_encrypt(\$symb);
-    my @sections = ();
+    my @sections;
     my $section_sel = '';
-    my $numsections = 0;
     my $numvisible = 5;
-    my %sectioncount = ();
-
-    $numsections = &Apache::loncommon::get_sections($env{'course.'.$env{'request.course.id'}.'.domain'},$env{'course.'.$env{'request.course.id'}.'.num'},\%sectioncount);
+    my @groups;
+    my $group_sel = '';
+    my $numgroupvis = 5;
+    my %sectioncount = &Apache::loncommon::get_sections();
 
     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
-        if ($numsections < 4) {
-            $numvisible = $numsections + 1;
+        if (scalar(@sections) < 4) {
+            $numvisible = scalar(@sections) + 1;
         }
+        unshift(@sections,'all'); # Put 'all' at the front of the list
+
     }
     foreach (@sections) {
         $section_sel .= "  <option value=\"$_\" />$_\n";
     }
-                                                                                   
+
+    if (&check_group_priv() eq 'ok') {
+        my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+        my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; 
+        my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
+        @groups = sort {$a cmp $b} keys(%curr_groups);
+        if (scalar(@groups) < 4) {
+            $numgroupvis = scalar(@groups) + 1;
+        }
+        unshift(@groups,'all'); # Put 'all' at the front of the list
+    } else { 
+        my @coursegroups = split(/:/,$env{'request.course.groups'});
+        if (@coursegroups > 0) {
+            @coursegroups = sort {$a cmp $b} @coursegroups;
+            @groups = ('all',@coursegroups);
+            if (scalar(@groups) < 4) {
+                $numgroupvis = scalar(@groups) + 1;
+            }
+        } else {
+            @groups = ('all');
+            $numgroupvis = 1;
+        }
+    }
+    foreach (@groups) {
+        $group_sel .= "  <option value=\"$_\" />$_\n";
+    }
+
     my $function = &Apache::loncommon::get_users_function();
     my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
                                                     $env{'user.domain'});
-    my $bodytag=&Apache::loncommon::bodytag('Discussion options',
-                                          '','');
     my %lt = &Apache::lonlocal::texthash(
-        'diso' => 'Discussion sorting and filtering options',
         'diop' => 'Display Options',
         'curr' => 'Current setting ',
         'actn' => 'Action',
@@ -1850,6 +2001,7 @@ sub print_sortfilter_options {
         'spur' => 'Specific user roles',
         'sprs' => 'Specific role status',
         'spse' => 'Specific sections',
+        'spgr' => 'Specific groups',
         'psub' => 'Pick specific users (by name)',
         'shal' => 'Show a list of current posters'
     );
@@ -1858,12 +2010,8 @@ sub print_sortfilter_options {
     my %role_types = ();
     my %status_types = ();
     &sort_filter_names(\%sort_types,\%role_types,\%status_types);
-    my $html=&Apache::lonxml::xmlbegin();
-    $r->print(<<END);
-$html
-<head>
-<title>$lt{'diso'}</title>
-<meta http-equiv="pragma" content="no-cache" />
+
+    my $js = <<END;
 <script type="text/javascript">
 function verifyFilter() {
     var rolenum = 0
@@ -1885,12 +2033,30 @@ function verifyFilter() {
     if (secnum == 0) {
         document.modifyshown.sectionpick.options[0].selected = true
     }
+
+    var grpnum = 0
+    for (var i=0; i<document.modifyshown.grouppick.length; i++) {
+        if (document.modifyshown.grouppick.options[i].selected == true) {
+            grpnum ++
+        }
+    }
+    if (grpnum == 0) {
+        document.modifyshown.grouppick.options[0].selected = true
+    }
+
     document.modifyshown.submit();
 }
 </script>
-</head>
-$bodytag
-<form name="modifyshown" method="post" action="/adm/feedback">
+END
+
+    my $start_page=
+	&Apache::loncommon::start_page('Discussion options',$js);
+    my $end_page=
+	&Apache::loncommon::end_page();
+
+    $r->print(<<END);
+$start_page
+<form name="modifyshown" method="POST" action="/adm/feedback">
 <b>$lt{'diso'}</b><br/> $lt{'prca'}
 <br /><br />
 <table border="0">
@@ -1903,10 +2069,12 @@ $bodytag
   <td>&nbsp;</td>
   <td><b>$lt{'spse'}</b></td>
   <td>&nbsp;</td>
+  <td><b>$lt{'spgr'}</b></td>
+  <td>&nbsp;</td>
   <td><b>$lt{'psub'}</b></td>
  </tr>
  <tr>
-  <td align="center">
+  <td align="center" valign="top">
    <select name="sortposts">
     <option value="ascdate" selected="selected" />$sort_types{'ascdate'}
     <option value="descdate" />$sort_types{'descdate'}
@@ -1917,7 +2085,7 @@ $bodytag
    </select>
   </td>
   <td>&nbsp;</td>
-  <td align="center">
+  <td align="center" valign="top">
    <select name="statusfilter">
     <option value="all" selected="selected" />$status_types{'all'}
     <option value="Active" />$status_types{'Active'}
@@ -1925,7 +2093,7 @@ $bodytag
    </select>
   </td>
   <td>&nbsp;</td>
-  <td align="center">
+  <td align="center" valign="top">
    <select name="rolefilter" multiple="true" size="5">
     <option value="all" />$role_types{'all'}
     <option value="st" />$role_types{'st'}
@@ -1933,18 +2101,23 @@ $bodytag
     <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 align="center">
+  <td align="center" valign="top">
    <select name="sectionpick" multiple="true" size="$numvisible">
     $section_sel
    </select>
   </td>
   <td>&nbsp;</td>
-  <td><label><input type="checkbox" name="posterlist" value="$symb" />$lt{'shal'}</label></td>
+  <td align="center" valign="top">
+   <select name="grouppick" multiple="true" size="$numvisible">
+    $group_sel
+   </select>
+  </td>
+  <td>&nbsp;</td>
+  <td valign="top"><label><input type="checkbox" name="posterlist" value="$symb" />$lt{'shal'}</label></td>
  </tr>
 </table>
 <br />
@@ -1952,12 +2125,19 @@ $bodytag
 <input type="hidden" name="previous" value="$previous" />
 <input type="hidden" name="applysort" value="$symb" />
 <input type="button" name="sub" value="Store Changes" onClick="verifyFilter()" />
+END
+    if (exists($env{'form.group'})) {
+        $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
+    }
+    if (exists($env{'form.ref'})) {
+        $r->print('<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />');
+    }
+    $r->print("
 <br />
 <br />
 </form>
-</body>
-</html>
-END
+$end_page
+");
 }
 
 sub print_showposters {
@@ -1972,23 +2152,36 @@ sub print_showposters {
         $crs.='_'.$env{'request.course.sec'};
     }
     $crs=~s/\_/\//g;
-    my $seeid=&Apache::lonnet::allowed('rin',$crs);
+    my $seeid;
+    my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+    my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+    my $group = $env{'form.group'};
+    my $ressymb = &wrap_symb($symb);
+    if (($group ne '') &&
+        ($ressymb =~ m|^bulletin___ \d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|)) {
+        if (&check_group_priv($group,'dgp') eq 'ok') {
+            $seeid = 1;
+        }
+    } else {
+        $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'});
+                                         $cdom,$cnum);
     my %namesort = ();
     my %postcounts = ();
-    my %lt=&Apache::lonlocal::texthash(
-                     'diso' => 'Discussion filtering options',
-    );
-    my $bodytag=&Apache::loncommon::bodytag('Discussion options',
-                                          '','');
+
+    my %lt = &Apache::lonlocal::texthash(
+                                          sele => 'Select',
+                                          full => 'Fullname',
+                                          usdo => 'Username/domain',
+                                          post => 'Posts',
+                                        );
     if ($contrib{'version'}) {
         for (my $idx=1;$idx<=$contrib{'version'};$idx++) {
             my $hidden=($contrib{'hidden'}=~/\.$idx\./);
             my $deleted=($contrib{'deleted'}=~/\.$idx\./);
             unless ((($hidden) && (!$seeid)) || ($deleted)) {
-                if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
+                if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
                     my %names = &Apache::lonnet::get('environment',['firstname','lastname'],$contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'});
                     my $lastname = $names{'lastname'};
                     my $firstname = $names{'firstname'};
@@ -2014,24 +2207,19 @@ sub print_showposters {
             }
         }
     }
-    my $html=&Apache::lonxml::xmlbegin();
+
+    my $start_page = &Apache::loncommon::start_page('Discussion options');
+    my $table_start =&Apache::loncommon::start_data_table();
     $r->print(<<END);
-$html
-<head>
-<title>$lt{'diso'}</title>
-<meta http-equiv="pragma" content="no-cache" />
-</head>
-$bodytag
+$start_page
  <form name="pickpostersform" method="post">
-  <table border="0">
-   <tr>
-    <td bgcolor="#777777">
-     <table border="0" cellpadding="3">
-      <tr bgcolor="#e6ffff">
-       <td><b>No.</b></td>
-       <td><b>Select</b></td>
-       <td><b>Fullname</b><font color="#999999">(Username/domain)</font></td>
-       <td><b>Posts</td>
+ <br />
+    $table_start
+      <tr>
+       <th>#</th>
+       <th>$lt{'sele'}</th>
+       <th>$lt{'full'} <font color="#999999">($lt{'usdo'})</font></th>
+       <th>$lt{'post'}</th>
       </tr>
 END
     my $count = 0;
@@ -2043,23 +2231,25 @@ END
                     next;
                 } else {
                     $count ++;
-                    $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>');
+                    $r->print(&Apache::loncommon::start_data_table_row().
+			      '<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>'.
+			      &Apache::loncommon::end_data_table_row());
                 }
             }
         }
     }
+    $r->print(&Apache::loncommon::end_data_table());
+    my $end_page   = &Apache::loncommon::end_page();
     $r->print(<<END);
-     </table>
-    </td>
-   </tr>
-  </table>
 <br />
 <input type="hidden" name="sortposts" value="$sortposts" />
 <input type="hidden" name="userpick" value="$symb" />
 <input type="button" name="store" value="Display posts" onClick="javascript:document.pickpostersform.submit()" />
 </form>
-</body>
-</html>
+$end_page
 END
 }
 
@@ -2067,7 +2257,8 @@ sub get_post_versions {
     my ($versions,$incoming,$htmldecode,$numver) = @_;
     if ($incoming =~ /^<version num="0">/) {
         my $p = HTML::LCParser->new(\$incoming);
-        my $done = 0;                                                                       
+        my $done = 0; 
+
         while ( (my $token = $p->get_tag("version")) && (!$done)) {
             my $num = $token->[1]{num};
             my $text = $p->get_text("/version");
@@ -2128,36 +2319,29 @@ 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>
-<meta http-equiv="pragma" content="no-cache" />
-<meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
-</head>
-<body bgcolor="#FFFFFF">
+  $r->print(&Apache::loncommon::start_page('Feedback not sent',undef,
+					   {'redirect'  => [2,$feedurl],
+					    'only_body' => 1,}));
+  $r->print(<<ENDFAILREDIR);
 <img align="right" src="$logo" />
 <b>Sorry, no recipients  ...</b>
-<br /><a href="$feedurl">Continue</a>
-</body>
-</html>
 ENDFAILREDIR
+  $r->print(&Apache::loncommon::end_page());
 }
 
 sub redirect_back {
-  my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$numpicks) = @_;
+  my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$grouppick,$numpicks,$group) = @_;
   my $sorttag = '';
   my $roletag = '';
   my $statustag = '';
   my $sectag = '';
+  my $grptag = '';
   my $userpicktag = '';
   my $qrystr = '';
   my $prevtag = '';
 
   &Apache::loncommon::content_type($r,'text/html');
   $r->send_http_header;
-
   &dewrapper(\$feedurl);
   if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
   if ($previous > 0) {
@@ -2196,6 +2380,20 @@ sub redirect_back {
               $feedurl .= '&sectionpick='.$sectionpick;
               $sectag = '<input type="hidden" name="sectionpick" value="'.$sectionpick.'" />';
           }
+          if (ref($grouppick) eq 'ARRAY') {
+              $feedurl .= '&grouppick=';
+              $sectag .=  '<input type="hidden" name="grouppick" value="';
+              foreach my $grp (@{$grouppick}) {
+                  $feedurl .= $grp.',';
+                  $grptag .= $grp.',';
+              }
+              $feedurl =~ s/,$//;
+              $grptag =~ s/,$//;
+              $grptag .= '" />';
+          } else {
+              $feedurl .= '&grouppick='.$grouppick;
+              $grptag = '<input type="hidden" name="grouppick" value="'.$grouppick.'" />';
+          }
           if (ref($rolefilter) eq 'ARRAY') {
               $feedurl .= '&rolefilter=';
               $roletag .=  '<input type="hidden" name="rolefilter" value="';
@@ -2214,17 +2412,34 @@ sub redirect_back {
           $statustag ='<input type="hidden" name="statusfilter" value="'.$statusfilter.'" />';
       }
   }
+  my $grouptag;
+  if ($group ne '') {
+      $grouptag = '<input type="hidden" name="group" value="'.$group.'" />';      my $refarg;
+      if (exists($env{'form.ref'})) {
+          $refarg = '&amp;ref='.$env{'form.ref'};
+          $grouptag .= '<input type="hidden" name="ref" value="'.$env{'form.ref'}.'" />';
+      }
+      if ($feedurl =~ /\?/) {
+          $feedurl .= '&amp;group='.$group.$refarg;
+      } else {
+          $feedurl .= '?group='.$group.$refarg;
+      }
+  } 
   $feedurl=&Apache::lonenc::check_encrypt($feedurl);
   my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
-  my $html=&Apache::lonxml::xmlbegin();
-  $r->print (<<ENDREDIR);
-$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.window.close(); }'>
+  my %onload;
+  if ($env{'environment.remote'} ne 'off') {
+      $onload{'onload'} =
+	  "if (window.name!='loncapaclient') { this.document.reldt.submit(); self.window.close(); }";
+  }
+  my $start_page=
+      &Apache::loncommon::start_page('Feedback sent',undef,
+				     {'redirect'    => [0,$feedurl],
+				      'only_body'   => 1,
+				      'add_entries' => \%onload});
+  my $end_page = &Apache::loncommon::end_page();
+  $r->print(<<ENDREDIR);
+$start_page
 <img align="right" src="$logo" />
 $typestyle
 <b>Sent $sendsomething message(s), and $sendposts post(s).</b>
@@ -2236,40 +2451,45 @@ $sorttag
 $statustag
 $roletag
 $sectag
+$grptag
 $userpicktag
+$grouptag
 </form>
-<br /><a href="$feedurl">Continue</a>
-</body>
-</html>
+$end_page
 ENDREDIR
 }
 
 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>
-<meta http-equiv="pragma" content="no-cache" />
-ENDNOREDIR
-
-  if ($feedurl!~/^\/adm\/feedback/) { 
-      $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="2; url='.
-		&Apache::lonenc::check_encrypt($feedurl).'">');
-  }
+ 
+  my %onload;
+  if ($env{'environment.remote'} ne 'off') {
+      $onload{'onload'} = 
+	  "if (window.name!='loncapaclient') { self.window.close(); }";
+  }
+
+  my %body_options = ('only_body'   => 1,
+		      'bgcolor'     => '#FFFFFF',
+		      'add_entries' => \%onload,);
+
+  if ($feedurl !~ m{^/adm/feedback}) { 
+      $body_options{'rediect'} = [2,$feedurl];
+  }
+  my $start_page=
+      &Apache::loncommon::start_page('Feedback not sent',undef,
+				     \%body_options);
+				      
+  my $end_page = &Apache::loncommon::end_page();
+
   $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.window.close(); }'>
+$start_page
 <img align="right" src="$logo" />
 <b>$nofeed</b>
-<br /><a href="$feedurl">$continue</a>
-</body>
-</html>
+<br />
+$end_page
 ENDNOREDIRTWO
 }
 
@@ -2280,36 +2500,35 @@ sub screen_header {
     unless (($env{'form.replydisc'}) || ($env{'form.editdisc'})) {
 	if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/) && ($env{'user.adv'})) {
 	    $msgoptions= 
-		'<p><label><input type="checkbox" name="author" /> '.
+		'<p><label><input type="radio" name="discuss" value="author" /> '.
 		&mt('Feedback to resource author').'</label></p>';
 	}
 	if (&feedback_available(1)) {
 	    $msgoptions.=
-		'<p><label><input type="checkbox" name="question" /> '.
+		'<p><label><input type="radio" name="discuss" value="question" /> '.
 		&mt('Question about resource content').'</label></p>';
 	}
 	if (&feedback_available(0,1)) {
 	    $msgoptions.=
-		'<p><label><input type="checkbox" name="course" /> '.
+		'<p><label><input type="radio" name="discuss" value="course" /> '.
 		&mt('Question/Comment/Feedback about course content').
 		'</label></p>';
 	}
 	if (&feedback_available(0,0,1)) {
 	    $msgoptions.=
-		'<p><label><input type="checkbox" name="policy" /> '.
+		'<p><label><input type="radio" name="discuss" value="policy" /> '.
 		&mt('Question/Comment/Feedback about course policy').
 		'</label></p>';
 	}
     }
-    if ($env{'request.course.id'}) {
+    if (($env{'request.course.id'}) && (!$env{'form.sendmessageonly'})) {
 	if (&discussion_open(undef,$symb) &&
 	    &Apache::lonnet::allowed('pch',
 				     $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"':'').' /> '.
+	    $discussoptions='<label><input type="radio" name="discuss" value="nonanon" checked="checked" /> '.
 		&mt('Contribution to course discussion of resource');
-	    $discussoptions.='</label><br /><label><input type="checkbox" name="anondiscuss" onClick="this.form.discuss.checked=false;" /> '.
+	    $discussoptions.='</label><br /><label><input type="radio" name="discuss" value="anon" /> '.
 		&mt('Anonymous contribution to course discussion of resource').
 		' <i>('.&mt('name only visible to course faculty').')</i></label> '.
 		'<a href="/adm/preferences?action=changescreenname">'.&mt('Change Screenname').'</a>';
@@ -2337,8 +2556,9 @@ sub resource_output {
 }
 
 sub clear_out_html {
-  my ($message,$override)=@_;
-  unless (&Apache::lonhtmlcommon::htmlareablocked()) { return $message; }
+  my ($message,$override,$ignore_htmlarea)=@_;
+  if (!$ignore_htmlarea
+      && !&Apache::lonhtmlcommon::htmlareablocked()) { return $message; }
 # Always allow the <m>-tag
   my %html=(M=>1);
 # Check if more is allowed
@@ -2354,9 +2574,9 @@ sub clear_out_html {
 	     H1=>1, H2=>1, H3=>1, H4=>1, H5=>1);
   }
 # Do the substitution of everything that is not explicitly allowed
-  $message =~ s/\<(\/?\s*(\w+)[^\>\<]*)/
+  $message =~ s/\<(\/?\s*(\w*)[^\>\<]*)/
 	  {($html{uc($2)}&&(length($1)<1000))?"\<$1":"\&lt;$1"}/ge;
-  $message =~ s/(\<?\s*(\w+)[^\<\>]*)\>/
+  $message =~ s/(\<?\s*(\w*)[^\<\>]*)\>/
 	  {($html{uc($2)}&&(length($1)<1000))?"$1\>":"$1\&gt;"}/ge;
   return $message;
 }
@@ -2432,13 +2652,13 @@ sub decide_receiver {
   my ($feedurl,$author,$question,$course,$policy,$defaultflag) = @_;
   my $typestyle='';
   my %to=();
-  if ($env{'form.author'}||$author) {
+  if ($env{'form.discuss'} eq 'author' ||$author) {
     $typestyle.='Submitting as Author Feedback<br />';
     $feedurl=~/^\/res\/(\w+)\/(\w+)\//;
     $to{$2.':'.$1}=1;
   }
-  if ($env{'form.question'}||$question) {
-    $typestyle.='Submitting as Question<br />';
+  if ($env{'form.discuss'} eq 'question' ||$question) {
+    $typestyle.=&mt('Submitting as Question').'<br />';
     foreach (split(/\,/,
 		   $env{'course.'.$env{'request.course.id'}.'.question.email'})
 	     ) {
@@ -2446,8 +2666,8 @@ sub decide_receiver {
         if ($rec) { $to{$rec}=1; }
     } 
   }
-  if ($env{'form.course'}||$course) {
-    $typestyle.='Submitting as Comment<br />';
+  if ($env{'form.discuss'} eq 'course' ||$course) {
+    $typestyle.=&mt('Submitting as Comment').'<br />';
     foreach (split(/\,/,
 		   $env{'course.'.$env{'request.course.id'}.'.comment.email'})
 	     ) {
@@ -2455,8 +2675,8 @@ sub decide_receiver {
         if ($rec) { $to{$rec}=1; }
     } 
   }
-  if ($env{'form.policy'}||$policy) {
-    $typestyle.='Submitting as Policy Feedback<br />';
+  if ($env{'form.discuss'} eq 'policy' ||$policy) {
+    $typestyle.=&mt('Submitting as Policy Feedback').'<br />';
     foreach (split(/\,/,
 		   $env{'course.'.$env{'request.course.id'}.'.policy.email'})
 	     ) {
@@ -2618,21 +2838,25 @@ sub adddiscuss {
 # ----------------------------------------------------------- Preview function
 
 sub show_preview {
-    my $r=shift;
+    my ($r) = @_;
     &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;
     my $message=&clear_out_html($env{'form.comment'});
     &newline_to_br(\$message);
     $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'},undef,1);
     $subject=~s/\n/\<br \/\>/g;
     $subject=&Apache::lontexconvert::msgtexconverted($subject);
-    my $html=&Apache::lonxml::xmlbegin();
-    $r->print($html.'<head>'.
-	      '</head><body><table border="2"><tr><td>'.
+    my $start_page=
+	&Apache::loncommon::start_page('Preview',undef,
+				       {'only_body'   => 1,});
+					
+    my $end_page = &Apache::loncommon::end_page();
+
+    $r->print($start_page.'<table border="2"><tr><td>'.
 	      '<b>Subject:</b> '.$subject.'<br /><br />'.
-	      $message.'</td></tr></table></body></html>');
+	      $message.'</td></tr></table>'.$end_page);
 }
 
 
@@ -2663,6 +2887,7 @@ sub generate_preview_button {
     unless ($fieldname) { $fieldname='comment'; }
     my $pre=&mt("Show Preview and Check Spelling");
     return(<<ENDPREVIEW);
+<br />
 <form name="preview" action="/adm/feedback?preview=1" method="post" target="preview">
 <input type="hidden" name="subject">
 <input type="hidden" name="comment" />
@@ -2674,14 +2899,13 @@ ENDPREVIEW
 
 sub modify_attachments {
     my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_;
-    my $orig_subject = &Apache::lonnet::unescape($env{'form.subject'});
-    my $subject=&clear_out_html($orig_subject);
+    my $orig_subject = &unescape($env{'form.subject'});
+    my $subject=&clear_out_html($orig_subject,undef,1);
     $subject=~s/\n/\<br \/\>/g;
     $subject=&Apache::lontexconvert::msgtexconverted($subject);
     my $timestamp=$env{'form.timestamp'};
     my $numoldver=$env{'form.numoldver'};
-    my $bodytag=&Apache::loncommon::bodytag('Discussion Post Attachments',
-                                          '','');
+
     my $msg = '';
     my %attachments = ();
     my %currattach = ();
@@ -2689,19 +2913,22 @@ 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
-<head>
-<title>Managing Attachments</title>
-<script>
+    my $js = <<END;
+<script type="text/javascript">
  function setAction () {
    document.modattachments.action = document.modattachments.origpage.value;
    document.modattachments.submit();
  }
 </script> 
-</head>
-$bodytag
+END
+
+    my $start_page = 
+	&Apache::loncommon::start_page('Discussion Post Attachments',$js);
+    my $end_page = 
+	&Apache::loncommon::end_page();
+				       
+    $r->print(<<END);
+$start_page
 <form name="modattachments" method="post" enctype="multipart/form-data" action="/adm/feedback?attach=$symb">
  <table border="2">
   <tr>
@@ -2741,7 +2968,6 @@ END
 <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="blog" value="$env{'form.blog'}" />
 <input type="hidden" name="discuss" value="$env{'form.discuss'}" />
 END
@@ -2754,8 +2980,7 @@ END
     $r->print(<<END);
  <input type="button" name="rtntoedit" value="Store Changes" onClick="setAction()"/>
 </form>
-</body>
-</html>
+$end_page
 END
     return;
 }
@@ -2793,6 +3018,7 @@ sub generate_attachments_button {
     my $origpage = $ENV{'REQUEST_URI'};
     my $att=$attachnum.' '.&mt("attachments");
     my $response = (<<END);
+<br />
 <form name="attachment" action="/adm/feedback?attach=$ressymb" method="post">
 Click to add/remove attachments:&nbsp;<input type="button" value="$att"
 onClick="if (typeof(document.mailform.onsubmit)=='function') {document.mailform.onsubmit();};this.form.comment.value=escape(document.mailform.comment.value);this.form.subject.value=escape(document.mailform.subject.value);
@@ -2808,7 +3034,6 @@ this.form.submit();" />
 <input type="hidden" name="subject" />
 <input type="hidden" name="comment" />
 <input type="hidden" name="blog" value = "0" />
-<input type="hidden" name="anondiscuss" value = "0" />
 <input type="hidden" name="discuss" value = "0" />
 <input type="hidden" name="numoldver" value="$numoldver" />
 ENDATTACH
@@ -2988,13 +3213,15 @@ sub handler {
 # --------------------------- Get query string for limited number of parameters
 
   &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']);
+         ['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','groupick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export','sendmessageonly','group','ref']);
+  my $group = $env{'form.group'};
   if ($env{'form.editdisc'}) {
-      if (!(&editing_allowed())) {
+      if (!(&editing_allowed($env{'form.editdisc'},$env{'form.group'}))) {
           my $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
           my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
           my $feedurl=&Apache::lonnet::clutter($url);
-          &redirect_back($r,$feedurl,&mt('Editing not permitted').'<br />',                     '0','0','','',$env{'form.previous'},'','','',);
+          &redirect_back($r,$feedurl,&mt('Editing not permitted').'<br />',                     '0','0','','',$env{'form.previous'},undef,undef,undef,
+                    undef,undef,undef,$group);
           return OK;
       }
   } 
@@ -3021,30 +3248,36 @@ sub handler {
 			  \%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'},'','','',
+                     undef,undef,undef,$group);
       return OK;
   }
   if ($env{'form.allversions'}) {
       &Apache::loncommon::content_type($r,'text/html');
+      &Apache::loncommon::no_cache($r);
       $r->send_http_header;
-      my $html=&Apache::lonxml::xmlbegin();
-      my $bodytag=&Apache::loncommon::bodytag('Discussion Post Versions');
-      $r->print(<<END);
-$html
-<head>
-<title>Post Versions</title>
-<meta http-equiv="pragma" content="no-cache" />
-</head>
-$bodytag
-END
+
+      $r->print(&Apache::loncommon::start_page('Discussion Post Versions'));
+
       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 $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+      my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
       my ($symb,$idx)=split(/\:\:\:/,$env{'form.allversions'});
       ($symb)=&get_feedurl_and_clean_symb($symb);
+      my $ressymb = &wrap_symb($symb);
+      my $group = $env{'form.group'};
+      my $seeid;
+      if (($group ne '') && (($ressymb =~ m|^bulletin___\d+___adm/wrapper/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard$|))) {
+          if (&check_group_priv($group,'dgp') eq 'ok') {
+              $seeid = 1;
+          }
+      } else {
+          $seeid = &Apache::lonnet::allowed('rin',$crs);
+      }
       if ($idx > 0) {
           my %messages = ();
           my %subjects = ();
@@ -3057,6 +3290,7 @@ END
                            $env{'course.'.$env{'request.course.id'}.'.num'});
           $r->print(&get_post_contents(\%contrib,$idx,$seeid,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname));
       }
+      $r->print(&Apache::loncommon::end_page());
       return OK;
   }
   if ($env{'form.posterlist'}) {
@@ -3075,7 +3309,7 @@ END
 			   \%discinfo,$env{'user.domain'},$env{'user.name'});
       &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0','',
 		     '',$env{'form.previous'},$env{'form.sortposts'},'','','',
-		     $numpicks);
+		     '',$numpicks,$group);
       return OK;
   }
   if ($env{'form.applysort'}) {
@@ -3083,7 +3317,8 @@ END
       &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.sectionpick'});
+		     $env{'form.sectionpick'},$env{'form.grouppick'},
+                     undef,$group);
       return OK;
   } elsif ($env{'form.cmd'} eq 'sortfilter') {
       my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
@@ -3125,22 +3360,26 @@ END
       &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();
+      my %onload;
+      if ($env{'environment.remote'} ne 'off') {
+	  $onload{'onload'} =
+	      "if (window.name!='loncapaclient') { this.document.reldt.submit(); self.window.close(); }";
+      }
+
+      my $start_page=
+	  &Apache::loncommon::start_page('New posts marked as read',undef,
+					 {'redirect'    => [2,$feedurl],
+					  'only_body'   => 1,
+					  'add_entries' => \%onload});
+      my $end_page = &Apache::loncommon::end_page();
       $r->print (<<ENDREDIR);
-$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.window.close(); }'>
+$start_page
 <img align="right" src="$logo" />
 $textline
 <form name="reldt" action="$feedurl" target="loncapaclient">
 </form>
-<br /><a href="$feedurl">Continue</a>
-</body>
-</html>
+<br />
+$end_page
 ENDREDIR
       return OK;
   } elsif ($env{'form.modifydisp'}) {
@@ -3184,7 +3423,7 @@ ENDREDIR
       my $previous=$env{'form.previous'};
       if ($env{'form.markondisp'}) { $previous=undef; }
       &redirect_back($r,$feedurl,&mt('Changed display status').'<br />',
-		     '0','0','','',$previous);
+		     '0','0','','',$previous,'','','','','','',$group);
       return OK;
   } elsif (($env{'form.hide'}) || ($env{'form.unhide'})) {
 # ----------------------------------------------------------------- Hide/unhide
@@ -3199,8 +3438,9 @@ ENDREDIR
       $crs=~s/\_/\//g;
       my $seeid=&Apache::lonnet::allowed('rin',$crs);
 
-      if ($env{'form.hide'} && !$seeid && !(&editing_allowed())) {
-          &redirect_back($r,$feedurl,&mt('Deletion not permitted').'<br />',                 '0','0','','',$env{'form.previous'},'','','',);
+      if ($env{'form.hide'} && !$seeid && !(&editing_allowed($env{'form.hide'},$env{'form.group'}))) {
+          &redirect_back($r,$feedurl,&mt('Deletion not permitted').'<br />',                 '0','0','','',$env{'form.previous'},'','','','',
+                 undef,undef,$group,);
           return OK;
       }
 
@@ -3229,7 +3469,8 @@ ENDREDIR
 			   $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'},undef,undef,undef,
+                     undef,undef,undef,$group);
       return OK;
   } elsif ($env{'form.cmd'}=~/^(threadedoff|threadedon)$/) {
       my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
@@ -3241,7 +3482,8 @@ 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'},undef,undef,undef,
+                     undef,undef,undef,$group);
       return OK;
   } elsif ($env{'form.deldisc'}) {
 # --------------------------------------------------------------- Hide for good
@@ -3255,7 +3497,8 @@ ENDREDIR
 			   $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'},undef,undef,undef,
+                     undef,undef,undef,$group);
       return OK;
   } elsif ($env{'form.preview'}) {
 # -------------------------------------------------------- User wants a preview
@@ -3265,7 +3508,7 @@ ENDREDIR
 # -------------------------------------------------------- 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','blog']);
+      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','addnewattach','delnewattach','timestamp','numoldver','idx','discuss','blog']);
       my (@currnewattach,@currdelold,@keepold);
       &process_attachments(\@currnewattach,\@currdelold,\@keepold);
       if (exists($env{'form.addnewattach.filename'})) {
@@ -3299,8 +3542,11 @@ ENDREDIR
           $status=$Apache::inputtags::status[-1];
       }
       my $discussion = &list_discussion($mode,$status,$symb); 
-      my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion');
-      $r->print($bodytag.$discussion);                                     
+      my $start_page = 
+	  &Apache::loncommon::start_page('Resource Feedback and Discussion');
+      my $end_page = 
+	  &Apache::loncommon::end_page();
+      $r->print($start_page.$discussion.$end_page);
       return OK;
   } else {
 # ------------------------------------------------------------- Normal feedback
@@ -3421,15 +3667,18 @@ ENDREDIR
       my ($typestyle,%to) = &decide_receiver($feedurl);
 
 # Actually send mail
-      my ($status,$numsent)=&send_msg(&clear_out_html($env{'form.subject'}),$feedurl,$email,$citations,
+      my ($status,$numsent)=&send_msg(&clear_out_html($env{'form.subject'},
+						      undef,1),
+				      $feedurl,$email,$citations,
 				      $attachmenturl,%to);
 
 # 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'} ne ''
+	     && $env{'form.discuss'} !~ /^(?:author|question|course|policy)/)
+	   || $env{'form.anondiscuss'} ne '') {
+	  my $subject = &clear_out_html($env{'form.subject'},undef,1);
+	  my $anonmode=($env{'form.discuss'} eq 'anon' || $env{'form.anondiscuss'} );
 	  $typestyle.=&adddiscuss($symb,$message,$anonmode,$attachmenturl,
 				  $subject);
 	  $numpost++;
@@ -3439,7 +3688,7 @@ ENDREDIR
 
       my $blog='';
       if ($env{'form.blog'}) {
-	  my $subject = &clear_out_html($env{'form.subject'});
+	  my $subject = &clear_out_html($env{'form.subject'},undef,1);
 	  $status.=&Apache::lonrss::addentry($env{'user.name'},
 				    $env{'user.domain'},
 				    'CourseBlog_'.$env{'request.course.id'},
@@ -3448,7 +3697,7 @@ ENDREDIR
       }
 	  
 # Receipt screen and redirect back to where came from
-      &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'});
+      &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'},undef,undef,undef,undef,undef,undef,$group);
   }
   return OK;
 } 
@@ -3489,7 +3738,19 @@ sub get_feedurl_and_clean_symb {
 }
 
 sub editing_allowed {
+    my ($postid,$group) = @_;
+    $postid = &unescape($postid);
     my $can_edit = 0;
+    if ($group ne '') {
+        my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+        my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+        if ($postid =~ m|^bulletin___\d+___adm/wrapper(/adm/\Q$cdom\E/\Q$cnum\E/\d+/bulletinboard)|) {
+            if (&check_group_priv($group,'egp') eq 'ok') {
+                $can_edit = 1;
+            }
+            return $can_edit;
+        }     
+    } 
     my $cid = $env{'request.course.id'};
     my $role = (split(/\./,$env{'request.role'}))[0];
     my $section = $env{'request.course.sec'};
@@ -3516,5 +3777,31 @@ sub editing_allowed {
     return $can_edit;
 }
 
+sub check_group_priv {
+    my ($group,$grp_priv) = @_;
+    foreach my $priv ('mdg','vcg') {
+        my $checkcourse = $env{'request.course.id'}.
+            ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'');
+        if (&Apache::lonnet::allowed($priv,$checkcourse)) {
+            return 'ok';
+        }
+    }
+    if ($grp_priv && $group ne '') {
+        if (&Apache::lonnet::allowed($grp_priv,$env{'request.course.id'}.'/'.$group)) {
+            return 'ok';
+        }
+    }
+    return '';
+}
+
+sub grp_args { 
+    my ($group) = @_;
+    my $extra_args = 'group='.$group;
+    if (exists($env{'form.ref'})) {
+        $extra_args .= '&ref='.$env{'form.ref'};
+    }
+    return $extra_args;
+}
+
 1;
 __END__