--- loncom/lonnet/perl/lonnet.pm 2016/08/05 15:34:27 1.1172.2.72 +++ loncom/lonnet/perl/lonnet.pm 2015/08/10 15:18:21 1.1291 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1172.2.72 2016/08/05 15:34:27 raeburn Exp $ +# $Id: lonnet.pm,v 1.1291 2015/08/10 15:18:21 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -75,6 +75,9 @@ use LWP::UserAgent(); use HTTP::Date; use Image::Magick; + +use Encode; + use vars qw(%perlvar %spareid %pr %prp $memcache %packagetab $tmpdir $_64bit %env %protocol %loncaparevs %serverhomeIDs %needsrelease %managerstab); @@ -89,7 +92,7 @@ use GDBM_File; use HTML::LCParser; use Fcntl qw(:flock); use Storable qw(thaw nfreeze); -use Time::HiRes qw( gettimeofday tv_interval ); +use Time::HiRes qw( sleep gettimeofday tv_interval ); use Cache::Memcached; use Digest::MD5; use Math::Random; @@ -102,13 +105,14 @@ use LONCAPA::Lond; use File::Copy; my $readit; -my $max_connection_retries = 10; # Or some such value. +my $max_connection_retries = 20; # Or some such value. require Exporter; our @ISA = qw (Exporter); our @EXPORT = qw(%env); + # ------------------------------------ Logging (parameters, docs, slots, roles) { my $logid; @@ -123,19 +127,19 @@ our @EXPORT = qw(%env); $logid ++; my $now = time(); my $id=$now.'00000'.$$.'00000'.$logid; - my $logentry = { - $id => { - 'exe_uname' => $env{'user.name'}, - 'exe_udom' => $env{'user.domain'}, - 'exe_time' => $now, - 'exe_ip' => $ENV{'REMOTE_ADDR'}, - 'delflag' => $delflag, - 'logentry' => $storehash, - 'uname' => $uname, - 'udom' => $udom, - } + my $logentry = { + $id => { + 'exe_uname' => $env{'user.name'}, + 'exe_udom' => $env{'user.domain'}, + 'exe_time' => $now, + 'exe_ip' => $ENV{'REMOTE_ADDR'}, + 'delflag' => $delflag, + 'logentry' => $storehash, + 'uname' => $uname, + 'udom' => $udom, + } }; - return &put('nohist_'.$hash_name,$logentry,$cdom,$cnum); + return &put('nohist_'.$hash_name,$logentry,$cdom,$cnum); } } @@ -356,7 +360,8 @@ sub remote_devalidate_cache { my $items; return unless (ref($cachekeys) eq 'ARRAY'); my $cachestr = join('&',@{$cachekeys}); - return &reply('devalidatecache:'.&escape($cachestr),$lonhost); + my $response = &reply('devalidatecache:'.&escape($cachestr),$lonhost); + return $response; } # -------------------------------------------------- Non-critical communication @@ -370,7 +375,7 @@ sub subreply { my $lockfile=$peerfile.".lock"; while (-e $lockfile) { # Need to wait for the lockfile to disappear. - sleep(1); + sleep(0.1); } # At this point, either a loncnew parent is listening or an old lonc # or loncnew child is listening so we can connect or everything's dead. @@ -388,7 +393,7 @@ sub subreply { } else { &create_connection(&hostname($server),$server); } - sleep(1); # Try again later if failed connection. + sleep(0.1); # Try again later if failed connection. } my $answer; if ($client) { @@ -417,8 +422,8 @@ sub reply { sub reconlonc { my ($lonid) = @_; + my $hostname = &hostname($lonid); if ($lonid) { - my $hostname = &hostname($lonid); my $peerfile="$perlvar{'lonSockDir'}/$hostname"; if ($hostname && -e $peerfile) { &logthis("Trying to reconnect lonc for $lonid ($hostname)"); @@ -464,7 +469,7 @@ sub critical { } my $answer=reply($cmd,$server); if ($answer eq 'con_lost') { - &reconlonc($server); + &reconlonc("$perlvar{'lonSockDir'}/$server"); my $answer=reply($cmd,$server); if ($answer eq 'con_lost') { my $now=time; @@ -481,7 +486,7 @@ sub critical { close($dfh); } } - sleep 2; + sleep 1; my $wcmd=''; { my $dfh; @@ -970,12 +975,12 @@ sub choose_server { } } foreach my $lonhost (keys(%servers)) { - my $loginvia; if ($skiploadbal) { if (ref($balancers) eq 'HASH') { next if (exists($balancers->{$lonhost})); } - } + } + my $loginvia; if ($checkloginvia) { $loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost}; if ($loginvia) { @@ -1301,7 +1306,7 @@ sub check_loadbalancing { } } if (ref($result) eq 'HASH') { - ($is_balancer,$currtargets,$currrules) = + ($is_balancer,$currtargets,$currrules) = &check_balancer_result($result,@hosts); if ($is_balancer) { if (ref($currrules) eq 'HASH') { @@ -1360,7 +1365,7 @@ sub check_loadbalancing { } } if (ref($result) eq 'HASH') { - ($is_balancer,$currtargets,$currrules) = + ($is_balancer,$currtargets,$currrules) = &check_balancer_result($result,@hosts); if ($is_balancer) { if (ref($currrules) eq 'HASH') { @@ -1416,8 +1421,8 @@ sub check_loadbalancing { $is_balancer = 0; if ($uname ne '' && $udom ne '') { if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) { - - &appenv({'user.loadbalexempt' => $lonhost, + + &appenv({'user.loadbalexempt' => $lonhost, 'user.loadbalcheck.time' => time}); } } @@ -1606,7 +1611,7 @@ sub idput { } } -# ---------------------------------------- Delete unwanted IDs from ids.db file +# ---------------------------------------- Delete unwanted IDs from ids.db file sub iddel { my ($udom,$idshashref,$uhome)=@_; @@ -1938,7 +1943,7 @@ sub get_multiple_instusers { my ($udom,$users,$caller) = @_; my ($outcome,$results); if (ref($users) eq 'HASH') { - my $count = keys(%{$users}); + my $count = keys(%{$users}); my $requested = &freeze_escape($users); my $homeserver = &domain($udom,'primary'); if ($homeserver ne '') { @@ -1982,7 +1987,7 @@ sub get_multiple_instusers { } else { ($outcome,my $userdata) = split(/=/,$response,2); if ($outcome eq 'ok') { - $results = &thaw_unescape($userdata); + $results = &thaw_unescape($userdata); } } } @@ -2131,6 +2136,7 @@ sub get_domain_defaults { } } if (ref($domconfig{'coursedefaults'}) eq 'HASH') { + $domdefaults{'canuse_pdfforms'} = $domconfig{'coursedefaults'}{'canuse_pdfforms'}; $domdefaults{'usejsme'} = $domconfig{'coursedefaults'}{'usejsme'}; $domdefaults{'uselcmath'} = $domconfig{'coursedefaults'}{'uselcmath'}; if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') { @@ -2147,8 +2153,8 @@ sub get_domain_defaults { } if ($domdefaults{'postsubmit'} eq 'on') { if (ref($domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') { - $domdefaults{$type.'postsubtimeout'} = - $domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}{$type}; + $domdefaults{$type.'postsubtimeout'} = + $domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}{$type}; } } } @@ -2205,7 +2211,7 @@ sub get_domain_defaults { if (ref($domconfig{'coursecategories'}) eq 'HASH') { $domdefaults{'catauth'} = 'std'; $domdefaults{'catunauth'} = 'std'; - if ($domconfig{'coursecategories'}{'auth'}) { + if ($domconfig{'coursecategories'}{'auth'}) { $domdefaults{'catauth'} = $domconfig{'coursecategories'}{'auth'}; } if ($domconfig{'coursecategories'}{'unauth'}) { @@ -2802,11 +2808,11 @@ sub ssi { &Apache::lonenc::check_encrypt(\$fn); if (%form) { $request=new HTTP::Request('POST',&absolute_url().$fn); - $request->content(join('&',map { + $request->content(join('&',map { my $name = escape($_); - "$name=" . ( ref($form{$_}) eq 'ARRAY' - ? join("&$name=", map {escape($_) } @{$form{$_}}) - : &escape($form{$_}) ); + "$name=" . ( ref($form{$_}) eq 'ARRAY' + ? join("&$name=", map {escape($_) } @{$form{$_}}) + : &escape($form{$_}) ); } keys(%form))); } else { $request=new HTTP::Request('GET',&absolute_url().$fn); @@ -2814,10 +2820,13 @@ sub ssi { $request->header(Cookie => $ENV{'HTTP_COOKIE'}); my $response= $ua->request($request); + my $content = $response->content; + + if (wantarray) { - return ($response->content, $response); + return ($content, $response); } else { - return $response->content; + return $content; } } @@ -2849,7 +2858,7 @@ sub allowuploaded { # # Determine if the current user should be able to edit a particular resource, # when viewing in course context. -# (a) When viewing resource used to determine if "Edit" item is included in +# (a) When viewing resource used to determine if "Edit" item is included in # Functions. # (b) When displaying folder contents in course editor, used to determine if # "Edit" link will be displayed alongside resource. @@ -2857,12 +2866,12 @@ sub allowuploaded { # input: six args -- filename (decluttered), course number, course domain, # url, symb (if registered) and group (if this is a group # item -- e.g., bulletin board, group page etc.). -# output: array of five scalars -- +# output: array of five scalars -- # $cfile -- url for file editing if editable on current server # $home -- homeserver of resource (i.e., for author if published, # or course if uploaded.). # $switchserver -- 1 if server switch will be needed. -# $forceedit -- 1 if icon/link should be to go to edit mode +# $forceedit -- 1 if icon/link should be to go to edit mode # $forceview -- 1 if icon/link should be to go to view mode # @@ -2951,7 +2960,7 @@ sub can_edit_resource { $forceedit = 1; } $cfile = $resurl; - } elsif (($resurl ne '') && (&is_on_map($resurl))) { + } elsif (($resurl ne '') && (&is_on_map($resurl))) { if ($resurl =~ m{^/adm/$match_domain/$match_username/\d+/smppg|bulletinboard$}) { $incourse = 1; if ($env{'form.forceedit'}) { @@ -2982,7 +2991,7 @@ sub can_edit_resource { } } elsif ($resurl eq '/res/lib/templates/simpleproblem.problem/smpedit') { my $template = '/res/lib/templates/simpleproblem.problem'; - if (&is_on_map($template)) { + if (&is_on_map($template)) { $incourse = 1; $forceview = 1; $cfile = $template; @@ -3029,7 +3038,7 @@ sub can_edit_resource { $cfile=$file; } } - if (($cfile ne '') && (!$incourse || $uploaded) && + if (($cfile ne '') && (!$incourse || $uploaded) && (($home ne '') && ($home ne 'no_host'))) { my @ids=¤t_machine_ids(); unless (grep(/^\Q$home\E$/,@ids)) { @@ -3056,9 +3065,9 @@ sub in_course { if ($hideprivileged) { my $skipuser; my %coursehash = &coursedescription($cdom.'_'.$cnum); - my @possdoms = ($cdom); - if ($coursehash{'checkforpriv'}) { - push(@possdoms,split(/,/,$coursehash{'checkforpriv'})); + my @possdoms = ($cdom); + if ($coursehash{'checkforpriv'}) { + push(@possdoms,split(/,/,$coursehash{'checkforpriv'})); } if (&privileged($uname,$udom,\@possdoms)) { $skipuser = 1; @@ -3562,7 +3571,7 @@ sub extract_embedded_items { } if (lc($tagname) eq 'a') { unless (($attr->{'href'} =~ /^#/) || ($attr->{'href'} eq '')) { - &add_filetype($allfiles,$attr->{'href'},'href'); + &add_filetype($allfiles,$attr->{'href'},'href'); } } if (lc($tagname) eq 'script') { @@ -4233,7 +4242,7 @@ sub get_my_roles { } else { my $possdoms = [$domain]; if (ref($roledoms) eq 'ARRAY') { - push(@{$possdoms},@{$roledoms}); + push(@{$possdoms},@{$roledoms}); } if (&privileged($username,$domain,$possdoms,\@privroles)) { if (!$nothide{$username.':'.$domain}) { @@ -4341,16 +4350,16 @@ sub courseiddump { if (($domfilter eq '') || (&host_domain($tryserver) eq $domfilter)) { my $rep; - if (grep { $_ eq $tryserver } ¤t_machine_ids()) { - $rep = &LONCAPA::Lond::dump_course_id_handler( - join(":", (&host_domain($tryserver), $sincefilter, - &escape($descfilter), &escape($instcodefilter), + if (grep { $_ eq $tryserver } current_machine_ids()) { + $rep = LONCAPA::Lond::dump_course_id_handler( + join(":", (&host_domain($tryserver), $sincefilter, + &escape($descfilter), &escape($instcodefilter), &escape($ownerfilter), &escape($coursefilter), - &escape($typefilter), &escape($regexp_ok), - $as_hash, &escape($selfenrollonly), - &escape($catfilter), $showhidden, $caller, - &escape($cloner), &escape($cc_clone), $cloneonly, - &escape($createdbefore), &escape($createdafter), + &escape($typefilter), &escape($regexp_ok), + $as_hash, &escape($selfenrollonly), + &escape($catfilter), $showhidden, $caller, + &escape($cloner), &escape($cc_clone), $cloneonly, + &escape($createdbefore), &escape($createdafter), &escape($creationcontext),$domcloner,$hasuniquecode, $reqcrsdom,&escape($reqinstcode)))); } else { @@ -4366,7 +4375,7 @@ sub courseiddump { &escape($creationcontext).':'.$domcloner.':'.$hasuniquecode. ':'.$reqcrsdom.':'.&escape($reqinstcode),$tryserver); } - + my @pairs=split(/\&/,$rep); foreach my $item (@pairs) { my ($key,$value)=split(/\=/,$item,2); @@ -4566,91 +4575,6 @@ sub set_first_access { } } -sub checkout { - my ($symb,$tuname,$tudom,$tcrsid)=@_; - my $now=time; - my $lonhost=$perlvar{'lonHostID'}; - my $infostr=&escape( - 'CHECKOUTTOKEN&'. - $tuname.'&'. - $tudom.'&'. - $tcrsid.'&'. - $symb.'&'. - $now.'&'.$ENV{'REMOTE_ADDR'}); - my $token=&reply('tmpput:'.$infostr,$lonhost); - if ($token=~/^error\:/) { - &logthis("WARNING: ". - "Checkout tmpput failed ".$tudom.' - '.$tuname.' - '.$symb. - ""); - return ''; - } - - $token=~s/^(\d+)\_.*\_(\d+)$/$1\*$2\*$lonhost/; - $token=~tr/a-z/A-Z/; - - my %infohash=('resource.0.outtoken' => $token, - 'resource.0.checkouttime' => $now, - 'resource.0.outremote' => $ENV{'REMOTE_ADDR'}); - - unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') { - return ''; - } else { - &logthis("WARNING: ". - "Checkout cstore failed ".$tudom.' - '.$tuname.' - '.$symb. - ""); - } - - if (&log($tudom,$tuname,&homeserver($tuname,$tudom), - &escape('Checkout '.$infostr.' - '. - $token)) ne 'ok') { - return ''; - } else { - &logthis("WARNING: ". - "Checkout log failed ".$tudom.' - '.$tuname.' - '.$symb. - ""); - } - return $token; -} - -# ------------------------------------------------------------ Check in an item - -sub checkin { - my $token=shift; - my $now=time; - my ($ta,$tb,$lonhost)=split(/\*/,$token); - $lonhost=~tr/A-Z/a-z/; - my $dtoken=$ta.'_'.&hostname($lonhost).'_'.$tb; - $dtoken=~s/\W/\_/g; - my ($dummy,$tuname,$tudom,$tcrsid,$symb,$chtim,$rmaddr)= - split(/\&/,&unescape(&reply('tmpget:'.$dtoken,$lonhost))); - - unless (($tuname) && ($tudom)) { - &logthis('Check in '.$token.' ('.$dtoken.') failed'); - return ''; - } - - unless (&allowed('mgr',$tcrsid)) { - &logthis('Check in '.$token.' ('.$dtoken.') unauthorized: '. - $env{'user.name'}.' - '.$env{'user.domain'}); - return ''; - } - - my %infohash=('resource.0.intoken' => $token, - 'resource.0.checkintime' => $now, - 'resource.0.inremote' => $ENV{'REMOTE_ADDR'}); - - unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') { - return ''; - } - - if (&log($tudom,$tuname,&homeserver($tuname,$tudom), - &escape('Checkin - '.$token)) ne 'ok') { - return ''; - } - - return ($symb,$tuname,$tudom,$tcrsid); -} - # --------------------------------------------- Set Expire Date for Spreadsheet sub expirespread { @@ -5244,7 +5168,7 @@ sub privileged { my $now = time; my $roles; if (ref($possroles) eq 'ARRAY') { - $roles = $possroles; + $roles = $possroles; } else { $roles = ['dc','su']; } @@ -5271,7 +5195,7 @@ sub privileged { for my $role (@rolesdump{grep { ! /^rolesdef_/ } keys(%rolesdump)}) { my ($trole, $tend, $tstart) = split(/_/, $role); if (grep(/^\Q$trole\E$/,@{$roles})) { - return 1 unless ($tend && $tend < $now) + return 1 unless ($tend && $tend < $now) or ($tstart && $tstart > $now); } } @@ -5309,7 +5233,7 @@ sub privileged_by_domain { my ($trole,$uname,$udom,$rest) = split(/:/,$item,4); my ($end,$start) = split(/:/,$dompersonnel{$server}{$item}); next if ($end && $end < $now); - $privileged{$dom}{$trole}{$uname.':'.$udom} = + $privileged{$dom}{$trole}{$uname.':'.$udom} = $dompersonnel{$server}{$item}; } } @@ -5780,14 +5704,15 @@ sub unserialize { return {} if $rep =~ /^error/; my %returnhash=(); - foreach my $item (split(/\&/,$rep)) { - my ($key, $value) = split(/=/, $item, 2); - $key = unescape($key) unless $escapedkeys; - next if $key =~ /^error: 2 /; - $returnhash{$key} = &thaw_unescape($value); - } + foreach my $item (split(/\&/,$rep)) { + my ($key, $value) = split(/=/, $item, 2); + $key = unescape($key) unless $escapedkeys; + next if $key =~ /^error: 2 /; + $returnhash{$key} = &thaw_unescape($value); + } + #return %returnhash; return \%returnhash; -} +} # see Lond::dump_with_regexp # if $escapedkeys hash keys won't get unescaped. @@ -5802,11 +5727,11 @@ sub dump { } else { $regexp='.'; } - if (grep { $_ eq $uhome } ¤t_machine_ids()) { + if (grep { $_ eq $uhome } current_machine_ids()) { # user is hosted on this machine - my $reply = LONCAPA::Lond::dump_with_regexp(join(':', ($udomain, + my $reply = LONCAPA::Lond::dump_with_regexp(join(":", ($udomain, $uname, $namespace, $regexp, $range)), $perlvar{'lonVersion'}); - return %{&unserialize($reply, $escapedkeys)}; + return %{unserialize($reply, $escapedkeys)}; } my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome); my @pairs=split(/\&/,$rep); @@ -5814,7 +5739,8 @@ sub dump { if (!($rep =~ /^error/ )) { foreach my $item (@pairs) { my ($key,$value)=split(/=/,$item,2); - $key = &unescape($key) unless ($escapedkeys); + $key = unescape($key) unless $escapedkeys; + #$key = &unescape($key); next if ($key =~ /^error: 2 /); $returnhash{$key}=&thaw_unescape($value); } @@ -5858,7 +5784,7 @@ sub currentdump { my $rep; if (grep { $_ eq $uhome } current_machine_ids()) { - $rep = LONCAPA::Lond::dump_profile_database(join(":", ($sdom, $sname, + $rep = LONCAPA::Lond::dump_profile_database(join(":", ($sdom, $sname, $courseid))); } else { $rep = reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome); @@ -6117,13 +6043,13 @@ sub tmpdel { return &reply("tmpdel:$token",$server); } -# ------------------------------------------------------------ get_timebased_id +# ------------------------------------------------------------ get_timebased_id sub get_timebased_id { my ($prefix,$keyid,$namespace,$cdom,$cnum,$idtype,$who,$locktries, $maxtries) = @_; my ($newid,$error,$dellock); - unless (($prefix =~ /^\w+$/) && ($keyid =~ /^\w+$/) && ($namespace ne '')) { + unless (($prefix =~ /^\w+$/) && ($keyid =~ /^\w+$/) && ($namespace ne '')) { return ('','ok','invalid call to get suffix'); } @@ -6137,7 +6063,7 @@ sub get_timebased_id { if (!$maxtries) { $maxtries = 10; } - + if (($cdom eq '') || ($cnum eq '')) { if ($env{'request.course.id'}) { $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; @@ -6219,9 +6145,9 @@ sub sixnum_code { # -------------------------------------------------- portfolio access checking sub portfolio_access { - my ($requrl) = @_; + my ($requrl,$clientip) = @_; my (undef,$udom,$unum,$file_name,$group) = &parse_portfolio_url($requrl); - my $result = &get_portfolio_access($udom,$unum,$file_name,$group); + my $result = &get_portfolio_access($udom,$unum,$file_name,$group,$clientip); if ($result) { my %setters; if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') { @@ -6247,7 +6173,7 @@ sub portfolio_access { } sub get_portfolio_access { - my ($udom,$unum,$file_name,$group,$access_hash) = @_; + my ($udom,$unum,$file_name,$group,$clientip,$access_hash) = @_; if (!ref($access_hash)) { my $current_perms = &get_portfile_permissions($udom,$unum); @@ -6256,7 +6182,7 @@ sub get_portfolio_access { $access_hash = $access_controls{$file_name}; } - my ($public,$guest,@domains,@users,@courses,@groups); + my ($public,$guest,@domains,@users,@courses,@groups,@ips); my $now = time; if (ref($access_hash) eq 'HASH') { foreach my $key (keys(%{$access_hash})) { @@ -6280,10 +6206,25 @@ sub get_portfolio_access { push(@courses,$key); } elsif ($scope eq 'group') { push(@groups,$key); + } elsif ($scope eq 'ip') { + push(@ips,$key); } } if ($public) { return 'ok'; + } elsif (@ips > 0) { + my $allowed; + foreach my $ipkey (@ips) { + if (ref($access_hash->{$ipkey}{'ip'}) eq 'ARRAY') { + if (&Apache::loncommon::check_ip_acc(join(',',@{$access_hash->{$ipkey}{'ip'}}),$clientip)) { + $allowed = 1; + last; + } + } + } + if ($allowed) { + return 'ok'; + } } if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') { if ($guest) { @@ -6505,7 +6446,7 @@ sub usertools_access { my ($toolstatus,$inststatus,$envkey); if ($context eq 'requestauthor') { - $envkey = $context; + $envkey = $context; } else { $envkey = $context.'.'.$tool; } @@ -7003,9 +6944,9 @@ sub allowed { && $thisallowed ne 'F' && $thisallowed ne '2' && &is_portfolio_url($uri)) { - $thisallowed = &portfolio_access($uri); + $thisallowed = &portfolio_access($uri,$clientip); } - + # Full access at system, domain or course-wide level? Exit. if ($thisallowed=~/F/) { return 'F'; @@ -7335,14 +7276,14 @@ sub constructaccess { # # User for whom data are being temporarily cached. my $cacheduser=''; -# Cached blockers for this user (a hash of blocking items). +# Cached blockers for this user (a hash of blocking items). my %cachedblockers=(); # When the data were last cached. my $cachedlast=''; sub load_all_blockers { my ($uname,$udom,$blocks)=@_; - if (($uname ne '') && ($udom ne '')) { + if (($uname ne '') && ($udom ne '')) { if (($cacheduser eq $uname.':'.$udom) && (abs($cachedlast-time)<5)) { return; @@ -7384,7 +7325,7 @@ sub get_commblock_resources { } else { %commblocks = &get_comm_blocks(); } - return %blockers unless (keys(%commblocks) > 0); + return %blockers unless (keys(%commblocks) > 0); my $navmap = Apache::lonnavmaps::navmap->new(); return %blockers unless (ref($navmap)); my $now = time; @@ -7396,7 +7337,7 @@ sub get_commblock_resources { if (ref($commblocks{$block}{'blocks'}{'docs'}) eq 'HASH') { if (ref($commblocks{$block}{'blocks'}{'docs'}{'maps'}) eq 'HASH') { if (keys(%{$commblocks{$block}{'blocks'}{'docs'}{'maps'}})) { - $blockers{$block}{maps} = $commblocks{$block}{'blocks'}{'docs'}{'maps'}; + $blockers{$block}{maps} = $commblocks{$block}{'blocks'}{'docs'}{'maps'}; } } if (ref($commblocks{$block}{'blocks'}{'docs'}{'resources'}) eq 'HASH') { @@ -7421,8 +7362,8 @@ sub get_commblock_resources { if ($item =~ /___\d+___/) { $type = 'resource'; @interval=&EXT("resource.0.interval",$item); - if (ref($navmap)) { - my $res = $navmap->getBySymb($item); + if (ref($navmap)) { + my $res = $navmap->getBySymb($item); push(@to_test,$res); } } else { @@ -7501,7 +7442,7 @@ sub has_comm_blocking { } if ($symb) { @symbs = ($symb); - } elsif (keys(%possibles)) { + } elsif (keys(%possibles)) { @symbs = keys(%possibles); } my $noblock; @@ -7539,7 +7480,7 @@ sub has_comm_blocking { } } -# -------------------------------- Deversion and split uri into path an filename +# -------------------------------- Deversion and split uri into path an filename # # Removes the version from a URI and @@ -7657,9 +7598,9 @@ sub metadata_query { my @server_list = (defined($server_array) ? @$server_array : keys(%libserv) ); for my $server (@server_list) { - my $domains = ''; + my $domains = ''; if (ref($domains_hash) eq 'HASH') { - $domains = $domains_hash->{$server}; + $domains = $domains_hash->{$server}; } unless ($custom or $customshow) { my $reply=&reply("querysend:".&escape($query).':::'.&escape($domains),$server); @@ -7794,7 +7735,7 @@ sub get_query_reply { my $replyfile=LONCAPA::tempdir().$queryid; my $reply=''; for (1..100) { - sleep 2; + sleep(0.2); if (-e $replyfile.'.end') { if (open(my $fh,$replyfile)) { $reply = join('',<$fh>); @@ -8204,7 +8145,8 @@ sub auto_crsreq_update { ':'.&escape($action).':'.&escape($ownername).':'. &escape($ownerdomain).':'.&escape($fullname).':'. &escape($title).':'.&escape($code).':'. - &escape($accessstart).':'.&escape($accessend).':'.$info,$homeserver); + &escape($accessstart).':'.&escape($accessend).':'.$info, + $homeserver); unless ($response =~ /(con_lost|error|no_such_host|refused)/) { my @items = split(/&/,$response); foreach my $item (@items) { @@ -8558,7 +8500,7 @@ sub assignrole { } } } elsif ($context eq 'requestauthor') { - if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'}) && + if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'}) && ($url eq '/'.$udom.'/') && ($role eq 'au')) { if ($env{'environment.requestauthor'} eq 'automatic') { $refused = ''; @@ -8566,13 +8508,13 @@ sub assignrole { my %domdefaults = &get_domain_defaults($udom); if (ref($domdefaults{'requestauthor'}) eq 'HASH') { my $checkbystatus; - if ($env{'user.adv'}) { + if ($env{'user.adv'}) { my $disposition = $domdefaults{'requestauthor'}{'_LC_adv'}; if ($disposition eq 'automatic') { $refused = ''; } elsif ($disposition eq '') { $checkbystatus = 1; - } + } } else { $checkbystatus = 1; } @@ -8659,7 +8601,7 @@ sub assignrole { $context); } elsif (($role eq 'ca') || ($role eq 'aa')) { &coauthorrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag, - $context); + $context); } if ($role eq 'cc') { &autoupdate_coowners($url,$end,$start,$uname,$udom); @@ -8974,7 +8916,7 @@ sub modifystudent { # student's environment $uid = undef if (!$forceid); $reply = &modify_student_enrollment($udom,$uname,$uid,$first,$middle,$last, - $gene,$usec,$end,$start,$type,$locktype, + $gene,$usec,$end,$start,$type,$locktype, $cid,$selfenroll,$context,$credits); return $reply; } @@ -9456,6 +9398,90 @@ sub files_not_in_path { return (@return_files); } +#------------------------------Submitted/Handedback Portfolio Files Versioning + +sub portfiles_versioning { + my ($symb,$domain,$stu_name,$portfiles,$versioned_portfiles) = @_; + my $portfolio_root = '/userfiles/portfolio'; + return unless ((ref($portfiles) eq 'ARRAY') && (ref($versioned_portfiles) eq 'ARRAY')); + foreach my $file (@{$portfiles}) { + &unmark_as_readonly($domain,$stu_name,[$symb,$env{'request.course.id'}],$file); + my ($directory,$answer_file) =($file =~ /^(.*?)([^\/]*)$/); + my ($answer_name,$answer_ver,$answer_ext) = &file_name_version_ext($answer_file); + my $getpropath = 1; + my ($dir_list,$listerror) = &dirlist($portfolio_root.$directory,$domain, + $stu_name,$getpropath); + my $version = &get_next_version($answer_name,$answer_ext,$dir_list); + my $new_answer = + &version_selected_portfile($domain,$stu_name,$directory,$answer_file,$version); + if ($new_answer ne 'problem getting file') { + push(@{$versioned_portfiles}, $directory.$new_answer); + &mark_as_readonly($domain,$stu_name,[$directory.$new_answer], + [$symb,$env{'request.course.id'},'graded']); + } + } +} + +sub get_next_version { + my ($answer_name, $answer_ext, $dir_list) = @_; + my $version; + if (ref($dir_list) eq 'ARRAY') { + foreach my $row (@{$dir_list}) { + my ($file) = split(/\&/,$row,2); + my ($file_name,$file_version,$file_ext) = + &file_name_version_ext($file); + if (($file_name eq $answer_name) && + ($file_ext eq $answer_ext)) { + # gets here if filename and extension match, + # regardless of version + if ($file_version ne '') { + # a versioned file is found so save it for later + if ($file_version > $version) { + $version = $file_version; + } + } + } + } + } + $version ++; + return($version); +} + +sub version_selected_portfile { + my ($domain,$stu_name,$directory,$file_name,$version) = @_; + my ($answer_name,$answer_ver,$answer_ext) = + &file_name_version_ext($file_name); + my $new_answer; + $env{'form.copy'} = + &getfile("/uploaded/$domain/$stu_name/portfolio$directory$file_name"); + if($env{'form.copy'} eq '-1') { + $new_answer = 'problem getting file'; + } else { + $new_answer = $answer_name.'.'.$version.'.'.$answer_ext; + my $copy_result = + &finishuserfileupload($stu_name,$domain,'copy', + '/portfolio'.$directory.$new_answer); + } + undef($env{'form.copy'}); + return ($new_answer); +} + +sub file_name_version_ext { + my ($file)=@_; + my @file_parts = split(/\./, $file); + my ($name,$version,$ext); + if (@file_parts > 1) { + $ext=pop(@file_parts); + if (@file_parts > 1 && $file_parts[-1] =~ /^\d+$/) { + $version=pop(@file_parts); + } + $name=join('.',@file_parts); + } else { + $name=join('.',@file_parts); + } + return($name,$version,$ext); +} + #----------------------------------------------Get portfolio file permissions sub get_portfile_permissions { @@ -9552,9 +9578,9 @@ sub modify_access_controls { my $tries = 0; my $gotlock = &newput('file_permissions',$lockhash,$domain,$user); - while (($gotlock ne 'ok') && $tries <3) { + while (($gotlock ne 'ok') && $tries < 10) { $tries ++; - sleep 1; + sleep(0.1); $gotlock = &newput('file_permissions',$lockhash,$domain,$user); } if ($gotlock eq 'ok') { @@ -9600,49 +9626,132 @@ sub modify_access_controls { } sub make_public_indefinitely { - my ($requrl) = @_; + my (@requrl) = @_; + return &automated_portfile_access('public',\@requrl); +} + +sub automated_portfile_access { + my ($accesstype,$addsref,$delsref,$info) = @_; + unless (($accesstype eq 'public') || ($accesstype eq 'ip')) { + return 'invalid'; + } + my %urls; + if (ref($addsref) eq 'ARRAY') { + foreach my $requrl (@{$addsref}) { + if (&is_portfolio_url($requrl)) { + unless (exists($urls{$requrl})) { + $urls{$requrl} = 'add'; + } + } + } + } + if (ref($delsref) eq 'ARRAY') { + foreach my $requrl (@{$delsref}) { + if (&is_portfolio_url($requrl)) { + unless (exists($urls{$requrl})) { + $urls{$requrl} = 'delete'; + } + } + } + } + unless (keys(%urls)) { + return 'invalid'; + } + my $ip; + if ($accesstype eq 'ip') { + if (ref($info) eq 'HASH') { + if ($info->{'ip'} ne '') { + $ip = $info->{'ip'}; + } + } + if ($ip eq '') { + return 'invalid'; + } + } + my $errors; my $now = time; - my $action = 'activate'; - my $aclnum = 0; - if (&is_portfolio_url($requrl)) { + my %current_perms; + foreach my $requrl (sort(keys(%urls))) { + my $action; + if ($urls{$requrl} eq 'add') { + $action = 'activate'; + } else { + $action = 'none'; + } + my $aclnum = 0; my (undef,$udom,$unum,$file_name,$group) = &parse_portfolio_url($requrl); - my $current_perms = &get_portfile_permissions($udom,$unum); - my %access_controls = &get_access_controls($current_perms, + unless (exists($current_perms{$unum.':'.$udom})) { + $current_perms{$unum.':'.$udom} = &get_portfile_permissions($udom,$unum); + } + my %access_controls = &get_access_controls($current_perms{$unum.':'.$udom}, $group,$file_name); foreach my $key (keys(%{$access_controls{$file_name}})) { my ($num,$scope,$end,$start) = ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/); - if ($scope eq 'public') { - if ($start <= $now && $end == 0) { - $action = 'none'; - } else { + if ($scope eq $accesstype) { + if (($start <= $now) && ($end == 0)) { + if ($accesstype eq 'ip') { + if (ref($access_controls{$file_name}{$key}) eq 'HASH') { + if (ref($access_controls{$file_name}{$key}{'ip'}) eq 'ARRAY') { + if (grep(/^\Q$ip\E$/,@{$access_controls{$file_name}{$key}{'ip'}})) { + if ($urls{$requrl} eq 'add') { + $action = 'none'; + last; + } else { + $action = 'delete'; + $aclnum = $num; + last; + } + } + } + } + } elsif ($accesstype eq 'public') { + if ($urls{$requrl} eq 'add') { + $action = 'none'; + last; + } else { + $action = 'delete'; + $aclnum = $num; + last; + } + } + } elsif ($accesstype eq 'public') { $action = 'update'; $aclnum = $num; + last; } - last; } } if ($action eq 'none') { - return 'ok'; + next; } else { my %changes; my $newend = 0; my $newstart = $now; - my $newkey = $aclnum.':public_'.$newend.'_'.$newstart; + my $newkey = $aclnum.':'.$accesstype.'_'.$newend.'_'.$newstart; $changes{$action}{$newkey} = { - type => 'public', + type => $accesstype, time => { start => $newstart, end => $newend, }, }; + if ($accesstype eq 'ip') { + $changes{$action}{$newkey}{'ip'} = [$ip]; + } my ($outcome,$deloutcome,$new_values,$translation) = &modify_access_controls($file_name,\%changes,$udom,$unum); - return $outcome; + unless ($outcome eq 'ok') { + $errors .= $outcome.' '; + } } + } + if ($errors) { + $errors =~ s/\s$//; + return $errors; } else { - return 'invalid'; + return 'ok'; } } @@ -10064,12 +10173,10 @@ sub get_userresdata { } #error 2 occurs when the .db doesn't exist if ($tmp!~/error: 2 /) { - if ((!defined($cached)) || ($tmp ne 'con_lost')) { - &logthis("WARNING:". - " Trying to get resource data for ". - $uname." at ".$udom.": ". - $tmp.""); - } + &logthis("WARNING:". + " Trying to get resource data for ". + $uname." at ".$udom.": ". + $tmp.""); } elsif ($tmp=~/error: 2 /) { #&EXT_cache_set($udom,$uname); &do_cache_new('userres',$hashid,undef,600); @@ -10121,7 +10228,7 @@ sub get_numsuppfiles { unless ($chome eq 'no_host') { ($suppcount,my $errors) = (0,0); my $suppmap = 'supplemental.sequence'; - ($suppcount,$errors) = + ($suppcount,$errors) = &Apache::loncommon::recurse_supplemental($cnum,$cdom,$suppmap,$suppcount,$errors); } &do_cache_new('suppcount',$hashid,$suppcount,600); @@ -10316,7 +10423,7 @@ sub EXT { $courseid = $cid; } if (($symbparm && $courseid) && - (($courseid eq $env{'request.course.id'}) || ($courseid eq $cid))) { + (($courseid eq $env{'request.course.id'}) || ($courseid eq $cid))) { #print '
'.$space.' - '.$qualifier.' - '.$spacequalifierrest; @@ -11104,7 +11211,7 @@ sub symbverify { $ids=$bighash{'ids_'.&clutter($thisurl)}; } unless ($ids) { - my $idkey = 'ids_'.($thisurl =~ m{^/}? '' : '/').$thisurl; + my $idkey = 'ids_'.($thisurl =~ m{^/}? '' : '/').$thisurl; $ids=$bighash{$idkey}; } if ($ids) { @@ -11120,14 +11227,14 @@ sub symbverify { if (ref($encstate)) { $$encstate = $bighash{'encrypted_'.$id}; } - if (($env{'request.role.adv'}) || - ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) || + if (($env{'request.role.adv'}) || + ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) || ($thisurl eq '/adm/navmaps')) { - $okay=1; + $okay=1; last; - } - } - } + } + } + } } untie(%bighash); } @@ -11211,9 +11318,9 @@ sub symbread { # no filename provided? try from environment unless ($thisfn) { if ($env{'request.symb'}) { - return $env{$cache_str}=&symbclean($env{'request.symb'}); - } - $thisfn=$env{'request.filename'}; + return $env{$cache_str}=&symbclean($env{'request.symb'}); + } + $thisfn=$env{'request.filename'}; } if ($thisfn=~m|^/enc/|) { $thisfn=&Apache::lonenc::unencrypted($thisfn); } # is that filename actually a symb? Verify, clean, and return @@ -11270,7 +11377,7 @@ sub symbread { $syval=&encode_symb($bighash{'map_id_'.$mapid}, $resid,$thisfn); if (ref($possibles) eq 'HASH') { - $possibles->{$syval} = 1; + $possibles->{$syval} = 1; } if ($checkforblock) { my @blockers = &has_comm_blocking('bre',$syval,$bighash{'src_'.$ids}); @@ -11279,7 +11386,7 @@ sub symbread { return; } } - } elsif ((!$donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) { + } elsif ((!$donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) { # ------------------------------------------ There is more than one possibility my $realpossible=0; foreach my $id (@possibilities) { @@ -11287,14 +11394,14 @@ sub symbread { my $canaccess; if (($donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) { $canaccess = 1; - } else { + } else { $canaccess = &allowed('bre',$file); } if ($canaccess) { my ($mapid,$resid)=split(/\./,$id); if ($bighash{'map_type_'.$mapid} ne 'page') { my $poss_syval=&encode_symb($bighash{'map_id_'.$mapid}, - $resid,$thisfn); + $resid,$thisfn); if (ref($possibles) eq 'HASH') { $possibles->{$syval} = 1; } @@ -11469,6 +11576,7 @@ sub rndseed { $which =&get_rand_alg($courseid); } if (defined(&getCODE())) { + if ($which eq '64bit5') { return &rndseed_CODE_64bit5($symb,$courseid,$domain,$username); } elsif ($which eq '64bit4') { @@ -11654,7 +11762,7 @@ sub rndseed_CODE_64bit5 { sub setup_random_from_rndseed { my ($rndseed)=@_; if ($rndseed =~/([,:])/) { - my ($num1,$num2) = map { abs($_); } (split(/[,:]/,$rndseed)); + my ($num1,$num2) = map { abs($_); } (split(/[,:]/,$rndseed)); if ((!$num1) || (!$num2) || ($num1 > 2147483562) || ($num2 > 2147483398)) { &Math::Random::random_set_seed_from_phrase($rndseed); } else { @@ -12187,9 +12295,9 @@ sub get_dns { delete($alldns{$dns}); next if ($response->is_error()); my @content = split("\n",$response->content); - unless ($nocache) { + unless ($nocache) { &do_cache_new('dns',$url,\@content,30*24*60*60); - } + } &$func(\@content,$hashref); return; } @@ -12226,7 +12334,7 @@ sub parse_dns_checksums_tab { if (ref($lines) eq 'ARRAY') { chomp(@{$lines}); my $version = shift(@{$lines}); - if ($version eq $release) { + if ($version eq $release) { foreach my $line (@{$lines}) { my ($file,$version,$shasum) = split(/,/,$line); if ($file =~ m{^/etc/httpd/conf}) { @@ -12286,8 +12394,8 @@ sub fetch_dns_checksums { } sub load_domain_tab { - my ($ignore_cache,$nocache) = @_; - &get_dns('/adm/dns/domain',\&parse_domain_tab,$ignore_cache,$nocache); + my ($ignore_cache) = @_; + &get_dns('/adm/dns/domain',\&parse_domain_tab,$ignore_cache); my $fh; if (open($fh,"<".$perlvar{'lonTabDir'}.'/domain.tab')) { my @lines = <$fh>; @@ -12373,8 +12481,8 @@ sub fetch_dns_checksums { } sub load_hosts_tab { - my ($ignore_cache,$nocache) = @_; - &get_dns('/adm/dns/hosts',\&parse_hosts_tab,$ignore_cache,$nocache); + my ($ignore_cache) = @_; + &get_dns('/adm/dns/hosts',\&parse_hosts_tab,$ignore_cache); open(my $config,"<$perlvar{'lonTabDir'}/hosts.tab"); my @config = <$config>; &parse_hosts_tab(\@config); @@ -12396,8 +12504,7 @@ sub fetch_dns_checksums { } sub all_names { - my ($ignore_cache,$nocache) = @_; - &load_hosts_tab($ignore_cache,$nocache) if (!$loaded); + &load_hosts_tab() if (!$loaded); return %name_to_host; } @@ -12519,7 +12626,7 @@ sub fetch_dns_checksums { } sub get_iphost { - my ($ignore_cache,$nocache) = @_; + my ($ignore_cache) = @_; if (!$ignore_cache) { if (%iphost) { @@ -12543,7 +12650,7 @@ sub fetch_dns_checksums { %old_name_to_ip = %{$ip_info->[1]}; } - my %name_to_host = &all_names($ignore_cache,$nocache); + my %name_to_host = &all_names(); foreach my $name (keys(%name_to_host)) { my $ip; if (!exists($name_to_ip{$name})) { @@ -12568,11 +12675,9 @@ sub fetch_dns_checksums { } push(@{$iphost{$ip}},@{$name_to_host{$name}}); } - unless ($nocache) { - &do_cache_new('iphost','iphost', - [\%iphost,\%name_to_ip,\%lonid_to_ip], - 48*60*60); - } + &do_cache_new('iphost','iphost', + [\%iphost,\%name_to_ip,\%lonid_to_ip], + 48*60*60); return %iphost; } @@ -12637,9 +12742,9 @@ sub all_loncaparevs { return qw(1.1 1.2 1.3 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11); } -# ------------------------------------------------------- Read loncaparev table +# ---------------------------------------------------------- Read loncaparev table { - sub load_loncaparevs { + sub load_loncaparevs { if (-e "$perlvar{'lonTabDir'}/loncaparevs.tab") { if (open(my $config,"<$perlvar{'lonTabDir'}/loncaparevs.tab")) { while (my $configline=<$config>) { @@ -12653,7 +12758,7 @@ sub all_loncaparevs { } } -# ----------------------------------------------------- Read serverhostID table +# ---------------------------------------------------------- Read serverhostID table { sub load_serverhomeIDs { if (-e "$perlvar{'lonTabDir'}/serverhomeIDs.tab") { @@ -12745,11 +12850,11 @@ BEGIN { close($config); } -# --------------------------------------------------------- Read loncaparev table +# ---------------------------------------------------------- Read loncaparev table &load_loncaparevs(); -# ------------------------------------------------------- Read serverhostID table +# ---------------------------------------------------------- Read serverhostID table &load_serverhomeIDs(); @@ -12763,10 +12868,11 @@ BEGIN { my $item = $token->[1]; my $name = $token->[2]{'name'}; my $value = $token->[2]{'value'}; - if ($item ne '' && $name ne '' && $value ne '') { + my $valuematch = $token->[2]{'valuematch'}; + if ($item ne '' && $name ne '' && ($value ne '' || $valuematch ne '')) { my $release = $parser->get_text(); $release =~ s/(^\s*|\s*$ )//gx; - $needsrelease{$item.':'.$name.':'.$value} = $release; + $needsrelease{$item.':'.$name.':'.$value.':'.$valuematch} = $release; } } } @@ -13096,13 +13202,13 @@ The first argument is required, all othe $priv is the privilege being checked. $uri contains additional information about what is being checked for access (e.g., -URL, course ID etc.). +URL, course ID etc.). $symb is the unique resource instance identifier in a course; if needed, -but not provided, it will be retrieved via a call to &symbread(). -$role is the role for which a priv is being checked (only used if priv is evb). -$clientip is the user's IP address (only used when checking for access to portfolio +but not provided, it will be retrieved via a call to &symbread(). +$role is the role for which a priv is being checked (only used if priv is evb). +$clientip is the user's IP address (only used when checking for access to portfolio files). -$noblockcheck, if true, skips calls to &has_comm_blocking() for the bre priv. This +$noblockcheck, if true, skips calls to &has_comm_blocking() for the bre priv. This prevents recursive calls to &allowed. F: full access @@ -13163,9 +13269,9 @@ provided for types, will default to retu =item * in_course($udom,$uname,$cdom,$cnum,$type,$hideprivileged) : determine if -user: $uname:$udom has a role in the course: $cdom_$cnum. +user: $uname:$udom has a role in the course: $cdom_$cnum. -Additional optional arguments are: $type (if role checking is to be restricted +Additional optional arguments are: $type (if role checking is to be restricted to certain user status types -- previous (expired roles), active (currently available roles) or future (roles available in the future), and $hideprivileged -- if true will not report course roles for users who @@ -13402,7 +13508,7 @@ values that are the resource value. I b versions are also returned. get_numsuppfiles($cnum,$cdom) : retrieve number of files in a course's -supplemental content area. This routine caches the number of files for +supplemental content area. This routine caches the number of files for 10 minutes. =back @@ -13505,20 +13611,20 @@ will be stored for query =item * -symbread($filename,$donotrecurse,$ignorecachednull,$checkforblock,$possibles) : -return symbolic list entry (all arguments optional). +symbread($filename,$donotrecurse,$ignorecachednull,$checkforblock,$possibles) : +return symbolic list entry (all arguments optional). -Args: filename is the filename (including path) for the file for which a symb -is required; donotrecurse, if true will prevent calls to allowed() being made -to check access status if more than one resource was found in the bighash -(see rev. 1.249) to avoid an infinite loop if an ambiguous resource is part of -a randompick); ignorecachednull, if true will prevent a symb of '' being +Args: filename is the filename (including path) for the file for which a symb +is required; donotrecurse, if true will prevent calls to allowed() being made +to check access status if more than one resource was found in the bighash +(see rev. 1.249) to avoid an infinite loop if an ambiguous resource is part of +a randompick); ignorecachednull, if true will prevent a symb of '' being returned if $env{$cache_str} is defined as ''; checkforblock if true will cause possible symbs to be checked to determine if they are subject to content blocking, if so they will not be included as possible symbs; possibles is a -ref to a hash, which, as a side effect, will be populated with all possible +ref to a hash, which, as a side effect, will be populated with all possible symbs (content blocking not tested). - + returns the data handle =item * @@ -13528,9 +13634,9 @@ and is a possible symb for the URL in $t resource that the user accessed using /enc/ returns a 1 on success, 0 on failure, user must be in a course, as it assumes the existence of the course initial hash, and uses $env('request.course.id'}. The third -arg is an optional reference to a scalar. If this arg is passed in the +arg is an optional reference to a scalar. If this arg is passed in the call to symbverify, it will be set to 1 if the symb has been set to be -encrypted; otherwise it will be null. +encrypted; otherwise it will be null. =item * @@ -13583,13 +13689,13 @@ expirespread($uname,$udom,$stype,$usymb) devalidate($symb) : devalidate temporary spreadsheet calculations, forcing spreadsheet to reevaluate the resource scores next time. -=item * +=item * can_edit_resource($file,$cnum,$cdom,$resurl,$symb,$group) : determine if current user can edit a particular resource, when viewing in course context. input: six args -- filename (decluttered), course number, course domain, - url, symb (if registered) and group (if this is a + url, symb (if registered) and group (if this is a group item -- e.g., bulletin board, group page etc.). output: array of five scalars -- @@ -13597,15 +13703,15 @@ when viewing in course context. $home -- homeserver of resource (i.e., for author if published, or course if uploaded.). $switchserver -- 1 if server switch will be needed. - $forceedit -- 1 if icon/link should be to go to edit mode + $forceedit -- 1 if icon/link should be to go to edit mode $forceview -- 1 if icon/link should be to go to view mode =item * is_course_upload($file,$cnum,$cdom) -Used in course context to determine if current file was uploaded to -the course (i.e., would be found in /userfiles/docs on the course's +Used in course context to determine if current file was uploaded to +the course (i.e., would be found in /userfiles/docs on the course's homeserver. input: 3 args -- filename (decluttered), course number and course domain. @@ -13619,20 +13725,20 @@ homeserver. =item * -store($storehash,$symb,$namespace,$udom,$uname,$laststore) : stores hash +store($storehash,$symb,$namespace,$udom,$uname,$laststore) : stores hash permanently for this url; hashref needs to be given and should be a \%hashname; the remaining args aren't required and if they aren't passed or are '' they will -be derived from the env (with the exception of $laststore, which is an +be derived from the env (with the exception of $laststore, which is an optional arg used when a user's submission is stored in grading). $laststore is $version=$timestamp, where $version is the most recent version number retrieved for the corresponding $symb in the $namespace db file, and $timestamp is the timestamp for that transaction (UNIX time). -$laststore is currently only passed when cstore() is called by +$laststore is currently only passed when cstore() is called by structuretags::finalize_storage(). =item * -cstore($storehash,$symb,$namespace,$udom,$uname,$laststore) : same as store +cstore($storehash,$symb,$namespace,$udom,$uname,$laststore) : same as store but uses critical subroutine =item * @@ -13770,7 +13876,7 @@ server ($udom and $uhome are optional) =item * -get_domain_defaults($target_domain,$ignore_cache) : returns hash with defaults +get_domain_defaults($target_domain,$ignore_cache) : returns hash with defaults for: authentication, language, quotas, timezone, date locale, and portal URL in the target domain. @@ -13825,7 +13931,7 @@ for course's uploaded content. =over =item -canuse_pdfforms, officialcredits, unofficialcredits, textbookcredits, officialquota, unofficialquota, +canuse_pdfforms, officialcredits, unofficialcredits, textbookcredits, officialquota, unofficialquota, communityquota, textbookquota =back @@ -13836,7 +13942,7 @@ on your servers. =over -=item +=item remotesessions, hostedsessions =back @@ -13844,10 +13950,10 @@ remotesessions, hostedsessions =back In cases where a domain coordinator has never used the "Set Domain Configuration" -utility to create a configuration.db file on a domain's primary library server +utility to create a configuration.db file on a domain's primary library server only the following domain defaults: auth_def, auth_arg_def, lang_def -- corresponding values are authentication type (internal, krb4, krb5, -or localauth), initial password or a kerberos realm, language (e.g., en-us) -- +or localauth), initial password or a kerberos realm, language (e.g., en-us) -- will be available. Values are retrieved from cache (if current), unless the optional $ignore_cache arg is true, or from domain's configuration.db (if available), or lastly from values in lonTabs/dns_domain,tab, or lonTabs/domain.tab. @@ -14275,8 +14381,8 @@ Returns: get_timebased_id(): -Attempts to get a unique timestamp-based suffix for use with items added to a -course via the Course Editor (e.g., folders, composite pages, +Attempts to get a unique timestamp-based suffix for use with items added to a +course via the Course Editor (e.g., folders, composite pages, group bulletin boards). Args: (first three required; six others optional) @@ -14287,24 +14393,24 @@ Args: (first three required; six others 2. keyid (alphanumeric): name of temporary locking key in hash, e.g., num, boardids -3. namespace: name of gdbm file used to store suffixes already assigned; +3. namespace: name of gdbm file used to store suffixes already assigned; file will be named nohist_namespace.db 4. cdom: domain of course; default is current course domain from %env 5. cnum: course number; default is current course number from %env -6. idtype: set to concat if an additional digit is to be appended to the +6. idtype: set to concat if an additional digit is to be appended to the unix timestamp to form the suffix, if the plain timestamp is already - in use. Default is to not do this, but simply increment the unix + in use. Default is to not do this, but simply increment the unix timestamp by 1 until a unique key is obtained. 7. who: holder of locking key; defaults to user:domain for user. -8. locktries: number of attempts to obtain a lock (sleep of 1s before +8. locktries: number of attempts to obtain a lock (sleep of 1s before retrying); default is 3. -9. maxtries: number of attempts to obtain a unique suffix; default is 20. +9. maxtries: number of attempts to obtain a unique suffix; default is 20. Returns: