Diff for /loncom/interface/lonmsg.pm between versions 1.89 and 1.125

version 1.89, 2004/03/01 16:19:45 version 1.125, 2004/12/15 02:35:17
Line 74  email program, so they have full access Line 74  email program, so they have full access
 interface, or other features they may wish to use in response to the  interface, or other features they may wish to use in response to the
 student's query.  student's query.
   
   =item * B<Blocking>: LON-CAPA can block display of e-mails that are 
   sent to a student during an online exam. A course coordinator or
   instructor can set an open and close date/time for scheduled online
   exams in a course. If a user uses the LON-CAPA internal messaging 
   system to display e-mails during the scheduled blocking event,  
   display of all e-mail sent during the blocking period will be 
   suppressed, and a message of explanation, including details of the 
   currently active blocking periods will be displayed instead. A user 
   who has a course coordinator or instructor role in a course will be
   unaffected by any blocking periods for the course, unless the user
   also has a student role in the course, AND has selected the student role.
   
 =back  =back
   
 Users can ask LON-CAPA to forward messages to conventional e-mail  Users can ask LON-CAPA to forward messages to conventional e-mail
Line 101  use Apache::lontexconvert(); Line 113  use Apache::lontexconvert();
 use HTML::Entities();  use HTML::Entities();
 use Mail::Send;  use Mail::Send;
 use Apache::lonlocal;  use Apache::lonlocal;
   use Apache::loncommunicate;
   
 # Querystring component with sorting type  # Querystring component with sorting type
 my $sqs;  my $sqs;
   my $startdis;
   my $interdis;
   
 # ===================================================================== Package  # ===================================================================== Package
   
 sub packagemsg {  sub packagemsg {
     my ($subject,$message,$citation,$baseurl,$attachmenturl)=@_;      my ($subject,$message,$citation,$baseurl,$attachmenturl,
     $message =&HTML::Entities::encode($message);   $recuser,$recdomain)=@_;
     $citation=&HTML::Entities::encode($citation);      $message =&HTML::Entities::encode($message,'<>&"');
     $subject =&HTML::Entities::encode($subject);      $citation=&HTML::Entities::encode($citation,'<>&"');
       $subject =&HTML::Entities::encode($subject,'<>&"');
     #remove machine specification      #remove machine specification
     $baseurl =~ s|^http://[^/]+/|/|;      $baseurl =~ s|^http://[^/]+/|/|;
     $baseurl =&HTML::Entities::encode($baseurl);      $baseurl =&HTML::Entities::encode($baseurl,'<>&"');
     #remove machine specification      #remove machine specification
     $attachmenturl =~ s|^http://[^/]+/|/|;      $attachmenturl =~ s|^http://[^/]+/|/|;
     $attachmenturl =&HTML::Entities::encode($attachmenturl);      $attachmenturl =&HTML::Entities::encode($attachmenturl,'<>&"');
   
     my $now=time;      my $now=time;
     $msgcount++;      $msgcount++;
Line 143  sub packagemsg { Line 159  sub packagemsg {
    '<role>'.$ENV{'request.role'}.'</role>'.     '<role>'.$ENV{'request.role'}.'</role>'.
    '<resource>'.$ENV{'request.filename'}.'</resource>'.     '<resource>'.$ENV{'request.filename'}.'</resource>'.
            '<msgid>'.$msgid.'</msgid>'.             '<msgid>'.$msgid.'</msgid>'.
      '<recuser>'.$recuser.'</recuser>'.
      '<recdomain>'.$recdomain.'</recdomain>'.
    '<message>'.$message.'</message>';     '<message>'.$message.'</message>';
     if (defined($citation)) {      if (defined($citation)) {
  $result.='<citation>'.$citation.'</citation>';   $result.='<citation>'.$citation.'</citation>';
Line 171  sub unpackagemsg { Line 189  sub unpackagemsg {
        }         }
     }      }
     if ($content{'attachmenturl'}) {      if ($content{'attachmenturl'}) {
        my ($fname,$ft)=($content{'attachmenturl'}=~/\/(\w+)\.(\w+)$/);         my ($fname)=($content{'attachmenturl'}=~m|/([^/]+)$|);
        if ($notoken) {         if ($notoken) {
    $content{'message'}.='<p>'.&mt('Attachment').': <tt>'.$fname.'.'.$ft.'</tt>';     $content{'message'}.='<p>'.&mt('Attachment').': <tt>'.$fname.'</tt>';
        } else {         } else {
    $content{'message'}.='<p>'.&mt('Attachment').': <a href="'.     &Apache::lonnet::allowuploaded('/adm/msg',
        &Apache::lonnet::tokenwrapper($content{'attachmenturl'}).    $content{'attachmenturl'});
        '"><tt>'.$fname.'.'.$ft.'</tt></a>';     $content{'message'}.='<p>'.&mt('Attachment').
          ': <a href="'.$content{'attachmenturl'}.'"><tt>'.
          $fname.'</tt></a>';
        }         }
     }      }
     return %content;      return %content;
Line 186  sub unpackagemsg { Line 206  sub unpackagemsg {
 # ======================================================= Get info out of msgid  # ======================================================= Get info out of msgid
   
 sub unpackmsgid {  sub unpackmsgid {
     my $msgid=&Apache::lonnet::unescape(shift);      my ($msgid,$folder)=@_;
       $msgid=&Apache::lonnet::unescape($msgid);
       my $suffix=&foldersuffix($folder);
     my ($sendtime,$shortsubj,$fromname,$fromdomain)=split(/\:/,      my ($sendtime,$shortsubj,$fromname,$fromdomain)=split(/\:/,
                           &Apache::lonnet::unescape($msgid));                            &Apache::lonnet::unescape($msgid));
     my %status=&Apache::lonnet::get('email_status',[$msgid]);      my %status=&Apache::lonnet::get('email_status'.$suffix,[$msgid]);
     if ($status{$msgid}=~/^error\:/) { $status{$msgid}=''; }      if ($status{$msgid}=~/^error\:/) { $status{$msgid}=''; }
     unless ($status{$msgid}) { $status{$msgid}='new'; }      unless ($status{$msgid}) { $status{$msgid}='new'; }
     return ($sendtime,$shortsubj,$fromname,$fromdomain,$status{$msgid});      return ($sendtime,$shortsubj,$fromname,$fromdomain,$status{$msgid});
Line 204  sub sendemail { Line 226  sub sendemail {
     my $msg = new Mail::Send;      my $msg = new Mail::Send;
     $msg->to($to);      $msg->to($to);
     $msg->subject('[LON-CAPA] '.$subject);      $msg->subject('[LON-CAPA] '.$subject);
     if (my $fh = $msg->open('smtp',Server => 'localhost')) {      my %oldENV=%ENV;
       undef(%ENV);
       if (my $fh = $msg->open()) {
  print $fh $body;   print $fh $body;
  $fh->close;   $fh->close;
     }      }
       %ENV=%oldENV;
       undef(%oldENV);
 }  }
   
 # ==================================================== Send notification emails  # ==================================================== Send notification emails
Line 426  sub user_normal_msg_raw { Line 452  sub user_normal_msg_raw {
     my $homeserver=&Apache::lonnet::homeserver($user,$domain);      my $homeserver=&Apache::lonnet::homeserver($user,$domain);
     if ($homeserver ne 'no_host') {      if ($homeserver ne 'no_host') {
        ($msgid,$message)=&packagemsg($subject,$message,$citation,$baseurl,         ($msgid,$message)=&packagemsg($subject,$message,$citation,$baseurl,
                                      $attachmenturl);                                       $attachmenturl,$user,$domain);
   # Store in user folder
        $status=&Apache::lonnet::critical(         $status=&Apache::lonnet::critical(
            'put:'.$domain.':'.$user.':nohist_email:'.             'put:'.$domain.':'.$user.':nohist_email:'.
            &Apache::lonnet::escape($msgid).'='.             &Apache::lonnet::escape($msgid).'='.
            &Apache::lonnet::escape($message),$homeserver);             &Apache::lonnet::escape($message),$homeserver);
   # Save new message received time
        &Apache::lonnet::put         &Apache::lonnet::put
                          ('email_status',{'recnewemail'=>time},$domain,$user);                           ('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'});
     } else {      } else {
        $status='no_host';         $status='no_host';
     }      }
Line 479  sub user_normal_msg { Line 513  sub user_normal_msg {
 }  }
   
   
   # ============================================================ List all folders
   
   sub folderlist {
       my $folder=shift;
       my @allfolders=&Apache::lonnet::getkeys('email_folders');
       if ($allfolders[0]=~/^error:/) { @allfolders=(); }
       return '<form method="post" action="/adm/email">'.
    &mt('Folder').': '.
    &Apache::loncommon::select_form($folder,'folder',
        ('' => &mt('INBOX'),'trash' => &mt('TRASH'),
         'new' => &mt('New Messages Only'),
                                 'critical' => &mt('Critical'),
         'sent' => &mt('Sent Messages'),
         map { $_ => $_ } @allfolders)).
         ' '.&mt('Show').
         '<select name="interdis">'.
         join("\n",map { '<option value="'.$_.'"'.
    ($_==$interdis?' selected="selected"':'').'>'.$_.'</option>' }
      (10,20,50,100,200)).'</select>'.
      '<input type="submit" value="'.&mt('View Folder').'" /><br />'.
       '<input type="hidden" name="sortedby" value="'.$ENV{'form.sortedby'}.'" />'.
         ($folder=~/^(new|critical)/?'</form>':'');
   }
   
   sub scrollbuttons {
       my ($start,$maxdis,$first,$finish,$total)=@_;
       unless ($total>0) { return ''; }
       $start++; $maxdis++;$first++;$finish++;
       return 
      '<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>';
   }
   
   # =============================================================== Folder suffix
   
   sub foldersuffix {
       my $folder=shift;
       unless ($folder) { return ''; }
       return '_'.&Apache::lonnet::escape($folder);
   }
   
 # =============================================================== Status Change  # =============================================================== Status Change
   
 sub statuschange {  sub statuschange {
     my ($msgid,$newstatus)=@_;      my ($msgid,$newstatus,$folder)=@_;
     my %status=&Apache::lonnet::get('email_status',[$msgid]);      my $suffix=&foldersuffix($folder);
       my %status=&Apache::lonnet::get('email_status'.$suffix,[$msgid]);
     if ($status{$msgid}=~/^error\:/) { $status{$msgid}=''; }      if ($status{$msgid}=~/^error\:/) { $status{$msgid}=''; }
     unless ($status{$msgid}) { $status{$msgid}='new'; }      unless ($status{$msgid}) { $status{$msgid}='new'; }
     unless (($status{$msgid} eq 'replied') ||       unless (($status{$msgid} eq 'replied') || 
             ($status{$msgid} eq 'forwarded')) {              ($status{$msgid} eq 'forwarded')) {
  &Apache::lonnet::put('email_status',{$msgid => $newstatus});   &Apache::lonnet::put('email_status'.$suffix,{$msgid => $newstatus});
     }      }
     if (($newstatus eq 'deleted') || ($newstatus eq 'new')) {      if (($newstatus eq 'deleted') || ($newstatus eq 'new')) {
  &Apache::lonnet::put('email_status',{$msgid => $newstatus});   &Apache::lonnet::put('email_status'.$suffix,{$msgid => $newstatus});
       }
   }
   
   # ============================================================= Make new folder
   
   sub makefolder {
       my ($newfolder)=@_;
       if (($newfolder eq 'sent')
        || ($newfolder eq 'critical')
        || ($newfolder eq 'trash')
        || ($newfolder eq 'new')) { return; }
       &Apache::lonnet::put('email_folders',{$newfolder => time});
   }
   
   # ======================================================== Move between folders
   
   sub movemsg {
       my ($msgid,$srcfolder,$trgfolder)=@_;
       my $unmsgid=&Apache::lonnet::unescape($msgid);
       my $srcsuffix=&foldersuffix($srcfolder);
       my $trgsuffix=&foldersuffix($trgfolder);
   
   # Copy message
       my %message=&Apache::lonnet::get('nohist_email'.$srcsuffix,[$msgid]);
       &Apache::lonnet::put('nohist_email'.$trgsuffix,{$msgid => $message{$msgid}});
   
   # Copy status
       my %status=&Apache::lonnet::get('email_status'.$srcsuffix,[$unmsgid]);
       &Apache::lonnet::put('email_status'.$trgsuffix,{$unmsgid => $status{$unmsgid}});
   # See if was deleted -> becomes "read" in trash
       my $currentstatus=(&unpackmsgid($status{$unmsgid}),$srcfolder);
       if ($currentstatus eq 'deleted') {
    &statuschange($msgid,'read',$trgfolder);
     }      }
   # Delete orginals
       &Apache::lonnet::del('nohist_email'.$srcsuffix,[$msgid]);
       &Apache::lonnet::del('email_status'.$srcsuffix,[$unmsgid]);
 }  }
   
 # ======================================================= Display a course list  # ======================================================= Display a course list
   
 sub discourse {  sub discourse {
     my $r=shift;      my $r=shift;
     my %courselist=&Apache::lonnet::dump(      my $classlist = &Apache::loncoursedata::get_classlist();
                    'classlist',  
    $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},  
    $ENV{'course.'.$ENV{'request.course.id'}.'.num'});  
     my $now=time;      my $now=time;
     my %lt=&Apache::lonlocal::texthash('cfa' => 'Check for All',      my %lt=&Apache::lonlocal::texthash('cfa' => 'Check for All',
             'cfs' => 'Check for Section/Group',              'cfs' => 'Check for Section/Group',
             'cfn' => 'Check for None');              'cfn' => 'Check for None');
     $r->print(<<ENDDISHEADER);      $r->print(<<ENDDISHEADER);
 <input type=hidden name=sendmode value=group>  <input type="hidden" name="sendmode" value="group" />
 <script>  <script>
     function checkall() {      function checkall() {
  for (i=0; i<document.forms.compemail.elements.length; i++) {   for (i=0; i<document.forms.compemail.elements.length; i++) {
Line 538  sub discourse { Line 651  sub discourse {
         }          }
     }      }
 </script>  </script>
 <input type=button onClick="checkall()" value="$lt{'cfa'}">&nbsp;  <input type="button" onClick="checkall()" value="$lt{'cfa'}" />&nbsp;
 <input type=button onClick="checksec()" value="$lt{'cfs'}">  <input type="button" onClick="checksec()" value="$lt{'cfs'}" />
 <input type=text size=5 name=chksec>&nbsp;  <input type="text" size="5" name=chksec />&nbsp;
 <input type=button onClick="uncheckall()" value="$lt{'cfn'}">  <input type="button" onClick="uncheckall()" value="$lt{'cfn'}" />
 <p>  <p>
 ENDDISHEADER  ENDDISHEADER
     my %coursepersonnel=      my %coursepersonnel=&Apache::lonnet::get_course_adv_roles();
        &Apache::lonnet::get_course_adv_roles();      $r->print('<table>');
     foreach my $role (sort keys %coursepersonnel) {      foreach my $role (sort keys %coursepersonnel) {
        foreach (split(/\,/,$coursepersonnel{$role})) {          foreach (split(/\,/,$coursepersonnel{$role})) {
    my ($puname,$pudom)=split(/\:/,$_);              my ($puname,$pudom)=split(/\:/,$_);
    $r->print(              $r->print('<tr><td><label>'.
              '<br /><input type="checkbox" name="send_to_&&&&&&_'.                        '<input type="checkbox" name="send_to_&&&&&&_'.
              $puname.':'.$pudom.'" /> '.                        $puname.':'.$pudom.'" /> '.
      &Apache::loncommon::plainname($puname,                        &Apache::loncommon::plainname($puname,$pudom).
                           $pudom).' ('.$_.'), <i>'.$role.'</i>');                        '</label></td>'.
  }                        '<td>('.$_.'),</td><td><i>'.$role.'</i></td></tr>');
           }
     }      }
       $r->print('</table><table>');
     foreach (sort keys %courselist) {      while (my ($student,$info) = each(%$classlist)) {
         my ($end,$start)=split(/\:/,$courselist{$_});          my ($sname,$sdom,$status,$fullname,$section) =
         my $active=1;              (@{$info}[&Apache::loncoursedata::CL_SNAME(),
         if (($end) && ($now>$end)) { $active=0; }                        &Apache::loncoursedata::CL_SDOM(),
         if ($active) {                        &Apache::loncoursedata::CL_STATUS(),
            my ($sname,$sdom)=split(/\:/,$_);                        &Apache::loncoursedata::CL_FULLNAME(),
            my %reply=&Apache::lonnet::get('environment',                        &Apache::loncoursedata::CL_SECTION()]);
               ['firstname','middlename','lastname','generation'],          next if ($status ne 'Active');
               $sdom,$sname);          my $key = 'send_to_&&&'.$section.'&&&'.$student;
            my $section=&Apache::lonnet::usection          if (! defined($fullname) || $fullname eq '') { $fullname = $sname; }
        ($sdom,$sname,$ENV{'request.course.id'});          $r->print('<tr><td><label>'.
            $r->print(                    qq{<input type="checkbox" name="$key">}.('&nbsp;'x2).
         '<br><input type=checkbox name="send_to_&&&'.$section.'&&&_'.$_.'"> '.                    $fullname.'</td><td>'.$sname.'@'.$sdom.'</td><td>'.$section.
       $reply{'firstname'}.' '.                     '</td></tr>');
                       $reply{'middlename'}.' '.  
                       $reply{'lastname'}.' '.  
                       $reply{'generation'}.  
                       ' ('.$_.') '.$section);  
         }   
     }      }
       $r->print('</table>');
 }  }
   
 # ==================================================== Display Critical Message  # ==================================================== Display Critical Message
Line 591  sub discrit { Line 701  sub discrit {
     foreach (sort keys %what) {      foreach (sort keys %what) {
         my %content=&unpackagemsg($what{$_});          my %content=&unpackagemsg($what{$_});
         next if ($content{'senderdomain'} eq '');          next if ($content{'senderdomain'} eq '');
         $content{'message'}=~s/\n/\<br\>/g;          $result.='<hr />'.&mt('From').': <b>'.
         $result.='<hr>'.&mt('From').': <b>'.  
 &Apache::loncommon::aboutmewrapper(  &Apache::loncommon::aboutmewrapper(
  &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).'</b> ('.   &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).'</b> ('.
 $content{'sendername'}.'@'.  $content{'sendername'}.'@'.
             $content{'senderdomain'}.') '.$content{'time'}.              $content{'senderdomain'}.') '.$content{'time'}.
             '<br>'.&mt('Subject').': '.$content{'subject'}.              '<br />'.&mt('Subject').': '.$content{'subject'}.
             '<br><blockquote>'.              '<br /><blockquote>'.
               &Apache::lontexconvert::msgtexconverted($content{'message'}).                &Apache::lontexconvert::msgtexconverted($content{'message'}).
             '</blockquote><small>'.              '</blockquote><small>'.
 &mt('You have to confirm that you received this message. After confirmation, this message will be moved to your regular inbox').  &mt('You have to confirm that you received this message. After confirmation, this message will be moved to your regular inbox').
Line 610  $content{'sendername'}.'@'. Line 719  $content{'sendername'}.'@'.
     # Check to see if there were any messages.      # Check to see if there were any messages.
     if ($result eq '') {      if ($result eq '') {
         $result = "<h2>".&mt('You have no critical messages.')."</h2>".          $result = "<h2>".&mt('You have no critical messages.')."</h2>".
     '<a href="/adm/roles">'.&mt('Select a course').'</a>';      '<a href="/adm/roles">'.&mt('Select a course').'</a><br />'.
               '<a href="/adm/email">'.&mt('Communicate').'</a>';
     } else {      } else {
         $r->print($header);          $r->print($header);
     }      }
     $r->print($result);      $r->print($result);
     $r->print('<input type=hidden name="displayedcrit" value="true"></form>');      $r->print('<input type="hidden" name="displayedcrit" value="true" /></form>');
 }  
   
 # =============================================================== Compose reply  
   
 sub comprep {  
     my ($r,$msgid)=@_;  
       my %message=&Apache::lonnet::get('nohist_email',[$msgid]);  
       my %content=&unpackagemsg($message{$msgid},1);  
       my $quotemsg='> '.$content{'message'};  
       $quotemsg=~s/\r/\n/g;  
       $quotemsg=~s/\f/\n/g;  
       $quotemsg=~s/\n+/\n\> /g;  
       my $torepl=&Apache::loncommon::aboutmewrapper(  
  &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).' ('.  
 $content{'sendername'}.'@'.  
             $content{'senderdomain'}.')';  
       my $subject=&mt('Re').': '.$content{'subject'};  
       my $dispcrit='';  
       if (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) {  
  my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message");  
          $dispcrit=  
  '<input type=checkbox name=critmsg> '.&mt('Send as critical message').' ' . $crithelp .   
  '<br>'.  
  '<input type=checkbox name=sendbck> '.&mt('Send as critical message').' ' .  
  &mt('and return receipt') . $crithelp . '<p>';  
       }  
     my %lt=&Apache::lonlocal::texthash(  
    'to' => 'To',  
    'sb' => 'Subject',  
    'sr' => 'Send Reply',  
    'ca' => 'Cancel'  
    );  
       $r->print(<<"ENDREPLY");  
 <form action="/adm/email" method="post">  
 <input type="hidden" name="sendreply" value="$msgid">  
 $lt{'to'}: $torepl<br />  
 $lt{'sb'}: <input type="text" size=50 name="subject" value="$subject"><p>  
 <textarea name="message" cols="84" rows="10" wrap="hard">  
 $quotemsg  
 </textarea></p><br />  
 $dispcrit  
 <input type="submit" name="send" value="$lt{'sr'}" />  
 <input type="submit" name="cancel" value="$lt{'ca'}"/ >  
 </form>  
 ENDREPLY  
 }  }
   
 sub sortedmessages {  sub sortedmessages {
     my @messages = &Apache::lonnet::getkeys('nohist_email');      my ($blocked,$startblock,$endblock,$numblocked,$folder) = @_;
       my $suffix=&foldersuffix($folder);
       my @messages = &Apache::lonnet::getkeys('nohist_email'.$suffix);
     #unpack the varibles and repack into temp for sorting      #unpack the varibles and repack into temp for sorting
     my @temp;      my @temp;
     foreach (@messages) {      foreach (@messages) {
  my $msgid=&Apache::lonnet::escape($_);   my $msgid=&Apache::lonnet::escape($_);
  my ($sendtime,$shortsubj,$fromname,$fromdomain,$status)=   my ($sendtime,$shortsubj,$fromname,$fromdomain,$status)=
     &Apache::lonmsg::unpackmsgid($msgid);      &Apache::lonmsg::unpackmsgid($msgid,$folder);
  my @temp1 = ($sendtime,$shortsubj,$fromname,$fromdomain,$status,   my @temp1 = ($sendtime,$shortsubj,$fromname,$fromdomain,$status,
      $msgid);       $msgid);
  push @temp ,\@temp1;          # Check whether message was sent during blocking period.
           if ($sendtime >= $startblock && ($sendtime <= $endblock && $endblock > 0) ) {
               my $escid = &Apache::lonnet::unescape($msgid);
               $$blocked{$escid} = 'ON';
               $$numblocked ++;
           } else { 
               push @temp ,\@temp1;
           }
     }      }
     #default sort      #default sort
     @temp = sort  {$a->[0] <=> $b->[0]} @temp;          @temp = sort  {$a->[0] <=> $b->[0]} @temp;    
Line 710  sub sortedmessages { Line 784  sub sortedmessages {
     return @temp;      return @temp;
 }  }
   
   # ======================================================== Display new messages
   
   
   sub disnew {
       my $r=shift;
       my %lt=&Apache::lonlocal::texthash(
          'nm' => 'New Messages',
          'su' => 'Subject',
          '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 @newmsgs;
       my %setters = ();
       my $startblock = 0;
       my $endblock = 0;
       my %blocked = ();
       my $numblocked = 0;
       # Check for blocking of display because of scheduled online exams.
       &blockcheck(\%setters,\$startblock,\$endblock);
       foreach (@msgids) {
           my ($sendtime,$shortsubj,$fromname,$fromdom,$status)=
       &Apache::lonmsg::unpackmsgid($_);
           if (defined($sendtime) && $sendtime!~/error/) {
               my $numsendtime = $sendtime;
               $sendtime = &Apache::lonlocal::locallocaltime($sendtime);
               if ($status eq 'new') {
                   if ($numsendtime >= $startblock && ($numsendtime <= $endblock && $endblock > 0) ) {
                       $blocked{$_} = 'ON';
                       $numblocked ++;
                   } else {
                       push @newmsgs, { 
                           msgid    => $_,
                           sendtime => $sendtime,
                           shortsub => &Apache::lonnet::unescape($shortsubj),
                           from     => $fromname,
                           fromdom  => $fromdom 
                           }
                   }
               }
           }
       }
       if ($#newmsgs >= 0) {
           $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>
   TABLEHEAD
           foreach my $msg (@newmsgs) {
               $r->print(<<"ENDLINK");
   <tr bgcolor="#FFBB77">
   <td><a href="/adm/email?display=$msg->{'msgid'}">$lt{'op'}</a></td>
   ENDLINK
               foreach ('sendtime','from','fromdom','shortsub') {
                   $r->print("<td>$msg->{$_}</td>");
               }
               $r->print("</td></tr>");
           }
           $r->print('</table></body></html>');
       } 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);
           if ($numblocked == 1) {
               $r->print("<h3>".&mt('You have').' '.$numblocked.' '.&mt('blocked unread message').".</h3>");
               $r->print(&mt('This message is not viewable because').' ');
           } else {
               $r->print("<h3>".&mt('You have').' '.$numblocked.' '.&mt('blocked unread messages').".</h3>");
               $r->print(&mt('These').' '.$numblocked.' '.&mt('messages are not viewable because '));
           }
           $r->print(
   &mt('display of LON-CAPA messages sent to you by other students between').' '.$beginblock.' '.&mt('and').' '.$finishblock.' '.&mt('is currently being blocked because of online exams').'.');
           &build_block_table($r,$startblock,$endblock,\%setters);
       }
   }
   
   
 # ======================================================== Display all messages  # ======================================================== Display all messages
   
 sub disall {  sub disall {
     my $r=shift;      my ($r,$folder)=@_;
      $r->print(<<ENDDISHEADER);      $r->print(&folderlist($folder));
       if ($folder eq 'new') {
    &disnew($r);
       } elsif ($folder eq 'critical') {
    &discrit($r);
       } else {
    &disfolder($r,$folder);
       }
   }
   
   # ============================================================ Display a folder
   
   sub disfolder {
       my ($r,$folder)=@_;
       my %blocked = ();
       my %setters = ();
       my $startblock;
       my $endblock;
       my $numblocked = 0;
       &blockcheck(\%setters,\$startblock,\$endblock);
       $r->print(<<ENDDISHEADER);
 <script>  <script>
     function checkall() {      function checkall() {
  for (i=0; i<document.forms.disall.elements.length; i++) {   for (i=0; i<document.forms.disall.elements.length; i++) {
Line 735  sub disall { Line 913  sub disall {
     }      }
 </script>  </script>
 ENDDISHEADER  ENDDISHEADER
     $r->print('<h1>'.&mt('Display All Messages').'</h1><form method=post name=disall '.      my $fsqs='&folder='.$folder;
       'action="/adm/email">'.      my @temp=sortedmessages(\%blocked,$startblock,$endblock,\$numblocked,$folder);
       '<table border=2><tr><th colspan=2>&nbsp</th><th>');      my $totalnumber=$#temp+1;
       unless ($totalnumber>0) {
    $r->print('<h2>'.&mt('Empty Folder').'</h2>');
    return;
       }
       unless ($interdis) {
    $interdis=20;
       }
       my $number=int($totalnumber/$interdis);
       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('<form method="post" name="disall" action="/adm/email">'.
         '<table border=2><tr><th colspan="3">&nbsp</th><th>');
     if ($ENV{'form.sortedby'} eq "revdate") {      if ($ENV{'form.sortedby'} eq "revdate") {
  $r->print('<a href = "?sortedby=date">'.&mt('Date').'</a></th>');   $r->print('<a href = "?sortedby=date'.$fsqs.'">'.&mt('Date').'</a></th>');
     } else {      } else {
  $r->print('<a href = "?sortedby=revdate">'.&mt('Date').'</a></th>');   $r->print('<a href = "?sortedby=revdate'.$fsqs.'">'.&mt('Date').'</a></th>');
     }      }
     $r->print('<th>');      $r->print('<th>');
     if ($ENV{'form.sortedby'} eq "revuser") {      if ($ENV{'form.sortedby'} eq "revuser") {
  $r->print('<a href = "?sortedby=user">'.&mt('Username').'</a>');   $r->print('<a href = "?sortedby=user'.$fsqs.'">'.&mt('Username').'</a>');
     } else {      } else {
  $r->print('<a href = "?sortedby=revuser">'.&mt('Username').'</a>');   $r->print('<a href = "?sortedby=revuser'.$fsqs.'">'.&mt('Username').'</a>');
     }      }
     $r->print('</th><th>');      $r->print('</th><th>');
     if ($ENV{'form.sortedby'} eq "revdomain") {      if ($ENV{'form.sortedby'} eq "revdomain") {
  $r->print('<a href = "?sortedby=domain">'.&mt('Domain').'</a>');   $r->print('<a href = "?sortedby=domain'.$fsqs.'">'.&mt('Domain').'</a>');
     } else {      } else {
  $r->print('<a href = "?sortedby=revdomain">'.&mt('Domain').'</a>');   $r->print('<a href = "?sortedby=revdomain'.$fsqs.'">'.&mt('Domain').'</a>');
     }      }
     $r->print('</th><th>');      $r->print('</th><th>');
     if ($ENV{'form.sortedby'} eq "revsubject") {      if ($ENV{'form.sortedby'} eq "revsubject") {
  $r->print('<a href = "?sortedby=subject">'.&mt('Subject').'</a>');   $r->print('<a href = "?sortedby=subject'.$fsqs.'">'.&mt('Subject').'</a>');
     } else {      } else {
     $r->print('<a href = "?sortedby=revsubject">'.&mt('Subject').'</a>');      $r->print('<a href = "?sortedby=revsubject'.$fsqs.'">'.&mt('Subject').'</a>');
     }      }
     $r->print('</th><th>');      $r->print('</th><th>');
     if ($ENV{'form.sortedby'} eq "revstatus") {      if ($ENV{'form.sortedby'} eq "revstatus") {
  $r->print('<a href = "?sortedby=status">'.&mt('Status').'</th>');   $r->print('<a href = "?sortedby=status'.$fsqs.'">'.&mt('Status').'</th>');
     } else {      } else {
       $r->print('<a href = "?sortedby=revstatus">'.&mt('Status').'</th>');        $r->print('<a href = "?sortedby=revstatus'.$fsqs.'">'.&mt('Status').'</th>');
     }      }
     $r->print('</tr>');      $r->print('</tr>');
     my @temp=sortedmessages();      for (my $n=$firstdis;$n<=$lastdis;$n++) {
     foreach (@temp){   my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$origID)= @{$temp[$n]};
  my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$origID)= @$_;  
  if (($status ne 'deleted') && defined($sendtime) && $sendtime!~/error/) {   if (($status ne 'deleted') && defined($sendtime) && $sendtime!~/error/) {
     if ($status eq 'new') {      if ($status eq 'new') {
  $r->print('<tr bgcolor="#FFBB77">');   $r->print('<tr bgcolor="#FFBB77">');
Line 781  ENDDISHEADER Line 974  ENDDISHEADER
     } else {      } else {
  $r->print('<tr bgcolor="#99BBBB">');   $r->print('<tr bgcolor="#99BBBB">');
     }      }
     $r->print('<td><a href="/adm/email?display='.$origID.$sqs.       $r->print('<td></a><input type=checkbox name="delmark_'.$origID.'" /></td><td><a href="/adm/email?display='.$origID.$sqs. 
       '">'.&mt('Open').'</a></td><td><a href="/adm/email?markdel='.$origID.$sqs.        '">'.&mt('Open').'</a></td><td>'.
       '">'.&mt('Delete').'</a><input type=checkbox name="delmark_'.$origID.'"></td>'.        ($folder ne 'trash'?'<a href="/adm/email?markdel='.$origID.$sqs.
         '">'.&mt('Delete'):'&nbsp').'</td>'.
       '<td>'.&Apache::lonlocal::locallocaltime($sendtime).'</td><td>'.        '<td>'.&Apache::lonlocal::locallocaltime($sendtime).'</td><td>'.
       $fromname.'</td><td>'.$fromdomain.'</td><td>'.        $fromname.'</td><td>'.$fromdomain.'</td><td>'.
       &Apache::lonnet::unescape($shortsubj).'</td><td>'.        &Apache::lonnet::unescape($shortsubj).'</td><td>'.
                       $status.'</td></tr>');                        $status.'</td></tr>');
    } elsif ($status eq 'deleted') {
   # purge
       &movemsg(&Apache::lonnet::unescape($origID),$folder,'trash');
  }   }
     }         }   
     $r->print('</table><p>'.      $r->print('</table><p>'.
               '<a href="javascript:checkall()">'.&mt('Check All').'</a>&nbsp;'.    '<a href="javascript:checkall()">'.&mt('Check All').'</a>&nbsp;'.
               '<a href="javascript:uncheckall()">'.&mt('Uncheck All').'</a><p>'.    '<a href="javascript:uncheckall()">'.&mt('Uncheck All').'</a></p>'.
       '<input type="hidden" name="sortedby" value="'.$ENV{'form.sortedby'}.'" />'.    '<input type="hidden" name="sortedby" value="'.$ENV{'form.sortedby'}.'" />');
               '<input type=submit name="markeddel" value="'.&mt('Delete Checked').'">'.      if ($folder ne 'trash') {
               '</form></body></html>');   $r->print(
         '<p><input type="submit" name="markeddel" value="'.&mt('Delete Checked').'" /></p>');
       }
       $r->print('<p><input type="submit" name="markedmove" value="'.&mt('Move Checked to Folder').'" />');
       my @allfolders=&Apache::lonnet::getkeys('email_folders');
       if ($allfolders[0]=~/^error:/) { @allfolders=(); }
       $r->print(
    &Apache::loncommon::select_form('','movetofolder',
        ( map { $_ => $_ } @allfolders))
         );
       $r->print('<input type="hidden" name="folder" value="'.$folder.'" /></form>');
       if ($numblocked > 0) {
           my $beginblock = &Apache::lonlocal::locallocaltime($startblock);
           my $finishblock = &Apache::lonlocal::locallocaltime($endblock);
           $r->print('<br /><br />'.
                     $numblocked.' '.&mt('message(s) is/are not viewable because display of LON-CAPA messages sent to you by other students between').' '.$beginblock.' '.&mt('and').' '.$finishblock.' '.&mt('is currently being blocked because of online exams.'));
           &build_block_table($r,$startblock,$endblock,\%setters);
       }
 }  }
   
 # ============================================================== Compose output  # ============================================================== Compose output
   
 sub compout {  sub compout {
     my ($r,$forwarding,$broadcast)=@_;      my ($r,$forwarding,$replying,$broadcast,$replycrit,$folder)=@_;
     &printheader($r,'/adm/email?compose=upload',      my $suffix=&foldersuffix($folder);
      'Distribute from uploaded file');  
       if ($broadcast eq 'individual') {
    &printheader($r,'/adm/email?compose=individual',
        'Send a Message');
       } elsif ($broadcast) {
    &printheader($r,'/adm/email?compose=group',
        'Broadcast Message');
       } elsif ($forwarding) {
    &Apache::lonhtmlcommon::add_breadcrumb
           ({href=>"/adm/email?display=".&Apache::lonnet::escape($forwarding),
             text=>"Display Message"});
    &printheader($r,'/adm/email?forward='.&Apache::lonnet::escape($forwarding),
        'Forwarding a Message');
       } elsif ($replying) {
    &Apache::lonhtmlcommon::add_breadcrumb
           ({href=>"/adm/email?display=".&Apache::lonnet::escape($replying),
             text=>"Display Message"});
    &printheader($r,'/adm/email?replyto='.&Apache::lonnet::escape($replying),
        'Replying to a Message');
       } elsif ($replycrit) {
    $r->print('<h3>'.&mt('Replying to a Critical Message').'</h3>');
    $replying=$replycrit;
       } else {
    &printheader($r,'/adm/email?compose=upload',
        'Distribute from Uploaded File');
       }
   
     my $dispcrit='';      my $dispcrit='';
     my $dissub='';      my $dissub='';
     my $dismsg='';      my $dismsg='';
       my $disbase='';
     my $func=&mt('Send New');      my $func=&mt('Send New');
     my %lt=&Apache::lonlocal::texthash('us' => 'Username',      my %lt=&Apache::lonlocal::texthash('us' => 'Username',
        'do' => 'Domain',         'do' => 'Domain',
Line 818  sub compout { Line 1059  sub compout {
     if (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) {      if (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) {
  my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message");   my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message");
          $dispcrit=           $dispcrit=
  '<input type="checkbox" name="critmsg"> '.&mt('Send as critical message').' ' . $crithelp .    '<input type="checkbox" name="critmsg" /> '.&mt('Send as critical message').' ' . $crithelp . 
  '<br>'.   '<br>'.
  '<input type="checkbox" name="sendbck"> '.&mt('Send as critical message').'  ' .   '<input type="checkbox" name="sendbck" /> '.&mt('Send as critical message').'  ' .
  &mt('and return receipt') . $crithelp . '<p>';   &mt('and return receipt') . $crithelp . '<p>';
       }       }
       my %message;
       my %content;
       my $defdom=$ENV{'user.domain'};
     if ($forwarding) {      if ($forwarding) {
        $dispcrit.='<input type="hidden" name="forwid" value="'.   %message=&Apache::lonnet::get('nohist_email'.$suffix,[$forwarding]);
    $forwarding.'">';   %content=&unpackagemsg($message{$forwarding},$folder);
        $func=&mt('Forward');   $dispcrit.='<input type="hidden" name="forwid" value="'.
       my %message=&Apache::lonnet::get('nohist_email',[$forwarding]);      $forwarding.'" />';
       my %content=&unpackagemsg($message{$forwarding});   $func=&mt('Forward');
   
        $dissub=&mt('Forwarding').': '.$content{'subject'};   $dissub=&mt('Forwarding').': '.$content{'subject'};
        $dismsg=&mt('Forwarded message from').' '.   $dismsg=&mt('Forwarded message from').' '.
    $content{'sendername'}.' '.&mt('at').' '.$content{'senderdomain'};      $content{'sendername'}.' '.&mt('at').' '.$content{'senderdomain'};
    if ($content{'baseurl'}) {
       $disbase='<input type="hidden" name="baseurl" value="'.&Apache::lonnet::escape($content{'baseurl'}).'" />';
    }
     }      }
     my $defdom=$ENV{'user.domain'};      if ($replying) {
    %message=&Apache::lonnet::get('nohist_email'.$suffix,[$replying]);
    %content=&unpackagemsg($message{$replying},$folder);
    $dispcrit.='<input type="hidden" name="replyid" value="'.
       $replying.'" />';
    $func=&mt('Send Reply to');
   
    $dissub=&mt('Reply').': '.$content{'subject'};       
    $dismsg='> '.$content{'message'};
    $dismsg=~s/\r/\n/g;
    $dismsg=~s/\f/\n/g;
    $dismsg=~s/\n+/\n\> /g;
    if ($content{'baseurl'}) {
       $disbase='<input type="hidden" name="baseurl" value="'.&Apache::lonnet::escape($content{'baseurl'}).'" />';
       if ($ENV{'user.adv'}) {
    $disbase.='<input type="checkbox" name="storebasecomment" />'.&mt('Store message for re-use').
       ' <a href="/adm/email?showcommentbaseurl='.
       &Apache::lonnet::escape($content{'baseurl'}).'" target="comments">'.
       &mt('Show re-usable messages').'</a><br />';
       }
    }
       }
       my $citation=&displayresource(%content);
     if ($ENV{'form.recdom'}) { $defdom=$ENV{'form.recdom'}; }      if ($ENV{'form.recdom'}) { $defdom=$ENV{'form.recdom'}; }
       $r->print(        $r->print(
                 '<form action="/adm/email"  name="compemail" method="post"'.                  '<form action="/adm/email"  name="compemail" method="post"'.
                 ' enctype="multipart/form-data">'."\n".                  ' enctype="multipart/form-data">'."\n".
                 '<input type="hidden" name="sendmail" value="on">'."\n".                  '<input type="hidden" name="sendmail" value="on" />'."\n".
                 '<table>');                  '<table>');
     unless (($broadcast eq 'group') || ($broadcast eq 'upload')) {      unless (($broadcast eq 'group') || ($broadcast eq 'upload')) {
         my $domform = &Apache::loncommon::select_dom_form($defdom,'recdomain');   if ($replying) {
         my $selectlink=&Apache::loncommon::selectstudent_link      $r->print('<tr><td colspan="2">'.&mt('Replying to').' '.
         &Apache::loncommon::aboutmewrapper(
    &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).' ('.
         $content{'sendername'}.'@'.
         $content{'senderdomain'}.')'.
         '<input type="hidden" name="recuname" value="'.$content{'sendername'}.'" />'.
         '<input type="hidden" name="recdomain" value="'.$content{'senderdomain'}.'" />'.
         '</td></tr>');
    } else {
       my $domform = &Apache::loncommon::select_dom_form($defdom,'recdomain');
       my $selectlink=&Apache::loncommon::selectstudent_link
     ('compemail','recuname','recdomain');      ('compemail','recuname','recdomain');
        $r->print(<<"ENDREC");      $r->print(<<"ENDREC");
 <table>  
 <tr><td>$lt{'us'}:</td><td><input type="text" size="12" name="recuname" value="$ENV{'form.recname'}"></td><td rowspan="2">$selectlink</td></tr>  <tr><td>$lt{'us'}:</td><td><input type="text" size="12" name="recuname" value="$ENV{'form.recname'}"></td><td rowspan="2">$selectlink</td></tr>
 <tr><td>$lt{'do'}:</td>  <tr><td>$lt{'do'}:</td>
 <td>$domform</td></tr>  <td>$domform</td></tr>
 ENDREC  ENDREC
           }
     }      }
     my $latexHelp = Apache::loncommon::helpLatexCheatsheet();      my $latexHelp = Apache::loncommon::helpLatexCheatsheet();
     if ($broadcast ne 'upload') {      if ($broadcast ne 'upload') {
        $r->print(<<"ENDCOMP");         $r->print(<<"ENDCOMP");
 <tr><td>$lt{'ad'}<br /><tt>username\@domain,username\@domain, ...  <tr><td>$lt{'ad'}<br /><tt>username\@domain,username\@domain, ...
 </tt></td><td>  </tt></td><td>
 <input type="text" size="50" name="additionalrec"></td></tr>  <input type="text" size="50" name="additionalrec" /></td></tr>
 <tr><td>$lt{'sb'}:</td><td><input type="text" size="50" name="subject" value="$dissub">  <tr><td>$lt{'sb'}:</td><td><input type="text" size="50" name="subject" value="$dissub" />
 </td></tr></table>  </td></tr></table>
 $latexHelp  $latexHelp
 <textarea name="message" cols="80" rows="10" wrap="hard">$dismsg  <textarea name="message" cols="80" rows="15" wrap="hard">$dismsg
 </textarea></p><br />  </textarea></p><br />
 $dispcrit  $dispcrit
   $disbase
 <input type="submit" name="send" value="$func $lt{'ma'}" />  <input type="submit" name="send" value="$func $lt{'ma'}" />
 <input type="submit" name="cancel" value="$lt{'ca'}" />  <input type="submit" name="cancel" value="$lt{'ca'}" /><hr />
   $citation
 ENDCOMP  ENDCOMP
     } else { # $broadcast is 'upload'      } else { # $broadcast is 'upload'
  $r->print(<<ENDUPLOAD);   $r->print(<<ENDUPLOAD);
 <input type=hidden name=sendmode value=upload>  <input type="hidden" name="sendmode" value="upload" />
 <input type="hidden" name="send" value="on" />  <input type="hidden" name="send" value="on" />
 <h3>Generate messages from a file</h3>  <h3>Generate messages from a file</h3>
 <p>  <p>
 Subject: <input type=text size=50 name=subject>  Subject: <input type="text" size="50" name="subject" />
 </p>  </p>
 <p>General message text<br />  <p>General message text<br />
 <textarea name=message cols=60 rows=10 wrap=hard>$dismsg  <textarea name="message" cols="60" rows="10" wrap="hard">$dismsg
 </textarea></p>  </textarea></p>
 <p>  <p>
 The file format for the uploaded portion of the message is:  The file format for the uploaded portion of the message is:
Line 890  username3\@domain1: text Line 1171  username3\@domain1: text
 The messages will be assembled from all lines with the respective   The messages will be assembled from all lines with the respective 
 <tt>username\@domain</tt>, and appended to the general message text.</p>  <tt>username\@domain</tt>, and appended to the general message text.</p>
 <p>  <p>
 <input type=file name=upfile size=20><p>  <input type="file" name="upfile" size="40" /></p><p>
 $dispcrit  $dispcrit
 <input type=submit value="Upload and send">  <input type="submit" value="Upload and Send" /></p>
 ENDUPLOAD  ENDUPLOAD
     }      }
     if ($broadcast eq 'group') {      if ($broadcast eq 'group') {
Line 903  ENDUPLOAD Line 1184  ENDUPLOAD
   
 # ---------------------------------------------------- Display all face to face  # ---------------------------------------------------- Display all face to face
   
   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'})) {
    return;
       }
       my %records=&Apache::lonnet::dump('nohist_email',
    $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
    $ENV{'course.'.$ENV{'request.course.id'}.'.num'},
                            '%255b'.$user.'%253a'.$domain.'%255d');
       my $result='';
       foreach (sort(keys(%records))) {
           my %content=&unpackagemsg($records{$_});
           next if ($content{'senderdomain'} eq '');
           next if ($content{'subject'} !~ /^Record/);
           # $content{'message'}=~s/\n/\<br\>/g;
           $result.='Recorded by '.
               $content{'sendername'}.'@'.$content{'senderdomain'}."\n";
           $result.=
               &Apache::lontexconvert::msgtexconverted($content{'message'})."\n";
        }
       return $result;
   }
   
 sub disfacetoface {  sub disfacetoface {
     my ($r,$user,$domain)=@_;      my ($r,$user,$domain)=@_;
       my $target=$ENV{'form.grade_target'};
     unless ($ENV{'request.course.id'}) { return; }      unless ($ENV{'request.course.id'}) { return; }
     unless (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) {      unless (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) {
  return;   return;
Line 920  sub disfacetoface { Line 1227  sub disfacetoface {
         $content{'message'}=~s/\n/\<br\>/g;          $content{'message'}=~s/\n/\<br\>/g;
         if ($content{'subject'}=~/^Record/) {          if ($content{'subject'}=~/^Record/) {
     $result.='<h3>'.&mt('Record').'</h3>';      $result.='<h3>'.&mt('Record').'</h3>';
           } elsif ($content{'subject'}=~/^Broadcast/) {
               $result .='<h3>'.&mt('Broadcast Message').'</h3>';
         } else {          } else {
             $result.='<h3>'.&mt('Sent Message').'</h3>';              $result.='<h3>'.&mt('Critical Message').'</h3>';
             %content=&unpackagemsg($content{'message'});              %content=&unpackagemsg($content{'message'});
             $content{'message'}=              $content{'message'}=
                 '<b>Subject: '.$content{'subject'}.'</b><br />'.                  '<b>'.&mt('Subject').': '.$content{'subject'}.'</b><br />'.
  $content{'message'};   $content{'message'};
         }          }
         $result.=&mt('By').': <b>'.          $result.=&mt('By').': <b>'.
Line 932  sub disfacetoface { Line 1241  sub disfacetoface {
  &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).'</b> ('.   &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).'</b> ('.
 $content{'sendername'}.'@'.  $content{'sendername'}.'@'.
             $content{'senderdomain'}.') '.$content{'time'}.              $content{'senderdomain'}.') '.$content{'time'}.
             '<br><blockquote>'.              '<br /><blockquote>'.
               &Apache::lontexconvert::msgtexconverted($content{'message'}).                &Apache::lontexconvert::msgtexconverted($content{'message'}).
       '</blockquote>';        '</blockquote>';
      }       }
     # Check to see if there were any messages.      # Check to see if there were any messages.
     if ($result eq '') {      if ($result eq '') {
         $r->print("<p><b>No notes, face-to-face discussion records, or critical messages in this course.</b></p>");   if ($target ne 'tex') { 
       $r->print("<p><b>".&mt("No notes, face-to-face discussion records, critical messages, or broadcast messages in this course.")."</b></p>");
    } else {
       $r->print('\textbf{'.&mt("No notes, face-to-face discussion records, critical messages or broadcast messages in this course.").'}\\\\');
    }
     } else {      } else {
        $r->print($result);         $r->print($result);
     }      }
 }  }
   
 # ---------------------------------------------------------------- Print header  
   
 sub printheader {  
     my ($r,$url,$desc,$baseurl)=@_;  
     &Apache::lonhtmlcommon::add_breadcrumb  
  ({href=>$url,  
   text=>$desc});  
     &header($r,$baseurl);  
 }  
   
 # ---------------------------------------------------------------- Face to face  # ---------------------------------------------------------------- Face to face
   
 sub facetoface {  sub facetoface {
Line 963  sub facetoface { Line 1266  sub facetoface {
     }      }
     &printheader($r,      &printheader($r,
  '/adm/email?recordftf=query',   '/adm/email?recordftf=query',
  "User Notes, Face-to-Face, Critical Messages");   "User Notes, Face-to-Face, Critical Messages, Broadcast Messages");
 # from query string  # from query string
   
     if ($ENV{'form.recname'}) { $ENV{'form.recuname'}=$ENV{'form.recname'}; }      if ($ENV{'form.recname'}) { $ENV{'form.recuname'}=$ENV{'form.recname'}; }
Line 978  sub facetoface { Line 1281  sub facetoface {
  ('stdselect','recuname','recdomain');   ('stdselect','recuname','recdomain');
     my %lt=&Apache::lonlocal::texthash('user' => 'Username',      my %lt=&Apache::lonlocal::texthash('user' => 'Username',
        'dom' => 'Domain',         'dom' => 'Domain',
        'head' => 'User Notes, Records of Face-To-Face Discussions, and Critical Messages in Course',         'head' => 'User Notes, Records of Face-To-Face Discussions, Critical Messages, and Broadcast Messages in Course',
        'subm' => 'Retrieve discussion and message records',         'subm' => 'Retrieve discussion and message records',
        'newr' => 'New Record (record is visible to course faculty and staff)',         'newr' => 'New Record (record is visible to course faculty and staff)',
        'post' => 'Post this Record');         'post' => 'Post this Record');
Line 1027  ENDBFORM Line 1330  ENDBFORM
     }      }
 }  }
   
   # ----------------------------------------------------------- Blocking during exams
   
   sub examblock {
       my ($r,$action) = @_;
       unless ($ENV{'request.course.id'}) { return;}
       unless (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'})) { $r->print('Not allowed'); }
       my %lt=&Apache::lonlocal::texthash(
               'comb' => 'Communication Blocking',
               'cbds' => 'Communication blocking during scheduled exams',
               'desc' => 'You can use communication blocking to prevent students enrolled in this course from displaying LON-CAPA messages sent by other students during an online exam. As blocking of communication could potentially interrupt legitimate communication between students who are also both enrolled in a different LON-CAPA course, please be careful that you select the correct start and end times for your scheduled exam when setting or modifying these parameters.',
                'mecb' => 'Modify existing communication blocking periods',
                'ncbc' => 'No communication blocks currently stored'
       );
   
       my %ltext = &Apache::lonlocal::texthash(
               'dura' => 'Duration',
               'setb' => 'Set by',
               'even' => 'Event',
               'actn' => 'Action',
               'star' => 'Start',
               'endd' => 'End'
       );
   
       &printheader($r,'/adm/email?block=display',$lt{'comb'});
       $r->print('<h3>'.$lt{'cbds'}.'</h3>');
   
       if ($action eq 'store') {
           &blockstore($r);
       }
   
       $r->print($lt{'desc'}.'<br /><br />
                  <form name="blockform" method="post" action="/adm/email?block=store">
                ');
   
       $r->print('<h4>'.$lt{'mecb'}.'</h4>');
       my %records = ();
       my $blockcount = 0;
       my $parmcount = 0;
       &get_blockdates(\%records,\$blockcount);
       if ($blockcount > 0) {
           $parmcount = &display_blocker_status($r,\%records,\%ltext);
       } else {
           $r->print($lt{'ncbc'}.'<br /><br />');
       }
       &display_addblocker_table($r,$parmcount,\%ltext);
       $r->print(<<"END");
   <br />
   <input type="hidden" name="blocktotal" value="$blockcount" />
   <input type ="submit" value="Save Changes" />
   </form>
   </body>
   </html>
   END
       return;
   }
   
   sub blockstore {
       my $r = shift;
       my %lt=&Apache::lonlocal::texthash(
               'tfcm' => 'The following changes were made',
               'cbps' => 'communication blocking period(s)',
               'werm' => 'was/were removed',
               'wemo' => 'was/were modified',
               'wead' => 'was/were added',
               'ncwm' => 'No changes were made.' 
       );
       my %adds = ();
       my %removals = ();
       my %cancels = ();
       my $modtotal = 0;
       my $canceltotal = 0;
       my $addtotal = 0;
       my %blocking = ();
       $r->print('<h3>'.$lt{'head'}.'</h3>');
       foreach (keys %ENV) {
           if ($_ =~ m/^form\.modify_(\w+)$/) {
               $adds{$1} = $1;
               $removals{$1} = $1;
               $modtotal ++;
           } elsif ($_ =~ m/^form\.cancel_(\d+)$/) {
               $cancels{$1} = $1;
               unless ( defined($removals{$1}) ) {
                   $removals{$1} = $1;
                   $canceltotal ++;
               }
           } elsif ($_ =~ m/^form\.add_(\d+)$/) {
               $adds{$1} = $1;
               $addtotal ++;
           }
       }
   
       foreach (keys %removals) {
           my $hashkey = $ENV{'form.key_'.$_};
           &Apache::lonnet::del('comm_block',["$hashkey"],
                            $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                            $ENV{'course.'.$ENV{'request.course.id'}.'.num'}
                            );
       }
       foreach (keys %adds) {
           unless ( defined($cancels{$_}) ) {
               my ($newstart,$newend) = &get_dates_from_form($_);
               my $newkey = $newstart.'____'.$newend;
               $blocking{$newkey} = $ENV{'user.name'}.'@'.$ENV{'user.domain'}.':'.$ENV{'form.title_'.$_};
           }
       }
       if ($addtotal + $modtotal > 0) {
           &Apache::lonnet::put('comm_block',\%blocking,
                        $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                        $ENV{'course.'.$ENV{'request.course.id'}.'.num'}
                        );
       }
       my $chgestotal = $canceltotal + $modtotal + $addtotal;
       if ($chgestotal > 0) {
           $r->print($lt{'tfcm'}.'<ul>');
           if ($canceltotal > 0) {
               $r->print('<li>'.$canceltotal.' '.$lt{'cbps'},' '.$lt{'werm'}.'</li>');
           }
           if ($modtotal > 0) {
               $r->print('<li>'.$modtotal.' '.$lt{'cbps'},' '.$lt{'wemo'}.'</li>');
           }
           if ($addtotal > 0) {
               $r->print('<li>'.$addtotal.' '.$lt{'cbps'},' '.$lt{'wead'}.'</li>');
           }
           $r->print('</ul>');
       } else {
           $r->print($lt{'ncwm'});
       }
       $r->print('<br />');
       return;
   }
   
   sub get_dates_from_form {
       my $item = shift;
       my $startdate = &Apache::lonhtmlcommon::get_date_from_form('startdate_'.$item);
       my $enddate   = &Apache::lonhtmlcommon::get_date_from_form('enddate_'.$item);
       return ($startdate,$enddate);
   }
   
   sub get_blockdates {
       my ($records,$blockcount) = @_;
       $$blockcount = 0;
       %{$records} = &Apache::lonnet::dump('comm_block',
                            $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                            $ENV{'course.'.$ENV{'request.course.id'}.'.num'}
                            );
       $$blockcount = keys %{$records};
                                                                                                                
       foreach (keys %{$records}) {
           if ($_ eq 'error: 2 tie(GDBM) Failed while attempting dump') {
               $$blockcount = 0;
               last;
           }
       }
   }
   
   sub display_blocker_status {
       my ($r,$records,$ltext) = @_;
       my $parmcount = 0;
       my @bgcols = ("#eeeeee","#dddddd");
       my $function = &Apache::loncommon::get_users_function();
       my $color = &Apache::loncommon::designparm($function.'.tabbg',
                                                       $ENV{'user.domain'});
       my %lt = &Apache::lonlocal::texthash(
           'modi' => 'Modify',
           'canc' => 'Cancel',
       );
       $r->print(<<"END");
   <table border="0" cellpadding="0" cellspacing="0">
    <tr>
     <td width="100%" bgcolor="#000000">
      <table width="100%" border="0" cellpadding="1" cellspacing="0">
       <tr>
        <td width="100%" bgcolor="#000000">
         <table border="0" cellpadding="3" cellspacing="3" bgcolor="#FFFFFF">
          <tr bgcolor="$color">
           <td><b>$$ltext{'dura'}</b></td>
           <td><b>$$ltext{'setb'}</b></td>
           <td><b>$$ltext{'even'}</b></td>
           <td><b>$$ltext{'actn'}?</b></td>
          </tr>
   END
       foreach (sort keys %{$records}) {
           my $iter = $parmcount%2;
           my $onchange = 'onFocus="javascript:window.document.forms['.
                          "'blockform'].elements['modify_".$parmcount."'].".
                          'checked=true;"';
           my ($start,$end) = split/____/,$_;
           my $startform = &Apache::lonhtmlcommon::date_setter('blockform','startdate_'.$parmcount,$start,$onchange);
           my $endform = &Apache::lonhtmlcommon::date_setter('blockform','enddate_'.$parmcount,$end,$onchange);
           my ($setter,$title) = split/:/,$$records{$_};
           my ($setuname,$setudom) = split/@/,$setter;
           my $settername = &Apache::loncommon::plainname($setuname,$setudom);
           $r->print(<<"END");
          <tr bgcolor="$bgcols[$iter]">
           <td>$$ltext{'star'}:&nbsp;$startform<br/>$$ltext{'endd'}:&nbsp;&nbsp;$endform</td>
           <td>$settername</td>
           <td><input type="text" name="title_$parmcount" size="15" value="$title"/><input type="hidden" name="key_$parmcount" value="$_"></td>
           <td>$lt{'modi'}?&nbsp;<input type="checkbox" name="modify_$parmcount"/><br />$lt{'canc'}?&nbsp;&nbsp;<input type="checkbox" name="cancel_$parmcount"/>
          </tr>
   END
           $parmcount ++;
       }
       $r->print(<<"END");
         </table>
        </td>
       </tr>
      </table>
     </td>
    </tr>
   </table>
   <br />
   <br />
   END
       return $parmcount;
   }
   
   sub display_addblocker_table {
       my ($r,$parmcount,$ltext) = @_;
       my $start = time;
       my $end = $start + (60 * 60 * 2); #Default is an exam of 2 hours duration.
       my $onchange = 'onFocus="javascript:window.document.forms['.
                      "'blockform'].elements['add_".$parmcount."'].".
                      'checked=true;"';
       my $startform = &Apache::lonhtmlcommon::date_setter('blockform','startdate_'.$parmcount,$start,$onchange);
       my $endform = &Apache::lonhtmlcommon::date_setter('blockform','enddate_'.$parmcount,$end,$onchange);
       my $function = &Apache::loncommon::get_users_function();
       my $color = &Apache::loncommon::designparm($function.'.tabbg',
                                                       $ENV{'user.domain'});
       my %lt = &Apache::lonlocal::texthash(
           'addb' => 'Add block',
           'exam' => 'e.g., Exam 1',
           'addn' => 'Add new communication blocking periods'
       );
       $r->print(<<"END");
   <h4>$lt{'addn'}</h4> 
   <table border="0" cellpadding="0" cellspacing="0">
    <tr>
     <td width="100%" bgcolor="#000000">
      <table width="100%" border="0" cellpadding="1" cellspacing="0">
       <tr>
        <td width="100%" bgcolor="#000000">
         <table border="0" cellpadding="3" cellspacing="3" bgcolor="#FFFFFF">
          <tr bgcolor="#CCCCFF">
           <td><b>$$ltext{'dura'}</b></td>
           <td><b>$$ltext{'even'} $lt{'exam'}</b></td>
           <td><b>$$ltext{'actn'}?</b></td>
          </tr>
          <tr bgcolor="#eeeeee">
           <td>$$ltext{'star'}:&nbsp;$startform<br />$$ltext{'endd'}:&nbsp;&nbsp;$endform</td>
           <td><input type="text" name="title_$parmcount" size="15" value=""/></td>
           <td>$lt{'addb'}?&nbsp;<input type="checkbox" name="add_$parmcount" value="1"/></td>
          </tr>
         </table>
        </td>
       </tr>
      </table>
     </td>
    </tr>
   </table>
   END
       return;
   }
   
   sub blockcheck {
       my ($setters,$startblock,$endblock) = @_;
       # Retrieve active student roles and active course coordinator/instructor roles
       my @livecses = ();
       my @staffcses = ();
       $$startblock = 0;
       $$endblock = 0;
       foreach (keys %ENV) {
           if ($_ =~ m-^user\.role\.(st|cc|in)\./(.+)$-) {
               my $role = $1;
               my $cse = $2;
               $cse =~ s|/|_|;
               if ($ENV{$_} =~ m/^(\d*)\.(\d*)$/) {
                   unless (($2 > 0 && $2 < time) || ($1 > time)) {
                       if ($role eq 'st') {
                           push @livecses, $cse;
                       } else {
                           unless (grep/^$cse$/,@staffcses) {
                               push @staffcses, $cse;
                           }
                       }
                   }
               }
           } elsif ($_ =~ m-user\.role\.cr/(\w+)/(\w+)/([^/]+)\./(.+)$- ) { 
               my $rolepriv = $ENV{'user.role..rolesdef_'.$3};
           }
       }
       # Retrieve blocking times and identity of blocker for active courses for students.
       if (@livecses > 0) {
           foreach my $cse (@livecses) {
               my ($cdom,$crs) = split/_/,$cse;
               if ( (grep/^$cse$/,@staffcses) && ($ENV{'request.role'} !~ m-^st\./$cdom/$crs$-) ) {
                   next;
               } else {
                   %{$$setters{$cse}} = ();
                   @{$$setters{$cse}{'staff'}} = ();
                   @{$$setters{$cse}{'times'}} = ();
                   my %records = &Apache::lonnet::dump('comm_block',$cdom,$crs);
                   foreach (keys %records) {
                       if ($_ =~ m/^(\d+)____(\d+)$/) {
                           if ($1 <= time && $2 >= time) {
                               my ($staff,$title) = split/:/,$records{$_};
                               push @{$$setters{$cse}{'staff'}}, $staff;
                               push @{$$setters{$cse}{'times'}}, $_;
                               if ( ($$startblock == 0) || ($$startblock > $1) ) {
                                   $$startblock = $1;
                               }
                               if ( ($$endblock == 0) || ($$endblock < $2) ) {
                                   $$endblock = $2;
                               }
                           }
                       }
                   }
               }
           }
       }
   }
   
   sub build_block_table {
       my ($r,$startblock,$endblock,$setters) = @_;
       my $function = &Apache::loncommon::get_users_function();
       my $color = &Apache::loncommon::designparm($function.'.tabbg',
                                                       $ENV{'user.domain'});
       my %lt = &Apache::lonlocal::texthash(
           'cacb' => 'Currently active communication blocks',
           'cour' => 'Course',
           'dura' => 'Duration',
           'blse' => 'Block set by'
       ); 
       $r->print(<<"END");
   <br /<br />$lt{'cacb'}:<br /><br />
   <table border="0" cellpadding="0" cellspacing="0">
    <tr>
     <td width="100%" bgcolor="#000000">
      <table width="100%" border="0" cellpadding="1" cellspacing="0">
       <tr>
        <td width="100%" bgcolor="#000000">
         <table border="0" cellpadding="3" cellspacing="3" bgcolor="#FFFFFF">
          <tr bgcolor="$color">
           <td><b>$lt{'cour'}</b></td>
           <td><b>$lt{'dura'}</b></td>
           <td><b>$lt{'blse'}</b></td>
          </tr>
   END
       foreach (keys %{$setters}) {
           my %courseinfo=&Apache::lonnet::coursedescription($_);
           for (my $i=0; $i<@{$$setters{$_}{staff}}; $i++) {
               my ($uname,$udom) = split/\@/,$$setters{$_}{staff}[$i];
               my $fullname = &Apache::loncommon::plainname($uname,$udom);
               my ($openblock,$closeblock) = split/____/,$$setters{$_}{times}[$i];
               $openblock = &Apache::lonlocal::locallocaltime($openblock);
               $closeblock= &Apache::lonlocal::locallocaltime($closeblock);
               $r->print('<tr><td>'.$courseinfo{'description'}.'</td>'.
                         '<td>'.$openblock.' to '.$closeblock.'</td>'.
                         '<td>'.$fullname.' ('.$uname.'@'.$udom.
                         ')</td></tr>');
           }
       }
       $r->print('</table></td></tr></table></td></tr></table>');
   }
   
   # ----------------------------------------------------------- Display a message
   
   sub displaymessage {
       my ($r,$msgid,$folder)=@_;
       my $suffix=&foldersuffix($folder);
       my %blocked = ();
       my %setters = ();
       my $startblock = 0;
       my $endblock = 0;
       my $numblocked = 0;
   # info to generate "next" and "previous" buttons and check if message is blocked
       &blockcheck(\%setters,\$startblock,\$endblock);
       my @messages=&sortedmessages(\%blocked,$startblock,$endblock,\$numblocked,$folder);
       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.'));
           &build_block_table($r,$startblock,$endblock,\%setters);
           return;
       }
       &statuschange($msgid,'read',$folder);
       my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]);
       my %content=&unpackagemsg($message{$msgid});
   
       my $counter=0;
       $r->print('<pre>');
       my $escmsgid=&Apache::lonnet::escape($msgid);
       foreach (@messages) {
    if ($_->[5] eq $escmsgid){
       last;
    }
    $counter++;
       }
       $r->print('</pre>');
       my $number_of_messages = scalar(@messages); #subtract 1 for last index
   # start output
       &printheader($r,'/adm/email?display='.&Apache::lonnet::escape($msgid),'Display a Message','',$content{'baseurl'});
       my %courseinfo=&Apache::lonnet::coursedescription($content{'courseid'});
   # Functions
       $r->print('<table border="2" width="100%"><tr bgcolor="#FFFFAA"><td>'.&mt('Functions').':</td>'.
         '<td><a href="/adm/email?replyto='.&Apache::lonnet::escape($msgid).$sqs.
         '"><b>'.&mt('Reply').'</b></a></td>'.
         '<td><a href="/adm/email?forward='.&Apache::lonnet::escape($msgid).$sqs.
         '"><b>'.&mt('Forward').'</b></a></td>'.
         '<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>'.
         '<td><a href="/adm/email?'.$sqs.
         '"><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.
     '"><b>'.&mt('Previous').'</b></a></td>');
       }
       if ($counter < $number_of_messages - 1){
    $r->print('<td><a href="/adm/email?display='.$messages[$counter+1]->[5].$sqs.
     '"><b>'.&mt('Next').'</b></a></td>');
       }
       $r->print('</tr></table>');
       $r->print('<br /><b>'.&mt('Subject').':</b> '.$content{'subject'}.
         ($folder ne 'sent'?'<br /><b>'.&mt('From').':</b> '.
         &Apache::loncommon::aboutmewrapper(
    &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),
    $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'}.') ').
         ($content{'courseid'}?'<br /><b>'.&mt('Course').':</b> '.$courseinfo{'description'}.
          ($content{'coursesec'}?' ('.&mt('Group/Section').': '.$content{'coursesec'}.')':''):'').
         '<br /><b>'.&mt('Time').':</b> '.$content{'time'}.
         ($content{'baseurl'}?'<br /><b>'.&mt('Refers to').':</b> <a href="'.$content{'baseurl'}.'">'.
          $content{'baseurl'}.' ('.&Apache::lonnet::gettitle($content{'baseurl'}).')</a>':'').
         '<p><pre>'.
         &Apache::lontexconvert::msgtexconverted($content{'message'},1).
         '</pre><hr />'.&displayresource(%content).'</p>');
       return;   
   }
   
   # =========================================================== Show the citation
   
   sub displayresource {
       my %content=@_;
   #
   # If the recipient is in the same course that the message was sent from and
   # has sufficient privileges, show "all details," else show citation
   #
       if (($ENV{'request.course.id'} eq $content{'courseid'})
        && (&Apache::lonnet::allowed('vgr',$content{'courseid'}))) {
    my $symb=&Apache::lonnet::symbread($content{'baseurl'});
   # Could not get a symb, give up
    unless ($symb) { return $content{'citation'}; }
   # Have a symb, can render
    return '<h2>'.&mt('Current attempts of student (if applicable)').'</h2>'.
       &Apache::loncommon::get_previous_attempt($symb,
        $content{'sendername'},
        $content{'senderdomain'},
        $content{'courseid'}).
       '<hr /><h2>'.&mt('Current screen output (if applicable)').'</h2>'.
       &Apache::loncommon::get_student_view($symb,
    $content{'sendername'},
    $content{'senderdomain'},
    $content{'courseid'}).
       '<h2>'.&mt('Correct Answer(s) (if applicable)').'</h2>'.
       &Apache::loncommon::get_student_answers($symb,
       $content{'sendername'},
       $content{'senderdomain'},
       $content{'courseid'});
       } else {
    return $content{'citation'};
       }
   }
   
 # ================================================================== The Header  # ================================================================== The Header
   
 sub header {  sub header {
     my ($r,$baseurl)=@_;      my ($r,$title,$baseurl)=@_;
     $r->print('<html><head><title>Communication and Messages</title>');      $r->print('<html><head><title>Communication and Messages</title>');
     if ($baseurl) {      if ($baseurl) {
  $r->print("<base href=\"http://$ENV{'SERVER_NAME'}/$baseurl\" />");   $r->print("<base href=\"http://$ENV{'SERVER_NAME'}/$baseurl\" />");
Line 1038  sub header { Line 1820  sub header {
     $r->print(&Apache::loncommon::studentbrowser_javascript().'</head>'.      $r->print(&Apache::loncommon::studentbrowser_javascript().'</head>'.
       &Apache::loncommon::bodytag('Communication and Messages'));        &Apache::loncommon::bodytag('Communication and Messages'));
         $r->print(&Apache::lonhtmlcommon::breadcrumbs          $r->print(&Apache::lonhtmlcommon::breadcrumbs
                   (undef,'Communication and Messages'));                    (undef,($title?$title:'Communication and Messages')));
   
   }
   
   # ---------------------------------------------------------------- Print header
   
   sub printheader {
       my ($r,$url,$desc,$title,$baseurl)=@_;
       &Apache::lonhtmlcommon::add_breadcrumb
    ({href=>$url,
     text=>$desc});
       &header($r,$title,$baseurl);
   }
   
   # ------------------------------------------------------------ Store the comment
   
   sub storecomment {
       my ($r)=@_;
       my $msgtxt=&Apache::lonfeedback::clear_out_html($ENV{'form.message'});
       my $cleanmsgtxt='';
       foreach (split(/[\n\r]/,$msgtxt)) {
    unless ($_=~/^\s*(\>|\&gt\;)/) {
       $cleanmsgtxt.=$_."\n";
    }
       }
       my $key=&Apache::lonnet::escape($ENV{'form.baseurl'}).'___'.time;
       &Apache::lonnet::put('nohist_stored_comments',{ $key => $cleanmsgtxt });
   }
   
   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('<html><body>');
       if ((keys %msgs)[0]=~/^error\:/) {
    $r->print(&mt('No stored comments yet.'));
       } else {
    my $found=0;
    foreach (sort keys %msgs) {
       $r->print("\n".$msgs{$_}."<hr />");
       $found=1;
    }
    unless ($found) {
       $r->print(&mt('No stored comments yet for this resource.'));
    }
       }
   }
   
   # ---------------------------------------------------------------- Send an email
   
   sub sendoffmail {
       my ($r,$folder)=@_;
       my $suffix=&foldersuffix($folder);
       my $sendstatus='';
       if ($ENV{'form.send'}) {
    &printheader($r,'','Messages being sent.');
    $r->rflush();
    my %content=();
    undef %content;
    if ($ENV{'form.forwid'}) {
       my $msgid=$ENV{'form.forwid'};
       my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]);
       %content=&unpackagemsg($message{$msgid},1);
       &statuschange($msgid,'forwarded',$folder);
       $ENV{'form.message'}.="\n\n-- Forwarded message --\n\n".
    $content{'message'};
    }
    if ($ENV{'form.replyid'}) {
       my $msgid=$ENV{'form.replyid'};
       my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]);
       %content=&unpackagemsg($message{$msgid},1);
       &statuschange($msgid,'replied',$folder);
    }
    my %toaddr=();
    undef %toaddr;
    if ($ENV{'form.sendmode'} eq 'group') {
       foreach (keys %ENV) {
    if ($_=~/^form\.send\_to\_\&\&\&[^\&]*\&\&\&\_(.+)$/) {
       $toaddr{$1}='';
    }
       }
    } elsif ($ENV{'form.sendmode'} eq 'upload') {
       foreach (split(/[\n\r\f]+/,$ENV{'form.upfile'})) {
    my ($rec,$txt)=split(/\s*\:\s*/,$_);
    if ($txt) {
       $rec=~s/\@/\:/;
       $toaddr{$rec}.=$txt."\n";
    }
       }
    } else {
       $toaddr{$ENV{'form.recuname'}.':'.$ENV{'form.recdomain'}}='';
    }
    if ($ENV{'form.additionalrec'}) {
       foreach (split(/\,/,$ENV{'form.additionalrec'})) {
    my ($auname,$audom)=split(/\@/,$_);
    $toaddr{$auname.':'.$audom}='';
       }
    }
   
    foreach (keys %toaddr) {
       my ($recuname,$recdomain)=split(/\:/,$_);
               my $msgtxt;
               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'});
               }
       if ($toaddr{$_}) { $msgtxt.='<hr />'.$toaddr{$_}; }
       my $thismsg;    
       if ((($ENV{'form.critmsg'}) || ($ENV{'form.sendbck'})) && 
    (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'}))) {
    $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'});
       } else {
    $r->print(&mt('Sending').' '.$recuname.'@'.$recdomain.': ');
    $thismsg=&user_normal_msg($recuname,$recdomain,
     &Apache::lonfeedback::clear_out_html($ENV{'form.subject'}),
     $msgtxt,
     $content{'citation'});
    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);
    }
       }
       $r->print($thismsg.'<br />');
       $sendstatus.=' '.$thismsg;
    }
       } else {
    &printheader($r,'','No messages sent.'); 
       }
       if ($sendstatus=~/^(\s*(?:ok|con_delayed)\s*)*$/) {
    $r->print('<br /><font color="green">'.&mt('Completed.').'</font>');
    if ($ENV{'form.displayedcrit'}) {
       &discrit($r);
    } else {
       &Apache::loncommunicate::menu($r);
    }
       } else {
    $r->print(
     '<h2><font color="red">'.&mt('Could not deliver message').'</font></h2>'.
     &mt('Please use the browser "Back" button and correct the recipient addresses')
     );
       }
 }  }
   
 # ===================================================================== Handler  # ===================================================================== Handler
Line 1058  sub handler { Line 1988  sub handler {
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
         ['display','replyto','forward','markread','markdel','markunread',          ['display','replyto','forward','markread','markdel','markunread',
          'sendreply','compose','sendmail','critical','recname','recdom',           'sendreply','compose','sendmail','critical','recname','recdom',
          'recordftf','sortedby']);           'recordftf','sortedby','block','folder','startdis','interdis',
    'showcommentbaseurl']);
     $sqs='&sortedby='.$ENV{'form.sortedby'};      $sqs='&sortedby='.$ENV{'form.sortedby'};
   
 # ------------------------------------------------------ They checked for email  # ------------------------------------------------------ They checked for email
     &Apache::lonnet::put('email_status',{'recnewemail'=>0});      unless ($ENV{'form.block'}) {
           &Apache::lonnet::put('email_status',{'recnewemail'=>0});
       }
   
 # ----------------------------------------------------------------- Breadcrumbs  # ----------------------------------------------------------------- Breadcrumbs
   
Line 1071  sub handler { Line 2005  sub handler {
           text=>"Communication/Messages",            text=>"Communication/Messages",
           faq=>12,bug=>'Communication Tools',});            faq=>12,bug=>'Communication Tools',});
   
   # ------------------------------------------------------------------ Get Folder
   
       my $folder=$ENV{'form.folder'};
       unless ($folder) { 
    $folder=''; 
       } else {
    $sqs.='&folder='.&Apache::lonnet::escape($folder);
       }
   
   # --------------------------------------------------------------------- Display
   
       $startdis=$ENV{'form.startdis'};
       $startdis--;
       unless ($startdis) { $startdis=0; }
   
       $interdis=$ENV{'form.interdis'};
       unless ($interdis) { $interdis=20; }
       $sqs.='&interdis='.$interdis;
   
       if ($ENV{'form.firstview'}) {
    $startdis=0;
       }
       if ($ENV{'form.lastview'}) {
    $startdis=-1;
       }
       if ($ENV{'form.prevview'}) {
    $startdis--;
       }
       if ($ENV{'form.nextview'}) {
    $startdis++;
       }
       my $postedstartdis=$startdis+1;
       $sqs.='&startdis='.$postedstartdis;
   
 # --------------------------------------------------------------- Render Output  # --------------------------------------------------------------- Render Output
   
     if ($ENV{'form.display'}) {      if ($ENV{'form.display'}) {
  my $msgid=$ENV{'form.display'};   &displaymessage($r,$ENV{'form.display'},$folder);
  &statuschange($msgid,'read');  
  my %message=&Apache::lonnet::get('nohist_email',[$msgid]);  
  my %content=&unpackagemsg($message{$msgid});  
 # info to generate "next" and "previous" buttons  
  my @messages=&sortedmessages();  
  my $counter=0;  
  $r->print('<pre>');  
  my $escmsgid=&Apache::lonnet::escape($msgid);  
  foreach (@messages) {  
     if ($_->[5] eq $escmsgid){  
  last;  
     }  
     $counter++;  
  }  
  $r->print('</pre>');  
  my $number_of_messages = scalar(@messages); #subtract 1 for last index  
 # start output  
  $r->print('<html><head><title>EMail and Messaging</title>');  
  $r->print(&Apache::loncommon::studentbrowser_javascript().  
   '</head>'.  
   &Apache::loncommon::bodytag('EMail and Messages').  
   &Apache::loncommon::help_open_faq(12).  
   &Apache::loncommon::help_open_bug('Communication Tools'));  
  my %courseinfo=&Apache::lonnet::coursedescription($content{'courseid'});  
   
  $r->print('<br /><b>'.&mt('Subject').':</b> '.$content{'subject'}.  
   '<br /><b>'.&mt('From').':</b> '.  
   &Apache::loncommon::aboutmewrapper(  
      &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),  
      $content{'sendername'},$content{'senderdomain'}).' ('.  
   $content{'sendername'}.' at '.  
   $content{'senderdomain'}.') '.  
   ($content{'courseid'}?'<br /><b>'.&mt('Course').':</b> '.$courseinfo{'description'}.  
    ($content{'coursesec'}?' ('.&mt('Group/Section').': '.$content{'coursesec'}.')':''):'').  
   '<br /><b>'.&mt('Time').':</b> '.$content{'time'}.'<p>'.  
   '<table border=2><tr bgcolor="#FFFFAA"><td>'.&mt('Functions').':</td>'.  
   '<td><a href="/adm/email?replyto='.&Apache::lonnet::escape($msgid).$sqs.  
   '"><b>'.&mt('Reply').'</b></a></td>'.  
   '<td><a href="/adm/email?forward='.&Apache::lonnet::escape($msgid).$sqs.  
   '"><b>'.&mt('Forward').'</b></a></td>'.  
   '<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>'.  
   '<td><a href="/adm/email?sortedby='.$ENV{'form.sortedby'}.  
   '"><b>'.&mt('Display all Messages').'</b></a></td>');  
  if ($counter > 0){  
     $r->print('<td><a href="/adm/email?display='.$messages[$counter-1]->[5].$sqs.  
       '"><b>'.&mt('Previous').'</b></a></td>');  
  }  
  if ($counter < $number_of_messages - 1){  
     $r->print('<td><a href="/adm/email?display='.$messages[$counter+1]->[5].$sqs.  
       '"><b>'.&mt('Next').'</b></a></td>');  
  }  
  $r->print('</tr></table><p><pre>'.  
   &Apache::lontexconvert::msgtexconverted($content{'message'},1).  
   '</pre><hr>'.$content{'citation'});  
     } elsif ($ENV{'form.replyto'}) {      } elsif ($ENV{'form.replyto'}) {
  &comprep($r,$ENV{'form.replyto'});   &compout($r,'',$ENV{'form.replyto'},undef,undef,$folder);
     } elsif ($ENV{'form.sendreply'}) {  
  if ($ENV{'form.send'}) {  
     my $msgid=$ENV{'form.sendreply'};  
     my %message=&Apache::lonnet::get('nohist_email',[$msgid]);  
     my %content=&unpackagemsg($message{$msgid},1);  
     &statuschange($msgid,'replied');  
     if ((($ENV{'form.critmsg'}) || ($ENV{'form.sendbck'})) &&   
  (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'}))) {  
  $r->print(&mt('Sending critical message').': '.  
   &user_crit_msg($content{'sendername'},  
  $content{'senderdomain'},  
  &Apache::lonfeedback::clear_out_html($ENV{'form.subject'}),  
  &Apache::lonfeedback::clear_out_html($ENV{'form.message'}),  
  $ENV{'form.sendbck'}));  
     } else {  
  $r->print(&mt('Sending').': '.&user_normal_msg($content{'sendername'},  
        $content{'senderdomain'},  
        &Apache::lonfeedback::clear_out_html($ENV{'form.subject'}),  
        &Apache::lonfeedback::clear_out_html($ENV{'form.message'})));  
     }  
  }  
  if ($ENV{'form.displayedcrit'}) {  
     &discrit($r);  
  } else {  
     &disall($r);  
  }  
     } elsif ($ENV{'form.confirm'}) {      } elsif ($ENV{'form.confirm'}) {
    &printheader($r,'','Confirmed Receipt');
  foreach (keys %ENV) {   foreach (keys %ENV) {
     if ($_=~/^form\.rec\_(.*)$/) {      if ($_=~/^form\.rec\_(.*)$/) {
  $r->print('<b>Confirming Receipt:</b> '.   $r->print('<b>'.&mt('Confirming Receipt').':</b> '.
   &user_crit_received($1).'<br>');    &user_crit_received($1).'<br>');
     }      }
     if ($_=~/^form\.reprec\_(.*)$/) {      if ($_=~/^form\.reprec\_(.*)$/) {
  my $msgid=$1;   my $msgid=$1;
  $r->print('<b>Confirming Receipt:</b> '.   $r->print('<b>'.&mt('Confirming Receipt').':</b> '.
   &user_crit_received($msgid).'<br>');    &user_crit_received($msgid).'<br>');
  &comprep($r,$msgid);   &compout($r,'','','',$msgid);
     }      }
  }   }
  &discrit($r);   &discrit($r);
     } elsif ($ENV{'form.critical'}) {      } elsif ($ENV{'form.critical'}) {
    &printheader($r,'','Displaying Critical Messages');
  &discrit($r);   &discrit($r);
     } elsif ($ENV{'form.forward'}) {      } elsif ($ENV{'form.forward'}) {
  &compout($r,$ENV{'form.forward'});   &compout($r,$ENV{'form.forward'},undef,undef,undef,$folder);
     } elsif ($ENV{'form.markread'}) {  
     } elsif ($ENV{'form.markdel'}) {      } elsif ($ENV{'form.markdel'}) {
  &statuschange($ENV{'form.markdel'},'deleted');   &printheader($r,'','Deleted Message');
  &disall($r);   &statuschange($ENV{'form.markdel'},'deleted',$folder);
    &Apache::loncommunicate::menu($r);
    &disall($r,$folder);
       } elsif ($ENV{'form.markedmove'}) {
    my $total=0;
    foreach (keys %ENV) {
       if ($_=~/^form\.delmark_(.*)$/) {
    &movemsg(&Apache::lonnet::unescape($1),$folder,
    $ENV{'form.movetofolder'});
    $total++;
       }
    }
    &printheader($r,'','Moved Messages');
    $r->print('Moved '.$total.' message(s)<p>');
    &Apache::loncommunicate::menu($r);
    &disall($r,$folder);
     } elsif ($ENV{'form.markeddel'}) {      } elsif ($ENV{'form.markeddel'}) {
  my $total=0;   my $total=0;
  foreach (keys %ENV) {   foreach (keys %ENV) {
     if ($_=~/^form\.delmark_(.*)$/) {      if ($_=~/^form\.delmark_(.*)$/) {
  &statuschange(&Apache::lonnet::unescape($1),'deleted');   &statuschange(&Apache::lonnet::unescape($1),'deleted',$folder);
  $total++;   $total++;
     }      }
  }   }
    &printheader($r,'','Deleted Messages');
  $r->print('Deleted '.$total.' message(s)<p>');   $r->print('Deleted '.$total.' message(s)<p>');
  &disall($r);   &Apache::loncommunicate::menu($r);
    &disall($r,$folder);
     } elsif ($ENV{'form.markunread'}) {      } elsif ($ENV{'form.markunread'}) {
    &printheader($r,'','Marked Message as Unread');
  &statuschange($ENV{'form.markunread'},'new');   &statuschange($ENV{'form.markunread'},'new');
  &disall($r);   &Apache::loncommunicate::menu($r);
    &disall($r,$folder);
     } elsif ($ENV{'form.compose'}) {      } elsif ($ENV{'form.compose'}) {
  &compout($r,'',$ENV{'form.compose'});   &compout($r,'','',$ENV{'form.compose'});
     } elsif ($ENV{'form.recordftf'}) {      } elsif ($ENV{'form.recordftf'}) {
  &facetoface($r,$ENV{'form.recordftf'});   &facetoface($r,$ENV{'form.recordftf'});
       } elsif ($ENV{'form.block'}) {
           &examblock($r,$ENV{'form.block'});
     } elsif ($ENV{'form.sendmail'}) {      } elsif ($ENV{'form.sendmail'}) {
  my $sendstatus='';   &sendoffmail($r,$folder);
  if ($ENV{'form.send'}) {   if ($ENV{'form.storebasecomment'}) {
     my %content=();      &storecomment($r);
     undef %content;  
     if ($ENV{'form.forwid'}) {  
  my $msgid=$ENV{'form.forwid'};  
  my %message=&Apache::lonnet::get('nohist_email',[$msgid]);  
  %content=&unpackagemsg($message{$msgid},1);  
  &statuschange($msgid,'forwarded');  
  $ENV{'form.message'}.="\n\n-- Forwarded message --\n\n".  
     $content{'message'};  
     }  
     my %toaddr=();  
     undef %toaddr;  
     if ($ENV{'form.sendmode'} eq 'group') {  
  foreach (keys %ENV) {  
     if ($_=~/^form\.send\_to\_\&\&\&[^\&]*\&\&\&\_(.+)$/) {  
  $toaddr{$1}='';  
     }  
  }  
     } elsif ($ENV{'form.sendmode'} eq 'upload') {  
  foreach (split(/[\n\r\f]+/,$ENV{'form.upfile'})) {  
     my ($rec,$txt)=split(/\s*\:\s*/,$_);  
     if ($txt) {  
  $rec=~s/\@/\:/;  
  $toaddr{$rec}.=$txt."\n";  
     }  
  }  
     } else {  
  $toaddr{$ENV{'form.recuname'}.':'.$ENV{'form.recdomain'}}='';  
     }  
     if ($ENV{'form.additionalrec'}) {  
  foreach (split(/\,/,$ENV{'form.additionalrec'})) {  
     my ($auname,$audom)=split(/\@/,$_);  
     $toaddr{$auname.':'.$audom}='';  
  }  
     }  
     foreach (keys %toaddr) {  
  my ($recuname,$recdomain)=split(/\:/,$_);  
  my $msgtxt=&Apache::lonfeedback::clear_out_html($ENV{'form.message'});  
  if ($toaddr{$_}) { $msgtxt.='<hr>'.$toaddr{$_}; }      
  if ((($ENV{'form.critmsg'}) || ($ENV{'form.sendbck'})) &&   
     (&Apache::lonnet::allowed('srm',$ENV{'request.course.id'}))) {  
     $r->print(&mt('Sending critical message').' ...');  
     $sendstatus.=' '.&user_crit_msg($recuname,$recdomain,  
     &Apache::lonfeedback::clear_out_html($ENV{'form.subject'}),  
     $msgtxt,  
     $ENV{'form.sendbck'});  
  } else {  
     $r->print(&mt('Sending').' ...');  
     $sendstatus.=' '.&user_normal_msg($recuname,$recdomain,  
       &Apache::lonfeedback::clear_out_html($ENV{'form.subject'}),  
       $msgtxt,  
       $content{'citation'});  
  }  
  $r->print('<br />');  
     }  
  }  
  if ($sendstatus=~/^(\s*(?:ok|con_delayed)\s*)*$/) {  
     $r->print('<br /><font color="green">'.&mt('Completed.').'</font>');  
     if ($ENV{'form.displayedcrit'}) {  
  &discrit($r);  
     } else {  
  &disall($r);  
     }  
  } else {  
     $r->print(  
       '<h2><font color="red">'.&mt('Could not deliver message').'</font></h2>'.  
       &mt('Please use the browser "Back" button and correct the recipient addresses')  
       );  
  }   }
    &disall($r,$folder);
       } elsif ($ENV{'form.newfolder'}) {
    &printheader($r,'','New Folder');
    &makefolder($ENV{'form.newfolder'});
    &Apache::loncommunicate::menu($r);
    &disall($r,$ENV{'form.newfolder'});
       } elsif ($ENV{'form.showcommentbaseurl'}) {
    &storedcommentlisting($r);
     } else {      } else {
  &disall($r);   &printheader($r,'','Display All Messages');
    &Apache::loncommunicate::menu($r);
    &disall($r,$folder);
     }      }
     $r->print('</body></html>');      $r->print('</body></html>');
     return OK;      return OK;

Removed from v.1.89  
changed lines
  Added in v.1.125


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>