--- loncom/interface/lonmsg.pm 2000/10/19 14:20:17 1.1 +++ loncom/interface/lonmsg.pm 2001/11/05 21:01:54 1.25 @@ -10,26 +10,43 @@ # # 10/05 Gerd Kortemeyer) # -# 10/19 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 package Apache::lonmsg; use strict; use Apache::lonnet(); - +use vars qw($msgcount); +use HTML::TokeParser; +use Apache::Constants qw(:common); # ===================================================================== Package -sub package { - var ($subject,$message)=@_; +sub packagemsg { + my ($subject,$message,$citation)=@_; $message=~s/\/\>\;/g; + $citation=~s/\/\>\;/g; $subject=~s/\/\>\;/g; - return ''.$ENV{'user.name'}.''. + my $now=time; + $msgcount++; + my $partsubj=$subject; + $partsubj=&Apache::lonnet::escape($partsubj); + $partsubj=substr($partsubj,0,50); + my $msgid=&Apache::lonnet::escape( + $now.':'.$partsubj.':'.$ENV{'user.name'}.':'. + $ENV{'user.domain'}.':'.$msgcount.':'.$$); + return $msgid, + ''.$ENV{'user.name'}.''. ''.$ENV{'user.domain'}.''. ''.$subject.''. - ''. + ''. ''.$ENV{'SERVER_NAME'}.''. ''.$ENV{'HTTP_HOST'}.''. ''.$ENV{'REMOTE_ADDR'}.''. @@ -41,26 +58,577 @@ sub package { ''.$ENV{'request.course.id'}.''. ''.$ENV{'request.role'}.''. ''.$ENV{'request.filename'}.''. - ''.$message.''; + ''.$msgid.''. + ''.$message.''. + ''.$citation.''; +} + +# ================================================== Unpack message into a hash + +sub unpackagemsg { + my $message=shift; + my %content=(); + my $parser=HTML::TokeParser->new(\$message); + my $token; + while ($token=$parser->get_token) { + if ($token->[0] eq 'S') { + my $entry=$token->[1]; + my $value=$parser->get_text('/'.$entry); + $content{$entry}=$value; + } + } + 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}); +} + # =============================== Automated message to the author of a resource sub author_res_msg { my ($filename,$message)=@_; + unless ($message) { return 'empty'; } $filename=&Apache::lonnet::declutter($filename); my ($domain,$author,@dummy)=split(/\//,$filename); my $homeserver=&Apache::lonnet::homeserver($author,$domain); if ($homeserver ne 'no_host') { my $id=unpack("%32C*",$message); - &Apache::lonnet::put('res_msgs',$filename.'_'.$id => package($message)); + my $msgid; + ($msgid,$message)=&packagemsg($filename,$message); + return &Apache::lonnet::reply('put:'.$domain.':'.$author. + ':nohist_res_msgs:'. + &Apache::lonnet::escape($filename.'_'.$id).'='. + &Apache::lonnet::escape($message),$homeserver); } + return 'no_host'; } # ================================================== Critical message to a user sub user_crit_msg { - my ($user,$domain,$subject,$message)=@_; + 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') { + ($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); + } else { + $status='no_host'; + } + &Apache::lonnet::logthis( + 'Sending critical email '.$msgid. + ', log status: '. + &Apache::lonnet::log($ENV{'user.domain'},$ENV{'user.name'}, + $ENV{'user.home'}, + 'Sending critical '.$msgid.' to '.$user.' at '.$domain.' with status: ' + .$status)); + return $status; +} + +# =================================================== Critical message received + +sub user_crit_received { + my $msgid=shift; + my %message=&Apache::lonnet::get('critical',[$msgid]); + my %contents=&unpackagemsg($message{$msgid}); + 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'}):'no msg req'); + $status.=' trans: '. + &Apache::lonnet::put( + 'nohist_email',{$contents{'msgid'} => $message{$msgid}}); + $status.=' del: '. + &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,$citation)=@_; +# 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') { + ($msgid,$message)=&packagemsg($subject,$message,$citation); + $status=&Apache::lonnet::critical( + 'put:'.$domain.':'.$user.':nohist_email:'. + &Apache::lonnet::escape($msgid).'='. + &Apache::lonnet::escape($message),$homeserver); + } else { + $status='no_host'; + } + &Apache::lonnet::log($ENV{'user.domain'},$ENV{'user.name'}, + $ENV{'user.home'}, + 'Sending '.$msgid.' to '.$user.' at '.$domain.' with status: '.$status); + 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; + $r->print(< + +  + +  + +

+ENDDISHEADER + map { + 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); + } + } sort keys %courselist; +} + +# ==================================================== Display Critical Message + +sub discrit { + my $r=shift; + $r->print('

Critical Messages

'. + '
'. + ''); + my %what=&Apache::lonnet::dump('critical'); + map { + my %content=&unpackagemsg($what{$_}); + $content{'message'}=~s/\n/\/g; + $r->print('
From: '.$content{'sendername'}.'@'. + $content{'senderdomain'}.' ('.$content{'time'}. + ')
'.$content{'message'}.'
'. + ''. + ''); + } sort keys %what; + $r->print( + ''); +} + +# =============================================================== Compose reply + +sub comprep { + my ($r,$msgid)=@_; + my %message=&Apache::lonnet::get('nohist_email',[$msgid]); + my %content=&unpackagemsg($message{$msgid}); + my $quotemsg='> '.$content{'message'}; + $quotemsg=~s/\r/\n/g; + $quotemsg=~s/\f/\n/g; + $quotemsg=~s/\n+/\n\> /g; + my $subject='Re: '.$content{'subject'}; + my $dispcrit=''; + if (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) { + $dispcrit= + ' Send as critical message
'. + ' Send as critical message'. + ' and return receipt

'; + } + $r->print(<<"ENDREPLY"); +

+ +Subject:

+

+$dispcrit + +

+ENDREPLY +} + +# ======================================================== Display all messages + +sub disall { + my $r=shift; + $r->print( + '

Display All Messages

'. + ''. + ''); + map { + my ($sendtime,$shortsubj,$fromname,$fromdomain,$status)= + &Apache::lonmsg::unpackmsgid($_); + unless ($status eq 'deleted') { + if ($status eq 'new') { + $r->print(''); + } elsif ($status eq 'read') { + $r->print(''); + } elsif ($status eq 'replied') { + $r->print(''); + } else { + $r->print(''); + } + $r->print(''. + ''); + } + } sort split(/\&/,&Apache::lonnet::reply('keys:'. + $ENV{'user.domain'}.':'. + $ENV{'user.name'}.':nohist_email', + $ENV{'user.home'})); + $r->print('
 DateUsernameDomainSubjectStatus
OpenDelete'.localtime($sendtime).''. + $fromname.''.$fromdomain.''. + &Apache::lonnet::unescape($shortsubj).''. + $status.'

'. + ''. + '

'); +} + +# ============================================================== Compose output + +sub compout { + my ($r,$forwarding,$broadcast)=@_; + my $dispcrit=''; + my $dissub=''; + my $dismsg=''; + my $func='Send New'; + if (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) { + $dispcrit= + ' Send as critical message
'. + ' Send as critical message'. + ' and return receipt

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

'. + ''); + unless (($broadcast eq 'group') || ($broadcast eq 'upload')) { + $r->print(<<"ENDREC"); +
+ + + +ENDREC + } + unless ($broadcast eq 'upload') { + $r->print(<<"ENDCOMP"); + +
Username:
Domain:
Additional Recipients
username\@domain,username\@domain, ... +
+
Subject: +
+

+$dispcrit + +ENDCOMP + } + if ($broadcast eq 'upload') { + $r->print(< +

Generate messages from a file

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

+

+General message text:

+

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

'); +} + +# ===================================================================== Handler + +sub handler { + my $r=shift; + +# ----------------------------------------------------------- Set document type + + $r->content_type('text/html'); + $r->send_http_header; + + return OK if $r->header_only; + +# --------------------------- Get query string for limited number of parameters + + map { + my ($name, $value) = split(/=/,$_); + $value =~ tr/+/ /; + $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; + if (($name eq 'display') || ($name eq 'replyto') || + ($name eq 'forward') || ($name eq 'markread') || + ($name eq 'markdel') || ($name eq 'markunread') || + ($name eq 'sendreply') || ($name eq 'compose') || + ($name eq 'sendmail') || ($name eq 'critical')) { + unless ($ENV{'form.'.$name}) { + $ENV{'form.'.$name}=$value; + } + } + } (split(/&/,$ENV{'QUERY_STRING'})); + +# --------------------------------------------------------------- Render Output + + $r->print('EMail and Messaging'); + $r->print( + ''); + $r->print('

EMail

'); + 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}); + $r->print('Subject: '.$content{'subject'}. + '
From: '.$content{'sendername'}.' at '. + $content{'senderdomain'}. + '
Time: '.$content{'time'}.'

'. + ''. + ''. + ''. + ''. + ''. + '
Functions:ReplyForwardMark UnreadDisplay all Messages

'.
+             $content{'message'}.'

'.$content{'citation'}); + } elsif ($ENV{'form.replyto'}) { + &comprep($r,$ENV{'form.replyto'}); + } elsif ($ENV{'form.sendreply'}) { + my $msgid=$ENV{'form.sendreply'}; + my %message=&Apache::lonnet::get('nohist_email',[$msgid]); + my %content=&unpackagemsg($message{$msgid}); + &statuschange($msgid,'replied'); + if ((($ENV{'form.critmsg'}) || ($ENV{'form.sendbck'})) && + (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'}))) { + $r->print('Sending critical: '. + &user_crit_msg($content{'sendername'}, + $content{'senderdomain'}, + $ENV{'form.subject'}, + $ENV{'form.message'}, + $ENV{'form.sendbck'})); + } else { + $r->print('Sending: '.&user_normal_msg($content{'sendername'}, + $content{'senderdomain'}, + $ENV{'form.subject'}, + $ENV{'form.message'})); + } + if ($ENV{'form.displayedcrit'}) { + &discrit($r); + } else { + &disall($r); + } + } elsif ($ENV{'form.confirm'}) { + map { + 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); + } + } keys %ENV; + &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; + map { + if ($_=~/^form\.delmark_(.*)$/) { + &statuschange(&Apache::lonnet::unescape($1),'deleted'); + $total++; + } + } keys %ENV; + $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.sendmail'}) { + 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}); + &statuschange($msgid,'forwarded'); + $ENV{'form.message'}.="\n\n-- Forwarded message --\n\n". + $content{'message'}; + } + my %toaddr=(); + undef %toaddr; + if ($ENV{'form.sendmode'} eq 'group') { + map { + if ($_=~/^form\.send\_to\_\&\&\&[^\&]*\&\&\&\_(.+)$/) { + $toaddr{$1}=''; + } + } keys %ENV; + } elsif ($ENV{'form.sendmode'} eq 'upload') { + map { + my ($rec,$txt)=split(/\s*\:\s*/,$_); + if ($txt) { + $rec=~s/\@/\:/; + $toaddr{$rec}.=$txt."\n"; + } + } split(/[\n\r\f]+/,$ENV{'form.upfile'}); + } else { + $toaddr{$ENV{'form.recuname'}.':'.$ENV{'form.recdomain'}}=''; + } + if ($ENV{'form.additionalrec'}) { + map { + my ($auname,$audom)=split(/\@/,$_); + $toaddr{$auname.':'.$audom}=''; + } split(/\,/,$ENV{'form.additionalrec'}); + } + map { + my ($recuname,$recdomain)=split(/\:/,$_); + my $msgtxt=$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, + $ENV{'form.subject'}, + $msgtxt, + $ENV{'form.sendbck'})); + } else { + $r->print('Sending: '.&user_normal_msg($recuname,$recdomain, + $ENV{'form.subject'}, + $msgtxt, + $content{'citation'})); + } + $r->print('
'); + } keys %toaddr; + if ($ENV{'form.displayedcrit'}) { + &discrit($r); + } else { + &disall($r); + } + } else { + &disall($r); + } + $r->print(''); + return OK; + +} +# ================================================= Main program, reset counter + +sub BEGIN { + $msgcount=0; } 1;