--- loncom/lonnet/perl/lonnet.pm 2020/01/17 04:51:33 1.1417 +++ loncom/lonnet/perl/lonnet.pm 2020/10/01 10:16:34 1.1426 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1417 2020/01/17 04:51:33 raeburn Exp $ +# $Id: lonnet.pm,v 1.1426 2020/10/01 10:16:34 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -1230,6 +1230,28 @@ sub choose_server { return ($login_host,$hostname,$portal_path,$isredirect,$lowest_load); } +sub get_course_sessions { + my ($cnum,$cdom,$lastactivity) = @_; + my %servers = &internet_dom_servers($cdom); + my %returnhash; + foreach my $server (sort(keys(%servers))) { + my $rep = &reply("coursesessions:$cdom:$cnum:$lastactivity",$server); + my @pairs=split(/\&/,$rep); + unless (($rep eq 'unknown_cmd') || ($rep =~ /^error/)) { + foreach my $item (@pairs) { + my ($key,$value)=split(/=/,$item,2); + $key = &unescape($key); + next if ($key =~ /^error: 2 /); + if (exists($returnhash{$key})) { + next if ($value < $returnhash{$key}); + } + $returnhash{$key}=$value; + } + } + } + return %returnhash; +} + # --------------------------------------------- Try to change a user's password sub changepass { @@ -3361,6 +3383,32 @@ sub repcopy { } } +# ------------------------------------------------- Unsubscribe from a resource + +sub unsubscribe { + my ($fname) = @_; + my $answer; + if ($fname=~/\/(aboutme|syllabus|bulletinboard|smppg)$/) { return $answer; } + $fname=~s/[\n\r]//g; + my $author=$fname; + $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/; + my ($udom,$uname)=split(/\//,$author); + my $home=homeserver($uname,$udom); + if ($home eq 'no_host') { + $answer = 'no_host'; + } elsif (grep { $_ eq $home } ¤t_machine_ids()) { + $answer = 'home'; + } else { + my $defdom = $perlvar{'lonDefDomain'}; + if (&will_trust('content',$defdom,$udom)) { + $answer = reply("unsub:$fname",$home); + } else { + $answer = 'untrusted'; + } + } + return $answer; +} + # ------------------------------------------------ Get server side include body sub ssi_body { my ($filelink,%form)=@_; @@ -3506,12 +3554,18 @@ sub remove_stale_resfile { $stale = 1; } if ($stale) { - unlink($fname); - if ($uri!~/\.meta$/) { - unlink($fname.'.meta'); + if (unlink($fname)) { + if ($uri!~/\.meta$/) { + if (-e $fname.'.meta') { + unlink($fname.'.meta'); + } + } + my $unsubresult = &unsubscribe($fname); + unless ($unsubresult eq 'ok') { + &logthis("no unsub of $fname from $homeserver, reason: $unsubresult"); + } + $removed = 1; } - &reply("unsub:$fname",$homeserver); - $removed = 1; } } } @@ -3661,6 +3715,18 @@ sub can_edit_resource { $forceedit = 1; } $cfile = $resurl; + } elsif (($resurl =~ m{^/ext/}) && ($symb ne '')) { + my ($map,$id,$res) = &decode_symb($symb); + if ($map =~ /\.page$/) { + $incourse = 1; + if ($env{'form.forceedit'}) { + $forceview = 1; + $cfile = $map; + } else { + $forceedit = 1; + $cfile = '/adm/wrapper'.$resurl; + } + } } elsif ($resurl =~ m{^/adm/wrapper/adm/$cdom/$cnum/\d+/ext\.tool$}) { $incourse = 1; if ($env{'form.forceedit'}) { @@ -3686,13 +3752,13 @@ sub can_edit_resource { $cfile = $template; } } elsif (($resurl =~ m{^/adm/wrapper/ext/}) && ($env{'form.folderpath'} =~ /^supplemental/)) { - $incourse = 1; - if ($env{'form.forceedit'}) { - $forceview = 1; - } else { - $forceedit = 1; - } - $cfile = $resurl; + $incourse = 1; + if ($env{'form.forceedit'}) { + $forceview = 1; + } else { + $forceedit = 1; + } + $cfile = $resurl; } elsif (($resurl =~ m{^/adm/wrapper/adm/$cdom/$cnum/\d+/ext\.tool$}) && ($env{'form.folderpath'} =~ /^supplemental/)) { $incourse = 1; if ($env{'form.forceedit'}) { @@ -7970,7 +8036,7 @@ sub customaccess { # ------------------------------------------------- Check for a user privilege sub allowed { - my ($priv,$uri,$symb,$role,$clientip,$noblockcheck)=@_; + my ($priv,$uri,$symb,$role,$clientip,$noblockcheck,$ignorecache)=@_; my $ver_orguri=$uri; $uri=&deversion($uri); my $orguri=$uri; @@ -8201,7 +8267,7 @@ sub allowed { } elsif ($noblockcheck) { $thisallowed.=$value; } else { - my @blockers = &has_comm_blocking($priv,$symb,$uri); + my @blockers = &has_comm_blocking($priv,$symb,$uri,$ignorecache); if (@blockers > 0) { $thisallowed = 'B'; } else { @@ -8224,7 +8290,7 @@ sub allowed { } elsif ($noblockcheck) { $thisallowed='F'; } else { - my @blockers = &has_comm_blocking($priv,$symb,$refuri); + my @blockers = &has_comm_blocking($priv,'',$refuri,'',1); if (@blockers > 0) { $thisallowed = 'B'; } else { @@ -8297,7 +8363,7 @@ sub allowed { if ($noblockcheck) { $thisallowed.=$value; } else { - my @blockers = &has_comm_blocking($priv,$symb,$uri); + my @blockers = &has_comm_blocking($priv,$symb,$uri,$ignorecache); if (@blockers > 0) { $thisallowed = 'B'; } else { @@ -8310,7 +8376,7 @@ sub allowed { $checkreferer=0; } } - + if ($checkreferer) { my $refuri=$env{'httpref.'.$orguri}; unless ($refuri) { @@ -8342,7 +8408,7 @@ sub allowed { } elsif ($noblockcheck) { $thisallowed.=$value; } else { - my @blockers = &has_comm_blocking($priv,$symb,$refuri); + my @blockers = &has_comm_blocking($priv,'',$refuri,'',1); if (@blockers > 0) { $thisallowed = 'B'; } else { @@ -8428,7 +8494,7 @@ sub allowed { } } } - + # # Rest of the restrictions depend on selected course # @@ -8597,6 +8663,10 @@ sub constructaccess { # # User for whom data are being temporarily cached. my $cacheduser=''; +# Course for which data are being temporarily cached. +my $cachedcid=''; +# List of blocks passed to &get_commblock_resources(); +my $cachedblocks=''; # Cached blockers for this user (a hash of blocking items). my %cachedblockers=(); # When the data were last cached. @@ -8606,13 +8676,22 @@ sub load_all_blockers { my ($uname,$udom,$blocks)=@_; if (($uname ne '') && ($udom ne '')) { if (($cacheduser eq $uname.':'.$udom) && - (abs($cachedlast-time)<5)) { + ($cachedcid eq $env{'request.course.id'}) && + (abs($cachedlast-time)<5) && + (((ref($blocks) eq 'HASH') && + ($cachedblocks eq join(',',sort(keys(%{$blocks}))))) || + (!ref($blocks) && $cachedblocks eq ''))) { return; } } $cachedlast=time; $cacheduser=$uname.':'.$udom; + $cachedcid=$env{'request.course.id'}; %cachedblockers = &get_commblock_resources($blocks); + if ((ref($blocks) eq 'HASH') && (keys(%{$blocks}) > 0)) { + $cachedblocks = join(',',sort(keys(%{$blocks}))); + } + return; } sub get_comm_blocks { @@ -8750,7 +8829,7 @@ sub get_commblock_resources { } sub has_comm_blocking { - my ($priv,$symb,$uri,$blocks) = @_; + my ($priv,$symb,$uri,$nosymbcache,$noenccheck,$blocked,$blocks) = @_; my @blockers; return unless ($env{'request.course.id'}); return unless ($priv eq 'bre'); @@ -8760,7 +8839,7 @@ sub has_comm_blocking { return unless (keys(%cachedblockers) > 0); my (%possibles,@symbs); if (!$symb) { - $symb = &symbread($uri,1,1,1,\%possibles); + $symb = &symbread($uri,1,1,1,\%possibles,$nosymbcache,$noenccheck); } if ($symb) { @symbs = ($symb); @@ -8774,9 +8853,11 @@ sub has_comm_blocking { foreach my $block (keys(%cachedblockers)) { if ($block =~ /^firstaccess____(.+)$/) { my $item = $1; - if (($item eq $map) || ($item eq $symb)) { - $noblock = 1; - last; + unless ($blocked) { + if (($item eq $map) || ($item eq $symb)) { + $noblock = 1; + last; + } } } if (ref($cachedblockers{$block}) eq 'HASH') { @@ -8787,18 +8868,20 @@ sub has_comm_blocking { } } } - } - if (ref($cachedblockers{$block}{'maps'}) eq 'HASH') { - if ($cachedblockers{$block}{'maps'}{$map}) { - unless (grep(/^\Q$block\E$/,@blockers)) { - push(@blockers,$block); + if (ref($cachedblockers{$block}{'maps'}) eq 'HASH') { + if ($cachedblockers{$block}{'maps'}{$map}) { + unless (grep(/^\Q$block\E$/,@blockers)) { + push(@blockers,$block); + } } } } } } - return if ($noblock); - return @blockers; + unless ($noblock) { + return @blockers; + } + return; } } @@ -10541,14 +10624,19 @@ sub writecoursepref { sub createcourse { my ($udom,$description,$url,$course_server,$nonstandard,$inst_code, - $course_owner,$crstype,$cnum,$context,$category)=@_; + $course_owner,$crstype,$cnum,$context,$category,$callercontext)=@_; $url=&declutter($url); my $cid=''; if ($context eq 'requestcourses') { my $can_create = 0; my ($ownername,$ownerdom) = split(':',$course_owner); if ($udom eq $ownerdom) { - if (&usertools_access($ownername,$ownerdom,$category,undef, + my $reload; + if (($callercontext eq 'auto') && + ($ownerdom eq $env{'user.domain'}) && ($ownername eq $env{'user.name'})) { + $reload = 'reload'; + } + if (&usertools_access($ownername,$ownerdom,$category,$reload, $context)) { $can_create = 1; } @@ -13112,18 +13200,16 @@ sub symbverify { if (tie(%bighash,'GDBM_File',$env{'request.course.fn'}.'.db', &GDBM_READER(),0640)) { - my $noclutter; if (($thisurl =~ m{^/adm/wrapper/ext/}) || ($thisurl =~ m{^ext/})) { $thisurl =~ s/\?.+$//; if ($map =~ m{^uploaded/.+\.page$}) { $thisurl =~ s{^(/adm/wrapper|)/ext/}{http://}; $thisurl =~ s{^\Qhttp://https://\E}{https://}; - $noclutter = 1; } } my $ids; - if ($noclutter) { - $ids=$bighash{'ids_'.$thisurl}; + if ($map =~ m{^uploaded/.+\.page$}) { + $ids=$bighash{'ids_'.&clutter_with_no_wrapper($thisurl)}; } else { $ids=$bighash{'ids_'.&clutter($thisurl)}; } @@ -13223,19 +13309,26 @@ sub deversion { # ------------------------------------------------------ Return symb list entry sub symbread { - my ($thisfn,$donotrecurse,$ignorecachednull,$checkforblock,$possibles)=@_; + my ($thisfn,$donotrecurse,$ignorecachednull,$checkforblock,$possibles, + $nocache,$noenccheck)=@_; my $cache_str='request.symbread.cached.'.$thisfn; - if (defined($env{$cache_str})) { - if ($ignorecachednull) { - return $env{$cache_str} unless ($env{$cache_str} eq ''); - } else { - return $env{$cache_str}; + if (defined($env{$cache_str}) && !$nocache) { + unless (ref($possibles) eq 'HASH') { + if ($ignorecachednull) { + return $env{$cache_str} unless ($env{$cache_str} eq ''); + } else { + return $env{$cache_str}; + } } } # no filename provided? try from environment unless ($thisfn) { if ($env{'request.symb'}) { - return $env{$cache_str}=&symbclean($env{'request.symb'}); + if ($nocache) { + return &symbclean($env{'request.symb'}); + } else { + return $env{$cache_str}=&symbclean($env{'request.symb'}); + } } $thisfn=$env{'request.filename'}; } @@ -13243,7 +13336,11 @@ sub symbread { # is that filename actually a symb? Verify, clean, and return if ($thisfn=~/\_\_\_\d+\_\_\_(.*)$/) { if (&symbverify($thisfn,$1)) { - return $env{$cache_str}=&symbclean($thisfn); + if ($nocache) { + return &symbclean($thisfn); + } else { + return $env{$cache_str}=&symbclean($thisfn); + } } } $thisfn=declutter($thisfn); @@ -13258,10 +13355,18 @@ sub symbread { 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}; - untie(%hash); + unless ($nocache) { + if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', + &GDBM_READER(),0640)) { + $syval=$hash{$targetfn}; + untie(%hash); + } + if ($syval) { + my @blockers = &has_comm_blocking('bre',$syval,$thisfn,$nocache,$noenccheck); + if (@blockers) { + $syval=''; + } + } } # ---------------------------------------------------------- There was an entry if ($syval) { @@ -13294,13 +13399,19 @@ sub symbread { $syval=&encode_symb($bighash{'map_id_'.$mapid}, $resid,$thisfn); if (ref($possibles) eq 'HASH') { - $possibles->{$syval} = 1; + unless ($bighash{'randomout_'.$ids} || $env{'request.role.adv'}) { + $possibles->{$syval} = 1; + } } if ($checkforblock) { - my @blockers = &has_comm_blocking('bre',$syval,$bighash{'src_'.$ids}); - if (@blockers) { - $syval = ''; - return; + unless ($bighash{'randomout_'.$ids} || $env{'request.role.adv'}) { + my @blockers = &has_comm_blocking('bre',$syval,$bighash{'src_'.$ids},'',$noenccheck); + if (@blockers) { + $syval = ''; + untie(%bighash); + return '' if ($nocache); + return $env{$cache_str}=''; + } } } } elsif ((!$donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) { @@ -13319,12 +13430,13 @@ sub symbread { if ($bighash{'map_type_'.$mapid} ne 'page') { my $poss_syval=&encode_symb($bighash{'map_id_'.$mapid}, $resid,$thisfn); - if (ref($possibles) eq 'HASH') { - $possibles->{$syval} = 1; - } + next if ($bighash{'randomout_'.$id} && !$env{'request.role.adv'}); + next unless (($noenccheck) || ($bighash{'encrypted_'.$id} eq $env{'request.enc'})); if ($checkforblock) { - my @blockers = &has_comm_blocking('bre',$poss_syval,$file); - unless (@blockers > 0) { + my @blockers = &has_comm_blocking('bre',$poss_syval,$file,'',$noenccheck); + if (@blockers > 0) { + $syval = ''; + } else { $syval = $poss_syval; $realpossible++; } @@ -13332,6 +13444,11 @@ sub symbread { $syval = $poss_syval; $realpossible++; } + if ($syval) { + if (ref($possibles) eq 'HASH') { + $possibles->{$syval} = 1; + } + } } } } @@ -13344,10 +13461,15 @@ sub symbread { } } if ($syval) { - return $env{$cache_str}=$syval; + if ($nocache) { + return $syval; + } else { + return $env{$cache_str}=$syval; + } } } &appenv({'request.ambiguous' => $thisfn}); + return '' if ($nocache); return $env{$cache_str}=''; }