--- loncom/interface/lonmsg.pm 2007/02/09 15:30:48 1.196 +++ loncom/interface/lonmsg.pm 2007/05/01 18:40:57 1.201 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Routines for messaging # -# $Id: lonmsg.pm,v 1.196 2007/02/09 15:30:48 www Exp $ +# $Id: lonmsg.pm,v 1.201 2007/05/01 18:40:57 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -28,6 +28,37 @@ package Apache::lonmsg; +=pod + +=head1 NAME + +Apache::lonmsg: supports internal messaging + +=head1 SYNOPSIS + +lonmsg provides routines for sending messages. + +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; use Apache::lonnet; use HTML::TokeParser(); @@ -57,23 +88,7 @@ sub packagemsg { #remove machine specification $attachmenturl =~ s|^http://[^/]+/|/|; $attachmenturl =&HTML::Entities::encode($attachmenturl,'<>&"'); - my $course_context; - if (defined($env{'form.replyid'})) { - my ($sendtime,$shortsubj,$fromname,$fromdomain,$count,$origcid)= - split(/\:/,&unescape($env{'form.replyid'})); - $course_context = $origcid; - } - foreach my $key (keys(%env)) { - if ($key=~/^form\.(rep)?rec\_(.*)$/) { - my ($sendtime,$shortsubj,$fromname,$fromdomain,$count,$origcid) = - split(/\:/,&unescape($2)); - $course_context = $origcid; - last; - } - } - unless(defined($course_context)) { - $course_context = $env{'request.course.id'}; - } + my $course_context = &get_course_context(); my $now=time; my $msgcount = &get_uniq(); unless(defined($msgid)) { @@ -136,7 +151,7 @@ sub packagemsg { } if (defined($symb)) { $result.= ''.$symb.''; - if (defined($course_context)) { + if ($course_context ne '') { if ($course_context eq $env{'request.course.id'}) { my $resource_title = &Apache::lonnet::gettitle($symb); if (defined($resource_title)) { @@ -148,6 +163,27 @@ sub packagemsg { return ($msgid,$result); } +sub get_course_context { + my $course_context; + if (defined($env{'form.replyid'})) { + my ($sendtime,$shortsubj,$fromname,$fromdomain,$count,$origcid)= + split(/\:/,&unescape($env{'form.replyid'})); + $course_context = $origcid; + } + foreach my $key (keys(%env)) { + if ($key=~/^form\.(rep)?rec\_(.*)$/) { + my ($sendtime,$shortsubj,$fromname,$fromdomain,$count,$origcid) = + split(/\:/,&unescape($2)); + $course_context = $origcid; + last; + } + } + if ($course_context eq '') { + $course_context = $env{'request.course.id'}; + } + return $course_context; +} + # ================================================== Unpack message into a hash sub unpackagemsg { @@ -256,7 +292,7 @@ sub sendnotification { $text=~s/\>\;/\>/gs; $text=~s/\<\/*[^\>]+\>//gs; my $url='http://'. - $Apache::lonnet::hostname{&Apache::lonnet::homeserver($touname,$toudom)}. + &Apache::lonnet::hostname(&Apache::lonnet::homeserver($touname,$toudom)). '/adm/email?username='.$touname.'&domain='.$toudom; my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid, $symb,$error) = &Apache::lonmsg::unpackmsgid($msgid); @@ -399,13 +435,17 @@ sub store_instructor_comment { my $cdom = $env{'course.'.$cid.'.domain'}; my $subject= &mt('Record').' ['.$uname.':'.$udom.']'; my $result = &user_normal_msg_raw($cnum,$cdom,$subject,$msg); + if ($result eq 'ok' || $result eq 'con_delayed') { + + } return $result; } # ================================================== Critical message to a user sub user_crit_msg_raw { - my ($user,$domain,$subject,$message,$sendback,$toperm,$sentmessage)=@_; + my ($user,$domain,$subject,$message,$sendback,$toperm,$sentmessage, + $nosentstore)=@_; # Check if allowed missing my ($status,$packed_message); my $msgid='undefined'; @@ -422,7 +462,7 @@ sub user_crit_msg_raw { if (defined($sentmessage)) { $$sentmessage = $packed_message; } - if ($env{'request.course.id'} eq '') { + if (!$nosentstore) { (undef,my $packed_message_no_citation) = &packagemsg($subject,$message,undef,undef,undef,$user,$domain, $msgid); @@ -459,9 +499,10 @@ sub user_crit_msg_raw { =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. +=item * B: + Sends a critical message $message to the $user at $domain. If $sendback + is true, a receipt will be sent to the current user when $user receives + the message. Additionally it will check if the user has a Forwarding address set, and send the message to that address instead @@ -474,7 +515,8 @@ sub user_crit_msg_raw { =cut sub user_crit_msg { - my ($user,$domain,$subject,$message,$sendback,$toperm,$sentmessage)=@_; + my ($user,$domain,$subject,$message,$sendback,$toperm,$sentmessage, + $nosentstore)=@_; my @status; my %userenv = &Apache::lonnet::get('environment',['msgforward'], $domain,$user); @@ -484,12 +526,12 @@ sub user_crit_msg { my ($forwuser,$forwdomain)=split(/\:/,$addr); push(@status, &user_crit_msg_raw($forwuser,$forwdomain,$subject,$message, - $sendback,$toperm,$sentmessage)); + $sendback,$toperm,$sentmessage,$nosentstore)); } } else { push(@status, &user_crit_msg_raw($user,$domain,$subject,$message,$sendback, - $toperm,$sentmessage)); + $toperm,$sentmessage,$nosentstore)); } if (wantarray) { return @status; @@ -528,7 +570,7 @@ sub user_crit_received { sub user_normal_msg_raw { my ($user,$domain,$subject,$message,$citation,$baseurl,$attachmenturl, $toperm,$currid,$newid,$sentmessage,$crsmsgid,$symb,$restitle, - $error)=@_; + $error,$nosentstore)=@_; # Check if allowed missing my ($status,$packed_message); my $msgid='undefined'; @@ -549,13 +591,8 @@ sub user_normal_msg_raw { # Save new message received time &Apache::lonnet::put ('email_status',{'recnewemail'=>time},$domain,$user); -# Into sent-mail folder unless a broadcast message or critical message - unless (($env{'request.course.id'}) && - (($env{'form.sendmode'} eq 'group') || - (($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'})))) { +# Into sent-mail folder if sent mail storage required + if (!$nosentstore) { (undef,my $packed_message_no_citation) = &packagemsg($subject,$message,undef,$baseurl,$attachmenturl, $user,$domain,$currid,undef,$crsmsgid,$symb,$error); @@ -563,10 +600,10 @@ sub user_normal_msg_raw { &store_sent_mail($msgid,$packed_message_no_citation); } } - if (defined($newid)) { + if (ref($newid) eq 'SCALAR') { $$newid = $msgid; } - if (defined($sentmessage)) { + if (ref($sentmessage) eq 'SCALAR') { $$sentmessage = $packed_message; } # Notifications @@ -595,41 +632,79 @@ sub user_normal_msg_raw { =pod =item * B: + $baseurl, $attachmenturl, $toperm, $sentmessage, $symb, $restitle, + $error,$nosentstore)>: Sends a message to the $user at $domain, with subject $subject and message $message. + Additionally it will check if the user has a Forwarding address + set, and send the message to that address instead + + returns + - in array context a list of results for each message that was sent + - in scalar context a space seperated list of results for each + message sent + =cut sub user_normal_msg { my ($user,$domain,$subject,$message,$citation,$baseurl,$attachmenturl, - $toperm,$sentmessage,$symb,$restitle,$error)=@_; - my $status=''; + $toperm,$sentmessage,$symb,$restitle,$error,$nosentstore)=@_; + 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.= + push(@status, &user_normal_msg_raw($forwuser,$forwdomain,$subject,$message, $citation,$baseurl,$attachmenturl,$toperm, - undef,undef,$sentmessage,undef,$symb,$restitle,$error).' '; + undef,undef,$sentmessage,undef,$symb, + $restitle,$error,$nosentstore)); } } else { - $status=&user_normal_msg_raw($user,$domain,$subject,$message, + push(@status,&user_normal_msg_raw($user,$domain,$subject,$message, $citation,$baseurl,$attachmenturl,$toperm, - undef,undef,$sentmessage,undef,$symb,$restitle,$error); + undef,undef,$sentmessage,undef,$symb, + $restitle,$error,$nosentstore)); + } + if (wantarray) { + return @status; } + return join(' ',@status); +} + +sub process_sent_mail { + my ($msgsubj,$subj_prefix,$numsent,$stamp,$msgname,$msgdom,$msgcount,$context,$pid,$savemsg,$recusers,$recudoms,$baseurl,$attachmenturl,$symb,$error,$senderuname,$senderdom,$senderhome) = @_; + my $sentsubj; + if ($numsent > 1) { + $sentsubj = $subj_prefix.' ('.$numsent.' sent) '.$msgsubj; + } + $sentsubj = &HTML::Entities::encode($sentsubj,'<>&"'); + my $sentmsgid = + &buildmsgid($stamp,$sentsubj,$msgname,$msgdom,$msgcount,$context,$pid); + (undef,my $sentmessage) = + &packagemsg($msgsubj,$savemsg,undef,$baseurl,$attachmenturl,$recusers, + $recudoms,$sentmsgid,undef,undef,$symb,$error); + my $status = &store_sent_mail($sentmsgid,$sentmessage,$senderuname, + $senderdom,$senderhome); return $status; } sub store_sent_mail { - my ($msgid,$message) = @_; + my ($msgid,$message,$senderuname,$senderdom,$senderhome) = @_; + if ($senderuname eq '') { + $senderuname = $env{'user.name'}; + } + if ($senderdom eq '') { + $senderdom = $env{'user.domain'}; + } + if ($senderhome eq '') { + $senderhome = $env{'user.home'}; + } my $status =' '.&Apache::lonnet::critical( - 'put:'.$env{'user.domain'}.':'.$env{'user.name'}. - ':nohist_email_sent:'. - &escape($msgid).'='. - &escape($message),$env{'user.home'}); + 'put:'.$senderdom.':'.$senderuname.':nohist_email_sent:'. + &escape($msgid).'='.&escape($message),$senderhome); return $status; } @@ -665,6 +740,102 @@ sub get_user_folders { return %userfolders; } +sub secapply { + my $rec=shift; + my $defaultflag=shift; + $rec=~s/\s+//g; + $rec=~s/\@/\:/g; + my ($adr,$sections_or_groups)=($rec=~/^([^\(]+)\(([^\)]+)\)/); + if ($sections_or_groups) { + foreach my $item (split(/\;/,$sections_or_groups)) { + if (($item eq $env{'request.course.sec'}) || + ($defaultflag && ($item eq '*'))) { + return $adr; + } elsif ($env{'request.course.groups'}) { + my @usersgroups = split(/:/,$env{'request.course.groups'}); + if (grep(/^\Q$item\E$/,@usersgroups)) { + return $adr; + } + } + } + } else { + return $rec; + } + return ''; +} + +=pod + +=item * B: + +Arguments + $feedurl - /res/ url of resource (only need if $author is true) + $author,$question,$course,$policy - all true/false parameters + if true will attempt to find the addresses of user that should receive + this type of feedback (author - feedback to author of resource $feedurl, + $question 'Resource Content Questions', $course 'Course Content Question', + $policy 'Course Policy') + (Additionally it also checks $env for whether the corresponding form. + element exists, for ease of use in a html response context) + + $defaultflag - (internal should be left blank) if true gather addresses + that aren't for a section even if I have a section + (used for reccursion internally, first we look for + addresses for our specific section then we recurse + and look for non section addresses) + +Returns + $typestyle - string of html text, describing what addresses were found + %to - a hash, which keys are addresses of users to send messages to + the keys will look like name:domain + +=cut + +sub decide_receiver { + my ($feedurl,$author,$question,$course,$policy,$defaultflag) = @_; + &Apache::lonenc::check_decrypt(\$feedurl); + my $typestyle=''; + my %to=(); + if ($env{'form.discuss'} eq 'author' ||$author) { + $typestyle.='Submitting as Author Feedback
'; + $feedurl=~ m{^/res/($LONCAPA::domain_re)/($LONCAPA::username_re)/}; + $to{$2.':'.$1}=1; + } + my $cid = $env{'request.course.id'}; + if ($env{'form.discuss'} eq 'question' ||$question) { + $typestyle.=&mt('Submitting as Question').'
'; + foreach my $item (split(/\,/,$env{'course.'.$cid.'.question.email'})) { + my $rec=&secapply($item,$defaultflag); + if ($rec) { $to{$rec}=1; } + } + } + if ($env{'form.discuss'} eq 'course' ||$course) { + $typestyle.=&mt('Submitting as Comment').'
'; + foreach my $item (split(/\,/,$env{'course.'.$cid.'.comment.email'})) { + my $rec=&secapply($item,$defaultflag); + if ($rec) { $to{$rec}=1; } + } + } + if ($env{'form.discuss'} eq 'policy' ||$policy) { + $typestyle.=&mt('Submitting as Policy Feedback').'
'; + foreach my $item (split(/\,/,$env{'course.'.$cid.'.policy.email'})) { + my $rec=&secapply($item,$defaultflag); + if ($rec) { $to{$rec}=1; } + } + } + if ((scalar(%to) eq '0') && (!$defaultflag)) { + ($typestyle,%to)= + &decide_receiver($feedurl,$author,$question,$course,$policy,1); + } + return ($typestyle,%to); +} + +=pod + +=back + +=cut + 1; __END__