[LON-CAPA-cvs] cvs: loncom /interface lonmsgdisplay.pm

raeburn lon-capa-cvs@mail.lon-capa.org
Mon, 18 Dec 2006 00:16:30 -0000


This is a MIME encoded message

--raeburn1166400990
Content-Type: text/plain

raeburn		Sun Dec 17 19:16:30 2006 EDT

  Modified files:              
    /loncom/interface	lonmsgdisplay.pm 
  Log:
  bugs 4205, 4511
  "New messages" display did not include checkboxes and was not honoring limit to number of messages displayed.
  
  "New messages" screen now eliminated.
  
  Can use checkboxes to select multiple messages, and mark read, unread, delete, move to a new folder or forward, for all selected. 
  
  Unread messages now appear in bold text.
  
  "Open" and "Delete" links removed.  Message date, sender, and subject for each message are now links which will display the message, if clicked.  Delete occurs by checking checkbox, and clicking "Go" (default action for checked items in folder is delete).
  
  Number of pages required for display of folder contents now correct when the total number of messages is an exact multiple of the number to display per page.
  
  Some sanity cheecking that destination folder for messages being moved is a user-defined folder.  
  
  
--raeburn1166400990
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20061217191630.txt"

Index: loncom/interface/lonmsgdisplay.pm
diff -u loncom/interface/lonmsgdisplay.pm:1.52 loncom/interface/lonmsgdisplay.pm:1.53
--- loncom/interface/lonmsgdisplay.pm:1.52	Sun Dec 17 10:52:37 2006
+++ loncom/interface/lonmsgdisplay.pm	Sun Dec 17 19:16:27 2006
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Routines for messaging display
 #
-# $Id: lonmsgdisplay.pm,v 1.52 2006/12/17 15:52:37 raeburn Exp $
+# $Id: lonmsgdisplay.pm,v 1.53 2006/12/18 00:16:27 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -137,11 +137,12 @@
 # ============================================================ List all folders
 
 sub folderlist {
-    my $folder=shift;
+    my ($folder,$msgstatus) = @_;
     my %lt = &Apache::lonlocal::texthash(
                 actn => 'Action',
                 fold => 'Folder',
                 show => 'Show',
+                status => 'Message Status',
                 go   => 'Go',
                 nnff => 'New Name for Folder',
                 newn => 'New Name',
@@ -160,6 +161,10 @@
     );
     $actions{'select_form_order'} = ['view','rename','delete'];
 
+    my %statushash = &get_msgstatus_types();
+
+    $statushash{'select_form_order'} = ['','new','read','replied','forwarded'];
+
     my %permfolders = &get_permanent_folders();
     my $permlist = join("','",sort(keys(%permfolders)));
     my ($permlistkeys,$permlistvals);
@@ -181,7 +186,7 @@
     my $folderlist = join("','",@userorder);
     $folderlist .= "','".$permlistvals;
 
-    $formhash{'select_form_order'} = ['','critical','new',@userorder,'sent','trash'];
+    $formhash{'select_form_order'} = ['','critical',@userorder,'sent','trash'];
     my $output = qq|<script type="text/javascript">
 function folder_choice(targetform,caller) {
     var permfolders_keys = new Array('$permlistkeys');
@@ -242,6 +247,9 @@
 			}
 	       (10,20,50,100,200)).'</select>
      </td>
+     <td align="center"><b>'.$lt{'status'}.'</b><br />'."\n".
+       &Apache::loncommon::select_form($msgstatus,'msgstatus',%statushash).'
+     </td>
      <td align="center"><b>'.$lt{'actn'}.'</b><br />'.
          &Apache::loncommon::select_form('view','folderaction',%actions).'
      </td><td><br />'.
@@ -262,7 +270,7 @@
 </table>'."\n".
     '<input type="hidden" name="sortedby" value="'.$env{'form.sortedby'}.'" />'.
     '<input type="hidden" name="renamed" value="" />'.
-        ($folder=~/^(new|critical)/?'</form>':'');
+        ($folder=~/^critical/?'</form>':'');
     return $output;
 }
 
@@ -270,25 +278,43 @@
     my %permfolders = 
 	&Apache::lonlocal::texthash(''         => 'INBOX',
 				    'trash'    => 'TRASH',
-				    'new'      => 'New Messages Only',
 				    'critical' => 'Critical',
 				    'sent'     => 'Sent Messages',
 				    );
     return %permfolders;
 }
 
+sub get_msgstatus_types {
+    my %statushash = &Apache::lonlocal::texthash(
+                                '' => 'Any',
+                                new => 'Unread',
+                                read => 'Read',
+                                replied => 'Replied to',
+                                forwarded => 'Forwarded',
+    );
+    return %statushash;
+}
+
 sub scrollbuttons {
-    my ($start,$maxdis,$first,$finish,$total)=@_;
+    my ($start,$maxdis,$first,$finish,$total,$msgstatus)=@_;
     unless ($total>0) { return ''; }
     $start++; $maxdis++;$first++;$finish++;
+
+    my %statushash = &get_msgstatus_types();
+    my $status;
+    if ($msgstatus eq '') {
+        $status = &mt('All');
+    } else {
+        $status = $statushash{$msgstatus};
+    }
     return
-   &mt('Page').': '. 
+   '<b>'.&mt('Page').'</b>: '. 
    '<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('Showing messages [_1] through [_2] of [_3]',$first,$finish,$total).'</form>';
+   &mt('<b>[_1] messages</b>: showing messages [_2] through [_3] of [_4].',$status,$first,$finish,$total).'</form>';
 }
 # =============================================================== Status Change
 
@@ -745,7 +771,7 @@
 }
 
 sub sortedmessages {
-    my ($blocked,$startblock,$endblock,$numblocked,$folder) = @_;
+    my ($blocked,$startblock,$endblock,$numblocked,$folder,$msgstatus) = @_;
     my $suffix=&Apache::lonmsg::foldersuffix($folder);
     my @messages = &Apache::lonnet::getkeys('nohist_email'.$suffix);
 
@@ -766,6 +792,7 @@
 	my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid)=
 	    &Apache::lonmsg::unpackmsgid($esc_msgid,$folder,undef,
 					 \%status_cache);
+        next if ($msgstatus ne '' && $msgstatus ne $status);
         my $description = &get_course_desc($fromcid,\%descriptions);
 	my @temp1 = ($sendtime,$shortsubj,$fromname,$fromdomain,$status,
 		     $esc_msgid,$description);
@@ -861,148 +888,111 @@
     }
 }
 
-# ======================================================== Display new messages
-
-
-sub disnew {
-    my $r=shift;
-    my %lt=&Apache::lonlocal::texthash(
-				       'nm' => 'New Messages',
-				       'su' => 'Subject',
-                                       'co' => 'Course',
-				       'da' => 'Date',
-				       'us' => 'Username',
-				       'op' => 'Open',
-				       'do' => 'Domain'
-				       );
-    my @msgids = sort(&Apache::lonnet::getkeys('nohist_email'));
-    my @newmsgs;
-    my %setters = ();
-    my %blocked = ();
-    my $numblocked = 0;
-    # Check for blocking of display because of scheduled online exams.
-    my ($startblock,$endblock) = &Apache::loncommon::blockcheck(\%setters,'com');
-    my %status_cache = 
-	&Apache::lonnet::get('email_status',\@msgids);
-    my %descriptions;
-    foreach my $id (@msgids) {
-	my $msgid=&escape($id);
-        my ($sendtime,$shortsubj,$fromname,$fromdom,$status,$fromcid)=
-	    &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') {
-                if ($numsendtime >= $startblock && ($numsendtime <= $endblock && $endblock > 0) ) {
-                    $blocked{$id} = 'ON';
-                    $numblocked ++;
-                } else {
-                    push(@newmsgs, { 
-                        msgid    => $msgid,
-                        sendtime => $sendtime,
-                        shortsub => $shortsubj,
-                        from     => $fromname,
-                        fromdom  => $fromdom,
-                        course   => $description, 
-		    });
-                }
-            }
-        }
-    }
-    if ($#newmsgs >= 0) {
-        $r->print(<<TABLEHEAD);
-<h2>$lt{'nm'}</h2>
-<table class="LC_mail_list"><tr><th>&nbsp;</th>
-<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 class="LC_mail_new">
-<td><a href="/adm/email?dismode=new&amp;display=$msg->{'msgid'}">$lt{'op'}</a></td>
-ENDLINK
-            foreach my $item ('sendtime','from','fromdom','shortsub','course') {
-                $r->print("<td>$msg->{$item}</td>");
-            }
-            $r->print("</tr>");
-        }
-        $r->print('</table>');
-    } elsif ($numblocked == 0) {
-        $r->print("<h3>".&mt('You have no unread messages')."</h3>");
-    }
-    if ($numblocked > 0) {
-        my $beginblock = &Apache::lonlocal::locallocaltime($startblock);
-        my $finishblock = &Apache::lonlocal::locallocaltime($endblock);
-        $r->print('<h3>'.&mt('You have [quant,_1,blocked unread message,blocked unread messages].',$numblocked).'</h3>'."\n".
-                 &mt('[quant,_1,message is,messages are] not viewable because display of LON-CAPA messages sent to you by other students between [_2] and [_3] is currently being blocked because of online exams.',$numblocked,$beginblock,$finishblock).'<br />'."\n".
-                 &Apache::loncommon::build_block_table($startblock,$endblock,
-                                                       \%setters));
-    }
-}
-
-
 # ======================================================== Display all messages
 
 sub disall {
-    my ($r,$folder)=@_;
-    $r->print(&folderlist($folder));
-    if ($folder eq 'new') {
-	&disnew($r);
-    } elsif ($folder eq 'critical') {
+    my ($r,$folder,$msgstatus)=@_;
+    $r->print(&folderlist($folder,$msgstatus));
+    if ($folder eq 'critical') {
 	&discrit($r);
     } else {
-	&disfolder($r,$folder);
+	&disfolder($r,$folder,$msgstatus);
     }
 }
 
 # ============================================================ Display a folder
 
 sub disfolder {
-    my ($r,$folder)=@_;
+    my ($r,$folder,$msgstatus)=@_;
+    my %statushash = &get_msgstatus_types();
     my %blocked = ();
     my %setters = ();
     my $numblocked = 0;
     my ($startblock,$endblock) = &Apache::loncommon::blockcheck(\%setters,'com');
+    my %lt = &Apache::lonlocal::texthash(
+                      sede => 'Select a destination folder to which the messages will be moved.',
+                      nome => 'No messages have been selected to apply ths action to.',
+                      chec => 'Check the checkbox for at least one message.',  
+    );
     $r->print(<<ENDDISHEADER);
 <script type="text/javascript">
     function checkall() {
-	for (i=0; i<document.forms.disall.elements.length; i++) {
-            if 
-          (document.forms.disall.elements[i].name.indexOf('delmark_')==0) {
-	      document.forms.disall.elements[i].checked=true;
-            }
+	for (i=0; i<document.forms.disall.delmark.length; i++) {
+	    document.forms.disall.delmark[i].checked=true;
         }
     }
 
     function uncheckall() {
-	for (i=0; i<document.forms.disall.elements.length; i++) {
-            if 
-          (document.forms.disall.elements[i].name.indexof('delmark_')==0) {
-	      document.forms.disall.elements[i].checked=false;
+	for (i=0; i<document.forms.disall.delmark.length; i++) {
+	    document.forms.disall.delmark[i].checked=false;
+        }
+    }
+    function checkfoldermove() {
+        if (document.disall.checkedaction.options[document.disall.checkedaction.selectedIndex].value == 'markedmove') {
+            if (document.disall.movetofolder.options[document.disall.movetofolder.selectedIndex].value == "") {
+                alert("$lt{'sede'}");
+                return;
             }
         }
+        return; 
     }
+
+    function validate_checkedaction() {
+        document.disall.markedaction.value = document.disall.checkedaction.options[document.disall.checkedaction.selectedIndex].value;
+        if (document.disall.checkedaction.options[document.disall.checkedaction.selectedIndex].value == 'markedmove') {
+            if (document.disall.movetofolder.options[document.disall.movetofolder.selectedIndex].value == "") {
+                alert("$lt{'sede'}");
+                return;
+            } 
+        }
+        var checktotal = 0;
+        for (var i=0; i<document.forms.disall.delmark.length; i++) {
+            if (document.forms.disall.delmark[i].checked) {
+                checktotal ++;
+            }
+        }
+        if (checktotal == 0) {
+            alert("$lt{'nome'}\\n$lt{'chec'}");
+            return;
+        }
+        document.disall.submit();
+    }
+
 </script>
 ENDDISHEADER
+    my %gotfolders = &Apache::lonmsg::get_user_folders();
+    my %userfolders;
     my $fsqs='&folder='.$folder;
-    my @temp=&sortedmessages(\%blocked,$startblock,$endblock,\$numblocked,$folder);
+    my @temp=&sortedmessages(\%blocked,$startblock,$endblock,\$numblocked,$folder,$msgstatus);
     my $totalnumber=$#temp+1;
-    unless ($totalnumber>0) {
-	$r->print('<h2>'.&mt('Empty Folder').'</h2>');
+    if ($totalnumber < 1) {
+        if ($msgstatus eq '') {
+	    $r->print('<h2>'.&mt('Empty Folder').'</h2>');
+        } elsif ($msgstatus eq 'replied') {
+            $r->print('<h2>'.&mt('You have not replied to any messages in this folder.').'</h2>');
+        } else { 
+            $r->print('<h2>'.&mt('There are no [_1] messages in this folder',lc($statushash{$msgstatus})).'</h2>');
+        }
 	return;
     }
     unless ($interdis) {
 	$interdis=20;
     }
     my $number=int($totalnumber/$interdis);
+    if ($interdis) {
+        if ($totalnumber%$interdis == 0) {
+            $number--; 
+        }
+    }
+
     if (($startdis<0) || ($startdis>$number)) { $startdis=$number; }
     my $firstdis=$interdis*$startdis;
     if ($firstdis>$#temp) { $firstdis=$#temp-$interdis+1; }
     my $lastdis=$firstdis+$interdis-1;
     if ($lastdis>$#temp) { $lastdis=$#temp; }
-    $r->print(&scrollbuttons($startdis,$number,$firstdis,$lastdis,$totalnumber));
+    $r->print(&scrollbuttons($startdis,$number,$firstdis,$lastdis,$totalnumber,$msgstatus));
     $r->print('<form method="post" name="disall" action="/adm/email">'.
-	      '<table class="LC_mail_list"><tr><th colspan="3">&nbsp;</th><th>');
+	      '<table class="LC_mail_list"><tr><th colspan="1">&nbsp;</th><th>');
     if ($env{'form.sortedby'} eq "revdate") {
 	$r->print('<a href = "?sortedby=date'.$fsqs.'">'.&mt('Date').'</a></th>');
     } else {
@@ -1069,14 +1059,28 @@
 		    $dis_domain = join('<br />',@{$content{'recdomain'}});
 		}
 	    }
-	    $r->print('<td><input type="checkbox" name="delmark_'.$origID.'" /></td><td><a href="/adm/email?display='.$origID.$sqs. 
-		      '">'.&mt('Open').'</a></td><td>'.
-		      ($folder ne 'trash'?'<a href="/adm/email?markdel='.$origID.$sqs.
-		      '">'.&mt('Delete'):'&nbsp').'</a></td>'.
-		      '<td>'.&Apache::lonlocal::locallocaltime($sendtime).'</td><td>'.
-		      $dis_name.'</td><td>'.$dis_domain.'</td><td>'.
-		      $shortsubj.'</td><td>'.
-                      $description.'</td><td>'.$status.'</td></tr>'."\n");
+            my $localsenttime = &Apache::lonlocal::locallocaltime($sendtime);
+            my $count = $n +1;
+	    $r->print('<td align="right"><nobr>'.(($status eq 'new')?'<b>':'').
+                      $count.'.'.(($status eq 'new')?'</b>':'').'&nbsp;'.
+                      '<input type="checkbox" name="delmark"'. 
+                      ' value="'.$origID.'" /></nobr></td>');
+            foreach my $item ($localsenttime,$dis_name,$dis_domain,$shortsubj) {
+                $r->print('<td>'.(($status eq 'new')?'<b>':'').
+                          '<a href="/adm/email?display='.$origID.$sqs.'">'.
+                          $item.(($status eq 'new')?'</b>':'').'</td>');
+            }
+            my $showstatus;
+            my %statushash = &get_msgstatus_types();
+            if ($status eq '') {
+                $showstatus = '';
+            } else {
+                $showstatus = $statushash{$status};
+            }
+	    $r->print('<td>'.(($status eq 'new')?'<b>':'').$description.
+                      (($status eq 'new')?'</b>':'').'</td><td>'.
+                      (($status eq 'new')?'<b>':'').$showstatus.
+                      (($status eq 'new')?'</b>':'').'</td></tr>'."\n");
 	} elsif ($status eq 'deleted') {
 # purge
 	    my ($result,$msg) = 
@@ -1084,25 +1088,49 @@
 	    
 	}
     }   
-    $r->print("</table>\n<p>".
-  '<a href="javascript:checkall()">'.&mt('Check All').'</a>&nbsp;'.
-  '<a href="javascript:uncheckall()">'.&mt('Uncheck All').'</a></p>'.
-  '<input type="hidden" name="sortedby" value="'.$env{'form.sortedby'}.'" />');
+    $r->print("</table>\n");
+    $r->print('<table border="0" cellspacing="2" cellpadding="2">
+ <tr>
+  <td>'.
+  '<input type="button" onclick="javascript:checkall()" value="'.&mt('Check All').'" /><br />'."\n".
+  '<input type="button" onclick="javascript:uncheckall()" value="'.&mt('Uncheck All').'" />'."\n".
+  '<input type="hidden" name="sortedby" value="'.$env{'form.sortedby'}.'" /></td><td>&nbsp;</td>'."\n".
+  '<td align="center"><b>'.&mt('Action').'</b><br />'."\n".
+  '  <select name="checkedaction" onchange="javascript:checkfoldermove()">'."\n");
+
     if ($folder ne 'trash') {
-	$r->print(
-	      '<p><input type="submit" name="markeddel" value="'.&mt('Delete Checked').'" /></p>');
+        $r->print('    <option value="markeddel">'.&mt('Delete').'</option>'."\n");
     }
-    $r->print('<p><input type="submit" name="markedmove" value="'.&mt('Move Checked to Folder').'" />');
-    my %gotfolders = &Apache::lonmsg::get_user_folders();
-    my %userfolders;
+    if ($msgstatus ne 'read') {
+        $r->print('    <option value="markedread">'.&mt('Mark Read').'</option>."\n"');
+    }
+    if ($msgstatus ne 'unread') {
+        $r->print('    <option value="markedunread">'.&mt('Mark Unread').'</option>'."\n");
+    }
+    $r->print('   <option value="markedforward">'.&mt('Forward').'</option>'."\n");
+    if (keys(%gotfolders) > 0) {
+        $r->print('   <option value="markedmove">'.&mt('Move to Folder ->').
+                  '</option>');
+    }
+    $r->print("\n".'</select></td>'."\n");
     foreach my $key (keys(%gotfolders)) {
         $userfolders{$key} = $key;
     }
-    $r->print(
-	&Apache::loncommon::select_form('','movetofolder',
-			                %userfolders));
+    if (keys(%gotfolders) > 0) {
+        $r->print('<td align="center"><b>'.&mt('Destination folder').'<b><br />');
+        foreach my $key (keys(%gotfolders)) {
+            $userfolders{$key} = $key;
+        }
+        $userfolders{''} = "";
+        $r->print(&Apache::loncommon::select_form('','movetofolder',%userfolders).
+                  '</td>');
+    }
+    $r->print('<td>&nbsp;</td><td>&nbsp;&nbsp;'.
+              '<input type="button" name="go" value="'.&mt('Go').
+              '" onclick="javascript:validate_checkedaction()"/></td>'."\n".
+              '</tr></table>');
     my $postedstartdis=$startdis+1;
-    $r->print('<input type="hidden" name="folder" value="'.$folder.'" /><input type="hidden" name="startdis" value="'.$postedstartdis.'" /><input type="hidden" name="interdis" value="'.$env{'form.interdis'}.'" /></form>');
+    $r->print('<input type="hidden" name="folder" value="'.$folder.'" /><input type="hidden" name="startdis" value="'.$postedstartdis.'" /><input type="hidden" name="interdis" value="'.$env{'form.interdis'}.'" /><input type="hidden" name="msgstatus" value="'.$msgstatus.'" ><input type="hidden" name="markedaction" value="" /></form>');
     if ($numblocked > 0) {
         my $beginblock = &Apache::lonlocal::locallocaltime($startblock);
         my $finishblock = &Apache::lonlocal::locallocaltime($endblock);
@@ -1116,7 +1144,8 @@
 # ============================================================== Compose output
 
 sub compout {
-    my ($r,$forwarding,$replying,$broadcast,$replycrit,$folder,$dismode)=@_;
+    my ($r,$forwarding,$replying,$broadcast,$replycrit,$folder,$dismode,
+        $multiforward)=@_;
     my $suffix=&Apache::lonmsg::foldersuffix($folder);
     my ($cdom,$cnum,$group,$refarg);
     if (exists($env{'form.group'})) {
@@ -1146,6 +1175,13 @@
     } elsif ($replycrit) {
 	$r->print('<h3>'.&mt('Replying to a Critical Message').'</h3>');
 	$replying=$replycrit;
+    } elsif ($multiforward) {
+        &Apache::lonhtmlcommon::add_breadcrumb
+        ({href=>"/adm/email?folder=".&escape($folder),
+          text=>"Display All Messages"});
+        &printheader($r,'/adm/email?compose=multiforward',
+             'Forwarding Multiple Messages');
+        $r->print(&mt('Each of the <b>[quant,_1,message]</b> you checked will be forwarded to the recipient(s) you select below.',$multiforward).'<br />');
     } else {
 	&printheader($r,'/adm/email?compose=upload',
 	     'Distribute from Uploaded File');
@@ -1162,6 +1198,7 @@
 				       'sb'  => 'Subject',
 				       'ca'  => 'Cancel',
 				       'ma'  => 'Mail',
+                                       'msg' => 'Messages',
                                        'gen' => 'Generate messages from a file',
                                        'gmt' => 'General message text',
                                        'tff' => 'The file format for the uploaded portion of the message is',
@@ -1263,24 +1300,49 @@
         }
     }
     my $latexHelp = Apache::loncommon::helpLatexCheatsheet();
-    if ($broadcast ne 'upload') {
-       $r->print(<<"ENDCOMP");
-<tr><td>$lt{'ad'}:<br /><tt>username:domain,username:domain, ...
-</tt></td><td>
-<input type="text" size="50" name="additionalrec" /></td></tr>
-<tr><td>$lt{'sb'}:</td><td><input type="text" size="50" name="subject" value="$dissub" />
-</td></tr></table>
+    my $subj_size;
+    if ($multiforward) {
+        $r->print(&additional_rec_row(\%lt));
+        $r->print('<tr><td colspan="2">'.
+                  &mt('Unless you choose otherwise:').'<ul><li>'.
+        &mt("The subject in each forwarded message will be <i>'Forwarding:'</i> followed by the original subject.").'</li><li>'.
+        &mt("The message itself will begin with a first line: <i>'Forwarded message from'</i> followed by the original sender's name.").'</li></ul></td></tr>');
+        $func=&mt('Forward');
+        $dissub = &mt('Forwarding').': ';
+        $subj_size = '10';
+        my $extra = '&lt;'.&mt('original subject').'&gt;&nbsp;&nbsp;&nbsp;'.
+                    '<input type="radio" name="showorigsubj" value="1" checked="checked" />'.&mt('Yes').'&nbsp;<input type="radio" name="showorigsubj" value="0" />'.&mt('No');
+        $dismsg = &mt('Forwarded message from ').' ';
+        my $sender = &mt("sender's name");
+        $r->print(&msg_subject_row($dissub,\%lt,$subj_size,$extra));
+        $r->print('<tr><td>'.&mt('Message begins with:').'</td><td><input type="text" name="msgheader" value="'.$dismsg.'" />&nbsp;'.$sender.'&nbsp;&nbsp;&nbsp;<input type="radio" name="showorigsender" value="1" checked="checked" />'.&mt('Yes').'&nbsp;<input type="radio" name="showorigsender" value="0" />'.&mt('No').'<input type="hidden" name="multiforward" value="'.$multiforward.'" /></td></tr>
+</table>
+<br />'.
+$latexHelp.
+&mt("Any new text to display before the text of the original messages:").'<br />
+<textarea name="message" id="message" cols="80" rows="5" wrap="hard">
+</textarea></p><br />');
+        my @to_forward = &Apache::loncommon::get_env_multiple('form.delmark');
+        foreach my $msg (@to_forward) {
+            $r->print('<input type="hidden" name="delmark" value="'.$msg.'" />');
+        }
+        $r->print(&submit_button_row($folder,$dismode,$func.' '.$lt{'msg'},
+                                     \%lt));
+    } elsif ($broadcast ne 'upload') {
+        $subj_size = '50';
+        $r->print(&additional_rec_row(\%lt));
+        $r->print(&msg_subject_row($dissub,\%lt,$subj_size));
+        $r->print(<<"ENDCOMP");
+</table>
 $latexHelp
 <textarea name="message" id="message" cols="80" rows="15" wrap="hard">$dismsg
 </textarea></p><br />
 $dispcrit
 $disbase
-<input type="hidden" name="folder" value="$folder" />
-<input type="hidden" name="dismode" value="$dismode" />
-<input type="submit" name="send" value="$func $lt{'ma'}" />
-<input type="submit" name="cancel" value="$lt{'ca'}" /><hr />
-$citation
 ENDCOMP
+        $r->print(&submit_button_row($folder,$dismode,$func.' '.$lt{'ma'},
+                                     \%lt));
+        $r->print($citation);
         if (exists($env{'form.ref'})) {
             $r->print('<input type="hidden" name="ref" value="'.
                       $env{'form.ref'}.'" />');
@@ -1350,6 +1412,35 @@
     return $output;
 }
 
+sub additional_rec_row {
+    my ($lt) = @_;
+    my $output = <<"ENDADD";
+<tr><td>$lt->{'ad'}:<br /><tt>username:domain,username:domain, ...
+</tt></td><td>
+<input type="text" size="50" name="additionalrec" /></td></tr>
+ENDADD
+    return $output;
+}
+
+sub submit_button_row {
+    my ($folder,$dismode,$sendtext,$lt) = @_;
+    my $output = qq| 
+<input type="hidden" name="folder" value="$folder" />
+<input type="hidden" name="dismode" value="$dismode" />
+<input type="submit" name="send" value="$sendtext" />
+<input type="submit" name="cancel" value="$lt->{'ca'}" /><hr />
+|;
+    return $output;
+}
+
+sub msg_subject_row {
+    my ($dissub,$lt,$subj_size,$extra) = @_;
+    my $output = '<tr><td>'.$lt->{'sb'}.':</td><td><input type="text" size="'.
+                 $subj_size.'" name="subject" value="'.$dissub.'" />'.$extra.
+                 '</td></tr>';
+    return $output;
+}
+
 sub retrieve_instructor_comments {
     my ($user,$domain)=@_;
     my $target=$env{'form.grade_target'};
@@ -1836,7 +1927,7 @@
 # ----------------------------------------------------------- Display a message
 
 sub displaymessage {
-    my ($r,$msgid,$folder)=@_;
+    my ($r,$msgid,$folder,$msgstatus)=@_;
     my $suffix=&Apache::lonmsg::foldersuffix($folder);
     my %blocked = ();
     my %setters = ();
@@ -1845,7 +1936,7 @@
 
 # info to generate "next" and "previous" buttons and check if message is blocked
     my ($startblock,$endblock) = &Apache::loncommon::blockcheck(\%setters,'com');
-    my @messages=&sortedmessages(\%blocked,$startblock,$endblock,\$numblocked,$folder);
+    my @messages=&sortedmessages(\%blocked,$startblock,$endblock,\$numblocked,$folder,$msgstatus);
     if ( $blocked{$msgid} eq 'ON' ) {
         &printheader($r,'/adm/email',&mt('Display a Message'));
         $r->print(&mt('You attempted to display a message that is currently blocked because you are enrolled in one or more courses for which there is an ongoing online exam.'));
@@ -1881,7 +1972,6 @@
 	      '<td><a href="/adm/email?markdel='.&escape($msgid).$sqs.
 	      '"><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>');
     if ($counter > 0){
 	$r->print('<td><a href="/adm/email?display='.$messages[$counter-1]->[5].$sqs.
@@ -2047,10 +2137,12 @@
         $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
     }
     if ($env{'form.send'}) {
-        if ($group eq '') {
-	    &printheader($r,'','Messages being sent.');
-        } else {
-            $r->print(&groupmail_header('sending',$group));
+        if (!$env{'form.multiforward'}) { 
+            if ($group eq '') {
+	        &printheader($r,'','Messages being sent.');
+            } else {
+                $r->print(&groupmail_header('sending',$group));
+            }
         }
 	$r->rflush();
 	my %content=();
@@ -2228,20 +2320,24 @@
     } else {
 	&printheader($r,'','No messages sent.'); 
     }
-    if ($sendstatus=~/^(\s*(?:ok|con_delayed)\s*)*$/) {
-	$r->print('<br /><span class="LC_success">'.&mt('Completed.').'</span>');
-	if ($env{'form.displayedcrit'}) {
-	    &discrit($r);
-        }
-        if ($group ne '') {
-            $r->print(&groupmail_sent($group,$cdom,$cnum)); 
-	} else {
-	    &Apache::loncommunicate::menu($r);
-	}
-    } else {
-	$r->print('<p><span class="LC_error">'.&mt('Could not deliver message').'</span> '.
+    if (!$env{'form.multiforward'}) { 
+        if ($sendstatus=~/^(\s*(?:ok|con_delayed)\s*)*$/) {
+	    $r->print('<br /><span class="LC_success">'.&mt('Completed.').
+                      '</span>');
+	    if ($env{'form.displayedcrit'}) {
+	        &discrit($r);
+            }
+            if ($group ne '') {
+                $r->print(&groupmail_sent($group,$cdom,$cnum)); 
+	    } else {
+	        &Apache::loncommunicate::menu($r);
+	    }
+        } else {
+	    $r->print('<p><span class="LC_error">'.&mt('Could not deliver message').'</span> '.
 		  &mt('Please use the browser "Back" button and correct the recipient addresses '."($sendstatus)").'</p>');
+        }
     }
+    return $sendstatus;
 }
 
 # ===================================================================== Handler
@@ -2261,7 +2357,8 @@
         ['display','replyto','forward','markread','markdel','markunread',
          'sendreply','compose','sendmail','critical','recname','recdom',
          'recordftf','sortedby','block','folder','startdis','interdis',
-	 'showcommentbaseurl','dismode','group','subject','text','ref']);
+	 'showcommentbaseurl','dismode','group','subject','text','ref',
+         'msgstatus']);
     $sqs='&sortedby='.$env{'form.sortedby'};
 
 # ------------------------------------------------------ They checked for email
@@ -2295,9 +2392,11 @@
     }
 
 # --------------------------------------------------------------------- Display
-
+    my $msgstatus = $env{'form.msgstatus'};
     $startdis=$env{'form.startdis'};
-    $startdis--;
+    if ($startdis ne '') {
+        $startdis--;
+    }
     unless ($startdis) { $startdis=0; }
 
     $interdis=$env{'form.interdis'};
@@ -2322,7 +2421,7 @@
 # --------------------------------------------------------------- Render Output
 
     if ($env{'form.display'}) {
-	&displaymessage($r,$env{'form.display'},$folder);
+	&displaymessage($r,$env{'form.display'},$folder,$msgstatus);
     } elsif ($env{'form.replyto'}) {
 	&compout($r,'',$env{'form.replyto'},undef,undef,$folder,$dismode);
     } elsif ($env{'form.confirm'}) {
@@ -2359,47 +2458,82 @@
 		      '<p class="LC_error">'.$msg."</p>\n");
 	}
 	&Apache::loncommunicate::menu($r);
-	&disall($r,($folder?$folder:$dismode));
-    } elsif ($env{'form.markedmove'}) {
-	my ($total,$failed,@failed_msg)=(0,0);
-	foreach my $key (keys(%env)) {
-	    if ($key=~/^form\.delmark_(.*)$/) {
-		my ($result,$msg) =
-		    &movemsg(&unescape($1),$folder,
-			     $env{'form.movetofolder'});
-		if ($result) {
+	&disall($r,($folder?$folder:$dismode),$msgstatus);
+    } elsif ($env{'form.markedaction'} eq 'markedforward') {
+        my $total = 0;
+        my @to_forward = &Apache::loncommon::get_env_multiple('form.delmark');
+        foreach my $msgid (@to_forward) {
+            &statuschange(&unescape($msgid),'forwarded',$folder);
+            $total ++;
+        }
+        if ($total > 0) {
+            &compout($r,undef,undef,undef,undef,$folder,$dismode,$total);
+        }
+    } elsif ($env{'form.markedaction'} eq 'markedread') {
+        my $total = 0;
+        my @to_markread = &Apache::loncommon::get_env_multiple('form.delmark');
+        foreach my $msgid (@to_markread) {
+            &statuschange(&unescape($msgid),'read',$folder);
+            $total ++;
+        }
+        &printheader($r,'','Marked Messages Read');
+        $r->print(&mt('Marked [_1] message(s) read',$total).'<p>');
+        &Apache::loncommunicate::menu($r);
+        &disall($r,($folder?$folder:$dismode),$msgstatus);
+    } elsif ($env{'form.markedaction'} eq 'markedunread') {
+        my $total = 0;
+        my @to_markunread = &Apache::loncommon::get_env_multiple('form.delmark');
+        foreach my $msgid (@to_markunread) {
+            &statuschange(&unescape($msgid),'new',$folder);
+            $total ++;
+        }
+        &printheader($r,'','Marked Messages Unread');
+        $r->print(&mt('Marked [_1] message(s) unread',$total).'<p>');
+        &Apache::loncommunicate::menu($r);
+        &disall($r,($folder?$folder:$dismode),$msgstatus);
+    } elsif ($env{'form.markedaction'} eq 'markedmove') {
+        my $destfolder = $env{'form.movetofolder'};
+        my %gotfolders = &Apache::lonmsg::get_user_folders();
+        &printheader($r,'','Moved Messages');
+        if (!defined($gotfolders{$destfolder})) {
+            $r->print(&mt('Destination folder [_1] is not a valid folder',
+                      $destfolder));
+        } else {
+	    my ($total,$failed,@failed_msg)=(0,0);
+            my @to_move = &Apache::loncommon::get_env_multiple('form.delmark');
+            foreach my $msgid (@to_move) {
+	        my ($result,$msg) = &movemsg(&unescape($msgid),$folder,
+			                     $env{'form.movetofolder'});
+	        if ($result) {
 		    $total++;
-		} else {
+	        } else {
 		    $failed++;
 		    push(@failed_msg,$msg);
-		}
+	        }
 	    }
-	}
-	&printheader($r,'','Moved Messages');
-	if ($failed) {
-	    $r->print('<p class="LC_error">
+	    if ($failed) {
+	        $r->print('<p class="LC_error">
                           '.&mt('Failed to move [_1] message(s)',$failed).
 		      '</p>');
-	    $r->print('<p class="LC_error">'.
-		      join("</p>\n<p class=\"LC_error\">",@failed_msg).
-		      "</p>\n");
-	}
-	$r->print(&mt('Moved [_1] message(s)',$total).'<p>');
+	        $r->print('<p class="LC_error">'.
+	   	          join("</p>\n<p class=\"LC_error\">",@failed_msg).
+		          "</p>\n");
+	    }
+	    $r->print(&mt('Moved [_1] message(s)',$total).'<p>');
+        }
 	&Apache::loncommunicate::menu($r);
-	&disall($r,($folder?$folder:$dismode));
-    } elsif ($env{'form.markeddel'}) {
+	&disall($r,($folder?$folder:$dismode),$msgstatus);
+    } elsif ($env{'form.markedaction'} eq 'markeddel') {
 	my ($total,$failed,@failed_msg)=(0,0);
-	foreach my $key (keys(%env)) {
-	    if ($key=~/^form\.delmark_(.*)$/) {
-		my ($result,$msg) = 
-		    &statuschange(&unescape($1),'deleted',
-				  $folder);
-		if ($result) {
-		    $total++;
-		} else {
-		    $failed++;
-		    push(@failed_msg,$msg);
-		}
+        my @to_delete = &Apache::loncommon::get_env_multiple('form.delmark');
+        foreach my $msgid (@to_delete) {
+	    my ($result,$msg) = &statuschange(&unescape($msgid),'deleted', 
+				              $folder);
+	    if ($result) {
+	        $total++;
+	    } else {
+	        $failed++;
+		push(@failed_msg,$msg);
 	    }
 	}
 	&printheader($r,'','Deleted Messages');
@@ -2413,12 +2547,12 @@
 	}
 	$r->print(&mt('Deleted [_1] message(s)',$total).'<p>');
 	&Apache::loncommunicate::menu($r);
-	&disall($r,($folder?$folder:$dismode));
+	&disall($r,($folder?$folder:$dismode),$msgstatus);
     } elsif ($env{'form.markunread'}) {
 	&printheader($r,'','Marked Message as Unread');
 	&statuschange($env{'form.markunread'},'new');
 	&Apache::loncommunicate::menu($r);
-	&disall($r,($folder?$folder:$dismode));
+	&disall($r,($folder?$folder:$dismode),$msgstatus);
     } elsif ($env{'form.compose'}) {
 	&compout($r,'','',$env{'form.compose'});
     } elsif ($env{'form.recordftf'}) {
@@ -2426,7 +2560,63 @@
     } elsif ($env{'form.block'}) {
         &examblock($r,$env{'form.block'});
     } elsif ($env{'form.sendmail'}) {
-	&sendoffmail($r,$folder);
+        if ($env{'form.multiforward'}) {
+            &printheader($r,'','Messages being sent.');
+            my $fixed_subj = $env{'form.subject'};
+            my $suffix=&Apache::lonmsg::foldersuffix($folder);
+            my (%sendresult,%forwardok,%forwardfail,$fwdcount);
+            my @to_forward = &Apache::loncommon::get_env_multiple('form.delmark');
+            foreach my $item (@to_forward) {
+                my $msgid=&unescape($item);
+                my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]);
+                my %content=&Apache::lonmsg::unpackagemsg($message{$msgid},1);
+                if ($env{'form.showorigsubj'}) {
+                    $env{'form.subject'} = $fixed_subj.$content{'subject'};
+                } else {
+                    $env{'form.subject'} = '';
+                }
+                my $uname = $content{'sendername'};
+                my $udom = $content{'senderdomain'};
+                &statuschange($msgid,'forwarded',$folder);
+                if ($env{'form.showorigsender'}) {
+                    $env{'form.message'} = $env{'form.msgheader'}.' '.
+                        &Apache::loncommon::plainname($uname,$udom).' ('.
+                                           $uname.':'.$udom.')';
+                }
+                $env{'form.message'} .= "\n\n-- Forwarded message --\n\n".
+                                        $content{'message'};
+                $fwdcount ++;
+                $r->print($fwdcount.': '); 
+                $sendresult{$msgid} = &sendoffmail($r,$folder);
+                $r->print('<br />');
+            }
+            foreach my $key (keys(%sendresult)) {
+                if ($sendresult{$key} =~/^(\s*(?:ok|con_delayed)\s*)*$/) {
+                    $forwardok{$key} = $sendresult{$key};
+                } else {
+                    $forwardfail{$key} = $sendresult{$key}; 
+                }
+            }
+            if (keys(%forwardok) > 0) {
+                my $count = keys(%forwardok);
+                $r->print('<br /><span class="LC_success">'.
+                          &mt('[quant,_1,message] forwarded.',$count).
+                          '</span>');
+            }
+            if (keys(%forwardfail) > 0) {
+                my $count = keys(%forwardfail);
+                $r->print('<p><span class="LC_error">'.
+                          &mt('Could not forward [quant,_1,message].',$count).
+                          '</span> ');
+                foreach my $key (keys(%forwardfail)) {
+                    $r->print(&mt('Could not deliver forwarded message.').'</span> '.
+                              &mt('The recipient addresses may need to be corrected').' ('.$forwardfail{$key}.').<br /><br />');
+                }
+            }
+            &Apache::loncommunicate::menu($r);
+        } else {
+	    &sendoffmail($r,$folder);
+        }
 	if ($env{'form.storebasecomment'}) {
 	    &storecomment($r);
         }
@@ -2438,7 +2628,7 @@
 				      $env{'form.message'},'/adm/communicate','public');
 	}
 	if ((!exists($env{'form.group'})) && (!$env{'form.displayedcrit'})) {
-	    &disall($r,($folder?$folder:$dismode));
+	    &disall($r,($folder?$folder:$dismode),$msgstatus);
 	}
     } elsif ($env{'form.newfolder'}) {
 	&printheader($r,'','New Folder');
@@ -2452,7 +2642,7 @@
             $showfolder = $folder;
         }
         &Apache::loncommunicate::menu($r);
-	&disall($r,$showfolder);
+	&disall($r,$showfolder,$msgstatus);
     } elsif ($env{'form.showcommentbaseurl'}) {
 	&storedcommentlisting($r);
     } elsif ($env{'form.folderaction'} eq 'delete') {
@@ -2466,7 +2656,7 @@
             $showfolder = $folder;
         }
         &Apache::loncommunicate::menu($r);
-        &disall($r,$showfolder);
+        &disall($r,$showfolder,$msgstatus);
     } elsif ($env{'form.folderaction'} eq 'rename') {
         &printheader($r,'','Renamed Folder');
         my $showfolder = $env{'form.renamed'};
@@ -2478,11 +2668,11 @@
             $showfolder = $folder;
         }
         &Apache::loncommunicate::menu($r);
-        &disall($r,$showfolder);
+        &disall($r,$showfolder,$msgstatus);
     } else {
 	&printheader($r,'','Display All Messages');
 	&Apache::loncommunicate::menu($r);
-	&disall($r,($folder?$folder:$dismode));
+	&disall($r,($folder?$folder:$dismode),$msgstatus);
     }
     $r->print(&Apache::loncommon::end_page());
     return OK;

--raeburn1166400990--