--- loncom/interface/lonfeedback.pm	2006/12/24 22:13:19	1.237
+++ loncom/interface/lonfeedback.pm	2009/03/04 17:07:31	1.267
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Feedback
 #
-# $Id: lonfeedback.pm,v 1.237 2006/12/24 22:13:19 raeburn Exp $
+# $Id: lonfeedback.pm,v 1.267 2009/03/04 17:07:31 bisitz Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -91,7 +91,7 @@ sub list_discussion {
     if (not &discussion_visible($status)) {
         if ($mode ne 'board') {
             &Apache::lonenc::check_encrypt(\$ressymb); 
-            return &send_message_link($ressymb);
+            return '<br />'.&send_message_link($ressymb);
         }
     }
     if ($group ne '' && $mode eq 'board') {
@@ -625,7 +625,7 @@ END
                             $filterchoice .= '&nbsp;'.$role_types{$role}.',';
                         }
                         $filterchoice =~ s/,$//;
-                        $filterchoice .= '<br />&nbsp;&nbsp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp&nbsp;';
+                        $filterchoice .= '<br />'.('&nbsp;' x8);
                     }
                     if ($statusfilter) {
                         $filterchoice .= '<i>'.&mt('status').'</i>-&nbsp;'.$status_types{$statusfilter};
@@ -637,7 +637,7 @@ END
                 }
             }
             if ($dischash{$toggkey}) {
-                my $storebutton = &mt('Store read/unread changes');
+                my $storebutton = &mt('Save read/unread changes');
                 $discussion.='<td align="right">'.
               '<input type="hidden" name="discsymb" value="'.$ressymb.'">'."\n".
               '<input type="button" name="readoptions" value="'.$storebutton.'"'.
@@ -732,20 +732,19 @@ END
             }
 	}
     } else {
-        $discussion.='<table class="LC_feedback_link"><tr><td>';
+        $discussion.='<div class="LC_feedback_link">';
         if (&discussion_open($status) &&
             &Apache::lonnet::allowed('pch',
     	        $env{'request.course.id'}.
 	        ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
 	    if ($outputtarget ne 'tex') {
-		$discussion.= &send_feedback_link($ressymb,$target).
-                              '<br />';
+		$discussion.= &send_feedback_link($ressymb,$target);
             }
 	}
         if ($outputtarget ne 'tex') {
 	    $discussion.= &send_message_link($ressymb);
         }
-        $discussion.='</td></tr></table>';
+        $discussion.='</div>';
     }
     return $discussion;
 }
@@ -763,10 +762,10 @@ sub send_feedback_link {
 
 sub send_message_link {
     my ($ressymb) = @_;
-    my $output = '<span class="LC_feedback_link">'.
+    my $output = '<span class="LC_message_link">'.
                  '  <a href="/adm/feedback?sendmessageonly=1&amp;symb='.
                  &escape($ressymb).'"><img alt="" src="'.
-                 &Apache::loncommon::lonhttpdurl('/adm/lonMisc/feedback.gif').
+                 &Apache::loncommon::lonhttpdurl('/res/adm/pages/com.png').
                  '" border="0" />'.&mt('Send Message').'</a></span>';
     return $output;
 }
@@ -795,7 +794,7 @@ sub action_links_bar {
             $discussion .= '&previous='.$prevread;
         }
         $discussion .= &group_args($group);
-        $discussion .='">'.&mt('Sorting/Filtering options').'</a>&nbsp;&nbsp';
+        $discussion .='">'.&mt('Sorting/Filtering options').'</a>'.('&nbsp;' x2);
     } else {
         $discussion .= '<td align="left">';
     }
@@ -901,6 +900,9 @@ sub build_posting_display {
 			  $env{'course.'.$env{'request.course.id'}.'.domain'},
 			  $env{'course.'.$env{'request.course.id'}.'.num'});
 
+    my $see_anonymous = 
+	&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));
+
     if ((@{$grouppick} == 0) || (grep(/^all$/,@{$grouppick}))) {
         $skip_group_check = 1;
     }
@@ -1001,18 +1003,20 @@ sub build_posting_display {
                                @{$$subjectsort{$subject}} = ("$idx");
                             }
                         }
-		        if ((!$contrib{$idx.':anonymous'}) || (&Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {
+		        if (!$contrib{$idx.':anonymous'} || $see_anonymous) {
 			    $sender=&Apache::loncommon::aboutmewrapper(
 					 $plainname,
 					 $contrib{$idx.':sendername'},
 					 $contrib{$idx.':senderdomain'}).' ('.
-					 $contrib{$idx.':sendername'}.' at '.
+					 $contrib{$idx.':sendername'}.':'.
 					 $contrib{$idx.':senderdomain'}.')';
 			    if ($contrib{$idx.':anonymous'}) {
 			        $sender.=' <font color="red"><b>['.$$anonhash{$key}.']</b></font> '.
 				    $screenname;
 			    }
-
+			    if ($see_anonymous) {
+				$sender.=&Apache::loncommon::student_image_tag($contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'});
+			    }
 # Set up for sorting by domain, then username
                             unless (defined($$usernamesort{$contrib{$idx.':senderdomain'}})) {
                                 %{$$usernamesort{$contrib{$idx.':senderdomain'}}} = ();
@@ -1236,7 +1240,7 @@ sub build_posting_display {
                                 $$newitem{$idx} = 1;
                                 $$discussionitems[$idx] .= '
                                  <p><table border="0" width="100%">
-                                  <tr><td align="left"><font color="#FF0000"><b>NEW</b></font></td>';
+                                  <tr><td align="left"><font color="#FF0000"><b>'.&mt('NEW').'</b></font></td>';
                             } else {
                                 $$newitem{$idx} = 0;
                                 $$discussionitems[$idx] .= '
@@ -1468,7 +1472,7 @@ sub replicate_attachments {
 }
 
 sub mail_screen {
-  my ($r,$feedurl,$options,$symb) = @_;
+  my ($r,$feedurl,$options,$caller_symb,$attachmaxtext) = @_;
   if (exists($env{'form.origpage'})) {
       &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','currnewattach','addnewattach','deloldattach','delnewattach','timestamp','idx','anondiscuss','discuss','blog','group','ref']);
   }
@@ -1478,9 +1482,9 @@ sub mail_screen {
             'myqu' => 'My question/comment/feedback:',
             'title' => 'Title',
             'reta' => 'Retained attachments',
-            'atta' => 'Attachment (128 KB max size)',
+            'atta' => 'Attachment',
            );
-  my $restitle = &get_resource_title($symb,$feedurl);
+  my $restitle = &get_resource_title($caller_symb,$feedurl);
   my $quote='';
   my $subject = '';
   my $comment = '';
@@ -1614,7 +1618,7 @@ END
       $comment = &unescape($env{'form.comment'});
       &process_attachments(\@currnewattach,\@currdelold,\@keepold);
   }
-  my $latexHelp=&Apache::loncommon::helpLatexCheatsheet();
+  my $latexHelp=&Apache::loncommon::helpLatexCheatsheet(undef,undef,1);
   my $send=&mt('Send');
   my $alert = &mt('Please select a feedback type.');
   my $js= <<END;
@@ -1691,6 +1695,8 @@ $quote
 <p>$lt{'myqu'}</p>
 <p>
 $latexHelp
+</p>
+<p>
 $lt{'title'}: <input type="text" name="subject" size="30" value="$subject" /></p>
 <p>
 <textarea name="comment" id="comment" cols="60" rows="10" wrap="hard">$comment
@@ -1717,7 +1723,7 @@ END
         }
     } else {
         $r->print(<<END);
-$lt{'atta'}: <input type="file" name="attachment" />
+$lt{'atta'} $attachmaxtext: <input type="file" name="attachment" />
 </p>
 END
     }
@@ -1791,14 +1797,14 @@ sub print_display_options {
         'actn' => 'Action',
         'deff' => 'Default for all discussions',
         'prca' => 'Preferences can be set for this discussion that determine ....',
-        'whpo' => 'Which posts are displayed when you display this bulletin board or resource, and',
+        'whpo' => 'Which posts are displayed when you display this discussion board or resource, and',
         'unwh' => 'Under what circumstances posts are identified as "NEW", and',
         'wipa' => 'Whether individual posts can be marked as read/unread',
         'allposts' => 'All posts',
         'unread' => 'New posts only',
         'unmark' => 'Posts not marked read',
         'ondisp' => 'Once displayed',
-        'onmark' => 'Once marked not NEW ',
+        'onmark' => 'Once marked not NEW',
         'toggon' => 'Shown',
         'toggoff' => 'Not shown',
         'disa' => 'Posts displayed?',
@@ -1956,6 +1962,7 @@ END
        <td>$lt{$disctogg}</td>
        <td><label><input type="checkbox" name="disctogg" onClick="discdispChk('2')" />$lt{'chgt'} "$toggchange"</label></td>
 END
+    my $save = &mt('Save');
     $r->print(&Apache::loncommon::end_data_table_row());
     $r->print(&Apache::loncommon::end_data_table());
     $r->print(<<END);
@@ -1967,7 +1974,7 @@ END
 <input type="hidden" name="$dispchgB" value=""/>
 <input type="hidden" name="$markchg" value=""/>
 <input type="hidden" name="$toggchg" value="" />
-<input type="button" name="sub" value="Store Changes" onClick="javascript:setDisp()" />
+<input type="button" name="sub" value="$save" onClick="javascript:setDisp()" />
 END
     if (exists($env{'form.group'})) {
         $r->print('<input type="hidden" name="group" value="'.$env{'form.group'}.'" />');
@@ -2055,7 +2062,7 @@ sub print_sortfilter_options {
         'spgr' => 'Specific groups',
         'psub' => 'Pick specific users (by name)',
         'shal' => 'Show a list of current posters',
-        'stor' => 'Store changes',
+        'stor' => 'Save changes',
     );
 
     my %sort_types = ();
@@ -2147,7 +2154,7 @@ $start_page
   </td>
   <td>&nbsp;</td>
   <td align="center" valign="top">
-   <select name="rolefilter" multiple="true" size="5">
+   <select name="rolefilter" multiple="multiple" size="5">
     <option value="all">$role_types{'all'}</option>
     <option value="st">$role_types{'st'}</option>
     <option value="cc">$role_types{'cc'}</option>
@@ -2159,13 +2166,13 @@ $start_page
   </td>
   <td>&nbsp;</td>
   <td align="center" valign="top">
-   <select name="sectionpick" multiple="true" size="$numvisible">
+   <select name="sectionpick" multiple="multiple" size="$numvisible">
     $section_sel
    </select>
   </td>
   <td>&nbsp;</td>
   <td align="center" valign="top">
-   <select name="grouppick" multiple="true" size="$numvisible">
+   <select name="grouppick" multiple="multiple" size="$numvisible">
     $group_sel
    </select>
   </td>
@@ -2386,7 +2393,7 @@ ENDFAILREDIR
 }
 
 sub redirect_back {
-  my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$grouppick,$numpicks,$group) = @_;
+  my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$blog,$status,$previous,$sort,$rolefilter,$statusfilter,$sectionpick,$grouppick,$numpicks,$group,$toolarge) = @_;
   my $sorttag = '';
   my $roletag = '';
   my $statustag = '';
@@ -2500,6 +2507,7 @@ $start_page
 $typestyle
 <b>Sent $sendsomething message(s), and $sendposts post(s).</b>
 $blog
+$toolarge
 <font color="red">$status</font>
 <form name="reldt" action="$feedurl" target="loncapaclient">
 $prevtag
@@ -2559,26 +2567,31 @@ sub screen_header {
 		'<p><label><input type="radio" name="discuss" value="author" /> '.
 		&mt('Feedback to resource author').'</label></p>';
 	}
+        my %optionhash=();
+        foreach my $type ('question','comment','policy') {
+	    $optionhash{$type}=$env{'course.'.$env{'request.course.id'}.'.'.$type.'.email.text'};
+	}
 	if (&feedback_available(1)) {
 	    $msgoptions.=
 		'<p><label><input type="radio" name="discuss" value="question" /> '.
-		&mt('Question about resource content').'</label></p>';
+		($optionhash{'question'}?$optionhash{'question'}:&mt('Question about resource content')).'</label></p>';
 	}
 	if (&feedback_available(0,1)) {
 	    $msgoptions.=
 		'<p><label><input type="radio" name="discuss" value="course" /> '.
-		&mt('Question/Comment/Feedback about course content').
+		($optionhash{'comment'}?$optionhash{'comment'}:&mt('Question/Comment/Feedback about course content')).
 		'</label></p>';
 	}
 	if (&feedback_available(0,0,1)) {
 	    $msgoptions.=
 		'<p><label><input type="radio" name="discuss" value="policy" /> '.
-		&mt('Question/Comment/Feedback about course policy').
+		($optionhash{'policy'}?$optionhash{'policy'}:&mt('Question/Comment/Feedback about course policy')).
 		'</label></p>';
 	}
     }
     if (($env{'request.course.id'}) && (!$env{'form.sendmessageonly'})) {
-	if (&discussion_open(undef,$symb) &&
+        my ($blocked,$blocktext) = &Apache::loncommon::blocking_status('boards');
+        if (!$blocked && &discussion_open(undef,$symb) && 
 	    &Apache::lonnet::allowed('pch',
 				     $env{'request.course.id'}.
 				     ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''))) {
@@ -2588,13 +2601,13 @@ sub screen_header {
 		&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>';
-        }
-        my $blockblog = &Apache::loncommon::blocking_status('blogs');
-        if (!$blockblog) {
-            $discussoptions.= &add_blog_checkbox();
+            my $blockblog = &Apache::loncommon::blocking_status('blogs');
+            if (!$blockblog) {
+                $discussoptions.= &add_blog_checkbox();
+            }
         }
     }
-    if ($msgoptions) { $msgoptions='<h2><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/feedback.gif').'" />'.&mt('Sending Messages').'</h2>'.$msgoptions; }
+    if ($msgoptions) { $msgoptions='<h2><img src="'.&Apache::loncommon::lonhttpdurl('/res/adm/pages/com.png').'" />'.&mt('Sending Messages').'</h2>'.$msgoptions; }
     if ($discussoptions) { 
 	$discussoptions='<h2><img src="'.&Apache::loncommon::lonhttpdurl('/adm/lonMisc/chat.gif').'" />'.&mt('Discussion Contributions').'</h2>'.$discussoptions; }
     return $msgoptions.$discussoptions;
@@ -2661,142 +2674,53 @@ ENDCITE
   return ($email,$citations);
 }
 
-sub secapply {
-    my $rec=shift;
-    my $defaultflag=shift;
-    $rec=~s/\s+//g;
-    $rec=~s/\@/\:/g;
-    my ($adr,$sections_or_groups)=($rec=~/^([^\(]+)\(([^\)]+)\)/);
-    if ($sections_or_groups) {
-	foreach my $item (split(/\;/,$sections_or_groups)) {
-            if (($item eq $env{'request.course.sec'}) ||
-                ($defaultflag && ($item eq '*'))) {
-                return $adr; 
-            } elsif ($env{'request.course.groups'}) {
-                my @usersgroups = split(/:/,$env{'request.course.groups'});
-                if (grep(/^\Q$item\E$/,@usersgroups)) {
-                    return $adr;
-                }
-            } 
-        }
-    } else {
-       return $rec;
-    }
-    return '';
-}
-
-=pod 
-
-=over 4
-
-=item *
-
-decide_receiver($feedurl,$author,$question,$course,$policy,$defaultflag);
-
-Arguments
-  $feedurl - /res/ url of resource (only need if $author is true)
-  $author,$question,$course,$policy - all true/false parameters
-    if true will attempt to find the addresses of user that should receive
-    this type of feedback (author - feedback to author of resource $feedurl,
-    $question 'Resource Content Questions', $course 'Course Content Question',
-    $policy 'Course Policy')
-    (Additionally it also checks $env for whether the corresponding form.<name>
-    element exists, for ease of use in a html response context)
-   
-  $defaultflag - (internal should be left blank) if true gather addresses 
-                 that aren't for a section even if I have a section
-                 (used for reccursion internally, first we look for
-                 addresses for our specific section then we recurse
-                 and look for non section addresses)
-
-Returns
-  $typestyle - string of html text, describing what addresses were found
-  %to - a hash, which keys are addresses of users to send messages to
-        the keys will look like   name:domain
-
-=cut
-
-sub decide_receiver {
-  my ($feedurl,$author,$question,$course,$policy,$defaultflag) = @_;
-  &Apache::lonenc::check_decrypt(\$feedurl);
-  my $typestyle='';
-  my %to=();
-  if ($env{'form.discuss'} eq 'author' ||$author) {
-    $typestyle.='Submitting as Author Feedback<br />';
-    $feedurl=~ m{^/res/($LONCAPA::domain_re)/($LONCAPA::username_re)/};
-    $to{$2.':'.$1}=1;
-  }
-  if ($env{'form.discuss'} eq 'question' ||$question) {
-    $typestyle.=&mt('Submitting as Question').'<br />';
-    foreach my $item (split(/\,/,
-		   $env{'course.'.$env{'request.course.id'}.'.question.email'})
-	     ) {
-	my $rec=&secapply($item,$defaultflag);
-        if ($rec) { $to{$rec}=1; }
-    } 
-  }
-  if ($env{'form.discuss'} eq 'course' ||$course) {
-    $typestyle.=&mt('Submitting as Comment').'<br />';
-    foreach my $item (split(/\,/,
-		   $env{'course.'.$env{'request.course.id'}.'.comment.email'})
-	     ) {
-	my $rec=&secapply($item,$defaultflag);
-        if ($rec) { $to{$rec}=1; }
-    } 
-  }
-  if ($env{'form.discuss'} eq 'policy' ||$policy) {
-    $typestyle.=&mt('Submitting as Policy Feedback').'<br />';
-    foreach my $item (split(/\,/,
-		   $env{'course.'.$env{'request.course.id'}.'.policy.email'})
-	     ) {
-	my $rec=&secapply($item,$defaultflag);
-        if ($rec) { $to{$rec}=1; }
-    } 
-  }
-  if ((scalar(%to) eq '0') && (!$defaultflag)) {
-     ($typestyle,%to)=
-	 &decide_receiver($feedurl,$author,$question,$course,$policy,1);
-  }
-  return ($typestyle,%to);
-}
 
 sub feedback_available {
     my ($question,$course,$policy)=@_;
-    my ($typestyle,%to)=&decide_receiver('',0,$question,$course,$policy);
+    my ($typestyle,%to)=&Apache::lonmsg::decide_receiver('',0,$question,
+							 $course,$policy);
     return scalar(%to);
 }
 
 sub send_msg {
-  my ($title,$feedurl,$email,$citations,$attachmenturl,$symb,%to)=@_;
-  my $status='';
-  my $sendsomething=0;
-  my $restitle = &get_resource_title($symb,$feedurl);
-  if ($title=~/^Error/) { $title=&mt('Feedback').': '.$title; }
-  unless ($title=~/\w/) { $title=&mt('Feedback'); }
-  foreach my $key (keys(%to)) {
-    if ($key) {
-      unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$key),
-               $title.' ['.$restitle.']',$email,$citations,$feedurl,
-                $attachmenturl,undef,undef,$symb,$restitle)=~/ok/) {
-	$status.='<br />'.&mt('Error sending message to').' '.$key.'<br />';
-      } else {
-	$sendsomething++;
-      }
+    my ($title,$feedurl,$email,$citations,$attachmenturl,$symb,%to)=@_;
+    my $status='';
+    my $sendsomething=0;
+    my $restitle = &get_resource_title($symb,$feedurl);
+    if ($title=~/^Error/) { $title=&mt('Feedback').': '.$title; }
+    unless ($title=~/\w/) { $title=&mt('Feedback'); }
+    foreach my $key (keys(%to)) {
+	if ($key) {
+	    my ($user,$domain) = split(/\:/,$key,2);
+	    if (!defined($user)) {
+		$status.='<br />'.&mt('Error sending message to [_1], no user specified.',$key);
+	    } elsif (!defined($domain)) {
+		$status.='<br />'.&mt('Error sending message to [_1], no domain specified.',$key);
+	    } else {
+		unless (&Apache::lonmsg::user_normal_msg($user,$domain,
+							 $title.' ['.$restitle.']',$email,$citations,$feedurl,
+							 $attachmenturl,undef,undef,$symb,$restitle)=~/ok/) {
+		    $status.='<br />'.&mt('Error sending message to').' '.$key.'<br />';
+		} else {
+		    $sendsomething++;
+		}
+	    }
+	}
     }
-  }
+
 
     my %record=&Apache::lonnet::restore('_feedback');
     my ($temp)=keys(%record);
     unless ($temp=~/^error\:/) {
-       my %newrecord=();
-       $newrecord{'resource'}=$feedurl;
-       $newrecord{'subnumber'}=$record{'subnumber'}+1;
-       unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') {
-	   $status.='<br />'.&mt('Not registered').'<br />';
-       }
+	my %newrecord=();
+	$newrecord{'resource'}=$feedurl;
+	$newrecord{'subnumber'}=$record{'subnumber'}+1;
+	unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') {
+	    $status.='<br />'.&mt('Not registered').'<br />';
+	}
     }
-       
-  return ($status,$sendsomething);
+    
+    return ($status,$sendsomething);
 }
 
 sub adddiscuss {
@@ -2967,9 +2891,18 @@ sub show_preview {
 					
     my $end_page = &Apache::loncommon::end_page();
 
-    $r->print($start_page.'<table border="2"><tr><td>'.
-	      '<b>'.&mt('Subject').':</b> '.$subject.'<br /><br />'.
-	      $message.'</td></tr></table>'.$end_page);
+    $r->print($start_page
+             .'<h1>'.&mt('Preview').'</h1>'
+             .&Apache::lonhtmlcommon::start_pick_box()
+             .&Apache::lonhtmlcommon::row_title(&mt('Subject'))
+             .$subject
+             .&Apache::lonhtmlcommon::row_closure()
+             .&Apache::lonhtmlcommon::row_title(&mt('Message'))
+             .$message
+             .&Apache::lonhtmlcommon::row_closure(1)
+             .&Apache::lonhtmlcommon::end_pick_box()
+             .$end_page
+    );
 }
 
 
@@ -3011,7 +2944,8 @@ ENDPREVIEW
 }
 
 sub modify_attachments {
-    my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_;
+    my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls,
+        $attachmaxtext,$toolarge)=@_;
 
     my %lt = &Apache::lonlocal::texthash(
                'subj' => 'Subject',
@@ -3019,7 +2953,7 @@ sub modify_attachments {
                'chth' => 'Check the checkboxes for any you wish to remove.',
                'thef' => 'The following attachments have been uploaded for inclusion with this posting.',
                'adda' => 'Add a new attachment to this post.',
-               'stch' => 'Store Changes',
+               'stch' => 'Save Changes',
              );
     my $js = <<END;
 <script type="text/javascript">
@@ -3053,10 +2987,12 @@ END
 				       
     $r->print(<<END);
 $start_page
+$toolarge
 <form name="modattachments" method="post" enctype="multipart/form-data" action="/adm/feedback?attach=$symb">
- <table border="2">
+ <br />
+ <table class="LC_data_table">
   <tr>
-   <td>
+   <td colspan="2">
     <b>Subject:</b> $subject</b><br /><br />
 END
     if ($idx) {
@@ -3082,9 +3018,15 @@ END
         $r->print("<br />"); 
     }
     $r->print(<<END);
-   $lt{'adda'}&nbsp;<input type="file" name="addnewattach" /><input type="button" name="upload" value="Upload" onClick="this.form.submit()" />    
+   </td></tr>
+   <tr>
+    <td>
+   $lt{'adda'}</td><td><input type="file" name="addnewattach" /><input type="button" name="upload" value="Upload" onClick="this.form.submit()" />    
    </td>
   </tr>
+  <tr>
+   <td colspan="2">$attachmaxtext</td>
+  </tr>
  </table>
 <input type="hidden" name="subject" value="$env{'form.subject'}" />
 <input type="hidden" name="comment" value="$env{'form.comment'}" />
@@ -3316,12 +3258,18 @@ function setblogvalue() {
 sub has_discussion {
     my $resourcesref = shift;
     my $navmap = Apache::lonnavmaps::navmap->new();
-    my @allres=$navmap->retrieveResources();
-    foreach my $resource (@allres) {
-        if ($resource->hasDiscussion()) {
-            my $ressymb = $resource->wrap_symb();
-            push(@{$resourcesref}, $ressymb);
+    if (defined($navmap)) {
+        my @allres=$navmap->retrieveResources();
+        foreach my $resource (@allres) {
+            if ($resource->hasDiscussion()) {
+                my $ressymb = $resource->wrap_symb();
+                if (ref($resourcesref) eq 'ARRAY') {
+                    push(@{$resourcesref}, $ressymb);
+                }
+            }
         }
+    } else {
+        &Apache::lonnet::logthis('Has discussion check failed - could not create navmap object.');
     }
     return;
 }
@@ -3367,6 +3315,10 @@ sub handler {
   &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
          ['hide','unhide','deldisc','postdata','preview','replydisc','editdisc','cmd','symb','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navtime','navmaps','navurl','sortposts','applysort','rolefilter','statusfilter','sectionpick','groupick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export','sendmessageonly','group','ref']);
   my $group = $env{'form.group'};
+  my %attachmax = (
+                    text => '(128 KB max size)',
+                    num  => 131072,
+                  );
   if ($env{'form.editdisc'}) {
       if (!(&editing_allowed($env{'form.editdisc'},$env{'form.group'}))) {
           my $symb=(split(/\:\:\:/,$env{'form.editdisc'}))[0];
@@ -3494,7 +3446,7 @@ sub handler {
       my %lt = &Apache::lonlocal::texthash(
           'mnpa' => 'Marked "New" posts as read in a total of',
           'robb' => 'resources/bulletin boards.',
-          'twnp' => 'There are currently no resources or bulletin boards with unread discussion postings.'
+          'twnp' => 'There are currently no resources or discussion boards with unread discussion postings.'
       );       
       foreach my $res (@resources) {
           my $ressymb=$res;
@@ -3637,10 +3589,10 @@ ENDREDIR
       my ($symb,$feedurl)=&get_feedurl_and_clean_symb($env{'form.symb'});
       if ($env{'form.cmd'} eq 'threadedon') {
 	  &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'});
-	  &Apache::lonnet::appenv('environment.threadeddiscussion' => 'on');
+	  &Apache::lonnet::appenv({'environment.threadeddiscussion' => 'on'});
       } else {
  	  &Apache::lonnet::del('environment',['threadeddiscussion']);
-	  &Apache::lonnet::delenv('environment\.threadeddiscussion');
+	  &Apache::lonnet::delenv('environment.threadeddiscussion');
       }
       &redirect_back($r,$feedurl,&mt('Changed discussion view mode').'<br />',
 		     '0','0','','',$env{'form.previous'},undef,undef,undef,
@@ -3675,13 +3627,15 @@ ENDREDIR
       &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','discuss','blog']);
-      my (@currnewattach,@currdelold,@keepold);
+      my (@currnewattach,@currdelold,@keepold,$toolarge);
       &process_attachments(\@currnewattach,\@currdelold,\@keepold);
       if (exists($env{'form.addnewattach.filename'})) {
-          unless (length($env{'form.addnewattach'})>131072) {
+          if (length($env{'form.addnewattach'})<=$attachmax{'num'}) {
               my $subdir = 'feedback/'.$env{'form.timestamp'};
               my $newattachment=&Apache::lonnet::userfileupload('addnewattach',undef,$subdir);
 	      push(@currnewattach, $newattachment);
+          } else {
+              $toolarge = '<p><span class="LC_warning">'.&mt('Attachment not included - exceeded permitted length').'</span><br /></p>';
           }
       }
       my $attachmenturls;
@@ -3694,7 +3648,7 @@ ENDREDIR
           $attachmenturls = $contrib{$idx.':attachmenturl'};
       }
       &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx,
-			  $attachmenturls);
+			  $attachmenturls,$attachmax{'text'},$toolarge);
       return OK;
   } elsif ($env{'form.export'}) {
       &Apache::loncommon::content_type($r,'text/html');
@@ -3717,7 +3671,7 @@ ENDREDIR
   } else {
 # ------------------------------------------------------------- Normal feedback
       my $feedurl=$env{'form.postdata'};
-      $feedurl=~s/^http\:\/\///;
+      $feedurl=~s/^https?\:\/\///;
       $feedurl=~s/^$ENV{'SERVER_NAME'}//;
       $feedurl=~s/^$ENV{'HTTP_HOST'}//;
       $feedurl=~s/\?.+$//;
@@ -3783,7 +3737,7 @@ ENDREDIR
           }
 	  my $options=&screen_header($feedurl,$symb);
 	  if ($options) {
-	      &mail_screen($r,$feedurl,$options,$symb);
+	      &mail_screen($r,$feedurl,$options,$symb,$attachmax{'text'});
 	  } else {
 	      &fail_redirect($r,$feedurl);
 	  }
@@ -3800,15 +3754,16 @@ ENDREDIR
       my $usersaw=&resource_output($feedurl);
 
 # Get resource answer (need to allow student to view grades for this to work)
-      &Apache::lonnet::appenv(('allowed.vgr'=>'F'));
-      my $usersymmb = &Apache::lonenc::check_encrypt($symb);
+      &Apache::lonnet::appenv({'allowed.vgr'=>'F'});
+      my $usersymb = &Apache::lonenc::check_encrypt($symb);
       my $useranswer=
           &Apache::loncommon::get_student_answers(
-              $usersymb),$env{'user.name'},$env{'user.domain'},
+              $usersymb,$env{'user.name'},$env{'user.domain'},
               $env{'request.course.id'});
       &Apache::lonnet::delenv('allowed.vgr');
 # Get attachments, if any, and not too large
       my $attachmenturl='';
+      my $toolarge='';
       if (($env{'form.origpage'}) || ($env{'form.editdisc'}) ||
 	  ($env{'form.replydisc'})) {
 	  my ($symb,$idx);
@@ -3827,9 +3782,13 @@ ENDREDIR
 	  $symb=~s|(bulletin___\d+___)adm/wrapper/|$1|;
 	  $attachmenturl=&construct_attachmenturl(\@currnewattach,\@keepold,$symb,$idx);
       } elsif ($env{'form.attachment.filename'}) {
-	  unless (length($env{'form.attachment'})>131072) {
-	      $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,'feedback');
-	  }
+	  if (length($env{'form.attachment'})<=$attachmax{'num'}) {
+              my $now = time;
+              my $subdir = 'feedback/'.$now;
+	      $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,$subdir);
+	  } else {
+              $toolarge = '<p><span class="LC_warning">'.&mt('Attachment not included - exceeded permitted length').'</span><br /></p>';
+          }
       }
 # Filter HTML out of message (could be nasty)
       my $message=&clear_out_html($env{'form.comment'});
@@ -3839,13 +3798,13 @@ ENDREDIR
 					     $usersaw,$useranswer);
  
 # Who gets this?
-      my ($typestyle,%to) = &decide_receiver($feedurl);
+      my ($typestyle,%to) = &Apache::lonmsg::decide_receiver($feedurl);
 
 # Actually send mail
       my ($status,$numsent)=&send_msg(&clear_out_html($env{'form.subject'},
 						      undef,1),
 				      $feedurl,$email,$citations,
-				      $attachmenturl,$symb,%to);
+				      $attachmenturl,$usersymb,%to);
 
 # Discussion? Store that.
       my $numpost=0;
@@ -3872,7 +3831,7 @@ ENDREDIR
       }
 	  
 # Receipt screen and redirect back to where came from
-      &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'},undef,undef,undef,undef,undef,undef,$group);
+      &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$blog,$status,$env{'form.previous'},undef,undef,undef,undef,undef,undef,$group,$toolarge);
   }
   return OK;
 }
@@ -4017,3 +3976,131 @@ sub get_resource_title {
 
 1;
 __END__
+
+
+=pod
+
+=head1 NAME
+
+Apache::lonfeedback.pm
+
+=head1 SYNOPSIS
+
+Handles feedback from students to instructors and system administrators.
+
+Provides a screenshot of the current resource, as well as previous attempts if the resource was a homework.
+
+Used by lonmsg.pm.
+
+This is part of the LearningOnline Network with CAPA project
+described at http://www.lon-capa.org.
+
+=head1 OVERVIEW
+
+None
+
+=head1 SUBROUTINES
+
+=over
+
+=item discussion_open()
+
+=item discussion_visible()
+
+=item list_discussion()
+
+=item send_feedback_link()
+
+=item send_message_link()
+
+=item action_links_bar()
+
+=item postingform_display()
+
+=item build_posting_display
+
+=item filter_regexp()
+
+=item get_post_contents()
+
+=item replicate_attachments()
+
+=item mail_screen()
+
+=item print_display_options()
+
+=item print_sortfilter_options()
+
+=item print_showposters()
+
+=item get_post_versions()
+
+=item get_post_attachments()
+
+=item fail_redirect()
+
+=item redirect_back()
+
+=item no_redirect_back()
+
+=item screen_header()
+
+=item resource_output()
+
+=item clear_out_html()
+
+=item assemble_email()
+
+=item feedback_available()
+
+=item send_msg()
+
+=item adddiscuss()
+
+=item get_discussion_info()
+
+=item show_preview()
+
+=item newline_to_br()
+
+=item generate_preview_button()
+
+=item modify_attachments()
+
+=item process_attachments()
+
+=item generate_attachments_button()
+
+=item extract_attachments()
+
+=item construct_attachmenturl()
+
+=item add_blog_checkbox()
+
+=item has_discussion()
+
+=item sort_filter_names()
+
+=item handler()
+
+=item blocked_reply_or_edit()
+
+=item wrap_symb()
+
+=item dewrapper()
+
+=item get_feedurl()
+
+=item get_feedurl_and_clean_symb()
+
+=item editing_allowed()
+
+=item check_group_priv()
+
+=item group_args()
+
+=item get_resource_title()
+
+=back
+
+=cut