--- loncom/interface/lonfeedback.pm	2006/05/09 20:54:55	1.201
+++ loncom/interface/lonfeedback.pm	2006/11/28 21:44:37	1.218
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Feedback
 #
-# $Id: lonfeedback.pm,v 1.201 2006/05/09 20:54:55 albertel Exp $
+# $Id: lonfeedback.pm,v 1.218 2006/11/28 21:44:37 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;
@@ -323,6 +335,7 @@ sub list_discussion {
     if ($newpostsflag) {
         $chglink .= '&previous='.$prevread;
     }
+    $chglink.=&group_args($group);
 
     if ($visible) {
 # Print the discusssion
@@ -394,23 +407,26 @@ 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;
 		}
+		$discussion .= &group_args($group);
 		$discussion .='">'.&mt('Threaded View').'</a>&nbsp;&nbsp;'.
 		    '<a href="/adm/feedback?cmd=threadedoff&amp;symb='.$escsymb;
 		if ($newpostsflag) {
 		    $discussion .= '&previous='.$prevread;
 		}
+		$discussion .= &group_args($group);
 		$discussion .='">'.&mt('Chronological View').'</a>&nbsp;&nbsp;
                               <a href= "/adm/feedback?cmd=sortfilter&amp;symb='.$escsymb;
                 if ($newpostsflag) {
                     $discussion .= '&previous='.$prevread;
                 }
+		$discussion .= &group_args($group);
                 $discussion .='">'.&mt('Sorting/Filtering options').'</a>&nbsp;&nbsp';
             } else {
                 $discussion .= '<td align="left">';
@@ -419,12 +435,17 @@ imscp_v1p1.xsd http://www.imsglobal.org/
             if ($newpostsflag) {
                 $discussion .= '&previous='.$prevread;
             }
+	    $discussion .= &group_args($group);
             $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';
+		    $discussion .= &group_args($group);
+		    $discussion .= '">'.
+                        &mt('Preferences on what is marked as NEW').
+			'</a><br /><a href="/adm/feedback?markread=1&amp;symb='.$escsymb;
+		    $discussion .= &group_args($group);
+                    $discussion .= '">'.&mt('Mark NEW posts no longer new').'</a>';
 		} else {
 		    $discussion .= '<td>&nbsp;</td>';
 		}
@@ -441,6 +462,7 @@ imscp_v1p1.xsd http://www.imsglobal.org/
                 if ($newpostsflag) {
                     $discussion .= '&previous='.$prevread;
                 }
+		$discussion .= &group_args($group);
                 $discussion .= '">'.&mt('Show all posts').'</a> '.&mt('to display').' '.
                          $numhidden.' ';
                 if ($showunmark) {
@@ -609,6 +631,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,61 +713,35 @@ 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 .= '<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";
-                    }
+            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>';
@@ -751,29 +751,88 @@ ENDDISCUSS
 	        ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
 	    if ($outputtarget ne 'tex') {
 		$discussion.='<a href="/adm/feedback?replydisc='.
-		    &Apache::lonnet::escape($ressymb).':::" '.$target.'>'.
-		    '<img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').'" border="0" />'.
+		    &escape($ressymb).':::" '.$target.'>'.
+		    '<img alt="" src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').'" border="0" />'.
 		    &mt('Post Discussion').'</a><br />';
             }
 	}
-	$discussion.='<a href="/adm/feedback?sendmessageonly=1&symb='.
-	    &Apache::lonnet::escape($ressymb).
-	    '"><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/feedback.gif').'" border="0" />'.
-		    &mt('Send Message').'</td></tr></table>';
+	$discussion.='<a href="/adm/feedback?sendmessageonly=1&amp;symb='.
+	    &escape($ressymb).
+	    '"><img alt="" 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') {
@@ -781,7 +840,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++) {
@@ -870,7 +930,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'},
@@ -911,14 +971,16 @@ 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>';                                             
+				    $sender .= &group_args($group);
+                                    $sender .= '" '.$target.'>'.&mt('Edit').'</a>';
+                                    
                                     unless ($seeid) {
                                         $sender.=" <a href=\"javascript:studentdelete('$escsymb','$idx','$$newpostsflag','$prevread')";
                                         $sender .= '">'.&mt('Delete').'</a>';
@@ -941,6 +1003,7 @@ sub build_posting_display {
                                     if ($$newpostsflag) {
                                         $sender .= '&previous='.$prevread;
                                     }
+				    $sender .= &group_args($group);
                                     $sender .= '">'.&mt('Hide').'</a>';
 			        }                     
 			        $sender.=' <a href="/adm/feedback?deldisc='.
@@ -948,6 +1011,7 @@ sub build_posting_display {
                                 if ($$newpostsflag) {
                                     $sender .= '&previous='.$prevread;
                                 }
+				$sender .= &group_args($group);
                                 $sender .= '">'.&mt('Delete').'</a>';
                             }
 		        } else {
@@ -975,16 +1039,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 .= &group_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',
@@ -1041,7 +1116,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) {
@@ -1066,6 +1141,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;
                             }
@@ -1096,7 +1188,9 @@ 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;
+				    $$discussionitems[$idx] .= &group_args($group);
+                                    $$discussionitems[$idx] .= '">'.&mt('Display all versions').'</a>';
                                 }
                                 $$discussionitems[$idx].='<br/>'.&mt('Earlier version(s) were posted on: ');
                                 if ($contrib{$idx.':history'} =~ m/:/) {
@@ -1159,6 +1253,7 @@ sub filter_regexp {
             $secregexp .= '[^:]*';
         }
     }
+
     if (defined($statusfilter) && $statusfilter ne '') {
         if ($statusfilter eq 'all') {
             $statusregexp = '[^:]+';
@@ -1179,7 +1274,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;
        } 
     }
@@ -1306,7 +1401,7 @@ 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 $title=&Apache::lonnet::gettitle($feedurl);
@@ -1391,14 +1486,11 @@ END
                       $numoldver = 1;
                   }
               }
-              my $message;
               if ($idx > 0) {
                   my %msgversions = ();
                   &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);
-                  $message = $msgversions{$numoldver};
+                  $quote = $msgversions{$numoldver};
               }
-	      &newline_to_br(\$message);
-	      $quote='<blockquote>'.&Apache::lontexconvert::msgtexconverted($message).'</blockquote>';
               if ($idx > 0) {
                   my %subversions = ();
                   &get_post_versions(\%subversions,$contrib{$idx.':subject'},1,$numoldver);
@@ -1419,18 +1511,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.value = 'anon'
-      }
-      if (currtype == 0) {
-          document.mailform.elements.discuss.value = 'nonanon'
+      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
   }
@@ -1444,8 +1535,8 @@ 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();
@@ -1455,33 +1546,19 @@ END
 //<!--
     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") {
-	  // anon versus nonanon discussion
-          if (document.mailform.elements.discuss[0].checked 
-	      || document.mailform.elements.discuss[1].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;
@@ -1508,6 +1585,11 @@ END
       &Apache::loncommon::start_page('Resource Feedback and Discussion',$js,
 				     {'add_entries' => \%onload});
 
+  if ($quote ne '') {
+      &newline_to_br(\$quote);
+      $quote='<blockquote>'.&Apache::lontexconvert::msgtexconverted($quote).'</blockquote>';
+  }
+
   $r->print(<<END);
 $start_page
 <h2><tt>$title</tt></h2>
@@ -1563,6 +1645,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" />
@@ -1597,7 +1685,7 @@ END
                 }
             }
             if ($attachmsg) {
-                $r->print("<b>Retained attachments</b>:$attachmsg<br />\n");
+                $r->print("<br /><b>Retained attachments</b>:$attachmsg<br />\n");
             }
             if ($newattachmsg) {
                 $r->print("$newattachmsg<br />");
@@ -1802,11 +1890,19 @@ END
 <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>
 $end_page
-END
+    ");
     return;
 }
 
@@ -1820,6 +1916,9 @@ sub print_sortfilter_options {
     my @sections;
     my $section_sel = '';
     my $numvisible = 5;
+    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 
@@ -1833,10 +1932,36 @@ sub print_sortfilter_options {
         unshift(@sections,'all'); # Put 'all' at the front of the list
 
     }
-    foreach (@sections) {
-        $section_sel .= "  <option value=\"$_\" />$_\n";
+    foreach my $sec (@sections) {
+        $section_sel .= "  <option value=\"$sec\">$sec</option>\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 my $group (@groups) {
+        $group_sel .= "  <option value=\"$group\">$group</option>\n";
+    }
+
     my $function = &Apache::loncommon::get_users_function();
     my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
                                                     $env{'user.domain'});
@@ -1849,6 +1974,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'
     );
@@ -1880,6 +2006,17 @@ 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>
@@ -1905,48 +2042,56 @@ $start_page
   <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'}
-    <option value="thread" />$sort_types{'thread'}
-    <option value="subject" />$sort_types{'subject'}
-    <option value="username" />$sort_types{'username'}
-    <option value="lastfirst" />$sort_types{'lastfirst'}
+    <option value="ascdate" selected="selected">$sort_types{'ascdate'}</option>
+    <option value="descdate">$sort_types{'descdate'}</option>
+    <option value="thread">$sort_types{'thread'}</option>
+    <option value="subject">$sort_types{'subject'}</option>
+    <option value="username">$sort_types{'username'}</option>
+    <option value="lastfirst">$sort_types{'lastfirst'}</option>
    </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'}
-    <option value="Expired" />$status_types{'Expired'}
+    <option value="all" selected="selected">$status_types{'all'}</option>
+    <option value="Active">$status_types{'Active'}</option>
+    <option value="Expired">$status_types{'Expired'}</option>
+    <option value="Future">$status_types{'Future'}</option>
    </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'}
-    <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'}
+    <option value="all">$role_types{'all'}</option>
+    <option value="st">$role_types{'st'}</option>
+    <option value="cc">$role_types{'cc'}</option>
+    <option value="in">$role_types{'in'}</option>
+    <option value="ta">$role_types{'ta'}</option>
+    <option value="ep">$role_types{'ep'}</option>
+    <option value="cr">$role_types{'cr'}</option>
    </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 />
@@ -1954,11 +2099,19 @@ $start_page
 <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>
 $end_page
-END
+");
 }
 
 sub print_showposters {
@@ -1973,19 +2126,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(
+                                          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'};
@@ -2020,10 +2190,10 @@ $start_page
  <br />
     $table_start
       <tr>
-       <th>No.</th>
-       <th>Select</th>
-       <th>Fullname<font color="#999999">(Username/domain)</font></th>
-       <th>Posts</th>
+       <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;
@@ -2134,18 +2304,18 @@ ENDFAILREDIR
 }
 
 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) {
@@ -2184,6 +2354,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="';
@@ -2202,6 +2386,19 @@ 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 %onload;
@@ -2210,12 +2407,11 @@ sub redirect_back {
 	  "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],
+      &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" />
@@ -2229,7 +2425,9 @@ $sorttag
 $statustag
 $roletag
 $sectag
+$grptag
 $userpicktag
+$grouptag
 </form>
 $end_page
 ENDREDIR
@@ -2276,23 +2474,23 @@ 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>';
 	}
@@ -2350,9 +2548,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;
 }
@@ -2428,13 +2626,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'})
 	     ) {
@@ -2442,8 +2640,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'})
 	     ) {
@@ -2451,8 +2649,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'})
 	     ) {
@@ -2617,6 +2815,10 @@ sub show_preview {
     my ($r) = @_;
     &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;
+    my $start_page=
+	&Apache::loncommon::start_page('Preview',undef,
+				       {'only_body'   => 1,});
+
     my $message=&clear_out_html($env{'form.comment'});
     &newline_to_br(\$message);
     $message=&Apache::lonspeller::markeduptext($message);
@@ -2624,9 +2826,6 @@ sub show_preview {
     my $subject=&clear_out_html($env{'form.subject'},undef,1);
     $subject=~s/\n/\<br \/\>/g;
     $subject=&Apache::lontexconvert::msgtexconverted($subject);
-    my $start_page=
-	&Apache::loncommon::start_page('Preview',undef,
-				       {'only_body'   => 1,});
 					
     my $end_page = &Apache::loncommon::end_page();
 
@@ -2663,6 +2862,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,7 +2874,20 @@ ENDPREVIEW
 
 sub modify_attachments {
     my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_;
-    my $orig_subject = &Apache::lonnet::unescape($env{'form.subject'});
+
+    my $js = <<END;
+<script type="text/javascript">
+ function setAction () {
+   document.modattachments.action = document.modattachments.origpage.value;
+   document.modattachments.submit();
+ }
+</script> 
+END
+
+    my $start_page = 
+	&Apache::loncommon::start_page('Discussion Post Attachments',$js);
+
+    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);
@@ -2688,17 +2901,7 @@ sub modify_attachments {
         &extract_attachments($attachmenturls,$idx,$numoldver,\$msg,\%attachments,\%currattach,$currdelold);
     }
     &Apache::lonenc::check_encrypt(\$symb);
-    my $js = <<END;
-<script type="text/javascript">
- function setAction () {
-   document.modattachments.action = document.modattachments.origpage.value;
-   document.modattachments.submit();
- }
-</script> 
-END
 
-    my $start_page = 
-	&Apache::loncommon::start_page('Discussion Post Attachments',$js);
     my $end_page = 
 	&Apache::loncommon::end_page();
 				       
@@ -2724,7 +2927,7 @@ END
             }
         }
     }
-    if (@{$currnewattach} > 0) {
+    if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {
         $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#/([^/]+)$#;
@@ -2793,6 +2996,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);
@@ -2971,8 +3175,9 @@ sub sort_filter_names {
                    );
     %{$status_types} = (
                      all     => 'Roles of any status',
-                     Active => 'Only active roles',
-                     Expired => 'Only inactive roles'
+                     Active  => 'Only active roles',
+                     Expired => 'Only past roles',
+                     Future  => 'Only future roles',
                    );
 }
   
@@ -2987,13 +3192,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','sendmessageonly']);
+         ['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;
       }
   } 
@@ -3020,7 +3227,8 @@ 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'}) {
@@ -3035,9 +3243,20 @@ sub handler {
           $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 = ();
@@ -3069,7 +3288,7 @@ sub handler {
 			   \%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'}) {
@@ -3077,7 +3296,8 @@ sub handler {
       &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'});
@@ -3182,7 +3402,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
@@ -3197,8 +3417,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;
       }
 
@@ -3227,7 +3448,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'});
@@ -3239,7 +3461,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
@@ -3253,7 +3476,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
@@ -3428,9 +3652,10 @@ ENDREDIR
 				      $attachmenturl,%to);
 
 # Discussion? Store that.
-
       my $numpost=0;
-      if ($env{'form.discuss'} || $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,
@@ -3451,7 +3676,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;
 } 
@@ -3492,7 +3717,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'};
@@ -3519,5 +3756,32 @@ 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 group_args { 
+    my ($group) = @_;
+    if ($group eq '') { return ''; }
+    my $extra_args = '&amp;group='.$group;
+    if (exists($env{'form.ref'})) {
+        $extra_args .= '&amp;ref='.$env{'form.ref'};
+    }
+    return $extra_args;
+}
+
 1;
 __END__