Annotation of rat/lonuserstate.pm, revision 1.134

1.1       www         1: # The LearningOnline Network with CAPA
                      2: # Construct and maintain state and binary representation of course for user
                      3: #
1.134   ! www         4: # $Id: lonuserstate.pm,v 1.133 2009/11/15 21:31:23 raeburn Exp $
1.25      www         5: #
                      6: # Copyright Michigan State University Board of Trustees
                      7: #
                      8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      9: #
                     10: # LON-CAPA is free software; you can redistribute it and/or modify
                     11: # it under the terms of the GNU General Public License as published by
                     12: # the Free Software Foundation; either version 2 of the License, or
                     13: # (at your option) any later version.
                     14: #
                     15: # LON-CAPA is distributed in the hope that it will be useful,
                     16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     18: # GNU General Public License for more details.
                     19: #
                     20: # You should have received a copy of the GNU General Public License
                     21: # along with LON-CAPA; if not, write to the Free Software
                     22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     23: #
                     24: # /home/httpd/html/adm/gpl.txt
                     25: #
                     26: # http://www.lon-capa.org/
                     27: #
1.26      harris41   28: ###
1.1       www        29: 
                     30: package Apache::lonuserstate;
                     31: 
1.26      harris41   32: # ------------------------------------------------- modules used by this module
1.1       www        33: use strict;
                     34: use HTML::TokeParser;
1.89      albertel   35: use Apache::lonnet;
1.114     www        36: use Apache::lonlocal;
1.26      harris41   37: use Apache::loncommon();
1.1       www        38: use GDBM_File;
1.12      www        39: use Apache::lonmsg;
1.15      www        40: use Safe;
1.21      www        41: use Safe::Hole;
1.15      www        42: use Opcode;
1.73      www        43: use Apache::lonenc;
1.96      albertel   44: use Fcntl qw(:flock);
1.114     www        45: use LONCAPA;
                     46:  
1.15      www        47: 
1.1       www        48: # ---------------------------------------------------- Globals for this package
                     49: 
                     50: my $pc;      # Package counter
                     51: my %hash;    # The big tied hash
1.19      www        52: my %parmhash;# The hash with the parameters
1.1       www        53: my @cond;    # Array with all of the conditions
                     54: my $errtext; # variable with all errors
1.116     www        55: my $retfrid; # variable with the very first RID in the course
                     56: my $retfurl; # first URL
1.29      www        57: my %randompick; # randomly picked resources
1.51      www        58: my %randompickseed; # optional seed for randomly picking resources
1.124     albertel   59: my %randomorder; # maps to order contents randomly
1.73      www        60: my %encurl; # URLs in this folder are supposed to be encrypted
                     61: my %hiddenurl; # this URL (or complete folder) is supposed to be hidden
1.61      www        62: 
                     63: # ----------------------------------- Remove version from URL and store in hash
                     64: 
1.134   ! www        65: sub versionerror {
        !            66:     my ($uri,$usedversion,$unusedversion)=@_;
        !            67:     return '<br />'.&mt('Version discrepancy: resource [_1] included in both version [_2] and version [_3]. Using version [_2].',
        !            68:                     $uri,$usedversion,$unusedversion).'<br />';
        !            69: }
        !            70: 
1.61      www        71: sub versiontrack {
                     72:     my $uri=shift;
                     73:     if ($uri=~/\.(\d+)\.\w+$/) {
                     74: 	my $version=$1;
                     75: 	$uri=~s/\.\d+\.(\w+)$/\.$1/;
1.62      www        76:         unless ($hash{'version_'.$uri}) {
                     77: 	    $hash{'version_'.$uri}=$version;
1.134   ! www        78: 	} elsif ($version!=$hash{'version_'.$uri}) {
        !            79:             $errtext.=&versionerror($uri,$hash{'version_'.$uri},$version);
        !            80:         }
1.61      www        81:     }
                     82:     return $uri;
                     83: }
                     84: 
                     85: # -------------------------------------------------------------- Put in version
                     86: 
                     87: sub putinversion {
                     88:     my $uri=shift;
1.93      www        89:     my $key=$env{'request.course.id'}.'_'.&Apache::lonnet::clutter($uri);
1.61      www        90:     if ($hash{'version_'.$uri}) {
                     91: 	my $version=$hash{'version_'.$uri};
1.65      www        92: 	if ($version eq 'mostrecent') { return $uri; }
1.66      www        93: 	if ($version eq &Apache::lonnet::getversion(
                     94: 			&Apache::lonnet::filelocation('',$uri))) 
                     95: 	             { return $uri; }
1.61      www        96: 	$uri=~s/\.(\w+)$/\.$version\.$1/;
                     97:     }
1.93      www        98:     &Apache::lonnet::do_cache_new('courseresversion',$key,&Apache::lonnet::declutter($uri),600);
1.61      www        99:     return $uri;
                    100: }
                    101: 
                    102: # ----------------------------------------- Processing versions file for course
                    103: 
                    104: sub processversionfile {
1.64      www       105:     my %cenv=@_;
1.61      www       106:     my %versions=&Apache::lonnet::dump('resourceversions',
                    107: 				       $cenv{'domain'},
                    108: 				       $cenv{'num'});
1.106     albertel  109:     foreach my $ver (keys(%versions)) {
                    110: 	if ($ver=~/^error\:/) { return; }
                    111: 	$hash{'version_'.$ver}=$versions{$ver};
1.61      www       112:     }
                    113: }
1.45      www       114: 
1.1       www       115: # --------------------------------------------------------- Loads map from disk
                    116: 
                    117: sub loadmap { 
1.124     albertel  118:     my ($uri,$parent_rid)=@_;
1.114     www       119:     if ($hash{'map_pc_'.$uri}) { 
1.120     albertel  120: 	$errtext.='<p class="LC_error">'.
                    121: 	    &mt('Multiple use of sequence/page [_1]! The course will not function properly.','<tt>'.$uri.'</tt>').
                    122: 	    '</p>';
1.114     www       123: 	return; 
                    124:     }
1.1       www       125:     $pc++;
                    126:     my $lpc=$pc;
                    127:     $hash{'map_pc_'.$uri}=$lpc;
                    128:     $hash{'map_id_'.$lpc}=$uri;
                    129: 
1.37      www       130: # Determine and check filename
1.62      www       131:     my $fn=&Apache::lonnet::filelocation('',&putinversion($uri));
1.37      www       132: 
                    133:     my $ispage=($fn=~/\.page$/);
1.1       www       134: 
1.10      www       135:     unless (($fn=~/\.sequence$/) ||
1.1       www       136:             ($fn=~/\.page$/)) { 
1.114     www       137: 	$errtext.=&mt("<br />Invalid map: <tt>[_1]</tt>",$fn);
1.98      albertel  138: 	return; 
1.1       www       139:     }
                    140: 
1.37      www       141:     my $instr=&Apache::lonnet::getfile($fn);
                    142: 
1.124     albertel  143:     if ($instr eq -1) {
                    144:         $errtext.=&mt('<br />Map not loaded: The file <tt>[_1]</tt> does not exist.',$fn);
                    145: 	return;
                    146:     }
1.22      www       147: 
1.37      www       148: # Successfully got file, parse it
1.1       www       149: 
1.124     albertel  150:     my $parser = HTML::TokeParser->new(\$instr);
                    151:     $parser->attr_encoded(1);
                    152:     # first get all parameters
                    153:     while (my $token = $parser->get_token) {
                    154: 	next if ($token->[0] ne 'S');
                    155: 	if ($token->[1] eq 'param') {
                    156: 	    &parse_param($token,$lpc);
                    157: 	} 
                    158:     }
                    159:     #reset parser
                    160:     $parser = HTML::TokeParser->new(\$instr);
                    161:     $parser->attr_encoded(1);
1.1       www       162: 
1.124     albertel  163:     my $linkpc=0;
1.1       www       164: 
1.124     albertel  165:     $fn=~/\.(\w+)$/;
1.1       www       166: 
1.124     albertel  167:     $hash{'map_type_'.$lpc}=$1;
1.1       www       168: 
1.124     albertel  169:     my $randomize = ($randomorder{$parent_rid} =~ /^yes$/i);
1.1       www       170: 
1.124     albertel  171:     my @map_ids;
                    172:     while (my $token = $parser->get_token) {
                    173: 	next if ($token->[0] ne 'S');
                    174: 	if ($token->[1] eq 'resource') {
                    175: 	    push(@map_ids,&parse_resource($token,$lpc,$ispage,$uri));
                    176: 	} elsif ($token->[1] eq 'link' && !$randomize) {
1.1       www       177: # ----------------------------------------------------------------------- Links
1.124     albertel  178: 	    &make_link(++$linkpc,$lpc,$token->[2]->{'to'},
                    179: 		       $token->[2]->{'from'},
                    180: 		       $token->[2]->{'condition'});
                    181: 	} elsif ($token->[1] eq 'condition' && !$randomize) {
                    182: 	    &parse_condition($token,$lpc);
                    183: 	}
                    184:     }
1.1       www       185: 
1.124     albertel  186:     if ($randomize) {
                    187: 	if (!$env{'request.role.adv'}) {
                    188: 	    my $seed;
                    189: 	    if (defined($randompickseed{$parent_rid})) {
                    190: 		$seed = $randompickseed{$parent_rid};
                    191: 	    } else {
                    192: 		my ($mapid,$resid)=split(/\./,$parent_rid);
                    193: 		my $symb=
                    194: 		    &Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},
                    195: 						 $resid,$hash{'src_'.$parent_rid});
1.85      albertel  196: 		
1.124     albertel  197: 		$seed = $symb;
                    198: 	    }
                    199: 	
                    200: 	    my $rndseed=&Apache::lonnet::rndseed($seed);
                    201: 	    &Apache::lonnet::setup_random_from_rndseed($rndseed);
                    202: 	    @map_ids=&Math::Random::random_permutation(@map_ids);
                    203: 	}
                    204: 	my $from = shift(@map_ids);
                    205: 	my $from_rid = $lpc.'.'.$from;
                    206: 	$hash{'map_start_'.$uri} = $from_rid;
                    207: 	$hash{'type_'.$from_rid}='start';
                    208: 
                    209: 	while (my $to = shift(@map_ids)) {
                    210: 	    &make_link(++$linkpc,$lpc,$to,$from);
                    211: 	    my $to_rid =  $lpc.'.'.$to;
                    212: 	    $hash{'type_'.$to_rid}='normal';
                    213: 	    $from = $to;
                    214: 	    $from_rid = $to_rid;
                    215: 	}
1.1       www       216: 
1.124     albertel  217: 	$hash{'map_finish_'.$uri}= $from_rid;
                    218: 	$hash{'type_'.$from_rid}='finish';
1.1       www       219:     }
1.121     albertel  220: 
1.127     albertel  221:     $parser = HTML::TokeParser->new(\$instr);
1.121     albertel  222:     $parser->attr_encoded(1);
                    223:     # last parse out the mapalias params so as to ignore anything
                    224:     # refering to non-existant resources
                    225:     while (my $token = $parser->get_token) {
                    226: 	next if ($token->[0] ne 'S');
                    227: 	if ($token->[1] eq 'param') {
                    228: 	    &parse_mapalias_param($token,$lpc);
                    229: 	} 
                    230:     }
                    231: }
                    232: 
1.124     albertel  233: 
                    234: # -------------------------------------------------------------------- Resource
                    235: sub parse_resource {
                    236:     my ($token,$lpc,$ispage,$uri) = @_;
                    237:     if ($token->[2]->{'type'} eq 'zombie') { next; }
                    238:     my $rid=$lpc.'.'.$token->[2]->{'id'};
                    239: 	    
                    240:     $hash{'kind_'.$rid}='res';
                    241:     $hash{'title_'.$rid}=$token->[2]->{'title'};
                    242:     my $turi=&versiontrack($token->[2]->{'src'});
                    243:     if ($token->[2]->{'version'}) {
                    244: 	unless ($hash{'version_'.$turi}) {
                    245: 	    $hash{'version_'.$turi}=$1;
                    246: 	}
                    247:     }
                    248:     my $title=$token->[2]->{'title'};
                    249:     $title=~s/\&colon\;/\:/gs;
                    250: #   my $symb=&Apache::lonnet::encode_symb($uri,
                    251: #					  $token->[2]->{'id'},
                    252: #					  $turi);
                    253: #   &Apache::lonnet::do_cache_new('title',$symb,$title);
                    254:     unless ($ispage) {
                    255: 	$turi=~/\.(\w+)$/;
                    256: 	my $embstyle=&Apache::loncommon::fileembstyle($1);
                    257: 	if ($token->[2]->{'external'} eq 'true') { # external
1.130     raeburn   258: 	    $turi=~s/^https?\:\/\//\/adm\/wrapper\/ext\//;
1.124     albertel  259: 	} elsif ($turi=~/^\/*uploaded\//) { # uploaded
                    260: 	    if (($embstyle eq 'img') 
                    261: 		|| ($embstyle eq 'emb')
                    262: 		|| ($embstyle eq 'wrp')) {
                    263: 		$turi='/adm/wrapper'.$turi;
                    264: 	    } elsif ($embstyle eq 'ssi') {
                    265: 		#do nothing with these
                    266: 	    } elsif ($turi!~/\.(sequence|page)$/) {
                    267: 		$turi='/adm/coursedocs/showdoc'.$turi;
                    268: 	    }
                    269: 	} elsif ($turi=~/\S/) { # normal non-empty internal resource
                    270: 	    my $mapdir=$uri;
                    271: 	    $mapdir=~s/[^\/]+$//;
                    272: 	    $turi=&Apache::lonnet::hreflocation($mapdir,$turi);
                    273: 	    if (($embstyle eq 'img') 
                    274: 		|| ($embstyle eq 'emb')
                    275: 		|| ($embstyle eq 'wrp')) {
                    276: 		$turi='/adm/wrapper'.$turi;
                    277: 	    }
                    278: 	}
                    279:     }
                    280: # Store reverse lookup, remove query string
                    281:     my $idsuri=$turi;
                    282:     $idsuri=~s/\?.+$//;
                    283:     if (defined($hash{'ids_'.$idsuri})) {
                    284: 	$hash{'ids_'.$idsuri}.=','.$rid;
                    285:     } else {
                    286: 	$hash{'ids_'.$idsuri}=''.$rid;
                    287:     }
                    288:     
                    289:     if ($turi=~/\/(syllabus|aboutme|navmaps|smppg|bulletinboard)$/) {
                    290: 	$turi.='?register=1';
                    291:     }
                    292:     
                    293:     $hash{'src_'.$rid}=$turi;
                    294:     
                    295:     if ($token->[2]->{'external'} eq 'true') {
                    296: 	$hash{'ext_'.$rid}='true:';
                    297:     } else {
                    298: 	$hash{'ext_'.$rid}='false:';
                    299:     }
                    300:     if ($token->[2]->{'type'}) {
                    301: 	$hash{'type_'.$rid}=$token->[2]->{'type'};
                    302: 	if ($token->[2]->{'type'} eq 'start') {
                    303: 	    $hash{'map_start_'.$uri}="$rid";
                    304: 	}
                    305: 	if ($token->[2]->{'type'} eq 'finish') {
                    306: 	    $hash{'map_finish_'.$uri}="$rid";
                    307: 	}
                    308:     }  else {
                    309: 	$hash{'type_'.$rid}='normal';
                    310:     }
                    311:     
                    312:     if (($turi=~/\.sequence$/) ||
                    313: 	($turi=~/\.page$/)) {
                    314: 	$hash{'is_map_'.$rid}=1;
                    315: 	&loadmap($turi,$rid);
                    316:     } 
                    317:     return $token->[2]->{'id'};
                    318: }
                    319: 
                    320: sub make_link {
                    321:     my ($linkpc,$lpc,$to,$from,$condition) = @_;
                    322:     
                    323:     my $linkid=$lpc.'.'.$linkpc;
                    324:     my $goesto=$lpc.'.'.$to;
                    325:     my $comesfrom=$lpc.'.'.$from;
                    326:     my $undercond=0;
                    327: 
                    328:     if ($condition) {
                    329: 	$undercond=$lpc.'.'.$condition;
                    330:     }
                    331: 
                    332:     $hash{'goesto_'.$linkid}=$goesto;
                    333:     $hash{'comesfrom_'.$linkid}=$comesfrom;
                    334:     $hash{'undercond_'.$linkid}=$undercond;
                    335: 
                    336:     if (defined($hash{'to_'.$comesfrom})) {
                    337: 	$hash{'to_'.$comesfrom}.=','.$linkid;
                    338:     } else {
                    339: 	$hash{'to_'.$comesfrom}=''.$linkid;
                    340:     }
                    341:     if (defined($hash{'from_'.$goesto})) {
                    342: 	$hash{'from_'.$goesto}.=','.$linkid;
                    343:     } else {
                    344: 	$hash{'from_'.$goesto}=''.$linkid;
                    345:     }
                    346: }
                    347: 
                    348: # ------------------------------------------------------------------- Condition
                    349: sub parse_condition {
                    350:     my ($token,$lpc) = @_;
                    351:     my $rid=$lpc.'.'.$token->[2]->{'id'};
                    352:     
                    353:     $hash{'kind_'.$rid}='cond';
                    354: 
                    355:     my $condition = $token->[2]->{'value'};
                    356:     $condition =~ s/[\n\r]+/ /gs;
                    357:     push(@cond, $condition);
                    358:     $hash{'condid_'.$rid}=$#cond;
                    359:     if ($token->[2]->{'type'}) {
                    360: 	$cond[$#cond].=':'.$token->[2]->{'type'};
                    361:     }  else {
                    362: 	$cond[$#cond].=':normal';
                    363:     }
                    364: }
                    365: 
                    366: # ------------------------------------------------------------------- Parameter
                    367: 
                    368: sub parse_param {
                    369:     my ($token,$lpc) = @_;
                    370:     my $referid=$lpc.'.'.$token->[2]->{'to'};
                    371:     my $name=$token->[2]->{'name'};
                    372:     my $part;
                    373:     if ($name=~/^parameter_(.*)_/) {
                    374: 	$part=$1;
                    375:     } else {
                    376: 	$part=0;
                    377:     }
                    378:     $name=~s/^.*_([^_]*)$/$1/;
                    379:     my $newparam=
                    380: 	&escape($token->[2]->{'type'}).':'.
                    381: 	&escape($part.'.'.$name).'='.
                    382: 	&escape($token->[2]->{'value'});
                    383:     if (defined($hash{'param_'.$referid})) {
                    384: 	$hash{'param_'.$referid}.='&'.$newparam;
                    385:     } else {
                    386: 	$hash{'param_'.$referid}=''.$newparam;
                    387:     }
                    388:     if ($token->[2]->{'name'}=~/^parameter_(0_)*randompick$/) {
                    389: 	$randompick{$referid}=$token->[2]->{'value'};
                    390:     }
                    391:     if ($token->[2]->{'name'}=~/^parameter_(0_)*randompickseed$/) {
                    392: 	$randompickseed{$referid}=$token->[2]->{'value'};
                    393:     }
                    394:     if ($token->[2]->{'name'}=~/^parameter_(0_)*randomorder$/) {
                    395: 	$randomorder{$referid}=$token->[2]->{'value'};
                    396:     }
                    397:     if ($token->[2]->{'name'}=~/^parameter_(0_)*encrypturl$/) {
                    398: 	if ($token->[2]->{'value'}=~/^yes$/i) {
                    399: 	    $encurl{$referid}=1;
                    400: 	}
                    401:     }
                    402:     if ($token->[2]->{'name'}=~/^parameter_(0_)*hiddenresource$/) {
                    403: 	if ($token->[2]->{'value'}=~/^yes$/i) {
                    404: 	    $hiddenurl{$referid}=1;
                    405: 	}
                    406:     }
                    407: }
                    408: 
1.121     albertel  409: sub parse_mapalias_param {
                    410:     my ($token,$lpc) = @_;
                    411:     my $referid=$lpc.'.'.$token->[2]->{'to'};
                    412:     return if (!exists($hash{'src_'.$referid}));
                    413: 
                    414:     if ($token->[2]->{'name'}=~/^parameter_(0_)*mapalias$/) {
1.122     albertel  415: 	&count_mapalias($token->[2]->{'value'},$referid);
1.121     albertel  416: 	$hash{'mapalias_'.$token->[2]->{'value'}}=$referid;
                    417:     }
1.1       www       418: }
                    419: 
1.3       www       420: # --------------------------------------------------------- Simplify expression
                    421: 
                    422: sub simplify {
1.85      albertel  423:     my $expression=shift;
1.101     albertel  424: # (0&1) = 1
1.105     albertel  425:     $expression=~s/\(0\&([_\.\d]+)\)/$1/g;
1.3       www       426: # (8)=8
1.105     albertel  427:     $expression=~s/\(([_\.\d]+)\)/$1/g;
1.3       www       428: # 8&8=8
1.105     albertel  429:     $expression=~s/([^_\.\d])([_\.\d]+)\&\2([^_\.\d])/$1$2$3/g;
1.3       www       430: # 8|8=8
1.105     albertel  431:     $expression=~s/([^_\.\d])([_\.\d]+)\|\2([^_\.\d])/$1$2$3/g;
1.3       www       432: # (5&3)&4=5&3&4
1.105     albertel  433:     $expression=~s/\(([_\.\d]+)((?:\&[_\.\d]+)+)\)\&([_\.\d]+[^_\.\d])/$1$2\&$3/g;
1.3       www       434: # (((5&3)|(4&6)))=((5&3)|(4&6))
1.105     albertel  435:     $expression=~
                    436: 	s/\((\(\([_\.\d]+(?:\&[_\.\d]+)*\)(?:\|\([_\.\d]+(?:\&[_\.\d]+)*\))+\))\)/$1/g;
1.3       www       437: # ((5&3)|(4&6))|(1&2)=(5&3)|(4&6)|(1&2)
1.85      albertel  438:     $expression=~
1.105     albertel  439: 	s/\((\([_\.\d]+(?:\&[_\.\d]+)*\))((?:\|\([_\.\d]+(?:\&[_\.\d]+)*\))+)\)\|(\([_\.\d]+(?:\&[_\.\d]+)*\))/\($1$2\|$3\)/g;
1.85      albertel  440:     return $expression;
1.3       www       441: }
                    442: 
1.2       www       443: # -------------------------------------------------------- Build condition hash
                    444: 
                    445: sub traceroute {
1.77      www       446:     my ($sofar,$rid,$beenhere,$encflag,$hdnflag)=@_;
1.81      albertel  447:     my $newsofar=$sofar=simplify($sofar);
1.120     albertel  448:     unless ($beenhere=~/\&\Q$rid\E\&/) {
1.85      albertel  449: 	$beenhere.=$rid.'&';  
                    450: 	my ($mapid,$resid)=split(/\./,$rid);
                    451: 	my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,$hash{'src_'.$rid});
                    452: 	my $hidden=&Apache::lonnet::EXT('resource.0.hiddenresource',$symb);
1.91      albertel  453: 
1.90      albertel  454: 	if ($hdnflag || lc($hidden) eq 'yes') {
                    455: 	    $hiddenurl{$rid}=1;
1.91      albertel  456: 	}
                    457: 	if (!$hdnflag && lc($hidden) eq 'no') {
1.90      albertel  458: 	    delete($hiddenurl{$rid});
                    459: 	}
1.91      albertel  460: 
1.85      albertel  461: 	my $encrypt=&Apache::lonnet::EXT('resource.0.encrypturl',$symb);
                    462: 	if ($encflag || lc($encrypt) eq 'yes') { $encurl{$rid}=1; }
1.116     www       463: 	if (($retfrid eq '') && ($hash{'src_'.$rid})
1.85      albertel  464: 	    && ($hash{'src_'.$rid}!~/\.sequence$/)) {
1.116     www       465: 	    $retfrid=$rid;
1.85      albertel  466: 	}
                    467: 	if (defined($hash{'conditions_'.$rid})) {
                    468: 	    $hash{'conditions_'.$rid}=simplify(
1.103     albertel  469:            '('.$hash{'conditions_'.$rid}.')|('.$sofar.')');
1.85      albertel  470: 	} else {
                    471: 	    $hash{'conditions_'.$rid}=$sofar;
                    472: 	}
1.107     albertel  473: 
                    474: 	# if the expression is just the 0th condition keep it
                    475: 	# otherwise leave a pointer to this condition expression
                    476: 	$newsofar = ($sofar eq '0') ? $sofar : '_'.$rid;
                    477: 
1.85      albertel  478: 	if (defined($hash{'is_map_'.$rid})) {
                    479: 	    if (defined($hash{'map_start_'.$hash{'src_'.$rid}})) {
                    480: 		$sofar=$newsofar=
                    481: 		    &traceroute($sofar,
1.126     albertel  482: 				$hash{'map_start_'.$hash{'src_'.$rid}},
                    483: 				$beenhere,
1.85      albertel  484: 				$encflag || $encurl{$rid},
                    485: 				$hdnflag || $hiddenurl{$rid});
                    486: 	    }
                    487: 	}
                    488: 	if (defined($hash{'to_'.$rid})) {
1.106     albertel  489: 	    foreach my $id (split(/\,/,$hash{'to_'.$rid})) {
1.2       www       490: 		my $further=$sofar;
1.106     albertel  491:                 if ($hash{'undercond_'.$id}) {
                    492: 		    if (defined($hash{'condid_'.$hash{'undercond_'.$id}})) {
1.105     albertel  493: 			$further=simplify('('.'_'.$rid.')&('.
1.106     albertel  494: 					  $hash{'condid_'.$hash{'undercond_'.$id}}.')');
1.85      albertel  495: 		    } else {
1.114     www       496: 			$errtext.=&mt('<br />Undefined condition ID: [_1]',$hash{'undercond_'.$id});
1.85      albertel  497: 		    }
1.2       www       498:                 }
1.106     albertel  499:                 $newsofar=&traceroute($further,$hash{'goesto_'.$id},$beenhere,
1.81      albertel  500: 				      $encflag,$hdnflag);
1.85      albertel  501: 	    }
                    502: 	}
1.2       www       503:     }
1.81      albertel  504:     return $newsofar;
1.2       www       505: }
1.1       www       506: 
1.19      www       507: # ------------------------------ Cascading conditions, quick access, parameters
1.4       www       508: 
                    509: sub accinit {
                    510:     my ($uri,$short,$fn)=@_;
                    511:     my %acchash=();
                    512:     my %captured=();
                    513:     my $condcounter=0;
1.5       www       514:     $acchash{'acc.cond.'.$short.'.0'}=0;
1.104     albertel  515:     foreach my $key (keys(%hash)) {
                    516: 	if ($key=~/^conditions/) {
                    517: 	    my $expr=$hash{$key};
1.109     albertel  518: 	    # try to find and factor out common sub-expressions
1.105     albertel  519: 	    foreach my $sub ($expr=~m/(\(\([_\.\d]+(?:\&[_\.\d]+)+\)(?:\|\([_\.\d]+(?:\&[_\.\d]+)+\))+\))/g) {
1.104     albertel  520: 		my $orig=$sub;
1.109     albertel  521: 
                    522: 		my ($factor) = ($sub=~/\(\(([_\.\d]+\&(:?[_\.\d]+\&)*)(?:[_\.\d]+\&*)+\)(?:\|\(\1(?:[_\.\d]+\&*)+\))+\)/);
                    523: 		next if (!defined($factor));
                    524: 
                    525: 		$sub=~s/\Q$factor\E//g;
1.85      albertel  526: 		$sub=~s/^\(/\($factor\(/;
                    527: 		$sub.=')';
                    528: 		$sub=simplify($sub);
1.109     albertel  529: 		$expr=~s/\Q$orig\E/$sub/;
1.85      albertel  530: 	    }
1.104     albertel  531: 	    $hash{$key}=$expr;
1.85      albertel  532: 	    unless (defined($captured{$expr})) {
                    533: 		$condcounter++;
                    534: 		$captured{$expr}=$condcounter;
                    535: 		$acchash{'acc.cond.'.$short.'.'.$condcounter}=$expr;
                    536: 	    } 
1.104     albertel  537: 	} elsif ($key=~/^param_(\d+)\.(\d+)/) {
1.86      albertel  538: 	    my $prefix=&Apache::lonnet::encode_symb($hash{'map_id_'.$1},$2,
                    539: 						    $hash{'src_'.$1.'.'.$2});
1.104     albertel  540: 	    foreach my $param (split(/\&/,$hash{$key})) {
                    541: 		my ($typename,$value)=split(/\=/,$param);
1.85      albertel  542: 		my ($type,$name)=split(/\:/,$typename);
1.114     www       543: 		$parmhash{$prefix.'.'.&unescape($name)}=
                    544: 		    &unescape($value);
                    545: 		$parmhash{$prefix.'.'.&unescape($name).'.type'}=
                    546: 		    &unescape($type);
1.85      albertel  547: 	    }
                    548: 	}
1.26      harris41  549:     }
1.104     albertel  550:     foreach my $key (keys(%hash)) {
                    551: 	if ($key=~/^ids/) {
                    552: 	    foreach my $resid (split(/\,/,$hash{$key})) {
1.85      albertel  553: 		my $uri=$hash{'src_'.$resid};
1.100     albertel  554: 		my ($uripath,$urifile) =
                    555: 		    &Apache::lonnet::split_uri_for_cond($uri);
1.85      albertel  556: 		if ($uripath) {
                    557: 		    my $uricond='0';
                    558: 		    if (defined($hash{'conditions_'.$resid})) {
                    559: 			$uricond=$captured{$hash{'conditions_'.$resid}};
                    560: 		    }
                    561: 		    if (defined($acchash{'acc.res.'.$short.'.'.$uripath})) {
                    562: 			if ($acchash{'acc.res.'.$short.'.'.$uripath}=~
                    563: 			    /(\&\Q$urifile\E\:[^\&]*)/) {
                    564: 			    my $replace=$1;
                    565: 			    my $regexp=$replace;
                    566: 			    #$regexp=~s/\|/\\\|/g;
1.105     albertel  567: 			    $acchash{'acc.res.'.$short.'.'.$uripath} =~
1.104     albertel  568: 				s/\Q$regexp\E/$replace\|$uricond/;
1.85      albertel  569: 			} else {
                    570: 			    $acchash{'acc.res.'.$short.'.'.$uripath}.=
                    571: 				$urifile.':'.$uricond.'&';
                    572: 			}
                    573: 		    } else {
                    574: 			$acchash{'acc.res.'.$short.'.'.$uripath}=
                    575: 			    '&'.$urifile.':'.$uricond.'&';
                    576: 		    }
                    577: 		} 
                    578: 	    }
                    579: 	}
1.26      harris41  580:     }
1.24      www       581:     $acchash{'acc.res.'.$short.'.'}='&:0&';
1.8       www       582:     my $courseuri=$uri;
                    583:     $courseuri=~s/^\/res\///;
1.131     raeburn   584:     my $regexp = 1;
                    585:     &Apache::lonnet::delenv('(acc\.|httpref\.)',$regexp);
1.128     raeburn   586:     &Apache::lonnet::appenv(\%acchash);
1.4       www       587: }
                    588: 
1.73      www       589: # ---------------- Selectively delete from randompick maps and hidden url parms
1.29      www       590: 
1.73      www       591: sub hiddenurls {
1.31      www       592:     my $randomoutentry='';
1.29      www       593:     foreach my $rid (keys %randompick) {
                    594:         my $rndpick=$randompick{$rid};
                    595:         my $mpc=$hash{'map_pc_'.$hash{'src_'.$rid}};
                    596: # ------------------------------------------- put existing resources into array
                    597:         my @currentrids=();
1.106     albertel  598:         foreach my $key (sort(keys(%hash))) {
                    599: 	    if ($key=~/^src_($mpc\.\d+)/) {
1.29      www       600: 		if ($hash{'src_'.$1}) { push @currentrids, $1; }
                    601:             }
                    602:         }
1.50      albertel  603: 	# rids are number.number and we want to numercially sort on 
                    604:         # the second number
                    605: 	@currentrids=sort {
                    606: 	    my (undef,$aid)=split(/\./,$a);
                    607: 	    my (undef,$bid)=split(/\./,$b);
                    608: 	    $aid <=> $bid;
                    609: 	} @currentrids;
1.29      www       610:         next if ($#currentrids<$rndpick);
                    611: # -------------------------------- randomly eliminate the ones that should stay
1.50      albertel  612: 	my (undef,$id)=split(/\./,$rid);
1.51      www       613:         if ($randompickseed{$rid}) { $id=$randompickseed{$rid}; }
1.50      albertel  614: 	my $rndseed=&Apache::lonnet::rndseed($id); # use id instead of symb
1.58      albertel  615: 	&Apache::lonnet::setup_random_from_rndseed($rndseed);
1.50      albertel  616: 	my @whichids=&Math::Random::random_permuted_index($#currentrids+1);
                    617:         for (my $i=1;$i<=$rndpick;$i++) { $currentrids[$whichids[$i]]=''; }
                    618: 	#&Apache::lonnet::logthis("$id,$rndseed,".join(':',@whichids));
1.29      www       619: # -------------------------------------------------------- delete the leftovers
                    620:         for (my $k=0; $k<=$#currentrids; $k++) {
                    621:             if ($currentrids[$k]) {
                    622: 		$hash{'randomout_'.$currentrids[$k]}=1;
1.32      www       623:                 my ($mapid,$resid)=split(/\./,$currentrids[$k]);
                    624:                 $randomoutentry.='&'.
1.86      albertel  625: 		    &Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},
                    626: 						 $resid,
                    627: 						 $hash{'src_'.$currentrids[$k]}
                    628: 						 ).'&';
1.29      www       629:             }
                    630:         }
1.31      www       631:     }
1.73      www       632: # ------------------------------ take care of explicitly hidden urls or folders
                    633:     foreach my $rid (keys %hiddenurl) {
                    634: 	$hash{'randomout_'.$rid}=1;
                    635: 	my ($mapid,$resid)=split(/\./,$rid);
                    636: 	$randomoutentry.='&'.
1.86      albertel  637: 	    &Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,
                    638: 					 $hash{'src_'.$rid}).'&';
1.73      www       639:     }
                    640: # --------------------------------------- append randomout entry to environment
1.31      www       641:     if ($randomoutentry) {
1.128     raeburn   642: 	&Apache::lonnet::appenv({'acc.randomout' => $randomoutentry});
1.29      www       643:     }
                    644: }
                    645: 
1.1       www       646: # ---------------------------------------------------- Read map and all submaps
                    647: 
                    648: sub readmap {
1.85      albertel  649:     my $short=shift;
                    650:     $short=~s/^\///;
1.108     albertel  651:     my %cenv=&Apache::lonnet::coursedescription($short,{'freshen_cache'=>1});
1.85      albertel  652:     my $fn=$cenv{'fn'};
                    653:     my $uri;
                    654:     $short=~s/\//\_/g;
                    655:     unless ($uri=$cenv{'url'}) { 
1.133     raeburn   656: 	&Apache::lonnet::logthis('<font color="blue">WARNING: '.
1.85      albertel  657: 				 "Could not load course $short.</font>"); 
1.114     www       658: 	return ('',&mt('No course data available.'));;
1.85      albertel  659:     }
                    660:     @cond=('true:normal');
1.96      albertel  661: 
1.133     raeburn   662:     unless (open(LOCKFILE,">$fn.db.lock")) {
                    663:         $errtext.='<br />'.&mt('Map not loaded - Lock file could not be opened when reading map:').' <tt>'.$fn.'</tt>.';
                    664:         $retfurl = '';
                    665:         return ($retfurl,$errtext);
                    666:     }
1.96      albertel  667:     my $lock=0;
1.132     raeburn   668:     my $gotstate=0;
1.96      albertel  669:     if (flock(LOCKFILE,LOCK_EX|LOCK_NB)) {
                    670: 	$lock=1;
1.132     raeburn   671:         &unlink_tmpfiles($fn);
1.96      albertel  672:     }
1.85      albertel  673:     undef %randompick;
                    674:     undef %hiddenurl;
                    675:     undef %encurl;
1.116     www       676:     $retfrid='';
1.132     raeburn   677:     my ($untiedhash,$untiedparmhash,$tiedhash,$tiedparmhash);
                    678:     if ($lock) {
                    679:         if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_WRCREAT(),0640)) {
                    680:             $tiedhash = 1;
                    681:             if (tie(%parmhash,'GDBM_File',$fn.'_parms.db',&GDBM_WRCREAT(),0640)) {
                    682:                 $tiedparmhash = 1;
                    683:                 $gotstate = &build_tmp_hashes($uri,$fn,$short,\%cenv);
                    684:                 unless ($gotstate) {
                    685:                     &Apache::lonnet::logthis('Failed to write statemap at first attempt '.$fn.' for '.$uri.'.</font>');
                    686:                 }
                    687:                 $untiedparmhash = untie(%parmhash);
                    688:                 unless ($untiedparmhash) {
                    689:                     &Apache::lonnet::logthis('<font color="blue">WARNING: '.
                    690:                         'Could not untie coursemap parmhash '.$fn.' for '.$uri.'.</font>');
                    691:                 }
                    692:             }
                    693:             $untiedhash = untie(%hash);
                    694:             unless ($untiedhash) {
                    695:                 &Apache::lonnet::logthis('<font color="blue">WARNING: '.
                    696:                     'Could not untie coursemap hash '.$fn.' for '.$uri.'.</font>');
                    697:             }
                    698:         }
1.96      albertel  699: 	flock(LOCKFILE,LOCK_UN);
1.132     raeburn   700:     }
                    701:     unless ($lock && $tiedhash && $tiedparmhash) { 
1.87      albertel  702: 	# if we are here it is likely because we are already trying to 
                    703: 	# initialize the course in another child, busy wait trying to 
                    704: 	# tie the hashes for the next 90 seconds, if we succeed forward 
                    705: 	# them on to navmaps, if we fail, throw up the Could not init 
                    706: 	# course screen
1.96      albertel  707: 	if ($lock) {
                    708: 	    # Got the lock but not the DB files
                    709: 	    flock(LOCKFILE,LOCK_UN);
1.132     raeburn   710:             $lock = 0;
1.96      albertel  711: 	}
1.132     raeburn   712:         if ($tiedhash) {
                    713:             unless($untiedhash) {
                    714: 	        untie(%hash);
                    715:             }
                    716:         }
                    717:         if ($tiedparmhash) {
                    718:             unless($untiedparmhash) {
                    719:                 untie(%parmhash);
                    720:             }
                    721:         }
1.133     raeburn   722: 	&Apache::lonnet::logthis('<font color="blue">WARNING: '.
1.132     raeburn   723: 				 "Could not tie coursemap $fn for $uri.</font>");
                    724:         $tiedhash = '';
                    725:         $tiedparmhash = '';
1.87      albertel  726: 	my $i=0;
                    727: 	while($i<90) {
                    728: 	    $i++;
                    729: 	    sleep(1);
1.132     raeburn   730: 	    if (flock(LOCKFILE,LOCK_EX|LOCK_NB)) {
                    731:                 $lock = 1;
                    732: 		if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER(),0640)) {
                    733:                     $tiedhash = 1;
                    734: 		    if (tie(%parmhash,'GDBM_File',$fn.'_parms.db',&GDBM_READER(),0640)) {
                    735:                         $tiedparmhash = 1;
                    736:                         if (-e "$fn.state") {
                    737: 		            $retfurl='/adm/navmaps';
                    738: 		            &Apache::lonnet::appenv({"request.course.id"  => $short,
                    739: 		   			             "request.course.fn"  => $fn,
                    740: 					             "request.course.uri" => $uri});
                    741: 		            $untiedhash = untie(%hash);
                    742: 		            $untiedparmhash = untie(%parmhash);
                    743:                             $gotstate = 1;
                    744: 		            last;
                    745: 		        }
                    746:                         $untiedparmhash = untie(%parmhash);
                    747: 	            }
                    748: 	            $untiedhash = untie(%hash);
                    749:                 }
                    750:             }
1.87      albertel  751: 	}
1.132     raeburn   752:         if ($lock) {
                    753:             flock(LOCKFILE,LOCK_UN);
1.133     raeburn   754:             $lock = 0;
1.132     raeburn   755:             if ($tiedparmhash) {
                    756:                 unless ($untiedparmhash) {
                    757:                     &Apache::lonnet::logthis('<font color="blue">WARNING: '.
                    758:                         'Could not untie coursemap parmhash '.$fn.' for '.$uri.'.</font>');
                    759:                 }
                    760:             }
                    761:             if ($tiedparmhash) {
                    762:                 unless ($untiedhash) {
                    763:                     &Apache::lonnet::logthis('<font color="blue">WARNING: '.
                    764:                         'Could not untie coursemap hash '.$fn.' for '.$uri.'.</font>');
                    765:                 }
                    766:             }
                    767:         }
                    768:     }
                    769:     unless ($gotstate) {
1.133     raeburn   770:         $lock = 0;
1.132     raeburn   771:         &Apache::lonnet::logthis('<font color="blue">WARNING: '.
                    772:                      'Could not read statemap '.$fn.' for '.$uri.'.</font>');
                    773:         &unlink_tmpfiles($fn);
1.133     raeburn   774:         if (flock(LOCKFILE,LOCK_EX|LOCK_NB)) {
                    775:             $lock=1;
                    776:         }
                    777:         undef %randompick;
                    778:         undef %hiddenurl;
                    779:         undef %encurl;
                    780:         $retfrid='';
                    781:         if ($lock) {
                    782:             if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_WRCREAT(),0640)) {
                    783:                 if (tie(%parmhash,'GDBM_File',$fn.'_parms.db',&GDBM_WRCREAT(),0640)) {
                    784:                     $gotstate = &build_tmp_hashes($uri,$fn,$short,\%cenv);
                    785:                     unless ($gotstate) {
1.132     raeburn   786:                         &Apache::lonnet::logthis('<font color="blue">WARNING: '.
1.133     raeburn   787:                             'Failed to write statemap at second attempt '.$fn.' for '.$uri.'.</font>');
1.132     raeburn   788:                     }
1.133     raeburn   789:                     unless (untie(%parmhash)) {
1.132     raeburn   790:                         &Apache::lonnet::logthis('<font color="blue">WARNING: '.
1.133     raeburn   791:                             'Could not untie coursemap parmhash '.$fn.'.db for '.$uri.'.</font>');
1.132     raeburn   792:                     }
1.133     raeburn   793:                 } else {
                    794:                     &Apache::lonnet::logthis('<font color="blue">WARNING: '.
                    795:                         'Could not tie coursemap '.$fn.'__parms.db for '.$uri.'.</font>');
                    796:                 }
                    797:                 unless (untie(%hash)) {
                    798:                     &Apache::lonnet::logthis('<font color="blue">WARNING: '.
                    799:                         'Could not untie coursemap hash '.$fn.'.db for '.$uri.'.</font>');
                    800:                 }
1.132     raeburn   801:             } else {
1.133     raeburn   802:                &Apache::lonnet::logthis('<font color="blue">WARNING: '.
                    803:                    'Could not tie coursemap '.$fn.'.db for '.$uri.'.</font>');
1.132     raeburn   804:             }
1.133     raeburn   805:             flock(LOCKFILE,LOCK_UN);
                    806:             $lock = 0;
                    807:         } else {
                    808:             &Apache::lonnet::logthis('<font color="blue">WARNING: '.
                    809:             'Could not obtain lock to tie coursemap hash '.$fn.'.db for '.$uri.'.</font>');
1.132     raeburn   810:         }
                    811:     }
1.133     raeburn   812:     close(LOCKFILE);
1.132     raeburn   813:     unless (($errtext eq '') || ($env{'request.course.uri'} =~ m{^/uploaded/})) {
                    814:         &Apache::lonmsg::author_res_msg($env{'request.course.uri'},
                    815:                                         $errtext);
1.1       www       816:     }
1.46      www       817: # ------------------------------------------------- Check for critical messages
                    818: 
1.89      albertel  819:     my @what=&Apache::lonnet::dump('critical',$env{'user.domain'},
                    820: 				   $env{'user.name'});
1.46      www       821:     if ($what[0]) {
                    822: 	if (($what[0] ne 'con_lost') && ($what[0]!~/^error\:/)) {
                    823: 	    $retfurl='/adm/email?critical=display';
                    824:         }
                    825:     }
1.85      albertel  826:     return ($retfurl,$errtext);
1.1       www       827: }
1.15      www       828: 
1.132     raeburn   829: sub build_tmp_hashes {
                    830:     my ($uri,$fn,$short,$cenvref) = @_;
                    831:     unless(ref($cenvref) eq 'HASH') {
                    832:         return;
                    833:     }
                    834:     my %cenv = %{$cenvref};
                    835:     my $gotstate = 0;
                    836:     %hash=();
                    837:     %parmhash=();
                    838:     $errtext='';
                    839:     $pc=0;
                    840:     &clear_mapalias_count();
                    841:     &processversionfile(%cenv);
                    842:     my $furi=&Apache::lonnet::clutter($uri);
                    843:     $hash{'src_0.0'}=&versiontrack($furi);
                    844:     $hash{'title_0.0'}=&Apache::lonnet::metadata($uri,'title');
                    845:     $hash{'ids_'.$furi}='0.0';
                    846:     $hash{'is_map_0.0'}=1;
                    847:     &loadmap($uri,'0.0');
                    848:     if (defined($hash{'map_start_'.$uri})) {
                    849:         &Apache::lonnet::appenv({"request.course.id"  => $short,
                    850:                                  "request.course.fn"  => $fn,
                    851:                                  "request.course.uri" => $uri});
                    852:         $env{'request.course.id'}=$short;
                    853:         &traceroute('0',$hash{'map_start_'.$uri},'&');
                    854:         &accinit($uri,$short,$fn);
                    855:         &hiddenurls();
                    856:     }
                    857:     $errtext .= &get_mapalias_errors();
                    858: # ------------------------------------------------------- Put versions into src
                    859:     foreach my $key (keys(%hash)) {
                    860:         if ($key=~/^src_/) {
                    861:             $hash{$key}=&putinversion($hash{$key});
                    862:         } elsif ($key =~ /^(map_(?:start|finish|pc)_)(.*)/) {
                    863:             my ($type, $url) = ($1,$2);
                    864:             my $value = $hash{$key};
                    865:             $hash{$type.&putinversion($url)}=$value;
                    866:         }
                    867:     }
                    868: # ---------------------------------------------------------------- Encrypt URLs
                    869:     foreach my $id (keys(%encurl)) {
                    870: #           $hash{'src_'.$id}=&Apache::lonenc::encrypted($hash{'src_'.$id});
                    871:         $hash{'encrypted_'.$id}=1;
                    872:     }
                    873: # ----------------------------------------------- Close hashes to finally store
                    874: # --------------------------------- Routine must pass this point, no early outs
                    875:     $hash{'first_rid'}=$retfrid;
                    876:     my ($mapid,$resid)=split(/\./,$retfrid);
                    877:     $hash{'first_mapurl'}=$hash{'map_id_'.$mapid};
                    878:     my $symb=&Apache::lonnet::encode_symb($hash{'map_id_'.$mapid},$resid,$hash{'src_'.$retfrid});
                    879:     $retfurl=&add_get_param($hash{'src_'.$retfrid},{ 'symb' => $symb });
                    880:     if ($hash{'encrypted_'.$retfrid}) {
                    881:         $retfurl=&Apache::lonenc::encrypted($retfurl,(&Apache::lonnet::allowed('adv') ne 'F'));
                    882:     }
                    883:     $hash{'first_url'}=$retfurl;
                    884: # ---------------------------------------------------- Store away initial state
                    885:     {
                    886:         my $cfh;
                    887:         if (open($cfh,">$fn.state")) {
                    888:             print $cfh join("\n",@cond);
                    889:             $gotstate = 1;
                    890:         } else {
                    891:             &Apache::lonnet::logthis("<font color=blue>WARNING: ".
                    892:                                      "Could not write statemap $fn for $uri.</font>");
                    893:         }
                    894:     }
                    895:     return $gotstate;
                    896: }
                    897: 
                    898: sub unlink_tmpfiles {
                    899:     my ($fn) = @_;
                    900:     if ($fn =~ m{^\Q$Apache::lonnet::perlvar{'lonUsersDir'}\E/tmp/}) {
                    901:         my @files = qw (.db _symb.db .state _parms.db);
                    902:         foreach my $file (@files) {
                    903:             if (-e $fn.$file) {
                    904:                 unless (unlink($fn.$file)) {
                    905:                     &Apache::lonnet::logthis("<font color=blue>WARNING: ".
                    906:                                  "Could not unlink ".$fn.$file."</font>");
                    907:                 }
                    908:             }
                    909:         }
                    910:     }
                    911:     return;
                    912: }
                    913: 
1.15      www       914: # ------------------------------------------------------- Evaluate state string
                    915: 
                    916: sub evalstate {
1.89      albertel  917:     my $fn=$env{'request.course.fn'}.'.state';
1.80      albertel  918:     my $state='';
1.15      www       919:     if (-e $fn) {
1.80      albertel  920: 	my @conditions=();
                    921: 	{
1.115     raeburn   922: 	    open(my $fh,"<$fn");
1.80      albertel  923: 	    @conditions=<$fh>;
1.115     raeburn   924:             close($fh);
1.80      albertel  925: 	}  
                    926: 	my $safeeval = new Safe;
                    927: 	my $safehole = new Safe::Hole;
                    928: 	$safeeval->permit("entereval");
                    929: 	$safeeval->permit(":base_math");
                    930: 	$safeeval->deny(":base_io");
                    931: 	$safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');
                    932: 	foreach my $line (@conditions) {
                    933: 	    chomp($line);
                    934: 	    my ($condition,$weight)=split(/\:/,$line);
                    935: 	    if ($safeeval->reval($condition)) {
                    936: 		if ($weight eq 'force') {
                    937: 		    $state.='3';
                    938: 		} else {
                    939: 		    $state.='2';
                    940: 		}
                    941: 	    } else {
                    942: 		if ($weight eq 'stop') {
                    943: 		    $state.='0';
                    944: 		} else {
                    945: 		    $state.='1';
                    946: 		}
                    947: 	    }
                    948: 	}
1.15      www       949:     }
1.128     raeburn   950:     &Apache::lonnet::appenv({'user.state.'.$env{'request.course.id'} => $state});
1.15      www       951:     return $state;
                    952: }
                    953: 
1.122     albertel  954: {
                    955:     my %mapalias_cache;
                    956:     sub count_mapalias {
                    957: 	my ($value,$resid) = @_;
                    958:  	push(@{ $mapalias_cache{$value} }, $resid);
                    959:     }
                    960: 
                    961:     sub get_mapalias_errors {
                    962: 	my $error_text;
                    963: 	foreach my $mapalias (sort(keys(%mapalias_cache))) {
                    964: 	    next if (scalar(@{ $mapalias_cache{$mapalias} } ) == 1);
                    965: 	    my $count;
                    966: 	    my $which =
                    967: 		join('</li><li>', 
                    968: 		     map {
                    969: 			 my $id = $_;
                    970: 			 if (exists($hash{'src_'.$id})) {
                    971: 			     $count++;
                    972: 			 }
                    973: 			 my ($mapid) = split(/\./,$id);
1.125     albertel  974:                          &mt('Resource "[_1]" <br /> in Map "[_2]"',
                    975: 			     $hash{'title_'.$id},
1.122     albertel  976: 			     $hash{'title_'.$hash{'ids_'.$hash{'map_id_'.$mapid}}});
                    977: 		     } (@{ $mapalias_cache{$mapalias} }));
                    978: 	    next if ($count < 2);
                    979: 	    $error_text .= '<div class="LC_error">'.
                    980: 		&mt('Error: Found the mapalias "[_1]" defined multiple times.',
                    981: 		    $mapalias).
                    982: 		'</div><ul><li>'.$which.'</li></ul>';
                    983: 	}
                    984: 	&clear_mapalias_count();
                    985: 	return $error_text;
                    986:     }
                    987:     sub clear_mapalias_count {
                    988: 	undef(%mapalias_cache);
                    989:     }
                    990: }
1.1       www       991: 1;
                    992: __END__
                    993: 
1.26      harris41  994: =head1 NAME
                    995: 
                    996: Apache::lonuserstate - Construct and maintain state and binary representation
                    997: of course for user
                    998: 
                    999: =head1 SYNOPSIS
                   1000: 
                   1001: Invoked by lonroles.pm.
                   1002: 
                   1003: &Apache::lonuserstate::readmap($cdom.'/'.$cnum);
                   1004: 
                   1005: =head1 INTRODUCTION
                   1006: 
                   1007: This module constructs and maintains state and binary representation
                   1008: of course for user.
                   1009: 
                   1010: This is part of the LearningOnline Network with CAPA project
                   1011: described at http://www.lon-capa.org.
                   1012: 
1.129     jms      1013: =head1 SUBROUTINES
1.26      harris41 1014: 
1.129     jms      1015: =over
1.26      harris41 1016: 
1.129     jms      1017: =item loadmap()
1.26      harris41 1018: 
1.129     jms      1019: Loads map from disk
1.26      harris41 1020: 
1.129     jms      1021: =item simplify()
1.26      harris41 1022: 
1.129     jms      1023: Simplify expression
1.26      harris41 1024: 
1.129     jms      1025: =item traceroute()
1.26      harris41 1026: 
1.129     jms      1027: Build condition hash
1.26      harris41 1028: 
1.129     jms      1029: =item accinit()
1.26      harris41 1030: 
1.129     jms      1031: Cascading conditions, quick access, parameters
1.26      harris41 1032: 
1.129     jms      1033: =item readmap()
1.26      harris41 1034: 
1.129     jms      1035: Read map and all submaps
1.1       www      1036: 
1.129     jms      1037: =item evalstate()
1.1       www      1038: 
1.129     jms      1039: Evaluate state string
1.1       www      1040: 
1.26      harris41 1041: =back
1.1       www      1042: 
1.26      harris41 1043: =cut

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.