--- loncom/interface/lonmsg.pm 2000/10/31 22:31:37 1.5 +++ loncom/interface/lonmsg.pm 2003/10/15 21:10:24 1.69 @@ -1,7 +1,31 @@ # The LearningOnline Network with CAPA -# # Routines for messaging # +# $Id: lonmsg.pm,v 1.69 2003/10/15 21:10:24 www Exp $ +# +# Copyright Michigan State University Board of Trustees +# +# This file is part of the LearningOnline Network with CAPA (LON-CAPA). +# +# LON-CAPA is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# LON-CAPA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LON-CAPA; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# /home/httpd/html/adm/gpl.txt +# +# http://www.lon-capa.org/ +# +# # (Routines to control the menu # # (TeX Conversion Module @@ -10,33 +34,117 @@ # # 10/05 Gerd Kortemeyer) # -# 10/19,10/20,10/30 Gerd Kortemeyer - +# 10/19,10/20,10/30, +# 02/06/01 Gerd Kortemeyer +# 07/27 Guy Albertelli +# 07/27,07/28,07/30,08/03,08/06,08/08,08/09,08/10,8/13,8/15, +# 10/1,11/5 Gerd Kortemeyer +# YEAR=2002 +# 1/1,3/18 Gerd Kortemeyer +# package Apache::lonmsg; +=pod + +=head1 NAME + +Apache::lonmsg: 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. + +=head1 OVERVIEW + +=head2 Messaging Overview + +XLON-CAPA provides an internal messaging system similar to +email, but customized for LON-CAPA's usage. LON-CAPA implements its +own messaging system, rather then building on top of email, because of +the features LON-CAPA messages can offer that conventional e-mail can +not: + +=over 4 + +=item * B: A message the recipient B +acknowlegde receipt of before they are allowed to continue using the +system, preventing a user from claiming they never got a message + +=item * B: LON-CAPA can reliably send reciepts informing the +sender that it has been read; again, useful for preventing students +from claiming they did not see a message. (While conventional e-mail +has some reciept support, it's sporadic, e-mail client-specific, and +generally the receiver can opt to not send one, making it useless in +this case.) + +=item * B: LON-CAPA knows about the sender, such as where +they are in a course. When a student mails an instructor asking for +help on the problem, the instructor receives not just the student's +question, but all submissions the student has made up to that point, +the user's rendering of the problem, and the complete view the student +saw of the resource, including discussion up to that point. Finally, +the instructor is reading all of this inside of LON-CAPA, not their +email program, so they have full access to LON-CAPA's grading +interface, or other features they may wish to use in response to the +student's query. + +=back + +Users can ask LON-CAPA to forward messages to conventional e-mail +addresses on their B screen, but generally, LON-CAPA messages +are much more useful then 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. + +=head1 FUNCTIONS + +=over 4 + +=cut + use strict; use Apache::lonnet(); use vars qw($msgcount); -use HTML::TokeParser; +use HTML::TokeParser(); use Apache::Constants qw(:common); +use Apache::loncommon(); +use Apache::lontexconvert(); +use HTML::Entities(); +use Mail::Send; +use Apache::lonlocal; + +# Querystring component with sorting type +my $sqs; # ===================================================================== Package sub packagemsg { - my ($subject,$message)=@_; - $message=~s/\/\>\;/g; - $subject=~s/\/\>\;/g; + my ($subject,$message,$citation,$baseurl,$attachmenturl)=@_; + $message =&HTML::Entities::encode($message); + $citation=&HTML::Entities::encode($citation); + $subject =&HTML::Entities::encode($subject); + #remove machine specification + $baseurl =~ s|^http://[^/]+/|/|; + $baseurl =&HTML::Entities::encode($baseurl); + #remove machine specification + $attachmenturl =~ s|^http://[^/]+/|/|; + $attachmenturl =&HTML::Entities::encode($attachmenturl); + my $now=time; $msgcount++; - my $msgid=$now.'_'.$ENV{'user.name'}.'_'. - $ENV{'user.domain'}.'_'.$msgcount.'_'.$$; - return $msgid, - ''.$ENV{'user.name'}.''. + my $partsubj=$subject; + $partsubj=&Apache::lonnet::escape($partsubj); + my $msgid=&Apache::lonnet::escape( + $now.':'.$partsubj.':'.$ENV{'user.name'}.':'. + $ENV{'user.domain'}.':'.$msgcount.':'.$$); + my $result=''.$ENV{'user.name'}.''. ''.$ENV{'user.domain'}.''. ''.$subject.''. - ''. + ''. ''.$ENV{'SERVER_NAME'}.''. ''.$ENV{'HTTP_HOST'}.''. ''.$ENV{'REMOTE_ADDR'}.''. @@ -50,12 +158,22 @@ sub packagemsg { ''.$ENV{'request.filename'}.''. ''.$msgid.''. ''.$message.''; + if (defined($citation)) { + $result.=''.$citation.''; + } + if (defined($baseurl)) { + $result.= ''.$baseurl.''; + } + if (defined($attachmenturl)) { + $result.= ''.$attachmenturl.''; + } + return $msgid,$result; } # ================================================== Unpack message into a hash sub unpackagemsg { - my $message=shift; + my ($message,$notoken)=@_; my %content=(); my $parser=HTML::TokeParser->new(\$message); my $token; @@ -66,11 +184,88 @@ sub unpackagemsg { $content{$entry}=$value; } } + if ($content{'attachmenturl'}) { + my ($fname,$ft)=($content{'attachmenturl'}=~/\/(\w+)\.(\w+)$/); + if ($notoken) { + $content{'message'}.='

'.&mt('Attachment').': '.$fname.'.'.$ft.''; + } else { + $content{'message'}.='

'.&mt('Attachment').': '.$fname.'.'.$ft.''; + } + } return %content; } +# ======================================================= Get info out of msgid + +sub unpackmsgid { + my $msgid=&Apache::lonnet::unescape(shift); + my ($sendtime,$shortsubj,$fromname,$fromdomain)=split(/\:/, + &Apache::lonnet::unescape($msgid)); + my %status=&Apache::lonnet::get('email_status',[$msgid]); + if ($status{$msgid}=~/^error\:/) { $status{$msgid}=''; } + unless ($status{$msgid}) { $status{$msgid}='new'; } + return ($sendtime,$shortsubj,$fromname,$fromdomain,$status{$msgid}); +} + + +sub sendemail { + my ($to,$subject,$body)=@_; + $body= + "*** ".&mt('This is an automatic message generated by the LON-CAPA system.')."\n". + "*** ".&mt('Please do not reply to this address.')."\n\n".$body; + my $msg = new Mail::Send; + $msg->to($to); + $msg->subject('[LON-CAPA] '.$subject); + if (my $fh = $msg->open('smtp',Server => 'localhost')) { + print $fh $body; + $fh->close; + } +} + +# ==================================================== Send notification emails + +sub sendnotification { + my ($to,$touname,$toudom,$subj,$crit)=@_; + my $sender=$ENV{'environment.firstname'}.' '.$ENV{'environment.lastname'}; + my $critical=($crit?' critical':''); + my $url='http://'. + $Apache::lonnet::hostname{&Apache::lonnet::homeserver($touname,$toudom)}. + '/adm/email?username='.$touname.'&domain='.$toudom; + my $body=(<300) { + my %what=&Apache::lonnet::get('email_status',['recnewemail']); + &Apache::lonnet::appenv('user.mailcheck.time'=>time); + if ($what{'recnewemail'}>0) { return 1; } + } + return 0; +} + # =============================== Automated message to the author of a resource +=pod + +=item * B: Sends message $message to the owner + of the resource with the URI $filename. + +=cut + sub author_res_msg { my ($filename,$message)=@_; unless ($message) { return 'empty'; } @@ -91,23 +286,37 @@ sub author_res_msg { # ================================================== Critical message to a user -sub user_crit_msg { - my ($user,$domain,$subject,$message)=@_; +sub user_crit_msg_raw { + my ($user,$domain,$subject,$message,$sendback)=@_; # Check if allowed missing my $status=''; my $msgid='undefined'; unless (($message)&&($user)&&($domain)) { $status='empty'; }; my $homeserver=&Apache::lonnet::homeserver($user,$domain); if ($homeserver ne 'no_host') { - my $msgid; ($msgid,$message)=&packagemsg($subject,$message); + if ($sendback) { $message.='true'; } $status=&Apache::lonnet::critical( 'put:'.$domain.':'.$user.':critical:'. &Apache::lonnet::escape($msgid).'='. &Apache::lonnet::escape($message),$homeserver); + if ($ENV{'request.course.id'}) { + &user_normal_msg_raw( + $ENV{'course.'.$ENV{'request.course.id'}.'.num'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, + 'Critical ['.$user.':'.$domain.']', + $message); + } } else { $status='no_host'; } +# Notifications + my %userenv = &Apache::lonnet::get('environment',['critnotification'], + $domain,$user); + if ($userenv{'critnotification'}) { + &sendnotification($userenv{'critnotification'},$user,$domain,$subject,1); + } +# Log this &Apache::lonnet::logthis( 'Sending critical email '.$msgid. ', log status: '. @@ -118,53 +327,647 @@ sub user_crit_msg { return $status; } +# New routine that respects "forward" and calls old routine + +=pod + +=item * B: Sends + a critical message $message to the $user at $domain. If $sendback is true, + a reciept will be sent to the current user when $user recieves the message. + +=cut + +sub user_crit_msg { + my ($user,$domain,$subject,$message,$sendback)=@_; + my $status=''; + my %userenv = &Apache::lonnet::get('environment',['msgforward'], + $domain,$user); + my $msgforward=$userenv{'msgforward'}; + if ($msgforward) { + foreach (split(/\,/,$msgforward)) { + my ($forwuser,$forwdomain)=split(/\:/,$_); + $status.= + &user_crit_msg_raw($forwuser,$forwdomain,$subject,$message, + $sendback).' '; + } + } else { + $status=&user_crit_msg_raw($user,$domain,$subject,$message,$sendback); + } + return $status; +} + # =================================================== Critical message received sub user_crit_received { - my $message=shift; - my %contents=&unpackagemsg($message); - my $status='rec: '. + my $msgid=shift; + my %message=&Apache::lonnet::get('critical',[$msgid]); + my %contents=&unpackagemsg($message{$msgid},1); + my $status='rec: '.($contents{'sendback'}? &user_normal_msg($contents{'sendername'},$contents{'senderdomain'}, - 'Receipt: '.$ENV{'user.name'}.' at '.$ENV{'user.domain'}, - 'User '.$ENV{'user.name'}.' at '.$ENV{'user.domain'}. - ' acknowledged receipt of message "'. - $contents{'subject'}.'" dated '.$contents{'time'}.".\n\n" - .'Message ID: '.$contents{'msgid'}); + &mt('Receipt').': '.$ENV{'user.name'}.' at '.$ENV{'user.domain'}, + &mt('User').' '.$ENV{'user.name'}.' '.&mt('at').' '.$ENV{'user.domain'}. + ' acknowledged receipt of message'."\n".' "'. + $contents{'subject'}.'"'."\n".&mt('dated').' '. + $contents{'time'}.".\n" + ):'no msg req'); $status.=' trans: '. - &Apache::lonnet::put('nohist_email',$contents{'msgid'} => $message); + &Apache::lonnet::put( + 'nohist_email',{$contents{'msgid'} => $message{$msgid}}); $status.=' del: '. - &Apache::lonnet::del('critical',$contents{'msgid'}); + &Apache::lonnet::del('critical',[$contents{'msgid'}]); &Apache::lonnet::log($ENV{'user.domain'},$ENV{'user.name'}, $ENV{'user.home'},'Received critical message '. $contents{'msgid'}. ', '.$status); + return $status; } # ======================================================== Normal communication -sub user_normal_msg { - my ($user,$domain,$subject,$message)=@_; +sub user_normal_msg_raw { + my ($user,$domain,$subject,$message,$citation,$baseurl,$attachmenturl)=@_; # Check if allowed missing my $status=''; my $msgid='undefined'; unless (($message)&&($user)&&($domain)) { $status='empty'; }; my $homeserver=&Apache::lonnet::homeserver($user,$domain); if ($homeserver ne 'no_host') { - my $msgid; - ($msgid,$message)=&packagemsg($subject,$message); + ($msgid,$message)=&packagemsg($subject,$message,$citation,$baseurl, + $attachmenturl); $status=&Apache::lonnet::critical( 'put:'.$domain.':'.$user.':nohist_email:'. &Apache::lonnet::escape($msgid).'='. &Apache::lonnet::escape($message),$homeserver); + &Apache::lonnet::put + ('email_status',{'recnewemail'=>time},$domain,$user); } else { $status='no_host'; } +# Notifications + my %userenv = &Apache::lonnet::get('environment',['notification'], + $domain,$user); + if ($userenv{'notification'}) { + &sendnotification($userenv{'notification'},$user,$domain,$subject,0); + } &Apache::lonnet::log($ENV{'user.domain'},$ENV{'user.name'}, $ENV{'user.home'}, 'Sending '.$msgid.' to '.$user.' at '.$domain.' with status: '.$status); return $status; } +# New routine that respects "forward" and calls old routine + +=pod + +=item * B: Sends a message to the + $user at $domain, with subject $subject and message $message. + +=cut + +sub user_normal_msg { + my ($user,$domain,$subject,$message,$citation,$baseurl,$attachmenturl)=@_; + my $status=''; + my %userenv = &Apache::lonnet::get('environment',['msgforward'], + $domain,$user); + my $msgforward=$userenv{'msgforward'}; + if ($msgforward) { + foreach (split(/\,/,$msgforward)) { + my ($forwuser,$forwdomain)=split(/\:/,$_); + $status.= + &user_normal_msg_raw($forwuser,$forwdomain,$subject,$message, + $citation,$baseurl,$attachmenturl).' '; + } + } else { + $status=&user_normal_msg_raw($user,$domain,$subject,$message, + $citation,$baseurl,$attachmenturl); + } + return $status; +} + + +# =============================================================== Status Change + +sub statuschange { + my ($msgid,$newstatus)=@_; + my %status=&Apache::lonnet::get('email_status',[$msgid]); + if ($status{$msgid}=~/^error\:/) { $status{$msgid}=''; } + unless ($status{$msgid}) { $status{$msgid}='new'; } + unless (($status{$msgid} eq 'replied') || + ($status{$msgid} eq 'forwarded')) { + &Apache::lonnet::put('email_status',{$msgid => $newstatus}); + } + if (($newstatus eq 'deleted') || ($newstatus eq 'new')) { + &Apache::lonnet::put('email_status',{$msgid => $newstatus}); + } +} + +# ======================================================= Display a course list + +sub discourse { + my $r=shift; + my %courselist=&Apache::lonnet::dump( + 'classlist', + $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); + my $now=time; + my %lt=&Apache::lonlocal::texthash('cfa' => 'Check for All', + 'cfs' => 'Check for Section/Group', + 'cfn' => 'Check for None'); + $r->print(< + +  + +  + +

+ENDDISHEADER + my %coursepersonnel= + &Apache::lonnet::get_course_adv_roles(); + foreach my $role (sort keys %coursepersonnel) { + foreach (split(/\,/,$coursepersonnel{$role})) { + my ($puname,$pudom)=split(/\:/,$_); + $r->print( + '
'. + &Apache::loncommon::plainname($puname, + $pudom).' ('.$_.'), '.$role.''); + } + } + + foreach (sort keys %courselist) { + my ($end,$start)=split(/\:/,$courselist{$_}); + my $active=1; + if (($end) && ($now>$end)) { $active=0; } + if ($active) { + my ($sname,$sdom)=split(/\:/,$_); + my %reply=&Apache::lonnet::get('environment', + ['firstname','middlename','lastname','generation'], + $sdom,$sname); + my $section=&Apache::lonnet::usection + ($sdom,$sname,$ENV{'request.course.id'}); + $r->print( + '
'. + $reply{'firstname'}.' '. + $reply{'middlename'}.' '. + $reply{'lastname'}.' '. + $reply{'generation'}. + ' ('.$_.') '.$section); + } + } +} + +# ==================================================== Display Critical Message + +sub discrit { + my $r=shift; + my $header = '

'.&mt('Critical Messages').'

'. + '
'. + ''; + my %what=&Apache::lonnet::dump('critical'); + my $result = ''; + foreach (sort keys %what) { + my %content=&unpackagemsg($what{$_}); + next if ($content{'senderdomain'} eq ''); + $content{'message'}=~s/\n/\/g; + $result.='
'.&mt('From').': '. +&Apache::loncommon::aboutmewrapper( + &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).' ('. +$content{'sendername'}.'@'. + $content{'senderdomain'}.') '.$content{'time'}. + '
'.&mt('Subject').': '.$content{'subject'}. + '
'. + &Apache::lontexconvert::msgtexconverted($content{'message'}). + '
'. + ''. + ''; + } + # Check to see if there were any messages. + if ($result eq '') { + $result = "

".&mt('You have no critical messages.')."

". + ''.&mt('Select a course').''; + } else { + $r->print($header); + } + $r->print($result); + $r->print(''); +} + +# =============================================================== Compose reply + +sub comprep { + my ($r,$msgid)=@_; + my %message=&Apache::lonnet::get('nohist_email',[$msgid]); + my %content=&unpackagemsg($message{$msgid},1); + my $quotemsg='> '.$content{'message'}; + $quotemsg=~s/\r/\n/g; + $quotemsg=~s/\f/\n/g; + $quotemsg=~s/\n+/\n\> /g; + my $torepl=&Apache::loncommon::aboutmewrapper( + &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).' ('. +$content{'sendername'}.'@'. + $content{'senderdomain'}.')'; + my $subject=&mt('Re').': '.$content{'subject'}; + my $dispcrit=''; + if (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) { + my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message"); + $dispcrit= + ' '.&mt('Send as critical message').' ' . $crithelp . + '
'. + ' '.&mt('Send as critical message').' ' . + &mt('and return receipt') . $crithelp . '

'; + } + my %lt=&Apache::lonlocal::texthash( + 'to' => 'To', + 'sb' => 'Subject', + 'sr' => 'Send Reply', + 'ca' => 'Cancel' + ); + $r->print(<<"ENDREPLY"); +

+ +$lt{'to'}: $torepl
+$lt{'sb'}:

+


+$dispcrit + + +
+ENDREPLY +} + +sub sortedmessages { + my @messages = &Apache::lonnet::getkeys('nohist_email'); + #unpack the varibles and repack into temp for sorting + my @temp; + foreach (@messages) { + my $msgid=&Apache::lonnet::escape($_); + my ($sendtime,$shortsubj,$fromname,$fromdomain,$status)= + &Apache::lonmsg::unpackmsgid($msgid); + my @temp1 = ($sendtime,$shortsubj,$fromname,$fromdomain,$status, + $msgid); + push @temp ,\@temp1; + } + #default sort + @temp = sort {$a->[0] <=> $b->[0]} @temp; + if ($ENV{'form.sortedby'} eq "date"){ + @temp = sort {$a->[0] <=> $b->[0]} @temp; + } + if ($ENV{'form.sortedby'} eq "revdate"){ + @temp = sort {$b->[0] <=> $a->[0]} @temp; + } + if ($ENV{'form.sortedby'} eq "user"){ + @temp = sort {lc($a->[2]) cmp lc($b->[2])} @temp; + } + if ($ENV{'form.sortedby'} eq "revuser"){ + @temp = sort {lc($b->[2]) cmp lc($a->[2])} @temp; + } + if ($ENV{'form.sortedby'} eq "domain"){ + @temp = sort {$a->[3] cmp $b->[3]} @temp; + } + if ($ENV{'form.sortedby'} eq "revdomain"){ + @temp = sort {$b->[3] cmp $a->[3]} @temp; + } + if ($ENV{'form.sortedby'} eq "subject"){ + @temp = sort {lc($a->[1]) cmp lc($b->[1])} @temp; + } + if ($ENV{'form.sortedby'} eq "revsubject"){ + @temp = sort {lc($b->[1]) cmp lc($a->[1])} @temp; + } + if ($ENV{'form.sortedby'} eq "status"){ + @temp = sort {$a->[4] cmp $b->[4]} @temp; + } + if ($ENV{'form.sortedby'} eq "revstatus"){ + @temp = sort {$b->[4] cmp $a->[4]} @temp; + } + return @temp; +} + +# ======================================================== Display all messages + +sub disall { + my $r=shift; + $r->print(< + function checkall() { + for (i=0; i +ENDDISHEADER + $r->print('

'.&mt('Display All Messages').'

'. + ''); + } else { + $r->print(''.&mt('Date').''); + } + $r->print(''); + } else { + $r->print(''.&mt('Status').''); + } + $r->print(''); + my @temp=sortedmessages(); + foreach (@temp){ + my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$origID)= @$_; + if (($status ne 'deleted') && defined($sendtime) && $sendtime!~/error/) { + if ($status eq 'new') { + $r->print(''); + } elsif ($status eq 'read') { + $r->print(''); + } elsif ($status eq 'replied') { + $r->print(''); + } else { + $r->print(''); + } + $r->print(''. + ''); + } + } + $r->print('
 '); + if ($ENV{'form.sortedby'} eq "revdate") { + $r->print(''.&mt('Date').''); + if ($ENV{'form.sortedby'} eq "revuser") { + $r->print(''.&mt('Username').''); + } else { + $r->print(''.&mt('Username').''); + } + $r->print(''); + if ($ENV{'form.sortedby'} eq "revdomain") { + $r->print(''.&mt('Domain').''); + } else { + $r->print(''.&mt('Domain').''); + } + $r->print(''); + if ($ENV{'form.sortedby'} eq "revsubject") { + $r->print(''.&mt('Subject').''); + } else { + $r->print(''.&mt('Subject').''); + } + $r->print(''); + if ($ENV{'form.sortedby'} eq "revstatus") { + $r->print(''.&mt('Status').'
'.&mt('Open').''.&mt('Delete').''.&Apache::lonlocal::locallocaltime($sendtime).''. + $fromname.''.$fromdomain.''. + &Apache::lonnet::unescape($shortsubj).''. + $status.'

'. + ''.&mt('Check All').' '. + ''.&mt('Uncheck All').'

'. + ''. + ''. + '

'); +} + +# ============================================================== Compose output + +sub compout { + my ($r,$forwarding,$broadcast)=@_; + my $dispcrit=''; + my $dissub=''; + my $dismsg=''; + my $func=&mt('Send New'); + my %lt=&Apache::lonlocal::texthash('us' => 'Username', + 'do' => 'Domain', + 'ad' => 'Additional Recipients', + 'sb' => 'Subject', + 'ca' => 'Cancel', + 'ma' => 'Mail'); + + if (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) { + my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message"); + $dispcrit= + ' '.&mt('Send as critical message').' ' . $crithelp . + '
'. + ' '.&mt('Send as critical message').' ' . + &mt('and return receipt') . $crithelp . '

'; + } + if ($forwarding) { + $dispcrit.=''; + $func=&mt('Forward'); + my %message=&Apache::lonnet::get('nohist_email',[$forwarding]); + my %content=&unpackagemsg($message{$forwarding}); + + $dissub=&mt('Forwarding').': '.$content{'subject'}; + $dismsg=&mt('Forwarded message from').' '. + $content{'sendername'}.' '.&mt('at').' '.$content{'senderdomain'}; + } + my $defdom=$ENV{'user.domain'}; + if ($ENV{'form.recdom'}) { $defdom=$ENV{'form.recdom'}; } + $r->print( + '

'."\n". + ''."\n". + ''); + unless (($broadcast eq 'group') || ($broadcast eq 'upload')) { + my $domform = &Apache::loncommon::select_dom_form($defdom,'recdomain'); + my $selectlink=&Apache::loncommon::selectstudent_link + ('compemail','recuname','recdomain'); + $r->print(<<"ENDREC"); +
+ + + +ENDREC + } + my $latexHelp = Apache::loncommon::helpLatexCheatsheet(); + if ($broadcast ne 'upload') { + $r->print(<<"ENDCOMP"); + +
$lt{'us'}:$selectlink
$lt{'do'}:$domform
$lt{'ad'}
username\@domain,username\@domain, ... +
+
$lt{'sb'}: +
+$latexHelp +


+$dispcrit + + +ENDCOMP + } else { # $broadcast is 'upload' + $r->print(< +

Generate messages from a file

+

+Subject: +

+

General message text
+

+

+The file format for the uploaded portion of the message is: +

+username1\@domain1: text
+username2\@domain2: text
+username3\@domain1: text
+
+

+

+The messages will be assembled from all lines with the respective +username\@domain, and appended to the general message text.

+

+

+$dispcrit + +ENDUPLOAD + } + if ($broadcast eq 'group') { + &discourse; + } + $r->print('

'); +} + +# ---------------------------------------------------- Display all face to face + +sub disfacetoface { + my ($r,$user,$domain)=@_; + unless ($ENV{'request.course.id'}) { return; } + unless (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) { + return; + } + my %records=&Apache::lonnet::dump('nohist_email', + $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.num'}, + '%255b'.$user.'%253a'.$domain.'%255d'); + my $result=''; + foreach (sort keys %records) { + my %content=&unpackagemsg($records{$_}); + next if ($content{'senderdomain'} eq ''); + $content{'message'}=~s/\n/\/g; + if ($content{'subject'}=~/^Record/) { + $result.='

'.&mt('Record').'

'; + } else { + $result.='

'.&mt('Sent Message').'

'; + %content=&unpackagemsg($content{'message'}); + $content{'message'}= + 'Subject: '.$content{'subject'}.'
'. + $content{'message'}; + } + $result.=&mt('By').': '. +&Apache::loncommon::aboutmewrapper( + &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).' ('. +$content{'sendername'}.'@'. + $content{'senderdomain'}.') '.$content{'time'}. + '
'. + &Apache::lontexconvert::msgtexconverted($content{'message'}). + '
'; + } + # Check to see if there were any messages. + if ($result eq '') { + $r->print("

No notes, face-to-face discussion records, or critical messages in this course.

"); + } else { + $r->print($result); + } +} + +# ---------------------------------------------------------------- Face to face + +sub facetoface { + my ($r,$stage)=@_; + unless (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) { + return; + } +# from query string + if ($ENV{'form.recname'}) { $ENV{'form.recuname'}=$ENV{'form.recname'}; } + if ($ENV{'form.recdom'}) { $ENV{'form.recdomain'}=$ENV{'form.recdom'}; } + + my $defdom=$ENV{'user.domain'}; +# already filled in + if ($ENV{'form.recdomain'}) { $defdom=$ENV{'form.recdomain'}; } +# generate output + my $domform = &Apache::loncommon::select_dom_form($defdom,'recdomain'); + my $stdbrws = &Apache::loncommon::selectstudent_link + ('stdselect','recuname','recdomain'); + $r->print(<<"ENDTREC"); +

User Notes, Records of Face-To-Face Discussions, and Critical Messages in Course

+
+ + + + + + + +
Username: +$stdbrws +
Domain:$domform
+
+ENDTREC + if (($stage ne 'query') && + ($ENV{'form.recdomain'}) && ($ENV{'form.recuname'})) { + chomp($ENV{'form.newrecord'}); + if ($ENV{'form.newrecord'}) { + &user_normal_msg_raw( + $ENV{'course.'.$ENV{'request.course.id'}.'.num'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, + 'Record ['.$ENV{'form.recuname'}.':'.$ENV{'form.recdomain'}.']', + $ENV{'form.newrecord'}); + } + $r->print('

'.&Apache::loncommon::plainname($ENV{'form.recuname'}, + $ENV{'form.recdomain'}).'

'); + &disfacetoface($r,$ENV{'form.recuname'},$ENV{'form.recdomain'}); + $r->print(< + + +ENDRHEAD + $r->print(<New Record (record is visible to course faculty and staff)
+ +
+ + + +ENDBFORM + } +} + # ===================================================================== Handler sub handler { @@ -172,27 +975,231 @@ sub handler { # ----------------------------------------------------------- Set document type - $r->content_type('text/html'); + &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; return OK if $r->header_only; +# --------------------------- Get query string for limited number of parameters + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['display','replyto','forward','markread','markdel','markunread', + 'sendreply','compose','sendmail','critical','recname','recdom', + 'recordftf','sortedby']); + $sqs='&sortedby='.$ENV{'form.sortedby'}; +# ------------------------------------------------------ They checked for email + &Apache::lonnet::put('email_status',{'recnewemail'=>0}); # --------------------------------------------------------------- Render Output - - $r->print('EMail and Messaging'); - $r->print(''); - $r->print('

EMail

'); + if (!$ENV{'form.display'}) { + $r->print('EMail and Messaging'. + &Apache::loncommon::studentbrowser_javascript().''. + &Apache::loncommon::bodytag('EMail and Messages')); + } + if ($ENV{'form.display'}) { + my $msgid=$ENV{'form.display'}; + &statuschange($msgid,'read'); + my %message=&Apache::lonnet::get('nohist_email',[$msgid]); + my %content=&unpackagemsg($message{$msgid}); +# info to generate "next" and "previous" buttons + my @messages=&sortedmessages(); + my $counter=0; + $r->print('
');
+      my $escmsgid=&Apache::lonnet::escape($msgid);
+      foreach (@messages) {
+ 	  if ($_->[5] eq $escmsgid){
+ 	      last;
+ 	  }
+ 	  $counter++;
+      }
+      $r->print('
'); + my $number_of_messages = scalar(@messages); #subtract 1 for last index +# start output + $r->print('EMail and Messaging'); + if (defined($content{'baseurl'})) { + $r->print(""); + } + $r->print(&Apache::loncommon::studentbrowser_javascript(). + ''. + &Apache::loncommon::bodytag('EMail and Messages')); + $r->print(''.&mt('Subject').': '.$content{'subject'}. + '
'.&mt('From').': '. +&Apache::loncommon::aboutmewrapper( +&Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}), +$content{'sendername'},$content{'senderdomain'}).' ('. + $content{'sendername'}.' at '. + $content{'senderdomain'}.') '. + '
'.&mt('Time').': '.$content{'time'}.'

'. + ''. + ''. + ''. + ''. + ''. + ''); + if ($counter > 0){ + $r->print(''); + } + if ($counter < $number_of_messages - 1){ + $r->print(''); + } + $r->print('
'.&mt('Functions').':'.&mt('Reply').''.&mt('Forward').''.&mt('Mark Unread').'Delete'.&mt('Display all Messages').''.&mt('Previous').''.&mt('Next').'

'.
+             &Apache::lontexconvert::msgtexconverted($content{'message'}).
+             '

'.$content{'citation'}); + } elsif ($ENV{'form.replyto'}) { + &comprep($r,$ENV{'form.replyto'}); + } elsif ($ENV{'form.sendreply'}) { + if ($ENV{'form.send'}) { + my $msgid=$ENV{'form.sendreply'}; + my %message=&Apache::lonnet::get('nohist_email',[$msgid]); + my %content=&unpackagemsg($message{$msgid},1); + &statuschange($msgid,'replied'); + if ((($ENV{'form.critmsg'}) || ($ENV{'form.sendbck'})) && + (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'}))) { + $r->print(&mt('Sending critical').': '. + &user_crit_msg($content{'sendername'}, + $content{'senderdomain'}, + &Apache::lonfeedback::clear_out_html($ENV{'form.subject'}), + &Apache::lonfeedback::clear_out_html($ENV{'form.message'}), + $ENV{'form.sendbck'})); + } else { + $r->print(&mt('Sending').': '.&user_normal_msg($content{'sendername'}, + $content{'senderdomain'}, + &Apache::lonfeedback::clear_out_html($ENV{'form.subject'}), + &Apache::lonfeedback::clear_out_html($ENV{'form.message'}))); + } + } + if ($ENV{'form.displayedcrit'}) { + &discrit($r); + } else { + &disall($r); + } + } elsif ($ENV{'form.confirm'}) { + foreach (keys %ENV) { + if ($_=~/^form\.rec\_(.*)$/) { + $r->print('Confirming Receipt: '. + &user_crit_received($1).'
'); + } + if ($_=~/^form\.reprec\_(.*)$/) { + my $msgid=$1; + $r->print('Confirming Receipt: '. + &user_crit_received($msgid).'
'); + &comprep($r,$msgid); + } + } + &discrit($r); + } elsif ($ENV{'form.critical'}) { + &discrit($r); + } elsif ($ENV{'form.forward'}) { + &compout($r,$ENV{'form.forward'}); + } elsif ($ENV{'form.markread'}) { + } elsif ($ENV{'form.markdel'}) { + &statuschange($ENV{'form.markdel'},'deleted'); + &disall($r); + } elsif ($ENV{'form.markeddel'}) { + my $total=0; + foreach (keys %ENV) { + if ($_=~/^form\.delmark_(.*)$/) { + &statuschange(&Apache::lonnet::unescape($1),'deleted'); + $total++; + } + } + $r->print('Deleted '.$total.' message(s)

'); + &disall($r); + } elsif ($ENV{'form.markunread'}) { + &statuschange($ENV{'form.markunread'},'new'); + &disall($r); + } elsif ($ENV{'form.compose'}) { + &compout($r,'',$ENV{'form.compose'}); + } elsif ($ENV{'form.recordftf'}) { + &facetoface($r,$ENV{'form.recordftf'}); + } elsif ($ENV{'form.sendmail'}) { + if ($ENV{'form.send'}) { + my %content=(); + undef %content; + if ($ENV{'form.forwid'}) { + my $msgid=$ENV{'form.forwid'}; + my %message=&Apache::lonnet::get('nohist_email',[$msgid]); + %content=&unpackagemsg($message{$msgid},1); + &statuschange($msgid,'forwarded'); + $ENV{'form.message'}.="\n\n-- Forwarded message --\n\n". + $content{'message'}; + } + my %toaddr=(); + undef %toaddr; + if ($ENV{'form.sendmode'} eq 'group') { + foreach (keys %ENV) { + if ($_=~/^form\.send\_to\_\&\&\&[^\&]*\&\&\&\_(.+)$/) { + $toaddr{$1}=''; + } + } + } elsif ($ENV{'form.sendmode'} eq 'upload') { + foreach (split(/[\n\r\f]+/,$ENV{'form.upfile'})) { + my ($rec,$txt)=split(/\s*\:\s*/,$_); + if ($txt) { + $rec=~s/\@/\:/; + $toaddr{$rec}.=$txt."\n"; + } + } + } else { + $toaddr{$ENV{'form.recuname'}.':'.$ENV{'form.recdomain'}}=''; + } + if ($ENV{'form.additionalrec'}) { + foreach (split(/\,/,$ENV{'form.additionalrec'})) { + my ($auname,$audom)=split(/\@/,$_); + $toaddr{$auname.':'.$audom}=''; + } + } + foreach (keys %toaddr) { + my ($recuname,$recdomain)=split(/\:/,$_); + my $msgtxt=&Apache::lonfeedback::clear_out_html($ENV{'form.message'}); + if ($toaddr{$_}) { $msgtxt.='


'.$toaddr{$_}; } + if ((($ENV{'form.critmsg'}) || ($ENV{'form.sendbck'})) && + (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'}))) { + $r->print('Sending critical: '. + &user_crit_msg($recuname,$recdomain, + &Apache::lonfeedback::clear_out_html($ENV{'form.subject'}), + $msgtxt, + $ENV{'form.sendbck'})); + } else { + $r->print('Sending: '.&user_normal_msg($recuname,$recdomain, + &Apache::lonfeedback::clear_out_html($ENV{'form.subject'}), + $msgtxt, + $content{'citation'})); + } + $r->print('
'); + } + } + if ($ENV{'form.displayedcrit'}) { + &discrit($r); + } else { + &disall($r); + } + } else { + &disall($r); + } $r->print(''); return OK; } # ================================================= Main program, reset counter -sub BEGIN { +BEGIN { $msgcount=0; } -1; +=pod + +=back + +=cut + +1; + __END__