Diff for /loncom/interface/lonfeedback.pm between versions 1.50 and 1.128

version 1.50, 2003/08/06 17:00:30 version 1.128, 2004/10/04 21:35:52
Line 25 Line 25
 #  #
 # http://www.lon-capa.org/  # http://www.lon-capa.org/
 #  #
 # (Internal Server Error Handler  ###
 #  
 # (Login Screen  
 # 5/21/99,5/22,5/25,5/26,5/31,6/2,6/10,7/12,7/14,  
 # 1/14/00,5/29,5/30,6/1,6/29,7/1,11/9 Gerd Kortemeyer)  
 #  
 # 3/1/1 Gerd Kortemeyer)  
 #  
 # 3/1,2/3,2/5,2/6,2/8 Gerd Kortemeyer  
 # 2/9 Guy Albertelli  
 # 2/10 Gerd Kortemeyer  
 # 2/13 Guy Albertelli  
 # 7/25 Gerd Kortemeyer  
 # 7/26 Guy Albertelli  
 # 7/26,8/10,10/1,11/5,11/6,12/27,12/29 Gerd Kortemeyer  
 # YEAR=2002  
 # 1/1,1/16 Gerd Kortemeyer  
 #  
   
 package Apache::lonfeedback;  package Apache::lonfeedback;
   
Line 51  use Apache::Constants qw(:common); Line 34  use Apache::Constants qw(:common);
 use Apache::lonmsg();  use Apache::lonmsg();
 use Apache::loncommon();  use Apache::loncommon();
 use Apache::lontexconvert();  use Apache::lontexconvert();
   use Apache::lonlocal; # must not have ()
   use Apache::lonhtmlcommon();
   use Apache::lonnavmaps;
   use HTML::LCParser();
   use Apache::lonspeller();
   use Cwd;
   
   sub discussion_open {
       my ($status,$symb)=@_;
       if (defined($status) &&
    !($status eq 'CAN_ANSWER' || $status eq 'CANNOT_ANSWER'
     || $status eq 'OPEN')) {
    return 0;
       }
       my $close=&Apache::lonnet::EXT('resource.0.discussend',$symb);
       if (defined($close) && $close ne '' && $close < time) {
    return 0;
       }
       return 1;
   }
   
   sub discussion_visible {
       my ($status)=@_;
       if (not &discussion_open($status)) {
    my $hidden=&Apache::lonnet::EXT('resource.0.discusshide');
    if (lc($hidden) eq 'yes' or $hidden eq '' or !defined($hidden))  {
       if (!$ENV{'request.role.adv'}) { return 0; }
    }
       }
       return 1;
   }
   
   sub list_discussion {
       my ($mode,$status,$symb)=@_;
       my $outputtarget=$ENV{'form.grade_target'};
       if (defined($ENV{'form.export'})) {
    if($ENV{'form.export'}) {
               $outputtarget = 'export';
           }
       }    
       if (not &discussion_visible($status)) { return ''; }
       my @bgcols = ("#cccccc","#eeeeee");
       my $discussiononly=0;
       if ($mode eq 'board') { $discussiononly=1; }
       unless ($ENV{'request.course.id'}) { return ''; }
       my $crs='/'.$ENV{'request.course.id'};
       my $cid=$ENV{'request.course.id'};
       if ($ENV{'request.course.sec'}) {
    $crs.='_'.$ENV{'request.course.sec'};
       }                 
       $crs=~s/\_/\//g;
       unless ($symb) {
    $symb=&Apache::lonnet::symbread();
       }
       unless ($symb) { return ''; }
       my %usernamesort = ();
       my %namesort =();
       my %subjectsort = ();
   # backward compatibility (bulletin boards used to be 'wrapped')
       my $ressymb=$symb;
       if ($mode eq 'board') {
           unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
               $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
           }
       }
   
   # Get discussion display settings for this discussion
       my $lastkey = $ressymb.'_lastread';
       my $showkey = $ressymb.'_showonlyunread';
       my $markkey = $ressymb.'_showonlyunmark',
       my $visitkey = $ressymb.'_visit';
       my $ondispkey = $ressymb.'_markondisp';
       my $userpickkey = $ressymb.'_userpick';
       my $toggkey = $ressymb.'_readtoggle';
       my $readkey = $ressymb.'_read';
   
       my %dischash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$lastkey,$showkey,$markkey,$visitkey,$ondispkey,$userpickkey,$toggkey,$readkey],$ENV{'user.domain'},$ENV{'user.name'});
       my %discinfo = ();
       my $showonlyunread = 0;
       my $showunmark = 0; 
       my $markondisp = 0;
       my $prevread = 0;
       my $previous = 0;
       my $visit = 0;
       my $newpostsflag = 0;
       my @posters = split/\&/,$dischash{$userpickkey};
   
   # Retain identification of "NEW" posts identified in last display, if continuing 'previous' browsing of posts.
       &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','totposters']);
       my $sortposts = $ENV{'form.sortposts'};
       my $rolefilter = $ENV{'form.rolefilter'};
       my $statusfilter = $ENV{'form.statusfilter'};
       my $sectionpick = $ENV{'form.sectionpick'};
       my $totposters = $ENV{'form.totposters'};
       $previous = $ENV{'form.previous'};
       if ($previous > 0) {
           $prevread = $previous;
       } elsif (defined($dischash{$lastkey})) {
           unless ($dischash{$lastkey} eq '') {
               $prevread = $dischash{$lastkey};
           }
       }
   
   # Get information about students and non-students in course for filtering display of posts
       my %roleshash = ();
       my %roleinfo = ();
       if ($rolefilter) {
           %roleshash = &Apache::lonnet::dump('nohist_userroles',$ENV{'course.'.$ENV{'request.course.id'}.'.domain'},$ENV{'course.'.$ENV{'request.course.id'}.'.num'});
           foreach (keys %roleshash) {
               my ($role,$uname,$udom,$sec) = split/:/,$_;
               my ($end,$start) = split/:/,$roleshash{$_};
               my $now = time;
               my $status = 'Active';
               if (($now < $start) || ($end > 0 && $now > $end)) {
                   $status = 'Expired';
               }
               push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status;
           }
           my ($classlist) = &Apache::loncoursedata::get_classlist(
                                 $ENV{'request.course.id'},
                                 $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                                 $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
           my $sec_index = &Apache::loncoursedata::CL_SECTION();
           my $status_index = &Apache::loncoursedata::CL_STATUS();
           while (my ($student,$data) = each %$classlist) {
               my ($section,$status) = ($data->[$sec_index],
                                    $data->[$status_index]);
               push @{$roleinfo{$student}}, 'st:'.$section.':'.$status;
           }
       }
   
   # Get discussion display default settings for user
       if ($ENV{'environment.discdisplay'} eq 'unread') {
           $showonlyunread = 1;
       }
       if ($ENV{'environment.discmarkread'} eq 'ondisp') {
           $markondisp = 1;
       }
   
   # Override user's default if user specified display setting for this discussion
       if (defined($dischash{$ondispkey})) {
           unless ($dischash{$ondispkey} eq '') {
               $markondisp = $dischash{$ondispkey};
           }
       }
       if ($markondisp) {
           $discinfo{$lastkey} = time;
       }
   
       if (defined($dischash{$showkey})) {
           unless ($dischash{$showkey} eq '') {
               $showonlyunread = $dischash{$showkey};
           }
       }
   
       if (defined($dischash{$markkey})) {
           unless ($dischash{$markkey} eq '') {
               $showunmark = $dischash{$markkey};
           }
       }
   
       if (defined($dischash{$visitkey})) {
           unless ($dischash{$visitkey} eq '') {
               $visit = $dischash{$visitkey};
           }
       }
       $visit ++;
   
       my $seeid=&Apache::lonnet::allowed('rin',$crs);
       my $viewgrades=(&Apache::lonnet::allowed('vgr',$crs)
    && ($symb=~/\.(problem|exam|quiz|assess|survey|form)$/));
       my @discussionitems=();
       my %shown = ();
       my @posteridentity=();
   
       my $current=0;
       my $visible=0;
       my @depth=();
       my @replies = ();
       my %alldiscussion=();
       my %imsitems=();
       my %imsfiles=();
       my %notshown = ();
       my %newitem = ();
       my $maxdepth=0;
   
       my $target='';
       unless ($ENV{'browser.interface'} eq 'textual' ||
       $ENV{'environment.remote'} eq 'off' ) {
    $target='target="LONcom"';
       }
   
       my $now = time;
       $discinfo{$visitkey} = $visit;
   
       &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
       &build_posting_display(\%usernamesort,\%subjectsort,\%namesort,\%notshown,\%newitem,\%dischash,\%shown,\%alldiscussion,\%imsitems,\%imsfiles,\%roleinfo,\@discussionitems,\@replies,\@depth,\@posters,\$maxdepth,\$visible,\$newpostsflag,\$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$ressymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$statusfilter,$toggkey,$outputtarget);
   
       my $discussion='';
       my $manifestfile;
       my $manifestok=0;
       my $tempexport;
       my $imsresources;
       my $copyresult;
   
       my $function = &Apache::loncommon::get_users_function();
       my $color = &Apache::loncommon::designparm($function.'.tabbg',
                                                       $ENV{'user.domain'});
       my %lt = &Apache::lonlocal::texthash(
           'cuse' => 'Current discussion settings',
           'allposts' => 'All posts',
           'unread' => 'New posts only',
           'unmark' => 'Unread only',
           'ondisp' => 'Once displayed',
           'onmark' => 'Once marked not NEW',
           'toggoff' => 'Off',
           'toggon' => 'On',
           'disa' => 'Posts to be displayed',
           'npce' => 'Posts cease to be marked "NEW"',
           'epcb' => 'Each post can be toggled read/unread', 
           'chgt' => 'Change',
           'disp' => 'Display',
           'nolo' => 'Not new',
           'togg' => 'Toggle read/unread',
       );
   
       my $currdisp = $lt{'allposts'};
       my $currmark = $lt{'onmark'};
       my $currtogg = $lt{'toggoff'};
       my $dispchange = $lt{'unread'};
       my $markchange = $lt{'ondisp'};
       my $toggchange = $lt{'toggon'};
       my $chglink = '/adm/feedback?modifydisp='.$ressymb;
       my $displinkA = 'onlyunread';
       my $displinkB = 'onlyunmark';
       my $marklink = 'markondisp';
       my $togglink = 'toggon';
   
       if ($markondisp) {
           $currmark = $lt{'ondisp'};
           $markchange = $lt{'onmark'};
           $marklink = 'markonread';
       }
   
       if ($showonlyunread) {
           $currdisp = $lt{'unread'};
           $dispchange = $lt{'allposts'};
           $displinkA = 'allposts';
       }
   
       if ($showunmark) {
           $currdisp = $lt{'unmark'};
           $dispchange = $lt{'unmark'};
           $displinkA='allposts';
           $displinkB='onlyunread';
           $showonlyunread = 0;
       }
   
       if ($dischash{$toggkey}) {
           $currtogg = $lt{'toggon'};
           $toggchange = $lt{'toggoff'};
           $togglink = 'toggoff';
       } 
      
       $chglink .= '&changes='.$displinkA.'_'.$displinkB.'_'.$marklink.'_'.$togglink;
   
       if ($newpostsflag) {
           $chglink .= '&previous='.$prevread;
       }
   
       if ($visible) {
   # Print the discusssion
           if ($outputtarget eq 'tex') {
               $discussion.='<tex>\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}'.
                            '\textbf{DISCUSSIONS}\makebox[2 cm][b]{\hrulefill}'.
                            '\vskip 0 mm\noindent\textbf{'.$lt{'cuse'}.'}:\vskip 0 mm'.
                            '\noindent\textbf{'.$lt{'disa'}.'}: \textit{'.$currdisp.'}\vskip 0 mm'.
                            '\noindent\textbf{'.$lt{'npce'}.'}: \textit{'.$currmark.'}</tex>';
           } elsif ($outputtarget eq 'export') {
   # Create temporary directory if this is an export
               my $now = time;
               $tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports';
               if (!-e $tempexport) {
                   mkdir($tempexport,0700);
               }
               $tempexport .= '/'.$now;
               if (!-e $tempexport) {
                   mkdir($tempexport,0700);
               }
               $tempexport .= '/'.$ENV{'user.domain'}.'_'.$ENV{'user.name'};
               if (!-e $tempexport) {
                   mkdir($tempexport,0700);
               }
   # open manifest file
               my $manifest = '/imsmanifest.xml';
               my $manifestfilename = $tempexport.$manifest;
               if ($manifestfile = Apache::File->new('>'.$manifestfilename)) {
                   $manifestok=1;
                   print $manifestfile qq|
   <?xml version="1.0" encoding="UTF-8"?>
   <manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
   identifier="MANIFEST-$ressymb" xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 
   imscp_v1p1.xsd http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd">
     <organizations default="$ressymb">
       <organization identifier="$ressymb">
         <title>Discussion for $ressymb</title>\n|;
               } else {
                   $discussion .= 'An error occurred opening the manifest file.<br />';
               }
    } else {
               my $colspan=$maxdepth+1;
               $discussion.= qq|
   <script>
      function studentdelete (symb,idx,newflag,previous) {
          var symbparm = symb+':::'+idx
          var prevparm = ""
          if (newflag == 1) {
              prevparm = "&previous="+previous
          }
          if (confirm("Are you sure you want to delete this post?\\nDeleted posts will no longer be visible to you and other students,\\nbut will continue to be visible to your instructor")) {
              document.location.href = "/adm/feedback?hide="+symbparm+prevparm
          }  
      }
   </script>
               |;
       $discussion.='<form name="readchoices" method="post" action="/adm/feedback?chgreads='.$symb.'"><table bgcolor="#AAAAAA" cellpadding="2" cellspacing="2" border="0">';
       $discussion .='<tr><td bgcolor="#DDDDBB" colspan="'.$colspan.'">'.
    '<table border="0" width="100%" bgcolor="#DDDDBB"><tr>';
       if ($visible>2) {
    $discussion.='<td align="left">'.
       '<a href="/adm/feedback?threadedon='.$ressymb;
    if ($newpostsflag) {
       $discussion .= '&previous='.$prevread;
    }
    $discussion .='">'.&mt('Threaded View').'</a>&nbsp;&nbsp;'.
       '<a href="/adm/feedback?threadedoff='.$ressymb;
    if ($newpostsflag) {
       $discussion .= '&previous='.$prevread;
    }
    $discussion .='">'.&mt('Chronological View').'</a>&nbsp;&nbsp;
                                 <a href= "/adm/feedback?sortfilter='.$ressymb;
                   if ($newpostsflag) {
                       $discussion .= '&previous='.$prevread;
                   }
                   $discussion .='">'.&mt('Sorting/Filtering options').'</a>&nbsp;&nbsp';
               } else {
                   $discussion .= '<td align="left">';
               }
               $discussion .='<a href= "/adm/feedback?export='.$ressymb;
               if ($newpostsflag) {
                   $discussion .= '&previous='.$prevread;
               }
               $discussion .= '">'.&mt('Export').'?</a>&nbsp;&nbsp;</td>';
       if ($newpostsflag) {
    if (!$markondisp) {
       $discussion .='<td align="right"><a href="/adm/feedback?markread='.$ressymb.'">'.&mt('Mark NEW posts no longer new').'</a>&nbsp;&nbsp;';
    } else {
       $discussion .= '<td>&nbsp;</td>';
    }
       } else {
    $discussion .= '<td>&nbsp;</td>';
       }
       $discussion .= '</tr></table></td></tr>';
   
               my $numhidden = keys %notshown;
               if ($numhidden > 0) {
                   my $colspan = $maxdepth+1;
                   $discussion.="\n".'<tr><td bgcolor="#CCCCCC" colspan="'.$colspan.'">'.
                            '<a href="/adm/feedback?allposts='.$ressymb;
                   if ($newpostsflag) {
                       $discussion .= '&previous='.$prevread;
                   }
                   $discussion .= '">'.&mt('Show all posts').'</a> '.&mt('to display').' '.
                            $numhidden.' ';
                   if ($showunmark) {
                       $discussion .= &mt('posts previously marked read');
                   } else {
                       $discussion .= &mt('previously viewed posts');
                   }
                   $discussion .= '<br/></td></tr>';
               }
           }
   
   # Choose sort mechanism
           my @showposts = ();
           if ($sortposts eq 'descdate') {
               @showposts = (sort { $b <=> $a } keys %alldiscussion);
           } elsif ($sortposts eq 'thread') {
               @showposts = (sort { $a <=> $b } keys %alldiscussion);
           } elsif ($sortposts eq 'subject') {
               foreach (sort keys %subjectsort) {
                   push @showposts, @{$subjectsort{$_}};
               }
           } elsif ($sortposts eq 'username') {
               foreach my $domain (sort keys %usernamesort) {
                   foreach (sort keys %{$usernamesort{$domain}}) {
                       push @showposts, @{$usernamesort{$domain}{$_}};
                   }
               }
           } elsif ($sortposts eq 'lastfirst') {
               foreach my $last (sort keys %namesort) {
                    foreach (sort keys %{$namesort{$last}}) {
                        push @showposts, @{$namesort{$last}{$_}};
                    }
               }
           } else {
               $sortposts = 'ascdate';
               @showposts =  (sort { $a <=> $b } keys %alldiscussion);
           }
           my $currdepth = 0;
           my $firstidx = $alldiscussion{$showposts[0]};
           foreach (@showposts) {
               unless (($sortposts eq 'thread') || ($sortposts eq 'ascdate' && $ENV{'environment.threadeddiscussion'}) || ($outputtarget eq 'export')) {
                   $alldiscussion{$_} = $_;
               }
               unless ( ($notshown{$alldiscussion{$_}} eq '1') || ($shown{$alldiscussion{$_}} == 0) ) {
                   if ($outputtarget ne 'tex' && $outputtarget ne 'export') {
       $discussion.="\n<tr>";
    }
           my $thisdepth=$depth[$alldiscussion{$_}];
                   if ($outputtarget ne 'tex' && $outputtarget ne 'export') {
       for (1..$thisdepth) {
    $discussion.='<td>&nbsp;&nbsp;&nbsp;</td>';
       }
    }
           my $colspan=$maxdepth-$thisdepth+1;
                   if ($outputtarget eq 'tex') {
       #cleanup block
       $discussionitems[$alldiscussion{$_}]=~s/<table([^>]*)>/<table TeXwidth="90 mm">/;
       $discussionitems[$alldiscussion{$_}]=~s/<tr([^>]*)><td([^>]*)>/<tr><td TeXwidth="20 mm" align="left">/;
                       my $threadinsert='';
                       if ($thisdepth > 0) {
    $threadinsert='<br /><strong>Reply: '.$thisdepth.'</strong>';
       }
       $discussionitems[$alldiscussion{$_}]=~s/<\/td><td([^>]*)>/$threadinsert<\/td><td TeXwidth="65 mm" align="left">/;
       $discussionitems[$alldiscussion{$_}]=~s/<a([^>]+)>(Edit|Hide|Delete|Reply|Submissions)<\/a>//g;
                       $discussionitems[$alldiscussion{$_}]=~s/(<b>|<\/b>|<\/a>|<a([^>]+)>)//g;
   
       $discussionitems[$alldiscussion{$_}]='<tex>\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}</tex>'.$discussionitems[$alldiscussion{$_}];
       $discussion.=$discussionitems[$alldiscussion{$_}];
    } elsif ($outputtarget eq 'export') {
                       my $postfilename = $alldiscussion{$_}.'-'.$imsitems{$alldiscussion{$_}}{'timestamp'}.'.html';
                       if ($manifestok) {
                           if (($depth[$alldiscussion{$_}] <= $currdepth) && ($alldiscussion{$_} != $firstidx)) {
                               print $manifestfile '  </item>'."\n";
                           }
                           $currdepth = $depth[$alldiscussion{$_}];
                           print $manifestfile "\n". 
         '<item identifier="ITEM-'.$ressymb.'-'.$alldiscussion{$_}.'" isvisible="'.
           $imsitems{$alldiscussion{$_}}{'isvisible'}.'" identifieref="RES-'.$ressymb.'-'.$alldiscussion{$_}.'">'.
           '<title>'.$imsitems{$alldiscussion{$_}}{'title'}.'</title>';
                           $imsresources .= "\n".
       '<resource identifier="RES-'.$ressymb.'-'.$alldiscussion{$_}.'" type="webcontent" href="'.$postfilename.'">'.
         '<file href="'.$alldiscussion{$_}.'.html">'."\n".
         $imsfiles{$alldiscussion{$_}}{$imsitems{$alldiscussion{$_}}{'currversion'}}."\n".
       '</resource>';
                       }
                       my $postingfile;
                       my $postingfilename = $tempexport.'/'.$postfilename;
                       if ($postingfile = Apache::File->new('>'.$postingfilename)) {
                           print $postingfile '<html><head><title>Discussion Post</title></head><body>'.
                                              $imsitems{$alldiscussion{$_}}{'title'}.' '.
                                              $imsitems{$alldiscussion{$_}}{'sender'}.
                                              $imsitems{$alldiscussion{$_}}{'timestamp'}.'<br /><br />'.
                                              $imsitems{$alldiscussion{$_}}{'message'}.'<br />'.
                                              $imsitems{$alldiscussion{$_}}{'attach'}.'</body></html>'."\n"; 
                           close($postingfile);
                       } else {
                           $discussion .= 'An error occurred opening the export file for posting '.$alldiscussion{$_}.'<br />';
                       }
                       $copyresult.=&replicate_attachments($imsitems{$alldiscussion{$_}}{'allattachments'},$tempexport);
                   } else {
                       $discussion.='<td  bgcolor="'.$bgcols[$newitem{$alldiscussion{$_}}].
                          '" colspan="'.$colspan.'">'. $discussionitems[$alldiscussion{$_}].
                          '</td></tr>';
                   }
       }
           }
    unless ($outputtarget eq 'tex' || $outputtarget eq 'export') {
               my $colspan=$maxdepth+1;
               $discussion .= <<END;
               <tr bgcolor="#FFFFFF">
                <td colspan="$colspan" valign="top">
                 <table border="0" bgcolor="#FFFFFF" width="100%" cellspacing="2" cellpadding="2">
                  <tr>
                   <td align="left">
                    <table border="0" cellpadding="0" cellspacing="4">
                     <tr>
                      <td>
                       <font size="-1"><b>$lt{'cuse'}</b>:</td>
                      <td>&nbsp;</td>
                      <td><font size="-1">
   END
               if ($newpostsflag) {
                   $discussion .= 
                      '1.&nbsp;'.$lt{'disp'}.'&nbsp;-&nbsp;<i>'.$currdisp.'</i>&nbsp;&nbsp;2.&nbsp;'.$lt{'nolo'}.'&nbsp;-&nbsp;<i>'.$currmark.'</i>';
                   if ($dischash{$toggkey}) {
                      $discussion .= '&nbsp;&nbsp;3.&nbsp;'.$lt{'togg'}.'&nbsp;-&nbsp;<i>'.$currtogg.'</i>';
                   }
               } else {
                   if ($dischash{$toggkey}) {
                      $discussion .= '1.&nbsp;'.$lt{'disp'}.'&nbsp;-&nbsp;<i>'.$currdisp.'</i>&nbsp;2.&nbsp;'.$lt{'togg'}.'&nbsp;-&nbsp;<i>'.$currtogg.'</i>';
                   } else {
                       $discussion .=
                            $lt{'disp'}.'&nbsp;-&nbsp;<i>'.$currdisp.'</i>';
                   }
               }
               $discussion .= <<END;
                      </font></td>
                      <td>&nbsp;</td>
                      <td>
                       <font size="-1"><b><a href="$chglink">$lt{'chgt'}</a>?</font></b>
                      </td>
                     </tr>
                    </table>
                   </td>
   END
               if ($dischash{$toggkey}) {
                   my $storebutton = &mt('Store read/unread changes');
                   $discussion.='<td align="right">'.
                 '<input type="hidden" name="discsymb" value="'.$ressymb.'">'."\n".
                 '<input type="button" name="readoptions" value="'.$storebutton.'"'.
                 ' onClick="this.form.submit();">'."\n".
                 '</td>';
               }
               $discussion .= (<<END);
                  </tr>
                 </table>
                </td>
               </tr>
              </table>
              <br /><br /></form>
   END
           } 
           if ($outputtarget eq 'export') {
               if ($manifestok) {
                   while ($currdepth > 0) {
                       print $manifestfile "    </item>\n";
                       $currdepth --;
                   }
                   print $manifestfile qq|
       </organization>
     </organizations>
     <resources>
       $imsresources
     </resources>
   </manifest>
                   |;
                   close($manifestfile);
   
   #Create zip file in prtspool
   
                   my $imszipfile = '/prtspool/'.
                   $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'.
                        time.'_'.rand(1000000000).'.zip';
       # zip can cause an sh launch which can pass along all of %ENV
       # which can be too large for /bin/sh to handle
                   my %oldENV=%ENV;
                   undef(%ENV);
                   my $cwd = &getcwd(); 
                   my $imszip = '/home/httpd/'.$imszipfile;
                   chdir $tempexport;
                   open(OUTPUT, "zip -r $imszip *  2> /dev/null |");
                   close(OUTPUT);
                   chdir $cwd;
                   %ENV=%oldENV;
                   undef(%oldENV);
                   $discussion .= 'Download the zip file from <a href="'.$imszipfile.'">Discussion Posting Archive</a><br />';
                   if ($copyresult) {
                       $discussion .= 'The following errors occurred during export - <br />'.$copyresult;
                   }
               } else {
                   $discussion .= '<br />Unfortunately you will not be able to retrieve an archive of the discussion posts at this time, because there was a problem creating a manifest file.<br />';
               }
               return $discussion;
           }
       }
       if ($discussiononly) {
           my $now = time;
           my $attachnum = 0;
           my $newattachmsg = '';
           my @currnewattach = ();
           my @currdelold = ();
           my $comment = '';
           my $subject = '';
           if ($ENV{'form.origpage'}) {
               &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['addnewattach','deloldattach','delnewattach','timestamp','idx','subject','comment']);
               $subject = &Apache::lonnet::unescape($ENV{'form.subject'});
               $comment = &Apache::lonnet::unescape($ENV{'form.comment'});
               my @keepold = ();
               &process_attachments(\@currnewattach,\@currdelold,\@keepold);
               if (@currnewattach > 0) {
                   $attachnum += @currnewattach;
               }
           }
    if (&discussion_open($status)) {
       $discussion.=(<<ENDDISCUSS);
   <form action="/adm/feedback" method="post" name="mailform" enctype="multipart/form-data">
   <input type="submit" name="discuss" value="Post Discussion" />
   <input type="submit" name="anondiscuss" value="Post Anonymous Discussion" />
   <input type="hidden" name="symb" value="$ressymb" />
   <input type="hidden" name="sendit" value="true" />
   <input type="hidden" name="timestamp" value="$now" />
   <br /><a name="newpost"></a>
   <font size="1">Note: in anonymous discussion, your name is visible only 
   to course faculty</font><br />
   <b>Title:</b>&nbsp;<input type="text" name="subject" value="$subject" size="30" /><br /><br />
   <textarea name="comment" cols="80" rows="14" wrap="hard">$comment</textarea>
   ENDDISCUSS
           if ($ENV{'form.origpage'}) {
               $discussion.='<input type="hidden" name="origpage" value="'.$ENV{'form.origpage'}.'" />'."\n";
               foreach (@currnewattach) {
                   $discussion.='<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n";
               }
           }
           $discussion.="</form>\n";
           if ($outputtarget ne 'tex') {
               $discussion.=&generate_attachments_button('',$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,'',$mode);
               if (@currnewattach > 0) {
                   $newattachmsg .= '<b>New attachments</b><br />';
                   if (@currnewattach > 1) {
                       $newattachmsg .= '<ol>';
                       foreach my $item (@currnewattach) {
                           $item =~ m#.*/([^/]+)$#;
                           $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";
                       }
                       $newattachmsg .= '</ol>'."\n";
                   } else {
                       $currnewattach[0] =~ m#.*/([^/]+)$#;
                       $newattachmsg .= '<a href="'.$currnewattach[0].'">'.$1.'</a><br />'."\n";
                   }
               }
               $discussion.=$newattachmsg;
       $discussion.=&generate_preview_button();
    }
    }
           } else {
    if (&discussion_open($status) &&
       &Apache::lonnet::allowed('pch',
      $ENV{'request.course.id'}.
    ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
       if ($outputtarget ne 'tex') {
    $discussion.='<table bgcolor="#BBBBBB"><tr><td><a href="/adm/feedback?replydisc='.
       $symb.':::" '.$target.'>'.
       '<img src="/adm/lonMisc/chat.gif" border="0" />'.
       &mt('Post Discussion').'</a></td></tr></table>';
       }
    }
       }
       return $discussion;
   }
   
   sub build_posting_display {
       my ($usernamesort,$subjectsort,$namesort,$notshown,$newitem,$dischash,$shown,$alldiscussion,$imsitems,$imsfiles,$roleinfo,$discussionitems,$replies,$depth,$posters,$maxdepth,$visible,$newpostsflag,$current,$status,$viewgrades,$seeid,$prevread,$sortposts,$ressymb,$target,$readkey,$showunmark,$showonlyunread,$totposters,$rolefilter,$sectionpick,$statusfilter,$toggkey,$outputtarget) = @_;
   
       my @original=();
       my @index=();
   
       my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'},
     $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   
       if ($contrib{'version'}) {
           my $oldest = $contrib{'1:timestamp'};
           if ($prevread eq '0') {
               $prevread = $oldest-1;
           }
    for (my $id=1;$id<=$contrib{'version'};$id++) {
       my $idx=$id;
               my $posttime = $contrib{$idx.':timestamp'};
               if ($prevread <= $posttime) {
                   $$newpostsflag = 1;
               }
       my $hidden=($contrib{'hidden'}=~/\.$idx\./);
               my $studenthidden=($contrib{'studenthidden'}=~/\.$idx\./);
       my $deleted=($contrib{'deleted'}=~/\.$idx\./);
       my $origindex='0.';
               my $numoldver=0;
       if ($contrib{$idx.':replyto'}) {
                   if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
   # this is a follow-up message
       $original[$idx]=$original[$contrib{$idx.':replyto'}];
       $$depth[$idx]=$$depth[$contrib{$idx.':replyto'}]+1;
       $origindex=$index[$contrib{$idx.':replyto'}];
       if ($$depth[$idx]>$$maxdepth) { $$maxdepth=$$depth[$idx]; }
                   } else {
                       $original[$idx]=0;
                       $$depth[$idx]=0;
                   }
       } else {
   # this is an original message
    $original[$idx]=0;
    $$depth[$idx]=0;
       }
       if ($$replies[$$depth[$idx]]) {
    $$replies[$$depth[$idx]]++;
       } else {
    $$replies[$$depth[$idx]]=1;
       }
       unless ((($hidden) && (!$seeid)) || ($deleted)) {
    $$visible++;
                   if ($contrib{$idx.':history'}) {
                       if ($contrib{$idx.':history'} =~ /:/) {
                           my @oldversions = split/:/,$contrib{$idx.':history'};
                           $numoldver = @oldversions;
                       } else {
                           $numoldver = 1;
                       } 
                   }
                   $$current = $numoldver;
    my %messages = ();
                   my %subjects = ();
                   my %attachtxt = ();
                   my %allattachments = ();
                   my ($screenname,$plainname);
                   my $sender = &mt('Anonymous');
                   my ($message,$subject,$vgrlink,$ctlink);
                   &get_post_contents(\%contrib,$idx,$seeid,$outputtarget,\%messages,\%subjects,\%allattachments,\%attachtxt,$imsfiles,\$screenname,\$plainname,$numoldver);
   
   
   # Set up for sorting by subject
                   unless ($outputtarget eq 'export') {
                       $message=$messages{$numoldver};
                       $message.=$attachtxt{$numoldver};
                       $subject=$subjects{$numoldver};
                       if ($message) {
             if ($hidden) {
       $message='<font color="#888888">'.$message.'</font>';
                               if ($studenthidden) {
                                   $message .='<br /><br />Deleted by poster (student).';
                               }
           }
   
                           if ($subject eq '') {
                              if (defined($$subjectsort{'__No subject'})) {
                                  push @{$$subjectsort{'__No subject'}}, $idx;
                              } else {
                                  @{$$subjectsort{'__No subject'}} = ("$idx");
                              }
                           } else {
                               if (defined($$subjectsort{$subject})) {
                                  push @{$$subjectsort{$subject}}, $idx;
                               } else {
                                  @{$$subjectsort{$subject}} = ("$idx");
                               }
                           }
           if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
       $sender=&Apache::loncommon::aboutmewrapper(
    $plainname,
    $contrib{$idx.':sendername'},
    $contrib{$idx.':senderdomain'}).' ('.
    $contrib{$idx.':sendername'}.' at '.
    $contrib{$idx.':senderdomain'}.')';
       if ($contrib{$idx.':anonymous'}) {
           $sender.=' ['.&mt('anonymous').'] '.
       $screenname;
       }
   
   # Set up for sorting by domain, then username
                               unless (defined($$usernamesort{$contrib{$idx.':senderdomain'}})) {
                                   %{$$usernamesort{$contrib{$idx.':senderdomain'}}} = ();
                               }
                               if (defined($$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}})) {
                                   push @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}}, $idx;
                               } else {
                                   @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}} = ("$idx");
                               }
   # Set up for sorting by last name, then first name
                               my %names = &Apache::lonnet::get('environment',
                                    ['firstname','lastname'],$contrib{$idx.':senderdomain'},
                                     ,$contrib{$idx.':sendername'});
                               my $lastname = $names{'lastname'};
                               my $firstname = $names{'firstname'};
                               if ($lastname eq '') {
                                   $lastname = '_';
                               }
                               if ($firstname eq '') {
                                   $firstname = '_';
                               }
                               unless (defined($$namesort{$lastname})) {
                                   %{$$namesort{$lastname}} = ();
                               }
                               if (defined($$namesort{$lastname}{$firstname})) {
                                   push @{$$namesort{$lastname}{$firstname}}, $idx;
                               } else {
                                   @{$$namesort{$lastname}{$firstname}} = ("$idx");
                               }
                               if ($ENV{'course.'.$ENV{'request.course.id'}.'.allow_discussion_post_editing'} =~ m/yes/i) {
                                   if (($ENV{'user.domain'} eq $contrib{$idx.':senderdomain'}) && ($ENV{'user.name'} eq $contrib{$idx.':sendername'})) {
                                       $sender.=' <a href="/adm/feedback?editdisc='.
                                            $ressymb.':::'.$idx;
                                       if ($newpostsflag) {
                                           $sender .= '&previous='.$prevread;
                                       }
                                       $sender .= '" '.$target.'>'.&mt('Edit').'</a>';                                             
                                       unless ($seeid) {
                                           $sender.=" <a href=\"javascript:studentdelete('$ressymb','$idx','$newpostsflag','$prevread')";
                                           $sender .= '">'.&mt('Delete').'</a>';
                                       }
                                   }
                               } 
       if ($seeid) {
           if ($hidden) {
                                       unless ($studenthidden) {
                   $sender.=' <a href="/adm/feedback?unhide='.
                   $ressymb.':::'.$idx;
                                           if ($newpostsflag) {
                                                $sender .= '&previous='.$prevread;
                                           }
                                           $sender .= '">'.&mt('Make Visible').'</a>';
                                       }
           } else {
       $sender.=' <a href="/adm/feedback?hide='.
           $ressymb.':::'.$idx;
                                       if ($newpostsflag) {
                                           $sender .= '&previous='.$prevread;
                                       }
                                       $sender .= '">'.&mt('Hide').'</a>';
           }                     
           $sender.=' <a href="/adm/feedback?deldisc='.
           $ressymb.':::'.$idx;
                                   if ($newpostsflag) {
                                       $sender .= '&previous='.$prevread;
                                   }
                                   $sender .= '">'.&mt('Delete').'</a>';
                               }
           } else {
       if ($screenname) {
           $sender='<i>'.$screenname.'</i>';
       }
   # Set up for sorting by domain, then username for anonymous
                               unless (defined($$usernamesort{'__anon'})) {
                                   %{$$usernamesort{'__anon'}} = ();
                               }
                               if (defined($$usernamesort{'__anon'}{'__anon'})) {
                                   push @{$$usernamesort{'__anon'}{'__anon'}}, $idx;
                               } else {
                                   @{$$usernamesort{'__anon'}{'__anon'}} = ("$idx");
                               }
   # Set up for sorting by last name, then first name for anonymous
                               unless (defined($$namesort{'__anon'})) {
                                   %{$$namesort{'__anon'}} = ();
                               }
                               if (defined($$namesort{'__anon'}{'__anon'})) {
                                   push @{$$namesort{'__anon'}{'__anon'}}, $idx;
                               } else {
                                   @{$$namesort{'__anon'}{'__anon'}} = ("$idx");
                               }
           }
           if (&discussion_open($status) &&
           &Apache::lonnet::allowed('pch',
    $ENV{'request.course.id'}.
    ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
       $sender.=' <a href="/adm/feedback?replydisc='.
               $ressymb.':::'.$idx;
                               if ($newpostsflag) {
                                       $sender .= '&previous='.$prevread;
                               }
                               $sender .= '" '.$target.'>'.&mt('Reply').'</a>';
                           }
           if ($viewgrades) {
           $vgrlink=&Apache::loncommon::submlink('Submissions',
                               $contrib{$idx.':sendername'},$contrib{$idx.':senderdomain'},$ressymb);
           }
                           if ($$dischash{$readkey}=~/\.$idx\./) { 
                               $ctlink = '<b>'.&mt('Mark unread').'?</b>&nbsp;<input type="checkbox" name="postunread_'.$idx.'" />';
                           } else {
                               $ctlink = '<b>'.&mt('Mark read').'?</b>&nbsp;<input type="checkbox" name="postread_'.$idx.'" />';
                           }
                       }
   #figure out at what position this needs to print
                   }
                   if ($outputtarget eq 'export' || $message) {
       my $thisindex=$idx;
       if ( (($ENV{'environment.threadeddiscussion'}) && (($sortposts eq '') || ($sortposts eq 'ascdate'))) || ($sortposts eq 'thread') || ($outputtarget eq 'export')) {
    $thisindex=$origindex.substr('00'.$$replies[$$depth[$idx]],-2,2);
       }
       $$alldiscussion{$thisindex}=$idx;
                       $$shown{$idx} = 0;
                       $index[$idx]=$thisindex;
                   }
                   if ($outputtarget eq 'export') {
                       %{$$imsitems{$idx}} = ();
                       $$imsitems{$idx}{'isvisible'}='true';
                       if ($hidden) {
                           $$imsitems{$idx}{'isvisible'}='false';
                       }
                       $$imsitems{$idx}{'title'}=$subjects{$numoldver};
                       $$imsitems{$idx}{'message'}=$messages{$numoldver};
                       $$imsitems{$idx}{'attach'}=$attachtxt{$numoldver};
                       $$imsitems{$idx}{'timestamp'}=$contrib{$idx.':timestamp'};
                       $$imsitems{$idx}{'sender'}=$plainname.' ('.
                                            $contrib{$idx.':sendername'}.' at '.
                                            $contrib{$idx.':senderdomain'}.')';
                       $$imsitems{$idx}{'isanonymous'}='false';
                       if ($contrib{$idx.':anonymous'}) {
                           $$imsitems{$idx}{'isanonymous'}='true';
                       }
                       $$imsitems{$idx}{'currversion'}=$numoldver;
                       %{$$imsitems{$idx}{'allattachments'}}=%allattachments;
                       unless ($messages{$numoldver} eq '' && $attachtxt{$numoldver} eq '') {
                           $$shown{$idx} = 1;
                       }
                   } else {
                       if ($message) {
                           my $spansize = 2;
                           if ($showonlyunread && $prevread > $posttime) {
                               $$notshown{$idx} = 1;
                           } elsif ($showunmark && $$dischash{$readkey}=~/\.$idx\./) {
                               $$notshown{$idx} = 1;
                           } else {
   # apply filters
                               my $uname = $contrib{$idx.':sendername'};
                               my $udom = $contrib{$idx.':senderdomain'};
                               my $poster = $uname.':'.$udom;
                               my $rolematch = '';
                               my $skiptest = 1;
                               if ($totposters > 0) {
                                   if (grep/^$poster$/,@{$posters}) {
                                       $$shown{$idx} = 1;
                                   }
                               } else {
                                   if ($rolefilter) {
                                       if ($rolefilter eq 'all') {
                                           $rolematch = '([^:]+)';
                                       } else {
                                           $rolematch = $rolefilter;
                                           $skiptest = 0;
                                       }
                                   }
                                   if ($sectionpick) {
                                       if ($sectionpick eq 'all') {
                                           $rolematch .= ':([^:]*)';
                                       } else {
                                           $rolematch .= ':'.$sectionpick;
                                           $skiptest = 0;
                                       }
                                   }
                                   if ($statusfilter) {
                                       if ($statusfilter eq 'all') {
                                           $rolematch .= ':([^:]+)';
                                       } else {
                                           $rolematch .= ':'.$statusfilter;
                                           $skiptest = 0;
                                       }
                                   }
                                   if ($skiptest) {
                                       $$shown{$idx} = 1;
                                   } else {
                                       foreach my $role (@{$$roleinfo{$poster}}) {
                                           if ($role =~ m/^$rolematch$/) {
                                               $$shown{$idx} = 1;
                                               last;
                                           }
                                       }
                                   }
                               }
                           }
                           unless ($$notshown{$idx} == 1) {
                               if ($prevread > 0 && $prevread <= $posttime) {
                                   $$newitem{$idx} = 1;
                                   $$discussionitems[$idx] .= '
                                    <p><table border="0" width="100%">
                                     <tr><td align="left"><font color="#FF0000"><b>NEW</b></font></td>';
                               } else {
                                   $$newitem{$idx} = 0;
                                   $$discussionitems[$idx] .= '
                                    <p><table border="0" width="100%">
                                     <tr><td align="left">&nbsp;</td>';
                               }
                               $$discussionitems[$idx] .= '<td align ="left">&nbsp;&nbsp;'.
                                   '<b>'.$subject.'</b>&nbsp;&nbsp;'.
                                   $sender.'</b> '.$vgrlink.' ('.
                                   &Apache::lonlocal::locallocaltime($posttime).')</td>';
                               if ($$dischash{$toggkey}) {
                                   $$discussionitems[$idx].='<td align="right">&nbsp;&nbsp;'.
                                     $ctlink.'</td>';
                               }
                               $$discussionitems[$idx].= '</tr></table><blockquote>'.
                                       $message.'</blockquote></p>';
                               if ($contrib{$idx.':history'}) {
                                   my @postversions = ();
                                   $$discussionitems[$idx] .= &mt('This post has been edited by the author.');
                                   if ($seeid) {
                                       $$discussionitems[$idx] .= '&nbsp;&nbsp;<a href="/adm/feedback?allversions='.$ressymb.':::'.$idx.'">'.&mt('Display all versions').'</a>';
                                   }
                                   $$discussionitems[$idx].='<br/>'.&mt('Earlier version(s) were posted on: ');
                                   if ($contrib{$idx.':history'} =~ m/:/) {
                                       @postversions = split/:/,$contrib{$idx.':history'};
                                   } else {
                                       @postversions = ("$contrib{$idx.':history'}");
                                   }
                                   for (my $i=0; $i<@postversions; $i++) {
                                       my $version = $i+1;
                                       $$discussionitems[$idx] .= '<b>'.$version.'.</b> - '.&Apache::lonlocal::locallocaltime($postversions[$i]).'  ';
                                   }
                               }
                           }
                       }
                   }
               }
    }
       }
   }
   
   sub get_post_contents {
       my ($contrib,$idx,$seeid,$type,$messages,$subjects,$allattachments,$attachtxt,$imsfiles,$screenname,$plainname,$numver) = @_;
       my $discussion = '';
       my $start=$numver;
       my $end=$numver + 1;
       %{$$imsfiles{$idx}}=();
       if ($type eq 'allversions') {
          unless($seeid) {
              $discussion=&mt('You do not have privileges to view all versions of posts.').&mt('Please select a different role');
              return $discussion;
          } 
       }
   #    $$screenname=&Apache::loncommon::screenname(
   #                                        $$contrib{$idx.':sendername'},
   #                                        $$contrib{$idx.':senderdomain'});
   #    $$plainname=&Apache::loncommon::nickname(
   #                                        $$contrib{$idx.':sendername'},
   #                                        $$contrib{$idx.':senderdomain'});
       ($$screenname,$$plainname)=($$contrib{$idx.':screenname'},
    $$contrib{$idx.':plainname'});
       my $sender=&Apache::loncommon::aboutmewrapper(
                                    $$plainname,
                                    $$contrib{$idx.':sendername'},
                                    $$contrib{$idx.':senderdomain'}).' ('.
                                    $$contrib{$idx.':sendername'}.' at '.
                                    $$contrib{$idx.':senderdomain'}.')';
       my $attachmenturls = $$contrib{$idx.':attachmenturl'};
       my @postversions = ();
       if ($type eq 'allversions' || $type eq 'export') {
           $start = 0;
           if ($$contrib{$idx.':history'}) {
               if ($$contrib{$idx.':history'} =~ m/:/) {
                   @postversions = split/:/,$$contrib{$idx.':history'};
               } else {
                   @postversions = ("$$contrib{$idx.':history'}");
               }
           }
           &get_post_versions($messages,$$contrib{$idx.':message'},1);
           &get_post_versions($subjects,$$contrib{$idx.':subject'},1);
           push @postversions,$$contrib{$idx.':timestamp'};
           $end = @postversions;
       } else {
           &get_post_versions($messages,$$contrib{$idx.':message'},1,$numver);
           &get_post_versions($subjects,$$contrib{$idx.':subject'},1,$numver);
       }
   
       if ($$contrib{$idx.':anonymous'}) {
           $sender.=' ['.&mt('anonymous').'] '.$$screenname;
       }
       if ($type eq 'allversions') {
           $discussion=('<b>'.$sender.'</b><br /><ul>');
       }
       for (my $i=$start; $i<$end; $i++) {
           my ($timesent,$attachmsg);
           my %currattach = ();
           $timesent = &Apache::lonlocal::locallocaltime($postversions[$i]);
           $$messages{$i}=~s/\n/\<br \/\>/g;
           $$messages{$i}=&Apache::lontexconvert::msgtexconverted($$messages{$i});
           $$subjects{$i}=~s/\n/\<br \/\>/g;
           $$subjects{$i}=&Apache::lontexconvert::msgtexconverted($$subjects{$i});
           if ($attachmenturls) {
               &extract_attachments($attachmenturls,$idx,$i,\$attachmsg,$allattachments,\%currattach);
           }
           if ($type eq 'export') {
               $$imsfiles{$idx}{$i} = '';
               if ($attachmsg) {
                   $$attachtxt{$i} = '<br />Attachments:<br />';
                   foreach (sort keys %currattach) {
                       if ($$allattachments{$_}{'filename'} =~ m-^/uploaded/([^/]+/[^/]+)(/feedback)?(/?\d*)/([^/]+)$-) {
                           my $fname = $1.$3.'/'.$4;
                           $$imsfiles{$idx}{$i} .= '<file href="'.$fname.'">'."\n";
                           $$attachtxt{$i}.= '<a href="'.$fname.'">'.$4.'</a><br />';
                       }
                   }
               }
           } else {
               if ($attachmsg) {
                   $$attachtxt{$i} = '<br />Attachments:'.$attachmsg.'<br />';
               } else {
                   $$attachtxt{$i} = '';
               }
           }
           if ($type eq 'allversions') {
               $discussion.= <<"END";
   <li><b>$$subjects{$i}</b>, $timesent<br />
   $$messages{$i}<br />
   $$attachtxt{$i}</li>
   END
           }
       }
       if ($type eq 'allversions') {
           $discussion.=('</ul></body></html>');
           return $discussion;
       } else {
           return;
       }
   }
   
   sub replicate_attachments {
       my ($attachrefs,$tempexport) = @_;
       my $response;
       foreach my $id (keys %{$attachrefs}) {
           if ($$attachrefs{$id}{'filename'} =~ m-^/uploaded/([^/]+)/([^/]+)(/feedback)?(/?\d*)/([^/]+)$-) {
               my $path = $tempexport;
               my $tail = $1.'/'.$2.$4;
               my @extras = split/\//,$tail;
               my $destination = $tempexport.'/'.$1.'/'.$2.$4.'/'.$5;
               if (!-e $destination) {
                   my $i= 0;
                   while ($i<@extras) {
                       $path .= '/'.$extras[$i];
                       if (!-e $path) {
                           mkdir($path,0700);
                       }
                       $i ++;
                   }
                   my ($content,$rtncode);
                   my $uploadreply = &Apache::lonnet::getuploaded('GET',$$attachrefs{$id}{'filename'},$1,$2,$content,$rtncode);
                   if ($uploadreply eq 'ok') {
                       my $attachcopy;
                       if ($attachcopy = Apache::File->new('>'.$destination)) {
                           print $attachcopy $content;
                           close($attachcopy);
                       } else {
                           $response .= 'Error copying file attachment - '.$5.' to IMS package: '.$!.'<br />'."\n";
                       }
                   } else {
                       &Apache::lonnet::logthis("Replication of attachment failed when building IMS export of discussion posts - domain: $1, course: $2, file: $$attachrefs{$id}{'filename'} -error: $rtncode");
                       $response .= 'Error copying file attachment - '.$5.' to IMS package: '.$rtncode.'<br />'."\n";
                   }
               }
           }
       }
       return $response;
   }
   
 sub mail_screen {  sub mail_screen {
   my ($r,$feedurl,$options) = @_;    my ($r,$feedurl,$options) = @_;
     if (exists($ENV{'form.origpage'})) {
         &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','currnewattach','addnewattach','deloldattach','delnewattach','timestamp','idx','anondiscuss','discuss']);
     }
   my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion',    my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion',
                                           '','onLoad="window.focus();"');                                            '','onLoad="window.focus();setposttype();"');
   my $latexHelp = Apache::loncommon::helpLatexCheatsheet();    my $title=&Apache::lonnet::gettitle($feedurl);
   $r->print(<<ENDDOCUMENT);    if (!$title) { $title = $feedurl; }
     my $quote='';
     my $subject = '';
     my $comment = '';
     my $prevtag = '';
     my $parentmsg = '';
     my ($symb,$idx,$attachmenturls);
     my $numoldver = 0;
     my $attachmsg = '';
     my $newattachmsg = '';
     my @currnewattach = ();
     my @currdelold = ();
     my @keepold = ();
     my %attachments = ();
     my %currattach = ();
     my $attachnum = 0;
     my $anonchk = (<<END);
     function anonchk() {
        if (document.mailform.anondiscuss.checked == true) {
             document.attachment.anondiscuss.value = '1'
        }
        if (document.mailform.discuss.checked == true) {
             document.attachment.discuss.value = '1'
        }
        return
      }
   END
     my $anonscript;
     if (exists($ENV{'form.origpage'})) {
         $anonscript = (<<END);
     function setposttype() {
         var anondisc = $ENV{'form.anondiscuss'};
         var disc = $ENV{'form.discuss'};
         if (anondisc == 1) {
             document.mailform.anondiscuss.checked = true
         }
         if (disc == 1) {
             document.mailform.discuss.checked = true
         }
         return
     }
   END
     } else {
         $anonscript = (<<END);
     function setposttype() {
         return
     }
   END
     }
     if (($ENV{'form.replydisc'}) || ($ENV{'form.editdisc'})) {
         if ($ENV{'form.replydisc'}) {
             ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'});
         } else {
             ($symb,$idx)=split(/\:\:\:/,$ENV{'form.editdisc'});
         }
         my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
      $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
         unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) {
             if ($contrib{$idx.':history'}) {
                 if ($contrib{$idx.':history'} =~ /:/) {
                     my @oldversions = split/:/,$contrib{$idx.':history'};
                     $numoldver = @oldversions;
                 } else {
                     $numoldver = 1;
                 }
             }
             if ($ENV{'form.replydisc'}) {
                 if ($contrib{$idx.':history'}) {
                     if ($contrib{$idx.':history'} =~ /:/) {
                         my @oldversions = split/:/,$contrib{$idx.':history'};
                         $numoldver = @oldversions;
                     } else {
                         $numoldver = 1;
                     }
                 }
                 my $message;
                 if ($idx > 0) {
                     my %msgversions = ();
                     &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);
                     $message = $msgversions{$numoldver};
                 }
         $message=~s/\n/\<br \/\>/g;
         $quote='<blockquote>'.&Apache::lontexconvert::msgtexconverted($message).'</blockquote>';
                 if ($idx > 0) {
                     my %subversions = ();
                     &get_post_versions(\%subversions,$contrib{$idx.':subject'},1,$numoldver);
                     $subject = 'Re: '.$subversions{$numoldver};
                 }
                 $subject = &HTML::Entities::encode($subject,'<>&"');
             } else {
                 $attachmenturls = $contrib{$idx.':attachmenturl'};
                 if ($idx > 0) {
                     my %msgversions = ();
                     &get_post_versions(\%msgversions,$contrib{$idx.':message'},0,$numoldver);
                     $comment = $msgversions{$numoldver};
                     my %subversions = ();
                     &get_post_versions(\%subversions,$contrib{$idx.':subject'},0,$numoldver);
                     $subject = $subversions{$numoldver}; 
                 }
                 if (defined($contrib{$idx.':replyto'})) {
                     $parentmsg = $contrib{$idx.':replyto'};
                 }
                 unless (exists($ENV{'form.origpage'})) {
                     my $anonflag = 0;
                     if ($contrib{$idx.':anonymous'}) {
                         $anonflag = 1;
                     }
                     $anonscript = (<<END);
     function setposttype () {
         var currtype = $anonflag
         if (currtype == 1) {
             document.mailform.elements.discuss.checked = false
             document.mailform.elements.anondiscuss.checked = true
         }
         if (currtype == 0) {
             document.mailform.elements.anondiscuss.checked = false
             document.mailform.elements.discuss.checked = true
         }
         return
     }
   END
                 }
             }
         }
         if ($ENV{'form.previous'}) {
             $prevtag = '<input type="hidden" name="previous" value="'.$ENV{'form.previous'}.'" />';
         }
     }
   
     if ($ENV{'form.origpage'}) {
         $subject = &Apache::lonnet::unescape($ENV{'form.subject'});
         $comment = &Apache::lonnet::unescape($ENV{'form.comment'});
         &process_attachments(\@currnewattach,\@currdelold,\@keepold);
     }
     my $latexHelp=&Apache::loncommon::helpLatexCheatsheet();
     my $htmlheader=&Apache::lonhtmlcommon::htmlareaheaders();
     my $send=&mt('Send');
     $r->print(<<END);
 <html>  <html>
 <head>  <head>
 <title>The LearningOnline Network with CAPA</title>  <title>The LearningOnline Network with CAPA</title>
 <meta http-equiv="pragma" content="no-cache"></meta>  <meta http-equiv="pragma" content="no-cache"></meta>
 <script>  $htmlheader
   <script type="text/javascript">
   //<!--
     function gosubmit() {      function gosubmit() {
         var rec=0;          var rec=0;
         if (typeof(document.mailform.elements.author)!="undefined") {          if (typeof(document.mailform.elements.author)!="undefined") {
Line 97  sub mail_screen { Line 1364  sub mail_screen {
         }          }
   
         if (rec) {          if (rec) {
               if (typeof(document.mailform.onsubmit)=='function') {
    document.mailform.onsubmit();
       }
     document.mailform.submit();      document.mailform.submit();
         } else {          } else {
             alert('Please check a feedback type.');              alert('Please check a feedback type.');
  }   }
     }      }
       $anonchk
       $anonscript
   //-->
 </script>  </script>
 </head>  </head>
 $bodytag  $bodytag
 <h2><tt>$feedurl</tt></h2>  <h2><tt>$title</tt></h2>
 <form action="/adm/feedback" method="post" name="mailform"  <form action="/adm/feedback" method="post" name="mailform"
 enctype="multipart/form-data">  enctype="multipart/form-data">
 <input type=hidden name=postdata value="$feedurl">  $prevtag
   <input type="hidden" name="postdata" value="$feedurl" />
   END
     if ($ENV{'form.replydisc'}) {
         $r->print(<<END);
   <input type="hidden" name="replydisc" value="$ENV{'form.replydisc'}" />
   END
     } elsif ($ENV{'form.editdisc'}) {
        $r->print(<<END);
   <input type="hidden" name="editdisc" value ="$ENV{'form.editdisc'}" />
   <input type="hidden" name="parentmsg" value ="$parentmsg" />
   END
     }
     $r->print(<<END);
 Please check at least one of the following feedback types:  Please check at least one of the following feedback types:
 $options<hr>  $options<hr />
 My question/comment/feedback:<p>  $quote
   <p>My question/comment/feedback:</p>
   <p>
 $latexHelp  $latexHelp
 <textarea name=comment cols=60 rows=10 wrap=hard>  Title: <input type="text" name="subject" size="30" value="$subject" /></p>
 </textarea><p>  <p>
   <textarea name="comment" id="comment" cols="60" rows="10" wrap="hard">$comment
   </textarea></p>
   <p>
   END
       if ( ($ENV{'form.editdisc'}) || ($ENV{'form.replydisc'}) ) {
           if ($ENV{'form.origpage'}) {
               foreach (@currnewattach) {
                   $r->print('<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n");
               }
               foreach (@currdelold) {
                   $r->print('<input type="hidden" name="deloldattach" value="'.$_.'" />'."\n");
               }
           }
           if ($ENV{'form.editdisc'}) {
               if ($attachmenturls) {
                   &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\%attachments,\%currattach,\@currdelold);
                   $attachnum = scalar(keys %currattach);
                   foreach (keys %currattach) {
                       $r->print('<input type="hidden" name="keepold" value="'.$_.'" />'."\n");
                   }
               }
           }
       } else {
           $r->print(<<END);
 Attachment (128 KB max size): <input type="file" name="attachment" />  Attachment (128 KB max size): <input type="file" name="attachment" />
 </p>  </p>
   END
       }
       $r->print(<<END);
 <p>  <p>
 <input type="hidden" name="sendit" value="1" />  <input type="hidden" name="sendit" value="1" />
 <input type=button value="Send Feedback" onClick='gosubmit();' />  <input type="button" value="$send" onClick='gosubmit();' />
 </p>  </p>
 </form>  </form>
 ENDDOCUMENT  END
 $r->print(&generate_preview_button().'</body></html>');      if ($ENV{'form.editdisc'} || $ENV{'form.replydisc'}) {
           my $now = time;
           my $ressymb = $symb;
           my $postidx = '';
           if ($ENV{'form.editdisc'}) {
               $postidx = $idx;
           }
           if (@currnewattach > 0) {
               $attachnum += @currnewattach;
           }
           $r->print(&generate_attachments_button($postidx,$attachnum,$ressymb,$now,\@currnewattach,\@currdelold,$numoldver));
           if ($attachnum > 0) {
               if (@currnewattach > 0) {
                   $newattachmsg .= '<b>New attachments</b><br />';
                   if (@currnewattach > 1) {
                       $newattachmsg .= '<ol>';
                       foreach my $item (@currnewattach) {
                           $item =~ m#.*/([^/]+)$#;
                           $newattachmsg .= '<li><a href="'.$item.'">'.$1.'</a></li>'."\n";
                       }
                       $newattachmsg .= '</ol>'."\n";
                   } else {
                       $currnewattach[0] =~ m#.*/([^/]+)$#;
                       $newattachmsg .= '<a href="'.$currnewattach[0].'">'.$1.'</a><br />'."\n";
                   }
               }
               if ($attachmsg) {
                   $r->print("<b>Retained attachments</b>:$attachmsg<br />\n");
               }
               if ($newattachmsg) {
                   $r->print("$newattachmsg<br />");
               }
           }
       }
       $r->print(&generate_preview_button().
                 &Apache::lonhtmlcommon::htmlareaselectactive('comment').
                 '</body></html>');
   }
   
   sub print_display_options {
       my ($r,$symb,$previous,$dispchgA,$dispchgB,$markchg,$toggchg,$feedurl) = @_;
    # backward compatibility (bulletin boards used to be 'wrapped')
       if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
           $feedurl=~s|^/adm/wrapper||;
       }
   
       my $function = &Apache::loncommon::get_users_function();
       my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
                                                       $ENV{'user.domain'});
       my $bodytag=&Apache::loncommon::bodytag('Discussion options',
                                             '','');
   
       my %lt = &Apache::lonlocal::texthash(
           'dido' => 'Discussion display options',
           'pref' => 'Display Preference',
           'curr' => 'Current setting ',
           'actn' => 'Action',
           'deff' => 'Default for all discussions',
           'prca' => 'Preferences can be set for this discussion that determine ....',
           'whpo' => 'Which posts are displayed when you display this bulletin board or resource, and',
           'unwh' => 'Under what circumstances posts are identified as "NEW", and',
           'wipa' => 'Whether individual posts can be marked as read/unread',
           'allposts' => 'All posts',
           'unread' => 'New posts only',
           'unmark' => 'Posts not marked read',
           'ondisp' => 'Once displayed',
           'onmark' => 'Once marked not NEW ',
           'toggon' => 'Shown',
           'toggoff' => 'Not shown',
           'disa' => 'Posts displayed?',
           'npmr' => 'New posts cease to be identified as "NEW"?',
           'dotm' => 'Option to mark each post as read/unread?',  
           'chgt' => 'Change to ',
           'mkdf' => 'Set to ',
           'yhni' => 'You have not indicated that you wish to change any of the discussion settings',
           'ywbr' => 'You will be returned to the previous page if you click OK.'
       );
   
       my $dispchangeA = $lt{'unread'};
       my $dispchangeB = $lt{'unmark'};
       my $markchange = $lt{'ondisp'};
       my $toggchange = $lt{'toggon'};
       my $currdisp = $lt{'allposts'};
       my $currmark = $lt{'onmark'};
       my $discdisp = 'allposts';
       my $discmark = 'onmark';
       my $currtogg = $lt{'toggoff'};
       my $disctogg = 'toggoff';
                                                                                         
       if ($dispchgA eq 'allposts') {
           $dispchangeA = $lt{'allposts'};
           $currdisp = $lt{'unread'};
           $discdisp = 'unread';
       }
   
       if ($markchg eq 'markonread') {
           $markchange = $lt{'onmark'};
           $currmark = $lt{'ondisp'};
           $discmark = 'ondisp';
       }
   
       if ($dispchgB eq 'onlyunread') {
           $dispchangeB = $lt{'unread'};
           $currdisp = $lt{'unmark'};
           $discdisp = 'unmark';
       }
       if ($toggchg eq 'toggoff') {
           $toggchange = $lt{'toggoff'};
           $currtogg = $lt{'toggon'};
           $disctogg = 'toggon';
       }
       $r->print(<<END);
   <html>
   <head>
   <title>$lt{'dido'}</title>
   <meta http-equiv="pragma" content="no-cache" />
   <script>
   function discdispChk(caller) {
       var disctogg = '$toggchg'
       if (caller == 0) {
           if (document.modifydisp.discdisp[0].checked == true) {
               if (document.modifydisp.discdisp[1].checked == true) {
                   document.modifydisp.discdisp[1].checked = false
               }
           }
       }
       if (caller == 1) {
           if (document.modifydisp.discdisp[1].checked == true) {
               if (document.modifydisp.discdisp[0].checked == true) {
                   document.modifydisp.discdisp[0].checked = false
               }
               if (disctogg == 'toggon') {
                   document.modifydisp.disctogg.checked = true
               }
               if (disctogg == 'toggoff') {
                   document.modifydisp.disctogg.checked = false
               }
           }
       }
       if (caller == 2) {
           var dispchgB = '$dispchgB'
           if (disctogg == 'toggoff') {
               if (document.modifydisp.disctogg.checked == true) {
                   if (dispchgB == 'onlyunmark') {
                       document.modifydisp.discdisp[1].checked = false
                   }
               }
           }
       }  
   }
   
   function setDisp() {
       var prev = "$previous"
       var chktotal = 0
       if (document.modifydisp.discdisp[0].checked == true) {
           document.modifydisp.$dispchgA.value = "$symb"
           chktotal ++
       }
       if (document.modifydisp.discdisp[1].checked == true) {
           document.modifydisp.$dispchgB.value = "$symb"
           chktotal ++
       }
       if (document.modifydisp.discmark.checked == true) {
           document.modifydisp.$markchg.value = "$symb"
           chktotal ++
       }
       if (document.modifydisp.disctogg.checked == true) {
           document.modifydisp.$toggchg.value = "$symb"
           chktotal ++
       }
       if (chktotal > 0) { 
           document.modifydisp.submit()
       } else {
           if(confirm("$lt{'yhni'}. \\n$lt{'ywbr'}"))      {
               if (prev > 0) {
                   location.href = "$feedurl?previous=$previous"
               } else {
                   location.href = "$feedurl"
               }
           }
       }
   }
   </script>
   </head>
   $bodytag
   <form name="modifydisp" method="post" action="/adm/feedback">
   $lt{'sdpf'}<br/> $lt{'prca'}  <ol><li>$lt{'whpo'}</li><li>$lt{'unwh'}</li><li>$lt{'wipa'}</li></ol>
   <br />
   <table border="0" cellpadding="0" cellspacing="0">
    <tr>
     <td width="100%" bgcolor="#000000">
      <table width="100%" border="0" cellpadding="1" cellspacing="0">
       <tr>
        <td width="100%" bgcolor="#000000">
         <table border="0" cellpadding="3" cellspacing="1" bgcolor="#FFFFFF">
          <tr bgcolor="$tabcolor">
           <td><b>$lt{'pref'}</b></td>
           <td><b>$lt{'curr'}</b></td>
           <td><b>$lt{'actn'}?</b></td>
          </tr>
          <tr bgcolor="#dddddd">
          <td>$lt{'disa'}</td>
          <td>$lt{$discdisp}</td>
          <td><input type="checkbox" name="discdisp" onClick="discdispChk('0')" />&nbsp;$lt{'chgt'} "$dispchangeA"
              <br />
              <input type="checkbox" name="discdisp" onClick="discdispChk('1')" />&nbsp;$lt{'chgt'} "$dispchangeB"
          </td>
         </tr><tr bgcolor="#eeeeee">
          <td>$lt{'npmr'}</td>
          <td>$lt{$discmark}</td>
          <td><input type="checkbox" name="discmark" />$lt{'chgt'} "$markchange"</td>
         </tr><tr bgcolor="#dddddd">
          <td>$lt{'dotm'}</td>
          <td>$lt{$disctogg}</td>
          <td><input type="checkbox" name="disctogg" onClick="discdispChk('2')" />$lt{'chgt'} "$toggchange"</td>
         </tr>
        </table>
       </td>
      </tr>
     </table>
    </td>
   </tr>
   </table>
   <br />
   <br />
   <input type="hidden" name="previous" value="$previous" />
   <input type="hidden" name="$dispchgA" value=""/>
   <input type="hidden" name="$dispchgB" value=""/>
   <input type="hidden" name="$markchg" value=""/>
   <input type="hidden" name="$toggchg" value="" />
   <input type="button" name="sub" value="Store Changes" onClick="javascript:setDisp()" />
   <br />
   <br />
   </form>
   </body>
   </html>
   END
       return;
   }
   
   sub print_sortfilter_options {
       my ($r,$symb,$previous,$feedurl) = @_;
    # backward compatibility (bulletin boards used to be 'wrapped')
       if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
           $feedurl=~s|^/adm/wrapper||;
       }
       my @sections = ();
       my $section_sel = '';
       my $numsections = 0;
       my $numvisible = 5;
       my ($classlist) = &Apache::loncoursedata::get_classlist(
                                 $ENV{'request.course.id'},
                                 $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                                 $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
                                                                                      
       my $sec_index = &Apache::loncoursedata::CL_SECTION();
       my $status_index = &Apache::loncoursedata::CL_STATUS();
       my %sectioncount = ();
       while (my ($student,$data) = each %$classlist) {
           my ($section,$status) = ($data->[$sec_index],
                                    $data->[$status_index]);
           unless ($section eq '' || $section =~ /^\s*$/) {
               if (!defined($sectioncount{$section})) {
                   $sectioncount{$section} = 1;
                   $numsections ++;
               } else {
                   $sectioncount{$section} ++;
               }
           }
       }
                                                                                      
       if ($ENV{'request.course.sec'} !~ /^\s*$/) {
           @sections = ($ENV{'request.course.sec'});
           $numvisible = 1;
       } else {
           @sections = sort {$a cmp $b} keys(%sectioncount);
           unshift(@sections,'all'); # Put 'all' at the front of the list
           if ($numsections < 4) {
               $numvisible = $numsections + 1;
           }
       }
       foreach (@sections) {
           $section_sel .= "  <option value=\"$_\" />$_\n";
       }
                                                                                      
       my $function = &Apache::loncommon::get_users_function();
       my $tabcolor = &Apache::loncommon::designparm($function.'.tabbg',
                                                       $ENV{'user.domain'});
       my $bodytag=&Apache::loncommon::bodytag('Discussion options',
                                             '','');
       my %lt = &Apache::lonlocal::texthash(
           'diso' => 'Discussion sorting and filtering options',
           'diop' => 'Display Options',
           'curr' => 'Current setting ',
           'actn' => 'Action',
           'prca' => 'Options can be set that control the sort order of the posts, in addition to which posts are displayed.',
           'soor' => 'Sort order',
           'disp' => 'Specific user roles',
           'actv' => 'Specific role status',
           'spse' => 'Specific sections',
           'psub' => 'Pick specific users (by name)',
           'shal' => 'Show a list of current posters'
       );
       $r->print(<<END);
   <html>
   <head>
   <title>$lt{'diso'}</title>
   <meta http-equiv="pragma" content="no-cache" />
   </head>
   $bodytag
   <form name="modifyshown" method="post" action="/adm/feedback">
   <b>$lt{'diso'}</b><br/> $lt{'prca'}
   <br /><br />
   <table border="0">
    <tr>
     <td><b>$lt{'soor'}</b></td>
     <td>&nbsp;</td>
     <td><b>$lt{'disp'}</b></td>
     <td>&nbsp;</td>
     <td><b>$lt{'actv'}</b></td>
     <td>&nbsp;</td>
     <td><b>$lt{'spse'}</b></td>
     <td>&nbsp;</td>
     <td><b>$lt{'psub'}</b></td>
    </tr>
    <tr>
     <td>
      <select name="sortposts">
       <option value="ascdate" />Date order - oldest first
       <option value="descdate" />Date order - newest first
       <option value="thread" />Threaded
       <option value="subject" />By subject
       <option value="username" />By domain and username
       <option value="lastfirst" />By last name, first name
      </select>
     </td>
     <td>&nbsp;</td>
     <td>
      <select name="rolefilter" multiple="true" size="5">
       <option value="all" />All users
       <option value="st" />Students
       <option value="cc" />Course Coordinators
       <option value="in" />Instructors
       <option value="ta" />TAs
       <option value="pr" />Exam proctors
       <option value="cr" />Custom roles
      </select>
     </td>
     <td>&nbsp;</td>
     <td>
      <select name="statusfilter">
       <option value="all" />Roles of any status
       <option value="Active" />Only active roles
       <option value="Expired" />Only inactive roles
      </select>
     </td>
     <td>&nbsp;</td>
     <td>
      <select name="sectionpick" multiple="true" size="$numvisible">
       $section_sel
      </select>
     </td>
     <td>&nbsp;</td>
     <td><input type="checkbox" name="posterlist" value="$symb" />$lt{'shal'}</td>
    </tr>
   </table>
   <br />
   <br />
   <input type="hidden" name="previous" value="$previous" />
   <input type="hidden" name="applysort" value="$symb" />
   <input type="button" name="sub" value="Store Changes" onClick="javascript:document.modifyshown.submit()" />
   <br />
   <br />
   </form>
   </body>
   </html>
   END
   }
   
   sub print_showposters {
       my ($r,$symb,$previous,$feedurl,$sortposts) = @_;
    # backward compatibility (bulletin boards used to be 'wrapped')
       if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
           $feedurl=~s|^/adm/wrapper||;
       }
   # backward compatibility (bulletin boards used to be 'wrapped')
       my $ressymb=$symb;
       if ($ressymb =~ /bulletin___\d+___/) {
           unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
               $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
           }
       }
       my $crs='/'.$ENV{'request.course.id'};
       if ($ENV{'request.course.sec'}) {
           $crs.='_'.$ENV{'request.course.sec'};
       }
       $crs=~s/\_/\//g;
       my $seeid=&Apache::lonnet::allowed('rin',$crs);
       my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'},
                             $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                             $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
       my %namesort = ();
       my %postcounts = ();
       my %lt=&Apache::lonlocal::texthash(
                        'diso' => 'Discussion filtering options',
       );
       my $bodytag=&Apache::loncommon::bodytag('Discussion options',
                                             '','');
       if ($contrib{'version'}) {
           for (my $idx=1;$idx<=$contrib{'version'};$idx++) {
               my $hidden=($contrib{'hidden'}=~/\.$idx\./);
               my $deleted=($contrib{'deleted'}=~/\.$idx\./);
               unless ((($hidden) && (!$seeid)) || ($deleted)) {
                   if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
                       my %names = &Apache::lonnet::get('environment',['firstname','lastname'],$contrib{$idx.':senderdomain'},$contrib{$idx.':sendername'});
                       my $lastname = $names{'lastname'};
                       my $firstname = $names{'firstname'};
                       if ($lastname eq '') {
                           $lastname = '_';
                       }
                       if ($firstname eq '') {
                           $firstname = '_';
                       }
                       unless (defined($namesort{$lastname})) {
                           %{$namesort{$lastname}} = ();
                       }
                       my $poster =  $contrib{$idx.':sendername'}.':'.$contrib{$idx.':senderdomain'};
                       $postcounts{$poster} ++;
                       if (defined($namesort{$lastname}{$firstname})) {
                           if (!grep/^$poster$/,@{$namesort{$lastname}{$firstname}}) {
                               push @{$namesort{$lastname}{$firstname}}, $poster;
                           }
                       } else {
                           @{$namesort{$lastname}{$firstname}} = ("$poster");
                       }
                   }
               }
           }
       }
       $r->print(<<END);
   <html>
   <head>
   <title>$lt{'diso'}</title>
   <meta http-equiv="pragma" content="no-cache" />
   </head>
   $bodytag
    <form name="pickpostersform" method="post">
     <table border="0">
      <tr>
       <td bgcolor="#777777">
        <table border="0" cellpadding="3">
         <tr bgcolor="#e6ffff">
          <td><b>No.</b></td>
          <td><b>Select</b></td>
          <td><b>Fullname</b><font color="#999999">(Username/domain)</font></td>
          <td><b>Posts</td>
         </tr>
   END
       my $count = 0;
       foreach my $last (sort keys %namesort) {
           foreach my $first (sort keys %{$namesort{$last}}) {
               foreach (sort @{$namesort{$last}{$first}}) {
                   my ($uname,$udom) = split/:/,$_;
                   if (!$uname || !$udom) { 
                       next;
                   } else {
                       $count ++;
                       $r->print('<tr bgcolor="#ffffe6"><td align="right">'.$count.'</td><td align="center"><input name="stuinfo" type="checkbox" value="'.$_.'" /></td><td>'.$last.', '.$first.' ('.$uname.','.$udom.')</td><td>'.$postcounts{$_}.'</td></tr>');
                   }
               }
           }
       }
       $r->print(<<END);
        </table>
       </td>
      </tr>
     </table>
   <br />
   <input type="hidden" name="sortposts" value="$sortposts" />
   <input type="hidden" name="userpick" value="$symb" />
   <input type="button" name="store" value="Display posts" onClick="javascript:document.pickpostersform.submit()" />
   </form>
   </body>
   </html>
   END
 }  }
   
 sub fail_redirect {  sub get_post_versions {
       my ($versions,$incoming,$htmldecode,$numver) = @_;
       if ($incoming =~ /^<version num="0">/) {
           my $p = HTML::LCParser->new(\$incoming);
           my $done = 0;                                                                       
           while ( (my $token = $p->get_tag("version")) && (!$done)) {
               my $num = $token->[1]{num};
               my $text = $p->get_text("/version");
               if (defined($numver)) {
                   if ($num == $numver) {
                       if ($htmldecode) {
                           $text = &HTML::Entities::decode($text);
                       }
                       $$versions{$numver}=$text;
                       $done = 1;
                   }
               } else {
                   if ($htmldecode) {
                       $text = &HTML::Entities::decode($text);
                   }
                   $$versions{$num}=$text;
               }
           }
       } else {
           if (!defined($numver)) {
               $numver = 0;
           }
           if ($htmldecode) {
               $$versions{$numver} = $incoming;
           } else {
               $$versions{$numver} = &HTML::Entities::encode($incoming,'<>&"');
           }
       }
       return;
   }
   
   sub get_post_attachments {
       my ($attachments,$attachmenturls) = @_;
       my $num;
       if ($attachmenturls =~ m/^<attachment id="0">/) {
           my $p = HTML::LCParser->new(\$attachmenturls);
           while (my $token = $p->get_tag("attachment","filename","post"))  {
               if ($token->[0] eq "attachment") {
                   $num = $token->[1]{id};
                   %{$$attachments{$num}} =();
               } elsif ($token->[0] eq "filename") {
                   $$attachments{$num}{'filename'} = $p->get_text("/filename");
               } elsif ($token->[0] eq "post") {
                   my $id = $token->[1]{id};
                   $$attachments{$num}{$id} = $p->get_text("/post");
               }
           }
       } else {
           %{$$attachments{'0'}} = ();
           $$attachments{'0'}{'filename'} = $attachmenturls;
           $$attachments{'0'}{'0'} = 'n';
       }
   
       return;
   }
   
   sub fail_redirect {;
   my ($r,$feedurl) = @_;    my ($r,$feedurl) = @_;
     if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
   $r->print (<<ENDFAILREDIR);    $r->print (<<ENDFAILREDIR);
   <html>
 <head><title>Feedback not sent</title>  <head><title>Feedback not sent</title>
 <meta http-equiv="pragma" content="no-cache"></meta>  <meta http-equiv="pragma" content="no-cache" />
 <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl">  <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
 </head>  </head>
 <html>  
 <body bgcolor="#FFFFFF">  <body bgcolor="#FFFFFF">
 <img align=right src=/adm/lonIcons/lonlogos.gif>  <img align="right" src="/adm/lonIcons/lonlogos.gif" />
 <b>Sorry, no recipients  ...</b>  <b>Sorry, no recipients  ...</b>
   <br /><a href="$feedurl">Continue</a>
 </body>  </body>
 </html>  </html>
 ENDFAILREDIR  ENDFAILREDIR
 }  }
   
 sub redirect_back {  sub redirect_back {
   my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status) = @_;    my ($r,$feedurl,$typestyle,$sendsomething,$sendposts,$status,$previous,$sort,$rolefilter,$statusfilter,$secpick,$numpicks) = @_;
     my $sorttag = '';
     my $roletag = '';
     my $statustag = '';
     my $sectag = '';
     my $userpicktag = '';
     my $qrystr = '';
     my $prevtag = '';
    # backward compatibility (bulletin boards used to be 'wrapped')
     if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
         $feedurl=~s|^/adm/wrapper||;
     }
     if ($feedurl=~/^\/adm\//) { $feedurl.='?register=1' };
     if ($previous > 0) {
         $qrystr = 'previous='.$previous;
         if ($feedurl =~ /\?register=1/) {
             $feedurl .= '&'.$qrystr;
         } else {
             $feedurl .= '?'.$qrystr;
         }
         $prevtag = '<input type="hidden" name="previous" value="'.$previous.'" />';
     }
     if (defined($sort)) {
         my $sortqry = 'sortposts='.$sort;
         if (($feedurl =~ /\?register=1/) || ($feedurl =~ /\?previous=/)) {
             $feedurl .= '&'.$sortqry;
         } else {
             $feedurl .= '?'.$sortqry;
         }
         $sorttag = '<input type="hidden" name="sortposts" value="'.$sort.'" />';
         if ( (defined($numpicks)) && ($numpicks > 0) ) {
             my $userpickqry = 'totposters='.$numpicks;
             $feedurl .= '&'.$userpickqry;
             $userpicktag = '<input type="hidden" name="totposters" value="'.$numpicks.'" />';
         } else {
             my $roleqry = 'rolefilter='.$rolefilter;
             $feedurl .= '&'.$roleqry;
             $roletag = '<input type="hidden" name="rolefilter" value="'.$rolefilter.'" />';
             $feedurl .= '&statusfilter='.$statusfilter;
             $statustag ='<input type="hidden" name="statusfilter" value="'.$statusfilter.'" />';
             $feedurl .= '&sectionpick='.$secpick;
             $sectag = '<input type="hidden" name="sectionpick" value="'.$secpick.'" />';
         }
     }
   $r->print (<<ENDREDIR);    $r->print (<<ENDREDIR);
   <html>
 <head>  <head>
 <title>Feedback sent</title>  <title>Feedback sent</title>
 <meta http-equiv="pragma" content="no-cache"></meta>  <meta http-equiv="pragma" content="no-cache" />
 <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl">  <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
 </head>  </head>
 <html>  
 <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'>  <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'>
 <img align=right src=/adm/lonIcons/lonlogos.gif>  <img align="right" src="/adm/lonIcons/lonlogos.gif" />
 $typestyle  $typestyle
 <b>Sent $sendsomething message(s), and $sendposts post(s).</b>  <b>Sent $sendsomething message(s), and $sendposts post(s).</b>
 <font color=red>$status</font>  <font color="red">$status</font>
 <form name="reldt" action="$feedurl" target="loncapaclient">  <form name="reldt" action="$feedurl" target="loncapaclient">
   $prevtag
   $sorttag
   $statustag
   $roletag
   $sectag
   $userpicktag
 </form>  </form>
   <br /><a href="$feedurl">Continue</a>
 </body>  </body>
 </html>  </html>
 ENDREDIR  ENDREDIR
Line 165  ENDREDIR Line 2077  ENDREDIR
   
 sub no_redirect_back {  sub no_redirect_back {
   my ($r,$feedurl) = @_;    my ($r,$feedurl) = @_;
     my $nofeed=&mt('Sorry, no feedback possible on this resource  ...');
     my $continue=&mt('Continue');
   $r->print (<<ENDNOREDIR);    $r->print (<<ENDNOREDIR);
   <html>
 <head><title>Feedback not sent</title>  <head><title>Feedback not sent</title>
 <meta http-equiv="pragma" content="no-cache"></meta>  <meta http-equiv="pragma" content="no-cache" />
 ENDNOREDIR  ENDNOREDIR
   
   if ($feedurl!~/^\/adm\/feedback/) {     if ($feedurl!~/^\/adm\/feedback/) { 
Line 176  ENDNOREDIR Line 2091  ENDNOREDIR
       
   $r->print (<<ENDNOREDIRTWO);    $r->print (<<ENDNOREDIRTWO);
 </head>  </head>
 <html>  
 <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { self.close(); }'>  <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { self.close(); }'>
 <img align=right src=/adm/lonIcons/lonlogos.gif>  <img align="right" src="/adm/lonIcons/lonlogos.gif" />
 <b>Sorry, no feedback possible on this resource  ...</b>  <b>$nofeed</b>
   <br /><a href="$feedurl">$continue</a>
 </body>  </body>
 </html>  </html>
 ENDNOREDIRTWO  ENDNOREDIRTWO
 }  }
   
 sub screen_header {  sub screen_header {
   my ($feedurl) = @_;      my ($feedurl) = @_;
   my $msgoptions='';      my $msgoptions='';
   my $discussoptions='';      my $discussoptions='';
   if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/)) {      unless (($ENV{'form.replydisc'}) || ($ENV{'form.editdisc'})) {
     $msgoptions=    if (($feedurl=~/^\/res\//) && ($feedurl!~/^\/res\/adm/)) {
       '<p><input type=checkbox name=author> Feedback to resource author';      $msgoptions= 
   }   '<p><input type="checkbox" name="author" /> '.
   if (&feedback_available(1)) {   &mt('Feedback to resource author').'</p>';
     $msgoptions.=   }
     '<br><input type=checkbox name=question> Question about resource content';   if (&feedback_available(1)) {
   }      $msgoptions.=
   if (&feedback_available(0,1)) {   '<br /><input type="checkbox" name="question" /> '.
     $msgoptions.=   &mt('Question about resource content');
       '<br><input type=checkbox name=course> '.   }
  'Question/Comment/Feedback about course content';   if (&feedback_available(0,1)) {
   }      $msgoptions.=
   if (&feedback_available(0,0,1)) {   '<br /><input type="checkbox" name="course" /> '.
     $msgoptions.=   &mt('Question/Comment/Feedback about course content');
       '<br><input type=checkbox name=policy> '.   }
  'Question/Comment/Feedback about course policy';   if (&feedback_available(0,0,1)) {
   }      $msgoptions.=
    '<br /><input type="checkbox" name="policy" /> '.
   if ($ENV{'request.course.id'}) {   &mt('Question/Comment/Feedback about course policy');
       if (&Apache::lonnet::allowed('pch',   }
         $ENV{'request.course.id'}.      }
         ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {      if ($ENV{'request.course.id'}) {
     $discussoptions='<input type="checkbox" name="discuss" onClick="this.form.anondiscuss.checked=false;"> '.   if (&discussion_open() &&
  'Contribution to course discussion of resource';      &Apache::lonnet::allowed('pch',
     $discussoptions.='<br><input type="checkbox" name="anondiscuss" onClick="this.form.discuss.checked=false;"> '.       $ENV{'request.course.id'}.
  'Anonymous contribution to course discussion of resource'.       ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
         ' <i>(name only visible to course faculty)</i>';      $discussoptions='<input type="checkbox" name="discuss" onClick="this.form.anondiscuss.checked=false;" '.
    ($ENV{'form.replydisc'}?' checked="1"':'').' /> '.
    &mt('Contribution to course discussion of resource');
       $discussoptions.='<br /><input type="checkbox" name="anondiscuss" onClick="this.form.discuss.checked=false;" /> '.
    &mt('Anonymous contribution to course discussion of resource').
    ' <i>('.&mt('name only visible to course faculty').')</i>';
       }        }
   }      }
   if ($msgoptions) { $msgoptions='<h2>Sending Messages</h2>'.$msgoptions; }      if ($msgoptions) { $msgoptions='<h2><img src="/adm/lonMisc/feedback.gif" />'.&mt('Sending Messages').'</h2>'.$msgoptions; }
   if ($discussoptions) {       if ($discussoptions) { 
      $discussoptions='<h2>Discussion Contributions</h2>'.$discussoptions; }   $discussoptions='<h2><img src="/adm/lonMisc/chat.gif" />'.&mt('Discussion Contributions').'</h2>'.$discussoptions; }
   return $msgoptions.$discussoptions;      return $msgoptions.$discussoptions;
 }  }
   
 sub resource_output {  sub resource_output {
Line 240  sub resource_output { Line 2160  sub resource_output {
   
 sub clear_out_html {  sub clear_out_html {
   my ($message,$override)=@_;    my ($message,$override)=@_;
     unless (&Apache::lonhtmlcommon::htmlareablocked()) { return $message; }
   # Always allow the <m>-tag
     my %html=(M=>1);
   # Check if more is allowed
   my $cid=$ENV{'request.course.id'};    my $cid=$ENV{'request.course.id'};
   if (($ENV{"course.$cid.allow_limited_html_in_feedback"} =~ m/yes/i) ||    if (($ENV{"course.$cid.allow_limited_html_in_feedback"} =~ m/yes/i) ||
       ($override)) {        ($override)) {
       # allows <B> <I> <P> <A> <LI> <OL> <UL> <EM> <BR> <TT> <STRONG>         # allows <B> <I> <P> <A> <LI> <OL> <UL> <EM> <BR> <TT> <STRONG> 
       # <BLOCKQUOTE> <DIV .*> <DIV> <IMG>        # <BLOCKQUOTE> <DIV .*> <DIV> <IMG> <M> <SPAN> <H1> <H2> <H3> <H4> <SUB>
       my %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1,        # <SUP>
  BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, DIV=>1, IMG=>1);        %html=(B=>1, I=>1, P=>1, A=>1, LI=>1, OL=>1, UL=>1, EM=>1,
        BR=>1, TT=>1, STRONG=>1, BLOCKQUOTE=>1, DIV=>1, IMG=>1,
       $message =~ s/\<(\/?\s*(\w+)[^\>\<]*)/       M=>1, SUB=>1, SUP=>1, SPAN=>1, 
        H1=>1, H2=>1, H3=>1, H4=>1, H5=>1);
     }
   # Do the substitution of everything that is not explicitly allowed
     $message =~ s/\<(\/?\s*(\w+)[^\>\<]*)/
   {($html{uc($2)}&&(length($1)<1000))?"\<$1":"\&lt;$1"}/ge;    {($html{uc($2)}&&(length($1)<1000))?"\<$1":"\&lt;$1"}/ge;
       $message =~ s/(\<?\s*(\w+)[^\<\>]*)\>/    $message =~ s/(\<?\s*(\w+)[^\<\>]*)\>/
   {($html{uc($2)}&&(length($1)<1000))?"$1\>":"$1\&gt;"}/ge;    {($html{uc($2)}&&(length($1)<1000))?"$1\>":"$1\&gt;"}/ge;
   } else {  
       $message=~s/\<\/*m\s*\>//g;  
       $message=~s/\</\&lt\;/g;  
       $message=~s/\>/\&gt\;/g;  
   }  
   return $message;    return $message;
 }  }
   
Line 270  ENDEMAIL Line 2193  ENDEMAIL
     my $citations=<<"ENDCITE";      my $citations=<<"ENDCITE";
 <h2>Previous attempts of student (if applicable)</h2>  <h2>Previous attempts of student (if applicable)</h2>
 $prevattempts  $prevattempts
 <p><hr>  <br /><hr />
 <h2>Original screen output (if applicable)</h2>  <h2>Original screen output (if applicable)</h2>
 $usersaw  $usersaw
 <h2>Correct Answer(s) (if applicable)</h2>  <h2>Correct Answer(s) (if applicable)</h2>
Line 317  sub decide_receiver { Line 2240  sub decide_receiver {
     }       } 
   }    }
   if ($ENV{'form.course'}||$course) {    if ($ENV{'form.course'}||$course) {
     $typestyle.='Submitting as Comment<br>';      $typestyle.='Submitting as Comment<br />';
     foreach (split(/\,/,      foreach (split(/\,/,
    $ENV{'course.'.$ENV{'request.course.id'}.'.comment.email'})     $ENV{'course.'.$ENV{'request.course.id'}.'.comment.email'})
      ) {       ) {
Line 326  sub decide_receiver { Line 2249  sub decide_receiver {
     }       } 
   }    }
   if ($ENV{'form.policy'}||$policy) {    if ($ENV{'form.policy'}||$policy) {
     $typestyle.='Submitting as Policy Feedback<br>';      $typestyle.='Submitting as Policy Feedback<br />';
     foreach (split(/\,/,      foreach (split(/\,/,
    $ENV{'course.'.$ENV{'request.course.id'}.'.policy.email'})     $ENV{'course.'.$ENV{'request.course.id'}.'.policy.email'})
      ) {       ) {
Line 357  sub send_msg { Line 2280  sub send_msg {
       unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$_),        unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$_),
                'Feedback ['.$declutter.']',$email,$citations,$feedurl,                 'Feedback ['.$declutter.']',$email,$citations,$feedurl,
                 $attachmenturl)=~/ok/) {                  $attachmenturl)=~/ok/) {
  $status.='<br>Error sending message to '.$_.'<br>';   $status.='<br />'.&mt('Error sending message to').' '.$_.'<br />';
       } else {        } else {
  $sendsomething++;   $sendsomething++;
       }        }
Line 371  sub send_msg { Line 2294  sub send_msg {
        $newrecord{'resource'}=$feedurl;         $newrecord{'resource'}=$feedurl;
        $newrecord{'subnumber'}=$record{'subnumber'}+1;         $newrecord{'subnumber'}=$record{'subnumber'}+1;
        unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') {         unless (&Apache::lonnet::cstore(\%newrecord,'_feedback') eq 'ok') {
    $status.='<br>Not registered<br>';     $status.='<br />'.&mt('Not registered').'<br />';
        }         }
     }      }
                 
Line 379  sub send_msg { Line 2302  sub send_msg {
 }  }
   
 sub adddiscuss {  sub adddiscuss {
     my ($symb,$email,$anon,$attachmenturl)=@_;      my ($symb,$email,$anon,$attachmenturl,$subject)=@_;
     my $status='';      my $status='';
     if (&Apache::lonnet::allowed('pch',$ENV{'request.course.id'}.      my $realsymb;
       if ($symb=~/^bulletin___/) {
    my $filename=(&Apache::lonnet::decode_symb($symb))[2];
    $filename=~s|^adm/wrapper/||;
    $realsymb=&Apache::lonnet::symbread($filename);
       }
       if (&discussion_open(undef,$realsymb) &&
    &Apache::lonnet::allowed('pch',$ENV{'request.course.id'}.
         ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {          ($ENV{'request.course.sec'}?'/'.$ENV{'request.course.sec'}:''))) {
   
     my %contrib=('message'      => $email,      my %contrib=('message'      => $email,
Line 392  sub adddiscuss { Line 2322  sub adddiscuss {
                    $ENV{'environment.middlename'}.' '.                     $ENV{'environment.middlename'}.' '.
                                    $ENV{'environment.lastname'}.' '.                                     $ENV{'environment.lastname'}.' '.
                                    $ENV{'enrironment.generation'},                                     $ENV{'enrironment.generation'},
                  'attachmenturl'=> $attachmenturl);                   'attachmenturl'=> $attachmenturl,
                    'subject'      => $subject);
       if ($ENV{'form.replydisc'}) {
    $contrib{'replyto'}=(split(/\:\:\:/,$ENV{'form.replydisc'}))[1];
       }
     if ($anon) {      if ($anon) {
  $contrib{'anonymous'}='true';   $contrib{'anonymous'}='true';
     }      }
     if (($symb) && ($email)) {      if (($symb) && ($email)) {
        $status='Adding to class discussion'.($anon?' (anonymous)':'').': '.          if ($ENV{'form.editdisc'}) {
         &Apache::lonnet::store(\%contrib,$symb,$ENV{'request.course.id'},              my %newcontrib = ();
               $contrib{'ip'}=$ENV{'REMOTE_ADDR'};
               $contrib{'host'}=$Apache::lonnet::perlvar{'lonHostID'};
               $contrib{'timestamp'} = time;
               $contrib{'history'} = '';
               my $numoldver = 0;
               my ($oldsymb,$oldidx)=split(/\:\:\:/,$ENV{'form.editdisc'});
               $oldsymb=~s|(bulletin___\d+___)adm/wrapper/|$1|;
   # get timestamp for last post and history
               my %oldcontrib=&Apache::lonnet::restore($oldsymb,$ENV{'request.course.id'},
                        $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                        $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
               if (defined($oldcontrib{$oldidx.':replyto'})) {
                   $contrib{'replyto'} = $oldcontrib{$oldidx.':replyto'};
               }
               if (defined($oldcontrib{$oldidx.':history'})) {
                   if ($oldcontrib{$oldidx.':history'} =~ /:/) {
                       my @oldversions = split/:/,$oldcontrib{$oldidx.':history'};
                       $numoldver = @oldversions;
                   } else {
                       $numoldver = 1;
                   }
                   $contrib{'history'} = $oldcontrib{$oldidx.':history'}.':';
               }
               my $numnewver = $numoldver + 1;
               if (defined($oldcontrib{$oldidx.':subject'})) {
                   if ($oldcontrib{$oldidx.':subject'} =~ /^<version num="0">/) {
                       $contrib{'subject'} = '<version num="'.$numnewver.'">'.&HTML::Entities::encode($contrib{'subject'},'<>&"').'</version>';
                       $contrib{'subject'} = $oldcontrib{$oldidx.':subject'}.$contrib{'subject'};
                   } else {
                       $contrib{'subject'} = '<version num="0">'.&HTML::Entities::encode($oldcontrib{$oldidx.':subject'},'<>&"').'</version><version num="1">'.&HTML::Entities::encode($contrib{'subject'},'<>&"').'</version>';
                   }
               } 
               if (defined($oldcontrib{$oldidx.':message'})) {
                   if ($oldcontrib{$oldidx.':message'} =~ /^<version num="0">/) {
                       $contrib{'message'} = '<version num="'.$numnewver.'">'.&HTML::Entities::encode($contrib{'message'},'<>&"').'</version>';
                       $contrib{'message'} = $oldcontrib{$oldidx.':message'}.$contrib{'message'};
                   } else {
                       $contrib{'message'} = '<version num="0">'.&HTML::Entities::encode($oldcontrib{$oldidx.':message'},'<>&"').'</version><version num="1">'.&HTML::Entities::encode($contrib{'message'},'<>&"').'</version>';
                   }
               }
               $contrib{'history'} .= $oldcontrib{$oldidx.':timestamp'};
               foreach (keys %contrib) {
                   my $key = $oldidx.':'.&Apache::lonnet::escape($oldsymb).':'.$_;                                                                               
                   $newcontrib{$key} = $contrib{$_};
               }
               my $put_reply = &Apache::lonnet::putstore($ENV{'request.course.id'},
                     \%newcontrib,
                     $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                     $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
               $status='Editing class discussion'.($anon?' (anonymous)':'');
           } else {
              $status='Adding to class discussion'.($anon?' (anonymous)':'').': '.
              &Apache::lonnet::store(\%contrib,$symb,$ENV{'request.course.id'},
                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},                       $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
      $ENV{'course.'.$ENV{'request.course.id'}.'.num'});       $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
           }
         my %storenewentry=($symb => time);          my %storenewentry=($symb => time);
         $status.='<br>Updating discussion time: '.          $status.='<br />'.&mt('Updating discussion time').': '.
         &Apache::lonnet::put('discussiontimes',\%storenewentry,          &Apache::lonnet::put('discussiontimes',\%storenewentry,
                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},                       $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
      $ENV{'course.'.$ENV{'request.course.id'}.'.num'});       $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
Line 413  sub adddiscuss { Line 2401  sub adddiscuss {
        my %newrecord=();         my %newrecord=();
        $newrecord{'resource'}=$symb;         $newrecord{'resource'}=$symb;
        $newrecord{'subnumber'}=$record{'subnumber'}+1;         $newrecord{'subnumber'}=$record{'subnumber'}+1;
        $status.='<br>Registering: '.         $status.='<br />'.&mt('Registering').': '.
                &Apache::lonnet::cstore(\%newrecord,'_discussion');                 &Apache::lonnet::cstore(\%newrecord,'_discussion');
     }      }
     } else {      } else {
  $status.='Failed.';   $status.='Failed.';
     }      }
     return $status.'<br>';         return $status.'<br />';   
 }  }
   
 # ----------------------------------------------------------- Preview function  # ----------------------------------------------------------- Preview function
Line 428  sub show_preview { Line 2416  sub show_preview {
     my $r=shift;      my $r=shift;
     my $message=&clear_out_html($ENV{'form.comment'});      my $message=&clear_out_html($ENV{'form.comment'});
     $message=~s/\n/\<br \/\>/g;      $message=~s/\n/\<br \/\>/g;
       $message=&Apache::lonspeller::markeduptext($message);
     $message=&Apache::lontexconvert::msgtexconverted($message);      $message=&Apache::lontexconvert::msgtexconverted($message);
       my $subject=&clear_out_html($ENV{'form.subject'});
       $subject=~s/\n/\<br \/\>/g;
       $subject=&Apache::lontexconvert::msgtexconverted($subject);
     $r->print('<table border="2"><tr><td>'.      $r->print('<table border="2"><tr><td>'.
          '<b>Subject:</b> '.$subject.'<br /><br />'.
        $message.'</td></tr></table>');         $message.'</td></tr></table>');
 }  }
   
 sub generate_preview_button {  sub generate_preview_button {
       my $pre=&mt("Show Preview and Check Spelling");
     return(<<ENDPREVIEW);      return(<<ENDPREVIEW);
 <form name="preview" action="/adm/feedback?preview=1" method="post" target="preview">  <form name="preview" action="/adm/feedback?preview=1" method="post" target="preview">
   <input type="hidden" name="subject">
 <input type="hidden" name="comment" />  <input type="hidden" name="comment" />
 <input type="button" value="Show Preview"  <input type="button" value="$pre"
 onClick="this.form.comment.value=document.mailform.comment.value;this.form.submit();" />  onClick="if (typeof(document.mailform.onsubmit)=='function') {document.mailform.onsubmit();};this.form.comment.value=document.mailform.comment.value;this.form.subject.value=document.mailform.subject.value;this.form.submit();" />
 </form>  </form>
 ENDPREVIEW  ENDPREVIEW
 }  }
   
   sub modify_attachments {
       my ($r,$currnewattach,$currdelold,$symb,$idx,$attachmenturls)=@_;
       my $orig_subject = &Apache::lonnet::unescape($ENV{'form.subject'});
       my $subject=&clear_out_html($orig_subject);
       $subject=~s/\n/\<br \/\>/g;
       $subject=&Apache::lontexconvert::msgtexconverted($subject);
       my $timestamp=$ENV{'form.timestamp'};
       my $numoldver=$ENV{'form.numoldver'};
       my $bodytag=&Apache::loncommon::bodytag('Discussion Post Attachments',
                                             '','');
       my $msg = '';
       my %attachments = ();
       my %currattach = ();
       if ($idx) {
           &extract_attachments($attachmenturls,$idx,$numoldver,\$msg,\%attachments,\%currattach,$currdelold);
       }
       $r->print(<<END);
   <html>
   <head>
   <title>Managing Attachments</title>
   <script>
    function setAction () {
      document.modattachments.action = document.modattachments.origpage.value;
      document.modattachments.submit();
    }
   </script> 
   </head>
   $bodytag
   <form name="modattachments" method="post" enctype="multipart/form-data" action="/adm/feedback?attach=$symb">
    <table border="2">
     <tr>
      <td>
       <b>Subject:</b> $subject</b><br /><br />
   END
       if ($idx) {
           if ($attachmenturls) {
               my @currold = keys %currattach;
               if (@currold > 0) {
                   $r->print("The following attachments were part of the most recent saved version of this posting.<br />Check the checkboxes for any you wish to remove<br />\n");  
                   foreach my $id (@currold) {
                       my $attachurl = &HTML::Entities::decode($attachments{$id}{'filename'}); 
                       $attachurl =~ m#/([^/]+)$#;
                       $r->print('<input type="checkbox" name="deloldattach" value="'.$id.'" />&nbsp;'.$1.'<br />'."\n");
                   }
                   $r->print("<br />");
               }
           }
       }
       if (@{$currnewattach} > 0) {
           $r->print("The following attachments have been uploaded for inclusion with this posting.<br />Check the checkboxes for any you wish to remove<br />\n");
           foreach (@{$currnewattach}) {
               $_ =~ m#/([^/]+)$#;
               $r->print('<input type="checkbox" name="delnewattach" value="'.$_.'" />&nbsp;'.$1.'<br />'."\n");
           }
           $r->print("<br />"); 
       }
       $r->print(<<END);
      Add a new attachment to this post.&nbsp;<input type="file" name="addnewattach" /><input type="button" name="upload" value="Upload" onClick="this.form.submit()" />    
      </td>
     </tr>
    </table>
   <input type="hidden" name="subject" value="$ENV{'form.subject'}" />
   <input type="hidden" name="comment" value="$ENV{'form.comment'}" />
   <input type="hidden" name="timestamp" value="$ENV{'form.timestamp'}" />
   <input type="hidden" name="idx" value="$ENV{'form.idx'}" />
   <input type="hidden" name="numoldver" value="$ENV{'form.numoldver'}" />
   <input type="hidden" name="origpage" value="$ENV{'form.origpage'}" />
   <input type="hidden" name="anondiscuss" value="$ENV{'form.anondiscuss'}" />
   <input type="hidden" name="discuss" value="$ENV{'form.discuss'}" />
   END
       foreach (@{$currnewattach}) {
           $r->print('<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n");
       }
       foreach (@{$currdelold}) {
           $r->print('<input type="hidden" name="deloldattach" value="'.$_.'" />'."\n");
       }
       $r->print(<<END);
    <input type="button" name="rtntoedit" value="Store Changes" onClick="setAction()"/>
   </form>
   </body>
   </html>
   END
       return;
   }
   
   sub process_attachments {
       my ($currnewattach,$currdelold,$keepold) = @_;
       if (exists($ENV{'form.currnewattach'})) {
           if (ref($ENV{'form.currnewattach'}) eq 'ARRAY') {
               @{$currnewattach} = @{$ENV{'form.currnewattach'}};
           } else {
               $$currnewattach[0] = $ENV{'form.currnewattach'};
           }
       }
       if (exists($ENV{'form.deloldattach'})) {
           if (ref($ENV{'form.deloldattach'}) eq 'ARRAY') {
               @{$currdelold} = @{$ENV{'form.deloldattach'}};
           } else {
               $$currdelold[0] = $ENV{'form.deloldattach'};
           }
       }
       if (exists($ENV{'form.delnewattach'})) {
           my @currdelnew = ();
           my @currnew = ();
           if (ref($ENV{'form.delnewattach'}) eq 'ARRAY') {
               @currdelnew = @{$ENV{'form.delnewattach'}};
           } else {
               $currdelnew[0] = $ENV{'form.delnewattach'};
           }
           foreach my $newone (@{$currnewattach}) {
               my $delflag = 0;
               foreach (@currdelnew) {
                   if ($newone eq $_) {
                       $delflag = 1;
                       last;
                   }
               }
               unless ($delflag) {
                   push @currnew, $newone;
               }
           }
           @{$currnewattach} = @currnew;
       }
       if (exists($ENV{'form.keepold'})) {
           if (ref($ENV{'form.keepold'}) eq 'ARRAY') {
               @{$keepold} = @{$ENV{'form.keepold'}};
           } else {
               $$keepold[0] = $ENV{'form.keepold'};
           }
       }
   }
   
   sub generate_attachments_button {
       my ($idx,$attachnum,$ressymb,$now,$currnewattach,$deloldattach,$numoldver,$mode) = @_;
       my $origpage = $ENV{'REQUEST_URI'};
       my $att=$attachnum.' '.&mt("attachments");
       my $response = (<<END);
   <form name="attachment" action="/adm/feedback?attach=$ressymb" method="post">
   Click to add/remove attachments:&nbsp;<input type="button" value="$att"
   onClick="if (typeof(document.mailform.onsubmit)=='function') {document.mailform.onsubmit();};this.form.comment.value=escape(document.mailform.comment.value);this.form.subject.value=escape(document.mailform.subject.value);
   END
       unless ($mode eq 'board') {
           $response .= 'javascript:anonchk();';
       }
       $response .= (<<ENDATTACH);
   this.form.submit();" />
   <input type="hidden" name="origpage" value="$origpage" />
   <input type="hidden" name="idx" value="$idx" />
   <input type="hidden" name="timestamp" value="$now" />
   <input type="hidden" name="subject" />
   <input type="hidden" name="comment" />
   <input type="hidden" name="anondiscuss" value = "0";
   <input type="hidden" name="discuss" value = "0";
   <input type="hidden" name="numoldver" value="$numoldver" />
   ENDATTACH
       if (defined($deloldattach)) {
           if (@{$deloldattach} > 0) {
               foreach (@{$deloldattach}) {
                   $response .= '<input type="hidden" name="deloldattach" value="'.$_.'" />'."\n";
               }
           }
       }
       if (defined($currnewattach)) {
           if (@{$currnewattach} > 0) {
               foreach (@{$currnewattach}) {
                   $response .= '<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n";
               }
           }
       }
       $response .= '</form>';
       return $response;
   }
   
   sub extract_attachments {
       my ($attachmenturls,$idx,$numoldver,$message,$attachments,$currattach,$currdelold) = @_;
       %{$attachments}=();
       &get_post_attachments($attachments,$attachmenturls);
       foreach my $id (sort keys %{$attachments}) {
           if (exists($$attachments{$id}{$numoldver})) {
               if (defined($currdelold)) {
                   if (@{$currdelold} > 0) {
                       unless (grep/^$id$/,@{$currdelold}) {
                           $$currattach{$id} = $$attachments{$id}{$numoldver}; 
                       }
                   } else {
                       $$currattach{$id} = $$attachments{$id}{$numoldver};
                   }
               } else {
                   $$currattach{$id} = $$attachments{$id}{$numoldver};
               }
           }
       }
       my @attached = (sort { $a <=> $b } keys %{$currattach});
       if (@attached == 1) {
           my $id = $attached[0];
           my $attachurl;
           if ($attachmenturls =~ m/^<attachment id="0">/) {
               $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'});
           } else {
               $attachurl = $$attachments{$id}{'filename'};
           }
           $attachurl=~m|/([^/]+)$|;
           $$message.='<br /><a href="'.$attachurl.'"><tt>'.
           $1.'</tt></a><br />';
           &Apache::lonnet::allowuploaded('/adm/feedback',
                                  $attachurl);
       } elsif (@attached > 1) {
           $$message.='<ol>';
           foreach (@attached) {
               my $id = $_;
               my $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'});
               my ($fname)
                 =($attachurl=~m|/([^/]+)$|);
               $$message .= '<li><a href="'.$attachurl.
                 '"><tt>'.
                 $fname.'</tt></a></li>';
               &Apache::lonnet::allowuploaded('/adm/feedback',
                                $attachurl);
           }
           $$message .= '</ol>';
       }
   }
   
   sub construct_attachmenturl {
       my ($currnewattach,$keepold,$symb,$idx)=@_;
       my $oldattachmenturl;
       my $newattachmenturl;
       my $startnum = 0;
       my $currver = 0;
       if (($ENV{'form.editdisc'}) && ($idx)) {
           my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
                          $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                          $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
           $oldattachmenturl = $contrib{$idx.':attachmenturl'};
           if ($contrib{$idx.':history'}) {
               if ($contrib{$idx.':history'} =~ /:/) {
                   my @oldversions = split/:/,$contrib{$idx.':history'};
                   $currver = 1 + scalar(@oldversions);
               } else {
                   $currver = 2;
               }
           } else {
               $currver = 1;
           }
           if ($oldattachmenturl) {
               if ($oldattachmenturl =~ m/^<attachment id="0">/) {
                   my %attachments = ();
                   my $prevver = $currver-1;
                   &get_post_attachments(\%attachments,$oldattachmenturl);
                   my $numattach = scalar(keys %attachments);
                   $startnum += $numattach;
                   foreach my $num (sort {$a <=> $b} keys %attachments) {
                       $newattachmenturl .= '<attachment id="'.$num.'"><filename>'.$attachments{$num}{'filename'}.'</filename>';
                       foreach $_ (sort {$a <=> $b} keys %{$attachments{$num}}) {
                           unless ($_ eq 'filename') {
                               $newattachmenturl .= '<post id="'.$_.'">'.$attachments{$num}{$_}.'</post>';
                           }
                       }
                       if (grep/^$num$/,@{$keepold}) {
                           $newattachmenturl .= '<post id="'.$currver.'">'.$attachments{$num}{$prevver}.'</post>';
                       }
                       $newattachmenturl .= '</attachment>';
                   }
               } else {
                   $newattachmenturl = '<attachment id="0"><filename>'.&HTML::Entities::encode($oldattachmenturl).'</filename><post id="0">n</post>';
                   unless (grep/^0$/,@{$keepold}) {
                       $newattachmenturl .= '<post id="1">n</post>';
                   }
                   $newattachmenturl .= '</attachment>';
                   $startnum ++;
               }
           }
       }
       for (my $i=0; $i<@{$currnewattach}; $i++) {
           my $attachnum = $startnum + $i;
           $newattachmenturl .= '<attachment id="'.$attachnum.'"><filename>'.&HTML::Entities::encode($$currnewattach[$i]).'</filename><post id="'.$currver.'">n</post></attachment>';
       }
       return $newattachmenturl; 
   }
   
   sub has_discussion {
       my $resourcesref = shift;
       my $navmap = Apache::lonnavmaps::navmap->new();
       my @allres=$navmap->retrieveResources();
       foreach my $resource (@allres) {
           if ($resource->hasDiscussion()) {
               my $ressymb;
               if ($resource->symb() =~ m-(___adm/\w+/\w+)/(\d+)/bulletinboard$-) {
                   $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard';
               } else {
                   $ressymb = $resource->symb();
               }
               push @{$resourcesref}, $ressymb;
           }
       }
       return;
   } 
     
 sub handler {  sub handler {
   my $r = shift;    my $r = shift;
   if ($r->header_only) {    if ($r->header_only) {
      $r->content_type('text/html');       &Apache::loncommon::content_type($r,'text/html');
      $r->send_http_header;       $r->send_http_header;
      return OK;       return OK;
   }    }
   
 # --------------------------- Get query string for limited number of parameters  # --------------------------- Get query string for limited number of parameters
   
    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},    &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                              ['hide','unhide','deldisc','postdata','preview']);           ['hide','unhide','deldisc','postdata','preview','replydisc','editdisc','threadedon','threadedoff','onlyunread','allposts','onlyunmark','previous','markread','markonread','markondisp','toggoff','toggon','modifydisp','changes','navtime','navmaps','navurl','sortfilter','sortposts','applysort','rolefilter','statusfilter','sectionpick','posterlist','userpick','attach','origpage','currnewattach','deloldattach','keepold','allversions','export']);
     if ($ENV{'form.discsymb'}) {
   if (($ENV{'form.hide'}) || ($ENV{'form.unhide'})) {        my $symb = $ENV{'form.discsymb'};
         my $readkey = $symb.'_read';
         my %readinghash = ();
         my $chgcount = 0;
         %readinghash = &Apache::lonnet::get('nohist_'.$ENV{'request.course.id'}.'_discuss',[$readkey],$ENV{'user.domain'},$ENV{'user.name'});
         foreach my $key (keys %ENV) {
             if ($key =~ m/^form\.postunread_(\d+)/) {
                 if ($readinghash{$readkey} =~ /\.$1\./) {
                     $readinghash{$readkey} =~ s/\.$1\.//;
                     $chgcount ++;
                 }
             } elsif ($key =~ m/^form\.postread_(\d+)/) {
                 unless ($readinghash{$readkey} =~ /\.$1\./) {
                     $readinghash{$readkey} .= '.'.$1.'.';
                     $chgcount ++;
                 }
             }
         }
         if ($chgcount > 0) {
             &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%readinghash,$ENV{'user.domain'},$ENV{'user.name'});
         }
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
         my $previous=$ENV{'form.previous'};
         my $feedurl = &Apache::lonnet::clutter($url);
         &redirect_back($r,$feedurl,&mt('Marked postings read/unread').'<br />','0','0','',$previous,'','','',);
         return OK;
     }
     if ($ENV{'form.allversions'}) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my $bodytag=&Apache::loncommon::bodytag('Discussion Post Versions',
                                             '','');
         $r->print (<<END);
   <html>
   <head>
   <title>Post Versions</title>
   <meta http-equiv="pragma" content="no-cache" />
   </head>
   $bodytag
   END
         my $crs='/'.$ENV{'request.course.id'};
         if ($ENV{'request.course.sec'}) {
             $crs.='_'.$ENV{'request.course.sec'};
         }
         $crs=~s/\_/\//g;
         my $seeid=&Apache::lonnet::allowed('rin',$crs);
         my ($symb,$idx)=split(/\:\:\:/,$ENV{'form.allversions'});
         my $ressymb=$symb;
         unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
             $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
         }
         if ($idx > 0) {
             my %messages = ();
             my %subjects = ();
             my %attachmsgs = ();
             my %allattachments = ();
             my %imsfiles = ();
             my ($screenname,$plainname);
             my %contrib=&Apache::lonnet::restore($ressymb,$ENV{'request.course.id'},
                  $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                  $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
             my $discussion = &get_post_contents(\%contrib,$idx,$seeid,'allversions',\%messages,\%subjects,\%allattachments,\%attachmsgs,\%imsfiles,\$screenname,\$plainname);
             $r->print($discussion);
         }
         return OK;
     }
     if ($ENV{'form.posterlist'}) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my $symb=$ENV{'form.posterlist'};
         my $sortposts = $ENV{'form.sortposts'};
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
         my $previous=$ENV{'form.previous'};
         my $feedurl = &Apache::lonnet::clutter($url);
    # backward compatibility (bulletin boards used to be 'wrapped')
         if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
             $feedurl=~s|^/adm/wrapper||;
         }
         &print_showposters($r,$symb,$previous,$feedurl,$sortposts);
         return OK;
     }
     if ($ENV{'form.userpick'}) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my $symb=$ENV{'form.userpick'};
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
         my $previous=$ENV{'form.previous'};
   # backward compatibility (bulletin boards used to be 'wrapped')
         my $ressymb=$symb;
         unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
             $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
         }
         my $sort=$ENV{'form.sortposts'};
         my @posters = ();
         if (ref($ENV{'form.stuinfo'}) eq 'ARRAY') {
             @posters = $ENV{'form.stuinfo'};
         } else {
             $posters[0] = $ENV{'form.stuinfo'};
         }
         my $numpicks = @posters;
         if (defined($ENV{'form.userpick'})) {
             my %discinfo = ();
             $discinfo{$ressymb.'_userpick'} = join('&',@posters);
             &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
         }
         my $feedurl = &Apache::lonnet::clutter($url);
    # backward compatibility (bulletin boards used to be 'wrapped')
         if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
             $feedurl=~s|^/adm/wrapper||;
         }
         &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0','',$previous,$sort,'','','',$numpicks);
         return OK;
     }
     if ($ENV{'form.applysort'}) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my $symb=$ENV{'form.applysort'};
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
         my $previous=$ENV{'form.previous'};
         my $sort = $ENV{'form.sortposts'};
         my $rolefilter = $ENV{'form.rolefilter'};
         my $statusfilter = $ENV{'form.statusfilter'};
         my $secpick = $ENV{'form.sectionpick'};
         my $feedurl = &Apache::lonnet::clutter($url);
    # backward compatibility (bulletin boards used to be 'wrapped')
         if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
             $feedurl=~s|^/adm/wrapper||;
         }
         &redirect_back($r,$feedurl,&mt('Changed sort/filter').'<br />','0','0','',$previous,$sort,$rolefilter,$statusfilter,$secpick);
         return OK;
     } elsif ($ENV{'form.sortfilter'}) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my $symb=$ENV{'form.sortfilter'};
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
         my $previous=$ENV{'form.previous'};
         my $feedurl = &Apache::lonnet::clutter($url);
    # backward compatibility (bulletin boards used to be 'wrapped')
         if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
             $feedurl=~s|^/adm/wrapper||;
         }
         &print_sortfilter_options($r,$symb,$previous,$feedurl);
         return OK;
     } elsif ($ENV{'form.navtime'}) {
         my %discinfo = ();
         my @resources = ();
         if (defined($ENV{'form.navmaps'})) {
             if ($ENV{'form.navmaps'} =~ /:/) {
                 @resources = split/:/,$ENV{'form.navmaps'};
             } else {
                 @resources = ("$ENV{'form.navmaps'}");
             }
         } else {
             &has_discussion(\@resources);
         }
         my $numitems = @resources;
         my $feedurl = '/adm/navmaps';
         if ($ENV{'form.navurl'}) {
             $feedurl .= '?'.$ENV{'form.navurl'};
         }
         my %lt = &Apache::lonlocal::texthash(
             'mnpa' => 'Marked "New" posts as read in a total of',
             'robb' => 'resources/bulletin boards.',
             'twnp' => 'There are currently no resources or bulletin boards with unread discussion postings.'
         );       
         foreach (@resources) {
   # backward compatibility (bulletin boards used to be 'wrapped')
             my $ressymb=$_;
             if ($ressymb =~ m/bulletin___\d+___/) {
                 unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
                     $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper/|;
                 }
             }
             my $lastkey = $ressymb.'_lastread';
             $discinfo{$lastkey} = $ENV{'form.navtime'};
         }
         my $textline = "<b>$lt{'mnpa'} $numitems $lt{'robb'}</b>";
         if ($numitems > 0) {
             &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
         } else {
             $textline = "<b>$lt{'twnp'}</b>";
         }
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         $r->print (<<ENDREDIR);
   <html>
   <head>
   <title>New posts marked as read</title>
   <meta http-equiv="pragma" content="no-cache" />
   <meta HTTP-EQUIV="Refresh" CONTENT="2; url=$feedurl" />
   </head>
   <body bgcolor="#FFFFFF" onLoad='if (window.name!="loncapaclient") { this.document.reldt.submit(); self.close(); }'>
   <img align="right" src="/adm/lonIcons/lonlogos.gif" />
   $textline
   <form name="reldt" action="$feedurl" target="loncapaclient">
   </form>
   <br /><a href="$feedurl">Continue</a>
   </body>
   </html>
   ENDREDIR
         return OK;
     } elsif ($ENV{'form.modifydisp'}) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my $symb=$ENV{'form.modifydisp'};
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
         my $previous=$ENV{'form.previous'};
         my ($dispchgA,$dispchgB,$markchg,$toggchg) = split/_/,$ENV{'form.changes'};
         my $feedurl = &Apache::lonnet::clutter($url);
    # backward compatibility (bulletin boards used to be 'wrapped')  
         if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
             $feedurl=~s|^/adm/wrapper||;
         }
         &print_display_options($r,$symb,$previous,$dispchgA,$dispchgB,$markchg,$toggchg,$feedurl);
         return OK;
     } elsif (($ENV{'form.markondisp'}) || ($ENV{'form.markonread'}) || ($ENV{'form.allposts'}) || ($ENV{'form.onlyunread'}) || $ENV{'form.onlyunmark'} || $ENV{'form.toggoff'} || $ENV{'form.toggon'} ) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my $previous=$ENV{'form.previous'};
         my ($map,$ind,$url);
         if ( ($ENV{'form.toggoff'}) || ($ENV{'form.toggon'}) ) {
   # ------------------------------ Modify setting for read/unread toggle for each post 
             my $symb=$ENV{'form.toggoff'}?$ENV{'form.toggoff'}:$ENV{'form.toggon'};
             my $ressymb = $symb;
             ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
             unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
                 $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
             }
             my %discinfo = ();
             my $toggkey = $ressymb.'_readtoggle';
             if ($ENV{'form.toggon'}) {
                 $discinfo{$toggkey} = 1;
             } elsif ($ENV{'form.toggoff'}) {
                 $discinfo{$toggkey} = 0;
             }
             &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
         }
         if (($ENV{'form.markondisp'}) || ($ENV{'form.markonread'})) {
   # ---------------------- Modify setting for identification of 'NEW' posts in this discussion
             my $symb=$ENV{'form.markondisp'}?$ENV{'form.markondisp'}:$ENV{'form.markonread'};
             my $ressymb = $symb;
             ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
             unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
                 $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
             }
             my %discinfo = ();
             my $lastkey = $ressymb.'_lastread';
             my $ondispkey = $ressymb.'_markondisp';
             if ($ENV{'form.markondisp'}) {
                 $discinfo{$lastkey} = time;
                 $discinfo{$ondispkey} = 1;
             } elsif ($ENV{'form.markonread'}) {
                 if ( $previous > 0 ) {
                     $discinfo{$lastkey} = $previous;
                 }
                 $discinfo{$ondispkey} = 0;
             }
             &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
         }
         if (($ENV{'form.allposts'}) || ($ENV{'form.onlyunread'}) || ($ENV{'form.onlyunmark'}) ) {
   # ----------------------------------------------------------------- Modify display setting for this discussion 
             my $symb;
             if ($ENV{'form.allposts'}) {
                 $symb = $ENV{'form.allposts'};
             } elsif ($ENV{'form.onlyunread'}) {
                 $symb = $ENV{'form.onlyunread'};
             } else {
                 $symb = $ENV{'form.onlyunmark'};
             }
             my $ressymb = $symb;
             ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
             unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
                 $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
             }
             my %discinfo = ();
             if ($ENV{'form.allposts'}) {
                 $discinfo{$ressymb.'_showonlyunread'} = 0;
                 $discinfo{$ressymb.'_showonlyunmark'} = 0;
             } elsif ($ENV{'form.onlyunread'}) {
                 $discinfo{$ressymb.'_showonlyunread'} = 1;
             } else {
                 $discinfo{$ressymb.'_showonlyunmark'} = 1;
             }
             &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
         }
         if (($ENV{'form.markonread'}) || ($ENV{'form.allposts'}) || ($ENV{'form.onlyunread'}) || ($ENV{'form.onlyunmark'}) ||($ENV{'form.toggoff'}) || ($ENV{'form.toggon'}) ) {
             &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'<br />','0','0','',$previous);
         } else {
             &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed display status').'<br />','0','0');
         }
         return OK;
     } elsif ($ENV{'form.markread'}) {
   # ----------------------------------------------------------------- Mark new posts not NEW 
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my $symb=$ENV{'form.markread'};
         my $ressymb = $symb;
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
         unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
             $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper|;
         }
         my %discinfo = ();
         my $lastkey = $ressymb.'_lastread';
         $discinfo{$lastkey} = time;
         &Apache::lonnet::put('nohist_'.$ENV{'request.course.id'}.'_discuss',\%discinfo,$ENV{'user.domain'},$ENV{'user.name'});
         &redirect_back($r,&Apache::lonnet::clutter($url),&mt('Changed reading status').'<br />','0','0');
         return OK;
     } elsif (($ENV{'form.hide'}) || ($ENV{'form.unhide'})) {
 # ----------------------------------------------------------------- Hide/unhide  # ----------------------------------------------------------------- Hide/unhide
     $r->content_type('text/html');      &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;      $r->send_http_header;
   
     my $entry=$ENV{'form.hide'}?$ENV{'form.hide'}:$ENV{'form.unhide'};      my $entry=$ENV{'form.hide'}?$ENV{'form.hide'}:$ENV{'form.unhide'};
   
     my ($symb,$idx)=split(/\:\:\:/,$entry);      my ($symb,$idx)=split(/\:\:\:/,$entry);
     my ($map,$ind,$url)=split(/\_\_\_/,$symb);      my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
   
     my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},      my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},                       $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
Line 471  sub handler { Line 3074  sub handler {
   
                   
     my $currenthidden=$contrib{'hidden'};      my $currenthidden=$contrib{'hidden'};
       my $currentstudenthidden=$contrib{'studenthidden'};
   
       my $crs='/'.$ENV{'request.course.id'};
       if ($ENV{'request.course.sec'}) {
           $crs.='_'.$ENV{'request.course.sec'};
       }
       $crs=~s/\_/\//g;
       my $seeid=&Apache::lonnet::allowed('rin',$crs);
           
     if ($ENV{'form.hide'}) {      if ($ENV{'form.hide'}) {
  $currenthidden.='.'.$idx.'.';   $currenthidden.='.'.$idx.'.';
           unless ($seeid) {
               $currentstudenthidden.='.'.$idx.'.';
           }
     } else {      } else {
         $currenthidden=~s/\.$idx\.//g;          $currenthidden=~s/\.$idx\.//g;
     }      }
     my %newhash=('hidden' => $currenthidden);      my %newhash=('hidden' => $currenthidden);
       if ( ($ENV{'form.hide'}) && (!$seeid) ) {
           $newhash{'studenthidden'} = $currentstudenthidden;
       }
   
     &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'},      &Apache::lonnet::store(\%newhash,$symb,$ENV{'request.course.id'},
                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},                       $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
      $ENV{'course.'.$ENV{'request.course.id'}.'.num'});       $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   
     &redirect_back($r,&Apache::lonnet::clutter($url),      &redirect_back($r,&Apache::lonnet::clutter($url),
        'Changed discussion status<p>','0','0');         &mt('Changed discussion status').'<br />','0','0','',$ENV{'form.previous'});
     } elsif (($ENV{'form.threadedon'}) || ($ENV{'form.threadedoff'})) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         if ($ENV{'form.threadedon'}) {
     &Apache::lonnet::put('environment',{'threadeddiscussion' => 'on'});
     &Apache::lonnet::appenv('environment.threadeddiscussion' => 'on');
         } else {
      &Apache::lonnet::del('environment',['threadeddiscussion']);
     &Apache::lonnet::delenv('environment\.threadeddiscussion');
         }
         my $symb=$ENV{'form.threadedon'}?$ENV{'form.threadedon'}:$ENV{'form.threadedoff'};
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
         &redirect_back($r,&Apache::lonnet::clutter($url),
        &mt('Changed discussion view mode').'<br />','0','0','',$ENV{'form.previous'});
   } elsif ($ENV{'form.deldisc'}) {    } elsif ($ENV{'form.deldisc'}) {
 # --------------------------------------------------------------- Hide for good  # --------------------------------------------------------------- Hide for good
     $r->content_type('text/html');      &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;      $r->send_http_header;
   
     my $entry=$ENV{'form.deldisc'};      my $entry=$ENV{'form.deldisc'};
   
     my ($symb,$idx)=split(/\:\:\:/,$entry);      my ($symb,$idx)=split(/\:\:\:/,$entry);
     my ($map,$ind,$url)=split(/\_\_\_/,$symb);      my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
   
     my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},      my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
                      $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},                       $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
Line 511  sub handler { Line 3142  sub handler {
      $ENV{'course.'.$ENV{'request.course.id'}.'.num'});       $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
   
     &redirect_back($r,&Apache::lonnet::clutter($url),      &redirect_back($r,&Apache::lonnet::clutter($url),
        'Changed discussion status<p>','0','0');         &mt('Changed discussion status').'<br />','0','0','',$ENV{'form.previous'});
   } elsif ($ENV{'form.preview'}) {    } elsif ($ENV{'form.preview'}) {
 # -------------------------------------------------------- User wants a preview  # -------------------------------------------------------- User wants a preview
         $r->content_type('text/html');
         $r->send_http_header;
       &show_preview($r);        &show_preview($r);
     } elsif ($ENV{'form.attach'}) {
   # -------------------------------------------------------- Work on attachments
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['subject','comment','addnewattach','delnewattach','timestamp','numoldver','idx','anondiscuss','discuss']);
         my @currnewattach = ();
         my @currdelold = ();
         my @keepold = ();
         &process_attachments(\@currnewattach,\@currdelold,\@keepold);
         if (exists($ENV{'form.addnewattach.filename'})) {
             unless (length($ENV{'form.addnewattach'})>131072) {
                 my $subdir = 'feedback/'.$ENV{'form.timestamp'};
                 my $newattachment=&Apache::lonnet::userfileupload('addnewattach',undef,$subdir);
                 push @currnewattach, $newattachment;
             }
         }
         my $attachmenturls = '';
         my $idx = $ENV{'form.idx'};
         my $symb = $ENV{'form.attach'};
         if ($idx) {
             my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
                            $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
                            $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
             $attachmenturls = $contrib{$idx.':attachmenturl'};
         }
         &modify_attachments($r,\@currnewattach,\@currdelold,$symb,$idx,$attachmenturls);
     } elsif ($ENV{'form.chgreads'}) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($ENV{'form.chgreads'});
         &redirect_back($r,&Apache::lonnet::clutter($url),
          &mt('Changed read status').'<br />','0','0');
     } elsif ($ENV{'form.export'}) {
         &Apache::loncommon::content_type($r,'text/html');
         $r->send_http_header;
         my $symb=$ENV{'form.export'};
         my $mode;
         my $status='OPEN';
         my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
         my $previous=$ENV{'form.previous'};
         my $feedurl = &Apache::lonnet::clutter($url);
    # backward compatibility (bulletin boards used to be 'wrapped')
         if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
             $mode = 'board';
             $feedurl=~s|^/adm/wrapper||;
         }
         if ($feedurl =~ /\.(problem|exam|quiz|assess|survey|form|library)$/) {
             $mode='problem';
             $status=$Apache::inputtags::status[-1];
         }
         my $discussion = &list_discussion($mode,$status,$symb); 
         my $bodytag=&Apache::loncommon::bodytag('Resource Feedback and Discussion');
         $r->print($bodytag.$discussion);                                     
         return OK;
   } else {    } else {
 # ------------------------------------------------------------- Normal feedback  # ------------------------------------------------------------- Normal feedback
   my $feedurl=$ENV{'form.postdata'};    my $feedurl=$ENV{'form.postdata'};
   $feedurl=~s/^http\:\/\///;    $feedurl=~s/^http\:\/\///;
   $feedurl=~s/^$ENV{'SERVER_NAME'}//;    $feedurl=~s/^$ENV{'SERVER_NAME'}//;
   $feedurl=~s/^$ENV{'HTTP_HOST'}//;    $feedurl=~s/^$ENV{'HTTP_HOST'}//;
     $feedurl=~s/\?.+$//;
   
   my $symb=&Apache::lonnet::symbread($feedurl);    my $symb;
     if ($ENV{'form.replydisc'}) {
         $symb=(split(/\:\:\:/,$ENV{'form.replydisc'}))[0];
         my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
         $feedurl=&Apache::lonnet::clutter($url);
     } elsif ($ENV{'form.editdisc'}) {
         $symb=(split(/\:\:\:/,$ENV{'form.editdisc'}))[0];
         my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
         $feedurl=&Apache::lonnet::clutter($url);
     } elsif ($ENV{'form.origpage'}) {
         $symb=""; 
     } else {
         $symb=&Apache::lonnet::symbread($feedurl);
     }
   unless ($symb) {    unless ($symb) {
       $symb=$ENV{'form.symb'};        $symb=$ENV{'form.symb'};
       if ($symb) {        if ($symb) {
   my ($map,$id,$url)=split(/\_\_\_/,$symb);    my ($map,$id,$url)=&Apache::lonnet::decode_symb($symb);
           $feedurl=&Apache::lonnet::clutter($url);            $feedurl=&Apache::lonnet::clutter($url);
       }        }
   }    }
Line 534  sub handler { Line 3235  sub handler {
   if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form)$/) {    if ($feedurl=~/\.(problem|exam|quiz|assess|survey|form)$/) {
       unless ($symb) { $goahead=0; }        unless ($symb) { $goahead=0; }
   }    }
     # backward compatibility (bulletin boards used to be 'wrapped')
     if ($feedurl=~m|^/adm/wrapper/adm/.*/bulletinboard$|) {
         $feedurl=~s|^/adm/wrapper||;
     }
   if ($goahead) {    if ($goahead) {
 # Go ahead with feedback, no ambiguous reference  # Go ahead with feedback, no ambiguous reference
     $r->content_type('text/html');      &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;      $r->send_http_header;
       
     if (      if (
Line 553  sub handler { Line 3257  sub handler {
     unless ($ENV{'form.sendit'}) {      unless ($ENV{'form.sendit'}) {
       my $options=&screen_header($feedurl);        my $options=&screen_header($feedurl);
       if ($options) {        if ($options) {
  &mail_screen($r,$feedurl,$options);          &mail_screen($r,$feedurl,$options);
       } else {        } else {
  &fail_redirect($r,$feedurl);   &fail_redirect($r,$feedurl);
       }        }
Line 575  sub handler { Line 3279  sub handler {
       &Apache::lonnet::delenv('allowed.vgr');        &Apache::lonnet::delenv('allowed.vgr');
 # Get attachments, if any, and not too large  # Get attachments, if any, and not too large
       my $attachmenturl='';        my $attachmenturl='';
       if ($ENV{'form.attachment.filename'}) {        if (($ENV{'form.origpage'}) || ($ENV{'form.editdisc'}) || ($ENV{'form.replydisc'})) {
             my ($symb,$idx);
             if ($ENV{'form.replydisc'}) {
                 ($symb,$idx)=split(/\:\:\:/,$ENV{'form.replydisc'});
             } elsif ($ENV{'form.editdisc'}) {
                 ($symb,$idx)=split(/\:\:\:/,$ENV{'form.editdisc'});
             } elsif ($ENV{'form.origpage'}) {
                 $symb = $ENV{'form.symb'};
             }
             my @currnewattach = ();
             my @deloldattach = ();
             my @keepold = ();
             &process_attachments(\@currnewattach,\@deloldattach,\@keepold);
             $symb=~s|(bulletin___\d+___)adm/wrapper/|$1|;
             $attachmenturl=&construct_attachmenturl(\@currnewattach,\@keepold,$symb,$idx);
         } elsif ($ENV{'form.attachment.filename'}) {
   unless (length($ENV{'form.attachment'})>131072) {    unless (length($ENV{'form.attachment'})>131072) {
       $attachmenturl=&Apache::lonnet::userfileupload('attachment');        $attachmenturl=&Apache::lonnet::userfileupload('attachment',undef,'feedback');
   }    }
       }        }
 # Filter HTML out of message (could be nasty)  # Filter HTML out of message (could be nasty)
Line 598  sub handler { Line 3317  sub handler {
   
       my $numpost=0;        my $numpost=0;
       if ($ENV{'form.discuss'}) {        if ($ENV{'form.discuss'}) {
   $typestyle.=&adddiscuss($symb,$message,0,$attachmenturl);            my $subject = &clear_out_html($ENV{'form.subject'});
     $typestyle.=&adddiscuss($symb,$message,0,$attachmenturl,$subject);
   $numpost++;    $numpost++;
       }        }
   
       if ($ENV{'form.anondiscuss'}) {        if ($ENV{'form.anondiscuss'}) {
   $typestyle.=&adddiscuss($symb,$message,1,$attachmenturl);            my $subject = &clear_out_html($ENV{'form.subject'});
     $typestyle.=&adddiscuss($symb,$message,1,$attachmenturl,$subject);
   $numpost++;    $numpost++;
       }        }
   
   
 # Receipt screen and redirect back to where came from  # Receipt screen and redirect back to where came from
       &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status);        &redirect_back($r,$feedurl,$typestyle,$numsent,$numpost,$status,$ENV{'form.previous'});
   
     }      }
    } else {     } else {
Line 618  sub handler { Line 3339  sub handler {
    }     }
   } else {    } else {
 # Ambiguous Problem Resource  # Ambiguous Problem Resource
     $r->internal_redirect('/adm/ambiguous');        if ( &Apache::lonnet::mod_perl_version() == 2 ) {
     &Apache::lonnet::cleanenv();
         }
         $r->internal_redirect('/adm/ambiguous');
   }    }
 }  }
   return OK;    return OK;

Removed from v.1.50  
changed lines
  Added in v.1.128


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.