Annotation of loncom/interface/lonmsgdisplay.pm, revision 1.1

1.1     ! albertel    1: # The LearningOnline Network with CAPA
        !             2: # Routines for messaging display
        !             3: #
        !             4: # $Id: lonmsg.pm,v 1.179 2006/03/21 20:54:35 albertel Exp $
        !             5: #
        !             6: # Copyright Michigan State University Board of Trustees
        !             7: #
        !             8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
        !             9: #
        !            10: # LON-CAPA is free software; you can redistribute it and/or modify
        !            11: # it under the terms of the GNU General Public License as published by
        !            12: # the Free Software Foundation; either version 2 of the License, or
        !            13: # (at your option) any later version.
        !            14: #
        !            15: # LON-CAPA is distributed in the hope that it will be useful,
        !            16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            18: # GNU General Public License for more details.
        !            19: #
        !            20: # You should have received a copy of the GNU General Public License
        !            21: # along with LON-CAPA; if not, write to the Free Software
        !            22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
        !            23: #
        !            24: # /home/httpd/html/adm/gpl.txt
        !            25: #
        !            26: # http://www.lon-capa.org/
        !            27: #
        !            28: 
        !            29: 
        !            30: package Apache::lonmsgdisplay;
        !            31: 
        !            32: =pod
        !            33: 
        !            34: =head1 NAME
        !            35: 
        !            36: Apache::lonmsg: supports internal messaging
        !            37: 
        !            38: =head1 SYNOPSIS
        !            39: 
        !            40: lonmsg provides routines for sending messages, receiving messages, and
        !            41: a handler to allow users to read, send, and delete messages.
        !            42: 
        !            43: =head1 OVERVIEW
        !            44: 
        !            45: =head2 Messaging Overview
        !            46: 
        !            47: X<messages>LON-CAPA provides an internal messaging system similar to
        !            48: email, but customized for LON-CAPA's usage. LON-CAPA implements its
        !            49: own messaging system, rather then building on top of email, because of
        !            50: the features LON-CAPA messages can offer that conventional e-mail can
        !            51: not:
        !            52: 
        !            53: =over 4
        !            54: 
        !            55: =item * B<Critical messages>: A message the recipient B<must>
        !            56: acknowlegde receipt of before they are allowed to continue using the
        !            57: system, preventing a user from claiming they never got a message
        !            58: 
        !            59: =item * B<Receipts>: LON-CAPA can reliably send reciepts informing the
        !            60: sender that it has been read; again, useful for preventing students
        !            61: from claiming they did not see a message. (While conventional e-mail
        !            62: has some reciept support, it's sporadic, e-mail client-specific, and
        !            63: generally the receiver can opt to not send one, making it useless in
        !            64: this case.)
        !            65: 
        !            66: =item * B<Context>: LON-CAPA knows about the sender, such as where
        !            67: they are in a course. When a student mails an instructor asking for
        !            68: help on the problem, the instructor receives not just the student's
        !            69: question, but all submissions the student has made up to that point,
        !            70: the user's rendering of the problem, and the complete view the student
        !            71: saw of the resource, including discussion up to that point. Finally,
        !            72: the instructor is reading all of this inside of LON-CAPA, not their
        !            73: email program, so they have full access to LON-CAPA's grading
        !            74: interface, or other features they may wish to use in response to the
        !            75: student's query.
        !            76: 
        !            77: =item * B<Blocking>: LON-CAPA can block display of e-mails that are 
        !            78: sent to a student during an online exam. A course coordinator or
        !            79: instructor can set an open and close date/time for scheduled online
        !            80: exams in a course. If a user uses the LON-CAPA internal messaging 
        !            81: system to display e-mails during the scheduled blocking event,  
        !            82: display of all e-mail sent during the blocking period will be 
        !            83: suppressed, and a message of explanation, including details of the 
        !            84: currently active blocking periods will be displayed instead. A user 
        !            85: who has a course coordinator or instructor role in a course will be
        !            86: unaffected by any blocking periods for the course, unless the user
        !            87: also has a student role in the course, AND has selected the student role.
        !            88: 
        !            89: =back
        !            90: 
        !            91: Users can ask LON-CAPA to forward messages to conventional e-mail
        !            92: addresses on their B<PREF> screen, but generally, LON-CAPA messages
        !            93: are much more useful than traditional email can be made to be, even
        !            94: with HTML support.
        !            95: 
        !            96: Right now, this document will cover just how to send a message, since
        !            97: it is likely you will not need to programmatically read messages,
        !            98: since lonmsg already implements that functionality.
        !            99: 
        !           100: The routines used to package messages and unpackage messages are not
        !           101: only used by lonmsg when creating/extracting messages for LON-CAPA's
        !           102: internal messaging system, but also by lonnotify.pm which is available
        !           103: for use by Domain Coordinators to broadcast standard e-mail to specified
        !           104: users in their domain.  The XML packaging used in the two cases is very
        !           105: similar.  The differences are the use of <recuser>$uname</recuser> and 
        !           106: <recdomain>$udom</recdomain> in stored internal messages, compared 
        !           107: with <recipient username="$uname:$udom">$email</recipient> in stored
        !           108: Domain Coordinator e-mail for the storage of information about 
        !           109: recipients of the message/e-mail.
        !           110: 
        !           111: =head1 FUNCTIONS
        !           112: 
        !           113: =over 4
        !           114: 
        !           115: =cut
        !           116: 
        !           117: use strict;
        !           118: use Apache::lonnet;
        !           119: use vars qw($msgcount);
        !           120: use HTML::TokeParser();
        !           121: use Apache::Constants qw(:common);
        !           122: use Apache::loncommon();
        !           123: use Apache::lontexconvert();
        !           124: use HTML::Entities();
        !           125: use Apache::lonlocal;
        !           126: use Apache::loncommunicate;
        !           127: use Apache::lonfeedback;
        !           128: use Apache::lonrss();
        !           129: 
        !           130: # Querystring component with sorting type
        !           131: my $sqs;
        !           132: my $startdis;
        !           133: my $interdis;
        !           134: 
        !           135: # ============================================================ List all folders
        !           136: 
        !           137: sub folderlist {
        !           138:     my $folder=shift;
        !           139:     my @allfolders=&Apache::lonnet::getkeys('email_folders');
        !           140:     if ($allfolders[0]=~/^error:/) { @allfolders=(); }
        !           141:     return '<form method="post" action="/adm/email">'.
        !           142: 	&mt('Folder').': '.
        !           143: 	&Apache::loncommon::select_form($folder,'folder',
        !           144: 			     ('' => &mt('INBOX'),'trash' => &mt('TRASH'),
        !           145: 			      'new' => &mt('New Messages Only'),
        !           146:                               'critical' => &mt('Critical'),
        !           147: 			      'sent' => &mt('Sent Messages'),
        !           148: 			      map { $_ => $_ } @allfolders)).
        !           149: 			      ' '.&mt('Show').
        !           150: 			      '<select name="interdis">'.
        !           151: 			      join("\n",map { '<option value="'.$_.'"'.
        !           152: 	 ($_==$interdis?' selected="selected"':'').'>'.$_.'</option>' }
        !           153: 				   (10,20,50,100,200)).'</select>'.	
        !           154:    '<input type="submit" value="'.&mt('View Folder').'" /><br />'.
        !           155:     '<input type="hidden" name="sortedby" value="'.$env{'form.sortedby'}.'" />'.
        !           156: 			      ($folder=~/^(new|critical)/?'</form>':'');
        !           157: }
        !           158: 
        !           159: sub scrollbuttons {
        !           160:     my ($start,$maxdis,$first,$finish,$total)=@_;
        !           161:     unless ($total>0) { return ''; }
        !           162:     $start++; $maxdis++;$first++;$finish++;
        !           163:     return
        !           164:    &mt('Page').': '. 
        !           165:    '<input type="submit" name="firstview" value="'.&mt('First').'" />'.
        !           166:    '<input type="submit" name="prevview" value="'.&mt('Previous').'" />'.
        !           167:    '<input type="text" size="5" name="startdis" value="'.$start.'" onChange="this.form.submit()" /> of '.$maxdis.
        !           168:    '<input type="submit" name="nextview" value="'.&mt('Next').'" />'.
        !           169:    '<input type="submit" name="lastview" value="'.&mt('Last').'" /><br />'.
        !           170:    &mt('Showing messages [_1] through [_2] of [_3]',$first,$finish,$total).'</form>';
        !           171: }
        !           172: # =============================================================== Status Change
        !           173: 
        !           174: sub statuschange {
        !           175:     my ($msgid,$newstatus,$folder)=@_;
        !           176:     my $suffix=&foldersuffix($folder);
        !           177:     my %status=&Apache::lonnet::get('email_status'.$suffix,[$msgid]);
        !           178:     if ($status{$msgid}=~/^error\:/) { $status{$msgid}=''; }
        !           179:     unless ($status{$msgid}) { $status{$msgid}='new'; }
        !           180:     unless (($status{$msgid} eq 'replied') || 
        !           181:             ($status{$msgid} eq 'forwarded')) {
        !           182: 	&Apache::lonnet::put('email_status'.$suffix,{$msgid => $newstatus});
        !           183:     }
        !           184:     if (($newstatus eq 'deleted') || ($newstatus eq 'new')) {
        !           185: 	&Apache::lonnet::put('email_status'.$suffix,{$msgid => $newstatus});
        !           186:     }
        !           187:     if ($newstatus eq 'deleted') {
        !           188:        &movemsg(&Apache::lonnet::unescape($msgid),$folder,'trash');
        !           189:    }
        !           190: }
        !           191: 
        !           192: # ============================================================= Make new folder
        !           193: 
        !           194: sub makefolder {
        !           195:     my ($newfolder)=@_;
        !           196:     if (($newfolder eq 'sent')
        !           197:      || ($newfolder eq 'critical')
        !           198:      || ($newfolder eq 'trash')
        !           199:      || ($newfolder eq 'new')) { return; }
        !           200:     &Apache::lonnet::put('email_folders',{$newfolder => time});
        !           201: }
        !           202: 
        !           203: # ======================================================== Move between folders
        !           204: 
        !           205: sub movemsg {
        !           206:     my ($msgid,$srcfolder,$trgfolder)=@_;
        !           207:     if ($srcfolder eq 'new') { $srcfolder=''; }
        !           208:     my $srcsuffix=&foldersuffix($srcfolder);
        !           209:     my $trgsuffix=&foldersuffix($trgfolder);
        !           210: 
        !           211: # Copy message
        !           212:     my %message=&Apache::lonnet::get('nohist_email'.$srcsuffix,[$msgid]);
        !           213:     &Apache::lonnet::put('nohist_email'.$trgsuffix,{$msgid => $message{$msgid}});
        !           214: 
        !           215: # Copy status
        !           216:     unless ($trgfolder eq 'trash') {
        !           217: 	my %status=&Apache::lonnet::get('email_status'.$srcsuffix,[$msgid]);
        !           218: 	&Apache::lonnet::put('email_status'.$trgsuffix,{$msgid => $status{$msgid}});
        !           219:     }
        !           220: # Delete orginals
        !           221:     &Apache::lonnet::del('nohist_email'.$srcsuffix,[$msgid]);
        !           222:     &Apache::lonnet::del('email_status'.$srcsuffix,[$msgid]);
        !           223: }
        !           224: 
        !           225: # ======================================================= Display a course list
        !           226: 
        !           227: sub discourse {
        !           228:     my $r=shift;
        !           229:     my $classlist = &Apache::loncoursedata::get_classlist();
        !           230:     my $now=time;
        !           231:     my %lt=&Apache::lonlocal::texthash('cfa' => 'Check All',
        !           232:             'cfs' => 'Check Section/Group',
        !           233:             'cfn' => 'Uncheck All');
        !           234:     $r->print(<<ENDDISHEADER);
        !           235: <input type="hidden" name="sendmode" value="group" />
        !           236: <script>
        !           237:     function checkall() {
        !           238: 	for (i=0; i<document.forms.compemail.elements.length; i++) {
        !           239:             if 
        !           240:           (document.forms.compemail.elements[i].name.indexOf('send_to_')==0) {
        !           241: 	      document.forms.compemail.elements[i].checked=true;
        !           242:             }
        !           243:         }
        !           244:     }
        !           245: 
        !           246:     function checksec() {
        !           247: 	for (i=0; i<document.forms.compemail.elements.length; i++) {
        !           248:             if 
        !           249:           (document.forms.compemail.elements[i].name.indexOf
        !           250:            ('send_to_&&&'+document.forms.compemail.chksec.value+'&&&')==0) {
        !           251: 	      document.forms.compemail.elements[i].checked=true;
        !           252:             }
        !           253:         }
        !           254:     }
        !           255: 
        !           256:     function uncheckall() {
        !           257: 	for (i=0; i<document.forms.compemail.elements.length; i++) {
        !           258:             if 
        !           259:           (document.forms.compemail.elements[i].name.indexOf('send_to_')==0) {
        !           260: 	      document.forms.compemail.elements[i].checked=false;
        !           261:             }
        !           262:         }
        !           263:     }
        !           264: </script>
        !           265: <input type="button" onClick="checkall()" value="$lt{'cfa'}" />&nbsp;
        !           266: <input type="button" onClick="checksec()" value="$lt{'cfs'}" />
        !           267: <input type="text" size="5" name="chksec" />&nbsp;
        !           268: <input type="button" onClick="uncheckall()" value="$lt{'cfn'}" />
        !           269: <p>
        !           270: ENDDISHEADER
        !           271:     my %coursepersonnel=&Apache::lonnet::get_course_adv_roles();
        !           272:     $r->print('<table>');
        !           273:     foreach my $role (sort keys %coursepersonnel) {
        !           274:         foreach (split(/\,/,$coursepersonnel{$role})) {
        !           275:             my ($puname,$pudom)=split(/\:/,$_);
        !           276:             $r->print('<tr><td><label>'.
        !           277:                       '<input type="checkbox" name="send_to_&&&&&&_'.
        !           278:                       $puname.':'.$pudom.'" /> '.
        !           279:                       &Apache::loncommon::plainname($puname,$pudom).
        !           280:                       '</label></td>'.
        !           281:                       '<td>('.$_.'),</td><td><i>'.$role.'</i></td></tr>');
        !           282:         }
        !           283:     }
        !           284:     $r->print('</table><table>');
        !           285:     my $sort = sub {
        !           286: 	my $aname=lc($classlist->{$a}[&Apache::loncoursedata::CL_FULLNAME()]);
        !           287: 	if (!$aname) { $aname=$a; }
        !           288: 	my $bname=lc($classlist->{$b}[&Apache::loncoursedata::CL_FULLNAME()]);
        !           289: 	if (!$bname) { $bname=$b; }
        !           290: 	return $aname cmp $bname;
        !           291:     };
        !           292:     foreach my $student (sort $sort (keys(%{$classlist}))) {
        !           293: 	my $info=$classlist->{$student};
        !           294:         my ($sname,$sdom,$status,$fullname,$section) =
        !           295:             (@{$info}[&Apache::loncoursedata::CL_SNAME(),
        !           296:                       &Apache::loncoursedata::CL_SDOM(),
        !           297:                       &Apache::loncoursedata::CL_STATUS(),
        !           298:                       &Apache::loncoursedata::CL_FULLNAME(),
        !           299:                       &Apache::loncoursedata::CL_SECTION()]);
        !           300:         next if ($status ne 'Active');
        !           301: 	next if ($env{'request.course.sec'} &&
        !           302: 		 $section ne $env{'request.course.sec'});
        !           303:         my $key = 'send_to_&&&'.$section.'&&&_'.$student;
        !           304:         if (! defined($fullname) || $fullname eq '') { $fullname = $sname; }
        !           305:         $r->print('<tr><td><label>'.
        !           306:                   qq{<input type="checkbox" name="$key" />}.('&nbsp;'x2).
        !           307:                   $fullname.'</label></td><td>'.$sname.'@'.$sdom.'</td><td>'.$section.
        !           308:                   '</td></tr>');
        !           309:     }
        !           310:     $r->print('</table>');
        !           311: }
        !           312: 
        !           313: # ==================================================== Display Critical Message
        !           314: 
        !           315: sub discrit {
        !           316:     my $r=shift;
        !           317:     my $header = '<h1><font color=red>'.&mt('Critical Messages').'</font></h1>'.
        !           318:         '<form action="/adm/email" method="POST">'.
        !           319:         '<input type="hidden" name="confirm" value="true" />';
        !           320:     my %what=&Apache::lonnet::dump('critical');
        !           321:     my $result = '';
        !           322:     foreach (sort keys %what) {
        !           323:         my %content=&Apache::lonmsg::unpackagemsg($what{$_});
        !           324:         next if ($content{'senderdomain'} eq '');
        !           325:         $result.='<hr />'.&mt('From').': <b>'.
        !           326: &Apache::loncommon::aboutmewrapper(
        !           327:  &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).'</b> ('.
        !           328: $content{'sendername'}.'@'.
        !           329:             $content{'senderdomain'}.') '.$content{'time'}.
        !           330:             '<br />'.&mt('Subject').': '.$content{'subject'}.
        !           331:             '<br /><pre>'.
        !           332:               &Apache::lontexconvert::msgtexconverted($content{'message'}).
        !           333:             '</pre><small>'.
        !           334: &mt('You have to confirm that you received this message. After confirmation, this message will be moved to your regular inbox').
        !           335:             '</small><br />'.
        !           336:             '<input type="submit" name="rec_'.$_.'" value="'.&mt('Confirm Receipt').'" />'.
        !           337:             '<input type="submit" name="reprec_'.$_.'" '.
        !           338:                   'value="'.&mt('Confirm Receipt and Reply').'" />';
        !           339:     }
        !           340:     # Check to see if there were any messages.
        !           341:     if ($result eq '') {
        !           342:         $result = "<h2>".&mt('You have no critical messages.')."</h2>".
        !           343: 	    '<a href="/adm/roles">'.&mt('Select a course').'</a><br />'.
        !           344:             '<a href="/adm/email">'.&mt('Communicate').'</a>';
        !           345:     } else {
        !           346:         $r->print($header);
        !           347:     }
        !           348:     $r->print($result);
        !           349:     $r->print('<input type="hidden" name="displayedcrit" value="true" /></form>');
        !           350: }
        !           351: 
        !           352: sub sortedmessages {
        !           353:     my ($blocked,$startblock,$endblock,$numblocked,$folder) = @_;
        !           354:     my $suffix=&Apache::lonmsg::foldersuffix($folder);
        !           355:     my @messages = &Apache::lonnet::getkeys('nohist_email'.$suffix);
        !           356:     #unpack the varibles and repack into temp for sorting
        !           357:     my @temp;
        !           358:     my %descriptions;
        !           359:     my %status_cache = 
        !           360: 	&Apache::lonnet::get('email_status'.&Apache::lonmsg::foldersuffix($folder),\@messages);
        !           361:     foreach (@messages) {
        !           362: 	my $msgid=&Apache::lonnet::escape($_);
        !           363: 	my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$fromcid)=
        !           364: 	    &Apache::lonmsg::unpackmsgid($msgid,$folder,undef,
        !           365: 					 \%status_cache);
        !           366:         my $description = &get_course_desc($fromcid,\%descriptions);
        !           367: 	my @temp1 = ($sendtime,$shortsubj,$fromname,$fromdomain,$status,
        !           368: 		     $msgid,$description);
        !           369:         # Check whether message was sent during blocking period.
        !           370:         if ($sendtime >= $startblock && ($sendtime <= $endblock && $endblock > 0) ) {
        !           371:             my $escid = &Apache::lonnet::unescape($msgid);
        !           372:             $$blocked{$escid} = 'ON';
        !           373:             $$numblocked ++;
        !           374:         } else { 
        !           375:             push @temp ,\@temp1;
        !           376:         }
        !           377:     }
        !           378:     #default sort
        !           379:     @temp = sort  {$a->[0] <=> $b->[0]} @temp;    
        !           380:     if ($env{'form.sortedby'} eq "date"){
        !           381:         @temp = sort  {$a->[0] <=> $b->[0]} @temp;    
        !           382:     }
        !           383:     if ($env{'form.sortedby'} eq "revdate"){
        !           384:     	@temp = sort  {$b->[0] <=> $a->[0]} @temp; 
        !           385:     }
        !           386:     if ($env{'form.sortedby'} eq "user"){
        !           387: 	@temp = sort  {lc($a->[2]) cmp lc($b->[2])} @temp;
        !           388:     }
        !           389:     if ($env{'form.sortedby'} eq "revuser"){
        !           390: 	@temp = sort  {lc($b->[2]) cmp lc($a->[2])} @temp;
        !           391:     }
        !           392:     if ($env{'form.sortedby'} eq "domain"){
        !           393:         @temp = sort  {$a->[3] cmp $b->[3]} @temp;
        !           394:     }
        !           395:     if ($env{'form.sortedby'} eq "revdomain"){
        !           396:         @temp = sort  {$b->[3] cmp $a->[3]} @temp;
        !           397:     }
        !           398:     if ($env{'form.sortedby'} eq "subject"){
        !           399:         @temp = sort  {lc($a->[1]) cmp lc($b->[1])} @temp;
        !           400:     }
        !           401:     if ($env{'form.sortedby'} eq "revsubject"){
        !           402:         @temp = sort  {lc($b->[1]) cmp lc($a->[1])} @temp;
        !           403:     }
        !           404:     if ($env{'form.sortedby'} eq "course"){
        !           405:         @temp = sort  {lc($a->[6]) cmp lc($b->[6])} @temp;
        !           406:     }
        !           407:     if ($env{'form.sortedby'} eq "revcourse"){
        !           408:         @temp = sort  {lc($b->[6]) cmp lc($a->[6])} @temp;
        !           409:     }
        !           410:     if ($env{'form.sortedby'} eq "status"){
        !           411:         @temp = sort  {$a->[4] cmp $b->[4]} @temp;
        !           412:     }
        !           413:     if ($env{'form.sortedby'} eq "revstatus"){
        !           414:         @temp = sort  {$b->[4] cmp $a->[4]} @temp;
        !           415:     }
        !           416:     return @temp;
        !           417: }
        !           418: 
        !           419: sub get_course_desc {
        !           420:     my ($fromcid,$descriptions) = @_;
        !           421:     my $description;
        !           422:     if (!$fromcid) {
        !           423:         return $description;
        !           424:     } else {
        !           425:         if (defined($$descriptions{$fromcid})) {
        !           426:             $description = $$descriptions{$fromcid};
        !           427:         } else {
        !           428:             if (defined($env{'course.'.$fromcid.'.description'})) {
        !           429:                 $description = $env{'course.'.$fromcid.'.description'};
        !           430:             } else {
        !           431:                 my %courseinfo=&Apache::lonnet::coursedescription($fromcid);                $description = $courseinfo{'description'};
        !           432:                 $description = $courseinfo{'description'};
        !           433:             }
        !           434:             $$descriptions{$fromcid} = $description;
        !           435:         }
        !           436:         return $description;
        !           437:     }
        !           438: }
        !           439: 
        !           440: # ======================================================== Display new messages
        !           441: 
        !           442: 
        !           443: sub disnew {
        !           444:     my $r=shift;
        !           445:     my %lt=&Apache::lonlocal::texthash(
        !           446: 				       'nm' => 'New Messages',
        !           447: 				       'su' => 'Subject',
        !           448:                                        'co' => 'Course',
        !           449: 				       'da' => 'Date',
        !           450: 				       'us' => 'Username',
        !           451: 				       'op' => 'Open',
        !           452: 				       'do' => 'Domain'
        !           453: 				       );
        !           454:     my @msgids = sort(&Apache::lonnet::getkeys('nohist_email'));
        !           455:     my @newmsgs;
        !           456:     my %setters = ();
        !           457:     my $startblock = 0;
        !           458:     my $endblock = 0;
        !           459:     my %blocked = ();
        !           460:     my $numblocked = 0;
        !           461:     # Check for blocking of display because of scheduled online exams.
        !           462:     &blockcheck(\%setters,\$startblock,\$endblock);
        !           463:     my %status_cache = 
        !           464: 	&Apache::lonnet::get('email_status',\@msgids);
        !           465:     my %descriptions;
        !           466:     foreach (@msgids) {
        !           467: 	my $msgid=&Apache::lonnet::escape($_);
        !           468:         my ($sendtime,$shortsubj,$fromname,$fromdom,$status,$fromcid)=
        !           469: 	    &Apache::lonmsg::unpackmsgid($msgid,undef,undef,\%status_cache);
        !           470:         if (defined($sendtime) && $sendtime!~/error/) {
        !           471:             my $description = &get_course_desc($fromcid,\%descriptions);
        !           472:             my $numsendtime = $sendtime;
        !           473:             $sendtime = &Apache::lonlocal::locallocaltime($sendtime);
        !           474:             if ($status eq 'new') {
        !           475:                 if ($numsendtime >= $startblock && ($numsendtime <= $endblock && $endblock > 0) ) {
        !           476:                     $blocked{$_} = 'ON';
        !           477:                     $numblocked ++;
        !           478:                 } else {
        !           479:                     push @newmsgs, { 
        !           480:                         msgid    => $msgid,
        !           481:                         sendtime => $sendtime,
        !           482:                         shortsub => &Apache::lonnet::unescape($shortsubj),
        !           483:                         from     => $fromname,
        !           484:                         fromdom  => $fromdom,
        !           485:                         course   => $description 
        !           486:                         }
        !           487:                 }
        !           488:             }
        !           489:         }
        !           490:     }
        !           491:     if ($#newmsgs >= 0) {
        !           492:         $r->print(<<TABLEHEAD);
        !           493: <h2>$lt{'nm'}</h2>
        !           494: <table border=2><tr><th>&nbsp</th>
        !           495: <th>$lt{'da'}</th><th>$lt{'us'}</th><th>$lt{'do'}</th><th>$lt{'su'}</th><th>$lt{'co'}</th></tr>
        !           496: TABLEHEAD
        !           497:         foreach my $msg (@newmsgs) {
        !           498:             $r->print(<<"ENDLINK");
        !           499: <tr class="new" bgcolor="#FFBB77" onMouseOver="javascript:style.backgroundColor='#DD9955'" 
        !           500: onMouseOut="javascript:style.backgroundColor='#FFBB77'">
        !           501: <td><a href="/adm/email?dismode=new&display=$msg->{'msgid'}">$lt{'op'}</a></td>
        !           502: ENDLINK
        !           503:             foreach ('sendtime','from','fromdom','shortsub','course') {
        !           504:                 $r->print("<td>$msg->{$_}</td>");
        !           505:             }
        !           506:             $r->print("</td></tr>");
        !           507:         }
        !           508:         $r->print('</table>');
        !           509:     } elsif ($numblocked == 0) {
        !           510:         $r->print("<h3>".&mt('You have no unread messages')."</h3>");
        !           511:     }
        !           512:     if ($numblocked > 0) {
        !           513:         my $beginblock = &Apache::lonlocal::locallocaltime($startblock);
        !           514:         my $finishblock = &Apache::lonlocal::locallocaltime($endblock);
        !           515:         if ($numblocked == 1) {
        !           516:             $r->print("<h3>".&mt('You have').' '.$numblocked.' '.&mt('blocked unread message').".</h3>");
        !           517:             $r->print(&mt('This message is not viewable because').' ');
        !           518:         } else {
        !           519:             $r->print("<h3>".&mt('You have').' '.$numblocked.' '.&mt('blocked unread messages').".</h3>");
        !           520:             $r->print(&mt('These').' '.$numblocked.' '.&mt('messages are not viewable because '));
        !           521:         }
        !           522:         $r->print(
        !           523: &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').'.');
        !           524:         &build_block_table($r,$startblock,$endblock,\%setters);
        !           525:     }
        !           526: }
        !           527: 
        !           528: 
        !           529: # ======================================================== Display all messages
        !           530: 
        !           531: sub disall {
        !           532:     my ($r,$folder)=@_;
        !           533:     $r->print(&folderlist($folder));
        !           534:     if ($folder eq 'new') {
        !           535: 	&disnew($r);
        !           536:     } elsif ($folder eq 'critical') {
        !           537: 	&discrit($r);
        !           538:     } else {
        !           539: 	&disfolder($r,$folder);
        !           540:     }
        !           541: }
        !           542: 
        !           543: # ============================================================ Display a folder
        !           544: 
        !           545: sub disfolder {
        !           546:     my ($r,$folder)=@_;
        !           547:     my %blocked = ();
        !           548:     my %setters = ();
        !           549:     my $startblock;
        !           550:     my $endblock;
        !           551:     my $numblocked = 0;
        !           552:     &blockcheck(\%setters,\$startblock,\$endblock);
        !           553:     $r->print(<<ENDDISHEADER);
        !           554: <script>
        !           555:     function checkall() {
        !           556: 	for (i=0; i<document.forms.disall.elements.length; i++) {
        !           557:             if 
        !           558:           (document.forms.disall.elements[i].name.indexOf('delmark_')==0) {
        !           559: 	      document.forms.disall.elements[i].checked=true;
        !           560:             }
        !           561:         }
        !           562:     }
        !           563: 
        !           564:     function uncheckall() {
        !           565: 	for (i=0; i<document.forms.disall.elements.length; i++) {
        !           566:             if 
        !           567:           (document.forms.disall.elements[i].name.indexOf('delmark_')==0) {
        !           568: 	      document.forms.disall.elements[i].checked=false;
        !           569:             }
        !           570:         }
        !           571:     }
        !           572: </script>
        !           573: ENDDISHEADER
        !           574:     my $fsqs='&folder='.$folder;
        !           575:     my @temp=sortedmessages(\%blocked,$startblock,$endblock,\$numblocked,$folder);
        !           576:     my $totalnumber=$#temp+1;
        !           577:     unless ($totalnumber>0) {
        !           578: 	$r->print('<h2>'.&mt('Empty Folder').'</h2>');
        !           579: 	return;
        !           580:     }
        !           581:     unless ($interdis) {
        !           582: 	$interdis=20;
        !           583:     }
        !           584:     my $number=int($totalnumber/$interdis);
        !           585:     if (($startdis<0) || ($startdis>$number)) { $startdis=$number; }
        !           586:     my $firstdis=$interdis*$startdis;
        !           587:     if ($firstdis>$#temp) { $firstdis=$#temp-$interdis+1; }
        !           588:     my $lastdis=$firstdis+$interdis-1;
        !           589:     if ($lastdis>$#temp) { $lastdis=$#temp; }
        !           590:     $r->print(&scrollbuttons($startdis,$number,$firstdis,$lastdis,$totalnumber));
        !           591:     $r->print('<form method="post" name="disall" action="/adm/email">'.
        !           592: 	      '<table border=2><tr><th colspan="3">&nbsp</th><th>');
        !           593:     if ($env{'form.sortedby'} eq "revdate") {
        !           594: 	$r->print('<a href = "?sortedby=date'.$fsqs.'">'.&mt('Date').'</a></th>');
        !           595:     } else {
        !           596: 	$r->print('<a href = "?sortedby=revdate'.$fsqs.'">'.&mt('Date').'</a></th>');
        !           597:     }
        !           598:     $r->print('<th>');
        !           599:     if ($env{'form.sortedby'} eq "revuser") {
        !           600: 	$r->print('<a href = "?sortedby=user'.$fsqs.'">'.&mt('Username').'</a>');
        !           601:     } else {
        !           602: 	$r->print('<a href = "?sortedby=revuser'.$fsqs.'">'.&mt('Username').'</a>');
        !           603:     }
        !           604:     $r->print('</th><th>');
        !           605:     if ($env{'form.sortedby'} eq "revdomain") {
        !           606: 	$r->print('<a href = "?sortedby=domain'.$fsqs.'">'.&mt('Domain').'</a>');
        !           607:     } else {
        !           608: 	$r->print('<a href = "?sortedby=revdomain'.$fsqs.'">'.&mt('Domain').'</a>');
        !           609:     }
        !           610:     $r->print('</th><th>');
        !           611:     if ($env{'form.sortedby'} eq "revsubject") {
        !           612: 	$r->print('<a href = "?sortedby=subject'.$fsqs.'">'.&mt('Subject').'</a>');
        !           613:     } else {
        !           614:     	$r->print('<a href = "?sortedby=revsubject'.$fsqs.'">'.&mt('Subject').'</a>');
        !           615:     }
        !           616:     $r->print('</th><th>');
        !           617:     if ($env{'form.sortedby'} eq "revcourse") {
        !           618:         $r->print('<a href = "?sortedby=course'.$fsqs.'">'.&mt('Course').'</a>');
        !           619:     } else {
        !           620:         $r->print('<a href = "?sortedby=revcourse'.$fsqs.'">'.&mt('Course').'</a>');
        !           621:     }
        !           622:     $r->print('</th><th>');
        !           623:     if ($env{'form.sortedby'} eq "revstatus") {
        !           624: 	$r->print('<a href = "?sortedby=status'.$fsqs.'">'.&mt('Status').'</a></th>');
        !           625:     } else {
        !           626:      	$r->print('<a href = "?sortedby=revstatus'.$fsqs.'">'.&mt('Status').'</a></th>');
        !           627:     }
        !           628:     $r->print("</tr>\n");
        !           629:     for (my $n=$firstdis;$n<=$lastdis;$n++) {
        !           630: 	my ($sendtime,$shortsubj,$fromname,$fromdomain,$status,$origID,$description)= @{$temp[$n]};
        !           631: 	if (($status ne 'deleted') && defined($sendtime) && $sendtime!~/error/) {
        !           632: 	    if ($status eq 'new') {
        !           633: 		$r->print('<tr bgcolor="#FFBB77" onMouseOver="javascript:style.backgroundColor=\'#DD9955\'"  onMouseOut="javascript:style.backgroundColor=\'#FFBB77\'">');
        !           634: 	    } elsif ($status eq 'read') {
        !           635: 		$r->print('<tr bgcolor="#BBBB77" onMouseOver="javascript:style.backgroundColor=\'#999944\'"  onMouseOut="javascript:style.backgroundColor=\'#BBBB77\'">');
        !           636: 	    } elsif ($status eq 'replied') {
        !           637: 		$r->print('<tr bgcolor="#AAAA88" onMouseOver="javascript:style.backgroundColor=\'#888855\'"  onMouseOut="javascript:style.backgroundColor=\'#AAAA88\'">'); 
        !           638: 	    } else {
        !           639: 		$r->print('<tr bgcolor="#99BBBB" onMouseOver="javascript:style.backgroundColor=\'#669999\'"  onMouseOut="javascript:style.backgroundColor=\'#99BBBB\'">');
        !           640: 	    }
        !           641: 	    $r->print('<td><input type="checkbox" name="delmark_'.$origID.'" /></td><td><a href="/adm/email?display='.$origID.$sqs. 
        !           642: 		      '">'.&mt('Open').'</a></td><td>'.
        !           643: 		      ($folder ne 'trash'?'<a href="/adm/email?markdel='.$origID.$sqs.
        !           644: 		      '">'.&mt('Delete'):'&nbsp').'</a></td>'.
        !           645: 		      '<td>'.&Apache::lonlocal::locallocaltime($sendtime).'</td><td>'.
        !           646: 		      $fromname.'</td><td>'.$fromdomain.'</td><td>'.
        !           647: 		      &Apache::lonnet::unescape($shortsubj).'</td><td>'.
        !           648:                       $description.'</td><td>'.$status.'</td></tr>'."\n");
        !           649: 	} elsif ($status eq 'deleted') {
        !           650: # purge
        !           651: 	    &movemsg(&Apache::lonnet::unescape($origID),$folder,'trash');
        !           652: 	}
        !           653:     }   
        !           654:     $r->print("</table>\n<p>".
        !           655:   '<a href="javascript:checkall()">'.&mt('Check All').'</a>&nbsp;'.
        !           656:   '<a href="javascript:uncheckall()">'.&mt('Uncheck All').'</a></p>'.
        !           657:   '<input type="hidden" name="sortedby" value="'.$env{'form.sortedby'}.'" />');
        !           658:     if ($folder ne 'trash') {
        !           659: 	$r->print(
        !           660: 	      '<p><input type="submit" name="markeddel" value="'.&mt('Delete Checked').'" /></p>');
        !           661:     }
        !           662:     $r->print('<p><input type="submit" name="markedmove" value="'.&mt('Move Checked to Folder').'" />');
        !           663:     my @allfolders=&Apache::lonnet::getkeys('email_folders');
        !           664:     if ($allfolders[0]=~/^error:/) { @allfolders=(); }
        !           665:     $r->print(
        !           666: 	&Apache::loncommon::select_form('','movetofolder',
        !           667: 			     ( map { $_ => $_ } @allfolders))
        !           668: 	      );
        !           669:     my $postedstartdis=$startdis+1;
        !           670:     $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>');
        !           671:     if ($numblocked > 0) {
        !           672:         my $beginblock = &Apache::lonlocal::locallocaltime($startblock);
        !           673:         my $finishblock = &Apache::lonlocal::locallocaltime($endblock);
        !           674:         $r->print('<br /><br />'.
        !           675:                   $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.'));
        !           676:         &build_block_table($r,$startblock,$endblock,\%setters);
        !           677:     }
        !           678: }
        !           679: 
        !           680: # ============================================================== Compose output
        !           681: 
        !           682: sub compout {
        !           683:     my ($r,$forwarding,$replying,$broadcast,$replycrit,$folder,$dismode)=@_;
        !           684:     my $suffix=&Apache::lonmsg::foldersuffix($folder);
        !           685: 
        !           686:     if ($broadcast eq 'individual') {
        !           687: 	&printheader($r,'/adm/email?compose=individual',
        !           688: 	     'Send a Message');
        !           689:     } elsif ($broadcast) {
        !           690: 	&printheader($r,'/adm/email?compose=group',
        !           691: 	     'Broadcast Message');
        !           692:     } elsif ($forwarding) {
        !           693: 	&Apache::lonhtmlcommon::add_breadcrumb
        !           694:         ({href=>"/adm/email?display=".&Apache::lonnet::escape($forwarding),
        !           695:           text=>"Display Message"});
        !           696: 	&printheader($r,'/adm/email?forward='.&Apache::lonnet::escape($forwarding),
        !           697: 	     'Forwarding a Message');
        !           698:     } elsif ($replying) {
        !           699: 	&Apache::lonhtmlcommon::add_breadcrumb
        !           700:         ({href=>"/adm/email?display=".&Apache::lonnet::escape($replying),
        !           701:           text=>"Display Message"});
        !           702: 	&printheader($r,'/adm/email?replyto='.&Apache::lonnet::escape($replying),
        !           703: 	     'Replying to a Message');
        !           704:     } elsif ($replycrit) {
        !           705: 	$r->print('<h3>'.&mt('Replying to a Critical Message').'</h3>');
        !           706: 	$replying=$replycrit;
        !           707:     } else {
        !           708: 	&printheader($r,'/adm/email?compose=upload',
        !           709: 	     'Distribute from Uploaded File');
        !           710:     }
        !           711: 
        !           712:     my $dispcrit='';
        !           713:     my $dissub='';
        !           714:     my $dismsg='';
        !           715:     my $disbase='';
        !           716:     my $func=&mt('Send New');
        !           717:     my %lt=&Apache::lonlocal::texthash('us' => 'Username',
        !           718: 				       'do' => 'Domain',
        !           719: 				       'ad' => 'Additional Recipients',
        !           720: 				       'sb' => 'Subject',
        !           721: 				       'ca' => 'Cancel',
        !           722: 				       'ma' => 'Mail');
        !           723: 
        !           724:     if (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
        !           725: 	|| &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
        !           726: 				    '/'.$env{'request.course.sec'})) {
        !           727: 	 my $crithelp = Apache::loncommon::help_open_topic("Course_Critical_Message");
        !           728:          $dispcrit=
        !           729:  '<p><label><input type="checkbox" name="critmsg" /> '.&mt('Send as critical message').'</label> ' . $crithelp . 
        !           730:  '</p><p>'.
        !           731:  '<label><input type="checkbox" name="sendbck" /> '.&mt('Send as critical message').'  ' .
        !           732:  &mt('and return receipt') . '</label>' . $crithelp . 
        !           733:  '</p><p><label><input type="checkbox" name="permanent" /> '.
        !           734: &mt('Send copy to permanent email address (if known)').'</label></p>'.
        !           735: '<p><label><input type="checkbox" name="rsspost" /> '.
        !           736: 		  &mt('Include in course RSS newsfeed').'</label></p>';
        !           737:      }
        !           738:     my %message;
        !           739:     my %content;
        !           740:     my $defdom=$env{'user.domain'};
        !           741:     if ($forwarding) {
        !           742: 	%message=&Apache::lonnet::get('nohist_email'.$suffix,[$forwarding]);
        !           743: 	%content=&Apache::lonmsg::unpackagemsg($message{$forwarding},$folder);
        !           744: 	$dispcrit.='<input type="hidden" name="forwid" value="'.
        !           745: 	    $forwarding.'" />';
        !           746: 	$func=&mt('Forward');
        !           747: 	
        !           748: 	$dissub=&mt('Forwarding').': '.$content{'subject'};
        !           749: 	$dismsg=&mt('Forwarded message from').' '.
        !           750: 	    $content{'sendername'}.' '.&mt('at').' '.$content{'senderdomain'};
        !           751: 	if ($content{'baseurl'}) {
        !           752: 	    $disbase='<input type="hidden" name="baseurl" value="'.&Apache::lonnet::escape($content{'baseurl'}).'" />';
        !           753: 	}
        !           754:     }
        !           755:     if ($replying) {
        !           756: 	%message=&Apache::lonnet::get('nohist_email'.$suffix,[$replying]);
        !           757: 	%content=&Apache::lonmsg::unpackagemsg($message{$replying},$folder);
        !           758: 	$dispcrit.='<input type="hidden" name="replyid" value="'.
        !           759: 	    $replying.'" />';
        !           760: 	$func=&mt('Send Reply to');
        !           761: 	
        !           762: 	$dissub=&mt('Reply').': '.$content{'subject'};       
        !           763: 	$dismsg='> '.$content{'message'};
        !           764: 	$dismsg=~s/\r/\n/g;
        !           765: 	$dismsg=~s/\f/\n/g;
        !           766: 	$dismsg=~s/\n+/\n\> /g;
        !           767: 	if ($content{'baseurl'}) {
        !           768: 	    $disbase='<input type="hidden" name="baseurl" value="'.&Apache::lonnet::escape($content{'baseurl'}).'" />';
        !           769: 	    if ($env{'user.adv'}) {
        !           770: 		$disbase.='<label><input type="checkbox" name="storebasecomment" />'.&mt('Store message for re-use').
        !           771: 		    '</label> <a href="/adm/email?showcommentbaseurl='.
        !           772: 		    &Apache::lonnet::escape($content{'baseurl'}).'" target="comments">'.
        !           773: 		    &mt('Show re-usable messages').'</a><br />';
        !           774: 	    }
        !           775: 	}
        !           776:     }
        !           777:     my $citation=&displayresource(%content);
        !           778:     if ($env{'form.recdom'}) { $defdom=$env{'form.recdom'}; }
        !           779:       $r->print(
        !           780:                 '<form action="/adm/email"  name="compemail" method="post"'.
        !           781:                 ' enctype="multipart/form-data">'."\n".
        !           782:                 '<input type="hidden" name="sendmail" value="on" />'."\n".
        !           783:                 '<table>');
        !           784:     unless (($broadcast eq 'group') || ($broadcast eq 'upload')) {
        !           785: 	if ($replying) {
        !           786: 	    $r->print('<tr><td colspan="2">'.&mt('Replying to').' '.
        !           787: 		      &Apache::loncommon::aboutmewrapper(
        !           788: 							 &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).' ('.
        !           789: 		      $content{'sendername'}.'@'.
        !           790: 		      $content{'senderdomain'}.')'.
        !           791: 		      '<input type="hidden" name="recuname" value="'.$content{'sendername'}.'" />'.
        !           792: 		      '<input type="hidden" name="recdomain" value="'.$content{'senderdomain'}.'" />'.
        !           793: 		      '</td></tr>');
        !           794: 	} else {
        !           795: 	    my $domform = &Apache::loncommon::select_dom_form($defdom,'recdomain');
        !           796: 	    my $selectlink=&Apache::loncommon::selectstudent_link
        !           797: 	    ('compemail','recuname','recdomain');
        !           798: 	    $r->print(<<"ENDREC");
        !           799: <tr><td>$lt{'us'}:</td><td><input type="text" size="12" name="recuname" value="$env{'form.recname'}" /></td><td rowspan="2">$selectlink</td></tr>
        !           800: <tr><td>$lt{'do'}:</td>
        !           801: <td>$domform</td></tr>
        !           802: ENDREC
        !           803:         }
        !           804:     }
        !           805:     my $latexHelp = Apache::loncommon::helpLatexCheatsheet();
        !           806:     if ($broadcast ne 'upload') {
        !           807:        $r->print(<<"ENDCOMP");
        !           808: <tr><td>$lt{'ad'}<br /><tt>username\@domain,username\@domain, ...
        !           809: </tt></td><td>
        !           810: <input type="text" size="50" name="additionalrec" /></td></tr>
        !           811: <tr><td>$lt{'sb'}:</td><td><input type="text" size="50" name="subject" value="$dissub" />
        !           812: </td></tr></table>
        !           813: $latexHelp
        !           814: <textarea name="message" id="message" cols="80" rows="15" wrap="hard">$dismsg
        !           815: </textarea></p><br />
        !           816: $dispcrit
        !           817: $disbase
        !           818: <input type="hidden" name="folder" value="$folder" />
        !           819: <input type="hidden" name="dismode" value="$dismode" />
        !           820: <input type="submit" name="send" value="$func $lt{'ma'}" />
        !           821: <input type="submit" name="cancel" value="$lt{'ca'}" /><hr />
        !           822: $citation
        !           823: ENDCOMP
        !           824:     } else { # $broadcast is 'upload'
        !           825: 	$r->print(<<ENDUPLOAD);
        !           826: <input type="hidden" name="sendmode" value="upload" />
        !           827: <input type="hidden" name="send" value="on" />
        !           828: <h3>Generate messages from a file</h3>
        !           829: <p>
        !           830: Subject: <input type="text" size="50" name="subject" />
        !           831: </p>
        !           832: <p>General message text<br />
        !           833: <textarea name="message" id="message" cols="60" rows="10" wrap="hard">$dismsg
        !           834: </textarea></p>
        !           835: <p>
        !           836: The file format for the uploaded portion of the message is:
        !           837: <pre>
        !           838: username1\@domain1: text
        !           839: username2\@domain2: text
        !           840: username3\@domain1: text
        !           841: </pre>
        !           842: </p>
        !           843: <p>
        !           844: The messages will be assembled from all lines with the respective 
        !           845: <tt>username\@domain</tt>, and appended to the general message text.</p>
        !           846: <p>
        !           847: <input type="file" name="upfile" size="40" /></p><p>
        !           848: $dispcrit
        !           849: <input type="submit" value="Upload and Send" /></p>
        !           850: ENDUPLOAD
        !           851:     }
        !           852:     if ($broadcast eq 'group') {
        !           853:        &discourse($r);
        !           854:     }
        !           855:     $r->print('</form>'.
        !           856: 	      &Apache::lonfeedback::generate_preview_button('compemail','message').
        !           857: 	      &Apache::lonhtmlcommon::htmlareaselectactive('message'));
        !           858: }
        !           859: 
        !           860: # ---------------------------------------------------- Display all face to face
        !           861: 
        !           862: sub retrieve_instructor_comments {
        !           863:     my ($user,$domain)=@_;
        !           864:     my $target=$env{'form.grade_target'};
        !           865:     if (! $env{'request.course.id'}) { return; }
        !           866:     if (! &Apache::lonnet::allowed('srm',$env{'request.course.id'})
        !           867: 	&& ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
        !           868: 				      '/'.$env{'request.course.sec'})) {
        !           869: 	return;
        !           870:     }
        !           871:     my %records=&Apache::lonnet::dump('nohist_email',
        !           872: 			 $env{'course.'.$env{'request.course.id'}.'.domain'},
        !           873: 			 $env{'course.'.$env{'request.course.id'}.'.num'},
        !           874:                          '%255b'.$user.'%253a'.$domain.'%255d');
        !           875:     my $result='';
        !           876:     foreach (sort(keys(%records))) {
        !           877:         my %content=&Apache::lonmsg::unpackagemsg($records{$_});
        !           878:         next if ($content{'senderdomain'} eq '');
        !           879:         next if ($content{'subject'} !~ /^Record/);
        !           880: 	# &Apache::lonfeedback::newline_to_br(\$content{'message'});
        !           881: 	$result.='Recorded by '.
        !           882:             $content{'sendername'}.'@'.$content{'senderdomain'}."\n";
        !           883:         $result.=
        !           884:             &Apache::lontexconvert::msgtexconverted($content{'message'})."\n";
        !           885:      }
        !           886:     return $result;
        !           887: }
        !           888: 
        !           889: sub disfacetoface {
        !           890:     my ($r,$user,$domain)=@_;
        !           891:     my $target=$env{'form.grade_target'};
        !           892:     unless ($env{'request.course.id'}) { return; }
        !           893:     if  (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
        !           894: 	 && ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
        !           895: 				       '/'.$env{'request.course.sec'})) {
        !           896: 	$r->print('Not allowed');
        !           897: 	return;
        !           898:     }
        !           899:     my %records=&Apache::lonnet::dump('nohist_email',
        !           900: 			 $env{'course.'.$env{'request.course.id'}.'.domain'},
        !           901: 			 $env{'course.'.$env{'request.course.id'}.'.num'},
        !           902:                          '%255b'.$user.'%253a'.$domain.'%255d');
        !           903:     my $result='';
        !           904:     foreach (sort keys %records) {
        !           905:         my %content=&Apache::lonmsg::unpackagemsg($records{$_});
        !           906:         next if ($content{'senderdomain'} eq '');
        !           907: 	&Apache::lonfeedback::newline_to_br(\$content{'message'});
        !           908:         if ($content{'subject'}=~/^Record/) {
        !           909: 	    $result.='<h3>'.&mt('Record').'</h3>';
        !           910:         } elsif ($content{'subject'}=~/^Broadcast/) {
        !           911:             $result .='<h3>'.&mt('Broadcast Message').'</h3>';
        !           912:             if ($content{'subject'}=~/^Broadcast\./) {
        !           913:                 if (defined($content{'coursemsgid'})) {
        !           914:                     my $crsmsgid = &Apache::lonnet::escape($content{'coursemsgid'});
        !           915:                     my $broadcast_message = &general_message($crsmsgid);
        !           916:                     $content{'message'} = '<b>'.&mt('Subject').': '.$content{'message'}.'</b><br />'.$broadcast_message;
        !           917:                 } else {
        !           918:                     %content=&Apache::lonmsg::unpackagemsg($content{'message'});
        !           919:                     $content{'message'} =
        !           920:                     '<b>'.&mt('Subject').': '.$content{'subject'}.'</b><br />'.
        !           921:                     $content{'message'};
        !           922:                 }
        !           923:             }    
        !           924:         } else {
        !           925:             $result.='<h3>'.&mt('Critical Message').'</h3>';
        !           926:             if (defined($content{'coursemsgid'})) {
        !           927:                 my $crsmsgid=&Apache::lonnet::escape($content{'coursemsgid'});
        !           928:                 my $critical_message = &general_message($crsmsgid);
        !           929:                 $content{'message'} = '<b>'.&mt('Subject').': '.$content{'message'}.'</b><br />'.$critical_message;
        !           930:             } else {
        !           931:                 %content=&Apache::lonmsg::unpackagemsg($content{'message'});
        !           932:                 $content{'message'}=
        !           933:                 '<b>'.&mt('Subject').': '.$content{'subject'}.'</b><br />'.
        !           934: 		$content{'message'};
        !           935:             }
        !           936:         }
        !           937:         $result.=&mt('By').': <b>'.
        !           938: &Apache::loncommon::aboutmewrapper(
        !           939:  &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),$content{'sendername'},$content{'senderdomain'}).'</b> ('.
        !           940: $content{'sendername'}.'@'.
        !           941:             $content{'senderdomain'}.') '.$content{'time'}.
        !           942:             '<br /><pre>'.
        !           943:               &Apache::lontexconvert::msgtexconverted($content{'message'}).
        !           944: 	      '</pre>';
        !           945:      }
        !           946:     # Check to see if there were any messages.
        !           947:     if ($result eq '') {
        !           948: 	if ($target ne 'tex') { 
        !           949: 	    $r->print("<p><b>".&mt("No notes, face-to-face discussion records, critical messages, or broadcast messages in this course.")."</b></p>");
        !           950: 	} else {
        !           951: 	    $r->print('\textbf{'.&mt("No notes, face-to-face discussion records, critical messages or broadcast messages in this course.").'}\\\\');
        !           952: 	}
        !           953:     } else {
        !           954:        $r->print($result);
        !           955:     }
        !           956: }
        !           957: 
        !           958: sub general_message {
        !           959:     my ($crsmsgid) = @_;
        !           960:     my %general_content;
        !           961:     if ($crsmsgid) { 
        !           962:         my %course_content = &Apache::lonnet::get('nohist_email',[$crsmsgid],
        !           963:                            $env{'course.'.$env{'request.course.id'}.'.domain'},
        !           964:                            $env{'course.'.$env{'request.course.id'}.'.num'});
        !           965:         %general_content = &Apache::lonmsg::unpackagemsg($course_content{$crsmsgid});
        !           966:     }
        !           967:     return $general_content{'message'};
        !           968: }
        !           969: 
        !           970: # ---------------------------------------------------------------- Face to face
        !           971: 
        !           972: sub facetoface {
        !           973:     my ($r,$stage)=@_;
        !           974:     if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
        !           975: 	&& ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
        !           976: 				      '/'.$env{'request.course.sec'})) {
        !           977: 	$r->print('Not allowed');
        !           978: 	return;
        !           979:     }
        !           980:     &printheader($r,
        !           981: 		 '/adm/email?recordftf=query',
        !           982: 		 "User Notes, Face-to-Face, Critical Messages, Broadcast Messages");
        !           983: # from query string
        !           984: 
        !           985:     if ($env{'form.recname'}) { $env{'form.recuname'}=$env{'form.recname'}; }
        !           986:     if ($env{'form.recdom'}) { $env{'form.recdomain'}=$env{'form.recdom'}; }
        !           987: 
        !           988:     my $defdom=$env{'user.domain'};
        !           989: # already filled in
        !           990:     if ($env{'form.recdomain'}) { $defdom=$env{'form.recdomain'}; }
        !           991: # generate output
        !           992:     my $domform = &Apache::loncommon::select_dom_form($defdom,'recdomain');
        !           993:     my $stdbrws = &Apache::loncommon::selectstudent_link
        !           994: 	('stdselect','recuname','recdomain');
        !           995:     my %lt=&Apache::lonlocal::texthash('user' => 'Username',
        !           996: 				       'dom' => 'Domain',
        !           997: 				       'head' => 'User Notes, Records of Face-To-Face Discussions, Critical Messages, and Broadcast Messages in Course',
        !           998: 				       'subm' => 'Retrieve discussion and message records',
        !           999: 				       'newr' => 'New Record (record is visible to course faculty and staff)',
        !          1000: 				       'post' => 'Post this Record');
        !          1001:     $r->print(<<"ENDTREC");
        !          1002: <h3>$lt{'head'}</h3>
        !          1003: <form method="post" action="/adm/email" name="stdselect">
        !          1004: <input type="hidden" name="recordftf" value="retrieve" />
        !          1005: <table>
        !          1006: <tr><td>$lt{'user'}:</td><td><input type="text" size="12" name="recuname" value="$env{'form.recuname'}" /></td>
        !          1007: <td rowspan="2">
        !          1008: $stdbrws
        !          1009: <input type="submit" value="$lt{'subm'}" /></td>
        !          1010: </tr>
        !          1011: <tr><td>$lt{'dom'}:</td>
        !          1012: <td>$domform</td></tr>
        !          1013: </table>
        !          1014: </form>
        !          1015: ENDTREC
        !          1016:     if (($stage ne 'query') &&
        !          1017:         ($env{'form.recdomain'}) && ($env{'form.recuname'})) {
        !          1018:         chomp($env{'form.newrecord'});
        !          1019:         if ($env{'form.newrecord'}) {
        !          1020:            my $recordtxt = $env{'form.newrecord'};
        !          1021:            &Apache::lonmsg::user_normal_msg_raw(
        !          1022:             $env{'course.'.$env{'request.course.id'}.'.num'},
        !          1023:             $env{'course.'.$env{'request.course.id'}.'.domain'},
        !          1024:             &mt('Record').
        !          1025: 	     ' ['.$env{'form.recuname'}.':'.$env{'form.recdomain'}.']',
        !          1026: 	    $recordtxt);
        !          1027:         }
        !          1028:         $r->print('<h3>'.&Apache::loncommon::plainname($env{'form.recuname'},
        !          1029: 				     $env{'form.recdomain'}).'</h3>');
        !          1030:         &disfacetoface($r,$env{'form.recuname'},$env{'form.recdomain'});
        !          1031: 	$r->print(<<ENDRHEAD);
        !          1032: <form method="post" action="/adm/email">
        !          1033: <input name="recdomain" value="$env{'form.recdomain'}" type="hidden" />
        !          1034: <input name="recuname" value="$env{'form.recuname'}" type="hidden" />
        !          1035: ENDRHEAD
        !          1036:         $r->print(<<ENDBFORM);
        !          1037: <hr />$lt{'newr'}<br />
        !          1038: <textarea name="newrecord" cols="80" rows="10" wrap="hard"></textarea>
        !          1039: <br />
        !          1040: <input type="hidden" name="recordftf" value="post" />
        !          1041: <input type="submit" value="$lt{'post'}" />
        !          1042: </form>
        !          1043: ENDBFORM
        !          1044:     }
        !          1045: }
        !          1046: 
        !          1047: # ----------------------------------------------------------- Blocking during exams
        !          1048: 
        !          1049: sub examblock {
        !          1050:     my ($r,$action) = @_;
        !          1051:     unless ($env{'request.course.id'}) { return;}
        !          1052:     if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
        !          1053: 	&& ! &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
        !          1054: 				      '/'.$env{'request.course.sec'})) {
        !          1055: 	$r->print('Not allowed');
        !          1056: 	return;
        !          1057:     }
        !          1058:     my %lt=&Apache::lonlocal::texthash(
        !          1059:             'comb' => 'Communication Blocking',
        !          1060:             'cbds' => 'Communication blocking during scheduled exams',
        !          1061:             '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.',
        !          1062:              'mecb' => 'Modify existing communication blocking periods',
        !          1063:              'ncbc' => 'No communication blocks currently stored'
        !          1064:     );
        !          1065: 
        !          1066:     my %ltext = &Apache::lonlocal::texthash(
        !          1067:             'dura' => 'Duration',
        !          1068:             'setb' => 'Set by',
        !          1069:             'even' => 'Event',
        !          1070:             'actn' => 'Action',
        !          1071:             'star' => 'Start',
        !          1072:             'endd' => 'End'
        !          1073:     );
        !          1074: 
        !          1075:     &printheader($r,'/adm/email?block=display',$lt{'comb'});
        !          1076:     $r->print('<h3>'.$lt{'cbds'}.'</h3>');
        !          1077: 
        !          1078:     if ($action eq 'store') {
        !          1079:         &blockstore($r);
        !          1080:     }
        !          1081: 
        !          1082:     $r->print($lt{'desc'}.'<br /><br />
        !          1083:                <form name="blockform" method="post" action="/adm/email?block=store">
        !          1084:              ');
        !          1085: 
        !          1086:     $r->print('<h4>'.$lt{'mecb'}.'</h4>');
        !          1087:     my %records = ();
        !          1088:     my $blockcount = 0;
        !          1089:     my $parmcount = 0;
        !          1090:     &get_blockdates(\%records,\$blockcount);
        !          1091:     if ($blockcount > 0) {
        !          1092:         $parmcount = &display_blocker_status($r,\%records,\%ltext);
        !          1093:     } else {
        !          1094:         $r->print($lt{'ncbc'}.'<br /><br />');
        !          1095:     }
        !          1096:     &display_addblocker_table($r,$parmcount,\%ltext);
        !          1097:     my $end_page=&Apache::loncommon::end_page();
        !          1098:     $r->print(<<"END");
        !          1099: <br />
        !          1100: <input type="hidden" name="blocktotal" value="$blockcount" />
        !          1101: <input type ="submit" value="Save Changes" />
        !          1102: </form>
        !          1103: $end_page
        !          1104: END
        !          1105:     return;
        !          1106: }
        !          1107: 
        !          1108: sub blockstore {
        !          1109:     my $r = shift;
        !          1110:     my %lt=&Apache::lonlocal::texthash(
        !          1111:             'tfcm' => 'The following changes were made',
        !          1112:             'cbps' => 'communication blocking period(s)',
        !          1113:             'werm' => 'was/were removed',
        !          1114:             'wemo' => 'was/were modified',
        !          1115:             'wead' => 'was/were added',
        !          1116:             'ncwm' => 'No changes were made.' 
        !          1117:     );
        !          1118:     my %adds = ();
        !          1119:     my %removals = ();
        !          1120:     my %cancels = ();
        !          1121:     my $modtotal = 0;
        !          1122:     my $canceltotal = 0;
        !          1123:     my $addtotal = 0;
        !          1124:     my %blocking = ();
        !          1125:     $r->print('<h3>'.$lt{'head'}.'</h3>');
        !          1126:     foreach (keys %env) {
        !          1127:         if ($_ =~ m/^form\.modify_(\w+)$/) {
        !          1128:             $adds{$1} = $1;
        !          1129:             $removals{$1} = $1;
        !          1130:             $modtotal ++;
        !          1131:         } elsif ($_ =~ m/^form\.cancel_(\d+)$/) {
        !          1132:             $cancels{$1} = $1;
        !          1133:             unless ( defined($removals{$1}) ) {
        !          1134:                 $removals{$1} = $1;
        !          1135:                 $canceltotal ++;
        !          1136:             }
        !          1137:         } elsif ($_ =~ m/^form\.add_(\d+)$/) {
        !          1138:             $adds{$1} = $1;
        !          1139:             $addtotal ++;
        !          1140:         }
        !          1141:     }
        !          1142: 
        !          1143:     foreach (keys %removals) {
        !          1144:         my $hashkey = $env{'form.key_'.$_};
        !          1145:         &Apache::lonnet::del('comm_block',["$hashkey"],
        !          1146:                          $env{'course.'.$env{'request.course.id'}.'.domain'},
        !          1147:                          $env{'course.'.$env{'request.course.id'}.'.num'}
        !          1148:                          );
        !          1149:     }
        !          1150:     foreach (keys %adds) {
        !          1151:         unless ( defined($cancels{$_}) ) {
        !          1152:             my ($newstart,$newend) = &get_dates_from_form($_);
        !          1153:             my $newkey = $newstart.'____'.$newend;
        !          1154:             $blocking{$newkey} = $env{'user.name'}.'@'.$env{'user.domain'}.':'.$env{'form.title_'.$_};
        !          1155:         }
        !          1156:     }
        !          1157:     if ($addtotal + $modtotal > 0) {
        !          1158:         &Apache::lonnet::put('comm_block',\%blocking,
        !          1159:                      $env{'course.'.$env{'request.course.id'}.'.domain'},
        !          1160:                      $env{'course.'.$env{'request.course.id'}.'.num'}
        !          1161:                      );
        !          1162:     }
        !          1163:     my $chgestotal = $canceltotal + $modtotal + $addtotal;
        !          1164:     if ($chgestotal > 0) {
        !          1165:         $r->print($lt{'tfcm'}.'<ul>');
        !          1166:         if ($canceltotal > 0) {
        !          1167:             $r->print('<li>'.$canceltotal.' '.$lt{'cbps'},' '.$lt{'werm'}.'</li>');
        !          1168:         }
        !          1169:         if ($modtotal > 0) {
        !          1170:             $r->print('<li>'.$modtotal.' '.$lt{'cbps'},' '.$lt{'wemo'}.'</li>');
        !          1171:         }
        !          1172:         if ($addtotal > 0) {
        !          1173:             $r->print('<li>'.$addtotal.' '.$lt{'cbps'},' '.$lt{'wead'}.'</li>');
        !          1174:         }
        !          1175:         $r->print('</ul>');
        !          1176:     } else {
        !          1177:         $r->print($lt{'ncwm'});
        !          1178:     }
        !          1179:     $r->print('<br />');
        !          1180:     return;
        !          1181: }
        !          1182: 
        !          1183: sub get_dates_from_form {
        !          1184:     my $item = shift;
        !          1185:     my $startdate = &Apache::lonhtmlcommon::get_date_from_form('startdate_'.$item);
        !          1186:     my $enddate   = &Apache::lonhtmlcommon::get_date_from_form('enddate_'.$item);
        !          1187:     return ($startdate,$enddate);
        !          1188: }
        !          1189: 
        !          1190: sub get_blockdates {
        !          1191:     my ($records,$blockcount) = @_;
        !          1192:     $$blockcount = 0;
        !          1193:     %{$records} = &Apache::lonnet::dump('comm_block',
        !          1194:                          $env{'course.'.$env{'request.course.id'}.'.domain'},
        !          1195:                          $env{'course.'.$env{'request.course.id'}.'.num'}
        !          1196:                          );
        !          1197:     $$blockcount = keys %{$records};
        !          1198:                                                                                                              
        !          1199:     foreach (keys %{$records}) {
        !          1200:         if ($_ eq 'error: 2 tie(GDBM) Failed while attempting dump') {
        !          1201:             $$blockcount = 0;
        !          1202:             last;
        !          1203:         }
        !          1204:     }
        !          1205: }
        !          1206: 
        !          1207: sub display_blocker_status {
        !          1208:     my ($r,$records,$ltext) = @_;
        !          1209:     my $parmcount = 0;
        !          1210:     my @bgcols = ("#eeeeee","#dddddd");
        !          1211:     my $function = &Apache::loncommon::get_users_function();
        !          1212:     my $color = &Apache::loncommon::designparm($function.'.tabbg',
        !          1213:                                                     $env{'user.domain'});
        !          1214:     my %lt = &Apache::lonlocal::texthash(
        !          1215:         'modi' => 'Modify',
        !          1216:         'canc' => 'Cancel',
        !          1217:     );
        !          1218:     $r->print(<<"END");
        !          1219: <table border="0" cellpadding="0" cellspacing="0">
        !          1220:  <tr>
        !          1221:   <td width="100%" bgcolor="#000000">
        !          1222:    <table width="100%" border="0" cellpadding="1" cellspacing="0">
        !          1223:     <tr>
        !          1224:      <td width="100%" bgcolor="#000000">
        !          1225:       <table border="0" cellpadding="3" cellspacing="3" bgcolor="#FFFFFF">
        !          1226:        <tr bgcolor="$color">
        !          1227:         <td><b>$$ltext{'dura'}</b></td>
        !          1228:         <td><b>$$ltext{'setb'}</b></td>
        !          1229:         <td><b>$$ltext{'even'}</b></td>
        !          1230:         <td><b>$$ltext{'actn'}?</b></td>
        !          1231:        </tr>
        !          1232: END
        !          1233:     foreach (sort keys %{$records}) {
        !          1234:         my $iter = $parmcount%2;
        !          1235:         my $onchange = 'onFocus="javascript:window.document.forms['.
        !          1236:                        "'blockform'].elements['modify_".$parmcount."'].".
        !          1237:                        'checked=true;"';
        !          1238:         my ($start,$end) = split/____/,$_;
        !          1239:         my $startform = &Apache::lonhtmlcommon::date_setter('blockform','startdate_'.$parmcount,$start,$onchange);
        !          1240:         my $endform = &Apache::lonhtmlcommon::date_setter('blockform','enddate_'.$parmcount,$end,$onchange);
        !          1241:         my ($setter,$title) = split/:/,$$records{$_};
        !          1242:         my ($setuname,$setudom) = split/@/,$setter;
        !          1243:         my $settername = &Apache::loncommon::plainname($setuname,$setudom);
        !          1244:         $r->print(<<"END");
        !          1245:        <tr bgcolor="$bgcols[$iter]">
        !          1246:         <td>$$ltext{'star'}:&nbsp;$startform<br/>$$ltext{'endd'}:&nbsp;&nbsp;$endform</td>
        !          1247:         <td>$settername</td>
        !          1248:         <td><input type="text" name="title_$parmcount" size="15" value="$title" /><input type="hidden" name="key_$parmcount" value="$_" /></td>
        !          1249:         <td><label>$lt{'modi'}?&nbsp;<input type="checkbox" name="modify_$parmcount" /></label><br /><label>$lt{'canc'}?&nbsp;&nbsp;<input type="checkbox" name="cancel_$parmcount" /></label>
        !          1250:        </tr>
        !          1251: END
        !          1252:         $parmcount ++;
        !          1253:     }
        !          1254:     $r->print(<<"END");
        !          1255:       </table>
        !          1256:      </td>
        !          1257:     </tr>
        !          1258:    </table>
        !          1259:   </td>
        !          1260:  </tr>
        !          1261: </table>
        !          1262: <br />
        !          1263: <br />
        !          1264: END
        !          1265:     return $parmcount;
        !          1266: }
        !          1267: 
        !          1268: sub display_addblocker_table {
        !          1269:     my ($r,$parmcount,$ltext) = @_;
        !          1270:     my $start = time;
        !          1271:     my $end = $start + (60 * 60 * 2); #Default is an exam of 2 hours duration.
        !          1272:     my $onchange = 'onFocus="javascript:window.document.forms['.
        !          1273:                    "'blockform'].elements['add_".$parmcount."'].".
        !          1274:                    'checked=true;"';
        !          1275:     my $startform = &Apache::lonhtmlcommon::date_setter('blockform','startdate_'.$parmcount,$start,$onchange);
        !          1276:     my $endform = &Apache::lonhtmlcommon::date_setter('blockform','enddate_'.$parmcount,$end,$onchange);
        !          1277:     my $function = &Apache::loncommon::get_users_function();
        !          1278:     my $color = &Apache::loncommon::designparm($function.'.tabbg',
        !          1279:                                                     $env{'user.domain'});
        !          1280:     my %lt = &Apache::lonlocal::texthash(
        !          1281:         'addb' => 'Add block',
        !          1282:         'exam' => 'e.g., Exam 1',
        !          1283:         'addn' => 'Add new communication blocking periods'
        !          1284:     );
        !          1285:     $r->print(<<"END");
        !          1286: <h4>$lt{'addn'}</h4> 
        !          1287: <table border="0" cellpadding="0" cellspacing="0">
        !          1288:  <tr>
        !          1289:   <td width="100%" bgcolor="#000000">
        !          1290:    <table width="100%" border="0" cellpadding="1" cellspacing="0">
        !          1291:     <tr>
        !          1292:      <td width="100%" bgcolor="#000000">
        !          1293:       <table border="0" cellpadding="3" cellspacing="3" bgcolor="#FFFFFF">
        !          1294:        <tr bgcolor="#CCCCFF">
        !          1295:         <td><b>$$ltext{'dura'}</b></td>
        !          1296:         <td><b>$$ltext{'even'} $lt{'exam'}</b></td>
        !          1297:         <td><b>$$ltext{'actn'}?</b></td>
        !          1298:        </tr>
        !          1299:        <tr bgcolor="#eeeeee">
        !          1300:         <td>$$ltext{'star'}:&nbsp;$startform<br />$$ltext{'endd'}:&nbsp;&nbsp;$endform</td>
        !          1301:         <td><input type="text" name="title_$parmcount" size="15" value="" /></td>
        !          1302:         <td><label>$lt{'addb'}?&nbsp;<input type="checkbox" name="add_$parmcount" value="1" /></label></td>
        !          1303:        </tr>
        !          1304:       </table>
        !          1305:      </td>
        !          1306:     </tr>
        !          1307:    </table>
        !          1308:   </td>
        !          1309:  </tr>
        !          1310: </table>
        !          1311: END
        !          1312:     return;
        !          1313: }
        !          1314: 
        !          1315: sub blockcheck {
        !          1316:     my ($setters,$startblock,$endblock) = @_;
        !          1317:     # Retrieve active student roles and active course coordinator/instructor roles
        !          1318:     my @livecses = ();
        !          1319:     my @staffcses = ();
        !          1320:     $$startblock = 0;
        !          1321:     $$endblock = 0;
        !          1322:     foreach (keys %env) {
        !          1323:         if ($_ =~ m-^user\.role\.(st|cc|in)\./(.+)$-) {
        !          1324:             my $role = $1;
        !          1325:             my $cse = $2;
        !          1326:             $cse =~ s|/|_|;
        !          1327:             if ($env{$_} =~ m/^(\d*)\.(\d*)$/) {
        !          1328:                 unless (($2 > 0 && $2 < time) || ($1 > time)) {
        !          1329:                     if ($role eq 'st') {
        !          1330:                         push @livecses, $cse;
        !          1331:                     } else {
        !          1332:                         unless (grep/^$cse$/,@staffcses) {
        !          1333:                             push @staffcses, $cse;
        !          1334:                         }
        !          1335:                     }
        !          1336:                 }
        !          1337:             }
        !          1338:         } elsif ($_ =~ m-user\.role\.cr/(\w+)/(\w+)/([^/]+)\./(.+)$- ) { 
        !          1339:             my $rolepriv = $env{'user.role..rolesdef_'.$3};
        !          1340:         }
        !          1341:     }
        !          1342:     # Retrieve blocking times and identity of blocker for active courses for students.
        !          1343:     if (@livecses > 0) {
        !          1344:         foreach my $cse (@livecses) {
        !          1345:             my ($cdom,$crs) = split/_/,$cse;
        !          1346:             if ( (grep/^$cse$/,@staffcses) && ($env{'request.role'} !~ m-^st\./$cdom/$crs$-) ) {
        !          1347:                 next;
        !          1348:             } else {
        !          1349:                 %{$$setters{$cse}} = ();
        !          1350:                 @{$$setters{$cse}{'staff'}} = ();
        !          1351:                 @{$$setters{$cse}{'times'}} = ();
        !          1352:                 my %records = &Apache::lonnet::dump('comm_block',$cdom,$crs);
        !          1353:                 foreach (keys %records) {
        !          1354:                     if ($_ =~ m/^(\d+)____(\d+)$/) {
        !          1355:                         if ($1 <= time && $2 >= time) {
        !          1356:                             my ($staff,$title) = split/:/,$records{$_};
        !          1357:                             push @{$$setters{$cse}{'staff'}}, $staff;
        !          1358:                             push @{$$setters{$cse}{'times'}}, $_;
        !          1359:                             if ( ($$startblock == 0) || ($$startblock > $1) ) {
        !          1360:                                 $$startblock = $1;
        !          1361:                             }
        !          1362:                             if ( ($$endblock == 0) || ($$endblock < $2) ) {
        !          1363:                                 $$endblock = $2;
        !          1364:                             }
        !          1365:                         }
        !          1366:                     }
        !          1367:                 }
        !          1368:             }
        !          1369:         }
        !          1370:     }
        !          1371: }
        !          1372: 
        !          1373: sub build_block_table {
        !          1374:     my ($r,$startblock,$endblock,$setters) = @_;
        !          1375:     my $function = &Apache::loncommon::get_users_function();
        !          1376:     my $color = &Apache::loncommon::designparm($function.'.tabbg',
        !          1377:                                                     $env{'user.domain'});
        !          1378:     my %lt = &Apache::lonlocal::texthash(
        !          1379:         'cacb' => 'Currently active communication blocks',
        !          1380:         'cour' => 'Course',
        !          1381:         'dura' => 'Duration',
        !          1382:         'blse' => 'Block set by'
        !          1383:     ); 
        !          1384:     $r->print(<<"END");
        !          1385: <br /<br />$lt{'cacb'}:<br /><br />
        !          1386: <table border="0" cellpadding="0" cellspacing="0">
        !          1387:  <tr>
        !          1388:   <td width="100%" bgcolor="#000000">
        !          1389:    <table width="100%" border="0" cellpadding="1" cellspacing="0">
        !          1390:     <tr>
        !          1391:      <td width="100%" bgcolor="#000000">
        !          1392:       <table border="0" cellpadding="3" cellspacing="3" bgcolor="#FFFFFF">
        !          1393:        <tr bgcolor="$color">
        !          1394:         <td><b>$lt{'cour'}</b></td>
        !          1395:         <td><b>$lt{'dura'}</b></td>
        !          1396:         <td><b>$lt{'blse'}</b></td>
        !          1397:        </tr>
        !          1398: END
        !          1399:     foreach (keys %{$setters}) {
        !          1400:         my %courseinfo=&Apache::lonnet::coursedescription($_);
        !          1401:         for (my $i=0; $i<@{$$setters{$_}{staff}}; $i++) {
        !          1402:             my ($uname,$udom) = split/\@/,$$setters{$_}{staff}[$i];
        !          1403:             my $fullname = &Apache::loncommon::plainname($uname,$udom);
        !          1404:             my ($openblock,$closeblock) = split/____/,$$setters{$_}{times}[$i];
        !          1405:             $openblock = &Apache::lonlocal::locallocaltime($openblock);
        !          1406:             $closeblock= &Apache::lonlocal::locallocaltime($closeblock);
        !          1407:             $r->print('<tr><td>'.$courseinfo{'description'}.'</td>'.
        !          1408:                       '<td>'.$openblock.' to '.$closeblock.'</td>'.
        !          1409:                       '<td>'.$fullname.' ('.$uname.'@'.$udom.
        !          1410:                       ')</td></tr>');
        !          1411:         }
        !          1412:     }
        !          1413:     $r->print('</table></td></tr></table></td></tr></table>');
        !          1414: }
        !          1415: 
        !          1416: # ----------------------------------------------------------- Display a message
        !          1417: 
        !          1418: sub displaymessage {
        !          1419:     my ($r,$msgid,$folder)=@_;
        !          1420:     my $suffix=&Apache::lonmsg::foldersuffix($folder);
        !          1421:     my %blocked = ();
        !          1422:     my %setters = ();
        !          1423:     my $startblock = 0;
        !          1424:     my $endblock = 0;
        !          1425:     my $numblocked = 0;
        !          1426: # info to generate "next" and "previous" buttons and check if message is blocked
        !          1427:     &blockcheck(\%setters,\$startblock,\$endblock);
        !          1428:     my @messages=&sortedmessages(\%blocked,$startblock,$endblock,\$numblocked,$folder);
        !          1429:     if ( $blocked{$msgid} eq 'ON' ) {
        !          1430:         &printheader($r,'/adm/email',&mt('Display a Message'));
        !          1431:         $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.'));
        !          1432:         &build_block_table($r,$startblock,$endblock,\%setters);
        !          1433:         return;
        !          1434:     }
        !          1435:     &statuschange($msgid,'read',$folder);
        !          1436:     my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]);
        !          1437:     my %content=&Apache::lonmsg::unpackagemsg($message{$msgid});
        !          1438: 
        !          1439:     my $counter=0;
        !          1440:     $r->print('<pre>');
        !          1441:     my $escmsgid=&Apache::lonnet::escape($msgid);
        !          1442:     foreach (@messages) {
        !          1443: 	if ($_->[5] eq $escmsgid){
        !          1444: 	    last;
        !          1445: 	}
        !          1446: 	$counter++;
        !          1447:     }
        !          1448:     $r->print('</pre>');
        !          1449:     my $number_of_messages = scalar(@messages); #subtract 1 for last index
        !          1450: # start output
        !          1451:     &printheader($r,'/adm/email?display='.&Apache::lonnet::escape($msgid),'Display a Message','',$content{'baseurl'});
        !          1452:     my %courseinfo=&Apache::lonnet::coursedescription($content{'courseid'});
        !          1453: # Functions
        !          1454:     $r->print('<table border="2" width="100%"><tr bgcolor="#FFFFAA"><td>'.&mt('Functions').':</td>'.
        !          1455: 	      '<td><a href="/adm/email?replyto='.&Apache::lonnet::escape($msgid).$sqs.
        !          1456: 	      '"><b>'.&mt('Reply').'</b></a></td>'.
        !          1457: 	      '<td><a href="/adm/email?forward='.&Apache::lonnet::escape($msgid).$sqs.
        !          1458: 	      '"><b>'.&mt('Forward').'</b></a></td>'.
        !          1459: 	      '<td><a href="/adm/email?markunread='.&Apache::lonnet::escape($msgid).$sqs.
        !          1460: 	      '"><b>'.&mt('Mark Unread').'</b></a></td>'.
        !          1461: 	      '<td><a href="/adm/email?markdel='.&Apache::lonnet::escape($msgid).$sqs.
        !          1462: 	      '"><b>'.&mt('Delete').'</b></a></td>'.
        !          1463: 	      '<td><a href="/adm/email?'.$sqs.
        !          1464: 	      ($env{'form.dismode'} eq 'new'?'&folder=new':'').
        !          1465: 	      '"><b>'.&mt('Back to Folder Display').'</b></a></td>');
        !          1466:     if ($counter > 0){
        !          1467: 	$r->print('<td><a href="/adm/email?display='.$messages[$counter-1]->[5].$sqs.
        !          1468: 		  '"><b>'.&mt('Previous').'</b></a></td>');
        !          1469:     }
        !          1470:     if ($counter < $number_of_messages - 1){
        !          1471: 	$r->print('<td><a href="/adm/email?display='.$messages[$counter+1]->[5].$sqs.
        !          1472: 		  '"><b>'.&mt('Next').'</b></a></td>');
        !          1473:     }
        !          1474:     $r->print('</tr></table>');
        !          1475:     if ($env{'user.adv'}) {
        !          1476: 	$r->print('<table border="2" width="100%"><tr bgcolor="#FFAAAA"><td>'.&mt('Currently available actions (will open extra window)').':</td>');
        !          1477: 	my $symb=&Apache::lonnet::symbread($content{'baseurl'});      
        !          1478: 	if (&Apache::lonnet::allowed('vgr',$env{'request.course.id'})) {
        !          1479: 		$r->print('<td><b>'.&Apache::loncommon::track_student_link(&mt('View recent activity'),$content{'sendername'},$content{'senderdomain'},'check').'</b></td>');
        !          1480: 	    }
        !          1481: 	if (&Apache::lonnet::allowed('opa',$env{'request.course.id'}) && $symb) {
        !          1482: 	    $r->print('<td><b>'.&Apache::loncommon::pprmlink(&mt('Set/Change parameters'),$content{'sendername'},$content{'senderdomain'},$symb,'check').'</b></td>');
        !          1483: 	}
        !          1484: 	if (&Apache::lonnet::allowed('mgr',$env{'request.course.id'}) && $symb) {
        !          1485: 	    $r->print('<td><b>'.&Apache::loncommon::pgrdlink(&mt('Set/Change grades'),$content{'sendername'},$content{'senderdomain'},$symb,'check').'</b></td>');
        !          1486: 	}
        !          1487: 	$r->print('</tr></table>');
        !          1488:     }
        !          1489:     my $tolist;
        !          1490:     my @recipients = ();
        !          1491:     for (my $i=0; $i<@{$content{'recuser'}}; $i++) {
        !          1492:         $recipients[$i] =  &Apache::loncommon::aboutmewrapper(
        !          1493:            &Apache::loncommon::plainname($content{'recuser'}[$i],
        !          1494:                                       $content{'recdomain'}[$i]),
        !          1495:               $content{'recuser'}[$i],$content{'recdomain'}[$i]).
        !          1496:        ' ('.$content{'recuser'}[$i].' at '.$content{'recdomain'}[$i].') ';
        !          1497:     }
        !          1498:     $tolist = join(', ',@recipients);
        !          1499:     $r->print('<br /><b>'.&mt('Subject').':</b> '.$content{'subject'}.
        !          1500: 	      ($folder ne 'sent'?'<br /><b>'.&mt('From').':</b> '.
        !          1501: 	      &Apache::loncommon::aboutmewrapper(
        !          1502: 						 &Apache::loncommon::plainname($content{'sendername'},$content{'senderdomain'}),
        !          1503: 						 $content{'sendername'},$content{'senderdomain'}).' ('.
        !          1504: 	      $content{'sendername'}.' at '.
        !          1505: 	      $content{'senderdomain'}.') ':'<br /><b>'.&mt('To').':</b> '.
        !          1506:               $tolist).
        !          1507: 	      ($content{'courseid'}?'<br /><b>'.&mt('Course').':</b> '.$courseinfo{'description'}.
        !          1508: 	       ($content{'coursesec'}?' ('.&mt('Group/Section').': '.$content{'coursesec'}.')':''):'').
        !          1509: 	      '<br /><b>'.&mt('Time').':</b> '.$content{'time'}.
        !          1510: 	      ($content{'baseurl'}?'<br /><b>'.&mt('Refers to').':</b> <a href="'.$content{'baseurl'}.'">'.
        !          1511: 	       $content{'baseurl'}.' ('.&Apache::lonnet::gettitle($content{'baseurl'}).')</a>':'').
        !          1512: 	      '<p><pre>'.
        !          1513: 	      &Apache::lontexconvert::msgtexconverted($content{'message'},1).
        !          1514: 	      '</pre><hr />'.&displayresource(%content).'</p>');
        !          1515:     return;   
        !          1516: }
        !          1517: 
        !          1518: # =========================================================== Show the citation
        !          1519: 
        !          1520: sub displayresource {
        !          1521:     my %content=@_;
        !          1522: #
        !          1523: # If the recipient is in the same course that the message was sent from and
        !          1524: # has sufficient privileges, show "all details," else show citation
        !          1525: #
        !          1526:     if (($env{'request.course.id'} eq $content{'courseid'})
        !          1527:      && (&Apache::lonnet::allowed('vgr',$content{'courseid'}))) {
        !          1528: 	my $symb=&Apache::lonnet::symbread($content{'baseurl'});
        !          1529: # Could not get a symb, give up
        !          1530: 	unless ($symb) { return $content{'citation'}; }
        !          1531: # Have a symb, can render
        !          1532: 	return '<h2>'.&mt('Current attempts of student (if applicable)').'</h2>'.
        !          1533: 	    &Apache::loncommon::get_previous_attempt($symb,
        !          1534: 						     $content{'sendername'},
        !          1535: 						     $content{'senderdomain'},
        !          1536: 						     $content{'courseid'}).
        !          1537: 	    '<hr /><h2>'.&mt('Current screen output (if applicable)').'</h2>'.
        !          1538: 	    &Apache::loncommon::get_student_view($symb,
        !          1539: 						 $content{'sendername'},
        !          1540: 						 $content{'senderdomain'},
        !          1541: 						 $content{'courseid'}).
        !          1542: 	    '<h2>'.&mt('Correct Answer(s) (if applicable)').'</h2>'.
        !          1543: 	    &Apache::loncommon::get_student_answers($symb,
        !          1544: 						    $content{'sendername'},
        !          1545: 						    $content{'senderdomain'},
        !          1546: 						    $content{'courseid'});
        !          1547:     } elsif ($env{'user.adv'}) {
        !          1548: 	return $content{'citation'};
        !          1549:     }
        !          1550:     return '';
        !          1551: }
        !          1552: 
        !          1553: # ================================================================== The Header
        !          1554: 
        !          1555: sub header {
        !          1556:     my ($r,$title,$baseurl)=@_;
        !          1557:     
        !          1558:     my $extra = &Apache::loncommon::studentbrowser_javascript();
        !          1559:     if ($baseurl) {
        !          1560: 	$extra .= "<base href=\"http://$ENV{'SERVER_NAME'}/$baseurl\" />";
        !          1561:     }
        !          1562:     $r->print(&Apache::loncommon::start_page('Communication and Messages',
        !          1563: 					     $extra));
        !          1564:     $r->print(&Apache::lonhtmlcommon::breadcrumbs
        !          1565: 	      (undef,($title?$title:'Communication and Messages')));
        !          1566: 
        !          1567: }
        !          1568: 
        !          1569: # ---------------------------------------------------------------- Print header
        !          1570: 
        !          1571: sub printheader {
        !          1572:     my ($r,$url,$desc,$title,$baseurl)=@_;
        !          1573:     &Apache::lonhtmlcommon::add_breadcrumb
        !          1574: 	({href=>$url,
        !          1575: 	  text=>$desc});
        !          1576:     &header($r,$title,$baseurl);
        !          1577: }
        !          1578: 
        !          1579: # ------------------------------------------------------------ Store the comment
        !          1580: 
        !          1581: sub storecomment {
        !          1582:     my ($r)=@_;
        !          1583:     my $msgtxt=&Apache::lonfeedback::clear_out_html($env{'form.message'});
        !          1584:     my $cleanmsgtxt='';
        !          1585:     foreach (split(/[\n\r]/,$msgtxt)) {
        !          1586: 	unless ($_=~/^\s*(\>|\&gt\;)/) {
        !          1587: 	    $cleanmsgtxt.=$_."\n";
        !          1588: 	}
        !          1589:     }
        !          1590:     my $key=&Apache::lonnet::escape($env{'form.baseurl'}).'___'.time;
        !          1591:     &Apache::lonnet::put('nohist_stored_comments',{ $key => $cleanmsgtxt });
        !          1592: }
        !          1593: 
        !          1594: sub storedcommentlisting {
        !          1595:     my ($r)=@_;
        !          1596:     my %msgs=&Apache::lonnet::dump('nohist_stored_comments',undef,undef,
        !          1597:        '^'.&Apache::lonnet::escape(&Apache::lonnet::escape($env{'form.showcommentbaseurl'})));
        !          1598:     $r->print(&Apache::loncommon::start_page('Stored Comment Listing',undef,
        !          1599: 					     {'onlybody' => 1}));
        !          1600:     if ((keys %msgs)[0]=~/^error\:/) {
        !          1601: 	$r->print(&mt('No stored comments yet.'));
        !          1602:     } else {
        !          1603: 	my $found=0;
        !          1604: 	foreach (sort keys %msgs) {
        !          1605: 	    $r->print("\n".$msgs{$_}."<hr />");
        !          1606: 	    $found=1;
        !          1607: 	}
        !          1608: 	unless ($found) {
        !          1609: 	    $r->print(&mt('No stored comments yet for this resource.'));
        !          1610: 	}
        !          1611:     }
        !          1612: }
        !          1613: 
        !          1614: # ---------------------------------------------------------------- Send an email
        !          1615: 
        !          1616: sub sendoffmail {
        !          1617:     my ($r,$folder)=@_;
        !          1618:     my $suffix=&Apache::lonmsg::foldersuffix($folder);
        !          1619:     my $sendstatus='';
        !          1620:     my %specialmsg_status;
        !          1621:     my $numspecial = 0;
        !          1622:     if ($env{'form.send'}) {
        !          1623: 	&printheader($r,'','Messages being sent.');
        !          1624: 	$r->rflush();
        !          1625: 	my %content=();
        !          1626: 	undef %content;
        !          1627: 	if ($env{'form.forwid'}) {
        !          1628: 	    my $msgid=$env{'form.forwid'};
        !          1629: 	    my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]);
        !          1630: 	    %content=&Apache::lonmsg::unpackagemsg($message{$msgid},1);
        !          1631: 	    &statuschange($msgid,'forwarded',$folder);
        !          1632: 	    $env{'form.message'}.="\n\n-- Forwarded message --\n\n".
        !          1633: 		$content{'message'};
        !          1634: 	}
        !          1635: 	if ($env{'form.replyid'}) {
        !          1636: 	    my $msgid=$env{'form.replyid'};
        !          1637: 	    my %message=&Apache::lonnet::get('nohist_email'.$suffix,[$msgid]);
        !          1638: 	    %content=&Apache::lonmsg::unpackagemsg($message{$msgid},1);
        !          1639: 	    &statuschange($msgid,'replied',$folder);
        !          1640: 	}
        !          1641: 	my %toaddr=();
        !          1642: 	undef %toaddr;
        !          1643: 	if ($env{'form.sendmode'} eq 'group') {
        !          1644: 	    foreach (keys %env) {
        !          1645: 		if ($_=~/^form\.send\_to\_\&\&\&[^\&]*\&\&\&\_(.+)$/) {
        !          1646: 		    $toaddr{$1}='';
        !          1647: 		}
        !          1648: 	    }
        !          1649: 	} elsif ($env{'form.sendmode'} eq 'upload') {
        !          1650: 	    foreach (split(/[\n\r\f]+/,$env{'form.upfile'})) {
        !          1651: 		my ($rec,$txt)=split(/\s*\:\s*/,$_);
        !          1652: 		if ($txt) {
        !          1653: 		    $rec=~s/\@/\:/;
        !          1654: 		    $toaddr{$rec}.=$txt."\n";
        !          1655: 		}
        !          1656: 	    }
        !          1657: 	} else {
        !          1658: 	    $toaddr{$env{'form.recuname'}.':'.$env{'form.recdomain'}}='';
        !          1659: 	}
        !          1660: 	if ($env{'form.additionalrec'}) {
        !          1661: 	    foreach (split(/\,/,$env{'form.additionalrec'})) {
        !          1662: 		my ($auname,$audom)=split(/\@/,$_);
        !          1663: 		$toaddr{$auname.':'.$audom}='';
        !          1664: 	    }
        !          1665: 	}
        !          1666: 
        !          1667:         my $savemsg;
        !          1668:         my $msgtype;
        !          1669:         my %sentmessage;
        !          1670:         my $msgsubj=&Apache::lonfeedback::clear_out_html($env{'form.subject'});
        !          1671:         if ((($env{'form.critmsg'}) || ($env{'form.sendbck'})) &&
        !          1672:             (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
        !          1673: 	     || &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
        !          1674: 					 '/'.$env{'request.course.sec'})
        !          1675: 	     )) {
        !          1676:             $savemsg=&Apache::lonfeedback::clear_out_html($env{'form.message'},1);
        !          1677:             $msgtype = 'critical';
        !          1678:         } else {
        !          1679:             $savemsg=&Apache::lonfeedback::clear_out_html($env{'form.message'});
        !          1680:         }
        !          1681: 	
        !          1682: 	foreach (keys %toaddr) {
        !          1683: 	    my ($recuname,$recdomain)=split(/\:/,$_);
        !          1684:             my $msgtxt = $savemsg;
        !          1685: 	    if ($toaddr{$_}) { $msgtxt.='<hr />'.$toaddr{$_}; }
        !          1686: 	    my $thismsg;
        !          1687: 	    if ((($env{'form.critmsg'}) || ($env{'form.sendbck'})) && 
        !          1688: 		(&Apache::lonnet::allowed('srm',$env{'request.course.id'})
        !          1689: 		 || &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
        !          1690: 					     '/'.$env{'request.course.sec'}))) {
        !          1691: 		$r->print(&mt('Sending critical message').' '.$recuname.'@'.$recdomain.': ');
        !          1692: 		$thismsg=&Apache::lonmsg::user_crit_msg($recuname,$recdomain,$msgsubj,$msgtxt,
        !          1693: 				$env{'form.sendbck'},$env{'form.permanent'},
        !          1694:                                                              \$sentmessage{$_});
        !          1695: 	    } else {
        !          1696: 		$r->print(&mt('Sending').' '.$recuname.'@'.$recdomain.': ');
        !          1697: 		$thismsg=&Apache::lonmsg::user_normal_msg($recuname,$recdomain,$msgsubj,$msgtxt,
        !          1698: 					  $content{'citation'},undef,undef,$env{'form.permanent'},\$sentmessage{$_});
        !          1699:             }
        !          1700: 	    if (($env{'request.course.id'}) && (($msgtype eq 'critical') || 
        !          1701:                                          ($env{'form.sendmode'} eq 'group'))) {
        !          1702: 	        $specialmsg_status{$recuname.':'.$recdomain}  = $thismsg;
        !          1703:                 if ($thismsg eq 'ok') {
        !          1704:                     $numspecial ++;
        !          1705:                 }
        !          1706: 	    }
        !          1707: 	    $r->print($thismsg.'<br />');
        !          1708: 	    $sendstatus.=' '.$thismsg;
        !          1709: 	}
        !          1710:         if (($env{'request.course.id'}) && (($env{'form.sendmode'} eq 'group')
        !          1711:                                               || ($msgtype eq 'critical'))) {
        !          1712:             my $subj_prefix;
        !          1713:             if ($msgtype eq 'critical') {
        !          1714:                 $subj_prefix = 'Critical.';
        !          1715:             } else {
        !          1716:                 $subj_prefix = 'Broadcast.';
        !          1717:             }
        !          1718:             my ($specialmsgid,$specialresult);
        !          1719:             my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
        !          1720:             my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
        !          1721:             my $course_str = &Apache::lonnet::escape('['.$cnum.':'.$cdom.']');
        !          1722: 
        !          1723:             if ($numspecial) {
        !          1724:                 $specialresult = &Apache::lonmsg::user_normal_msg_raw($cnum,$cdom,$subj_prefix.
        !          1725:                     ' '.$course_str,$savemsg,undef,undef,undef,
        !          1726:                     undef,undef,\$specialmsgid);
        !          1727:                 $specialmsgid = &Apache::lonnet::unescape($specialmsgid);
        !          1728:             }
        !          1729:             if ($specialresult eq 'ok') {
        !          1730:                 my $record_sent;
        !          1731:                 my @recusers = ();
        !          1732:                 my @recudoms = ();
        !          1733:                 my ($stamp,$crssubj,$msgname,$msgdom,$msgcount,$context,$pid) = 
        !          1734:                             split(/\:/,&Apache::lonnet::unescape($specialmsgid));
        !          1735:                 foreach my $recipient (sort(keys(%toaddr))) {
        !          1736:                     if ($specialmsg_status{$recipient} eq 'ok') {
        !          1737:                         my $usersubj = $subj_prefix.'['.$recipient.']';
        !          1738:                         my $usermsgid = 
        !          1739: 			    &Apache::lonmsg::buildmsgid($stamp,$usersubj,
        !          1740: 							$msgname,$msgdom,
        !          1741: 							$msgcount,$context,
        !          1742: 							$pid);
        !          1743:                         &Apache::lonmsg::user_normal_msg_raw($cnum,$cdom,$subj_prefix.
        !          1744:                                              ' ['.$recipient.']',$msgsubj,undef,
        !          1745:                         undef,undef,undef,$usermsgid,undef,undef,$specialmsgid);
        !          1746:                         my ($uname,$udom) = split/:/,$recipient;
        !          1747:                         push(@recusers,$uname);
        !          1748:                         push(@recudoms,$udom);
        !          1749:                     }
        !          1750:                 }
        !          1751:                 if (@recusers) {
        !          1752:                     my $specialmessage;
        !          1753:                     my $sentsubj = $subj_prefix.' ('.$numspecial.' sent) '.
        !          1754:                                                                        $msgsubj;
        !          1755:                     $sentsubj = &HTML::Entities::encode($sentsubj,'<>&"');
        !          1756:                     my $sentmsgid = 
        !          1757: 			&Apache::lonmsg::buildmsgid($stamp,$sentsubj,$msgname,
        !          1758: 						    $msgdom,$msgcount,$context,
        !          1759: 						    $pid);
        !          1760:                     ($specialmsgid,$specialmessage) = &Apache::lonmsg::packagemsg($msgsubj,$savemsg,
        !          1761:                             undef,undef,undef,\@recusers,\@recudoms,$sentmsgid);
        !          1762:                     $record_sent = &Apache::lonmsg::store_sent_mail($specialmsgid,$specialmessage);
        !          1763:                 }
        !          1764:             } else {
        !          1765:                 &Apache::lonnet::logthis('Failed to create record of critical message or broadcast in '.$env{'course.'.$env{'request.course.id'}.'.num'}.' at '.$env{'course.'.$env{'request.course.id'}.'.domain'}.' - no msgid generated');
        !          1766:             }
        !          1767:         }
        !          1768:     } else {
        !          1769: 	&printheader($r,'','No messages sent.'); 
        !          1770:     }
        !          1771:     if ($sendstatus=~/^(\s*(?:ok|con_delayed)\s*)*$/) {
        !          1772: 	$r->print('<br /><font color="green">'.&mt('Completed.').'</font>');
        !          1773: 	if ($env{'form.displayedcrit'}) {
        !          1774: 	    &discrit($r);
        !          1775: 	} else {
        !          1776: 	    &Apache::loncommunicate::menu($r);
        !          1777: 	}
        !          1778:     } else {
        !          1779: 	$r->print(
        !          1780: 		  '<h2><font color="red">'.&mt('Could not deliver message').'</font></h2>'.
        !          1781: 		  &mt('Please use the browser "Back" button and correct the recipient addresses')
        !          1782: 		  );
        !          1783:     }
        !          1784: }
        !          1785: 
        !          1786: # ===================================================================== Handler
        !          1787: 
        !          1788: sub handler {
        !          1789:     my $r=shift;
        !          1790: 
        !          1791: # ----------------------------------------------------------- Set document type
        !          1792:     
        !          1793:     &Apache::loncommon::content_type($r,'text/html');
        !          1794:     $r->send_http_header;
        !          1795:     
        !          1796:     return OK if $r->header_only;
        !          1797:     
        !          1798: # --------------------------- Get query string for limited number of parameters
        !          1799:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
        !          1800:         ['display','replyto','forward','markread','markdel','markunread',
        !          1801:          'sendreply','compose','sendmail','critical','recname','recdom',
        !          1802:          'recordftf','sortedby','block','folder','startdis','interdis',
        !          1803: 	 'showcommentbaseurl','dismode']);
        !          1804:     $sqs='&sortedby='.$env{'form.sortedby'};
        !          1805: 
        !          1806: # ------------------------------------------------------ They checked for email
        !          1807:     unless ($env{'form.block'}) {
        !          1808:         &Apache::lonnet::put('email_status',{'recnewemail'=>0});
        !          1809:     }
        !          1810: 
        !          1811: # ----------------------------------------------------------------- Breadcrumbs
        !          1812: 
        !          1813:     &Apache::lonhtmlcommon::clear_breadcrumbs();
        !          1814:     &Apache::lonhtmlcommon::add_breadcrumb
        !          1815:         ({href=>"/adm/communicate",
        !          1816:           text=>"Communication/Messages",
        !          1817:           faq=>12,bug=>'Communication Tools',});
        !          1818: 
        !          1819: # ------------------------------------------------------------------ Get Folder
        !          1820: 
        !          1821:     my $folder=$env{'form.folder'};
        !          1822:     unless ($folder) { 
        !          1823: 	$folder=''; 
        !          1824:     } else {
        !          1825: 	$sqs.='&folder='.&Apache::lonnet::escape($folder);
        !          1826:     }
        !          1827: # ------------------------------------------------------------ Get Display Mode
        !          1828: 
        !          1829:     my $dismode=$env{'form.dismode'};
        !          1830:     unless ($dismode) { 
        !          1831: 	$dismode=''; 
        !          1832:     } else {
        !          1833: 	$sqs.='&dismode='.&Apache::lonnet::escape($dismode);
        !          1834:     }
        !          1835: 
        !          1836: # --------------------------------------------------------------------- Display
        !          1837: 
        !          1838:     $startdis=$env{'form.startdis'};
        !          1839:     $startdis--;
        !          1840:     unless ($startdis) { $startdis=0; }
        !          1841: 
        !          1842:     $interdis=$env{'form.interdis'};
        !          1843:     unless ($interdis) { $interdis=20; }
        !          1844:     $sqs.='&interdis='.$interdis;
        !          1845: 
        !          1846:     if ($env{'form.firstview'}) {
        !          1847: 	$startdis=0;
        !          1848:     }
        !          1849:     if ($env{'form.lastview'}) {
        !          1850: 	$startdis=-1;
        !          1851:     }
        !          1852:     if ($env{'form.prevview'}) {
        !          1853: 	$startdis--;
        !          1854:     }
        !          1855:     if ($env{'form.nextview'}) {
        !          1856: 	$startdis++;
        !          1857:     }
        !          1858:     my $postedstartdis=$startdis+1;
        !          1859:     $sqs.='&startdis='.$postedstartdis;
        !          1860: 
        !          1861: # --------------------------------------------------------------- Render Output
        !          1862: 
        !          1863:     if ($env{'form.display'}) {
        !          1864: 	&displaymessage($r,$env{'form.display'},$folder);
        !          1865:     } elsif ($env{'form.replyto'}) {
        !          1866: 	&compout($r,'',$env{'form.replyto'},undef,undef,$folder,$dismode);
        !          1867:     } elsif ($env{'form.confirm'}) {
        !          1868: 	&printheader($r,'','Confirmed Receipt');
        !          1869: 	foreach (keys %env) {
        !          1870: 	    if ($_=~/^form\.rec\_(.*)$/) {
        !          1871: 		$r->print('<b>'.&mt('Confirming Receipt').':</b> '.
        !          1872: 			  &Apache::lonmsg::user_crit_received($1).'<br>');
        !          1873: 	    }
        !          1874: 	    if ($_=~/^form\.reprec\_(.*)$/) {
        !          1875: 		my $msgid=$1;
        !          1876: 		$r->print('<b>'.&mt('Confirming Receipt').':</b> '.
        !          1877: 			  &Apache::lonmsg::user_crit_received($msgid).'<br>');
        !          1878: 		&compout($r,'','','',$msgid);
        !          1879: 	    }
        !          1880: 	}
        !          1881: 	&discrit($r);
        !          1882:     } elsif ($env{'form.critical'}) {
        !          1883: 	&printheader($r,'','Displaying Critical Messages');
        !          1884: 	&discrit($r);
        !          1885:     } elsif ($env{'form.forward'}) {
        !          1886: 	&compout($r,$env{'form.forward'},undef,undef,undef,$folder);
        !          1887:     } elsif ($env{'form.markdel'}) {
        !          1888: 	&printheader($r,'','Deleted Message');
        !          1889: 	&statuschange($env{'form.markdel'},'deleted',$folder);
        !          1890: 	&Apache::loncommunicate::menu($r);
        !          1891: 	&disall($r,($folder?$folder:$dismode));
        !          1892:     } elsif ($env{'form.markedmove'}) {
        !          1893: 	my $total=0;
        !          1894: 	foreach (keys %env) {
        !          1895: 	    if ($_=~/^form\.delmark_(.*)$/) {
        !          1896: 		&movemsg(&Apache::lonnet::unescape($1),$folder,
        !          1897: 			 $env{'form.movetofolder'});
        !          1898: 		$total++;
        !          1899: 	    }
        !          1900: 	}
        !          1901: 	&printheader($r,'','Moved Messages');
        !          1902: 	$r->print('Moved '.$total.' message(s)<p>');
        !          1903: 	&Apache::loncommunicate::menu($r);
        !          1904: 	&disall($r,($folder?$folder:$dismode));
        !          1905:     } elsif ($env{'form.markeddel'}) {
        !          1906: 	my $total=0;
        !          1907: 	foreach (keys %env) {
        !          1908: 	    if ($_=~/^form\.delmark_(.*)$/) {
        !          1909: 		&statuschange(&Apache::lonnet::unescape($1),'deleted',$folder);
        !          1910: 		$total++;
        !          1911: 	    }
        !          1912: 	}
        !          1913: 	&printheader($r,'','Deleted Messages');
        !          1914: 	$r->print('Deleted '.$total.' message(s)<p>');
        !          1915: 	&Apache::loncommunicate::menu($r);
        !          1916: 	&disall($r,($folder?$folder:$dismode));
        !          1917:     } elsif ($env{'form.markunread'}) {
        !          1918: 	&printheader($r,'','Marked Message as Unread');
        !          1919: 	&statuschange($env{'form.markunread'},'new');
        !          1920: 	&Apache::loncommunicate::menu($r);
        !          1921: 	&disall($r,($folder?$folder:$dismode));
        !          1922:     } elsif ($env{'form.compose'}) {
        !          1923: 	&compout($r,'','',$env{'form.compose'});
        !          1924:     } elsif ($env{'form.recordftf'}) {
        !          1925: 	&facetoface($r,$env{'form.recordftf'});
        !          1926:     } elsif ($env{'form.block'}) {
        !          1927:         &examblock($r,$env{'form.block'});
        !          1928:     } elsif ($env{'form.sendmail'}) {
        !          1929: 	&sendoffmail($r,$folder);
        !          1930: 	if ($env{'form.storebasecomment'}) {
        !          1931: 	    &storecomment($r);
        !          1932: 	}
        !          1933: 	if (($env{'form.rsspost'}) && ($env{'request.course.id'})) {
        !          1934: 	    &Apache::lonrss::addentry($env{'course.'.$env{'request.course.id'}.'.num'},
        !          1935: 				      $env{'course.'.$env{'request.course.id'}.'.domain'},
        !          1936: 				      'Course_Announcements',
        !          1937: 				      $env{'form.subject'},
        !          1938: 				      $env{'form.message'},'/adm/communicate','public');
        !          1939: 	}
        !          1940: 	&disall($r,($folder?$folder:$dismode));
        !          1941:     } elsif ($env{'form.newfolder'}) {
        !          1942: 	&printheader($r,'','New Folder');
        !          1943: 	&makefolder($env{'form.newfolder'});
        !          1944: 	&Apache::loncommunicate::menu($r);
        !          1945: 	&disall($r,$env{'form.newfolder'});
        !          1946:     } elsif ($env{'form.showcommentbaseurl'}) {
        !          1947: 	&storedcommentlisting($r);
        !          1948:     } else {
        !          1949: 	&printheader($r,'','Display All Messages');
        !          1950: 	&Apache::loncommunicate::menu($r); 
        !          1951: 	&disall($r,($folder?$folder:$dismode));
        !          1952:     }
        !          1953:     $r->print(&Apache::loncommon::end_page());
        !          1954:     return OK;
        !          1955: }
        !          1956: # ================================================= Main program, reset counter
        !          1957: 
        !          1958: BEGIN {
        !          1959:     $msgcount=0;
        !          1960: }
        !          1961: 
        !          1962: =pod
        !          1963: 
        !          1964: =back
        !          1965: 
        !          1966: =cut
        !          1967: 
        !          1968: 1; 
        !          1969: 
        !          1970: __END__
        !          1971: 
        !          1972: 
        !          1973: 
        !          1974: 
        !          1975: 
        !          1976: 
        !          1977: 

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