--- loncom/interface/lonmsgdisplay.pm 2006/08/29 00:28:51 1.35.2.5
+++ loncom/interface/lonmsgdisplay.pm 2009/09/08 22:08:20 1.134
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Routines for messaging display
#
-# $Id: lonmsgdisplay.pm,v 1.35.2.5 2006/08/29 00:28:51 albertel Exp $
+# $Id: lonmsgdisplay.pm,v 1.134 2009/09/08 22:08:20 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
@@ -74,8 +75,8 @@ email program, so they have full access
interface, or other features they may wish to use in response to the
student's query.
-=item * B: LON-CAPA can block display of e-mails that are
-sent to a student during an online exam. A course coordinator or
+=item * B: LON-CAPA can block selected communication
+features for students during an online exam. A course coordinator or
instructor can set an open and close date/time for scheduled online
exams in a course. If a user uses the LON-CAPA internal messaging
system to display e-mails during the scheduled blocking event,
@@ -93,25 +94,6 @@ addresses on their B 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 $uname and
-$udom in stored internal messages, compared
-with $email 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;
@@ -130,46 +113,196 @@ use lib '/home/httpd/lib/perl/';
use LONCAPA;
# Querystring component with sorting type
-my $sqs;
-my $startdis;
-my $interdis;
+my $sqs='';
+my $startdis='';
# ============================================================ List all folders
sub folderlist {
- my $folder=shift;
- my @allfolders=&Apache::lonnet::getkeys('email_folders');
- if ($allfolders[0]=~/^error:/) { @allfolders=(); }
- return '':'');
+ ''.
+ ($folder=~/^critical/?'':'');
+ return $output;
+}
+
+sub get_permanent_folders {
+ my %permfolders =
+ &Apache::lonlocal::texthash('' => 'INBOX',
+ 'trash' => 'TRASH',
+ 'critical' => 'Critical',
+ 'sent' => 'Sent Messages',
+ );
+ return %permfolders;
+}
+
+sub get_msgstatus_types {
+ my %statushash = &Apache::lonlocal::texthash(
+ '' => 'Any',
+ new => 'Unread',
+ read => 'Read',
+ replied => 'Replied to',
+ forwarded => 'Forwarded',
+ );
+ return %statushash;
}
sub scrollbuttons {
- my ($start,$maxdis,$first,$finish,$total)=@_;
+ my ($start,$maxdis,$first,$finish,$total,$msgstatus)=@_;
unless ($total>0) { return ''; }
$start++; $maxdis++;$first++;$finish++;
+
+ my %statushash = &get_msgstatus_types();
+ my $status;
+ if ($msgstatus eq '') {
+ $status = &mt('All');
+ } else {
+ $status = $statushash{$msgstatus};
+ }
return
- &mt('Page').': '.
- ''.
- ''.
- ' of '.$maxdis.
- ''.
- ' '.
- &mt('Showing messages [_1] through [_2] of [_3]',$first,$finish,$total).'';
+ ''.&mt('Page').': '.
+ ''.
+ ''.
+ ' / '.$maxdis.' '.
+ ''.
+ ' '.
+ &mt('[_1] messages: showing messages [_2] through [_3] of [_4].',$status,$first,$finish,$total).'';
}
# =============================================================== Status Change
@@ -195,14 +328,126 @@ sub statuschange {
# ============================================================= Make new folder
sub makefolder {
- my ($newfolder)=@_;
- if (($newfolder eq 'sent')
- || ($newfolder eq 'critical')
- || ($newfolder eq 'trash')
- || ($newfolder eq 'new')) { return; }
- &Apache::lonnet::put('email_folders',{$newfolder => time});
+ my ($newfolder) = @_;
+ my %permfolders = &get_permanent_folders();
+ my %userfolders = &Apache::lonmsg::get_user_folders();
+ my ($outcome,$warning);
+ if (defined($userfolders{$newfolder})) {
+ return &mt('The folder name: "[_1]" is already in use for an existing folder.',$newfolder);
+ }
+ foreach my $perm (keys(%permfolders)) {
+ if ($permfolders{$perm} eq $newfolder) {
+ return &mt('The folder name: "[_1]" is already used for one of the folders automatically generated by the system.',$newfolder);
+ }
+ }
+ if (&get_msgfolder_lock() eq 'ok') {
+ my %counter_hash = &Apache::lonnet::get('email_folders',["\0".'idcount']);
+ my $lastcount = $counter_hash{"\0".'idcount'};
+ my $folder_id = $lastcount + 1;
+ while (defined($userfolders{$folder_id})) {
+ $folder_id ++;
+ }
+ my %folderinfo = ( id => $folder_id,
+ created => time, );
+ $outcome =
+ &Apache::lonnet::put('email_folders',{$newfolder => \%folderinfo,
+ "\0".'idcount' => $folder_id});
+ my $releaseresult = &release_msgfolder_lock();
+ if ($releaseresult ne 'ok') {
+ $warning = $releaseresult;
+ }
+ } else {
+ $outcome =
+ &mt('Error - could not obtain lock on message folders record.');
+ }
+ return ($outcome,$warning);
+}
+
+# ============================================================= Delete folder
+
+sub deletefolder {
+ my ($folder)=@_;
+ my %permfolders = &get_permanent_folders();
+ if (defined($permfolders{$folder})) {
+ return &mt('The folder "[_1]" may not be deleted',$folder);
+ }
+ my %userfolders = &Apache::lonmsg::get_user_folders();
+ if (!defined($userfolders{$folder})) {
+ return &mt('The folder "[_1]" does not exist so deletion is not required.',
+ $folder);
+ }
+ # check folder is empty;
+ my $suffix=&Apache::lonmsg::foldersuffix($folder);
+ my @messages = &Apache::lonnet::getkeys('nohist_email'.$suffix);
+ if (@messages > 0) {
+ return &mt('The folder "[_1]" contains messages so it may not be deleted.',$folder).
+ ' '.
+ &mt('Delete or move the messages to a different folder first.');
+ }
+ my $delresult = &Apache::lonnet::del('email_folders',[$folder]);
+ return $delresult;
+}
+
+sub renamefolder {
+ my ($folder) = @_;
+ my $newname = $env{'form.renamed'};
+ my %permfolders = &get_permanent_folders();
+ 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);
+ }
+ my %userfolders = &Apache::lonmsg::get_user_folders();
+ if (defined($userfolders{$newname})) {
+ return &mt('The folder "[_1]" may not be renamed to "[_2]" because the new name you requested is already being used for an existing folder.',$folder,$newname);
+ }
+ if (!defined($userfolders{$folder})) {
+ return &mt('The folder "[_1]" could not be renamed to "[_2]" because the folder does not exist.',$folder,$newname);
+ }
+ my %folderinfo;
+ if (ref($userfolders{$folder}) eq 'HASH') {
+ %folderinfo = %{$userfolders{$folder}};
+ } else {
+ %folderinfo = ( id => $folder,
+ created => $userfolders{$folder},);
+ }
+ my $outcome =
+ &Apache::lonnet::put('email_folders',{$newname => \%folderinfo});
+ if ($outcome eq 'ok') {
+ $outcome = &Apache::lonnet::del('email_folders',[$folder]);
+ }
+ return $outcome;
+}
+
+sub get_msgfolder_lock {
+ # get lock for mail folder counter.
+ my $lockhash = { "\0".'lock_counter' => time, };
+ my $tries = 0;
+ my $gotlock = &Apache::lonnet::newput('email_folders',$lockhash);
+ while (($gotlock ne 'ok') && $tries <3) {
+ $tries ++;
+ sleep(1);
+ $gotlock = &Apache::lonnet::newput('email_folders',$lockhash);
+ }
+ return $gotlock;
+}
+
+sub release_msgfolder_lock {
+ # remove lock
+ my @del_lock = ("\0".'lock_counter');
+ my $dellockoutcome=&Apache::lonnet::del('email_folders',\@del_lock);
+ if ($dellockoutcome ne 'ok') {
+ return (' '.&mt('Warning: failed to release lock for counter').' ');
+ } else {
+ return 'ok';
+ }
}
+
# ======================================================== Move between folders
sub movemsg {
@@ -262,7 +507,8 @@ sub movemsg {
# ======================================================= Display a course list
sub discourse {
- my $result;
+ my ($statushash) = @_;
+ my ($result,$active,$previous,$future);
my ($course_personnel,
$current_members,
$expired_members,
@@ -271,51 +517,89 @@ sub discourse {
unshift @$current_members, (@$course_personnel);
my %defaultUsers;
- $result .= ''."\n";
+ my $tmptext;
+ if ($tmptext = &Apache::lonselstudent::render_student_list($current_members,
+ "activeusers",
+ "current",
+ \%defaultUsers,
+ 1,"selectedusers",1,'email')
+ ) {
+ $result .= ' ';
+ if (ref($statushash) eq 'HASH') {
+ $statushash->{'active'} = 1;
+ }
+ }
+ if ($tmptext = &Apache::lonselstudent::render_student_list($expired_members,
+ "previoususers",
+ "expired",
+ \%defaultUsers,
+ 1, "selectedusers",0,'email')
+ ) {
+ $result .= ' ';
+ if (ref($statushash) eq 'HASH') {
+ $statushash->{'previous'} = 1;
+ }
- $result .= &Apache::lonselstudent::render_student_list($current_members,
- "compemail",
- "current",
- \%defaultUsers,
- 1,"selectedusers",1);
-
- $result .= &Apache::lonselstudent::render_student_list($expired_members,
- "compemail",
- "expired",
- \%defaultUsers,
- 1, "selectedusers",0);
- $result .= &Apache::lonselstudent::render_student_list($future_members,
- "compemail",
- "future",
- \%defaultUsers,
- 1, "selectedusers", 0);
+ }
+ if ($tmptext = &Apache::lonselstudent::render_student_list($future_members,
+ "futureusers",
+ "future",
+ \%defaultUsers,
+ 1, "selectedusers",0,'email')
+ ) {
+ $result .= '';
+ if (ref($statushash) eq 'HASH') {
+ $statushash->{'future'} = 1;
+ }
+
+ }
return $result;
}
sub disgroup {
- my ($cdom,$cnum,$group,$viewgrps,$editgrps) = @_;
- my $result;
+ my ($r,$cdom,$cnum,$group,$access_status) = @_;
+ my $hasfloat;
# Needs to be in a course
if (!($env{'request.course.fn'})) {
- $result = &mt('Error: you must have a course role selected to be able to send a broadcast message to a group in the course.');
- return $result;
+ $r->print(''.&mt('Error: you must have a course role selected to be able to send a broadcast message to a group in the course.').'');
+ return;
}
if ($cdom eq '' || $cnum eq '') {
- $result = &mt('Error: could not determine domain or number of course');
- return $result;
+ $r->print(''.&mt('Error: could not determine domain or number of course').'');
+ return;
}
my ($memberinfo,$numitems) =
&Apache::longroup::group_memberlist($cdom,$cnum,$group,{},[]);
my @statustypes = ('active');
+ my $viewgrps = &Apache::lonnet::allowed('vcg',$env{'request.course.id'}.
+ ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));
+ my $editgrps = &Apache::lonnet::allowed('mdg',$env{'request.course.id'}.
+ ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:''));
if ($viewgrps || $editgrps) {
push(@statustypes,('future','previous'));
}
if (keys(%{$memberinfo}) == 0) {
- $result = &mt('As this group has no members, there are no '.
- 'recipients to select.');
- return $result;
+ $r->print(''.
+ &mt('As this group has no members, there are no recipients to select').
+ '');
+ return;
} else {
- $result = &mt('Select message recipients from the group members listed below. ');
+ $hasfloat = 1;
+ unless($env{'environment.wysiwygeditor'} eq 'on') {
+ $r->print('
');
+ }
my %Sortby = (
active => {},
previous => {},
@@ -325,9 +609,9 @@ sub disgroup {
'name' => 'Name',
'usnm' => 'Username',
'doma' => 'Domain',
- 'active' => 'Active Members',
- 'previous' => 'Former Members',
- 'future' => 'Future Members',
+ 'active' => 'Broadcast to Active Members',
+ 'previous' => 'Broadcast (Bcc) to Former Members',
+ 'future' => 'Broadcast (Bcc) to Future Members',
);
foreach my $user (sort(keys(%{$memberinfo}))) {
my $status = $$memberinfo{$user}{status};
@@ -341,75 +625,82 @@ sub disgroup {
push(@{$Sortby{$status}{$$memberinfo{$user}{fullname}}},$user);
}
}
- $result .= &group_check_uncheck();
- $result .= '
'.
- '
';
+ $r->print(&group_check_uncheck());
foreach my $status (@statustypes) {
if (ref($numitems) eq 'HASH') {
if ((defined($$numitems{$status})) && ($$numitems{$status})) {
- $result.='
'.
- '');
if ($numblocked > 0) {
- my $beginblock = &Apache::lonlocal::locallocaltime($startblock);
- my $finishblock = &Apache::lonlocal::locallocaltime($endblock);
- $r->print('
'.
- $numblocked.' '.&mt('message(s) is/are not viewable because display of LON-CAPA messages sent to you by other students between').' '.$beginblock.' '.&mt('and').' '.$finishblock.' '.&mt('is currently being blocked because of online exams.'));
- &build_block_table($r,$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 = '
'.
+ &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);
+
+ my ($blocked, $blocktext) = &Apache::loncommon::blocking_status("com");
+ $output .="
".$blocktext;
+
+ return $output;
+}
+
# ============================================================== Compose output
sub compout {
- my ($r,$forwarding,$replying,$broadcast,$replycrit,$folder,$dismode)=@_;
+ my ($r,$forwarding,$replying,$broadcast,$replycrit,$folder,$dismode,
+ $multiforward)=@_;
my $suffix=&Apache::lonmsg::foldersuffix($folder);
my ($cdom,$cnum,$group,$refarg);
if (exists($env{'form.group'})) {
@@ -924,6 +1261,20 @@ sub compout {
} elsif ($replycrit) {
$r->print('
'.&mt('Replying to a Critical Message').'
');
$replying=$replycrit;
+ } elsif ($multiforward) {
+ &Apache::lonhtmlcommon::add_breadcrumb
+ ({href=>"/adm/email?folder=".&escape($folder),
+ text=>"Display All Messages"});
+ &printheader($r,'/adm/email?compose=multiforward',
+ 'Forwarding Multiple Messages');
+ if ($multiforward > 1) {
+ $r->print(&mt('Each of the [quant,_1,message] you checked'
+ .' will be forwarded to the recipient(s) you select below.',$multiforward)
+ .' ');
+ } else {
+ $r->print(&mt('The message you checked will be forwarded to the recipient(s) you select below.').' ');
+ }
+
} else {
&printheader($r,'/adm/email?compose=upload',
'Distribute from Uploaded File');
@@ -933,37 +1284,126 @@ sub compout {
my $dissub='';
my $dismsg='';
my $disbase='';
- my $func=&mt('Send New');
- my %lt=&Apache::lonlocal::texthash('us' => 'Username',
- 'do' => 'Domain',
- 'ad' => 'Additional Recipients',
- 'sb' => 'Subject',
- 'ca' => 'Cancel',
- 'ma' => 'Mail');
-
+ my $attachrow;
+ my $func1='Send'; # do not translate here!
+ my %func2=( # do not translate here!
+ 'ma' => 'Message',
+ 'msg' => 'Messages',
+ );
+ my %lt=&Apache::lonlocal::texthash('us' => 'Username',
+ 'do' => 'Domain',
+ 'ad' => 'Additional Recipients',
+ 'rt' => 'Reply to',
+ 'ar' => 'Allow replies',
+ 'sb' => 'Subject',
+ 'ca' => 'Cancel',
+ 'gen' => 'Generate messages from a file',
+ 'gmt' => 'General message text',
+ 'tff' => 'The file format for the uploaded portion of the message is',
+ 'uas' => 'Upload and Send',
+ 'atta' => 'Attachment',
+ 'to' => 'To:',
+ );
+ my %attachmax = (
+ text => &mt('(128 KB max size)'),
+ num => 131072,
+ );
+ if (!$forwarding && !$multiforward) {
+ $attachrow = '
'.$lt{'atta'}.' '.$attachmax{'text'}.':
';
+ }
if (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
|| &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
'/'.$env{'request.course.sec'})) {
my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message");
$dispcrit=
- '
' . $crithelp .
- '
'.
- '' . $crithelp .
- '
'.
-'';
- }
+ ''.$crithelp.' '.&mt('Require return receipt?').' '.
+ ' '.
+' ';
+ }
+ 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.=' ';
+ }
+ }
+
my %message;
my %content;
+ my ($hasfloat,$broadcast_js,$sendmode,$can_grp_broadcast);
my $defdom=$env{'user.domain'};
+ if ($broadcast eq 'group') {
+ my %access_status = (
+ active => 0,
+ previous => 0,
+ future => 0,
+ );
+
+ if ($group eq '') {
+ my $studentsel = &discourse(\%access_status);
+ if ($studentsel) {
+ if ($env{'environment.wysiwygeditor'} eq 'on') {
+ $r->print($studentsel);
+ } else {
+ $r->print('
';
+ }
+ $body .= &Apache::loncommon::end_data_table_row().
+ &Apache::loncommon::end_data_table();
+ $body =~ s{}{<\\/}g;
+ $body =~ s{\n}{}g;
+ $r->print(<
+//
+
+
+ENDJS
+ $broadcast_link = 1;
+ }
+ }
+ return $broadcast_link;
}
# =========================================================== Show the citation
@@ -1758,7 +2796,12 @@ sub displayresource {
#
if (($env{'request.course.id'} eq $content{'courseid'})
&& (&Apache::lonnet::allowed('vgr',$content{'courseid'}))) {
- my $symb=&Apache::lonnet::symbread($content{'baseurl'});
+ my $symb;
+ if (defined($content{'symb'})) {
+ $symb = $content{'symb'};
+ } else {
+ $symb=&Apache::lonnet::symbread($content{'baseurl'});
+ }
# Could not get a symb, give up
unless ($symb) { return $content{'citation'}; }
# Have a symb, can render
@@ -1787,15 +2830,14 @@ sub displayresource {
sub header {
my ($r,$title,$baseurl)=@_;
-
my $extra = &Apache::loncommon::studentbrowser_javascript();
if ($baseurl) {
- $extra .= "";
+ $extra .= "";
}
- $r->print(&Apache::loncommon::start_page('Communication and Messages',
+ $r->print(&Apache::loncommon::start_page('Communication',
$extra));
$r->print(&Apache::lonhtmlcommon::breadcrumbs
- (($title?$title:'Communication and Messages')));
+ (($title?$title:'Send and Receive Messages')));
}
# ---------------------------------------------------------------- Print header
@@ -1814,9 +2856,9 @@ sub storecomment {
my ($r)=@_;
my $msgtxt=&Apache::lonfeedback::clear_out_html($env{'form.message'});
my $cleanmsgtxt='';
- foreach (split(/[\n\r]/,$msgtxt)) {
- unless ($_=~/^\s*(\>|\>\;)/) {
- $cleanmsgtxt.=$_."\n";
+ foreach my $line (split(/[\n\r]/,$msgtxt)) {
+ unless ($line=~/^\s*(\>|\>\;)/) {
+ $cleanmsgtxt.=$line."\n";
}
}
my $key=&escape($env{'form.baseurl'}).'___'.time;
@@ -1827,18 +2869,18 @@ 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 (sort keys %msgs) {
- $r->print("\n".$msgs{$_}."");
+ foreach my $key (sort(keys(%msgs))) {
+ $r->print("\n".$msgs{$key}."");
$found=1;
}
unless ($found) {
- $r->print(&mt('No stored comments yet for this resource.'));
+ $r->print(&mt('No saved comments yet for this resource.'));
}
}
}
@@ -1849,8 +2891,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'};
@@ -1860,10 +2905,12 @@ sub sendoffmail {
$cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
}
if ($env{'form.send'}) {
- if ($group eq '') {
- &printheader($r,'','Messages being sent.');
- } else {
- $r->print(&groupmail_header('sending',$group));
+ if (!$env{'form.multiforward'}) {
+ if ($group eq '') {
+ &printheader($r,'','Messages being sent.');
+ } else {
+ $r->print(&groupmail_header('sending',$group));
+ }
}
$r->rflush();
my %content=();
@@ -1871,10 +2918,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'};
@@ -1883,49 +2933,109 @@ sub sendoffmail {
&statuschange($msgid,'replied',$folder);
}
- my @to =
- &Apache::loncommon::get_env_multiple('form.selectedusers_forminput');
my $mode = $env{'form.sendmode'};
+ my (%toaddr,$tos,$cc,$bcc,$broadcast);
- my %toaddr;
- if (@to) {
- foreach my $dest (@to) {
- my ($user,$domain) = split(/:/, $dest);
- if (($user ne '') && ($domain ne '')) {
- my $address = $user.":".$domain; # How the code below expects it.
- $toaddr{$address} = '';
- }
- }
- }
-
- if ($env{'form.sendmode'} eq 'group') {
- foreach my $address (keys(%env)) {
- if ($address=~/^form\.send\_to\_\&\&\&[^\&]*\&\&\&\_(.+)$/) {
- $toaddr{$1}='';
- }
- }
- } elsif ($env{'form.sendmode'} eq 'upload') {
+ if ($mode eq 'group') {
+ if (defined($env{'form.courserecips'})) {
+ my $courseusers = $env{'form.courserecips'};
+ $courseusers =~ s/^_\&\&\&_//;
+ my @to = split('_&&&_',$courseusers);
+ foreach my $dest (@to) {
+ my ($user,$domain) = split(/:/, $dest);
+ if (($user ne '') && ($domain ne '')) {
+ my $rec = $user.":".$domain;
+ $toaddr{$rec} = '';
+ $broadcast->{$rec} = '';
+ }
+ }
+ }
+ } elsif ($mode eq 'upload') {
+ $nosentstore = 0;
foreach my $line (split(/[\n\r\f]+/,$env{'form.upfile'})) {
- my ($rec,$txt)=split(/\s*\:\s*/,$line);
+ my ($rec,$txt) = ($line =~ /^([^:]+:[^:]+):(.*)$/);
if ($txt) {
- $rec=~s/\@/\:/;
+ $rec =~ s/^\s+//;
+ $rec =~ s/\s+$//;
$toaddr{$rec}.=$txt."\n";
+ $broadcast->{$rec} = '';
}
}
} else {
if (($env{'form.recuname'} ne '') && ($env{'form.recdomain'} ne '')) {
$toaddr{$env{'form.recuname'}.':'.$env{'form.recdomain'}}='';
+ $tos->{$env{'form.recuname'}.':'.$env{'form.recdomain'}}='';
}
}
- if ($env{'form.additionalrec'}) {
- foreach (split(/\,/,$env{'form.additionalrec'})) {
- my ($auname,$audom)=split(/\@/,$_);
+ if ($env{'form.additionalrec_to'}) {
+ foreach my $rec (split(/\s*,\s*/,$env{'form.additionalrec_to'})) {
+ my ($auname,$audom)=split(/:/,$rec);
+ if (($auname ne "") && ($audom ne "")) {
+ $toaddr{$auname.':'.$audom}='';
+ $tos->{$auname.':'.$audom}='';
+ }
+ }
+ }
+ if ($env{'form.replying_to'}) {
+ my @toreplies =
+ &Apache::loncommon::get_env_multiple('form.replying_to');
+ foreach my $rec (@toreplies) {
+ my ($auname,$audom)=split(/:/,$rec);
+ if (($auname ne "") && ($audom ne "")) {
+ $toaddr{$auname.':'.$audom}='';
+ $tos->{$auname.':'.$audom}='';
+ }
+ }
+ }
+ 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}='';
+ if (!defined($tos->{$auname.':'.$audom})) {
+ $cc->{$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}='';
+ if (!defined($tos->{$auname.':'.$audom})) {
+ $cc->{$auname.':'.$audom}='';
+ }
+ }
+ }
+ }
+ if ($env{'form.replying_groupcc'}) {
+ my @groupreplies =
+ &Apache::loncommon::get_env_multiple('form.replying_groupcc');
+ foreach my $rec (@groupreplies) {
+ my ($auname,$audom)=split(/:/,$rec);
+ if (($auname ne "") && ($audom ne "")) {
+ $toaddr{$auname.':'.$audom}='';
+ if (!defined($tos->{$auname.':'.$audom})) {
+ $broadcast->{$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}='';
+ if ((!defined($tos->{$auname.':'.$audom})) &&
+ (!defined($cc->{$auname.':'.$audom}))) {
+ $bcc->{$auname.':'.$audom}='';
+ }
+ }
+ }
+ }
my $savemsg;
my $msgtype;
my %sentmessage;
@@ -1941,119 +3051,169 @@ sub sendoffmail {
} else {
$savemsg=&Apache::lonfeedback::clear_out_html($env{'form.message'});
}
-
+ my %reciphash = (
+ to => $tos,
+ cc => $cc,
+ bcc => $bcc,
+ );
+ if ($mode eq 'group') {
+ if ($group eq '') {
+ $reciphash{'course_broadcast'} = $broadcast;
+ } else {
+ if ($env{'form.groupmail'} eq 'cc') {
+ $reciphash{'group_cc_broadcast'} = $broadcast;
+ } else {
+ $reciphash{'group_bcc_broadcast'} = $broadcast;
+ }
+ }
+ }
+ 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 To, 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('
'.&mt('Attachment not included - exceeded permitted length').'
');
+ }
+ } 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.=''.$toaddr{$address}; }
+ if ($toaddr{$address}) {
+ $msgtxt.=''.$toaddr{$address};
+ }
my @thismsg;
- if ((($env{'form.critmsg'}) || ($env{'form.sendbck'})) &&
- (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
- || &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
- '/'.$env{'request.course.sec'}))) {
- $r->print(&mt('Sending critical message').' '.$recuname.':'.$recdomain.': ');
+ if ($msgtype eq 'critical') {
+ $r->print(&mt('Sending critical message').' '.
+ $recuname.':'.$recdomain.': ');
@thismsg=
&Apache::lonmsg::user_crit_msg($recuname,$recdomain,
$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});
+ \$sentmessage{$address},
+ undef,undef,undef,
+ $nosentstore,$recipid);
}
- 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') {
- $numspecial++;
- }
- }
+ $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.']');
-
- if ($numspecial) {
- $specialresult = &Apache::lonmsg::user_normal_msg_raw($cnum,$cdom,$subj_prefix.
- ' '.$course_str,$savemsg,undef,undef,undef,
- undef,undef,\$specialmsgid);
+ my $subj_prefix;
+ if ($numsent > 0) {
+ if (($env{'request.course.id'}) &&
+ (($mode eq 'group') ||
+ ($env{'form.courserecord'}) ||
+ ($msgtype eq 'critical')) ||
+ ($env{'form.replyid'} &&
+ (($content{'courseid'} ne '') &&
+ ($mode eq 'group')))) {
+ if ($msgtype eq 'critical') {
+ $subj_prefix = 'Critical.';
+ } elsif ($mode eq 'group') {
+ $subj_prefix = 'Broadcast.';
+ } else {
+ $subj_prefix = 'Archive';
+ }
+ my ($specialmsgid,$specialresult);
+ my $course_str;
+ if ($env{'form.replyid'}) {
+ if ($content{'courseid'} ne '') {
+ my %crsdesc =
+ &Apache::lonnet::coursedescription($content{'courseid'},
+ {'one_time' => 1});
+ $course_str = &escape('['.$crsdesc{'num'}.':'.$crsdesc{'domain'}.']');
+ }
+ } elsif ($env{'request.course.id'}) {
+ $course_str = &escape('['.$cnum.':'.$cdom.']');
+ }
+ $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 (@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 ($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 (($mode ne 'upload') && (@recusers > 0)) {
+ &Apache::lonmsg::process_sent_mail($msgsubj,
+ $subj_prefix,$numsent,$stamp,$msgname,$msgdom,
+ $msgcount,$context,$pid,$savemsg,\@recusers,
+ \@recudoms,undef,$attachmenturl,'','','','',$recipid);
+ }
+ } 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,
+ '','','','',$recipid);
}
}
- } else {
- &printheader($r,'','No messages sent.');
- }
- if ($sendstatus=~/^(\s*(?:ok|con_delayed)\s*)*$/) {
- $r->print(' '.&mt('Completed.').'');
- if ($env{'form.displayedcrit'}) {
- &discrit($r);
+ if (!$env{'form.multiforward'}) {
+ if ($sendstatus=~/^(\s*(?:ok|con_delayed)\s*)*$/) {
+ $r->print(' '.&mt('Completed.').
+ '');
+ if ($env{'form.displayedcrit'}) {
+ &discrit($r);
+ }
+ if ($group ne '') {
+ $r->print(&groupmail_sent($group,$cdom,$cnum));
+ } else {
+ &Apache::loncommunicate::menu($r);
+ }
+ } else {
+ $r->print('
'.&Apache::lonhtmlcommon::confirm_success(&mt('Could not deliver message'),1).' '.
+ &mt('Please use the browser "Back" button and correct the recipient addresses ([_1]).',$sendstatus).'
'.
+ &mt('Could not forward [quant,_1,message].',$count).
+ ' ');
+ foreach my $key (keys(%forwardfail)) {
+ $r->print(&mt('Could not deliver forwarded message.').' '.
+ &mt('The recipient addresses may need to be corrected').' ('.$forwardfail{$key}.').
The server encountered an internal error or
misconfiguration and was unable to complete
your request.
Please contact the server administrator at
root@localhost to inform them of the time this error occurred,
and the actions you performed just before this error.
More information about this error may be available
in the server error log.