--- rat/lonpageflip.pm 2001/05/03 15:54:06 1.15 +++ rat/lonpageflip.pm 2005/11/09 11:39:00 1.58 @@ -2,23 +2,36 @@ # # Page flip handler # -# (Page Handler +# $Id: lonpageflip.pm,v 1.58 2005/11/09 11:39:00 www Exp $ # -# (TeX Content Handler +# Copyright Michigan State University Board of Trustees # -# 05/29/00,05/30 Gerd Kortemeyer) -# 08/30,08/31,09/06,09/14,09/15,09/16,09/19,09/20,09/21,09/23, -# 10/02 Gerd Kortemeyer) +# This file is part of the LearningOnline Network with CAPA (LON-CAPA). +# +# LON-CAPA is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# LON-CAPA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LON-CAPA; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# /home/httpd/html/adm/gpl.txt +# +# http://www.lon-capa.org/ # -# 10/03,10/05,10/06,10/07,10/09,10/10,10/11,10/16,10/17, -# 11/14,11/16, -# 10/01/01,05/01 Gerd Kortemeyer package Apache::lonpageflip; use strict; use Apache::Constants qw(:common :http REDIRECT); -use Apache::lonnet(); +use Apache::lonnet; use HTML::TokeParser; use GDBM_File; @@ -26,21 +39,53 @@ use GDBM_File; my %hash; +sub cleanup { + if (tied(%hash)){ + &Apache::lonnet::logthis('Cleanup pageflip: hash'); + unless (untie(%hash)) { + &Apache::lonnet::logthis('Failed cleanup pageflip: hash'); + } + } +} + sub addrid { my ($current,$new,$condid)=@_; unless ($condid) { $condid=0; } - if (&Apache::lonnet::allowed('bre',$hash{'src_'.$new})) { + if ($current) { $current.=','.$new; } else { $current=''.$new; } - } + return $current; } +sub fullmove { + my ($rid,$mapurl,$direction)=@_; + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640)) { + ($rid,$mapurl)=&move($rid,$mapurl,$direction); + untie(%hash); + } + return($rid,$mapurl); +} + +sub hash_src { + my ($id)=@_; + my ($mapid,$resid)=split(/\./,$id); + my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid}, + $resid,$hash{'src_'.$id}); + if ($hash{'encrypted_'.$id}) { + return (&Apache::lonenc::encrypted($hash{'src_'.$id}), + &Apache::lonenc::encrypted($symb)); + } + return ($hash{'src_'.$id},$symb); +} + sub move { my ($rid,$mapurl,$direction)=@_; + my $startoutrid=$rid; my $next=''; @@ -48,8 +93,8 @@ sub move { my $posnext=''; if ($direction eq 'forward') { # --------------------------------------------------------------------- Forward - if ($hash{'type_'.$rid} eq 'finish') { - $rid=$hash{'ids_/res/'.$mapurl}; + while ($hash{'type_'.$rid} eq 'finish') { + $rid=$hash{'ids_'.$hash{'map_id_'.(split(/\./,$rid))[0]}}; } map { my $thiscond= @@ -71,17 +116,26 @@ sub move { } } split(/\,/,$posnext); if ($hash{'is_map_'.$next}) { +# This jumps to the beginning of a new map (going down level) if ( $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'sequence') { $mapurl=$hash{'src_'.$next}; $next=$hash{'map_start_'.$hash{'src_'.$next}}; + } elsif ( +# This jumps back up from an empty sequence, to a page up one level + $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'page') { + $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]}; } + } elsif + ((split(/\./,$startoutrid))[0]!=(split(/\./,$next))[0]) { +# This comes up from a map (coming up one level); + $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]}; } } elsif ($direction eq 'back') { # ------------------------------------------------------------------- Backwards - if ($hash{'type_'.$rid} eq 'start') { - $rid=$hash{'ids_/res/'.$mapurl}; - } + while ($hash{'type_'.$rid} eq 'start') { + $rid=$hash{'ids_'.$hash{'map_id_'.(split(/\./,$rid))[0]}}; + } map { my $thiscond= &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$_}}); @@ -102,21 +156,47 @@ sub move { } } split(/\,/,$posnext); if ($hash{'is_map_'.$next}) { +# This jumps to the end of a new map (going down one level) if ( $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'sequence') { $mapurl=$hash{'src_'.$next}; $next=$hash{'map_finish_'.$hash{'src_'.$next}}; - } + } elsif ( + $hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$next}}} eq 'page') { +# This jumps back up from an empty sequence, to a page up one level + $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]}; + } + } elsif + ((split(/\./,$startoutrid))[0]!=(split(/\./,$next))[0]) { +# This comes back up from a map (going up one level); + $mapurl=$hash{'map_id_'.(split(/\./,$next))[0]}; } - } elsif ($direction eq 'up') { -# -------------------------------------------------------------------------- Up - } elsif ($direction eq 'down') { -# ------------------------------------------------------------------------ Down } - return ($next,$mapurl); } +sub navlaunch { + my ($r)=@_; + &Apache::loncommon::content_type($r,'text/html'); + &Apache::loncommon::no_cache($r); + $r->send_http_header; + my $html=&Apache::lonxml::xmlbegin(); + $r->print("$html\n"); + $r->print(''. + &Apache::loncommon::bodytag('Launched')); + $r->print(<Goto first resource

+ +

Collapse external navigation window

+ENDNAV + $r->print(&Apache::loncommon::endbodytag().''); +} # ================================================================ Main Handler sub handler { @@ -125,89 +205,136 @@ sub handler { # ------------------------------------------- Set document type for header only if ($r->header_only) { - $r->content_type('text/html'); - $r->send_http_header; - return OK; + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + return OK; } my %cachehash=(); my $multichoice=0; my %multichoicehash=(); - my $redirecturl=''; + my ($redirecturl,$redirectsymb); my $next=''; my @possibilities=(); - - if (($ENV{'form.postdata'})&&($ENV{'request.course.fn'})) { - $ENV{'form.postdata'}=~/(\w+)\:(.*)/; + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['postdata']); + if (($env{'form.postdata'})&&($env{'request.course.fn'})) { + $env{'form.postdata'}=~/(\w+)\:(.*)/; my $direction=$1; my $currenturl=$2; - if ($direction eq 'return') { + if ($currenturl=~m|^/enc/|) { + $currenturl=&Apache::lonenc::unencrypted($currenturl); + } + $currenturl=~s/\.\d+\.(\w+)$/\.$1/; + if ($direction eq 'firstres') { + my $furl; + if (tie(my %bighash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640)) { + $furl=$bighash{'first_url'}; + untie(%bighash); + } + &Apache::loncommon::content_type($r,'text/html'); + $r->header_out(Location => + 'http://'.$ENV{'HTTP_HOST'}.$furl); + + return REDIRECT; + } + if ($direction eq 'return' || $direction eq 'navlaunch') { # -------------------------------------------------------- Return to last known my $last; - if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db', - &GDBM_READER,0640)) { + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', + &GDBM_READER(),0640)) { $last=$hash{'last_known'}; untie(%hash); } my $newloc; - if ($last) { - $newloc='/res/'.(split(/\_\_\_/,$last))[1]; + if (($last) && (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640))) { + my ($murl,$id,$fn)=&Apache::lonnet::decode_symb($last); + $id=$hash{'map_pc_'.&Apache::lonnet::clutter($murl)}.'.'.$id; + $newloc=$hash{'src_'.$id}; + if ($newloc) { + if ($hash{'encrypted_'.$id}) { $newloc=&Apache::lonenc::encrypted($newloc); } + + } else { + $newloc='/adm/navmaps'; + } + untie %hash; } else { - $newloc='/adm/noidea.html'; + $newloc='/adm/navmaps'; } - $r->content_type('text/html'); - $r->header_out(Location => - 'http://'.$ENV{'HTTP_HOST'}.$newloc); - - return REDIRECT; + if ($newloc eq '/adm/navmaps' && $direction eq 'navlaunch') { + &navlaunch($r); + return OK; + } else { + &Apache::loncommon::content_type($r,'text/html'); + $r->header_out(Location => + 'http://'.$ENV{'HTTP_HOST'}.$newloc); + + return REDIRECT; + } } $currenturl=~s/^http\:\/\///; $currenturl=~s/^[^\/]+//; - unless ($currenturl=~/\/res\//) { +# +# Is the current URL on the map? If not, start with last known URL +# + unless (&Apache::lonnet::is_on_map($currenturl)) { my $last; - if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db', - &GDBM_READER,0640)) { + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', + &GDBM_READER(),0640)) { $last=$hash{'last_known'}; untie(%hash); } if ($last) { - $currenturl='/res/'.(split(/\_\_\_/,$last))[1]; + $currenturl=&Apache::lonnet::clutter((&Apache::lonnet::decode_symb($last))[2]); } else { - $r->content_type('text/html'); - $r->header_out(Location => - 'http://'.$ENV{'HTTP_HOST'}.'/adm/noidea.html'); - return REDIRECT; + if ($direction eq 'return') { + &Apache::loncommon::content_type($r,'text/html'); + $r->header_out(Location => + 'http://'.$ENV{'HTTP_HOST'}.'/adm/noidea.html'); + return REDIRECT; + } else { + &navlaunch($r); + return OK; + } } } # ------------------------------------------- Do we have any idea where we are? my $position; if ($position=Apache::lonnet::symbread($currenturl)) { # ------------------------------------------------------------------------- Yes - my ($mapurl,$mapnum,$thisurl)=split(/\_\_\_/,$position); - $cachehash{$thisurl}=$mapnum; + my ($startoutmap,$mapnum,$thisurl)=&Apache::lonnet::decode_symb($position); + $cachehash{$startoutmap}{$thisurl}=[$thisurl,$mapnum]; + $cachehash{$startoutmap}{'last_known'}= + [&Apache::lonnet::declutter($currenturl),$mapnum]; + # ============================================================ Tie the big hash - if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'.db', - &GDBM_READER,0640)) { - my $rid=$hash{'map_pc_/res/'.$mapurl}.'.'.$mapnum; + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640)) { + my $rid=$hash{'map_pc_'.&Apache::lonnet::clutter($startoutmap)}. + '.'.$mapnum; # ------------------------------------------------- Move forward, backward, etc - - ($next,$mapurl)=&move($rid,$mapurl,$direction); + my $endupmap; + ($next,$endupmap)=&move($rid,$startoutmap,$direction); # -------------------------------------- Do we have one and only one empty URL? my $safecount=0; - while (($next) && ($next!~/\,/) && (!$hash{'src_'.$next}) - && ($safecount<25)) { - ($next,$mapurl)=&move($next,$mapurl,$direction); + while (($next) && ($next!~/\,/) && + ((!$hash{'src_'.$next}) || + ((!$env{'request.role.adv'}) && $hash{'randomout_'.$next})) + && ($safecount<10000)) { + ($next,$endupmap)=&move($next,$endupmap,$direction); $safecount++; } +# We are now at at least one non-empty URL # ----------------------------------------------------- Check out possibilities if ($next) { @possibilities=split(/\,/,$next); if ($#possibilities==0) { # ---------------------------------------------- Only one possibility, redirect - $redirecturl=$hash{'src_'.$next}; - $cachehash{&Apache::lonnet::declutter($redirecturl)} - =(split(/\./,$next))[1]; + ($redirecturl,$redirectsymb)=&hash_src($next); + $cachehash{$endupmap}{$redirecturl}= + [$redirecturl,(split(/\./,$next))[1]]; } else { # ------------------------ There are multiple possibilities for a next resource $multichoice=1; @@ -215,12 +342,16 @@ sub handler { $multichoicehash{'src_'.$_}=$hash{'src_'.$_}; $multichoicehash{'title_'.$_}=$hash{'title_'.$_}; $multichoicehash{'type_'.$_}=$hash{'type_'.$_}; - $cachehash - {&Apache::lonnet::declutter( - $multichoicehash - {'src_'.$_} - )} - =(split(/\./,$_))[1]; + (my $first, my $second) = $_ =~ /(\d+).(\d+)/; + my $symbSrc = Apache::lonnet::declutter($hash{'src_'.$_}); + $multichoicehash{'symb_'.$_} = + Apache::lonnet::declutter($hash{'map_id_'.$first}.'___'. + $second.'___'.$symbSrc); + + my ($choicemap,$choiceres)=split(/\./,$_); + my $map=&Apache::lonnet::declutter($hash{'src_'.$choicemap}); + my $url=$multichoicehash{'src_'.$_}; + $cachehash{$map}{$url}=[$url,$choiceres]; } @possibilities; } } else { @@ -230,49 +361,82 @@ sub handler { # ----------------- The program must come past this point to untie the big hash untie(%hash); # --------------------------------------------------------- Store position info - $cachehash{'last_direction'}=$direction; - $cachehash{'last_known'}=&Apache::lonnet::declutter($currenturl); - &Apache::lonnet::symblist($mapurl,%cachehash); + $cachehash{$startoutmap}{'last_direction'}=[$direction,'notasymb']; + foreach my $thismap (keys %cachehash) { + my $mapnum=$cachehash{$thismap}->{'mapnum'}; + delete($cachehash{$thismap}->{'mapnum'}); + &Apache::lonnet::symblist($thismap, + %{$cachehash{$thismap}}); + } # ============================================== Do not return before this line if ($redirecturl) { # ----------------------------------------------------- There is a URL to go to - $r->content_type('text/html'); - $r->header_out(Location => - 'http://'.$ENV{'HTTP_HOST'}.$redirecturl); + if ($direction eq 'forward') { + &Apache::lonnet::linklog($currenturl,$redirecturl); + } + if ($direction eq 'back') { + &Apache::lonnet::linklog($redirecturl,$currenturl); + } +# ------------------------------------------------- Check for critical messages + if ((time-$env{'user.criticalcheck.time'})>300) { + my @what=&Apache::lonnet::dump + ('critical',$env{'user.domain'}, + $env{'user.name'}); + if ($what[0]) { + if (($what[0] ne 'con_lost') && + ($what[0]!~/^error\:/)) { + $redirecturl='/adm/email?critical=display'; + $redirectsymb=''; + } + } + &Apache::lonnet::appenv('user.criticalcheck.time'=>time); + } + + &Apache::loncommon::content_type($r,'text/html'); + my $url='http://'.$ENV{'HTTP_HOST'}.$redirecturl; + if ($redirectsymb ne '') { $url.='?symb='.&Apache::lonnet::escape($redirectsymb); } + $r->header_out(Location => $url); return REDIRECT; } else { # --------------------------------------------------------- There was a problem - $r->content_type('text/html'); + &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; if ($#possibilities>0) { + my $bodytag= + &Apache::loncommon::bodytag('Multiple Resources'); $r->print(<Choose Next Location - -

LON-CAPA

-There are several possibilities of where to go next. +$bodytag +

There are several possibilities of where to go next

Please click on the the resource you intend to access:

ENDSTART - map { + foreach (@possibilities) { $r->print( ''); - } @possibilities; + } $r->print('
TitleType
'. + $multichoicehash{'src_'.$_}.'?symb=' . + Apache::lonnet::escape($multichoicehash{'symb_'.$_}).'">'. $multichoicehash{'title_'.$_}. ''.$multichoicehash{'type_'.$_}. '
'); return OK; } else { + my $bodytag=&Apache::loncommon::bodytag('No Resource'); $r->print(<Choose Next Location - - -

Sorry!

-

Next resource could not be identified.

+No Resource +$bodytag +

Next resource could not be identified.

+

You probably are at the beginning or the end of the +course.

+ ENDNONE @@ -281,16 +445,19 @@ ENDNONE } } else { # ------------------------------------------------- Problem, could not tie hash - $ENV{'user.error.msg'}="/adm/flip:bre:0:1:Course Data Missing"; + $env{'user.error.msg'}="/adm/flip:bre:0:1:Course Data Missing"; return HTTP_NOT_ACCEPTABLE; } } else { # ---------------------------------------- No, could not determine where we are - $r->internal_redirect('/adm/ambiguous'); + if ( &Apache::lonnet::mod_perl_version() == 2 ) { + &Apache::lonnet::cleanenv(); + } + $r->internal_redirect('/adm/ambiguous'); } } else { # -------------------------- Class was not initialized or page fliped strangely - $ENV{'user.error.msg'}="/adm/flip:bre:0:0:Choose Course"; + $env{'user.error.msg'}="/adm/flip:bre:0:0:Choose Course"; return HTTP_NOT_ACCEPTABLE; } } 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.