--- loncom/interface/lonmsg.pm	2005/06/06 02:29:46	1.145
+++ loncom/interface/lonmsg.pm	2006/03/16 22:12:17	1.178
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Routines for messaging
 #
-# $Id: lonmsg.pm,v 1.145 2005/06/06 02:29:46 albertel Exp $
+# $Id: lonmsg.pm,v 1.178 2006/03/16 22:12:17 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -97,6 +97,17 @@ Right now, this document will cover just
 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 <recuser>$uname</recuser> and 
+<recdomain>$udom</recdomain> in stored internal messages, compared 
+with <recipient username="$uname:$udom">$email</recipient> in stored
+Domain Coordinator e-mail for the storage of information about 
+recipients of the message/e-mail.
+
 =head1 FUNCTIONS
 
 =over 4
@@ -114,6 +125,8 @@ use HTML::Entities();
 use Mail::Send;
 use Apache::lonlocal;
 use Apache::loncommunicate;
+use Apache::lonfeedback;
+use Apache::lonrss();
 
 # Querystring component with sorting type
 my $sqs;
@@ -124,7 +137,7 @@ my $interdis;
 
 sub packagemsg {
     my ($subject,$message,$citation,$baseurl,$attachmenturl,
-	$recuser,$recdomain)=@_;
+	$recuser,$recdomain,$msgid,$type,$crsmsgid)=@_;
     $message =&HTML::Entities::encode($message,'<>&"');
     $citation=&HTML::Entities::encode($citation,'<>&"');
     $subject =&HTML::Entities::encode($subject,'<>&"');
@@ -134,20 +147,42 @@ 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(/\:/,&Apache::lonnet::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(/\:/,&Apache::lonnet::unescape($2));
+            $course_context = $origcid;
+            last;
+        }
+    }
+    unless(defined($course_context)) {
+        $course_context = $env{'request.course.id'};
+    }
     my $now=time;
     $msgcount++;
-    my $partsubj=$subject;
-    $partsubj=&Apache::lonnet::escape($partsubj);
-    my $msgid=&Apache::lonnet::escape(
-           $now.':'.$partsubj.':'.$env{'user.name'}.':'.
-           $env{'user.domain'}.':'.$msgcount.':'.
-           $env{'request.course.id'}.':'.$$);
-    my $result='<sendername>'.$env{'user.name'}.'</sendername>'.
+    unless(defined($msgid)) {
+        $msgid = &buildmsgid($now,$subject,$env{'user.name'},$env{'user.domain'},
+                            $msgcount,$course_context,$$);
+    }
+    my $result = '<sendername>'.$env{'user.name'}.'</sendername>'.
            '<senderdomain>'.$env{'user.domain'}.'</senderdomain>'.
            '<subject>'.$subject.'</subject>'.
-	   '<time>'.&Apache::lonlocal::locallocaltime($now).'</time>'.
-	   '<servername>'.$ENV{'SERVER_NAME'}.'</servername>'.
+           '<time>'.&Apache::lonlocal::locallocaltime($now).'</time>';
+    if (defined($crsmsgid)) {
+        $result.= '<courseid>'.$course_context.'</courseid>'.
+                  '<coursesec>'.$env{'request.course.sec'}.'</coursesec>'.
+                  '<msgid>'.$msgid.'</msgid>'.
+                  '<coursemsgid>'.$crsmsgid.'</coursemsgid>'.
+                  '<message>'.$message.'</message>';
+        return ($msgid,$result);
+    }
+    $result .= '<servername>'.$ENV{'SERVER_NAME'}.'</servername>'.
            '<host>'.$ENV{'HTTP_HOST'}.'</host>'.
 	   '<client>'.$ENV{'REMOTE_ADDR'}.'</client>'.
 	   '<browsertype>'.$env{'browser.type'}.'</browsertype>'.
@@ -155,14 +190,31 @@ sub packagemsg {
 	   '<browserversion>'.$env{'browser.version'}.'</browserversion>'.
            '<browsermathml>'.$env{'browser.mathml'}.'</browsermathml>'.
 	   '<browserraw>'.$ENV{'HTTP_USER_AGENT'}.'</browserraw>'.
-	   '<courseid>'.$env{'request.course.id'}.'</courseid>'.
+	   '<courseid>'.$course_context.'</courseid>'.
 	   '<coursesec>'.$env{'request.course.sec'}.'</coursesec>'.
 	   '<role>'.$env{'request.role'}.'</role>'.
 	   '<resource>'.$env{'request.filename'}.'</resource>'.
-           '<msgid>'.$msgid.'</msgid>'.
-	   '<recuser>'.$recuser.'</recuser>'.
-	   '<recdomain>'.$recdomain.'</recdomain>'.
-	   '<message>'.$message.'</message>';
+           '<msgid>'.$msgid.'</msgid>';
+    if (ref($recuser) eq 'ARRAY') {
+        for (my $i=0; $i<@{$recuser}; $i++) {
+            if ($type eq 'dcmail') {
+                my ($username,$email) = split(/:/,$$recuser[$i]);
+                $username = &Apache::lonnet::unescape($username);
+                $email = &Apache::lonnet::unescape($email);
+                $username = &HTML::Entities::encode($username,'<>&"');
+                $email = &HTML::Entities::encode($email,'<>&"');
+                $result .= '<recipient username="'.$username.'">'.
+                                            $email.'</recipient>';
+            } else {
+                $result .= '<recuser>'.$$recuser[$i].'</recuser>'.
+                           '<recdomain>'.$$recdomain[$i].'</recdomain>';
+            }
+        }
+    } else {
+        $result .= '<recuser>'.$recuser.'</recuser>'.
+                   '<recdomain>'.$recdomain.'</recdomain>';
+    }
+    $result .= '<message>'.$message.'</message>';
     if (defined($citation)) {
 	$result.='<citation>'.$citation.'</citation>';
     }
@@ -186,9 +238,18 @@ sub unpackagemsg {
        if ($token->[0] eq 'S') {
 	   my $entry=$token->[1];
            my $value=$parser->get_text('/'.$entry);
-           $content{$entry}=$value;
+           if (($entry eq 'recuser') || ($entry eq 'recdomain')) {
+               push(@{$content{$entry}},$value);
+           } elsif ($entry eq 'recipient') {
+               my $username = $token->[2]{'username'};
+               $username = &HTML::Entities::decode($username,'<>&"');
+               $content{$entry}{$username} = $value;
+           } else {
+               $content{$entry}=$value;
+           }
        }
     }
+    if (!exists($content{'recuser'})) { $content{'recuser'} = []; }
     if ($content{'attachmenturl'}) {
        my ($fname)=($content{'attachmenturl'}=~m|/([^/]+)$|);
        if ($notoken) {
@@ -206,15 +267,30 @@ sub unpackagemsg {
 
 # ======================================================= Get info out of msgid
 
+sub buildmsgid {
+    my ($now,$subject,$uname,$udom,$msgcount,$course_context,$pid) = @_;
+    $subject=&Apache::lonnet::escape($subject);
+    return(&Apache::lonnet::escape($now.':'.$subject.':'.$uname.':'.
+           $udom.':'.$msgcount.':'.$course_context.':'.$pid));
+}
+
 sub unpackmsgid {
-    my ($msgid,$folder)=@_;
+    my ($msgid,$folder,$skipstatus,$status_cache)=@_;
     $msgid=&Apache::lonnet::unescape($msgid);
-    my $suffix=&foldersuffix($folder);
-    my ($sendtime,$shortsubj,$fromname,$fromdomain,$count,$fromcid)=split(/\:/,
-                          &Apache::lonnet::unescape($msgid));
-    my %status=&Apache::lonnet::get('email_status'.$suffix,[$msgid]);
-    if ($status{$msgid}=~/^error\:/) { $status{$msgid}=''; }
-    unless ($status{$msgid}) { $status{$msgid}='new'; }
+    my ($sendtime,$shortsubj,$fromname,$fromdomain,$count,$fromcid,
+                     $processid)=split(/\:/,&Apache::lonnet::unescape($msgid));
+    if (!defined($processid)) { $fromcid = ''; }
+    my %status=();
+    unless ($skipstatus) {
+	if (ref($status_cache)) {
+	    $status{$msgid} = $status_cache->{$msgid};
+	} else {
+	    my $suffix=&foldersuffix($folder);
+	    %status=&Apache::lonnet::get('email_status'.$suffix,[$msgid]);
+	}
+	if ($status{$msgid}=~/^error\:/) { $status{$msgid}=''; }
+        unless ($status{$msgid}) { $status{$msgid}='new'; }
+    }
     return ($sendtime,$shortsubj,$fromname,$fromdomain,$status{$msgid},$fromcid);
 }
 
@@ -337,7 +413,20 @@ sub del_url_author_res_msg {
     }
     return &Apache::lonnet::del('nohist_res_msgs',\@delmsgs,$domain,$author);
 }
+# =================================== Clear out all author messages in URL path
 
+sub clear_author_res_msg {
+    my $url=shift;
+    $url=&Apache::lonnet::declutter($url);
+    my ($domain,$author)=($url=~/^(\w+)\/(\w+)\//);
+    my @delmsgs=();
+    foreach (&Apache::lonnet::getkeys('nohist_res_msgs',$domain,$author)) {
+	if ($_=~/^\Q$url\E/) {
+	    push (@delmsgs,$_);
+	}
+    }
+    return &Apache::lonnet::del('nohist_res_msgs',\@delmsgs,$domain,$author);
+}
 # ================= Return hash with URLs for which there is a resource message
 
 sub all_url_author_res_msg {
@@ -353,7 +442,7 @@ sub all_url_author_res_msg {
 # ================================================== Critical message to a user
 
 sub user_crit_msg_raw {
-    my ($user,$domain,$subject,$message,$sendback,$toperm)=@_;
+    my ($user,$domain,$subject,$message,$sendback,$toperm,$sentmessage)=@_;
 # Check if allowed missing
     my $status='';
     my $msgid='undefined';
@@ -367,13 +456,9 @@ sub user_crit_msg_raw {
            '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);
-       }
+        if (defined($sentmessage)) {
+            $$sentmessage = $message;
+        }
     } else {
        $status='no_host';
     }
@@ -411,7 +496,7 @@ sub user_crit_msg_raw {
 =cut
 
 sub user_crit_msg {
-    my ($user,$domain,$subject,$message,$sendback,$toperm)=@_;
+    my ($user,$domain,$subject,$message,$sendback,$toperm,$sentmessage)=@_;
     my $status='';
     my %userenv = &Apache::lonnet::get('environment',['msgforward'],
                                        $domain,$user);
@@ -421,10 +506,10 @@ sub user_crit_msg {
 	 my ($forwuser,$forwdomain)=split(/\:/,$_);
          $status.=
 	   &user_crit_msg_raw($forwuser,$forwdomain,$subject,$message,
-                $sendback,$toperm).' ';
+                $sendback,$toperm,$sentmessage).' ';
        }
     } else { 
-	$status=&user_crit_msg_raw($user,$domain,$subject,$message,$sendback,$toperm);
+	$status=&user_crit_msg_raw($user,$domain,$subject,$message,$sendback,$toperm,$sentmessage);
     }
     return $status;
 }
@@ -459,33 +544,51 @@ sub user_crit_received {
 
 sub user_normal_msg_raw {
     my ($user,$domain,$subject,$message,$citation,$baseurl,$attachmenturl,
-	$toperm)=@_;
+	$toperm,$currid,$newid,$sentmessage,$crsmsgid)=@_;
 # Check if allowed missing
-    my $status='';
+    my ($status,$packed_message);
     my $msgid='undefined';
     my $text=$message;
     unless (($message)&&($user)&&($domain)) { $status='empty'; };
     my $homeserver=&Apache::lonnet::homeserver($user,$domain);
     if ($homeserver ne 'no_host') {
-       ($msgid,$message)=&packagemsg($subject,$message,$citation,$baseurl,
-                                     $attachmenturl,$user,$domain);
+       ($msgid,$packed_message)=
+	                 &packagemsg($subject,$message,$citation,$baseurl,
+                                     $attachmenturl,$user,$domain,$currid,
+                                                         undef,$crsmsgid);
+
 # Store in user folder
        $status=&Apache::lonnet::critical(
            'put:'.$domain.':'.$user.':nohist_email:'.
            &Apache::lonnet::escape($msgid).'='.
-           &Apache::lonnet::escape($message),$homeserver);
+           &Apache::lonnet::escape($packed_message),$homeserver);
 # Save new message received time
        &Apache::lonnet::put
                          ('email_status',{'recnewemail'=>time},$domain,$user);
-# Into sent-mail folder
-       $status.=' '.&Apache::lonnet::critical(
-           'put:'.$env{'user.domain'}.':'.$env{'user.name'}.
-					      ':nohist_email_sent:'.
-           &Apache::lonnet::escape($msgid).'='.
-           &Apache::lonnet::escape($message),$env{'user.home'});
+# 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'})))) {
+           (undef, my $packed_message_no_citation)=
+                             &packagemsg($subject,$message,undef     ,$baseurl,
+                                          $attachmenturl,$user,$domain,$currid,
+                                                              undef,$crsmsgid);
+
+           $status .= &store_sent_mail($msgid,$packed_message_no_citation);
+       }
     } else {
        $status='no_host';
     }
+    if (defined($newid)) {
+        $$newid = $msgid;
+    }
+    if (defined($sentmessage)) {
+        $$sentmessage = $packed_message;
+    }
+
 # Notifications
     my %userenv = &Apache::lonnet::get('environment',['notification',
                                                       'permanentemail'],
@@ -516,25 +619,36 @@ sub user_normal_msg_raw {
 
 sub user_normal_msg {
     my ($user,$domain,$subject,$message,$citation,$baseurl,$attachmenturl,
-	$toperm)=@_;
+	$toperm,$sentmessage)=@_;
     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,$toperm).' ';
-       }
+        foreach (split(/\,/,$msgforward)) {
+	    my ($forwuser,$forwdomain)=split(/\:/,$_);
+	    $status.=
+	        &user_normal_msg_raw($forwuser,$forwdomain,$subject,$message,
+				     $citation,$baseurl,$attachmenturl,$toperm,
+				     undef,undef,$sentmessage).' ';
+        }
     } else { 
 	$status=&user_normal_msg_raw($user,$domain,$subject,$message,
-				     $citation,$baseurl,$attachmenturl,$toperm);
+				     $citation,$baseurl,$attachmenturl,$toperm,
+				     undef,undef,$sentmessage);
     }
     return $status;
 }
 
+sub store_sent_mail {
+    my ($msgid,$message) = @_;
+    my $status =' '.&Apache::lonnet::critical(
+               'put:'.$env{'user.domain'}.':'.$env{'user.name'}.
+                                          ':nohist_email_sent:'.
+               &Apache::lonnet::escape($msgid).'='.
+               &Apache::lonnet::escape($message),$env{'user.home'});
+    return $status;
+}
 
 # ============================================================ List all folders
 
@@ -564,13 +678,14 @@ sub scrollbuttons {
     my ($start,$maxdis,$first,$finish,$total)=@_;
     unless ($total>0) { return ''; }
     $start++; $maxdis++;$first++;$finish++;
-    return 
+    return
+   &mt('Page').': '. 
    '<input type="submit" name="firstview" value="'.&mt('First').'" />'.
    '<input type="submit" name="prevview" value="'.&mt('Previous').'" />'.
    '<input type="text" size="5" name="startdis" value="'.$start.'" onChange="this.form.submit()" /> of '.$maxdis.
    '<input type="submit" name="nextview" value="'.&mt('Next').'" />'.
    '<input type="submit" name="lastview" value="'.&mt('Last').'" /><br />'.
-   &mt('Messages [_1] through [_2] of [_3]',$first,$finish,$total).'</form>';
+   &mt('Showing messages [_1] through [_2] of [_3]',$first,$finish,$total).'</form>';
 }
 
 # =============================================================== Folder suffix
@@ -596,6 +711,9 @@ sub statuschange {
     if (($newstatus eq 'deleted') || ($newstatus eq 'new')) {
 	&Apache::lonnet::put('email_status'.$suffix,{$msgid => $newstatus});
     }
+    if ($newstatus eq 'deleted') {
+       &movemsg(&Apache::lonnet::unescape($msgid),$folder,'trash');
+   }
 }
 
 # ============================================================= Make new folder
@@ -656,7 +774,7 @@ sub discourse {
 	for (i=0; i<document.forms.compemail.elements.length; i++) {
             if 
           (document.forms.compemail.elements[i].name.indexOf
-           ('send_to_&&&'+document.forms.compemail.chksec.value)==0) {
+           ('send_to_&&&'+document.forms.compemail.chksec.value+'&&&')==0) {
 	      document.forms.compemail.elements[i].checked=true;
             }
         }
@@ -764,12 +882,17 @@ sub sortedmessages {
     my @messages = &Apache::lonnet::getkeys('nohist_email'.$suffix);
     #unpack the varibles and repack into temp for sorting
     my @temp;
+    my %descriptions;
+    my %status_cache = 
+	&Apache::lonnet::get('email_status'.&foldersuffix($folder),\@messages);
     foreach (@messages) {
 	my $msgid=&Apache::lonnet::escape($_);
 	my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid)=
-	    &Apache::lonmsg::unpackmsgid($msgid,$folder);
+	    &Apache::lonmsg::unpackmsgid($msgid,$folder,undef,
+					 \%status_cache);
+        my $description = &get_course_desc($fromcid,\%descriptions);
 	my @temp1 = ($sendtime,$shortsubj,$fromname,$fromdomain,$status,
-		     $msgid);
+		     $msgid,$description);
         # Check whether message was sent during blocking period.
         if ($sendtime >= $startblock && ($sendtime <= $endblock && $endblock > 0) ) {
             my $escid = &Apache::lonnet::unescape($msgid);
@@ -805,6 +928,12 @@ sub sortedmessages {
     if ($env{'form.sortedby'} eq "revsubject"){
         @temp = sort  {lc($b->[1]) cmp lc($a->[1])} @temp;
     }
+    if ($env{'form.sortedby'} eq "course"){
+        @temp = sort  {lc($a->[6]) cmp lc($b->[6])} @temp;
+    }
+    if ($env{'form.sortedby'} eq "revcourse"){
+        @temp = sort  {lc($b->[6]) cmp lc($a->[6])} @temp;
+    }
     if ($env{'form.sortedby'} eq "status"){
         @temp = sort  {$a->[4] cmp $b->[4]} @temp;
     }
@@ -814,6 +943,27 @@ sub sortedmessages {
     return @temp;
 }
 
+sub get_course_desc {
+    my ($fromcid,$descriptions) = @_;
+    my $description;
+    if (!$fromcid) {
+        return $description;
+    } else {
+        if (defined($$descriptions{$fromcid})) {
+            $description = $$descriptions{$fromcid};
+        } else {
+            if (defined($env{'course.'.$fromcid.'.description'})) {
+                $description = $env{'course.'.$fromcid.'.description'};
+            } else {
+                my %courseinfo=&Apache::lonnet::coursedescription($fromcid);                $description = $courseinfo{'description'};
+                $description = $courseinfo{'description'};
+            }
+            $$descriptions{$fromcid} = $description;
+        }
+        return $description;
+    }
+}
+
 # ======================================================== Display new messages
 
 
@@ -822,15 +972,13 @@ sub disnew {
     my %lt=&Apache::lonlocal::texthash(
 				       'nm' => 'New Messages',
 				       'su' => 'Subject',
+                                       'co' => 'Course',
 				       'da' => 'Date',
 				       'us' => 'Username',
 				       'op' => 'Open',
 				       'do' => 'Domain'
 				       );
-    my @msgids = sort split(/\&/,&Apache::lonnet::reply
-                            ('keys:'.$env{'user.domain'}.':'.
-                             $env{'user.name'}.':nohist_email',
-                             $env{'user.home'}));
+    my @msgids = sort(&Apache::lonnet::getkeys('nohist_email'));
     my @newmsgs;
     my %setters = ();
     my $startblock = 0;
@@ -839,10 +987,15 @@ sub disnew {
     my $numblocked = 0;
     # Check for blocking of display because of scheduled online exams.
     &blockcheck(\%setters,\$startblock,\$endblock);
+    my %status_cache = 
+	&Apache::lonnet::get('email_status',\@msgids);
+    my %descriptions;
     foreach (@msgids) {
+	my $msgid=&Apache::lonnet::escape($_);
         my ($sendtime,$shortsubj,$fromname,$fromdom,$status,$fromcid)=
-	    &Apache::lonmsg::unpackmsgid($_);
+	    &Apache::lonmsg::unpackmsgid($msgid,undef,undef,\%status_cache);
         if (defined($sendtime) && $sendtime!~/error/) {
+            my $description = &get_course_desc($fromcid,\%descriptions);
             my $numsendtime = $sendtime;
             $sendtime = &Apache::lonlocal::locallocaltime($sendtime);
             if ($status eq 'new') {
@@ -851,11 +1004,12 @@ sub disnew {
                     $numblocked ++;
                 } else {
                     push @newmsgs, { 
-                        msgid    => $_,
+                        msgid    => $msgid,
                         sendtime => $sendtime,
                         shortsub => &Apache::lonnet::unescape($shortsubj),
                         from     => $fromname,
-                        fromdom  => $fromdom 
+                        fromdom  => $fromdom,
+                        course   => $description 
                         }
                 }
             }
@@ -865,19 +1019,20 @@ sub disnew {
         $r->print(<<TABLEHEAD);
 <h2>$lt{'nm'}</h2>
 <table border=2><tr><th>&nbsp</th>
-<th>$lt{'da'}</th><th>$lt{'us'}</th><th>$lt{'do'}</th><th>$lt{'su'}</th></tr>
+<th>$lt{'da'}</th><th>$lt{'us'}</th><th>$lt{'do'}</th><th>$lt{'su'}</th><th>$lt{'co'}</th></tr>
 TABLEHEAD
         foreach my $msg (@newmsgs) {
             $r->print(<<"ENDLINK");
-<tr bgcolor="#FFBB77">
+<tr class="new" bgcolor="#FFBB77" onMouseOver="javascript:style.backgroundColor='#DD9955'" 
+onMouseOut="javascript:style.backgroundColor='#FFBB77'">
 <td><a href="/adm/email?dismode=new&display=$msg->{'msgid'}">$lt{'op'}</a></td>
 ENDLINK
-            foreach ('sendtime','from','fromdom','shortsub') {
+            foreach ('sendtime','from','fromdom','shortsub','course') {
                 $r->print("<td>$msg->{$_}</td>");
             }
             $r->print("</td></tr>");
         }
-        $r->print('</table>'.&Apache::loncommon::endbodytag().'</html>');
+        $r->print('</table>'.&Apache::loncommon::end_page());
     } elsif ($numblocked == 0) {
         $r->print("<h3>".&mt('You have no unread messages')."</h3>");
     }
@@ -986,6 +1141,12 @@ ENDDISHEADER
     	$r->print('<a href = "?sortedby=revsubject'.$fsqs.'">'.&mt('Subject').'</a>');
     }
     $r->print('</th><th>');
+    if ($env{'form.sortedby'} eq "revcourse") {
+        $r->print('<a href = "?sortedby=course'.$fsqs.'">'.&mt('Course').'</a>');
+    } else {
+        $r->print('<a href = "?sortedby=revcourse'.$fsqs.'">'.&mt('Course').'</a>');
+    }
+    $r->print('</th><th>');
     if ($env{'form.sortedby'} eq "revstatus") {
 	$r->print('<a href = "?sortedby=status'.$fsqs.'">'.&mt('Status').'</a></th>');
     } else {
@@ -993,16 +1154,16 @@ ENDDISHEADER
     }
     $r->print("</tr>\n");
     for (my $n=$firstdis;$n<=$lastdis;$n++) {
-	my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$origID)= @{$temp[$n]};
+	my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$origID,$description)= @{$temp[$n]};
 	if (($status ne 'deleted') && defined($sendtime) && $sendtime!~/error/) {
 	    if ($status eq 'new') {
-		$r->print('<tr bgcolor="#FFBB77">');
+		$r->print('<tr bgcolor="#FFBB77" onMouseOver="javascript:style.backgroundColor=\'#DD9955\'"  onMouseOut="javascript:style.backgroundColor=\'#FFBB77\'">');
 	    } elsif ($status eq 'read') {
-		$r->print('<tr bgcolor="#BBBB77">');
+		$r->print('<tr bgcolor="#BBBB77" onMouseOver="javascript:style.backgroundColor=\'#999944\'"  onMouseOut="javascript:style.backgroundColor=\'#BBBB77\'">');
 	    } elsif ($status eq 'replied') {
-		$r->print('<tr bgcolor="#AAAA88">'); 
+		$r->print('<tr bgcolor="#AAAA88" onMouseOver="javascript:style.backgroundColor=\'#888855\'"  onMouseOut="javascript:style.backgroundColor=\'#AAAA88\'">'); 
 	    } else {
-		$r->print('<tr bgcolor="#99BBBB">');
+		$r->print('<tr bgcolor="#99BBBB" onMouseOver="javascript:style.backgroundColor=\'#669999\'"  onMouseOut="javascript:style.backgroundColor=\'#99BBBB\'">');
 	    }
 	    $r->print('<td><input type="checkbox" name="delmark_'.$origID.'" /></td><td><a href="/adm/email?display='.$origID.$sqs. 
 		      '">'.&mt('Open').'</a></td><td>'.
@@ -1011,7 +1172,7 @@ ENDDISHEADER
 		      '<td>'.&Apache::lonlocal::locallocaltime($sendtime).'</td><td>'.
 		      $fromname.'</td><td>'.$fromdomain.'</td><td>'.
 		      &Apache::lonnet::unescape($shortsubj).'</td><td>'.
-                      $status."</td></tr>\n");
+                      $description.'</td><td>'.$status.'</td></tr>'."\n");
 	} elsif ($status eq 'deleted') {
 # purge
 	    &movemsg(&Apache::lonnet::unescape($origID),$folder,'trash');
@@ -1087,7 +1248,9 @@ sub compout {
 				       'ca' => 'Cancel',
 				       'ma' => 'Mail');
 
-    if (&Apache::lonnet::allowed('srm',$env{'request.course.id'})) {
+    if (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
+	|| &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
+				    '/'.$env{'request.course.sec'})) {
 	 my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message");
          $dispcrit=
  '<p><label><input type="checkbox" name="critmsg" /> '.&mt('Send as critical message').'</label> ' . $crithelp . 
@@ -1095,7 +1258,9 @@ sub compout {
  '<label><input type="checkbox" name="sendbck" /> '.&mt('Send as critical message').'  ' .
  &mt('and return receipt') . '</label>' . $crithelp . 
  '</p><p><label><input type="checkbox" name="permanent" /> '.
-&mt('Send copy to permanent email address (if known)').'</label></p>';
+&mt('Send copy to permanent email address (if known)').'</label></p>'.
+'<p><label><input type="checkbox" name="rsspost" /> '.
+		  &mt('Include in course RSS newsfeed').'</label></p>';
      }
     my %message;
     my %content;
@@ -1212,9 +1377,10 @@ $dispcrit
 ENDUPLOAD
     }
     if ($broadcast eq 'group') {
-       &discourse;
+       &discourse($r);
     }
     $r->print('</form>'.
+	      &Apache::lonfeedback::generate_preview_button('compemail','message').
 	      &Apache::lonhtmlcommon::htmlareaselectactive('message'));
 }
 
@@ -1224,7 +1390,9 @@ sub retrieve_instructor_comments {
     my ($user,$domain)=@_;
     my $target=$env{'form.grade_target'};
     if (! $env{'request.course.id'}) { return; }
-    if (! &Apache::lonnet::allowed('srm',$env{'request.course.id'})) {
+    if (! &Apache::lonnet::allowed('srm',$env{'request.course.id'})
+	&& ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
+				      '/'.$env{'request.course.sec'})) {
 	return;
     }
     my %records=&Apache::lonnet::dump('nohist_email',
@@ -1249,7 +1417,10 @@ sub disfacetoface {
     my ($r,$user,$domain)=@_;
     my $target=$env{'form.grade_target'};
     unless ($env{'request.course.id'}) { return; }
-    unless (&Apache::lonnet::allowed('srm',$env{'request.course.id'})) {
+    if  (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
+	 && ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
+				       '/'.$env{'request.course.sec'})) {
+	$r->print('Not allowed');
 	return;
     }
     my %records=&Apache::lonnet::dump('nohist_email',
@@ -1265,12 +1436,30 @@ sub disfacetoface {
 	    $result.='<h3>'.&mt('Record').'</h3>';
         } elsif ($content{'subject'}=~/^Broadcast/) {
             $result .='<h3>'.&mt('Broadcast Message').'</h3>';
+            if ($content{'subject'}=~/^Broadcast\./) {
+                if (defined($content{'coursemsgid'})) {
+                    my $crsmsgid = &Apache::lonnet::escape($content{'coursemsgid'});
+                    my $broadcast_message = &general_message($crsmsgid);
+                    $content{'message'} = '<b>'.&mt('Subject').': '.$content{'message'}.'</b><br />'.$broadcast_message;
+                } else {
+                    %content=&unpackagemsg($content{'message'});
+                    $content{'message'} =
+                    '<b>'.&mt('Subject').': '.$content{'subject'}.'</b><br />'.
+                    $content{'message'};
+                }
+            }    
         } else {
             $result.='<h3>'.&mt('Critical Message').'</h3>';
-            %content=&unpackagemsg($content{'message'});
-            $content{'message'}=
+            if (defined($content{'coursemsgid'})) {
+                my $crsmsgid=&Apache::lonnet::escape($content{'coursemsgid'});
+                my $critical_message = &general_message($crsmsgid);
+                $content{'message'} = '<b>'.&mt('Subject').': '.$content{'message'}.'</b><br />'.$critical_message;
+            } else {
+                %content=&unpackagemsg($content{'message'});
+                $content{'message'}=
                 '<b>'.&mt('Subject').': '.$content{'subject'}.'</b><br />'.
 		$content{'message'};
+            }
         }
         $result.=&mt('By').': <b>'.
 &Apache::loncommon::aboutmewrapper(
@@ -1293,11 +1482,26 @@ $content{'sendername'}.'@'.
     }
 }
 
+sub general_message {
+    my ($crsmsgid) = @_;
+    my %general_content;
+    if ($crsmsgid) { 
+        my %course_content = &Apache::lonnet::get('nohist_email',[$crsmsgid],
+                           $env{'course.'.$env{'request.course.id'}.'.domain'},
+                           $env{'course.'.$env{'request.course.id'}.'.num'});
+        %general_content = &unpackagemsg($course_content{$crsmsgid});
+    }
+    return $general_content{'message'};
+}
+
 # ---------------------------------------------------------------- Face to face
 
 sub facetoface {
     my ($r,$stage)=@_;
-    unless (&Apache::lonnet::allowed('srm',$env{'request.course.id'})) {
+    if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
+	&& ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
+				      '/'.$env{'request.course.sec'})) {
+	$r->print('Not allowed');
 	return;
     }
     &printheader($r,
@@ -1340,12 +1544,13 @@ ENDTREC
         ($env{'form.recdomain'}) && ($env{'form.recuname'})) {
         chomp($env{'form.newrecord'});
         if ($env{'form.newrecord'}) {
+           my $recordtxt = $env{'form.newrecord'};
            &user_normal_msg_raw(
             $env{'course.'.$env{'request.course.id'}.'.num'},
             $env{'course.'.$env{'request.course.id'}.'.domain'},
             &mt('Record').
 	     ' ['.$env{'form.recuname'}.':'.$env{'form.recdomain'}.']',
-	    $env{'form.newrecord'});
+	    $recordtxt);
         }
         $r->print('<h3>'.&Apache::loncommon::plainname($env{'form.recuname'},
 				     $env{'form.recdomain'}).'</h3>');
@@ -1371,7 +1576,12 @@ ENDBFORM
 sub examblock {
     my ($r,$action) = @_;
     unless ($env{'request.course.id'}) { return;}
-    unless (&Apache::lonnet::allowed('srm',$env{'request.course.id'})) { $r->print('Not allowed'); }
+    if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
+	&& ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
+				      '/'.$env{'request.course.sec'})) {
+	$r->print('Not allowed');
+	return;
+    }
     my %lt=&Apache::lonlocal::texthash(
             'comb' => 'Communication Blocking',
             'cbds' => 'Communication blocking during scheduled exams',
@@ -1411,14 +1621,13 @@ sub examblock {
         $r->print($lt{'ncbc'}.'<br /><br />');
     }
     &display_addblocker_table($r,$parmcount,\%ltext);
-    my $endbody=&Apache::loncommon::endbodytag();
+    my $end_page=&Apache::loncommon::end_page();
     $r->print(<<"END");
 <br />
 <input type="hidden" name="blocktotal" value="$blockcount" />
 <input type ="submit" value="Save Changes" />
 </form>
-$endbody
-</html>
+$end_page
 END
     return;
 }
@@ -1777,7 +1986,7 @@ sub displaymessage {
 	      '<td><a href="/adm/email?markunread='.&Apache::lonnet::escape($msgid).$sqs.
 	      '"><b>'.&mt('Mark Unread').'</b></a></td>'.
 	      '<td><a href="/adm/email?markdel='.&Apache::lonnet::escape($msgid).$sqs.
-	      '"><b>Delete</b></a></td>'.
+	      '"><b>'.&mt('Delete').'</b></a></td>'.
 	      '<td><a href="/adm/email?'.$sqs.
 	      ($env{'form.dismode'} eq 'new'?'&folder=new':'').
 	      '"><b>'.&mt('Back to Folder Display').'</b></a></td>');
@@ -1790,6 +1999,30 @@ sub displaymessage {
 		  '"><b>'.&mt('Next').'</b></a></td>');
     }
     $r->print('</tr></table>');
+    if ($env{'user.adv'}) {
+	$r->print('<table border="2" width="100%"><tr bgcolor="#FFAAAA"><td>'.&mt('Currently available actions (will open extra window)').':</td>');
+	my $symb=&Apache::lonnet::symbread($content{'baseurl'});      
+	if (&Apache::lonnet::allowed('vgr',$env{'request.course.id'})) {
+		$r->print('<td><b>'.&Apache::loncommon::track_student_link(&mt('View recent activity'),$content{'sendername'},$content{'senderdomain'},'check').'</b></td>');
+	    }
+	if (&Apache::lonnet::allowed('opa',$env{'request.course.id'}) && $symb) {
+	    $r->print('<td><b>'.&Apache::loncommon::pprmlink(&mt('Set/Change parameters'),$content{'sendername'},$content{'senderdomain'},$symb,'check').'</b></td>');
+	}
+	if (&Apache::lonnet::allowed('mgr',$env{'request.course.id'}) && $symb) {
+	    $r->print('<td><b>'.&Apache::loncommon::pgrdlink(&mt('Set/Change grades'),$content{'sendername'},$content{'senderdomain'},$symb,'check').'</b></td>');
+	}
+	$r->print('</tr></table>');
+    }
+    my $tolist;
+    my @recipients = ();
+    for (my $i=0; $i<@{$content{'recuser'}}; $i++) {
+        $recipients[$i] =  &Apache::loncommon::aboutmewrapper(
+           &Apache::loncommon::plainname($content{'recuser'}[$i],
+                                      $content{'recdomain'}[$i]),
+              $content{'recuser'}[$i],$content{'recdomain'}[$i]).
+       ' ('.$content{'recuser'}[$i].' at '.$content{'recdomain'}[$i].') ';
+    }
+    $tolist = join(', ',@recipients);
     $r->print('<br /><b>'.&mt('Subject').':</b> '.$content{'subject'}.
 	      ($folder ne 'sent'?'<br /><b>'.&mt('From').':</b> '.
 	      &Apache::loncommon::aboutmewrapper(
@@ -1797,11 +2030,7 @@ sub displaymessage {
 						 $content{'sendername'},$content{'senderdomain'}).' ('.
 	      $content{'sendername'}.' at '.
 	      $content{'senderdomain'}.') ':'<br /><b>'.&mt('To').':</b> '.
-	      &Apache::loncommon::aboutmewrapper(
-						 &Apache::loncommon::plainname($content{'recuser'},$content{'recdomain'}),
-						 $content{'recuser'},$content{'recdomain'}).' ('.
-	      $content{'recuser'}.' at '.
-	      $content{'recdomain'}.') ').
+              $tolist).
 	      ($content{'courseid'}?'<br /><b>'.&mt('Course').':</b> '.$courseinfo{'description'}.
 	       ($content{'coursesec'}?' ('.&mt('Group/Section').': '.$content{'coursesec'}.')':''):'').
 	      '<br /><b>'.&mt('Time').':</b> '.$content{'time'}.
@@ -1842,26 +2071,25 @@ sub displayresource {
 						    $content{'sendername'},
 						    $content{'senderdomain'},
 						    $content{'courseid'});
-    } else {
+    } elsif ($env{'user.adv'}) {
 	return $content{'citation'};
     }
+    return '';
 }
 
 # ================================================================== The Header
 
 sub header {
     my ($r,$title,$baseurl)=@_;
-    $r->print(&Apache::lonxml::xmlbegin().
-	      '<head>'.&Apache::lonxml::fontsettings().
-	      '<title>Communication and Messages</title>'.
-	      &Apache::lonhtmlcommon::htmlareaheaders());
+    
+    my $extra = &Apache::loncommon::studentbrowser_javascript();
     if ($baseurl) {
-	$r->print("<base href=\"http://$ENV{'SERVER_NAME'}/$baseurl\" />");
+	$extra .= "<base href=\"http://$ENV{'SERVER_NAME'}/$baseurl\" />";
     }
-    $r->print(&Apache::loncommon::studentbrowser_javascript().'</head>'.
-	      &Apache::loncommon::bodytag('Communication and Messages'));
-        $r->print(&Apache::lonhtmlcommon::breadcrumbs
-                  (undef,($title?$title:'Communication and Messages')));
+    $r->print(&Apache::loncommon::start_page('Communication and Messages',
+					     $extra));
+    $r->print(&Apache::lonhtmlcommon::breadcrumbs
+	      (undef,($title?$title:'Communication and Messages')));
 
 }
 
@@ -1894,8 +2122,8 @@ sub storedcommentlisting {
     my ($r)=@_;
     my %msgs=&Apache::lonnet::dump('nohist_stored_comments',undef,undef,
        '^'.&Apache::lonnet::escape(&Apache::lonnet::escape($env{'form.showcommentbaseurl'})));
-    $r->print(&Apache::lonxml::xmlbegin().'<head>'.
-	      &Apache::lonxml::fontsettings().'</head><body>');
+    $r->print(&Apache::loncommon::start_page('Stored Comment Listing',undef,
+					     {'onlybody' => 1}));
     if ((keys %msgs)[0]=~/^error\:/) {
 	$r->print(&mt('No stored comments yet.'));
     } else {
@@ -1916,6 +2144,8 @@ sub sendoffmail {
     my ($r,$folder)=@_;
     my $suffix=&foldersuffix($folder);
     my $sendstatus='';
+    my %specialmsg_status;
+    my $numspecial = 0;
     if ($env{'form.send'}) {
 	&printheader($r,'','Messages being sent.');
 	$r->rflush();
@@ -1960,42 +2190,103 @@ sub sendoffmail {
 		$toaddr{$auname.':'.$audom}='';
 	    }
 	}
+
+        my $savemsg;
+        my $msgtype;
+        my %sentmessage;
+        my $msgsubj=&Apache::lonfeedback::clear_out_html($env{'form.subject'});
+        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'})
+	     )) {
+            $savemsg=&Apache::lonfeedback::clear_out_html($env{'form.message'},1);
+            $msgtype = 'critical';
+        } else {
+            $savemsg=&Apache::lonfeedback::clear_out_html($env{'form.message'});
+        }
 	
 	foreach (keys %toaddr) {
 	    my ($recuname,$recdomain)=split(/\:/,$_);
-            my $msgtxt;
-            if ((($env{'form.critmsg'}) || ($env{'form.sendbck'})) &&
-                (&Apache::lonnet::allowed('srm',$env{'request.course.id'}))) {
-                $msgtxt=&Apache::lonfeedback::clear_out_html($env{'form.message'},1);
-            } else {  
-	        $msgtxt=&Apache::lonfeedback::clear_out_html($env{'form.message'});
-            }
+            my $msgtxt = $savemsg;
 	    if ($toaddr{$_}) { $msgtxt.='<hr />'.$toaddr{$_}; }
-	    my $thismsg;    
+	    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'})
+		 || &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
+					     '/'.$env{'request.course.sec'}))) {
 		$r->print(&mt('Sending critical message').' '.$recuname.'@'.$recdomain.': ');
-		$thismsg=&user_crit_msg($recuname,$recdomain,
-					&Apache::lonfeedback::clear_out_html($env{'form.subject'}),
-					$msgtxt,
-					$env{'form.sendbck'},$env{'form.permanent'});
+		$thismsg=&user_crit_msg($recuname,$recdomain,$msgsubj,$msgtxt,
+				$env{'form.sendbck'},$env{'form.permanent'},
+                                                             \$sentmessage{$_});
 	    } else {
 		$r->print(&mt('Sending').' '.$recuname.'@'.$recdomain.': ');
-		$thismsg=&user_normal_msg($recuname,$recdomain,
-					  &Apache::lonfeedback::clear_out_html($env{'form.subject'}),
-					  $msgtxt,
-					  $content{'citation'},undef,undef,$env{'form.permanent'});
-		if (($env{'request.course.id'}) && ($env{'form.sendmode'} eq 'group')) {
-		    &user_normal_msg_raw(
-					 $env{'course.'.$env{'request.course.id'}.'.num'},
-					 $env{'course.'.$env{'request.course.id'}.'.domain'},
-					 'Broadcast ['.$recuname.':'.$recdomain.']',
-					 $msgtxt);
-		}
+		$thismsg=&user_normal_msg($recuname,$recdomain,$msgsubj,$msgtxt,
+					  $content{'citation'},undef,undef,$env{'form.permanent'},\$sentmessage{$_});
+            }
+	    if (($env{'request.course.id'}) && (($msgtype eq 'critical') || 
+                                         ($env{'form.sendmode'} eq 'group'))) {
+	        $specialmsg_status{$recuname.':'.$recdomain}  = $thismsg;
+                if ($thismsg eq 'ok') {
+                    $numspecial ++;
+                }
 	    }
 	    $r->print($thismsg.'<br />');
 	    $sendstatus.=' '.$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 $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
+            my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
+            my $course_str = &Apache::lonnet::escape('['.$cnum.':'.$cdom.']');
+
+            if ($numspecial) {
+                $specialresult = &user_normal_msg_raw($cnum,$cdom,$subj_prefix.
+                    ' '.$course_str,$savemsg,undef,undef,undef,
+                    undef,undef,\$specialmsgid);
+                $specialmsgid = &Apache::lonnet::unescape($specialmsgid);
+            }
+            if ($specialresult eq 'ok') {
+                my $record_sent;
+                my @recusers = ();
+                my @recudoms = ();
+                my ($stamp,$crssubj,$msgname,$msgdom,$msgcount,$context,$pid) = 
+                            split(/\:/,&Apache::lonnet::unescape($specialmsgid));
+                foreach my $recipient (sort(keys(%toaddr))) {
+                    if ($specialmsg_status{$recipient} eq 'ok') {
+                        my $usersubj = $subj_prefix.'['.$recipient.']';
+                        my $usermsgid = &buildmsgid($stamp,$usersubj,$msgname,
+                                              $msgdom,$msgcount,$context,$pid);
+                        &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 = &buildmsgid($stamp,$sentsubj,$msgname,
+                                              $msgdom,$msgcount,$context,$pid);
+                    ($specialmsgid,$specialmessage) = &packagemsg($msgsubj,$savemsg,
+                            undef,undef,undef,\@recusers,\@recudoms,$sentmsgid);
+                    $record_sent = &store_sent_mail($specialmsgid,$specialmessage);
+                }
+            } 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');
+            }
+        }
     } else {
 	&printheader($r,'','No messages sent.'); 
     }
@@ -2161,6 +2452,13 @@ sub handler {
 	if ($env{'form.storebasecomment'}) {
 	    &storecomment($r);
 	}
+	if (($env{'form.rsspost'}) && ($env{'request.course.id'})) {
+	    &Apache::lonrss::addentry($env{'course.'.$env{'request.course.id'}.'.num'},
+				      $env{'course.'.$env{'request.course.id'}.'.domain'},
+				      'Course_Announcements',
+				      $env{'form.subject'},
+				      $env{'form.message'},'/adm/communicate','public');
+	}
 	&disall($r,($folder?$folder:$dismode));
     } elsif ($env{'form.newfolder'}) {
 	&printheader($r,'','New Folder');
@@ -2174,7 +2472,7 @@ sub handler {
 	&Apache::loncommunicate::menu($r); 
 	&disall($r,($folder?$folder:$dismode));
     }
-    $r->print(&Apache::loncommon::endbodytag().'</html>');
+    $r->print(&Apache::loncommon::end_page());
     return OK;
 }
 # ================================================= Main program, reset counter