Diff for /loncom/xml/lonxml.pm between versions 1.98 and 1.118

version 1.98, 2001/06/27 18:52:34 version 1.118, 2001/08/18 15:49:28
Line 12 Line 12
 # 6/2,6/3,6/8,6/9 Gerd Kortemeyer  # 6/2,6/3,6/8,6/9 Gerd Kortemeyer
 # 6/12,6/13 H. K. Ng  # 6/12,6/13 H. K. Ng
 # 6/16 Gerd Kortemeyer  # 6/16 Gerd Kortemeyer
   # 7/27 H. K. Ng
   # 8/7,8/9,8/10,8/11,8/15,8/16,8/17,8/18 Gerd Kortemeyer
   
 package Apache::lonxml;   package Apache::lonxml; 
 use vars   use vars 
 qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace);  qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace);
 use strict;  use strict;
 use HTML::TokeParser;  use HTML::TokeParser;
   use HTML::TreeBuilder;
 use Safe;  use Safe;
 use Safe::Hole;  use Safe::Hole;
 use Math::Cephes qw(:trigs :hypers :bessels erf erfc);  use Math::Cephes qw(:trigs :hypers :bessels erf erfc);
Line 70  $evaluate = 1; Line 73  $evaluate = 1;
 # data structure for eidt mode, determines what tags can go into what other tags  # data structure for eidt mode, determines what tags can go into what other tags
 %insertlist=();  %insertlist=();
   
 #stores the list of active tag namespaces  # stores the list of active tag namespaces
 @namespace=();  @namespace=();
   
   # has the dynamic menu been updated to know about this resource
   $Apache::lonxml::registered=0;
   
 sub xmlbegin {  sub xmlbegin {
   my $output='';    my $output='';
   if ($ENV{'browser.mathml'}) {    if ($ENV{'browser.mathml'}) {
Line 89  sub xmlbegin { Line 95  sub xmlbegin {
 }  }
   
 sub xmlend {  sub xmlend {
     return '</html>';      my $discussion='';
       if ($ENV{'request.course.id'}) {
          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=&Apache::lonnet::symbread();
          if ($symb) {
             my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'},
                        $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
        $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
             if ($contrib{'version'}) {
                 $discussion.=
                     '<address><hr /><h2>Course Discussion of Resource</h2>';
                 my $idx;
                 for ($idx=1;$idx<=$contrib{'version'};$idx++) {
    my $hidden=($contrib{'hidden'}=~/\.$idx\./);
    unless (($hidden) && (!$seeid)) {
                    my $message=$contrib{$idx.':message'};
                    $message=~s/\n/\<br \/\>/g;
                    if ($message) {
                     if ($hidden) {
         $message='<font color="#888888">'.$message.'</font>';
                     }
                     my $sender='Anonymous';
                     if ((!$contrib{$idx.':anonymous'}) || ($seeid)) {
                         $sender=$contrib{$idx.':sendername'}.' at '.
         $contrib{$idx.':senderdomain'};
                         if ($contrib{$idx.':anonymous'}) {
     $sender.=' (anonymous)';
                         }
                         if ($seeid) {
     if ($hidden) {
                                $sender.=' <a href="/adm/feedback?unhide='.
    $symb.':::'.$idx.'">Make Visible</a>';
                             } else {
                                $sender.=' <a href="/adm/feedback?hide='.
    $symb.':::'.$idx.'">Hide</a>';
     }
                         }                   
                     }
     $discussion.='<p><b>'.$sender.'</b> ('.
                         localtime($contrib{$idx.':timestamp'}).
                         '):<blockquote>'.$message.
                         '</blockquote></p>';
           }
                  } 
                 }
                 $discussion.='</address>';
             }
          }
       }
       return $discussion.'</html>';
   }
   
   sub maketoken {
       my ($symb,$tuname,$tudom,$tcrsid)=@_;
       unless ($symb) {
    $symb=&Apache::lonnet::symbread();
       }
       unless ($tuname) {
    $tuname=$ENV{'user.name'};
           $tudom=$ENV{'user.domain'};
           $tcrsid=$ENV{'request.course.id'};
       }
   
       return &Apache::lonnet::checkout($symb,$tuname,$tudom,$tcrsid);
   }
   
   sub printtokenheader {
       my ($target,$token,$symb,$tuname,$tudom,$tcrsid)=@_;
       unless ($token) { return ''; }
   
       unless ($symb) {
    $symb=&Apache::lonnet::symbread();
       }
       unless ($tuname) {
    $tuname=$ENV{'user.name'};
           $tudom=$ENV{'user.domain'};
           $tcrsid=$ENV{'request.course.id'};
       }
   
       my %reply=&Apache::lonnet::get('environment',
                 ['firstname','middlename','lastname','generation'],
                 $tudom,$tuname);
       my $plainname=$reply{'firstname'}.' '. 
                     $reply{'middlename'}.' '.
                     $reply{'lastname'}.' '.
     $reply{'generation'};
   
       if ($target eq 'web') {
    return 
    '<img align="right" src="/cgi-bin/barcode.gif?encode='.$token.'" />'.
                  'Checked out for '.$plainname.
                  '<br />User: '.$tuname.' at '.$tudom.
          '<br />CourseID: '.$tcrsid.
                  '<br />DocID: '.$token.
                  '<br />Time: '.localtime().'<hr />';
       } else {
           return $token;                         
       }
 }  }
   
 sub fontsettings() {  sub fontsettings() {
Line 102  sub fontsettings() { Line 210  sub fontsettings() {
 }  }
   
 sub registerurl {  sub registerurl {
     if ($ENV{'REQUEST_URI'}!~/^\/(res\/)*adm\//) {      my $forcereg=shift;
       if ($Apache::lonxml::registered) { return ''; }
       $Apache::lonxml::registered=1;
       if (($ENV{'REQUEST_URI'}!~/^\/(res\/)*adm\//) || ($forcereg)) {
         my $hwkadd='';          my $hwkadd='';
         if ($ENV{'REQUEST_URI'}=~/\.(problem|exam|quiz|assess|survey|form)$/) {          if ($ENV{'REQUEST_URI'}=~/\.(problem|exam|quiz|assess|survey|form)$/) {
     if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {      if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
Line 139  ENDPARM Line 250  ENDPARM
           menu.currentStale=0;            menu.currentStale=0;
           menu.clearbut(3,1);            menu.clearbut(3,1);
           menu.switchbutton            menu.switchbutton
          (6,3,'catalog.gif','catalog','info','catalog_info()');
             menu.switchbutton
        (8,1,'eval.gif','evaluate','this','gopost("/adm/evaluate",currentURL)');         (8,1,'eval.gif','evaluate','this','gopost("/adm/evaluate",currentURL)');
           menu.switchbutton            menu.switchbutton
     (8,2,'fdbk.gif','feedback','on this','gopost("/adm/feedback",currentURL)');      (8,2,'fdbk.gif','feedback','on this','gopost("/adm/feedback",currentURL)');
Line 167  ENDPARM Line 280  ENDPARM
           menu.clearbut(7,3);            menu.clearbut(7,3);
           menu.menucltim=menu.setTimeout(            menu.menucltim=menu.setTimeout(
  'clearbut(2,1);clearbut(2,3);clearbut(8,1);clearbut(8,2);clearbut(8,3);'+   'clearbut(2,1);clearbut(2,3);clearbut(8,1);clearbut(8,2);clearbut(8,3);'+
  'clearbut(9,1);clearbut(9,2);clearbut(9,3);',   'clearbut(9,1);clearbut(9,2);clearbut(9,3);clearbut(6,3)',
   2000);    2000);
   
       }        }
Line 229  sub xmlparse { Line 342  sub xmlparse {
  &setup_globals($target);   &setup_globals($target);
  #&printalltags();   #&printalltags();
  my @pars = ();   my @pars = ();
  @Apache::lonxml::pwd=();  
  my $pwd=$ENV{'request.filename'};   my $pwd=$ENV{'request.filename'};
  $pwd =~ s:/[^/]*$::;   $pwd =~ s:/[^/]*$::;
  &newparser(\@pars,\$content_file_string,$pwd);   &newparser(\@pars,\$content_file_string,$pwd);
  my $currentstring = '';  
  my $finaloutput = '';   
  my $newarg = '';  
  my $result;  
   
  my $safeeval = new Safe;   my $safeeval = new Safe;
  my $safehole = new Safe::Hole;   my $safehole = new Safe::Hole;
Line 248  sub xmlparse { Line 356  sub xmlparse {
  my @stack = ();    my @stack = (); 
  my @parstack = ();   my @parstack = ();
  &initdepth;   &initdepth;
  my $token;  
  while ( $#pars > -1 ) {  
    while ($token = $pars[$#pars]->get_token) {  
      if (($token->[0] eq 'T') || ($token->[0] eq 'C') || ($token->[0] eq 'D') ) {  
        if ($metamode<1) { $result=$token->[1]; }  
      } elsif ($token->[0] eq 'PI') {  
        if ($metamode<1) { $result=$token->[2]; }  
      } elsif ($token->[0] eq 'S') {  
        # add tag to stack      
        push (@stack,$token->[1]);  
        # add parameters list to another stack  
        push (@parstack,&parstring($token));  
        &increasedepth($token);         
        if (exists $style_for_target{$token->[1]}) {  
  if ($Apache::lonxml::redirection) {  
    $Apache::lonxml::outputstack['-1'] .=    
      &recurse($style_for_target{$token->[1]},$target,$safeeval,  
       \%style_for_target,@parstack);  
  } else {  
    $finaloutput .= &recurse($style_for_target{$token->[1]},$target,  
     $safeeval,\%style_for_target,@parstack);  
  }  
        } else {  
  $result = &callsub("start_$token->[1]", $target, $token, \@stack,  
     \@parstack, \@pars, $safeeval, \%style_for_target);  
        }                
      } elsif ($token->[0] eq 'E')  {  
        #clear out any tags that didn't end  
        while ($token->[1] ne $stack[$#stack] && ($#stack > -1)) {  
  &Apache::lonxml::warning("Unbalanced tags in resource $stack['-1']");  
  &end_tag(\@stack,\@parstack,$token);  
        }  
          
        if (exists $style_for_target{'/'."$token->[1]"}) {  
  if ($Apache::lonxml::redirection) {  
    $Apache::lonxml::outputstack['-1'] .=    
      &recurse($style_for_target{'/'."$token->[1]"},  
       $target,$safeeval,\%style_for_target,@parstack);  
  } else {  
    $finaloutput .= &recurse($style_for_target{'/'."$token->[1]"},  
     $target,$safeeval,\%style_for_target,  
     @parstack);  
  }  
   
        } else {   my $finaloutput = &inner_xmlparse($target,\@stack,\@parstack,\@pars,
  $result = &callsub("end_$token->[1]", $target, $token, \@stack,      $safeeval,\%style_for_target);
     \@parstack, \@pars,$safeeval, \%style_for_target);  
        }  
      } else {  
        &Apache::lonxml::error("Unknown token event :$token->[0]:$token->[1]:");  
      }  
      #evaluate variable refs in result  
      if ($result ne "") {  
        if ( $#parstack > -1 ) {  
  if ($Apache::lonxml::redirection) {  
    $Apache::lonxml::outputstack['-1'] .=   
      &Apache::run::evaluate($result,$safeeval,$parstack[$#parstack]);  
  } else {  
    $finaloutput .= &Apache::run::evaluate($result,$safeeval,  
   $parstack[$#parstack]);  
  }  
        } else {  
  $finaloutput .= &Apache::run::evaluate($result,$safeeval,'');  
        }  
        $result = '';  
      }   
      if ($token->[0] eq 'E') {   
        &end_tag(\@stack,\@parstack,$token);  
      }  
    }  
    pop @pars;  
    pop @Apache::lonxml::pwd;  
  }  
   
 # if ($target eq 'meta') {   return $finaloutput;
 #   $finaloutput.=&endredirection;  }
 # }  
   
   if (($ENV{'QUERY_STRING'}) && ($target eq 'web')) {  sub htmlclean {
       $finaloutput=&afterburn($finaloutput);      my ($raw,$full)=@_;
   
       my $tree = HTML::TreeBuilder->new;
       $tree->ignore_unknown(0);
       
       $tree->parse($raw);
   
       my $output= $tree->as_HTML(undef,' ');
        
       $output=~s/\<(br|hr|img|meta|allow)([^\>\/]*)\>/\<$1$2 \/\>/gis;
       $output=~s/\<\/(br|hr|img|meta|allow)\>//gis;
       unless ($full) {
          $output=~s/\<[\/]*(body|head|html)\>//gis;
       }
   
       $tree = $tree->delete;
   
       return $output;
   }
   
   sub inner_xmlparse {
     my ($target,$stack,$parstack,$pars,$safeeval,$style_for_target)=@_;
     &Apache::lonxml::debug('Reentrant parser starting, again?');
     my $finaloutput = '';
     my $result;
     my $token;
     while ( $#$pars > -1 ) {
       while ($token = $$pars['-1']->get_token) {
         if (($token->[0] eq 'T') || ($token->[0] eq 'C') || ($token->[0] eq 'D') ) {
    if ($metamode<1) {
     $result=$token->[1];
    }
         } elsif ($token->[0] eq 'PI') {
    if ($metamode<1) {
     $result=$token->[2];
    }
         } elsif ($token->[0] eq 'S') {
    # add tag to stack    
    push (@$stack,$token->[1]);
    # add parameters list to another stack
    push (@$parstack,&parstring($token));
    &increasedepth($token);       
    if (exists $$style_for_target{$token->[1]}) {
     if ($Apache::lonxml::redirection) {
       $Apache::lonxml::outputstack['-1'] .=  
         &recurse($$style_for_target{$token->[1]},$target,$safeeval,
          $style_for_target,@$parstack);
     } else {
       $finaloutput .= &recurse($$style_for_target{$token->[1]},$target,
        $safeeval,$style_for_target,@$parstack);
     }
    } else {
     $result = &callsub("start_$token->[1]", $target, $token, $stack,
        $parstack, $pars, $safeeval, $style_for_target);
    }              
         } elsif ($token->[0] eq 'E') {
    #clear out any tags that didn't end
    while ($token->[1] ne $$stack['-1'] && ($#$stack > -1)) {
     &Apache::lonxml::warning("Unbalanced tags in resource $$stack['-1']");
     &end_tag($stack,$parstack,$token);
    }
   
    if (exists $$style_for_target{'/'."$token->[1]"}) {
     if ($Apache::lonxml::redirection) {
       $Apache::lonxml::outputstack['-1'] .=  
         &recurse($$style_for_target{'/'."$token->[1]"},
          $target,$safeeval,$style_for_target,@$parstack);
     } else {
       $finaloutput .= &recurse($$style_for_target{'/'."$token->[1]"},
        $target,$safeeval,$style_for_target,
        @$parstack);
     }
       
    } else {
     $result = &callsub("end_$token->[1]", $target, $token, $stack,
        $parstack, $pars,$safeeval, $style_for_target);
    }
         } else {
    &Apache::lonxml::error("Unknown token event :$token->[0]:$token->[1]:");
         }
         #evaluate variable refs in result
         if ($result ne "") {
    if ( $#$parstack > -1 ) {
     if ($Apache::lonxml::redirection) {
       $Apache::lonxml::outputstack['-1'] .= 
         &Apache::run::evaluate($result,$safeeval,$$parstack['-1']);
     } else {
       $finaloutput .= &Apache::run::evaluate($result,$safeeval,
      $$parstack['-1']);
     }
    } else {
     $finaloutput .= &Apache::run::evaluate($result,$safeeval,'');
    }
    $result = '';
         } 
         if ($token->[0] eq 'E') { 
    &end_tag($stack,$parstack,$token);
         }
       }
       pop @$pars;
       pop @Apache::lonxml::pwd;
   }    }
   
  return $finaloutput;    # if ($target eq 'meta') {
 }    #   $finaloutput.=&endredirection;
     # }
   
     if (($ENV{'QUERY_STRING'}) && ($target eq 'web')) {
       $finaloutput=&afterburn($finaloutput);
     }
     return $finaloutput;
   }
   
 sub recurse {  sub recurse {
     
   my @innerstack = ();     my @innerstack = (); 
   my @innerparstack = ();    my @innerparstack = ();
   my ($newarg,$target,$safeeval,$style_for_target,@parstack) = @_;    my ($newarg,$target,$safeeval,$style_for_target,@parstack) = @_;
Line 464  sub callsub { Line 606  sub callsub {
   
 sub setup_globals {  sub setup_globals {
   my ($target)=@_;    my ($target)=@_;
     $Apache::lonxml::registered = 0;
     @Apache::lonxml::pwd=();
   if ($target eq 'meta') {    if ($target eq 'meta') {
     $Apache::lonxml::redirection = 0;      $Apache::lonxml::redirection = 0;
     $Apache::lonxml::metamode = 1;      $Apache::lonxml::metamode = 1;
Line 498  sub init_safespace { Line 642  sub init_safespace {
   $safeeval->permit(":base_math");    $safeeval->permit(":base_math");
   $safeeval->permit("sort");    $safeeval->permit("sort");
   $safeeval->deny(":base_io");    $safeeval->deny(":base_io");
     $safehole->wrap(\&Apache::scripttag::xmlparse,$safeeval,'&xmlparse');
   $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');    $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');
       
   $safehole->wrap(\&Math::Cephes::asin,$safeeval,'&asin');    $safehole->wrap(\&Math::Cephes::asin,$safeeval,'&asin');
Line 680  sub parstring { Line 825  sub parstring {
   
 sub writeallows {  sub writeallows {
     my $thisurl='/res/'.&Apache::lonnet::declutter(shift);      my $thisurl='/res/'.&Apache::lonnet::declutter(shift);
       if ($ENV{'httpref.'.$thisurl}) {
    $thisurl=$ENV{'httpref.'.$thisurl};
       }
     my $thisdir=$thisurl;      my $thisdir=$thisurl;
     $thisdir=~s/\/[^\/]+$//;      $thisdir=~s/\/[^\/]+$//;
     my %httpref=();      my %httpref=();
Line 767  SIMPLECONTENT Line 915  SIMPLECONTENT
 <form method="post">  <form method="post">
 <textarea cols="80" rows="40" name="filecont">$filecontents</textarea>  <textarea cols="80" rows="40" name="filecont">$filecontents</textarea>
 <br />  <br />
 <input type="submit" name="savethisfile" value="Save this file" />  <input type="submit" name="attemptclean" 
          value="Save and then attempt to clean HTML" />
   <input type="submit" name="savethisfile" value="Save this" />
 </form>  </form>
 ENDFOOTER  ENDFOOTER
       $result=~s/(\<body[^\>]*\>)/$1$editheader/is;        $result=~s/(\<body[^\>]*\>)/$1$editheader/is;
Line 798  sub handler { Line 948  sub handler {
 # Edit action? Save file.  # Edit action? Save file.
 #  #
   unless ($ENV{'request.state'} eq 'published') {    unless ($ENV{'request.state'} eq 'published') {
       if ($ENV{'form.savethisfile'}) {        if (($ENV{'form.savethisfile'}) || ($ENV{'form.attemptclean'})) {
   &storefile($file,$ENV{'form.filecont'});    &storefile($file,$ENV{'form.filecont'});
       }        }
   }    }
Line 818  sub handler { Line 968  sub handler {
 ENDNOTFOUND  ENDNOTFOUND
     $filecontents='';      $filecontents='';
   } else {    } else {
         unless ($ENV{'request.state'} eq 'published') {
            if ($ENV{'form.attemptclean'}) {
       $filecontents=&htmlclean($filecontents,1);
            }
         }
     $result = &Apache::lonxml::xmlparse($target,$filecontents,'',%mystyle);      $result = &Apache::lonxml::xmlparse($target,$filecontents,'',%mystyle);
   }    }
   

Removed from v.1.98  
changed lines
  Added in v.1.118


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