--- loncom/lonnet/perl/lonnet.pm 2005/11/22 00:01:53 1.683 +++ loncom/lonnet/perl/lonnet.pm 2006/02/23 18:15:16 1.713 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.683 2005/11/22 00:01:53 raeburn Exp $ +# $Id: lonnet.pm,v 1.713 2006/02/23 18:15:16 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -40,8 +40,8 @@ qw(%perlvar %hostname %badServerCache %i %courselogs %accesshash %userrolehash %domainrolehash $processmarker $dumpcount %coursedombuf %coursenumbuf %coursehombuf %coursedescrbuf %courseinstcodebuf %courseownerbuf %domaindescription %domain_auth_def %domain_auth_arg_def - %domain_lang_def %domain_city %domain_longi %domain_lati $tmpdir $_64bit - %env); + %domain_lang_def %domain_city %domain_longi %domain_lati %domain_primary + $tmpdir $_64bit %env); use IO::Socket; use GDBM_File; @@ -124,7 +124,7 @@ sub logperm { # -------------------------------------------------- Non-critical communication sub subreply { my ($cmd,$server)=@_; - my $peerfile="$perlvar{'lonSockDir'}/$server"; + my $peerfile="$perlvar{'lonSockDir'}/".$hostname{$server}; # # With loncnew process trimming, there's a timing hole between lonc server # process exit and the master server picking up the listen on the AF_UNIX @@ -152,7 +152,7 @@ sub subreply { } my $answer; if ($client) { - print $client "$cmd\n"; + print $client "sethost:$server:$cmd\n"; $answer=<$client>; if (!$answer) { $answer="con_lost"; } chomp($answer); @@ -271,7 +271,7 @@ sub transfer_profile_to_env { my %Remove; for ($envi=0;$envi<=$#profile;$envi++) { chomp($profile[$envi]); - my ($envname,$envvalue)=split(/=/,$profile[$envi]); + my ($envname,$envvalue)=split(/=/,$profile[$envi],2); $env{$envname} = $envvalue; if (my ($key,$time) = ($envname =~ /^(cgi\.(\d+)_\d+\.)/)) { if ($time < time-300) { @@ -289,14 +289,14 @@ sub transfer_profile_to_env { sub appenv { my %newenv=@_; - foreach (keys %newenv) { - if (($newenv{$_}=~/^user\.role/) || ($newenv{$_}=~/^user\.priv/)) { + foreach my $key (keys(%newenv)) { + if (($newenv{$key}=~/^user\.role/) || ($newenv{$key}=~/^user\.priv/)) { &logthis("WARNING: ". - "Attempt to modify environment ".$_." to ".$newenv{$_} + "Attempt to modify environment ".$key." to ".$newenv{$key} .''); - delete($newenv{$_}); + delete($newenv{$key}); } else { - $env{$_}=$newenv{$_}; + $env{$key}=$newenv{$key}; } } @@ -323,7 +323,7 @@ sub appenv { for (my $i=0; $i<=$#oldenv; $i++) { chomp($oldenv[$i]); if ($oldenv[$i] ne '') { - my ($name,$value)=split(/=/,$oldenv[$i]); + my ($name,$value)=split(/=/,$oldenv[$i],2); unless (defined($newenv{$name})) { $newenv{$name}=$value; } @@ -380,12 +380,12 @@ sub delenv { close($fh); return 'error: '.$!; } - foreach (@oldenv) { - if ($_=~/^$delthis/) { - my ($key,undef) = split('=',$_); + foreach my $cur_key (@oldenv) { + if ($cur_key=~/^$delthis/) { + my ($key,undef) = split('=',$cur_key,2); delete($env{$key}); } else { - print $fh $_; + print $fh $cur_key; } } close($fh); @@ -947,13 +947,50 @@ sub userenvironment { sub studentphoto { my ($udom,$unam,$ext) = @_; my $home=&Apache::lonnet::homeserver($unam,$udom); - my $ret=&Apache::lonnet::reply("studentphoto:$udom:$unam:$ext",$home); - my $url="/uploaded/$udom/$unam/internal/studentphoto.".$ext; - if ($ret ne 'ok') { - return '/adm/lonKaputt/lonlogo_broken.gif'; + if (defined($env{'request.course.id'})) { + if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) { + if ($udom eq $env{'course.'.$env{'request.course.id'}.'.domain'}) { + return(&retrievestudentphoto($udom,$unam,$ext)); + } else { + my ($result,$perm_reqd)= + &Apache::lonnet::auto_photo_permission($unam,$udom); + if ($result eq 'ok') { + if (!($perm_reqd eq 'yes')) { + return(&retrievestudentphoto($udom,$unam,$ext)); + } + } + } + } + } else { + my ($result,$perm_reqd) = + &Apache::lonnet::auto_photo_permission($unam,$udom); + if ($result eq 'ok') { + if (!($perm_reqd eq 'yes')) { + return(&retrievestudentphoto($udom,$unam,$ext)); + } + } + } + return '/adm/lonKaputt/lonlogo_broken.gif'; +} + +sub retrievestudentphoto { + my ($udom,$unam,$ext,$type) = @_; + my $home=&Apache::lonnet::homeserver($unam,$udom); + my $ret=&Apache::lonnet::reply("studentphoto:$udom:$unam:$ext:$type",$home); + if ($ret eq 'ok') { + my $url="/uploaded/$udom/$unam/internal/studentphoto.$ext"; + if ($type eq 'thumbnail') { + $url="/uploaded/$udom/$unam/internal/studentphoto_tn.$ext"; + } + my $tokenurl=&Apache::lonnet::tokenwrapper($url); + return $tokenurl; + } else { + if ($type eq 'thumbnail') { + return '/adm/lonKaputt/genericstudent_tn.gif'; + } else { + return '/adm/lonKaputt/lonlogo_broken.gif'; + } } - my $tokenurl=&Apache::lonnet::tokenwrapper($url); - return $tokenurl; } # -------------------------------------------------------------------- New chat @@ -1108,7 +1145,9 @@ sub ssi { my $ua=new LWP::UserAgent; my $request; - + + $form{'no_update_last_known'}=1; + if (%form) { $request=new HTTP::Request('POST',"http://".$ENV{'HTTP_HOST'}.$fn); $request->content(join('&',map { &escape($_).'='.&escape($form{$_}) } keys %form)); @@ -1280,8 +1319,15 @@ sub clean_filename { } # --------------- Take an uploaded file and put it into the userfiles directory -# input: name of form element, coursedoc=1 means this is for the course -# output: url of file in userspace +# input: $formname - the contents of the file are in $env{"form.$formname"} +# the desired filenam is in $env{"form.$formname"} +# $coursedoc - if true up to the current course +# if false +# $subdir - directory in userfile to store the file into +# $parser, $allfiles, $codebase - unknown +# +# output: url of file in userspace, or error: +# or /adm/notfound.html if failure to upload occurse sub userfileupload { @@ -1351,8 +1397,16 @@ sub finishuserfileupload { } # Save the file { - open(FH,'>'.$filepath.'/'.$file); - print FH $env{'form.'.$formname}; + if (!open(FH,'>'.$filepath.'/'.$file)) { + &logthis('Failed to create '.$filepath.'/'.$file); + print STDERR ('Failed to create '.$filepath.'/'.$file."\n"); + return '/adm/notfound.html'; + } + if (!print FH ($env{'form.'.$formname})) { + &logthis('Failed to write to '.$filepath.'/'.$file); + print STDERR ('Failed to write to '.$filepath.'/'.$file."\n"); + return '/adm/notfound.html'; + } close(FH); } if ($parser eq 'parse') { @@ -1853,28 +1907,25 @@ sub courseiddump { # ---------------------------------------------------------- DC e-mail sub dcmailput { - my ($domain,$msgid,$contents,$server)=@_; + my ($domain,$msgid,$message,$server)=@_; my $status = &Apache::lonnet::critical( 'dcmailput:'.$domain.':'.&Apache::lonnet::escape($msgid).'='. - &Apache::lonnet::escape($$contents{$server}),$server); + &Apache::lonnet::escape($message),$server); return $status; } sub dcmaildump { my ($dom,$startdate,$enddate,$senders) = @_; - my %returnhash=(); - foreach my $tryserver (keys(%libserv)) { - if ($hostdom{$tryserver} eq $dom) { - %{$returnhash{$tryserver}}=(); - my $cmd='dcmaildump:'.$dom.':'. - &escape($startdate).':'.&escape($enddate).':'; - my @esc_senders=map { &escape($_)} @$senders; - $cmd.=&escape(join('&',@esc_senders)); - foreach (split(/\&/,&reply($cmd,$tryserver))) { - my ($key,$value) = split(/\=/,$_); - if (($key) && ($value)) { - $returnhash{$tryserver}{&unescape($key)} = &unescape($value); - } + my %returnhash=(); + if (exists($domain_primary{$dom})) { + my $cmd='dcmaildump:'.$dom.':'.&escape($startdate).':'. + &escape($enddate).':'; + my @esc_senders=map { &escape($_)} @$senders; + $cmd.=&escape(join('&',@esc_senders)); + foreach (split(/\&/,&reply($cmd,$domain_primary{$dom}))) { + my ($key,$value) = split(/\=/,$_); + if (($key) && ($value)) { + $returnhash{&unescape($key)} = &unescape($value); } } } @@ -2781,7 +2832,7 @@ sub del { # -------------------------------------------------------------- dump interface sub dump { - my ($namespace,$udomain,$uname,$regexp)=@_; + my ($namespace,$udomain,$uname,$regexp,$range)=@_; if (!$udomain) { $udomain=$env{'user.domain'}; } if (!$uname) { $uname=$env{'user.name'}; } my $uhome=&homeserver($uname,$udomain); @@ -2790,11 +2841,11 @@ sub dump { } else { $regexp='.'; } - my $rep=reply("dump:$udomain:$uname:$namespace:$regexp",$uhome); + my $rep=reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome); my @pairs=split(/\&/,$rep); my %returnhash=(); foreach (@pairs) { - my ($key,$value)=split(/=/,$_); + my ($key,$value)=split(/=/,$_,2); $returnhash{unescape($key)}=&thaw_unescape($value); } return %returnhash; @@ -3013,8 +3064,9 @@ sub tmpput { # ------------------------------------------------------------ tmpget interface sub tmpget { - my ($token)=@_; - my $rep=&reply("tmpget:$token",$perlvar{'lonHostID'}); + my ($token,$server)=@_; + if (!defined($server)) { $server = $perlvar{'lonHostID'}; } + my $rep=&reply("tmpget:$token",$server); my %returnhash; foreach my $item (split(/\&/,$rep)) { my ($key,$value)=split(/=/,$item); @@ -3023,6 +3075,13 @@ sub tmpget { return %returnhash; } +# ------------------------------------------------------------ tmpget interface +sub tmpdel { + my ($token,$server)=@_; + if (!defined($server)) { $server = $perlvar{'lonHostID'}; } + return &reply("tmpdel:$token",$server); +} + # ---------------------------------------------- Custom access rule evaluation sub customaccess { @@ -3061,6 +3120,7 @@ sub customaccess { sub allowed { my ($priv,$uri,$symb)=@_; + my $ver_orguri=$uri; $uri=&deversion($uri); my $orguri=$uri; $uri=&declutter($uri); @@ -3161,7 +3221,7 @@ sub allowed { $thisallowed.=$1; } } else { - my $refuri=$env{'httpref.'.$orguri}; + my $refuri = $env{'httpref.'.$orguri} || $env{'httpref.'.$ver_orguri}; if ($refuri) { if ($refuri =~ m|^/adm/|) { $thisallowed='F'; @@ -3341,17 +3401,21 @@ sub allowed { my $unamedom=$env{'user.name'}.':'.$env{'user.domain'}; if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.roles.denied'} =~/\Q$rolecode\E/) { - &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'. - 'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode.' in '. - $env{'request.course.id'}); + if ($priv ne 'pch') { + &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'. + 'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode.' in '. + $env{'request.course.id'}); + } return ''; } if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.users.denied'} =~/\Q$unamedom\E/) { - &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}. - 'Denied by user: '.$priv.' for '.$uri.' as '.$unamedom.' in '. - $env{'request.course.id'}); + if ($priv ne 'pch') { + &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}. + 'Denied by user: '.$priv.' for '.$uri.' as '.$unamedom.' in '. + $env{'request.course.id'}); + } return ''; } } @@ -3361,9 +3425,11 @@ sub allowed { if ($thisallowed=~/R/) { my $rolecode=(split(/\./,$env{'request.role'}))[0]; if (&metadata($uri,'roledeny')=~/\Q$rolecode\E/) { - &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'. - 'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode); - return ''; + if ($priv ne 'pch') { + &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'. + 'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode); + } + return ''; } } @@ -3386,15 +3452,17 @@ sub allowed { return 'F'; } +sub split_uri_for_cond { + my $uri=&deversion(&declutter(shift)); + my @uriparts=split(/\//,$uri); + my $filename=pop(@uriparts); + my $pathname=join('/',@uriparts); + return ($pathname,$filename); +} # --------------------------------------------------- Is a resource on the map? sub is_on_map { - my $uri=&deversion(&declutter(shift)); - my @uriparts=split(/\//,$uri); - my $filename=$uriparts[$#uriparts]; - my $pathname=$uri; - $pathname=~s|/\Q$filename\E$||; - $pathname=~s/^adm\/wrapper\///; + my ($pathname,$filename) = &split_uri_for_cond(shift); #Trying to find the conditional for the file my $match=($env{'acc.res.'.$env{'request.course.id'}.'.'.$pathname}=~ /\&\Q$filename\E\:([\d\|]+)\&/); @@ -3667,6 +3735,82 @@ sub auto_create_password { return ($authparam,$create_passwd,$authchk); } +sub auto_photo_permission { + my ($cnum,$cdom,$students) = @_; + my $homeserver = &homeserver($cnum,$cdom); + my ($outcome,$perm_reqd,$conditions) = + split(/:/,&unescape(&reply('autophotopermission:'.$cdom,$homeserver)),3); + if ($outcome =~ /^(con_lost|unknown_cmd|no_such_host)$/) { + return (undef,undef); + } + return ($outcome,$perm_reqd,$conditions); +} + +sub auto_checkphotos { + my ($uname,$udom,$pid) = @_; + my $homeserver = &homeserver($uname,$udom); + my ($result,$resulttype); + my $outcome = &unescape(&reply('autophotocheck:'.&escape($udom).':'. + &escape($uname).':'.&escape($pid), + $homeserver)); + if ($outcome =~ /^(con_lost|unknown_cmd|no_such_host)$/) { + return (undef,undef); + } + if ($outcome) { + ($result,$resulttype) = split(/:/,$outcome); + } + return ($result,$resulttype); +} + +sub auto_photochoice { + my ($cnum,$cdom) = @_; + my $homeserver = &homeserver($cnum,$cdom); + my ($update,$comment) = split(/:/,&unescape(&reply('autophotochoice:'. + &escape($cdom), + $homeserver))); + if ($update =~ /^(con_lost|unknown_cmd|no_such_host)$/) { + return (undef,undef); + } + return ($update,$comment); +} + +sub auto_photoupdate { + my ($affiliatesref,$dom,$cnum,$photo) = @_; + my $homeserver = &homeserver($cnum,$dom); + my $host=$hostname{$homeserver}; + my $cmd = ''; + my $maxtries = 1; + foreach (keys %{$affiliatesref}) { + $cmd .= $_.'='.join(",",@{$$affiliatesref{$_}}).'%%'; + } + $cmd =~ s/%%$//; + $cmd = &escape($cmd); + my $query = 'institutionalphotos'; + my $queryid=&reply("querysend:".$query.':'.$dom.':'.$cnum.':'.$cmd,$homeserver); + unless ($queryid=~/^\Q$host\E\_/) { + &logthis('institutionalphotos: invalid queryid: '.$queryid.' for host: '.$host.' and homeserver: '.$homeserver.' and course: '.$cnum); + return 'error: '.$queryid; + } + my $reply = &get_query_reply($queryid); + my $tries = 1; + while (($reply=~/^timeout/) && ($tries < $maxtries)) { + $reply = &get_query_reply($queryid); + $tries ++; + } + if ( ($reply =~/^timeout/) || ($reply =~/^error/) ) { + &logthis('institutionalphotos error: '.$reply.' for '.$dom.' '.$env{'user.name'}.' for '.$queryid.' course: '.$cnum.' maxtries: '.$maxtries.' tries: '.$tries); + } else { + my @responses = split(/:/,$reply); + my $outcome = shift(@responses); + foreach my $item (@responses) { + my ($key,$value) = split(/=/,$item); + $$photo{$key} = $value; + } + return $outcome; + } + return 'error'; +} + sub auto_instcode_format { my ($caller,$codedom,$instcodes,$codes,$codetitles,$cat_titles,$cat_order) = @_; my $courses = ''; @@ -3718,6 +3862,10 @@ sub modify_group_roles { my $role = 'gr/'.&escape($userprivs); my ($uname,$udom) = split(/:/,$user); my $result = &assignrole($udom,$uname,$url,$role,$end,$start); + if ($result eq 'ok') { + &devalidate_getgroups_cache($udom,$uname,$cdom,$cnum); + } + return $result; } @@ -4519,13 +4667,62 @@ sub GetFileTimestamp { } } +sub stat_file { + my ($uri) = @_; + $uri = &clutter($uri); + my ($udom,$uname,$file,$dir); + if ($uri =~ m-^/(uploaded|editupload)/-) { + ($udom,$uname,$file) = + ($uri =~ m-/(?:uploaded|editupload)/?([^/]*)/?([^/]*)/?(.*)-); + $file = 'userfiles/'.$file; + $dir = &Apache::loncommon::propath($udom,$uname); + } + if ($uri =~ m-^/res/-) { + ($udom,$uname) = + ($uri =~ m-/(?:res)/?([^/]*)/?([^/]*)/-); + $file = $uri; + } + + if (!$udom || !$uname || !$file) { + # unable to handle the uri + return (); + } + + my ($result) = &dirlist($file,$udom,$uname,$dir); + my @stats = split('&', $result); + if($stats[0] ne 'empty' && $stats[0] ne 'no_such_dir') { + shift(@stats); #filename is first + return @stats; + } + return (); +} + # -------------------------------------------------------- Value of a Condition +# gets the value of a specific preevaluated condition +# stored in the string $env{user.state.} +# or looks up a condition reference in the bighash and if if hasn't +# already been evaluated recurses into docondval to get the value of +# the condition, then memoizing it to +# $env{user.state..} sub directcondval { my $number=shift; if (!defined($env{'user.state.'.$env{'request.course.id'}})) { &Apache::lonuserstate::evalstate(); } + if (exists($env{'user.state.'.$env{'request.course.id'}.".$number"})) { + return $env{'user.state.'.$env{'request.course.id'}.".$number"}; + } elsif ($number =~ /^_/) { + my $sub_condition; + if (tie(my %bighash,'GDBM_File',$env{'request.course.fn'}.'.db', + &GDBM_READER(),0640)) { + $sub_condition=$bighash{'conditions'.$number}; + untie(%bighash); + } + my $value = &docondval($sub_condition); + &appenv('user.state.'.$env{'request.course.id'}.".$number" => $value); + return $value; + } if ($env{'user.state.'.$env{'request.course.id'}}) { return substr($env{'user.state.'.$env{'request.course.id'}},$number,1); } else { @@ -4533,43 +4730,49 @@ sub directcondval { } } +# get the collection of conditions for this resource sub condval { my $condidx=shift; - my $result=0; my $allpathcond=''; - foreach (split(/\|/,$condidx)) { - if (defined($env{'acc.cond.'.$env{'request.course.id'}.'.'.$_})) { - $allpathcond.= - '('.$env{'acc.cond.'.$env{'request.course.id'}.'.'.$_}.')|'; - } + foreach my $cond (split(/\|/,$condidx)) { + if (defined($env{'acc.cond.'.$env{'request.course.id'}.'.'.$cond})) { + $allpathcond.= + '('.$env{'acc.cond.'.$env{'request.course.id'}.'.'.$cond}.')|'; + } } $allpathcond=~s/\|$//; - if ($env{'request.course.id'}) { - if ($allpathcond) { - my $operand='|'; - my @stack; - foreach ($allpathcond=~/(\d+|\(|\)|\&|\|)/g) { - if ($_ eq '(') { - push @stack,($operand,$result) - } elsif ($_ eq ')') { - my $before=pop @stack; - if (pop @stack eq '&') { - $result=$result>$before?$before:$result; - } else { - $result=$result>$before?$result:$before; - } - } elsif (($_ eq '&') || ($_ eq '|')) { - $operand=$_; - } else { - my $new=directcondval($_); - if ($operand eq '&') { - $result=$result>$new?$new:$result; - } else { - $result=$result>$new?$result:$new; - } - } - } - } + return &docondval($allpathcond); +} + +#evaluates an expression of conditions +sub docondval { + my ($allpathcond) = @_; + my $result=0; + if ($env{'request.course.id'} + && defined($allpathcond)) { + my $operand='|'; + my @stack; + foreach my $chunk ($allpathcond=~/(\d+|_\d+\.\d+|\(|\)|\&|\|)/g) { + if ($chunk eq '(') { + push @stack,($operand,$result); + } elsif ($chunk eq ')') { + my $before=pop @stack; + if (pop @stack eq '&') { + $result=$result>$before?$before:$result; + } else { + $result=$result>$before?$result:$before; + } + } elsif (($chunk eq '&') || ($chunk eq '|')) { + $operand=$chunk; + } else { + my $new=directcondval($chunk); + if ($operand eq '&') { + $result=$result>$new?$new:$result; + } else { + $result=$result>$new?$result:$new; + } + } + } } return $result; } @@ -4801,10 +5004,21 @@ sub EXT { return $env{'course.'.$courseid.'.'.$spacequalifierrest}; } elsif ($realm eq 'resource') { - my $section; if (defined($courseid) && $courseid eq $env{'request.course.id'}) { if (!$symbparm) { $symbparm=&symbread(); } } + + if ($space eq 'title') { + if (!$symbparm) { $symbparm = $env{'request.filename'}; } + return &gettitle($symbparm); + } + + if ($space eq 'map') { + my ($map) = &decode_symb($symbparm); + return &symbread($map); + } + + my ($section, $group, @groups); my ($courselevelm,$courselevel); if ($symbparm && defined($courseid) && $courseid eq $env{'request.course.id'}) { @@ -4821,12 +5035,20 @@ sub EXT { if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) { $section=$env{'request.course.sec'}; + @groups=&sort_course_groups($env{'request.course.groups'},$courseid); + if (@groups > 0) { + @groups = sort(@groups); + } } else { if (! defined($usection)) { $section=&getsection($udom,$uname,$courseid); } else { $section = $usection; } + my $grouplist = &get_users_groups($udom,$uname,$courseid); + if ($grouplist) { + @groups=&sort_course_groups($grouplist,$courseid); + } } my $seclevel=$courseid.'.['.$section.'].'.$spacequalifierrest; @@ -4842,12 +5064,17 @@ sub EXT { my $userreply=&resdata($uname,$udom,'user', ($courselevelr,$courselevelm, $courselevel)); - if (defined($userreply)) { return $userreply; } # ------------------------------------------------ second, check some of course + my $coursereply; + if (@groups > 0) { + $coursereply = &check_group_parms($courseid,\@groups,$symbparm, + $mapparm,$spacequalifierrest); + if (defined($coursereply)) { return $coursereply; } + } - my $coursereply=&resdata($env{'course.'.$courseid.'.num'}, + $coursereply=&resdata($env{'course.'.$courseid.'.num'}, $env{'course.'.$courseid.'.domain'}, 'course', ($seclevelr,$seclevelm,$seclevel, @@ -4918,10 +5145,41 @@ sub EXT { if ($space eq 'time') { return time; } + } elsif ($realm eq 'server') { +# ----------------------------------------------------------------- system.time + if ($space eq 'name') { + return $ENV{'SERVER_NAME'}; + } } return ''; } +sub check_group_parms { + my ($courseid,$groups,$symbparm,$mapparm,$what) = @_; + my @groupitems = (); + my $resultitem; + my @levels = ($symbparm,$mapparm,$what); + foreach my $group (@{$groups}) { + foreach my $level (@levels) { + my $item = $courseid.'.['.$group.'].'.$level; + push(@groupitems,$item); + } + } + my $coursereply = &resdata($env{'course.'.$courseid.'.num'}, + $env{'course.'.$courseid.'.domain'}, + 'course',@groupitems); + return $coursereply; +} + +sub sort_course_groups { # Sort groups based on defined rankings. Default is sort(). + my ($grouplist,$courseid) = @_; + my @groups = split/:/,$grouplist; + if (@groups > 1) { + @groups = sort(@groups); + } + return @groups; +} + sub packages_tab_default { my ($uri,$varname)=@_; my (undef,$part,$name)=split(/\./,$varname); @@ -5149,7 +5407,7 @@ sub metadata { $metaentry{':keys'}=join(',',keys %metathesekeys); &metadata_generate_part0(\%metathesekeys,\%metaentry,$uri); $metaentry{':allpossiblekeys'}=join(',',keys %metathesekeys); - &do_cache_new('meta',$uri,\%metaentry,60*60*24); + &do_cache_new('meta',$uri,\%metaentry,60*60); # this is the end of "was not already recently cached } return $metaentry{':'.$what}; @@ -5245,10 +5503,17 @@ sub get_slot { $cdom=$env{'course.'.$courseid.'.domain'}; $cnum=$env{'course.'.$courseid.'.num'}; } - my %slotinfo=&get('slots',[$which],$cdom,$cnum); - &Apache::lonhomework::showhash(%slotinfo); - my ($tmp)=keys(%slotinfo); - if ($tmp=~/^error:/) { return (); } + my $key=join("\0",'slots',$cdom,$cnum,$which); + my %slotinfo; + if (exists($remembered{$key})) { + $slotinfo{$which} = $remembered{$key}; + } else { + %slotinfo=&get('slots',[$which],$cdom,$cnum); + &Apache::lonhomework::showhash(%slotinfo); + my ($tmp)=keys(%slotinfo); + if ($tmp=~/^error:/) { return (); } + $remembered{$key} = $slotinfo{$which}; + } if (ref($slotinfo{$which}) eq 'HASH') { return %{$slotinfo{$which}}; } @@ -5263,9 +5528,12 @@ sub symblist { if (($env{'request.course.fn'}) && (%newhash)) { if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', &GDBM_WRCREAT(),0640)) { - foreach (keys %newhash) { - $hash{declutter($_)}=&encode_symb($mapname,$newhash{$_}->[1], - $newhash{$_}->[0]); + foreach my $url (keys %newhash) { + next if ($url eq 'last_known' + && $env{'form.no_update_last_known'}); + $hash{declutter($url)}=&encode_symb($mapname, + $newhash{$url}->[1], + $newhash{$url}->[0]); } if (untie(%hash)) { return 'ok'; @@ -5282,6 +5550,7 @@ sub symbverify { my $thisfn=$thisurl; # wrapper not part of symbs $thisfn=~s/^\/adm\/wrapper//; + $thisfn=~s/^\/adm\/coursedocs\/showdoc\///; $thisfn=&declutter($thisfn); # direct jump to resource in page or to a sequence - will construct own symbs if ($thisfn=~/\.(page|sequence)$/) { return 1; } @@ -5336,6 +5605,7 @@ sub symbclean { # remove wrapper $symb=~s/(\_\_\_\d+\_\_\_)adm\/wrapper\/(res\/)*/$1/; + $symb=~s/(\_\_\_\d+\_\_\_)adm\/coursedocs\/showdoc\/(res\/)*/$1/; return $symb; } @@ -5412,6 +5682,9 @@ sub symbread { if ( ($thisfn =~ m/^(uploaded|editupload)\//) && ($thisfn !~ m/\.(page|sequence)$/) ) { $targetfn = 'adm/wrapper/'.$thisfn; } + if ($targetfn =~ m|^adm/wrapper/(ext/.*)|) { + $targetfn=$1; + } if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', &GDBM_READER(),0640)) { $syval=$hash{$targetfn}; @@ -5983,6 +6256,11 @@ sub filelocation { my ($dir,$file) = @_; my $location; $file=~ s/^\s*(\S+)\s*$/$1/; ## strip off leading and trailing spaces + + if ($file =~ m-^/adm/-) { + $file=~s-^/adm/wrapper/-/-; + $file=~s-^/adm/coursedocs/showdoc/-/-; + } if ($file=~m:^/~:) { # is a contruction space reference $location = $file; $location =~ s:/~(.*?)/(.*):/home/$1/public_html/$2:; @@ -6022,6 +6300,9 @@ sub hreflocation { my ($dir,$file)=@_; unless (($file=~m-^http://-i) || ($file=~m-^/-)) { $file=filelocation($dir,$file); + } elsif ($file=~m-^/adm/-) { + $file=~s-^/adm/wrapper/-/-; + $file=~s-^/adm/coursedocs/showdoc/-/-; } if ($file=~m-^\Q$perlvar{'lonDocRoot'}\E-) { $file=~s-^\Q$perlvar{'lonDocRoot'}\E--; @@ -6065,6 +6346,8 @@ sub declutter { if ($thisfn=~m|^/enc/|) { $thisfn=&Apache::lonenc::unencrypted($thisfn); } $thisfn=~s/^\Q$perlvar{'lonDocRoot'}\E//; $thisfn=~s/^\///; + $thisfn=~s|^adm/wrapper/||; + $thisfn=~s|^adm/coursedocs/showdoc/||; $thisfn=~s/^res\///; $thisfn=~s/\?.+$//; return $thisfn; @@ -6077,6 +6360,30 @@ sub clutter { unless ($thisfn=~/^\/(uploaded|editupload|adm|userfiles|ext|raw|priv|public)\//) { $thisfn='/res'.$thisfn; } + if ($thisfn !~m|/adm|) { + if ($thisfn =~ m|/ext/|) { + $thisfn='/adm/wrapper'.$thisfn; + } else { + my ($ext) = ($thisfn =~ /\.(\w+)$/); + my $embstyle=&Apache::loncommon::fileembstyle($ext); + if ($embstyle eq 'ssi' + || ($embstyle eq 'hdn') + || ($embstyle eq 'rat') + || ($embstyle eq 'prv') + || ($embstyle eq 'ign')) { + #do nothing with these + } elsif (($embstyle eq 'img') + || ($embstyle eq 'emb') + || ($embstyle eq 'wrp')) { + $thisfn='/adm/wrapper'.$thisfn; + } elsif ($embstyle eq 'unk' + && $thisfn!~/\.(sequence|page)$/) { + $thisfn='/adm/coursedocs/showdoc'.$thisfn; + } else { + &logthis("Got a blank emb style"); + } + } + } return $thisfn; } @@ -6185,7 +6492,7 @@ BEGIN { # next if /^\#/; chomp; my ($domain, $domain_description, $def_auth, $def_auth_arg, - $def_lang, $city, $longi, $lati) = split(/:/,$_); + $def_lang, $city, $longi, $lati, $primary) = split(/:/,$_); $domain_auth_def{$domain}=$def_auth; $domain_auth_arg_def{$domain}=$def_auth_arg; $domaindescription{$domain}=$domain_description; @@ -6193,6 +6500,7 @@ BEGIN { $domain_city{$domain}=$city; $domain_longi{$domain}=$longi; $domain_lati{$domain}=$lati; + $domain_primary{$domain}=$primary; # &logthis("Domain.tab: $domain, $domain_auth_def{$domain}, $domain_auth_arg_def{$domain},$domaindescription{$domain}"); # &logthis("Domain.tab: $domain ".$domaindescription{$domain} ); @@ -6922,10 +7230,15 @@ namesp ($udom and $uname are optional) =item * -dump($namespace,$udom,$uname,$regexp) : +dump($namespace,$udom,$uname,$regexp,$range) : dumps the complete (or key matching regexp) namespace into a hash -($udom, $uname and $regexp are optional) +($udom, $uname, $regexp, $range are optional) +$range should be either an integer '100' (give me the first 100 + matching records) + or be two integers sperated by a - with no spaces + '30-50' (give me the 30th through the 50th matching + records) =item * inc($namespace,$store,$udom,$uname) : increments $store in $namespace. @@ -7081,6 +7394,16 @@ getfile($file,$caller) : two cases - req - returns the entire contents of a file or -1; it properly subscribes to and replicates the file if neccessary. + +=item * + +stat_file($url) : $url is expected to be a /res/ or /uploaded/ style file + reference + +returns either a stat() list of data about the file or an empty list +if the file doesn't exist or couldn't find out about it (connection +problems or user unknown) + =item * filelocation($dir,$file) : returns file system location of a file