Diff for /loncom/interface/lonfeedback.pm between versions 1.220 and 1.221

version 1.220, 2006/11/29 03:23:02 version 1.221, 2006/11/29 03:55:15
Line 133  sub list_discussion { Line 133  sub list_discussion {
     my $previous = 0;      my $previous = 0;
     my $visit = 0;      my $visit = 0;
     my $newpostsflag = 0;      my $newpostsflag = 0;
     my @posters = split/\&/,$dischash{$userpickkey};      my @posters = split(/\&/,$dischash{$userpickkey});
   
 # Retain identification of "NEW" posts identified in last display, if continuing 'previous' browsing of posts.  # 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','grouppick','totposters']);      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['previous','sortposts','rolefilter','statusfilter','sectionpick','grouppick','totposters']);
Line 162  sub list_discussion { Line 162  sub list_discussion {
     my ($classgroups,$studentgroups);      my ($classgroups,$studentgroups);
     if ($env{'form.rolefilter'}) {      if ($env{'form.rolefilter'}) {
         %roleshash = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);          %roleshash = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
         foreach (keys %roleshash) {          foreach my $rolekey (keys(%roleshash)) {
             my ($role,$uname,$udom,$sec) = split/:/,$_;              my ($role,$uname,$udom,$sec) = split(/:/,$rolekey);
             if ($role =~ /^cr/) {              if ($role =~ /^cr/) {
                 $role = 'cr';                  $role = 'cr';
             }              }
             my ($end,$start) = split/:/,$roleshash{$_};              my ($end,$start) = split(/:/,$roleshash{$rolekey});
             my $now = time;              my $now = time;
             my $status = 'Active';              my $status = 'Active';
             if (($now < $start) || ($end > 0 && $now > $end)) {              if (($now < $start) || ($end > 0 && $now > $end)) {
                 $status = 'Expired';                  $status = 'Expired';
             }              }
             if ($uname && $udom) {               if ($uname && $udom) { 
                 push @{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status;                  push(@{$roleinfo{$uname.':'.$udom}}, $role.':'.$sec.':'.$status);
             }              }
         }          }
         my ($classlist,$keylist) =          my ($classlist,$keylist) =
Line 184  sub list_discussion { Line 184  sub list_discussion {
         while (my ($student,$data) = each %$classlist) {          while (my ($student,$data) = each %$classlist) {
             my ($section,$status) = ($data->[$sec_index],              my ($section,$status) = ($data->[$sec_index],
                                  $data->[$status_index]);                                   $data->[$status_index]);
             push @{$roleinfo{$student}}, 'st:'.$section.':'.$status;              push(@{$roleinfo{$student}}, 'st:'.$section.':'.$status);
         }          }
  ($classgroups,$studentgroups) =    ($classgroups,$studentgroups) = 
     &Apache::loncoursedata::get_group_memberships($classlist,$keylist,      &Apache::loncoursedata::get_group_memberships($classlist,$keylist,
Line 493  imscp_v1p1.xsd http://www.imsglobal.org/ Line 493  imscp_v1p1.xsd http://www.imsglobal.org/
 # Choose sort mechanism  # Choose sort mechanism
         my @showposts = ();          my @showposts = ();
         if ($sortposts eq 'descdate') {          if ($sortposts eq 'descdate') {
             @showposts = (sort { $b <=> $a } keys %alldiscussion);              @showposts = (sort { $b <=> $a } keys(%alldiscussion));
         } elsif ($sortposts eq 'thread') {          } elsif ($sortposts eq 'thread') {
             @showposts = (sort { $a <=> $b } keys %alldiscussion);              @showposts = (sort { $a <=> $b } keys(%alldiscussion));
         } elsif ($sortposts eq 'subject') {          } elsif ($sortposts eq 'subject') {
             foreach (sort keys %subjectsort) {              foreach my $key (sort(keys(%subjectsort))) {
                 push @showposts, @{$subjectsort{$_}};                  push(@showposts, @{$subjectsort{$key}});
             }              }
         } elsif ($sortposts eq 'username') {          } elsif ($sortposts eq 'username') {
             foreach my $domain (sort keys %usernamesort) {              foreach my $domain (sort(keys(%usernamesort))) {
                 foreach (sort keys %{$usernamesort{$domain}}) {                  foreach my $key (sort(keys(%{$usernamesort{$domain}}))) {
                     push @showposts, @{$usernamesort{$domain}{$_}};                      push(@showposts, @{$usernamesort{$domain}{$key}});
                 }                  }
             }              }
         } elsif ($sortposts eq 'lastfirst') {          } elsif ($sortposts eq 'lastfirst') {
             foreach my $last (sort keys %namesort) {              foreach my $last (sort(keys(%namesort))) {
                  foreach (sort keys %{$namesort{$last}}) {                   foreach my $key (sort(keys(%{$namesort{$last}}))) {
                      push @showposts, @{$namesort{$last}{$_}};                       push(@showposts, @{$namesort{$last}{$key}});
                  }                   }
             }              }
         } else {          } else {
             @showposts =  (sort { $a <=> $b } keys %alldiscussion);              @showposts =  (sort { $a <=> $b } keys(%alldiscussion));
         }          }
         my $currdepth = 0;          my $currdepth = 0;
         my $firstidx = $alldiscussion{$showposts[0]};          my $firstidx = $alldiscussion{$showposts[0]};
         foreach (@showposts) {          foreach my $post (@showposts) {
             unless (($sortposts eq 'thread') || (($sortposts eq '') && ($env{'environment.threadeddiscussion'})) || ($outputtarget eq 'export')) {              unless (($sortposts eq 'thread') || (($sortposts eq '') && ($env{'environment.threadeddiscussion'})) || ($outputtarget eq 'export')) {
                 $alldiscussion{$_} = $_;                  $alldiscussion{$post} = $post;
             }              }
             unless ( ($notshown{$alldiscussion{$_}} eq '1') || ($shown{$alldiscussion{$_}} == 0) ) {              unless ( ($notshown{$alldiscussion{$post}} eq '1') || ($shown{$alldiscussion{$post}} == 0) ) {
                 if ($outputtarget ne 'tex' && $outputtarget ne 'export') {                  if ($outputtarget ne 'tex' && $outputtarget ne 'export') {
     $discussion.="\n<tr>";      $discussion.="\n<tr>";
  }   }
         my $thisdepth=$depth[$alldiscussion{$_}];          my $thisdepth=$depth[$alldiscussion{$post}];
                 if ($outputtarget ne 'tex' && $outputtarget ne 'export') {                  if ($outputtarget ne 'tex' && $outputtarget ne 'export') {
     for (1..$thisdepth) {      for (1..$thisdepth) {
  $discussion.='<td>&nbsp;&nbsp;&nbsp;</td>';   $discussion.='<td>&nbsp;&nbsp;&nbsp;</td>';
Line 534  imscp_v1p1.xsd http://www.imsglobal.org/ Line 534  imscp_v1p1.xsd http://www.imsglobal.org/
         my $colspan=$maxdepth-$thisdepth+1;          my $colspan=$maxdepth-$thisdepth+1;
                 if ($outputtarget eq 'tex') {                  if ($outputtarget eq 'tex') {
     #cleanup block      #cleanup block
     $discussionitems[$alldiscussion{$_}]=~s/<table([^>]*)>/<table TeXwidth="90 mm">/;      $discussionitems[$alldiscussion{$post}]=~s/<table([^>]*)>/<table TeXwidth="90 mm">/;
     $discussionitems[$alldiscussion{$_}]=~s/<tr([^>]*)><td([^>]*)>/<tr><td TeXwidth="20 mm" align="left">/;      $discussionitems[$alldiscussion{$post}]=~s/<tr([^>]*)><td([^>]*)>/<tr><td TeXwidth="20 mm" align="left">/;
                     my $threadinsert='';                      my $threadinsert='';
                     if ($thisdepth > 0) {                      if ($thisdepth > 0) {
  $threadinsert='<br /><strong>Reply: '.$thisdepth.'</strong>';   $threadinsert='<br /><strong>Reply: '.$thisdepth.'</strong>';
     }      }
     $discussionitems[$alldiscussion{$_}]=~s/<\/td><td([^>]*)>/$threadinsert<\/td><td TeXwidth="65 mm" align="left">/;      $discussionitems[$alldiscussion{$post}]=~s/<\/td><td([^>]*)>/$threadinsert<\/td><td TeXwidth="65 mm" align="left">/;
     $discussionitems[$alldiscussion{$_}]=~s/<a([^>]+)>(Edit|Hide|Delete|Reply|Submissions)<\/a>//g;      $discussionitems[$alldiscussion{$post}]=~s/<a([^>]+)>(Edit|Hide|Delete|Reply|Submissions)<\/a>//g;
                     $discussionitems[$alldiscussion{$_}]=~s/(<b>|<\/b>|<\/a>|<a([^>]+)>)//g;                      $discussionitems[$alldiscussion{$post}]=~s/(<b>|<\/b>|<\/a>|<a([^>]+)>)//g;
   
     $discussionitems[$alldiscussion{$_}]='<tex>\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}</tex>'.$discussionitems[$alldiscussion{$_}];      $discussionitems[$alldiscussion{$post}]='<tex>\vskip 0 mm\noindent\makebox[2 cm][b]{\hrulefill}</tex>'.$discussionitems[$alldiscussion{$post}];
     $discussion.=$discussionitems[$alldiscussion{$_}];      $discussion.=$discussionitems[$alldiscussion{$post}];
  } elsif ($outputtarget eq 'export') {   } elsif ($outputtarget eq 'export') {
                     my $postfilename = $alldiscussion{$_}.'-'.$imsitems{$alldiscussion{$_}}{'timestamp'}.'.html';                      my $postfilename = $alldiscussion{$post}.'-'.$imsitems{$alldiscussion{$post}}{'timestamp'}.'.html';
                     if ($manifestok) {                      if ($manifestok) {
                         if (($depth[$alldiscussion{$_}] <= $currdepth) && ($alldiscussion{$_} != $firstidx)) {                          if (($depth[$alldiscussion{$post}] <= $currdepth) && ($alldiscussion{$post} != $firstidx)) {
                             print $manifestfile '  </item>'."\n";                              print $manifestfile '  </item>'."\n";
                         }                          }
                         $currdepth = $depth[$alldiscussion{$_}];                          $currdepth = $depth[$alldiscussion{$post}];
                         print $manifestfile "\n".                           print $manifestfile "\n". 
       '<item identifier="ITEM-'.$ressymb.'-'.$alldiscussion{$_}.'" isvisible="'.        '<item identifier="ITEM-'.$ressymb.'-'.$alldiscussion{$post}.'" isvisible="'.
         $imsitems{$alldiscussion{$_}}{'isvisible'}.'" identifieref="RES-'.$ressymb.'-'.$alldiscussion{$_}.'">'.          $imsitems{$alldiscussion{$post}}{'isvisible'}.'" identifieref="RES-'.$ressymb.'-'.$alldiscussion{$post}.'">'.
         '<title>'.$imsitems{$alldiscussion{$_}}{'title'}.'</title>';          '<title>'.$imsitems{$alldiscussion{$post}}{'title'}.'</title>';
                         $imsresources .= "\n".                          $imsresources .= "\n".
     '<resource identifier="RES-'.$ressymb.'-'.$alldiscussion{$_}.'" type="webcontent" href="'.$postfilename.'">'."\n".      '<resource identifier="RES-'.$ressymb.'-'.$alldiscussion{$post}.'" type="webcontent" href="'.$postfilename.'">'."\n".
       '<file href="'.$postfilename.'">'."\n".        '<file href="'.$postfilename.'">'."\n".
       $imsfiles{$alldiscussion{$_}}{$imsitems{$alldiscussion{$_}}{'currversion'}}."\n".        $imsfiles{$alldiscussion{$post}}{$imsitems{$alldiscussion{$post}}{'currversion'}}."\n".
     '</resource>';      '</resource>';
                     }                      }
                     my $postingfile;                      my $postingfile;
                     my $postingfilename = $tempexport.'/'.$postfilename;                      my $postingfilename = $tempexport.'/'.$postfilename;
                     if ($postingfile = Apache::File->new('>'.$postingfilename)) {                      if ($postingfile = Apache::File->new('>'.$postingfilename)) {
                         print $postingfile '<html><head><title>Discussion Post</title></head><body>'.                          print $postingfile '<html><head><title>Discussion Post</title></head><body>'.
                                            $imsitems{$alldiscussion{$_}}{'title'}.' '.                                             $imsitems{$alldiscussion{$post}}{'title'}.' '.
                                            $imsitems{$alldiscussion{$_}}{'sender'}.                                             $imsitems{$alldiscussion{$post}}{'sender'}.
                                            $imsitems{$alldiscussion{$_}}{'timestamp'}.'<br /><br />'.                                             $imsitems{$alldiscussion{$post}}{'timestamp'}.'<br /><br />'.
                                            $imsitems{$alldiscussion{$_}}{'message'}.'<br />'.                                             $imsitems{$alldiscussion{$post}}{'message'}.'<br />'.
                                            $imsitems{$alldiscussion{$_}}{'attach'}.'</body></html>'."\n";                                              $imsitems{$alldiscussion{$post}}{'attach'}.'</body></html>'."\n"; 
                         close($postingfile);                          close($postingfile);
                     } else {                      } else {
                         $discussion .= $lt{'aerr'}.' '.$alldiscussion{$_}.'<br />';                          $discussion .= $lt{'aerr'}.' '.$alldiscussion{$post}.'<br />';
                     }                      }
                     $copyresult.=&replicate_attachments($imsitems{$alldiscussion{$_}}{'allattachments'},$tempexport);                      $copyresult.=&replicate_attachments($imsitems{$alldiscussion{$post}}{'allattachments'},$tempexport);
                 } else {                  } else {
                     $discussion.='<td  bgcolor="'.$bgcols[$newitem{$alldiscussion{$_}}].                      $discussion.='<td  bgcolor="'.$bgcols[$newitem{$alldiscussion{$post}}].
                        '" colspan="'.$colspan.'">'. $discussionitems[$alldiscussion{$_}].                         '" colspan="'.$colspan.'">'. $discussionitems[$alldiscussion{$post}].
                        '</td></tr>';                         '</td></tr>';
                 }                  }
     }      }
Line 652  END Line 652  END
                     }                      }
                     if (@rolefilter > 0) {                      if (@rolefilter > 0) {
                         $filterchoice .= '<i>'.&mt('roles').'</i>-';                          $filterchoice .= '<i>'.&mt('roles').'</i>-';
                         foreach (@rolefilter) {                          foreach my $role (@rolefilter) {
                             $filterchoice .= '&nbsp;'.$role_types{$_}.',';                              $filterchoice .= '&nbsp;'.$role_types{$role}.',';
                         }                          }
                         $filterchoice =~ s/,$//;                          $filterchoice =~ s/,$//;
                         $filterchoice .= '<br />&nbsp;&nbsp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp&nbsp;';                          $filterchoice .= '<br />&nbsp;&nbsp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp&nbsp;';
Line 901  sub build_posting_display { Line 901  sub build_posting_display {
  $$visible++;   $$visible++;
                 if ($contrib{$idx.':history'}) {                  if ($contrib{$idx.':history'}) {
                     if ($contrib{$idx.':history'} =~ /:/) {                      if ($contrib{$idx.':history'} =~ /:/) {
                         my @oldversions = split/:/,$contrib{$idx.':history'};                          my @oldversions = split(/:/,$contrib{$idx.':history'});
                         $numoldver = @oldversions;                          $numoldver = @oldversions;
                     } else {                      } else {
                         $numoldver = 1;                          $numoldver = 1;
Line 940  sub build_posting_display { Line 940  sub build_posting_display {
   
                         if ($subject eq '') {                          if ($subject eq '') {
                            if (defined($$subjectsort{'__No subject'})) {                             if (defined($$subjectsort{'__No subject'})) {
                                push @{$$subjectsort{'__No subject'}}, $idx;                                 push(@{$$subjectsort{'__No subject'}}, $idx);
                            } else {                             } else {
                                @{$$subjectsort{'__No subject'}} = ("$idx");                                 @{$$subjectsort{'__No subject'}} = ("$idx");
                            }                             }
                         } else {                          } else {
                             if (defined($$subjectsort{$subject})) {                              if (defined($$subjectsort{$subject})) {
                                push @{$$subjectsort{$subject}}, $idx;                                 push(@{$$subjectsort{$subject}}, $idx);
                             } else {                              } else {
                                @{$$subjectsort{$subject}} = ("$idx");                                 @{$$subjectsort{$subject}} = ("$idx");
                             }                              }
Line 968  sub build_posting_display { Line 968  sub build_posting_display {
                                 %{$$usernamesort{$contrib{$idx.':senderdomain'}}} = ();                                  %{$$usernamesort{$contrib{$idx.':senderdomain'}}} = ();
                             }                              }
                             if (defined($$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}})) {                              if (defined($$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}})) {
                                 push @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}}, $idx;                                  push(@{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}}, $idx);
                             } else {                              } else {
                                 @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}} = ("$idx");                                  @{$$usernamesort{$contrib{$idx.':senderdomain'}}{$contrib{$idx.':sendername'}}} = ("$idx");
                             }                              }
Line 988  sub build_posting_display { Line 988  sub build_posting_display {
                                 %{$$namesort{$lastname}} = ();                                  %{$$namesort{$lastname}} = ();
                             }                              }
                             if (defined($$namesort{$lastname}{$firstname})) {                              if (defined($$namesort{$lastname}{$firstname})) {
                                 push @{$$namesort{$lastname}{$firstname}}, $idx;                                  push(@{$$namesort{$lastname}{$firstname}}, $idx);
                             } else {                              } else {
                                 @{$$namesort{$lastname}{$firstname}} = ("$idx");                                  @{$$namesort{$lastname}{$firstname}} = ("$idx");
                             }                              }
Line 1044  sub build_posting_display { Line 1044  sub build_posting_display {
                                 %{$$usernamesort{'__anon'}} = ();                                  %{$$usernamesort{'__anon'}} = ();
                             }                              }
                             if (defined($$usernamesort{'__anon'}{'__anon'})) {                              if (defined($$usernamesort{'__anon'}{'__anon'})) {
                                 push @{$$usernamesort{'__anon'}{'__anon'}}, $idx;                                  push(@{$$usernamesort{'__anon'}{'__anon'}}, $idx);
                             } else {                              } else {
                                 @{$$usernamesort{'__anon'}{'__anon'}} = ("$idx");                                  @{$$usernamesort{'__anon'}{'__anon'}} = ("$idx");
                             }                              }
Line 1053  sub build_posting_display { Line 1053  sub build_posting_display {
                                 %{$$namesort{'__anon'}} = ();                                  %{$$namesort{'__anon'}} = ();
                             }                              }
                             if (defined($$namesort{'__anon'}{'__anon'})) {                              if (defined($$namesort{'__anon'}{'__anon'})) {
                                 push @{$$namesort{'__anon'}{'__anon'}}, $idx;                                  push(@{$$namesort{'__anon'}{'__anon'}}, $idx);
                             } else {                              } else {
                                 @{$$namesort{'__anon'}{'__anon'}} = ("$idx");                                  @{$$namesort{'__anon'}{'__anon'}} = ("$idx");
                             }                              }
Line 1213  sub build_posting_display { Line 1213  sub build_posting_display {
                                 }                                  }
                                 $$discussionitems[$idx].='<br/>'.&mt('Earlier version(s) were posted on: ');                                  $$discussionitems[$idx].='<br/>'.&mt('Earlier version(s) were posted on: ');
                                 if ($contrib{$idx.':history'} =~ m/:/) {                                  if ($contrib{$idx.':history'} =~ m/:/) {
                                     @postversions = split/:/,$contrib{$idx.':history'};                                      @postversions = split(/:/,$contrib{$idx.':history'});
                                 } else {                                  } else {
                                     @postversions = ("$contrib{$idx.':history'}");                                      @postversions = ("$contrib{$idx.':history'}");
                                 }                                  }
Line 1236  sub filter_regexp { Line 1236  sub filter_regexp {
     my $skiptest = 1;      my $skiptest = 1;
     if (@{$rolefilter} > 0) {      if (@{$rolefilter} > 0) {
         my @okrolefilter = ();          my @okrolefilter = ();
         foreach (@{$rolefilter}) {          foreach my $role (@{$rolefilter}) {
             unless ($_ eq '') {              unless ($role eq '') {
                 push @okrolefilter, $_;                  push(@okrolefilter, $role);
             }              }
         }          }
         if (@okrolefilter > 0) {          if (@okrolefilter > 0) {
Line 1256  sub filter_regexp { Line 1256  sub filter_regexp {
     }      }
     if (@{$sectionpick} > 0) {      if (@{$sectionpick} > 0) {
         my @oksectionpick = ();          my @oksectionpick = ();
         foreach (@{$sectionpick}) {          foreach my $sec (@{$sectionpick}) {
             unless ($_ eq '') {              unless ($sec eq '') {
                  push @oksectionpick, $_;                   push(@oksectionpick, $sec);
             }              }
         }          }
         if ((@oksectionpick > 0) && (!grep/^all$/,@oksectionpick)) {          if ((@oksectionpick > 0) && (!grep/^all$/,@oksectionpick)) {
Line 1320  sub get_post_contents { Line 1320  sub get_post_contents {
         }          }
         &get_post_versions($messages,$$contrib{$idx.':message'},1);          &get_post_versions($messages,$$contrib{$idx.':message'},1);
         &get_post_versions($subjects,$$contrib{$idx.':subject'},1);          &get_post_versions($subjects,$$contrib{$idx.':subject'},1);
         push @postversions,$$contrib{$idx.':timestamp'};          push(@postversions,$$contrib{$idx.':timestamp'});
         $end = @postversions;          $end = @postversions;
     } else {      } else {
         &get_post_versions($messages,$$contrib{$idx.':message'},1,$numver);          &get_post_versions($messages,$$contrib{$idx.':message'},1,$numver);
Line 1348  sub get_post_contents { Line 1348  sub get_post_contents {
             $$imsfiles{$idx}{$i} = '';              $$imsfiles{$idx}{$i} = '';
             if ($attachmsg) {              if ($attachmsg) {
                 $$attachtxt{$i} = '<br />'.&mt('Attachments').':<br />';                  $$attachtxt{$i} = '<br />'.&mt('Attachments').':<br />';
                 foreach (sort keys %currattach) {                  foreach my $key (sort(keys(%currattach))) {
                     if ($$allattachments{$_}{'filename'} =~ m-^/uploaded/([^/]+/[^/]+)(/feedback)?(/?\d*)/([^/]+)$-) {                      if ($$allattachments{$key}{'filename'} =~ m-^/uploaded/([^/]+/[^/]+)(/feedback)?(/?\d*)/([^/]+)$-) {
                         my $fname = $1.$3.'/'.$4;                          my $fname = $1.$3.'/'.$4;
                         $$imsfiles{$idx}{$i} .= '<file href="'.$fname.'">'."\n";                          $$imsfiles{$idx}{$i} .= '<file href="'.$fname.'">'."\n";
                         $$attachtxt{$i}.= '<a href="'.$fname.'">'.$4.'</a><br />';                          $$attachtxt{$i}.= '<a href="'.$fname.'">'.$4.'</a><br />';
Line 1382  END Line 1382  END
 sub replicate_attachments {  sub replicate_attachments {
     my ($attachrefs,$tempexport) = @_;      my ($attachrefs,$tempexport) = @_;
     my $response;      my $response;
     foreach my $id (keys %{$attachrefs}) {      foreach my $id (keys(%{$attachrefs})) {
         if ($$attachrefs{$id}{'filename'} =~ m-^/uploaded/([^/]+)/([^/]+)(/feedback)?(/?\d*)/([^/]+)$-) {          if ($$attachrefs{$id}{'filename'} =~ m-^/uploaded/([^/]+)/([^/]+)(/feedback)?(/?\d*)/([^/]+)$-) {
             my $path = $tempexport;              my $path = $tempexport;
             my $tail = $1.'/'.$2.$4;              my $tail = $1.'/'.$2.$4;
             my @extras = split/\//,$tail;              my @extras = split(/\//,$tail);
             my $destination = $tempexport.'/'.$1.'/'.$2.$4.'/'.$5;              my $destination = $tempexport.'/'.$1.'/'.$2.$4.'/'.$5;
             if (!-e $destination) {              if (!-e $destination) {
                 my $i= 0;                  my $i= 0;
Line 1497  END Line 1497  END
       unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) {        unless (($contrib{'hidden'}=~/\.$idx\./) || ($contrib{'deleted'}=~/\.$idx\./)) {
           if ($contrib{$idx.':history'}) {            if ($contrib{$idx.':history'}) {
               if ($contrib{$idx.':history'} =~ /:/) {                if ($contrib{$idx.':history'} =~ /:/) {
                   my @oldversions = split/:/,$contrib{$idx.':history'};                    my @oldversions = split(/:/,$contrib{$idx.':history'});
                   $numoldver = @oldversions;                    $numoldver = @oldversions;
               } else {                } else {
                   $numoldver = 1;                    $numoldver = 1;
Line 1506  END Line 1506  END
           if ($env{'form.replydisc'}) {            if ($env{'form.replydisc'}) {
               if ($contrib{$idx.':history'}) {                if ($contrib{$idx.':history'}) {
                   if ($contrib{$idx.':history'} =~ /:/) {                    if ($contrib{$idx.':history'} =~ /:/) {
                       my @oldversions = split/:/,$contrib{$idx.':history'};                        my @oldversions = split(/:/,$contrib{$idx.':history'});
                       $numoldver = @oldversions;                        $numoldver = @oldversions;
                   } else {                    } else {
                       $numoldver = 1;                        $numoldver = 1;
Line 1650  $lt{'title'}: <input type="text" name="s Line 1650  $lt{'title'}: <input type="text" name="s
 END  END
     if ( ($env{'form.editdisc'}) || ($env{'form.replydisc'}) ) {      if ( ($env{'form.editdisc'}) || ($env{'form.replydisc'}) ) {
         if ($env{'form.origpage'}) {          if ($env{'form.origpage'}) {
             foreach (@currnewattach) {              foreach my $attach (@currnewattach) {
                 $r->print('<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n");                  $r->print('<input type="hidden" name="currnewattach" value="'.$attach.'" />'."\n");
             }              }
             foreach (@currdelold) {              foreach my $oldatt (@currdelold) {
                 $r->print('<input type="hidden" name="deloldattach" value="'.$_.'" />'."\n");                  $r->print('<input type="hidden" name="deloldattach" value="'.$oldatt.'" />'."\n");
             }              }
         }          }
         if ($env{'form.editdisc'}) {          if ($env{'form.editdisc'}) {
             if ($attachmenturls) {              if ($attachmenturls) {
                 &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\%attachments,\%currattach,\@currdelold);                  &extract_attachments($attachmenturls,$idx,$numoldver,\$attachmsg,\%attachments,\%currattach,\@currdelold);
                 $attachnum = scalar(keys %currattach);                  $attachnum = scalar(keys(%currattach));
                 foreach (keys %currattach) {                  foreach my $key (keys(%currattach)) {
                     $r->print('<input type="hidden" name="keepold" value="'.$_.'" />'."\n");                      $r->print('<input type="hidden" name="keepold" value="'.$key.'" />'."\n");
                 }                  }
             }              }
         }          }
Line 2200  sub print_showposters { Line 2200  sub print_showposters {
                     $postcounts{$poster} ++;                      $postcounts{$poster} ++;
                     if (defined($namesort{$lastname}{$firstname})) {                      if (defined($namesort{$lastname}{$firstname})) {
                         if (!grep/^$poster$/,@{$namesort{$lastname}{$firstname}}) {                          if (!grep/^$poster$/,@{$namesort{$lastname}{$firstname}}) {
                             push @{$namesort{$lastname}{$firstname}}, $poster;                              push(@{$namesort{$lastname}{$firstname}}, $poster);
                         }                          }
                     } else {                      } else {
                         @{$namesort{$lastname}{$firstname}} = ("$poster");                          @{$namesort{$lastname}{$firstname}} = ("$poster");
Line 2225  $start_page Line 2225  $start_page
       </tr>        </tr>
 END  END
     my $count = 0;      my $count = 0;
     foreach my $last (sort keys %namesort) {      foreach my $last (sort(keys(%namesort))) {
         foreach my $first (sort keys %{$namesort{$last}}) {          foreach my $first (sort(keys(%{$namesort{$last}}))) {
             foreach (sort @{$namesort{$last}{$first}}) {              foreach my $user (sort(@{$namesort{$last}{$first}})) {
                 my ($uname,$udom) = split/:/,$_;                  my ($uname,$udom) = split(/:/,$user);
                 if (!$uname || !$udom) {                   if (!$uname || !$udom) { 
                     next;                      next;
                 } else {                  } else {
                     $count ++;                      $count ++;
                     $r->print(&Apache::loncommon::start_data_table_row().                      $r->print(&Apache::loncommon::start_data_table_row().
       '<td align="right">'.$count.'</td>        '<td align="right">'.$count.'</td>
                                <td align="center"><label><input name="stuinfo" type="checkbox" value="'.$_.'" /></td>                                 <td align="center"><label><input name="stuinfo" type="checkbox" value="'.$user.'" /></td>
                                <td>'.$last.', '.$first.' ('.$uname.':'.$udom.')</label></td>                                 <td>'.$last.', '.$first.' ('.$uname.':'.$udom.')</label></td>
                                <td>'.$postcounts{$_}.'</td>'.                                 <td>'.$postcounts{$user}.'</td>'.
       &Apache::loncommon::end_data_table_row());        &Apache::loncommon::end_data_table_row());
                 }                  }
             }              }
Line 2374  sub redirect_back { Line 2374  sub redirect_back {
           if (ref($sectionpick) eq 'ARRAY') {            if (ref($sectionpick) eq 'ARRAY') {
               $feedurl .= '&sectionpick=';                $feedurl .= '&sectionpick=';
               $sectag .=  '<input type="hidden" name="sectionpick" value="';                $sectag .=  '<input type="hidden" name="sectionpick" value="';
               foreach (@{$sectionpick}) {                foreach my $sec (@{$sectionpick}) {
                   $feedurl .= $_.',';                    $feedurl .= $sec.',';
                   $sectag .= $_.',';                    $sectag .= $sec.',';
               }                }
               $feedurl =~ s/,$//;                $feedurl =~ s/,$//;
               $sectag =~ s/,$//;                $sectag =~ s/,$//;
Line 2402  sub redirect_back { Line 2402  sub redirect_back {
           if (ref($rolefilter) eq 'ARRAY') {            if (ref($rolefilter) eq 'ARRAY') {
               $feedurl .= '&rolefilter=';                $feedurl .= '&rolefilter=';
               $roletag .=  '<input type="hidden" name="rolefilter" value="';                $roletag .=  '<input type="hidden" name="rolefilter" value="';
               foreach (@{$rolefilter}) {                foreach my $role (@{$rolefilter}) {
                   $feedurl .= $_.',';                    $feedurl .= $role.',';
                   $roletag .= $_.',';                    $roletag .= $role.',';
               }                }
               $feedurl =~ s/,$//;                $feedurl =~ s/,$//;
               $roletag =~ s/,$//;                $roletag =~ s/,$//;
Line 2615  sub secapply { Line 2615  sub secapply {
     $rec=~s/\@/\:/g;      $rec=~s/\@/\:/g;
     my ($adr,$sections)=($rec=~/^([^\(]+)\(([^\)]+)\)/);      my ($adr,$sections)=($rec=~/^([^\(]+)\(([^\)]+)\)/);
     if ($sections) {      if ($sections) {
  foreach (split(/\;/,$sections)) {   foreach my $sec (split(/\;/,$sections)) {
             if (($_ eq $env{'request.course.sec'}) ||              if (($sec eq $env{'request.course.sec'}) ||
                 ($defaultflag && ($_ eq '*'))) {                  ($defaultflag && ($sec eq '*'))) {
                 return $adr;                   return $adr; 
             }              }
         }          }
Line 2669  sub decide_receiver { Line 2669  sub decide_receiver {
   }    }
   if ($env{'form.discuss'} eq 'question' ||$question) {    if ($env{'form.discuss'} eq 'question' ||$question) {
     $typestyle.=&mt('Submitting as Question').'<br />';      $typestyle.=&mt('Submitting as Question').'<br />';
     foreach (split(/\,/,      foreach my $item (split(/\,/,
    $env{'course.'.$env{'request.course.id'}.'.question.email'})     $env{'course.'.$env{'request.course.id'}.'.question.email'})
      ) {       ) {
  my $rec=&secapply($_,$defaultflag);   my $rec=&secapply($item,$defaultflag);
         if ($rec) { $to{$rec}=1; }          if ($rec) { $to{$rec}=1; }
     }       } 
   }    }
   if ($env{'form.discuss'} eq 'course' ||$course) {    if ($env{'form.discuss'} eq 'course' ||$course) {
     $typestyle.=&mt('Submitting as Comment').'<br />';      $typestyle.=&mt('Submitting as Comment').'<br />';
     foreach (split(/\,/,      foreach my $item (split(/\,/,
    $env{'course.'.$env{'request.course.id'}.'.comment.email'})     $env{'course.'.$env{'request.course.id'}.'.comment.email'})
      ) {       ) {
  my $rec=&secapply($_,$defaultflag);   my $rec=&secapply($item,$defaultflag);
         if ($rec) { $to{$rec}=1; }          if ($rec) { $to{$rec}=1; }
     }       } 
   }    }
   if ($env{'form.discuss'} eq 'policy' ||$policy) {    if ($env{'form.discuss'} eq 'policy' ||$policy) {
     $typestyle.=&mt('Submitting as Policy Feedback').'<br />';      $typestyle.=&mt('Submitting as Policy Feedback').'<br />';
     foreach (split(/\,/,      foreach my $item (split(/\,/,
    $env{'course.'.$env{'request.course.id'}.'.policy.email'})     $env{'course.'.$env{'request.course.id'}.'.policy.email'})
      ) {       ) {
  my $rec=&secapply($_,$defaultflag);   my $rec=&secapply($item,$defaultflag);
         if ($rec) { $to{$rec}=1; }          if ($rec) { $to{$rec}=1; }
     }       } 
   }    }
Line 2713  sub send_msg { Line 2713  sub send_msg {
   my $sendsomething=0;    my $sendsomething=0;
   if ($title=~/^Error/) { $title=&mt('Feedback').': '.$title; }    if ($title=~/^Error/) { $title=&mt('Feedback').': '.$title; }
   unless ($title=~/\w/) { $title=&mt('Feedback'); }    unless ($title=~/\w/) { $title=&mt('Feedback'); }
   foreach (keys %to) {    foreach my $key (keys(%to)) {
     if ($_) {      if ($key) {
       my $declutter=&Apache::lonnet::declutter($feedurl);        my $declutter=&Apache::lonnet::declutter($feedurl);
       unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$_),        unless (&Apache::lonmsg::user_normal_msg(split(/\:/,$key),
                $title.' ['.$declutter.']',$email,$citations,$feedurl,                 $title.' ['.$declutter.']',$email,$citations,$feedurl,
                 $attachmenturl)=~/ok/) {                  $attachmenturl)=~/ok/) {
  $status.='<br />'.&mt('Error sending message to').' '.$_.'<br />';   $status.='<br />'.&mt('Error sending message to').' '.$key.'<br />';
       } else {        } else {
  $sendsomething++;   $sendsomething++;
       }        }
Line 2727  sub send_msg { Line 2727  sub send_msg {
   }    }
   
     my %record=&Apache::lonnet::restore('_feedback');      my %record=&Apache::lonnet::restore('_feedback');
     my ($temp)=keys %record;      my ($temp)=keys(%record);
     unless ($temp=~/^error\:/) {      unless ($temp=~/^error\:/) {
        my %newrecord=();         my %newrecord=();
        $newrecord{'resource'}=$feedurl;         $newrecord{'resource'}=$feedurl;
Line 2788  sub adddiscuss { Line 2788  sub adddiscuss {
             }              }
             if (defined($oldcontrib{$oldidx.':history'})) {              if (defined($oldcontrib{$oldidx.':history'})) {
                 if ($oldcontrib{$oldidx.':history'} =~ /:/) {                  if ($oldcontrib{$oldidx.':history'} =~ /:/) {
                     my @oldversions = split/:/,$oldcontrib{$oldidx.':history'};                      my @oldversions = split(/:/,$oldcontrib{$oldidx.':history'});
                     $numoldver = @oldversions;                      $numoldver = @oldversions;
                 } else {                  } else {
                     $numoldver = 1;                      $numoldver = 1;
Line 2831  sub adddiscuss { Line 2831  sub adddiscuss {
      $env{'course.'.$env{'request.course.id'}.'.num'});       $env{'course.'.$env{'request.course.id'}.'.num'});
     }      }
     my %record=&Apache::lonnet::restore('_discussion');      my %record=&Apache::lonnet::restore('_discussion');
     my ($temp)=keys %record;      my ($temp)=keys(%record);
     unless ($temp=~/^error\:/) {      unless ($temp=~/^error\:/) {
        my %newrecord=();         my %newrecord=();
        $newrecord{'resource'}=$symb;         $newrecord{'resource'}=$symb;
Line 2959  $start_page Line 2959  $start_page
 END  END
     if ($idx) {      if ($idx) {
         if ($attachmenturls) {          if ($attachmenturls) {
             my @currold = keys %currattach;              my @currold = keys(%currattach);
             if (@currold > 0) {              if (@currold > 0) {
                 $r->print($lt{'thfo'}.'<br />'.$lt{'chth'}.'<br />'."\n");                    $r->print($lt{'thfo'}.'<br />'.$lt{'chth'}.'<br />'."\n");  
                 foreach my $id (@currold) {                  foreach my $id (@currold) {
Line 2973  END Line 2973  END
     }      }
     if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {      if ((ref($currnewattach) eq 'ARRAY') && (@{$currnewattach} > 0)) {
         $r->print($lt{'thef'}.'<br />'.$lt{'chth'}.'<br />'."\n");          $r->print($lt{'thef'}.'<br />'.$lt{'chth'}.'<br />'."\n");
         foreach (@{$currnewattach}) {          foreach my $attach (@{$currnewattach}) {
             $_ =~ m#/([^/]+)$#;              $attach =~ m#/([^/]+)$#;
             $r->print('<label><input type="checkbox" name="delnewattach" value="'.$_.'" />&nbsp;'.$1.'</label><br />'."\n");              $r->print('<label><input type="checkbox" name="delnewattach" value="'.$attach.'" />&nbsp;'.$1.'</label><br />'."\n");
         }          }
         $r->print("<br />");           $r->print("<br />"); 
     }      }
Line 3020  sub process_attachments { Line 3020  sub process_attachments {
         my @currnew = ();          my @currnew = ();
         foreach my $newone (@{$currnewattach}) {          foreach my $newone (@{$currnewattach}) {
             my $delflag = 0;              my $delflag = 0;
             foreach (@currdelnew) {              foreach my $item (@currdelnew) {
                 if ($newone eq $_) {                  if ($newone eq $item) {
                     $delflag = 1;                      $delflag = 1;
                     last;                      last;
                 }                  }
             }              }
             unless ($delflag) {              unless ($delflag) {
                 push @currnew, $newone;                  push(@currnew, $newone);
             }              }
         }          }
         @{$currnewattach} = @currnew;          @{$currnewattach} = @currnew;
Line 3064  this.form.submit();" /> Line 3064  this.form.submit();" />
 ENDATTACH  ENDATTACH
     if (defined($deloldattach)) {      if (defined($deloldattach)) {
         if (@{$deloldattach} > 0) {          if (@{$deloldattach} > 0) {
             foreach (@{$deloldattach}) {              foreach my $delatt (@{$deloldattach}) {
                 $response .= '<input type="hidden" name="deloldattach" value="'.$_.'" />'."\n";                  $response .= '<input type="hidden" name="deloldattach" value="'.$delatt.'" />'."\n";
             }              }
         }          }
     }      }
     if (defined($currnewattach)) {      if (defined($currnewattach)) {
         if (@{$currnewattach} > 0) {          if (@{$currnewattach} > 0) {
             foreach (@{$currnewattach}) {              foreach my $attach (@{$currnewattach}) {
                 $response .= '<input type="hidden" name="currnewattach" value="'.$_.'" />'."\n";                  $response .= '<input type="hidden" name="currnewattach" value="'.$attach.'" />'."\n";
             }              }
         }          }
     }      }
Line 3084  sub extract_attachments { Line 3084  sub extract_attachments {
     my ($attachmenturls,$idx,$numoldver,$message,$attachments,$currattach,$currdelold) = @_;      my ($attachmenturls,$idx,$numoldver,$message,$attachments,$currattach,$currdelold) = @_;
     %{$attachments}=();      %{$attachments}=();
     &get_post_attachments($attachments,$attachmenturls);      &get_post_attachments($attachments,$attachmenturls);
     foreach my $id (sort keys %{$attachments}) {      foreach my $id (sort(keys(%{$attachments}))) {
         if (exists($$attachments{$id}{$numoldver})) {          if (exists($$attachments{$id}{$numoldver})) {
             if (defined($currdelold)) {              if (defined($currdelold)) {
                 if (@{$currdelold} > 0) {                  if (@{$currdelold} > 0) {
Line 3099  sub extract_attachments { Line 3099  sub extract_attachments {
             }              }
         }          }
     }      }
     my @attached = (sort { $a <=> $b } keys %{$currattach});      my @attached = (sort { $a <=> $b } keys(%{$currattach}));
     if (@attached == 1) {      if (@attached == 1) {
         my $id = $attached[0];          my $id = $attached[0];
         my $attachurl;          my $attachurl;
Line 3115  sub extract_attachments { Line 3115  sub extract_attachments {
                                $attachurl);                                 $attachurl);
     } elsif (@attached > 1) {      } elsif (@attached > 1) {
         $$message.='<ol>';          $$message.='<ol>';
         foreach (@attached) {          foreach my $attach (@attached) {
             my $id = $_;              my $id = $attach;
             my $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'});              my $attachurl = &HTML::Entities::decode($$attachments{$id}{'filename'});
             my ($fname)              my ($fname)
               =($attachurl=~m|/([^/]+)$|);                =($attachurl=~m|/([^/]+)$|);
Line 3143  sub construct_attachmenturl { Line 3143  sub construct_attachmenturl {
         $oldattachmenturl = $contrib{$idx.':attachmenturl'};          $oldattachmenturl = $contrib{$idx.':attachmenturl'};
         if ($contrib{$idx.':history'}) {          if ($contrib{$idx.':history'}) {
             if ($contrib{$idx.':history'} =~ /:/) {              if ($contrib{$idx.':history'} =~ /:/) {
                 my @oldversions = split/:/,$contrib{$idx.':history'};                  my @oldversions = split(/:/,$contrib{$idx.':history'});
                 $currver = 1 + scalar(@oldversions);                  $currver = 1 + scalar(@oldversions);
             } else {              } else {
                 $currver = 2;                  $currver = 2;
Line 3156  sub construct_attachmenturl { Line 3156  sub construct_attachmenturl {
                 my %attachments = ();                  my %attachments = ();
                 my $prevver = $currver-1;                  my $prevver = $currver-1;
                 &get_post_attachments(\%attachments,$oldattachmenturl);                  &get_post_attachments(\%attachments,$oldattachmenturl);
                 my $numattach = scalar(keys %attachments);                  my $numattach = scalar(keys(%attachments));
                 $startnum += $numattach;                  $startnum += $numattach;
                 foreach my $num (sort {$a <=> $b} keys %attachments) {                  foreach my $num (sort {$a <=> $b} keys(%attachments)) {
                     $newattachmenturl .= '<attachment id="'.$num.'"><filename>'.$attachments{$num}{'filename'}.'</filename>';                      $newattachmenturl .= '<attachment id="'.$num.'"><filename>'.$attachments{$num}{'filename'}.'</filename>';
                     foreach $_ (sort {$a <=> $b} keys %{$attachments{$num}}) {                      foreach my $item (sort {$a <=> $b} keys(%{$attachments{$num}})) {
                         unless ($_ eq 'filename') {                          unless ($item eq 'filename') {
                             $newattachmenturl .= '<post id="'.$_.'">'.$attachments{$num}{$_}.'</post>';                              $newattachmenturl .= '<post id="'.$item.'">'.$attachments{$num}{$item}.'</post>';
                         }                          }
                     }                      }
                     if (grep/^$num$/,@{$keepold}) {                      if (grep/^$num$/,@{$keepold}) {
Line 3194  sub has_discussion { Line 3194  sub has_discussion {
     foreach my $resource (@allres) {      foreach my $resource (@allres) {
         if ($resource->hasDiscussion()) {          if ($resource->hasDiscussion()) {
             my $ressymb = $resource->wrap_symb();              my $ressymb = $resource->wrap_symb();
             push @{$resourcesref}, $ressymb;              push(@{$resourcesref}, $ressymb);
         }          }
     }      }
     return;      return;
Line 3256  sub handler { Line 3256  sub handler {
       my $readkey = $symb.'_read';        my $readkey = $symb.'_read';
       my $chgcount = 0;        my $chgcount = 0;
       my %readinghash = &Apache::lonnet::get('nohist_'.$env{'request.course.id'}.'_discuss',[$readkey],$env{'user.domain'},$env{'user.name'});        my %readinghash = &Apache::lonnet::get('nohist_'.$env{'request.course.id'}.'_discuss',[$readkey],$env{'user.domain'},$env{'user.name'});
       foreach my $key (keys %env) {        foreach my $key (keys(%env)) {
           if ($key =~ m/^form\.postunread_(\d+)/) {            if ($key =~ m/^form\.postunread_(\d+)/) {
               if ($readinghash{$readkey} =~ /\.$1\./) {                if ($readinghash{$readkey} =~ /\.$1\./) {
                   $readinghash{$readkey} =~ s/\.$1\.//;                    $readinghash{$readkey} =~ s/\.$1\.//;
Line 3355  sub handler { Line 3355  sub handler {
       my @resources = ();        my @resources = ();
       if (defined($env{'form.navmaps'})) {        if (defined($env{'form.navmaps'})) {
           if ($env{'form.navmaps'} =~ /:/) {            if ($env{'form.navmaps'} =~ /:/) {
               @resources = split/:/,$env{'form.navmaps'};                @resources = split(/:/,$env{'form.navmaps'});
           } else {            } else {
               @resources = ("$env{'form.navmaps'}");                @resources = ("$env{'form.navmaps'}");
           }            }
Line 3370  sub handler { Line 3370  sub handler {
           'robb' => 'resources/bulletin boards.',            'robb' => 'resources/bulletin boards.',
           'twnp' => 'There are currently no resources or bulletin boards with unread discussion postings.'            'twnp' => 'There are currently no resources or bulletin boards with unread discussion postings.'
       );               );       
       foreach (@resources) {        foreach my $res (@resources) {
           my $ressymb=$_;            my $ressymb=$res;
   &Apache::lonenc::check_decrypt(\$ressymb);    &Apache::lonenc::check_decrypt(\$ressymb);
           my $lastkey = $ressymb.'_lastread';            my $lastkey = $ressymb.'_lastread';
           $discinfo{$lastkey} = $env{'form.navtime'};            $discinfo{$lastkey} = $env{'form.navtime'};
Line 3541  ENDREDIR Line 3541  ENDREDIR
           unless (length($env{'form.addnewattach'})>131072) {            unless (length($env{'form.addnewattach'})>131072) {
               my $subdir = 'feedback/'.$env{'form.timestamp'};                my $subdir = 'feedback/'.$env{'form.timestamp'};
               my $newattachment=&Apache::lonnet::userfileupload('addnewattach',undef,$subdir);                my $newattachment=&Apache::lonnet::userfileupload('addnewattach',undef,$subdir);
       push @currnewattach, $newattachment;        push(@currnewattach, $newattachment);
           }            }
       }        }
       my $attachmenturls;        my $attachmenturls;

Removed from v.1.220  
changed lines
  Added in v.1.221


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