--- loncom/interface/lonmsgdisplay.pm 2007/01/04 16:54:07 1.62 +++ loncom/interface/lonmsgdisplay.pm 2008/06/06 05:24:28 1.86 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Routines for messaging display # -# $Id: lonmsgdisplay.pm,v 1.62 2007/01/04 16:54:07 raeburn Exp $ +# $Id: lonmsgdisplay.pm,v 1.86 2008/06/06 05:24:28 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -33,12 +33,13 @@ package Apache::lonmsgdisplay; =head1 NAME -Apache::lonmsg: supports internal messaging +Apache::lonmsgdisplay: supports internal messaging =head1 SYNOPSIS -lonmsg provides routines for sending messages, receiving messages, and -a handler to allow users to read, send, and delete messages. +lonmsgdisplay provides a handler to allow users to read, send, +and delete messages, and to create and delete message folders, +and to move messages between folders. =head1 OVERVIEW @@ -93,25 +94,6 @@ addresses on their B<PREF> screen, but g are much more useful than traditional email can be made to be, even with HTML support. -Right now, this document will cover just how to send a message, since -it is likely you will not need to programmatically read messages, -since lonmsg already implements that functionality. - -The routines used to package messages and unpackage messages are not -only used by lonmsg when creating/extracting messages for LON-CAPA's -internal messaging system, but also by lonnotify.pm which is available -for use by Domain Coordinators to broadcast standard e-mail to specified -users in their domain. The XML packaging used in the two cases is very -similar. The differences are the use of <recuser>$uname</recuser> and -<recdomain>$udom</recdomain> in stored internal messages, compared -with <recipient username="$uname:$udom">$email</recipient> in stored -Domain Coordinator e-mail for the storage of information about -recipients of the message/e-mail. - -=head1 FUNCTIONS - -=over 4 - =cut use strict; @@ -119,6 +101,7 @@ use Apache::lonnet; use HTML::TokeParser(); use Apache::Constants qw(:common); use Apache::loncommon(); +use Apache::lonhtmlcommon(); use Apache::lontexconvert(); use HTML::Entities(); use Apache::lonlocal; @@ -407,6 +390,9 @@ sub renamefolder { if ($env{'form.renamed'} eq '') { return &mt('The folder "[_1]" may not be renamed to "[_2]" as the new name you requested is an invalid name.',$folder,$newname); } + if (defined($permfolders{$folder})) { + return &mt('The folder "[_1]" may not be renamed as it is a folder provided by the system.',$folder); + } if (defined($permfolders{$newname})) { return &mt('The folder "[_1]" may not be renamed to "[_2]" as the new name you requested is reserved for folders provided automatically by the system.',$folder,$newname); } @@ -569,7 +555,7 @@ sub disgroup { 'recipients to select.'); return $result; } else { - $result = &mt('Select message recipients from the group members listed below.<br />'); + $result = &mt('Select message recipients from the group members listed below.').'<br />'; my %Sortby = ( active => {}, previous => {}, @@ -751,12 +737,27 @@ $content{'sendername'}.':'. '<br />'.&mt('Subject').': '.$content{'subject'}. '<br /><pre>'. &Apache::lontexconvert::msgtexconverted($content{'message'}). - '</pre><small>'. -&mt('You have to confirm that you received this message. After confirmation, this message will be moved to your regular inbox'). - '</small><br />'. - '<input type="submit" name="rec_'.$key.'" value="'.&mt('Confirm Receipt').'" />'. - '<input type="submit" name="reprec_'.$key.'" '. - 'value="'.&mt('Confirm Receipt and Reply').'" />'; + '</pre><div class="LC_error">'; + my ($rec_button,$reprec_button); + $rec_button = &mt('Move to Inbox'); + if (!$content{'noreplies'}) { + $reprec_button = &mt('Move to Inbox/Compose reply'); + } + if ($content{'sendback'}) { + $rec_button = &mt('Confirm Receipt'); + if (!$content{'noreplies'}) { + $reprec_button = &mt('Confirm Receipt and Reply'); + } + $result .= &mt('You have to confirm that you have received this message before you can view other pages. After confirmation, this message will be moved to your regular inbox'); + } else { + $result .= &mt('Access to other pages will be prevented until you have moved the message to your inbox.'); + } + $result .= '</div><br />'. + '<input type="submit" name="rec_'.$key.'" value="'.$rec_button.'" />'; + if (!$content{'noreplies'}) { + $result .= '<input type="submit" name="reprec_'.$key.'" '. + 'value="'.$reprec_button.'" />'; + } } # Check to see if there were any messages. if ($result eq '') { @@ -891,8 +892,7 @@ sub get_course_desc { sub disall { my ($r,$folder,$msgstatus)=@_; - my %saveable = ('folder' => 'scalar', - 'msgstatus' => 'scalar', + my %saveable = ('msgstatus' => 'scalar', 'sortedby' => 'scalar', 'interdis' => 'scalar', ); @@ -924,28 +924,10 @@ sub disfolder { nome => 'No messages have been selected to apply ths action to.', chec => 'Check the checkbox for at least one message.', ); + my $jscript = &Apache::loncommon::check_uncheck_jscript(); $r->print(<<ENDDISHEADER); <script type="text/javascript"> - function checkall() { - for (i=0; i<document.forms.disall.delmark.length; i++) { - document.forms.disall.delmark[i].checked=true; - } - } - - function uncheckall() { - for (i=0; i<document.forms.disall.delmark.length; i++) { - document.forms.disall.delmark[i].checked=false; - } - } - function checkfoldermove() { - if (document.disall.checkedaction.options[document.disall.checkedaction.selectedIndex].value == 'markedmove') { - if (document.disall.movetofolder.options[document.disall.movetofolder.selectedIndex].value == "") { - alert("$lt{'sede'}"); - return; - } - } - return; - } + $jscript function validate_checkedaction() { document.disall.markedaction.value = document.disall.checkedaction.options[document.disall.checkedaction.selectedIndex].value; @@ -956,11 +938,17 @@ sub disfolder { } } var checktotal = 0; - for (var i=0; i<document.forms.disall.delmark.length; i++) { - if (document.forms.disall.delmark[i].checked) { + if (document.forms.disall.delmark.length > 0) { + for (var i=0; i<document.forms.disall.delmark.length; i++) { + if (document.forms.disall.delmark[i].checked) { + checktotal ++; + } + } + } else { + if (document.forms.disall.delmark.checked) { checktotal ++; } - } + } if (checktotal == 0) { alert("$lt{'nome'}\\n$lt{'chec'}"); return; @@ -982,6 +970,10 @@ ENDDISHEADER } else { $r->print('<h2>'.&mt('There are no '.lc($statushash{$msgstatus}).' messages in this folder.').'</h2>'); } + if ($numblocked > 0) { + $r->print(&blocked_in_folder($numblocked,$startblock,$endblock, + \%setters)); + } return; } my $interdis = $env{'form.interdis'}; @@ -1052,16 +1044,23 @@ ENDDISHEADER } my ($dis_name,$dis_domain) = ($fromname,$fromdomain); if ($folder eq 'sent') { - if (defined($recv_name) && !defined($recv_domain)) { - $dis_name = join('<br />',@{$recv_name}); - $dis_domain = join('<br />',@{$recv_domain}); + if (defined($recv_name) && defined($recv_domain)) { + if (ref($recv_name) eq 'ARRAY' && + ref($recv_domain) eq 'ARRAY') { + $dis_name = join('<br />',@{$recv_name}); + $dis_domain = join('<br />',@{$recv_domain}); + } } else { my $msg_id = &unescape($origID); my %message = &Apache::lonnet::get('nohist_email'.$suffix, [$msg_id]); my %content = &Apache::lonmsg::unpackagemsg($message{$msg_id}); - $dis_name = join('<br />',@{$content{'recuser'}}); - $dis_domain = join('<br />',@{$content{'recdomain'}}); + if (ref($content{'recuser'}) eq 'ARRAY') { + $dis_name = join('<br />',@{$content{'recuser'}}); + } + if (ref($content{'recdomain'}) eq 'ARRAY') { + $dis_domain = join('<br />',@{$content{'recdomain'}}); + } } } my $localsenttime = &Apache::lonlocal::locallocaltime($sendtime); @@ -1097,11 +1096,11 @@ ENDDISHEADER $r->print('<table border="0" cellspacing="2" cellpadding="2"> <tr> <td>'. - '<input type="button" onclick="javascript:checkall()" value="'.&mt('Check All').'" /><br />'."\n". - '<input type="button" onclick="javascript:uncheckall()" value="'.&mt('Uncheck All').'" />'."\n". + '<input type="button" onclick="javascript:checkAll(document.disall.delmark)" value="'.&mt('Check All').'" /><br />'."\n". + '<input type="button" onclick="javascript:uncheckAll(document.disall.delmark)" value="'.&mt('Uncheck All').'" />'."\n". '<input type="hidden" name="sortedby" value="'.$env{'form.sortedby'}.'" /></td><td> </td>'."\n". '<td align="center"><b>'.&mt('Action').'</b><br />'."\n". - ' <select name="checkedaction" onchange="javascript:checkfoldermove()">'."\n"); + ' <select name="checkedaction">'."\n"); if ($folder ne 'trash') { $r->print(' <option value="markeddel">'.&mt('Delete').'</option>'."\n"); @@ -1138,15 +1137,22 @@ ENDDISHEADER my $postedstartdis=$startdis+1; $r->print('<input type="hidden" name="folder" value="'.$folder.'" /><input type="hidden" name="startdis" value="'.$postedstartdis.'" /><input type="hidden" name="interdis" value="'.$env{'form.interdis'}.'" /><input type="hidden" name="msgstatus" value="'.$msgstatus.'" ><input type="hidden" name="markedaction" value="" /></form>'); if ($numblocked > 0) { - my $beginblock = &Apache::lonlocal::locallocaltime($startblock); - my $finishblock = &Apache::lonlocal::locallocaltime($endblock); - $r->print('<br /><br />'. - &mt('[quant,_1,message is, messages are] not viewable because display of LON-CAPA messages sent to you by other students between [_2] and [_3] is currently being blocked because of online exams.',$numblocked,$beginblock,$finishblock)); - $r->print(&Apache::loncommon::build_block_table($startblock,$endblock, - \%setters)); + $r->print(&blocked_in_folder($numblocked,$startblock,$endblock, + \%setters)); } } +sub blocked_in_folder { + my ($numblocked,$startblock,$endblock,$setters) = @_; + my $beginblock = &Apache::lonlocal::locallocaltime($startblock); + my $finishblock = &Apache::lonlocal::locallocaltime($endblock); + my $output = '<br /><br />'. + &mt('[quant,_1,message is, messages are] not viewable because display of LON-CAPA messages sent to you by other students between [_2] and [_3] is currently being blocked because of online exams.',$numblocked,$beginblock,$finishblock); + $output .= &Apache::loncommon::build_block_table($startblock,$endblock, + $setters); + return $output; +} + # ============================================================== Compose output sub compout { @@ -1187,7 +1193,14 @@ sub compout { text=>"Display All Messages"}); &printheader($r,'/adm/email?compose=multiforward', 'Forwarding Multiple Messages'); - $r->print(&mt('Each of the <b>[quant,_1,message]</b> you checked will be forwarded to the recipient(s) you select below.',$multiforward).'<br />'); + if ($multiforward > 1) { + $r->print(&mt('Each of the <b>[quant,_1,message]</b> you checked' + .' will be forwarded to the recipient(s) you select below.',$multiforward) + .'<br />'); + } else { + $r->print(&mt('The message you checked will be forwarded to the recipient(s) you select below.').'<br />'); + } + } else { &printheader($r,'/adm/email?compose=upload', 'Distribute from Uploaded File'); @@ -1197,10 +1210,13 @@ sub compout { my $dissub=''; my $dismsg=''; my $disbase=''; + my $attachrow; my $func=&mt('Send New'); my %lt=&Apache::lonlocal::texthash('us' => 'Username', 'do' => 'Domain', 'ad' => 'Additional Recipients', + 'rt' => 'Reply to', + 'ar' => 'Allow replies', 'sb' => 'Subject', 'ca' => 'Cancel', 'ma' => 'Mail', @@ -1209,7 +1225,15 @@ sub compout { 'gmt' => 'General message text', 'tff' => 'The file format for the uploaded portion of the message is', 'uas' => 'Upload and Send', + 'atta' => 'Attachment', ); + my %attachmax = ( + text => '(128 KB max size)', + num => 131072, + ); + if (!$forwarding && !$multiforward) { + $attachrow = '<br />'.$lt{'atta'}.' '.$attachmax{'text'}.': <input type="file" name="attachment" />'; + } if (&Apache::lonnet::allowed('srm',$env{'request.course.id'}) || &Apache::lonnet::allowed('srm',$env{'request.course.id'}. '/'.$env{'request.course.sec'})) { @@ -1223,7 +1247,19 @@ sub compout { &mt('Send copy to permanent email address (if known)').'</label></p>'. '<p><label><input type="checkbox" name="rsspost" /> '. &mt('Include in course RSS newsfeed').'</label></p>'; - } + } + if ($broadcast ne 'group') { + if (&Apache::lonnet::allowed('dff',$env{'request.course.id'}) || + &Apache::lonnet::allowed('dff',$env{'request.course.id'}. + '/'.$env{'request.course.sec'})) { + + $dispcrit.='<p><label>'. + '<input type="checkbox" name="courserecord" value="1" /> '. + &mt("Include in course's 'User records' for recipient(s)"). + '</label></p>'; + } + } + my %message; my %content; my $defdom=$env{'user.domain'}; @@ -1256,12 +1292,18 @@ sub compout { if ($content{'baseurl'}) { $disbase='<input type="hidden" name="baseurl" value="'.&escape($content{'baseurl'}).'" />'; if ($env{'user.adv'}) { - $disbase.='<label><input type="checkbox" name="storebasecomment" />'.&mt('Store message for re-use'). + $disbase.='<label><input type="checkbox" name="storebasecomment" />'.&mt('Save message for re-use'). '</label> <a href="/adm/email?showcommentbaseurl='. &escape($content{'baseurl'}).'" target="comments">'. &mt('Show re-usable messages').'</a><br />'; } } + my $jscript = &Apache::loncommon::check_uncheck_jscript(); + $r->print(<<"ENDREPSCRIPT"); +<script type="text/javascript"> +$jscript +</script> +ENDREPSCRIPT } my $citation=&displayresource(%content); my ($can_grp_broadcast,$viewgrps,$editgrps); @@ -1293,14 +1335,52 @@ sub compout { } if (($broadcast ne 'group') && ($broadcast ne 'upload')) { if ($replying) { - $r->print('<tr><td colspan="2">'.&mt('Replying to').' '. - &Apache::loncommon::aboutmewrapper( + if ($content{'noreplies'}) { + $r->print('<tr><td>'.&mt('This message was designated by the sender not to allow replies.').'</td></tr></table></form>'); + return; + } + $r->print('<tr><td colspan="2">'.&mt('Replying to').' '); + if ($content{'replytoaddr'}) { + my ($replytoname,$replytodom) = split(/:/,$content{'replytoaddr'}); + if ($replytoname ne '' && $replytodom ne '') { + $r->print(&Apache::loncommon::plainname($replytoname, + $replytodom).' ('.$replytoname.':'. + $replytodom.')'); + $r->print('<input type="hidden" name="recuname" value="'. + $replytoname.'" />'. + '<input type="hidden" name="recdomain" value="'. + $replytodom.'" /></td></tr>'); + + } else { + $r->print(&mt('The sender did not designate a reply to address for this message.').'</td></tr></table>'); + return; + } + } else { + $r->print(&Apache::loncommon::aboutmewrapper( &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).' ('. $content{'sendername'}.':'. - $content{'senderdomain'}.')'. - '<input type="hidden" name="recuname" value="'.$content{'sendername'}.'" />'. - '<input type="hidden" name="recdomain" value="'.$content{'senderdomain'}.'" />'. - '</td></tr>'); + $content{'senderdomain'}.')'); + $r->print('<input type="hidden" name="recuname" value="'. + $content{'sendername'}.'" />'. + '<input type="hidden" name="recdomain" value="'. + $content{'senderdomain'}.'" /></td></tr>'); + } + if ($content{'recipid'}) { + my @ccs = &retrieve_cc_recips('replying',%content); + if (@ccs > 0) { + my $replyall = qq| + <span class="LC_nobreak"> + <input type="button" value="check all" + onclick="javascript:checkAll(document.compemail.replying_cc)" /> + + <input type="button" value="uncheck all" + onclick="javascript:uncheckAll(document.compemail.replying_cc)" /> + </span> +|; + my $cclist = join(' ',@ccs); + $r->print('<tr><td>'.&mt('Reply to other recipients').':<br />'.$replyall.'</td><td>'.$cclist.'</td></tr>'); + } + } } else { $r->print(&recipient_input_row($defdom,%lt)); } @@ -1337,12 +1417,20 @@ $latexHelp. } elsif ($broadcast ne 'upload') { $subj_size = '50'; $r->print(&additional_rec_row(\%lt)); + if (&Apache::lonnet::allowed('srm',$env{'request.course.id'}) + || &Apache::lonnet::allowed('srm',$env{'request.course.id'}. + '/'.$env{'request.course.sec'})) { + $r->print(&reply_to_row(\%lt)); + } $r->print(&msg_subject_row($dissub,\%lt,$subj_size)); $r->print(<<"ENDCOMP"); </table> $latexHelp <textarea name="message" id="message" cols="80" rows="15" wrap="hard">$dismsg -</textarea></p><br /> +</textarea> +$attachrow +</p> +<br /> $dispcrit $disbase ENDCOMP @@ -1411,19 +1499,31 @@ sub recipient_input_row { &Apache::loncommon::selectstudent_link('compemail','recuname', 'recdomain'); my $output = <<"ENDREC"; -<tr><td>$lt{'us'}:</td><td><input type="text" size="12" name="recuname" value="$env{'form.recname'}" /></td><td rowspan="2">$selectlink</td></tr> -<tr><td>$lt{'do'}:</td> -<td>$domform</td></tr> +<tr><td colspan="2"><span class="LC_nobreak">$lt{'us'}: <input type="text" size="12" name="recuname" value="$env{'form.recname'}" /> $lt{'do'}: $domform $selectlink</span></td></tr> ENDREC return $output; } +sub reply_to_row { + my ($lt) = @_; + my $radioyes = &mt('Yes'); + my $radiono = &mt('No'); + my $output = <<"ENDREP"; +<tr><td colspan="2"><span class="LC_nobreak">$lt->{'ar'}:<label><input type="radio" name="can_reply" value="Y" checked="checked" />$radioyes</label> <label><input type="radio" name="can_reply" value="N" />$radiono</label></span> <span class="LC_nobreak">$lt->{'rt'}: <input type="text" size="25" name="reply_to_addr" value="$env{'user.name'}:$env{'user.domain'}" /></span></td></tr> +ENDREP + return $output; +} + sub additional_rec_row { my ($lt) = @_; + my $cc = &mt('Cc:'); + my $bcc = &mt('Bcc:'); + my $exmpl = &mt('username:domain,username:domain,...'); my $output = <<"ENDADD"; -<tr><td>$lt->{'ad'}:<br /><tt>username:domain,username:domain, ... -</tt></td><td> -<input type="text" size="50" name="additionalrec" /></td></tr> +<tr><td>$lt->{'ad'} :<br /><tt>($exmpl) +</tt></td><td> <span class="LC_nobreak">$cc +<input type="text" size="50" name="additionalrec_cc" /></span><br /> +<span class="LC_nobreak">$bcc <input type="text" size="50" name="additionalrec_bcc" /></span></td></tr> ENDADD return $output; } @@ -1441,7 +1541,7 @@ sub submit_button_row { sub msg_subject_row { my ($dissub,$lt,$subj_size,$extra) = @_; - my $output = '<tr><td>'.$lt->{'sb'}.':</td><td><input type="text" size="'. + my $output = '<tr><td colspan="2">'.$lt->{'sb'}.': <input type="text" size="'. $subj_size.'" name="subject" value="'.$dissub.'" />'.$extra. '</td></tr>'; return $output; @@ -1508,7 +1608,20 @@ sub disfacetoface { '<b>'.&mt('Subject').': '.$content{'subject'}.'</b><br />'. $content{'message'}; } - } + } + } elsif ($content{'subject'}=~/^Archive/) { + $result.='<h3>'.&mt('Archived Message').'</h3>'; + if (defined($content{'coursemsgid'})) { + my $crsmsgid = &escape($content{'coursemsgid'}); + my $archive_message = &general_message($crsmsgid); + $content{'message'} = '<b>'.&mt('Subject').': '.$content{'message'}.'</b><br />'.$archive_message; + } else { + %content=&Apache::lonmsg::unpackagemsg($content{'message'}); + $content{'message'} = + '<b>'.&mt('Subject').': '.$content{'subject'}.'</b><br +'. + $content{'message'}; + } } else { $result.='<h3>'.&mt('Critical Message').'</h3>'; if (defined($content{'coursemsgid'})) { @@ -1571,7 +1684,7 @@ sub facetoface { : 'faculty and staff'; &printheader($r, '/adm/email?recordftf=query', - "User Notes, Face-to-Face, Critical Messages, Broadcast Messages"); + "User Notes, Face-to-Face, Critical Messages, Broadcast Messages, Archived Messages"); # from query string if ($env{'form.recname'}) { $env{'form.recuname'}=$env{'form.recname'}; } @@ -1586,7 +1699,7 @@ sub facetoface { ('stdselect','recuname','recdomain'); my %lt=&Apache::lonlocal::texthash('user' => 'Username', 'dom' => 'Domain', - 'head' => "User Notes, Records of Face-To-Face Discussions, Critical Messages, and Broadcast Messages in $crstype", + 'head' => "User Notes, Records of Face-To-Face Discussions, Critical Messages, Broadcast Messages and Archived Messages in $crstype", 'subm' => 'Retrieve discussion and message records', 'newr' => 'New Record (record is visible to '.lc($crstype).' '.$leaders.')', 'post' => 'Post this Record'); @@ -1650,8 +1763,8 @@ sub examblock { 'cbds' => 'Communication blocking during scheduled exams', 'desc' => "You can use communication blocking to prevent $usertype enrolled in this course from displaying LON-CAPA messages sent by other $usertype during an online exam. As blocking of communication could potentially interrupt legitimate communication between $usertype who are also both enrolled in a different LON-CAPA course, please be careful that you select the correct start and end times for your scheduled exam when setting or modifying these parameters.", 'mecb' => 'Modify existing communication blocking periods', - 'ncbc' => 'No communication blocks currently stored', - 'stor' => 'Store', + 'ncbc' => 'No communication blocks currently saved', + 'stor' => 'Save', ); my %ltext = &Apache::lonlocal::texthash( @@ -1954,7 +2067,6 @@ sub displaymessage { } my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]); my %content=&Apache::lonmsg::unpackagemsg($message{$msgid}); - my $counter=0; $r->print('<pre>'); my $escmsgid=&escape($msgid); @@ -1965,15 +2077,33 @@ sub displaymessage { $counter++; } $r->print('</pre>'); + + my $see_anonymous; + my $from_student = 0; + if ($env{'request.course.id'} eq $content{'courseid'}) { + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $username = $content{'sendername'}.':'.$content{'senderdomain'}; + my %classlist_entry = + &Apache::lonnet::get('classlist',[$username],$cdom,$cnum); + if (exists($classlist_entry{$username})) { + $from_student = 1; + $see_anonymous = &Apache::lonnet::allowed('rin',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')); + } + } + + my $number_of_messages = scalar(@messages); #subtract 1 for last index # start output &printheader($r,'/adm/email?display='.&escape($msgid),'Display a Message','',$content{'baseurl'}); my %courseinfo=&Apache::lonnet::coursedescription($content{'courseid'}); # Functions - $r->print('<table border="2" width="100%"><tr bgcolor="#FFFFAA"><td>'.&mt('Functions').':</td>'. - '<td><a href="/adm/email?replyto='.&escape($msgid).$sqs. - '"><b>'.&mt('Reply').'</b></a></td>'. - '<td><a href="/adm/email?forward='.&escape($msgid).$sqs. + $r->print('<table border="2" width="100%"><tr bgcolor="#FFFFAA"><td>'.&mt('Functions').':</td>'); + if (!$content{'noreplies'}) { + $r->print('<td><a href="/adm/email?replyto='.&escape($msgid).$sqs. + '"><b>'.&mt('Reply').'</b></a></td>'); + } + $r->print('<td><a href="/adm/email?forward='.&escape($msgid).$sqs. '"><b>'.&mt('Forward').'</b></a></td>'. '<td><a href="/adm/email?markunread='.&escape($msgid).$sqs. '"><b>'.&mt('Mark Unread').'</b></a></td>'. @@ -1997,6 +2127,7 @@ sub displaymessage { $symb=&Apache::lonnet::symbread($content{'baseurl'}); } if ($env{'user.adv'}) { + my $adv_actions; $r->print('<table border="2" width="100%"><tr bgcolor="#FFAAAA"><td>'.&mt('Currently available actions (will open extra window)').':</td>'); if (&Apache::lonnet::allowed('vgr',$env{'request.course.id'})) { $r->print('<td><b>'.&Apache::loncommon::track_student_link(&mt('View recent activity'),$content{'sendername'},$content{'senderdomain'},'check').'</b></td>'); @@ -2009,16 +2140,22 @@ sub displaymessage { } $r->print('</tr></table>'); } - my $tolist; - my @recipients = (); - for (my $i=0; $i<@{$content{'recuser'}}; $i++) { - $recipients[$i] = &Apache::loncommon::aboutmewrapper( - &Apache::loncommon::plainname($content{'recuser'}[$i], + my ($tolist,$cclist); + my (@recipients,@ccs); + if (ref($content{'recuser'}) eq 'ARRAY') { + for (my $i=0; $i<@{$content{'recuser'}}; $i++) { + $recipients[$i] = &Apache::loncommon::aboutmewrapper( + &Apache::loncommon::plainname($content{'recuser'}[$i], $content{'recdomain'}[$i]), - $content{'recuser'}[$i],$content{'recdomain'}[$i]). - ' ('.$content{'recuser'}[$i].' at '.$content{'recdomain'}[$i].') '; + $content{'recuser'}[$i],$content{'recdomain'}[$i]). + ' ('.$content{'recuser'}[$i].' '.&mt('at').' '.$content{'recdomain'}[$i].') '; + } } $tolist = join(', ',@recipients); + if ($content{'recipid'}) { + @ccs = &retrieve_cc_recips('display',%content); + $cclist = join(', ',@ccs); + } my ($restitle,$baseurl,$refers_to); if (defined($content{'resource_title'})) { $restitle = $content{'resource_title'}; @@ -2030,18 +2167,50 @@ sub displaymessage { if (defined($content{'baseurl'})) { $baseurl = &Apache::lonenc::check_encrypt($content{'baseurl'}); } - print STDERR "baseurl is $content{'baseurl'}, title is $content{'resource_title'}, symb is $content{'symb'}, course is $content{'courseid'}\n"; - $r->print('<br /><b>'.&mt('Subject').':</b> '.$content{'subject'}. - ($folder ne 'sent'?'<br /><b>'.&mt('From').':</b> '. + if ($from_student && $see_anonymous ) { + $r->print(&Apache::loncommon::student_image_tag($content{'senderdomain'},$content{'sendername'})); + } + + $r->print('<br /><b>'.&mt('Subject').':</b> '.$content{'subject'}); + if ($folder eq 'sent') { + $r->print('<br /><b>'.&mt('To').':</b> '.$tolist); + if ($content{'replytoaddr'}) { + my ($replytoname,$replytodom) = split(/:/,$content{'replytoaddr'}); + if ($replytoname ne '' && $replytodom ne '') { + $r->print('<br /><b>'.&mt('Reply To').':</b> '. + $replytoname.' '.&mt('at').' '.$replytodom); + } + } + } else { + $r->print('<br /><b>'.&mt('From').':</b> '. &Apache::loncommon::aboutmewrapper( &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}), - $content{'sendername'},$content{'senderdomain'}).' ('. - $content{'sendername'}.' at '. - $content{'senderdomain'}.') ':'<br /><b>'.&mt('To').':</b> '. - $tolist). - ($content{'courseid'}?'<br /><b>'.&mt($crstype).':</b> '.$courseinfo{'description'}. - ($content{'coursesec'}?' ('.&mt('Section').': '.$content{'coursesec'}.')':''):''). - '<br /><b>'.&mt('Time').':</b> '.$content{'time'}); + $content{'sendername'},$content{'senderdomain'})); + if ($content{'noreplies'}) { + $r->print(' ('.&mt('No replies to sender').')'); + } else { + if ($content{'replytoaddr'}) { + my ($replytoname,$replytodom) = split(/:/,$content{'replytoaddr'}); + if ($replytoname ne '' && $replytodom ne '') { + $r->print('<br /><b>'.&mt('Reply To').':</b> '. + $replytoname.' '.&mt('at').' '.$replytodom); + } + } else { + $r->print(' ('.$content{'sendername'}.' '.&mt('at').' '. + $content{'senderdomain'}.') '); + } + if ($cclist) { + $r->print('<br /><b>'.&mt('Cc').':</b> '.$cclist); + } + } + } + if ($content{'courseid'}) { + $r->print('<br /><b>'.&mt($crstype).':</b> '.$courseinfo{'description'}); + if ($content{'coursesec'}) { + $r->print(' ('.&mt('Section').': '.$content{'coursesec'}.')'); + } + } + $r->print('<br /><b>'.&mt('Time').':</b> '.$content{'time'}); if ($baseurl) { if (defined($content{'courseid'}) && defined($env{'request.course.id'})) { if ($content{'courseid'} eq $env{'request.course.id'}) { @@ -2094,6 +2263,38 @@ sub displaymessage { return; } +sub retrieve_cc_recips { + my ($context,%content) = @_; + my %reciphash = + &Apache::lonnet::get('nohist_emailrecip',[$content{'recipid'}], + $content{'senderdomain'},$content{'sendername'}); + my $recipinfo = $reciphash{$content{'recipid'}}; + my @ccs; + if (ref($recipinfo) eq 'HASH') { + if (ref($recipinfo->{'cc'}) eq 'HASH') { + foreach my $cc (sort(keys(%{$recipinfo->{'cc'}}))) { + my ($ccname,$ccdom) = split(/:/,$cc); + if (!(($ccname eq $env{'user.name'}) && + ($ccdom eq $env{'user.domain'}))) { + my $showcc ='<span class="LC_nobreak">'; + if ($context eq 'replying') { + $showcc = '<label><input type="checkbox" name="replying_cc" value="'.$cc.'" />'; + } + $showcc .= &Apache::loncommon::aboutmewrapper( + &Apache::loncommon::plainname($ccname, + $ccdom),$ccname,$ccdom); + if ($context eq 'replying') { + $showcc .='</label>'; + } + $showcc .= '</span>'; + push(@ccs,$showcc); + } + } + } + } + return @ccs; +} + # =========================================================== Show the citation sub displayresource { @@ -2178,10 +2379,10 @@ sub storedcommentlisting { my ($r)=@_; my %msgs=&Apache::lonnet::dump('nohist_stored_comments',undef,undef, '^'.&escape(&escape($env{'form.showcommentbaseurl'}))); - $r->print(&Apache::loncommon::start_page('Stored Comment Listing',undef, + $r->print(&Apache::loncommon::start_page('Saved Comment Listing',undef, {'onlybody' => 1})); if ((keys %msgs)[0]=~/^error\:/) { - $r->print(&mt('No stored comments yet.')); + $r->print(&mt('No saved comments yet.')); } else { my $found=0; foreach my $key (sort(keys(%msgs))) { @@ -2189,7 +2390,7 @@ sub storedcommentlisting { $found=1; } unless ($found) { - $r->print(&mt('No stored comments yet for this resource.')); + $r->print(&mt('No saved comments yet for this resource.')); } } } @@ -2200,8 +2401,11 @@ sub sendoffmail { my ($r,$folder)=@_; my $suffix=&Apache::lonmsg::foldersuffix($folder); my $sendstatus=''; - my %specialmsg_status; - my $numspecial = 0; + my %msg_status; + my $numsent = 0; + my $nosentstore = 1; + my $attachmenturl; + my $now = time; my ($cdom,$cnum,$group); if (exists($env{'form.group'})) { $group = $env{'form.group'}; @@ -2224,10 +2428,13 @@ sub sendoffmail { if ($env{'form.forwid'}) { my $msgid=$env{'form.forwid'}; my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]); - %content=&Apache::lonmsg::unpackagemsg($message{$msgid},1); + %content=&Apache::lonmsg::unpackagemsg($message{$msgid},1,1); &statuschange($msgid,'forwarded',$folder); - $env{'form.message'}.="\n\n-- Forwarded message --\n\n". - $content{'message'}; + if ($content{'attachmenturl'} ne '') { + $attachmenturl = $content{'attachmenturl'}; + } + $env{'form.message'} .= "\n\n-- Forwarded message --\n\n". + $content{'message'}; } if ($env{'form.replyid'}) { my $msgid=$env{'form.replyid'}; @@ -2240,7 +2447,7 @@ sub sendoffmail { &Apache::loncommon::get_env_multiple('form.selectedusers_forminput'); my $mode = $env{'form.sendmode'}; - my %toaddr; + my (%toaddr,$cc,$bcc); if (@to) { foreach my $dest (@to) { my ($user,$domain) = split(/:/, $dest); @@ -2258,6 +2465,7 @@ sub sendoffmail { } } } elsif ($env{'form.sendmode'} eq 'upload') { + $nosentstore = 0; foreach my $line (split(/[\n\r\f]+/,$env{'form.upfile'})) { my ($rec,$txt) = ($line =~ /^([^:]+:[^:]+):(.*)$/); if ($txt) { @@ -2269,17 +2477,38 @@ sub sendoffmail { } else { if (($env{'form.recuname'} ne '') && ($env{'form.recdomain'} ne '')) { $toaddr{$env{'form.recuname'}.':'.$env{'form.recdomain'}}=''; + $cc->{$env{'form.recuname'}.':'.$env{'form.recdomain'}}=''; } } - if ($env{'form.additionalrec'}) { - foreach my $rec (split(/\,/,$env{'form.additionalrec'})) { + if ($env{'form.additionalrec_cc'}) { + foreach my $rec (split(/\s*,\s*/,$env{'form.additionalrec_cc'})) { my ($auname,$audom)=split(/:/,$rec); if (($auname ne "") && ($audom ne "")) { - $toaddr{$auname.':'.$audom}=''; + $toaddr{$auname.':'.$audom}=''; + $cc->{$auname.':'.$audom}=''; } } } - + if ($env{'form.additionalrec_bcc'}) { + foreach my $rec (split(/\s*,\s*/,$env{'form.additionalrec_bcc'})) { + my ($auname,$audom)=split(/:/,$rec); + if (($auname ne "") && ($audom ne "")) { + $toaddr{$auname.':'.$audom}=''; + $bcc->{$auname.':'.$audom}=''; + } + } + } + if ($env{'form.replying_cc'}) { + my @ccreplies = + &Apache::loncommon::get_env_multiple('form.replying_cc'); + foreach my $rec (@ccreplies) { + my ($auname,$audom)=split(/:/,$rec); + if (($auname ne "") && ($audom ne "")) { + $toaddr{$auname.':'.$audom}=''; + $cc->{$auname.':'.$audom}=''; + } + } + } my $savemsg; my $msgtype; my %sentmessage; @@ -2295,11 +2524,35 @@ sub sendoffmail { } else { $savemsg=&Apache::lonfeedback::clear_out_html($env{'form.message'}); } - + my %reciphash = ( + cc => $cc, + bcc => $bcc, + ); + my ($recipid,$recipstatus) = + &Apache::lonmsg::store_recipients($msgsubj,$env{'user.name'}, + $env{'user.domain'},\%reciphash); + if ($recipstatus ne 'ok') { + &Apache::lonnet::logthis('Failed to store Bcc and Cc recipients for '.$env{'user.name'}.':'.$env{'user.domain'}); + } + if ($env{'form.attachment'}) { + if (length($env{'form.attachment'})<131072) { + $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,'feedback/'.$now); + } else { + $r->print('<p><span class="LC_warning">'.&mt('Attachment not included - exceeded permitted length').'</span><br /></p>'); + } + } elsif ($env{'form.multiforward'}) { + if ($env{'form.attachmenturl'} ne '') { + $attachmenturl = $env{'form.attachmenturl'}; + } + } + my @recusers; + my @recudoms; foreach my $address (sort(keys(%toaddr))) { my ($recuname,$recdomain)=split(/\:/,$address); my $msgtxt = $savemsg; - if ($toaddr{$address}) { $msgtxt.='<hr />'.$toaddr{$address}; } + if ($toaddr{$address}) { + $msgtxt.='<hr />'.$toaddr{$address}; + } my @thismsg; if ($msgtype eq 'critical') { $r->print(&mt('Sending critical message').' '. @@ -2309,104 +2562,103 @@ sub sendoffmail { $msgsubj,$msgtxt, $env{'form.sendbck'}, $env{'form.permanent'}, - \$sentmessage{$address}); + \$sentmessage{$address}, + $nosentstore,$recipid); } else { $r->print(&mt('Sending').' '.$recuname.':'.$recdomain.': '); @thismsg= &Apache::lonmsg::user_normal_msg($recuname,$recdomain, $msgsubj,$msgtxt, $content{'citation'}, - undef,undef, + undef,$attachmenturl, $env{'form.permanent'}, - \$sentmessage{$address}); - } - if (($env{'request.course.id'}) && (($msgtype eq 'critical') || - ($env{'form.sendmode'} eq 'group'))) { - $specialmsg_status{$recuname.':'.$recdomain} = - join(' ',@thismsg); - foreach my $result (@thismsg) { - if ($result eq 'ok' || $result eq 'con_delayed') { - $numspecial++; - } - } + \$sentmessage{$address}, + undef,undef,undef, + $nosentstore,$recipid); + } + $msg_status{$recuname.':'.$recdomain}=join(' ',@thismsg); + if ($msg_status{$recuname.':'.$recdomain} =~ /(ok|con_delayed)/) { + $numsent++; + push(@recusers,$recuname); + push(@recudoms,$recdomain); } $sendstatus.=' '.join(' ',@thismsg); } - if (($env{'request.course.id'}) && (($env{'form.sendmode'} eq 'group') - || ($msgtype eq 'critical'))) { - my $subj_prefix; - if ($msgtype eq 'critical') { - $subj_prefix = 'Critical.'; - } else { - $subj_prefix = 'Broadcast.'; - } - my ($specialmsgid,$specialresult); - my $course_str = &escape('['.$cnum.':'.$cdom.']'); + my $subj_prefix; + if ($numsent > 0) { + if (($env{'request.course.id'}) && + (($env{'form.sendmode'} eq 'group') || + ($env{'form.courserecord'}) || + ($msgtype eq 'critical'))) { + if ($msgtype eq 'critical') { + $subj_prefix = 'Critical.'; + } elsif ($env{'form.sendmode'} eq 'group') { + $subj_prefix = 'Broadcast.'; + } else { + $subj_prefix = 'Archive'; + } + my ($specialmsgid,$specialresult); + my $course_str = &escape('['.$cnum.':'.$cdom.']'); - if ($numspecial) { - $specialresult = &Apache::lonmsg::user_normal_msg_raw($cnum,$cdom,$subj_prefix. - ' '.$course_str,$savemsg,undef,undef,undef, - undef,undef,\$specialmsgid); + $specialresult = + &Apache::lonmsg::user_normal_msg_raw($cnum,$cdom, + $subj_prefix.' '.$course_str,$savemsg,undef,undef, + $attachmenturl,undef,undef,\$specialmsgid,undef,undef,undef, + undef,undef,1); $specialmsgid = &unescape($specialmsgid); - } - if ($specialresult eq 'ok') { - my $record_sent; - my @recusers; - my @recudoms; - my ($stamp,$crssubj,$msgname,$msgdom,$msgcount,$context,$pid) = - split(/\:/,&unescape($specialmsgid)); - - foreach my $recipient (sort(keys(%toaddr))) { - if ($specialmsg_status{$recipient} eq 'ok') { - my $usersubj = $subj_prefix.'['.$recipient.']'; - my $usermsgid = - &Apache::lonmsg::buildmsgid($stamp,$usersubj, - $msgname,$msgdom, - $msgcount,$context, - $pid); - &Apache::lonmsg::user_normal_msg_raw($cnum,$cdom,$subj_prefix. - ' ['.$recipient.']',$msgsubj,undef, - undef,undef,undef,$usermsgid,undef,undef,$specialmsgid); - my ($uname,$udom) = split(/:/,$recipient); - push(@recusers,$uname); - push(@recudoms,$udom); + if ($specialresult eq 'ok') { + my ($stamp,$crssubj,$msgname,$msgdom,$msgcount,$context,$pid) = + split(/\:/,&unescape($specialmsgid)); + + foreach my $recipient (sort(keys(%toaddr))) { + if ($msg_status{$recipient} =~ /\s*(ok|con_delayed)\s*/) { + my $usersubj = $subj_prefix.'['.$recipient.']'; + my $usermsgid = + &Apache::lonmsg::buildmsgid($stamp,$usersubj, + $msgname,$msgdom, + $msgcount,$context, + $pid); + &Apache::lonmsg::user_normal_msg_raw($cnum,$cdom, + $subj_prefix.' ['.$recipient.']',$msgsubj, + undef,undef,$attachmenturl,undef,$usermsgid,undef, + undef,$specialmsgid,undef,undef,undef,1); + } } - } - if (@recusers) { - my $specialmessage; - my $sentsubj = - $subj_prefix.' ('.$numspecial.' sent) '.$msgsubj; - $sentsubj = &HTML::Entities::encode($sentsubj,'<>&"'); - my $sentmsgid = - &Apache::lonmsg::buildmsgid($stamp,$sentsubj,$msgname, - $msgdom,$msgcount,$context, - $pid); - ($specialmsgid,$specialmessage) = &Apache::lonmsg::packagemsg($msgsubj,$savemsg, - undef,undef,undef,\@recusers,\@recudoms,$sentmsgid); - $record_sent = &Apache::lonmsg::store_sent_mail($specialmsgid,$specialmessage); + if (($env{'form.sendmode'} ne 'upload') && (@recusers > 0)) { + &Apache::lonmsg::process_sent_mail($msgsubj, + $subj_prefix,$numsent,$stamp,$msgname,$msgdom, + $msgcount,$context,$pid,$savemsg,\@recusers, + \@recudoms,undef,$attachmenturl); + } + } else { + &Apache::lonnet::logthis('Failed to create record of critical, broadcast or archived message in '.$env{'course.'.$env{'request.course.id'}.'.num'}.' '&mt('at').' '.$env{'course.'.$env{'request.course.id'}.'.domain'}.' - no msgid generated'); } } else { - &Apache::lonnet::logthis('Failed to create record of critical message or broadcast in '.$env{'course.'.$env{'request.course.id'}.'.num'}.' at '.$env{'course.'.$env{'request.course.id'}.'.domain'}.' - no msgid generated'); + my $stamp = time; + my $msgcount = &Apache::lonmsg::get_uniq(); + my $context = &Apache::lonmsg::get_course_context(); + &Apache::lonmsg::process_sent_mail($msgsubj,$subj_prefix, + $numsent,$stamp,$env{'user.name'}, + $env{'user.domain'},$msgcount,$context, + $$,$savemsg,\@recusers,\@recudoms,undef,$attachmenturl); } } - } else { - &printheader($r,'','No messages sent.'); - } - if (!$env{'form.multiforward'}) { - if ($sendstatus=~/^(\s*(?:ok|con_delayed)\s*)*$/) { - $r->print('<br /><span class="LC_success">'.&mt('Completed.'). - '</span>'); - if ($env{'form.displayedcrit'}) { - &discrit($r); + if (!$env{'form.multiforward'}) { + if ($sendstatus=~/^(\s*(?:ok|con_delayed)\s*)*$/) { + $r->print('<br /><span class="LC_success">'.&mt('Completed.'). + '</span>'); + if ($env{'form.displayedcrit'}) { + &discrit($r); + } + if ($group ne '') { + $r->print(&groupmail_sent($group,$cdom,$cnum)); + } else { + &Apache::loncommunicate::menu($r); + } + } else { + $r->print('<p><span class="LC_error">'.&mt('Could not deliver message').'</span> '. + &mt('Please use the browser "Back" button and correct the recipient addresses ([_1]).',$sendstatus).'</p>'); } - if ($group ne '') { - $r->print(&groupmail_sent($group,$cdom,$cnum)); - } else { - &Apache::loncommunicate::menu($r); - } - } else { - $r->print('<p><span class="LC_error">'.&mt('Could not deliver message').'</span> '. - &mt('Please use the browser "Back" button and correct the recipient addresses '."($sendstatus)").'</p>'); } } return $sendstatus; @@ -2496,16 +2748,19 @@ sub handler { &printheader($r,'','Confirmed Receipt'); my $replying = 0; foreach my $envkey (keys(%env)) { - if ($envkey=~/^form\.rec\_(.*)$/) { - $r->print('<b>'.&mt('Confirming Receipt').':</b> '. - &Apache::lonmsg::user_crit_received($1).'<br>'); - } - if ($envkey=~/^form\.reprec\_(.*)$/) { - my $msgid=$1; - $r->print('<b>'.&mt('Confirming Receipt').':</b> '. - &Apache::lonmsg::user_crit_received($msgid).'<br>'); - &compout($r,'','','',$msgid); - $replying = 1; + if ($envkey=~/^form\.(rep)?rec\_(.*)$/) { + my $repchk = $1; + my $msgid = $2; + $r->print('<b>'.&mt('Confirming Receipt').':</b> '); + my $result = &Apache::lonmsg::user_crit_received($msgid); + if ($result =~ /trans:\s+ok/) { + &statuschange($msgid,'read'); + } + $r->print($result.'<br />'); + if ($repchk eq 'rep') { + &compout($r,'','','',$msgid); + $replying = 1; + } } } if (!$replying) { @@ -2637,7 +2892,7 @@ sub handler { foreach my $item (@to_forward) { my $msgid=&unescape($item); my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]); - my %content=&Apache::lonmsg::unpackagemsg($message{$msgid},1); + my %content=&Apache::lonmsg::unpackagemsg($message{$msgid},1,1); if ($env{'form.showorigsubj'}) { $env{'form.subject'} = $fixed_subj.$content{'subject'}; } else { @@ -2651,8 +2906,10 @@ sub handler { &Apache::loncommon::plainname($uname,$udom).' ('. $uname.':'.$udom.')'; } - $env{'form.message'} .= "\n\n-- Forwarded message --\n\n". - $content{'message'}; + $env{'form.message'}.="\n\n-- Forwarded message --\n\n". + $content{'message'}; + $env{'form.attachmenturl'} = $content{'attachmenturl'}; + $env{'form.multiforwid'} = $item; $fwdcount ++; $r->print($fwdcount.': '); $sendresult{$msgid} = &sendoffmail($r,$folder); @@ -2719,6 +2976,7 @@ sub handler { my $delresult = &deletefolder($folder); if ($delresult eq 'ok') { $r->print(&mt('Mail folder "[_1]" deleted.',$folder).'<br />'); + $env{'form.folder'} = ''; } else { $r->print(&mt('Deletion failed.').' '.$delresult.'<br />'); $showfolder = $folder; @@ -2749,8 +3007,6 @@ sub handler { =pod -=back - =cut 1;