--- loncom/interface/lonfeedback.pm	2006/05/08 22:07:31	1.195
+++ loncom/interface/lonfeedback.pm	2006/07/17 23:02:33	1.208
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Feedback
 #
-# $Id: lonfeedback.pm,v 1.195 2006/05/08 22:07:31 albertel Exp $
+# $Id: lonfeedback.pm,v 1.208 2006/07/17 23:02:33 raeburn 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,7 +135,7 @@ 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 = ();
@@ -136,6 +144,13 @@ sub list_discussion {
     } else {
         $sectionpick[0] = $env{'form.sectionpick'};
     }
+    my @grouppick = ();
+    if ($env{'form.grouppick'} =~ /,/) {
+        @grouppick = split/,/,$env{'form.grouppick'};
+    } else {
+        $grouppick[0] = $env{'form.grouppick'};
+    }
+
     my @rolefilter = ();
     if ($env{'form.rolefilter'} =~ /,/) {
         @rolefilter = split/,/,$env{'form.rolefilter'};
@@ -152,13 +167,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 +191,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 +200,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 +242,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 +277,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 +286,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 +355,9 @@ sub list_discussion {
     if ($newpostsflag) {
         $chglink .= '&previous='.$prevread;
     }
+    if ($group ne '') {
+        $chglink.='&'.$grp_arg;
+    }
 
     if ($visible) {
 # Print the discusssion
@@ -394,23 +429,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 +463,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 +496,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 +667,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 +749,34 @@ 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>';
@@ -751,29 +786,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.'>'.
+		    &escape($ressymb).':::" '.$target.'>'.
 		    '<img 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).
+	    &escape($ressymb).
 	    '"><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/feedback.gif').'" border="0" />'.
-		    &mt('Send Message').'</td></tr></table>';
+		    &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 $skipgrpcheck = 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})) {
+        $skipgrpcheck = 1;
+    }
     if ($contrib{'version'}) {
         my $oldest = $contrib{'1:timestamp'};
         if ($prevread eq '0') {
@@ -781,7 +875,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 +965,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 +1006,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>';
@@ -941,6 +1040,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='.
@@ -948,6 +1050,9 @@ sub build_posting_display {
                                 if ($$newpostsflag) {
                                     $sender .= '&previous='.$prevread;
                                 }
+                                if ($group ne '') {
+                                    $sender .= '&amp;'.&grp_args($group);
+                                }
                                 $sender .= '">'.&mt('Delete').'</a>';
                             }
 		        } else {
@@ -975,16 +1080,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',
@@ -1041,7 +1157,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 +1182,23 @@ sub build_posting_display {
                                         }
                                     }
                                 }
+                                if ($$shown{$idx} && !$skipgrpcheck) {
+                                    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 +1229,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/:/) {
@@ -1159,6 +1296,7 @@ sub filter_regexp {
             $secregexp .= '[^:]*';
         }
     }
+
     if (defined($statusfilter) && $statusfilter ne '') {
         if ($statusfilter eq 'all') {
             $statusregexp = '[^:]+';
@@ -1179,7 +1317,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 +1444,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);
@@ -1328,12 +1466,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
@@ -1341,13 +1482,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
   }
@@ -1414,20 +1557,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
   }
@@ -1441,8 +1581,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();
@@ -1452,36 +1592,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") {
-          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;
@@ -1494,7 +1617,7 @@ END
 	    }
 	    document.mailform.submit();
         } else {
-            alert('Please check a feedback type.');
+            alert('Please select a feedback type.');
 	}
     }
     $anonchk
@@ -1563,6 +1686,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" />
@@ -1583,7 +1712,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) {
@@ -1802,11 +1931,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;
 }
 
@@ -1817,28 +1954,55 @@ 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'});
@@ -1851,6 +2015,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'
     );
@@ -1882,6 +2047,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>
@@ -1907,10 +2083,12 @@ $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'}
@@ -1921,7 +2099,7 @@ $start_page
    </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'}
@@ -1929,7 +2107,7 @@ $start_page
    </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'}
@@ -1937,18 +2115,23 @@ $start_page
     <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 />
@@ -1956,11 +2139,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 {
@@ -1975,19 +2166,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'};
@@ -2015,19 +2223,17 @@ sub print_showposters {
     }
 
     my $start_page = &Apache::loncommon::start_page('Discussion options');
-
+    my $table_start =&Apache::loncommon::start_data_table();
     $r->print(<<END);
 $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;
@@ -2039,18 +2245,19 @@ 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" />
@@ -2137,18 +2344,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) {
@@ -2187,6 +2394,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="';
@@ -2205,16 +2426,32 @@ 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 = ('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('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" />
@@ -2228,7 +2465,9 @@ $sorttag
 $statustag
 $roletag
 $sectag
+$grptag
 $userpicktag
+$grouptag
 </form>
 $end_page
 ENDREDIR
@@ -2238,9 +2477,15 @@ sub no_redirect_back {
   my ($r,$feedurl) = @_;
   my $nofeed=&mt('Sorry, no feedback possible on this resource  ...');
  
+  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 (window.name!='loncapaclient') { self.window.close(); }"});
+		      'add_entries' => \%onload,);
 
   if ($feedurl !~ m{^/adm/feedback}) { 
       $body_options{'rediect'} = [2,$feedurl];
@@ -2269,23 +2514,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>';
 	}
@@ -2295,10 +2540,9 @@ sub screen_header {
 	    &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>';
@@ -2422,13 +2666,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'})
 	     ) {
@@ -2436,8 +2680,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'})
 	     ) {
@@ -2445,8 +2689,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'})
 	     ) {
@@ -2657,6 +2901,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" />
@@ -2668,7 +2913,7 @@ ENDPREVIEW
 
 sub modify_attachments {
     my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_;
-    my $orig_subject = &Apache::lonnet::unescape($env{'form.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);
@@ -2697,6 +2942,7 @@ END
 	&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>
@@ -2736,7 +2982,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
@@ -2787,6 +3032,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);
@@ -2802,7 +3048,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
@@ -2982,13 +3227,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;
       }
   } 
@@ -3015,7 +3262,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'}) {
@@ -3030,9 +3278,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 = ();
@@ -3064,7 +3323,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'}) {
@@ -3072,7 +3331,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'});
@@ -3114,7 +3374,12 @@ sub handler {
       &Apache::loncommon::content_type($r,'text/html');
       $r->send_http_header;
       my $logo=&Apache::loncommon::lonhttpdurl('/adm/lonIcons/lonlogos.gif');
-      my %onload = ('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('New posts marked as read',undef,
 					 {'redirect'    => [2,$feedurl],
@@ -3172,7 +3437,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
@@ -3187,8 +3452,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;
       }
 
@@ -3217,7 +3483,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'});
@@ -3229,7 +3496,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
@@ -3243,7 +3511,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
@@ -3253,7 +3522,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'})) {
@@ -3418,11 +3687,12 @@ 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=(defined($env{'form.anondiscuss'}));
+	  my $anonmode=($env{'form.discuss'} eq 'anon' || $env{'form.anondiscuss'} );
 	  $typestyle.=&adddiscuss($symb,$message,$anonmode,$attachmenturl,
 				  $subject);
 	  $numpost++;
@@ -3441,7 +3711,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;
 } 
@@ -3482,7 +3752,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'};
@@ -3509,5 +3791,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__