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