--- loncom/interface/lonmsgdisplay.pm 2006/11/29 19:31:47 1.45
+++ loncom/interface/lonmsgdisplay.pm 2014/05/21 19:03:04 1.176
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Routines for messaging display
#
-# $Id: lonmsgdisplay.pm,v 1.45 2006/11/29 19:31:47 raeburn Exp $
+# $Id: lonmsgdisplay.pm,v 1.176 2014/05/21 19:03:04 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;
@@ -127,49 +110,210 @@ use Apache::lonfeedback;
use Apache::lonrss();
use Apache::lonselstudent();
use lib '/home/httpd/lib/perl/';
-use LONCAPA;
+use LONCAPA qw(:DEFAULT :match);
# 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 {
+ # Don't translate here!
+ my %statushash = (
+ '' => '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++;
- return
- &mt('Page').': '.
- ''.
- ''.
- ' of '.$maxdis.
- ''.
- ' '.
- &mt('Showing messages [_1] through [_2] of [_3]',$first,$finish,$total).'';
+
+ my %statushash = &get_msgstatus_types();
+ my $status;
+ if ($msgstatus eq '') {
+ $status = 'All'; # Don't translate here!
+ } else {
+ $status = $statushash{$msgstatus};
+ }
+ my $output = ''.&mt('Page:').' ';
+ if ($maxdis == 1) {
+ # No buttons if only one page is displayed
+ $output .= '1/1';
+ } else {
+ $output .=
+ ''.
+ ''.
+ ' / '.$maxdis.' '.
+ ''.
+ '';
+ }
+ $output .=
+ '
'
+ .''.&mt($status.' messages:').' '
+ .&mt('showing messages [_1] through [_2] of [_3].',
+ $first,$finish,$total)
+ .'
'
+ .'';
+
+ return $output;
}
# =============================================================== Status Change
@@ -195,14 +339,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.',$permfolders{$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 +518,9 @@ sub movemsg {
# ======================================================= Display a course list
sub discourse {
- my $result;
+ my ($statushash) = @_;
+ my ($result,$active,$previous,$future);
+ my $crstype = &Apache::loncommon::course_type();
my ($course_personnel,
$current_members,
$expired_members,
@@ -271,51 +529,106 @@ 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')
+ ) {
+ my $bcc_curr_hdr;
+ if ($crstype eq 'Community') {
+ $bcc_curr_hdr = &mt('Bcc: community participants with current access');
+ } else {
+ $bcc_curr_hdr = &mt('Bcc: course members with current access');
+ }
+ $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')
+ ) {
+ my $bcc_prev_hdr;
+ if ($crstype eq 'Community') {
+ $bcc_prev_hdr = &mt('Bcc: community participants with expired access');
+ } else {
+ $bcc_prev_hdr = &mt('Bcc: course members with expired access');
+ }
+ $result .= ' ';
+ if (ref($statushash) eq 'HASH') {
+ $statushash->{'previous'} = 1;
+ }
+
+ }
+ if ($tmptext = &Apache::lonselstudent::render_student_list($future_members,
+ "futureusers",
+ "future",
+ \%defaultUsers,
+ 1, "selectedusers",0,'email')
+ ) {
+ my $bcc_future_hdr;
+ if ($crstype eq 'Community') {
+ $bcc_future_hdr = &mt('Bcc: community participants with future access');
+ } else {
+ $bcc_future_hdr = &mt('Bcc: course members with future access');
+ }
- $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);
+ $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;
+ $r->print('
');
my %Sortby = (
active => {},
previous => {},
@@ -325,9 +638,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 +654,80 @@ 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('
'.
- &mt('[_1,quant,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 = '
'.
+ &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'})) {
@@ -915,6 +1349,21 @@ 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[_1] [quant,_2,message] [_3]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');
@@ -924,37 +1373,139 @@ 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 $crstype = &Apache::loncommon::course_type();
my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message");
+ my $rsstxt;
+ if (&Apache::loncommon::course_type() eq 'Community') {
+ $rsstxt = &mt('Include in community RSS newsfeed');
+ } else {
+ $rsstxt = &mt('Include in course RSS newsfeed');
+ }
$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'})) {
+
+ my $rectxt;
+ if (&Apache::loncommon::course_type() eq 'Community') {
+ $rectxt = &mt("Include in community's 'User records' for recipient(s)");
+ } else {
+ $rectxt = &mt("Include in course's 'User records' for recipient(s)");
+ }
+
+ $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) {
+ $r->print('
'.$studentsel.'
');
+ $hasfloat = 1;
+ }
+ } else {
+ $can_grp_broadcast = &check_group_priv($group);
+ if ($can_grp_broadcast) {
+ $hasfloat = &disgroup($r,$cdom,$cnum,$group,\%access_status);
+ }
+ }
+ if ($hasfloat) {
+ $sendmode = ''."\n";
+ $broadcast_js = qq|
+
+
+|;
+ }
+ }
if ($forwarding) {
%message=&Apache::lonnet::get('nohist_email'.$suffix,[$forwarding]);
%content=&Apache::lonmsg::unpackagemsg($message{$forwarding},$folder);
$dispcrit.='';
- $func=&mt('Forward');
+ $func1='Forward'; # do not translate here!
$dissub=&mt('Forwarding').': '.$content{'subject'};
$dismsg=&mt('Forwarded message from').' '.
@@ -968,7 +1519,7 @@ sub compout {
%content=&Apache::lonmsg::unpackagemsg($message{$replying},$folder);
$dispcrit.='';
- $func=&mt('Send Reply to');
+ $func1='Send Reply to'; # do not translate here!
$dissub=&mt('Reply').': '.$content{'subject'};
$dismsg='> '.$content{'message'};
@@ -978,74 +1529,193 @@ sub compout {
if ($content{'baseurl'}) {
$disbase='';
if ($env{'user.adv'}) {
- $disbase.='
');
- return;
+ catch(error) {
+ writeWin(caller);
+ return;
+ }
+ if (newWindow) {
+ caller = newWindow;
+ }
+ writeWin(caller);
+ return;
+}
+
+function writeWin(caller) {
+ caller.document.writeln('$start_page $body $end_page');
+ caller.document.close();
+ caller.focus();
+}
+// ]]>
+
+
+ENDJS
+ $broadcast_link = 1;
+ }
+ }
+ return $broadcast_link;
}
# =========================================================== Show the citation
@@ -1710,7 +2623,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
@@ -1739,15 +2657,14 @@ sub displayresource {
sub header {
my ($r,$title,$baseurl)=@_;
-
my $extra = &Apache::loncommon::studentbrowser_javascript();
if ($baseurl) {
$extra .= "";
}
- $r->print(&Apache::loncommon::start_page('Communication and Messages',
+ $r->print(&Apache::loncommon::start_page('Messages',
$extra));
$r->print(&Apache::lonhtmlcommon::breadcrumbs
- (($title?$title:'Communication and Messages')));
+ (($title?$title:'Send and display messages')));
}
# ---------------------------------------------------------------- Print header
@@ -1779,10 +2696,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))) {
@@ -1790,7 +2707,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.'));
}
}
}
@@ -1801,8 +2718,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'};
@@ -1812,10 +2732,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=();
@@ -1823,10 +2745,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'};
@@ -1835,50 +2760,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) = ($line =~ /^([^:]+:[^:]+):(.*)$/);
if ($txt) {
$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 my $rec (split(/\,/,$env{'form.additionalrec'})) {
+ 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;
@@ -1894,119 +2878,175 @@ 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.="\n".''."\n".$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*)*$/) {
+ my $message = &Apache::lonhtmlcommon::confirm_success(&mt('Completed.'));
+ $message = &Apache::loncommon::confirmwrapper($message);
+ $r->print($message);
+ if ($env{'form.displayedcrit'}) {
+ &discrit($r);
+ }
+ if ($group ne '') {
+ $r->print(&groupmail_sent($group,$cdom,$cnum));
+ } else {
+ &Apache::loncommunicate::menu($r);
+ }
+ } else {
+ my $message = &Apache::lonhtmlcommon::confirm_success(&mt('Could not deliver message'),1);
+ $message .= ' '.&mt('Please use the browser "Back" button and correct the recipient addresses ([_1]).',$sendstatus);
+ $message = &Apache::loncommon::confirmwrapper($message);
+ $r->print($message);
+ }
}
- if ($group ne '') {
- $r->print(&groupmail_sent($group,$cdom,$cnum));
- } else {
- &Apache::loncommunicate::menu($r);
- }
} else {
- $r->print('
'.&mt('Could not deliver message').' '.
- &mt('Please use the browser "Back" button and correct the recipient addresses '."($sendstatus)").'
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.