File:  [LON-CAPA] / loncom / interface / lonfeedback.pm
Revision 1.78: download - view: text, annotated - select for diffs
Wed Apr 28 21:13:13 2004 UTC (20 years, 1 month ago) by raeburn
Branches: MAIN
CVS tags: HEAD
For discussion posts: added "Title" for each post, and the ability for a user to mark posts as read/unread, and to display only unread posts, or all posts. Read/unread information stored for visible posts for each user in a course-specific db file (e.g., msu_35101d1a78a4060msul1_discuss.db) in lonUsers/$dom/a/b/c/abcuser.  Should this be made a nohist_...db instead???

    1: # The LearningOnline Network
    2: # Feedback
    3: #
    4: # $Id: lonfeedback.pm,v 1.78 2004/04/28 21:13:13 raeburn 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::lonfeedback;
   31: 
   32: use strict;
   33: use Apache::Constants qw(:common);
   34: use Apache::lonmsg();
   35: use Apache::loncommon();
   36: use Apache::lontexconvert();
   37: use Apache::lonlocal;
   38: 
   39: sub list_discussion {
   40:     my ($mode,$status,$symb)=@_;
   41: #    &Apache::lonnet::logthis("status is $status");
   42:     if (!($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'
   43: 	  || $status eq 'OPEN')) {
   44: 	return '';
   45:     }
   46:     my $discussiononly=0;
   47:     if ($mode eq 'board') { $discussiononly=1; }
   48:     unless ($ENV{'request.course.id'}) { return ''; }
   49:     my $crs='/'.$ENV{'request.course.id'};
   50:     if ($ENV{'request.course.sec'}) {
   51: 	$crs.='_'.$ENV{'request.course.sec'};
   52:     }                 
   53:     $crs=~s/\_/\//g;
   54:     unless ($symb) {
   55: 	$symb=&Apache::lonnet::symbread();
   56:     }
   57:     unless ($symb) { return ''; }
   58: 
   59:     my %dischash = &Apache::lonnet::restore($symb,$ENV{'request.course.id'}.'_discuss',$ENV{'user.domain'},$ENV{'user.name'});
   60:     my %readids = ();
   61:     my $showonlyunread;
   62:     foreach my $key (keys %dischash) {
   63:         if ($key eq 'showonlyunread') {
   64:             $showonlyunread = $dischash{$key};
   65:         } else {
   66:             if ($dischash{$key} eq 'read') {
   67:                 $readids{$key} = 1;
   68:             }
   69:         }
   70:     }
   71: 
   72:     my $seeid=&Apache::lonnet::allowed('rin',$crs);
   73:     my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs)
   74: 	&& ($symb=~/\.(problem|exam|quiz|assess|survey|form)$/));
   75:     my @discussionitems=();
   76:     # backward compatibility (bulletin boards used to be 'wrapped')
   77:     my $ressymb=$symb;
   78:     if ($mode eq 'board') {
   79: 	$ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
   80:     }
   81:     my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'},
   82: 			  $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
   83: 			  $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   84:     my $visible=0;
   85:     my @depth=();
   86:     my @original=();
   87:     my @index=();
   88:     my @replies=();
   89:     my %alldiscussion=();
   90:     my $maxdepth=0;
   91: 
   92:     my $target='';
   93:     unless ($ENV{'browser.interface'} eq 'textual' ||
   94: 	    $ENV{'environment.remote'} eq 'off' ) {
   95: 	$target='target="LONcom"';
   96:     }
   97:     if ($contrib{'version'}) {
   98: 	for (my $id=1;$id<=$contrib{'version'};$id++) {
   99: 	    my $idx=$id;
  100: 	    my $hidden=($contrib{'hidden'}=~/\.$idx\./);
  101: 	    my $deleted=($contrib{'deleted'}=~/\.$idx\./);
  102: 	    my $origindex='0.';
  103: 	    if (($contrib{$idx.':replyto'}) && ($ENV{'environment.threadeddiscussion'})) {
  104: # this is a follow-up message
  105: 		$original[$idx]=$original[$contrib{$idx.':replyto'}];
  106: 		$depth[$idx]=$depth[$contrib{$idx.':replyto'}]+1;
  107: 		$origindex=$index[$contrib{$idx.':replyto'}];
  108: 		if ($depth[$idx]>$maxdepth) { $maxdepth=$depth[$idx]; }
  109: 	    } else {
  110: # this is an original message
  111: 		$original[$idx]=0;
  112: 		$depth[$idx]=0;
  113: 	    }
  114: 	    if ($replies[$depth[$idx]]) {
  115: 		$replies[$depth[$idx]]++;
  116: 	    } else {
  117: 		$replies[$depth[$idx]]=1;
  118: 	    }
  119: 	    unless ((($hidden) && (!$seeid)) || ($deleted)) {
  120: 		$visible++;
  121: 		my $message=$contrib{$idx.':message'};
  122: 		$message=~s/\n/\<br \/\>/g;
  123: 		$message=&Apache::lontexconvert::msgtexconverted($message);
  124:                 my $subject=$contrib{$idx.':subject'};
  125:                 if (defined($subject)) {
  126:                     $subject=~s/\n/\<br \/\>/g;
  127:                     $subject=&Apache::lontexconvert::msgtexconverted($subject);
  128:                 }
  129: 		if ($contrib{$idx.':attachmenturl'}) {
  130: 		    my ($fname,$ft)
  131:                         =($contrib{$idx.':attachmenturl'}=~/\/(\w+)\.(\w+)$/);
  132: 		    $message.='<p>'.&mt('Attachment').': <a href="'.
  133: 			&Apache::lonnet::tokenwrapper(
  134:                                              $contrib{$idx.':attachmenturl'}).
  135: 			'"><tt>'.$fname.'.'.$ft.'</tt></a></p>';
  136: 		}
  137: 		if ($message) {
  138: 		    if ($hidden) {
  139: 			$message='<font color="#888888">'.$message.'</font>';
  140: 		    }
  141: 		    my $screenname=&Apache::loncommon::screenname(
  142: 					    $contrib{$idx.':sendername'},
  143: 					    $contrib{$idx.':senderdomain'});
  144: 		    my $plainname=&Apache::loncommon::nickname(
  145: 					    $contrib{$idx.':sendername'},
  146: 					    $contrib{$idx.':senderdomain'});
  147: 		    
  148: 		    my $sender=&mt('Anonymous');
  149: 		    if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
  150: 			$sender=&Apache::loncommon::aboutmewrapper(
  151: 					 $plainname,
  152: 					 $contrib{$idx.':sendername'},
  153: 					 $contrib{$idx.':senderdomain'}).' ('.
  154: 					 $contrib{$idx.':sendername'}.' at '.
  155: 					 $contrib{$idx.':senderdomain'}.')';
  156: 			if ($contrib{$idx.':anonymous'}) {
  157: 			    $sender.=' ['.&mt('anonymous').'] '.
  158: 				$screenname;
  159: 			}
  160: 			if ($seeid) {
  161: 			    if ($hidden) {
  162: 				$sender.=' <a href="/adm/feedback?unhide='.
  163: 				    $ressymb.':::'.$idx.'">'.&mt('Make Visible').'</a>';
  164: 			    } else {
  165: 				$sender.=' <a href="/adm/feedback?hide='.
  166: 				    $ressymb.':::'.$idx.'">'.&mt('Hide').'</a>';
  167: 			    }                     
  168: 			    $sender.=' <a href="/adm/feedback?deldisc='.
  169: 				$ressymb.':::'.$idx.'">'.&mt('Delete').'</a>';
  170: 			}
  171: 		    } else {
  172: 			if ($screenname) {
  173: 			    $sender='<i>'.$screenname.'</i>';
  174: 			}
  175: 		    }
  176: 		    if (&Apache::lonnet::allowed('pch',
  177: 						 $ENV{'request.course.id'}.
  178: 						 ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
  179: 			$sender.=' <a href="/adm/feedback?replydisc='.
  180: 			    $ressymb.':::'.$idx.'" '.$target.'>'.&mt('Reply').'</a>';
  181: 		    }
  182: 		    my $vgrlink;
  183:                     my $ctlink;
  184:                     if ($readids{$idx} == 1) {
  185:                         $ctlink = '<b>'.&mt('Mark unread').'?</b>&nbsp;'.
  186:                             '<input type="checkbox" name="'.
  187:                             'postunread_'.$idx.'" />';
  188:                     } else {
  189:                         $ctlink = '<b>'.&mt('Mark read').'?</b>&nbsp;'.
  190:                             '<input type="checkbox" name="'.
  191:                             'postread_'.$idx.'" />';
  192:                     }
  193: 		    if ($viewgrades) {
  194: 			$vgrlink=&Apache::loncommon::submlink('Submissions',
  195:             $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$symb);
  196: 		    }
  197: #figure out at what position this needs to print
  198: 		    my $thisindex=$idx;
  199: 		    if ($ENV{'environment.threadeddiscussion'}) {
  200: 			$thisindex=$origindex.substr('00'.$replies[$depth[$idx]],-2,2);	
  201: 		    }
  202: 		    $alldiscussion{$thisindex}=$idx;
  203: 		    $index[$idx]=$thisindex;
  204:                     $discussionitems[$idx]='<p><table border="0" width="100%">'.
  205:                         '<tr><td align="left"><b>'.$subject.'</b>&nbsp;&nbsp;'.
  206:                         $sender.'</b> '.$vgrlink.' ('.
  207:                         localtime($contrib{$idx.':timestamp'}).
  208:                         ')</td><td align="right">&nbsp;&nbsp;'.$ctlink.'</td></tr>';
  209:                     if ($showonlyunread && $readids{$idx}) {
  210:                         $discussionitems[$idx] .= '<tr><td colspan="2" align="right"><i><font size="-1">Check "Show all posts?" or "Mark unread?", then "Save read settings" to display message</font></i></td></tr></table>';
  211:                     } else {
  212:                         $discussionitems[$idx] .= '</table><blockquote>'.$message.'</blockquote></p>';
  213:                     }
  214:                 }
  215:             }
  216: 	}
  217:     }
  218:     my $discussion='';
  219:     if ($visible) {
  220: # Print a the discusssion
  221:         $discussion .= '<form name="readchoices" method="post" action="/adm/feedback?chgreads='.$symb.'">';
  222: 	$discussion.='<table bgcolor="#AAAAAA" cellpadding="2" cellspacing="2" border="0">';
  223: 	if ($visible>2) {
  224: 	    my $colspan=$maxdepth+1;
  225: my $showoption = '<tr><td align="right" bgcolor="#FFFFFF" colspan="'.$colspan.'">';
  226:             my $showflag = 'all';
  227:             if ($showonlyunread) {
  228:                 $showoption .= '<b>Show all posts?</b><input type="checkbox"
  229: name="allposts" value="1"></td></tr>';
  230:             } else {
  231:                 $showoption .= '<b>Show only unread posts?</b><input type="checkbox" name="onlyunread" value="1"></td></tr>';
  232:             }
  233:             $discussion.=$showoption;
  234: 	    $discussion.='<tr><td bgcolor="DDDDBB" colspan="'.$colspan.'">'.
  235:             '<table border="0" width="100%" bgcolor="#DDDDBB"><tr><td align="left">'.
  236:             '<a href="/adm/feedback?threadedon='.$symb.'">'.&mt('Threaded View').'</a>&nbsp;&nbsp;'.
  237:             '<a href="/adm/feedback?threadedoff='.$symb.'">'.&mt('Chronological View').'</a>&nbsp;&nbsp;</td>'.
  238:             '<td align="right"><a href="/adm/feedback?markread='.$symb.'">'.&mt('Mark all read').'</a>&nbsp;&nbsp;'.
  239:             '<a href="/adm/feedback?markunread='.$symb.'">'.&mt('Mark all unread').'</a>&nbsp;&nbsp;'.
  240:             '</td></tr></table></td></tr>';
  241: 	}
  242: 
  243: 	foreach (sort { $a <=> $b } keys %alldiscussion) {
  244: 	    $discussion.="\n<tr>";
  245: 	    my $thisdepth=$depth[$alldiscussion{$_}];
  246: 	    for (1..$thisdepth) {
  247: 		$discussion.='<td>&nbsp;&nbsp;&nbsp;</td>';
  248: 	    }
  249: 	    my $colspan=$maxdepth-$thisdepth+1;
  250:             $discussion.='<td  bgcolor="#CCCCCC" colspan="'.$colspan.'">'.
  251:                          $discussionitems[$alldiscussion{$_}].
  252: 	                 '</td></tr>';
  253: 	}
  254:         my $colspan=$maxdepth+1;
  255:         $discussion.='<tr><td bgcolor="#FFFFFF" align="right" colspan="'.
  256:         $colspan.'"><br /><input type="hidden" name="storereads" value="0">'.            '<input type="hidden" name="discsymb" value="'.$symb.'">'.
  257:         '<input type="button" name="readoptions" '.
  258:         'value="Save read settings" onClick="this.form.storereads.value=1;this.form.submit();"></td></tr>';
  259:         $discussion .= '</table><br /><br /></form>';
  260:     }
  261:     if ($discussiononly) {
  262: 	$discussion.=(<<ENDDISCUSS);
  263: <form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data">
  264: <input type="submit" name="discuss" value="Post Discussion" />
  265: <input type="submit" name="anondiscuss" value="Post Anonymous Discussion" />
  266: <input type="hidden" name="symb" value="$ressymb" />
  267: <input type="hidden" name="sendit" value="true" />
  268: <br />
  269: <font size="1">Note: in anonymous discussion, your name is visible only to
  270: course faculty</font><br />
  271: <b>Title:</b>&nbsp;<input type="text" name="subject" value="" size="30" /><br /><br />
  272: <textarea name="comment" cols="60" rows="10" wrap="hard"></textarea>
  273: <p>
  274: Attachment (128 KB max size): <input type="file" name="attachment" />
  275: </p>
  276: </form>
  277: ENDDISCUSS
  278:       $discussion.=&generate_preview_button();
  279:     } else {
  280: 	if (&Apache::lonnet::allowed('pch',
  281: 				   $ENV{'request.course.id'}.
  282: 	($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
  283: 			    $discussion.='<table bgcolor="#BBBBBB"><tr><td><a href="/adm/feedback?replydisc='.
  284: 				$symb.':::" '.$target.'>'.
  285: 				'<img src="/adm/lonMisc/chat.gif" border="0" />'.
  286: 				&mt('Post Discussion').'</a></td></tr></table>';
  287: 			}
  288:     }
  289:    return $discussion;
  290: }
  291: 
  292: sub mail_screen {
  293:   my ($r,$feedurl,$options) = @_;
  294:   my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion',
  295:                                           '','onLoad="window.focus();"');
  296:   my $title=&Apache::lonnet::gettitle($feedurl);
  297:   if (!$title) { $title = $feedurl; }
  298:   my $quote='';
  299:   my $subject = '';
  300:   if ($ENV{'form.replydisc'}) {
  301:       my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'});
  302:       my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
  303: 					   $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  304: 					   $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  305:       unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) { 
  306: 	  my $message=$contrib{$idx.':message'};
  307: 	  $message=~s/\n/\<br \/\>/g;
  308: 	  $quote='<blockquote>'.&Apache::lontexconvert::msgtexconverted($message).'</blockquote>';
  309:           $subject = 'Re: '.$contrib{$idx.':subject'};
  310:       }
  311:   }
  312:   my $latexHelp = Apache::loncommon::helpLatexCheatsheet();
  313:   my $send=&mt('Send');
  314:   $r->print(<<ENDDOCUMENT);
  315: <html>
  316: <head>
  317: <title>The LearningOnline Network with CAPA</title>
  318: <meta http-equiv="pragma" content="no-cache"></meta>
  319: <script type="text/javascript">
  320: //<!--
  321:     function gosubmit() {
  322:         var rec=0;
  323:         if (typeof(document.mailform.elements.author)!="undefined") {
  324:           if (document.mailform.elements.author.checked) {
  325:              rec=1;
  326:           } 
  327:         }
  328:         if (typeof(document.mailform.elements.question)!="undefined") {
  329:           if (document.mailform.elements.question.checked) {
  330:              rec=1;
  331:           } 
  332:         }
  333:         if (typeof(document.mailform.elements.course)!="undefined") {
  334:           if (document.mailform.elements.course.checked) {
  335:              rec=1;
  336:           } 
  337:         }
  338:         if (typeof(document.mailform.elements.policy)!="undefined") {
  339:           if (document.mailform.elements.policy.checked) {
  340:              rec=1;
  341:           } 
  342:         }
  343:         if (typeof(document.mailform.elements.discuss)!="undefined") {
  344:           if (document.mailform.elements.discuss.checked) {
  345:              rec=1;
  346:           } 
  347:         }
  348:         if (typeof(document.mailform.elements.anondiscuss)!="undefined") {
  349:           if (document.mailform.elements.anondiscuss.checked) {
  350:              rec=1;
  351:           } 
  352:         }
  353: 
  354:         if (rec) {
  355: 	    document.mailform.submit();
  356:         } else {
  357:             alert('Please check a feedback type.');
  358: 	}
  359:     }
  360: //-->
  361: </script>
  362: </head>
  363: $bodytag
  364: <h2><tt>$title</tt></h2>
  365: <form action="/adm/feedback" method="post" name="mailform"
  366: enctype="multipart/form-data">
  367: <input type="hidden" name="postdata" value="$feedurl" />
  368: <input type="hidden" name="replydisc" value="$ENV{'form.replydisc'}" />
  369: Please check at least one of the following feedback types:
  370: $options<hr />
  371: $quote
  372: <p>My question/comment/feedback:</p>
  373: <p>
  374: $latexHelp
  375: Title: <input type="text" name="subject" size="30" value="$subject" /></p>
  376: <p>
  377: <textarea name="comment" cols="60" rows="10" wrap="hard">
  378: </textarea></p>
  379: <p>
  380: Attachment (128 KB max size): <input type="file" name="attachment" />
  381: </p>
  382: <p>
  383: <input type="hidden" name="sendit" value="1" />
  384: <input type="button" value="$send" onClick='gosubmit();' />
  385: </p>
  386: </form>
  387: ENDDOCUMENT
  388: $r->print(&generate_preview_button().'</body></html>');
  389: }
  390: 
  391: sub fail_redirect {
  392:   my ($r,$feedurl) = @_;
  393:   if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
  394:   $r->print (<<ENDFAILREDIR);
  395: <html>
  396: <head><title>Feedback not sent</title>
  397: <meta http-equiv="pragma" content="no-cache" />
  398: <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
  399: </head>
  400: <body bgcolor="#FFFFFF">
  401: <img align="right" src="/adm/lonIcons/lonlogos.gif" />
  402: <b>Sorry, no recipients  ...</b>
  403: </body>
  404: </html>
  405: ENDFAILREDIR
  406: }
  407: 
  408: sub redirect_back {
  409:   my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status) = @_;
  410:   if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
  411:   $r->print (<<ENDREDIR);
  412: <html>
  413: <head>
  414: <title>Feedback sent</title>
  415: <meta http-equiv="pragma" content="no-cache" />
  416: <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl">
  417: </head>
  418: <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'>
  419: <img align="right" src="/adm/lonIcons/lonlogos.gif" />
  420: $typestyle
  421: <b>Sent $sendsomething message(s), and $sendposts post(s).</b>
  422: <font color="red">$status</font>
  423: <form name="reldt" action="$feedurl" target="loncapaclient">
  424: </form>
  425: </body>
  426: </html>
  427: ENDREDIR
  428: }
  429: 
  430: sub no_redirect_back {
  431:   my ($r,$feedurl) = @_;
  432:   $r->print (<<ENDNOREDIR);
  433: <html>
  434: <head><title>Feedback not sent</title>
  435: <meta http-equiv="pragma" content="no-cache" />
  436: ENDNOREDIR
  437: 
  438:   if ($feedurl!~/^\/adm\/feedback/) { 
  439:     $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="2; url='.$feedurl.'">');
  440:   }
  441:   
  442:   $r->print (<<ENDNOREDIRTWO);
  443: </head>
  444: <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { self.close(); }'>
  445: <img align="right" src="/adm/lonIcons/lonlogos.gif" />
  446: <b>Sorry, no feedback possible on this resource  ...</b>
  447: </body>
  448: </html>
  449: ENDNOREDIRTWO
  450: }
  451: 
  452: sub screen_header {
  453:     my ($feedurl) = @_;
  454:     my $msgoptions='';
  455:     my $discussoptions='';
  456:     unless ($ENV{'form.replydisc'}) {
  457: 	if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/)) {
  458: 	    $msgoptions= 
  459: 		'<p><input type="checkbox" name="author" /> '.
  460: 		&mt('Feedback to resource author').'</p>';
  461: 	}
  462: 	if (&feedback_available(1)) {
  463: 	    $msgoptions.=
  464: 		'<br /><input type="checkbox" name="question" /> '.
  465: 		&mt('Question about resource content');
  466: 	}
  467: 	if (&feedback_available(0,1)) {
  468: 	    $msgoptions.=
  469: 		'<br /><input type="checkbox" name="course" /> '.
  470: 		&mt('Question/Comment/Feedback about course content');
  471: 	}
  472: 	if (&feedback_available(0,0,1)) {
  473: 	    $msgoptions.=
  474: 		'<br /><input type="checkbox" name="policy" /> '.
  475: 		&mt('Question/Comment/Feedback about course policy');
  476: 	}
  477:     }
  478:     if ($ENV{'request.course.id'}) {
  479: 	if (&Apache::lonnet::allowed('pch',
  480: 				     $ENV{'request.course.id'}.
  481: 				     ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
  482: 	    $discussoptions='<input type="checkbox" name="discuss" onClick="this.form.anondiscuss.checked=false;" '.
  483: 		($ENV{'form.replydisc'}?' checked="1"':'').' /> '.
  484: 		&mt('Contribution to course discussion of resource');
  485: 	    $discussoptions.='<br /><input type="checkbox" name="anondiscuss" onClick="this.form.discuss.checked=false;" /> '.
  486: 		&mt('Anonymous contribution to course discussion of resource').
  487: 		' <i>('.&mt('name only visible to course faculty').')</i>';
  488:       }
  489:     }
  490:     if ($msgoptions) { $msgoptions='<h2><img src="/adm/lonMisc/feedback.gif" />'.&mt('Sending Messages').'</h2>'.$msgoptions; }
  491:     if ($discussoptions) { 
  492: 	$discussoptions='<h2><img src="/adm/lonMisc/chat.gif" />'.&mt('Discussion Contributions').'</h2>'.$discussoptions; }
  493:     return $msgoptions.$discussoptions;
  494: }
  495: 
  496: sub resource_output {
  497:   my ($feedurl) = @_;
  498:   my $usersaw=&Apache::lonnet::ssi_body($feedurl);
  499:   $usersaw=~s/\<body[^\>]*\>//gi;
  500:   $usersaw=~s/\<\/body\>//gi;
  501:   $usersaw=~s/\<html\>//gi;
  502:   $usersaw=~s/\<\/html\>//gi;
  503:   $usersaw=~s/\<head\>//gi;
  504:   $usersaw=~s/\<\/head\>//gi;
  505:   $usersaw=~s/action\s*\=/would_be_action\=/gi;
  506:   return $usersaw;
  507: }
  508: 
  509: sub clear_out_html {
  510:   my ($message,$override)=@_;
  511:   my $cid=$ENV{'request.course.id'};
  512:   if (($ENV{"course.$cid.allow_limited_html_in_feedback"} =~ m/yes/i) ||
  513:       ($override)) {
  514:       # allows <B> <I> <P> <A> <LI> <OL> <UL> <EM> <BR> <TT> <STRONG> 
  515:       # <BLOCKQUOTE> <DIV .*> <DIV> <IMG>
  516:       my %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1,
  517: 		BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, DIV=>1, IMG=>1,
  518:                 M=>1);
  519: 
  520:       $message =~ s/\<(\/?\s*(\w+)[^\>\<]*)/
  521: 	  {($html{uc($2)}&&(length($1)<1000))?"\<$1":"\&lt;$1"}/ge;
  522:       $message =~ s/(\<?\s*(\w+)[^\<\>]*)\>/
  523: 	  {($html{uc($2)}&&(length($1)<1000))?"$1\>":"$1\&gt;"}/ge;
  524:   } else {
  525:       $message=~s/\</\&lt\;/g;
  526:       $message=~s/\>/\&gt\;/g;
  527:   }
  528:   return $message;
  529: }
  530: 
  531: sub assemble_email {
  532:   my ($feedurl,$message,$prevattempts,$usersaw,$useranswer)=@_;
  533:   my $email=<<"ENDEMAIL";
  534: Refers to <a href="$feedurl">$feedurl</a>
  535: 
  536: $message
  537: ENDEMAIL
  538:     my $citations=<<"ENDCITE";
  539: <h2>Previous attempts of student (if applicable)</h2>
  540: $prevattempts
  541: <br /><hr />
  542: <h2>Original screen output (if applicable)</h2>
  543: $usersaw
  544: <h2>Correct Answer(s) (if applicable)</h2>
  545: $useranswer
  546: ENDCITE
  547:   return ($email,$citations);
  548: }
  549: 
  550: sub secapply {
  551:     my $rec=shift;
  552:     my $defaultflag=shift;
  553:     $rec=~s/\s+//g;
  554:     $rec=~s/\@/\:/g;
  555:     my ($adr,$sections)=($rec=~/^([^\(]+)\(([^\)]+)\)/);
  556:     if ($sections) {
  557: 	foreach (split(/\;/,$sections)) {
  558:             if (($_ eq $ENV{'request.course.sec'}) ||
  559:                 ($defaultflag && ($_ eq '*'))) {
  560:                 return $adr; 
  561:             }
  562:         }
  563:     } else {
  564:        return $rec;
  565:     }
  566:     return '';
  567: }
  568: 
  569: sub decide_receiver {
  570:   my ($feedurl,$author,$question,$course,$policy,$defaultflag) = @_;
  571:   my $typestyle='';
  572:   my %to=();
  573:   if ($ENV{'form.author'}||$author) {
  574:     $typestyle.='Submitting as Author Feedback<br>';
  575:     $feedurl=~/^\/res\/(\w+)\/(\w+)\//;
  576:     $to{$2.':'.$1}=1;
  577:   }
  578:   if ($ENV{'form.question'}||$question) {
  579:     $typestyle.='Submitting as Question<br>';
  580:     foreach (split(/\,/,
  581: 		   $ENV{'course.'.$ENV{'request.course.id'}.'.question.email'})
  582: 	     ) {
  583: 	my $rec=&secapply($_,$defaultflag);
  584:         if ($rec) { $to{$rec}=1; }
  585:     } 
  586:   }
  587:   if ($ENV{'form.course'}||$course) {
  588:     $typestyle.='Submitting as Comment<br />';
  589:     foreach (split(/\,/,
  590: 		   $ENV{'course.'.$ENV{'request.course.id'}.'.comment.email'})
  591: 	     ) {
  592: 	my $rec=&secapply($_,$defaultflag);
  593:         if ($rec) { $to{$rec}=1; }
  594:     } 
  595:   }
  596:   if ($ENV{'form.policy'}||$policy) {
  597:     $typestyle.='Submitting as Policy Feedback<br />';
  598:     foreach (split(/\,/,
  599: 		   $ENV{'course.'.$ENV{'request.course.id'}.'.policy.email'})
  600: 	     ) {
  601: 	my $rec=&secapply($_,$defaultflag);
  602:         if ($rec) { $to{$rec}=1; }
  603:     } 
  604:   }
  605:   if ((scalar(%to) eq '0') && (!$defaultflag)) {
  606:      ($typestyle,%to)=
  607: 	 &decide_receiver($feedurl,$author,$question,$course,$policy,1);
  608:   }
  609:   return ($typestyle,%to);
  610: }
  611: 
  612: sub feedback_available {
  613:     my ($question,$course,$policy)=@_;
  614:     my ($typestyle,%to)=&decide_receiver('',0,$question,$course,$policy);
  615:     return scalar(%to);
  616: }
  617: 
  618: sub send_msg {
  619:   my ($feedurl,$email,$citations,$attachmenturl,%to)=@_;
  620:   my $status='';
  621:   my $sendsomething=0;
  622:   foreach (keys %to) {
  623:     if ($_) {
  624:       my $declutter=&Apache::lonnet::declutter($feedurl);
  625:       unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$_),
  626:                'Feedback ['.$declutter.']',$email,$citations,$feedurl,
  627:                 $attachmenturl)=~/ok/) {
  628: 	$status.='<br />'.&mt('Error sending message to').' '.$_.'<br />';
  629:       } else {
  630: 	$sendsomething++;
  631:       }
  632:     }
  633:   }
  634: 
  635:     my %record=&Apache::lonnet::restore('_feedback');
  636:     my ($temp)=keys %record;
  637:     unless ($temp=~/^error\:/) {
  638:        my %newrecord=();
  639:        $newrecord{'resource'}=$feedurl;
  640:        $newrecord{'subnumber'}=$record{'subnumber'}+1;
  641:        unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') {
  642: 	   $status.='<br />'.&mt('Not registered').'<br />';
  643:        }
  644:     }
  645:        
  646:   return ($status,$sendsomething);
  647: }
  648: 
  649: sub adddiscuss {
  650:     my ($symb,$email,$anon,$attachmenturl,$subject)=@_;
  651:     my $status='';
  652:     if (&Apache::lonnet::allowed('pch',$ENV{'request.course.id'}.
  653:         ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
  654: 
  655:     my %contrib=('message'      => $email,
  656:                  'sendername'   => $ENV{'user.name'},
  657:                  'senderdomain' => $ENV{'user.domain'},
  658:                  'screenname'   => $ENV{'environment.screenname'},
  659:                  'plainname'    => $ENV{'environment.firstname'}.' '.
  660: 		                   $ENV{'environment.middlename'}.' '.
  661:                                    $ENV{'environment.lastname'}.' '.
  662:                                    $ENV{'enrironment.generation'},
  663:                  'attachmenturl'=> $attachmenturl,
  664:                  'subject'      => $subject);
  665:     if ($ENV{'form.replydisc'}) {
  666: 	$contrib{'replyto'}=(split(/\:\:\:/,$ENV{'form.replydisc'}))[1];
  667:     }
  668:     if ($anon) {
  669: 	$contrib{'anonymous'}='true';
  670:     }
  671:     if (($symb) && ($email)) {
  672:        $status='Adding to class discussion'.($anon?' (anonymous)':'').': '.
  673:         &Apache::lonnet::store(\%contrib,$symb,$ENV{'request.course.id'},
  674:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  675: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  676:         my %storenewentry=($symb => time);
  677:         $status.='<br />'.&mt('Updating discussion time').': '.
  678:         &Apache::lonnet::put('discussiontimes',\%storenewentry,
  679:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  680: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  681:     }
  682:     my %record=&Apache::lonnet::restore('_discussion');
  683:     my ($temp)=keys %record;
  684:     unless ($temp=~/^error\:/) {
  685:        my %newrecord=();
  686:        $newrecord{'resource'}=$symb;
  687:        $newrecord{'subnumber'}=$record{'subnumber'}+1;
  688:        $status.='<br />'.&mt('Registering').': '.
  689:                &Apache::lonnet::cstore(\%newrecord,'_discussion');
  690:     }
  691:     } else {
  692: 	$status.='Failed.';
  693:     }
  694:     return $status.'<br />';   
  695: }
  696: 
  697: # ----------------------------------------------------------- Preview function
  698: 
  699: sub show_preview {
  700:     my $r=shift;
  701:     my $message=&clear_out_html($ENV{'form.comment'});
  702:     $message=~s/\n/\<br \/\>/g;
  703:     $message=&Apache::lontexconvert::msgtexconverted($message);
  704:     my $subject=&clear_out_html($ENV{'form.subject'});
  705:     $subject=~s/\n/\<br \/\>/g;
  706:     $subject=&Apache::lontexconvert::msgtexconverted($subject);
  707:     $r->print('<table border="2"><tr><td>'.
  708:        '<b>Subject:</b> '.$subject.'<br /><br />'.
  709:        $message.'</td></tr></table>');
  710: }
  711: 
  712: sub generate_preview_button {
  713:     my $pre=&mt("Show Preview");
  714:     return(<<ENDPREVIEW);
  715: <form name="preview" action="/adm/feedback?preview=1" method="post" target="preview">
  716: <input type="hidden" name="subject">
  717: <input type="hidden" name="comment" />
  718: <input type="button" value="$pre"
  719: onClick="this.form.comment.value=document.mailform.comment.value;this.form.subject.value=document.mailform.subject.value;this.form.submit();" />
  720: </form>
  721: ENDPREVIEW
  722: }
  723: 
  724: sub handler {
  725:   my $r = shift;
  726:   if ($r->header_only) {
  727:      &Apache::loncommon::content_type($r,'text/html');
  728:      $r->send_http_header;
  729:      return OK;
  730:   }
  731: 
  732: # --------------------------- Get query string for limited number of parameters
  733: 
  734:    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
  735: #         ['hide','unhide','deldisc','postdata','preview','replydisc','threadedon','threadedoff']);
  736:          ['hide','unhide','deldisc','postdata','preview','replydisc','threadedon','threadedoff','markread','markunread','storereads','onlyunread','allposts','chgreads']);
  737: 
  738:   if (($ENV{'form.markread'}) || ($ENV{'form.markunread'})) {
  739: # ----------------------------------------------------------------- Modify read/unread for all
  740:       &Apache::loncommon::content_type($r,'text/html');
  741:       $r->send_http_header;
  742:       my $symb=$ENV{'form.markread'}?$ENV{'form.markread'}:$ENV{'form.markunread'};
  743:       my $ressymb = $symb;
  744:       my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
  745:       $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
  746:       my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'},
  747:                           $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  748:                           $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  749:       my %readinghash = ();
  750:                                                                                  
  751:       if ($contrib{'version'}) {
  752:           for (my $id=1;$id<=$contrib{'version'};$id++) {
  753:               my $msgid = $id.':message';
  754:               if (defined($contrib{$msgid})) {
  755:                   if ($ENV{'form.markread'}) {
  756:                       $readinghash{$id} = 'read';
  757:                   } else {
  758:                        $readinghash{$id} = 'unread';
  759:                   }
  760:               }
  761:           }
  762:           if ($ENV{'form.allposts'}) {
  763:               $readinghash{'showonlyunread'} = 0;
  764:           } elsif ($ENV{'form.onlyunread'}) {
  765:               $readinghash{'showonlyunread'} = 1;
  766:           }
  767:           &Apache::lonnet::cstore(\%readinghash,$symb,$ENV{'request.course.id'}.'_discuss',$ENV{'user.domain'},$ENV{'user.name'});
  768:       }
  769:                                                                                  
  770:       &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed reading status'),'0','0');
  771:       return OK;
  772:   } else {
  773:       my $symb = $ENV{'form.discsymb'};
  774:       my %readinghash = ();
  775:       my $chgcount = 0;
  776:       foreach my $key (keys %ENV) {
  777:           if ($key =~ m/^form\.postunread_(\d+)/) {
  778:               $readinghash{$1} = 'unread';
  779:               $chgcount ++;
  780:           } elsif ($key =~ m/^form\.postread_(\d+)/) {
  781:               $readinghash{$1} = 'read';
  782:               $chgcount ++;
  783:           }
  784:       }
  785:       if ($ENV{'form.allposts'}) {
  786:           $readinghash{'showonlyunread'} = 0;
  787:           $chgcount ++;
  788:       } elsif ($ENV{'form.onlyunread'}) {
  789:           $readinghash{'showonlyunread'} = 1;
  790:           $chgcount ++;
  791:       }
  792:                                                                                  
  793:       if ($chgcount > 0) {
  794:           &Apache::lonnet::cstore(\%readinghash,$symb,$ENV{'request.course.id'}.'_discuss',$ENV{'user.domain'},$ENV{'user.name'});
  795:       }
  796:   }
  797: 
  798:   if ($ENV{'form.chgreads'}) {
  799:       &Apache::loncommon::content_type($r,'text/html');
  800:       $r->send_http_header;
  801:       my ($map,$ind,$url)=&Apache::lonnet::decode_symb($ENV{'form.chgreads'});
  802:       &redirect_back($r,&Apache::lonnet::clutter($url),
  803:        &mt('Changed read status').'<br />','0','0');
  804:   } elsif (($ENV{'form.hide'}) || ($ENV{'form.unhide'})) {
  805: # ----------------------------------------------------------------- Hide/unhide
  806:     &Apache::loncommon::content_type($r,'text/html');
  807:     $r->send_http_header;
  808: 
  809:     my $entry=$ENV{'form.hide'}?$ENV{'form.hide'}:$ENV{'form.unhide'};
  810: 
  811:     my ($symb,$idx)=split(/\:\:\:/,$entry);
  812:     my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
  813: 
  814:     my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
  815:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  816: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  817: 
  818:         
  819:     my $currenthidden=$contrib{'hidden'};
  820:     
  821:     if ($ENV{'form.hide'}) {
  822: 	$currenthidden.='.'.$idx.'.';
  823:     } else {
  824:         $currenthidden=~s/\.$idx\.//g;
  825:     }
  826:     my %newhash=('hidden' => $currenthidden);
  827: 
  828:     &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'},
  829:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  830: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  831: 
  832:     &redirect_back($r,&Apache::lonnet::clutter($url),
  833:        &mt('Changed read status').'<br />','0','0');
  834:   } elsif (($ENV{'form.threadedon'}) || ($ENV{'form.threadedoff'})) {
  835:       &Apache::loncommon::content_type($r,'text/html');
  836:       $r->send_http_header;
  837:       if ($ENV{'form.threadedon'}) {
  838: 	  &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'});
  839: 	  &Apache::lonnet::appenv('environment.threadeddiscussion' => 'on');
  840:       } else {
  841:  	  &Apache::lonnet::del('environment',['threadeddiscussion']);
  842: 	  &Apache::lonnet::delenv('environment\.threadeddiscussion');
  843:       }
  844:       my $symb=$ENV{'form.threadedon'}?$ENV{'form.threadedon'}:$ENV{'form.threadedoff'};
  845:       my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
  846:       &redirect_back($r,&Apache::lonnet::clutter($url),
  847: 		     &mt('Changed discussion view mode').'<br />','0','0');
  848:   } elsif ($ENV{'form.deldisc'}) {
  849: # --------------------------------------------------------------- Hide for good
  850:     &Apache::loncommon::content_type($r,'text/html');
  851:     $r->send_http_header;
  852: 
  853:     my $entry=$ENV{'form.deldisc'};
  854: 
  855:     my ($symb,$idx)=split(/\:\:\:/,$entry);
  856:     my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
  857: 
  858:     my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
  859:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  860: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  861: 
  862:         
  863:     my $currentdeleted=$contrib{'deleted'};
  864:     
  865:     $currentdeleted.='.'.$idx.'.';
  866: 
  867:     my %newhash=('deleted' => $currentdeleted);
  868: 
  869:     &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'},
  870:                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
  871: 		     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
  872: 
  873:     &redirect_back($r,&Apache::lonnet::clutter($url),
  874:        &mt('Changed discussion status').'<br />','0','0');
  875:   } elsif ($ENV{'form.preview'}) {
  876: # -------------------------------------------------------- User wants a preview
  877:       $r->content_type('text/html');
  878:       $r->send_http_header;
  879:       &show_preview($r);
  880:   } else {
  881: # ------------------------------------------------------------- Normal feedback
  882:   my $feedurl=$ENV{'form.postdata'};
  883:   $feedurl=~s/^http\:\/\///;
  884:   $feedurl=~s/^$ENV{'SERVER_NAME'}//;
  885:   $feedurl=~s/^$ENV{'HTTP_HOST'}//;
  886:   $feedurl=~s/\?.+$//;
  887: 
  888:   my $symb;
  889:   if ($ENV{'form.replydisc'}) {
  890:       $symb=(split(/\:\:\:/,$ENV{'form.replydisc'}))[0];
  891:       my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
  892:       $feedurl=&Apache::lonnet::clutter($url);
  893:   } else {
  894:       $symb=&Apache::lonnet::symbread($feedurl);
  895:   }
  896:   unless ($symb) {
  897:       $symb=$ENV{'form.symb'};
  898:       if ($symb) {
  899: 	  my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
  900:           $feedurl=&Apache::lonnet::clutter($url);
  901:       }
  902:   }
  903:   my $goahead=1;
  904:   if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form)$/) {
  905:       unless ($symb) { $goahead=0; }
  906:   }
  907:   # backward compatibility (bulltin boards used to be 'wrapped')
  908:   if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
  909:       $feedurl=~s|^/adm/wrapper||;
  910:   }
  911:   if ($goahead) {
  912: # Go ahead with feedback, no ambiguous reference
  913:     &Apache::loncommon::content_type($r,'text/html');
  914:     $r->send_http_header;
  915:   
  916:     if (
  917:       (
  918:        ($feedurl=~m:^/res:) && ($feedurl!~m:^/res/adm:)
  919:       ) 
  920:       || 
  921:       ($ENV{'request.course.id'} && ($feedurl!~m:^/adm:))
  922:       ||
  923:       ($ENV{'request.course.id'} && ($symb=~/^bulletin\_\_\_/))
  924:      ) {
  925: # --------------------------------------------------- Print login screen header
  926:     unless ($ENV{'form.sendit'}) {
  927:       my $options=&screen_header($feedurl);
  928:       if ($options) {
  929: 	&mail_screen($r,$feedurl,$options);
  930:       } else {
  931: 	&fail_redirect($r,$feedurl);
  932:       }
  933:     } else {
  934:       
  935: # Get previous user input
  936:       my $prevattempts=&Apache::loncommon::get_previous_attempt(
  937:             $symb,$ENV{'user.name'},$ENV{'user.domain'},
  938:             $ENV{'request.course.id'});
  939: 
  940: # Get output from resource
  941:       my $usersaw=&resource_output($feedurl);
  942: 
  943: # Get resource answer (need to allow student to view grades for this to work)
  944:       &Apache::lonnet::appenv(('allowed.vgr'=>'F'));
  945:       my $useranswer=&Apache::loncommon::get_student_answers(
  946:                        $symb,$ENV{'user.name'},$ENV{'user.domain'},
  947: 		       $ENV{'request.course.id'});
  948:       &Apache::lonnet::delenv('allowed.vgr');
  949: # Get attachments, if any, and not too large
  950:       my $attachmenturl='';
  951:       if ($ENV{'form.attachment.filename'}) {
  952: 	  unless (length($ENV{'form.attachment'})>131072) {
  953: 	      $attachmenturl=&Apache::lonnet::userfileupload('attachment');
  954: 	  }
  955:       }
  956: # Filter HTML out of message (could be nasty)
  957:       my $message=&clear_out_html($ENV{'form.comment'});
  958: 
  959: # Assemble email
  960:       my ($email,$citations)=&assemble_email($feedurl,$message,$prevattempts,
  961:           $usersaw,$useranswer);
  962:  
  963: # Who gets this?
  964:       my ($typestyle,%to) = &decide_receiver($feedurl);
  965: 
  966: # Actually send mail
  967:       my ($status,$numsent)=&send_msg($feedurl,$email,$citations,
  968:           $attachmenturl,%to);
  969: 
  970: # Discussion? Store that.
  971: 
  972:       my $numpost=0;
  973:       if ($ENV{'form.discuss'}) {
  974:           my $subject = &clear_out_html($ENV{'form.subject'});
  975: 	  $typestyle.=&adddiscuss($symb,$message,0,$attachmenturl,$subject);
  976: 	  $numpost++;
  977:       }
  978: 
  979:       if ($ENV{'form.anondiscuss'}) {
  980:           my $subject = &clear_out_html($ENV{'form.subject'});
  981: 	  $typestyle.=&adddiscuss($symb,$message,1,$attachmenturl,$subject);
  982: 	  $numpost++;
  983:       }
  984: 
  985: 
  986: # Receipt screen and redirect back to where came from
  987:       &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status);
  988: 
  989:     }
  990:    } else {
  991: # Unable to give feedback
  992:     &no_redirect_back($r,$feedurl);
  993:    }
  994:   } else {
  995: # Ambiguous Problem Resource
  996:       if ( &Apache::lonnet::mod_perl_version() == 2 ) {
  997: 	  &Apache::lonnet::cleanenv();
  998:       }
  999:       $r->internal_redirect('/adm/ambiguous');
 1000:   }
 1001: }
 1002:   return OK;
 1003: } 
 1004: 
 1005: 1;
 1006: __END__

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