--- loncom/lonnet/perl/lonnet.pm 2010/08/17 01:33:18 1.1056.4.4 +++ loncom/lonnet/perl/lonnet.pm 2011/07/28 18:30:16 1.1056.4.28 @@ -1,7 +1,7 @@ # The LearningOnline Network # TCP networking package # -# $Id: lonnet.pm,v 1.1056.4.4 2010/08/17 01:33:18 raeburn Exp $ +# $Id: lonnet.pm,v 1.1056.4.28 2011/07/28 18:30:16 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -76,7 +76,7 @@ use HTTP::Date; use Image::Magick; use vars qw(%perlvar %spareid %pr %prp $memcache %packagetab $tmpdir - $_64bit %env %protocol %loncaparevs %serverhomeIDs); + $_64bit %env %protocol %loncaparevs %serverhomeIDs %needsrelease); my (%badServerCache, $memcache, %courselogs, %accesshash, %domainrolehash, %userrolehash, $processmarker, $dumpcount, %coursedombuf, @@ -95,6 +95,7 @@ use Math::Random; use File::MMagic; use LONCAPA qw(:DEFAULT :match); use LONCAPA::Configuration; +use File::Copy; my $readit; my $max_connection_retries = 10; # Or some such value. @@ -195,6 +196,29 @@ sub get_server_timezone { } } +sub get_server_distarch { + my ($lonhost,$ignore_cache) = @_; + if (defined($lonhost)) { + if (!defined(&hostname($lonhost))) { + return; + } + my $cachetime = 12*3600; + if (!$ignore_cache) { + my ($distarch,$cached)=&is_cached_new('serverdistarch',$lonhost); + if (defined($cached)) { + return $distarch; + } + } + my $rep = &reply('serverdistarch',$lonhost); + unless ($rep eq 'unknown_command' || $rep eq 'no_such_host' || + $rep eq 'con_lost' || $rep eq 'rejected' || $rep eq 'refused' || + $rep eq '') { + return &do_cache_new('serverdistarch',$lonhost,$rep,$cachetime); + } + } + return; +} + sub get_server_loncaparev { my ($dom,$lonhost,$ignore_cache,$caller) = @_; if (defined($lonhost)) { @@ -222,7 +246,7 @@ sub get_server_loncaparev { my @ids=¤t_machine_ids(); if (grep(/^\Q$lonhost\E$/,@ids)) { $answer = $perlvar{'lonVersion'}; - if ($answer =~ /^[\'\"]?([\d.\-]+)[\'\"]?$/) { + if ($answer =~ /^[\'\"]?([\w.\-]+)[\'\"]?$/) { $loncaparev = $1; } } else { @@ -230,7 +254,7 @@ sub get_server_loncaparev { if (($answer eq 'unknown_cmd') || ($answer eq 'con_lost')) { if ($caller eq 'loncron') { my $ua=new LWP::UserAgent; - $ua->timeout(20); + $ua->timeout(4); my $protocol = $protocol{$lonhost}; $protocol = 'http' if ($protocol ne 'https'); my $url = $protocol.'://'.&hostname($lonhost).'/adm/about.html'; @@ -238,14 +262,14 @@ sub get_server_loncaparev { my $response=$ua->request($request); unless ($response->is_error()) { my $content = $response->content; - if ($content =~ /

VERSION\:\s*([\d.\-]+)<\/p>/) { + if ($content =~ /

VERSION\:\s*([\w.\-]+)<\/p>/) { $loncaparev = $1; } } } else { $loncaparev = $loncaparevs{$lonhost}; } - } elsif ($answer =~ /^[\'\"]?([\d.\-]+)[\'\"]?$/) { + } elsif ($answer =~ /^[\'\"]?([\w.\-]+)[\'\"]?$/) { $loncaparev = $1; } } @@ -751,13 +775,23 @@ sub overloaderror { # ------------------------------ Find server with least workload from spare.tab sub spareserver { - my ($loadpercent,$userloadpercent,$want_server_name) = @_; + my ($loadpercent,$userloadpercent,$want_server_name,$udom) = @_; my $spare_server; if ($userloadpercent !~ /\d/) { $userloadpercent=0; } my $lowest_load=($loadpercent > $userloadpercent) ? $loadpercent : $userloadpercent; - + my ($uint_dom,$remotesessions); + if (($udom ne '') && (&domain($udom) ne '')) { + my $uprimary_id = &Apache::lonnet::domain($udom,'primary'); + $uint_dom = &Apache::lonnet::internet_dom($uprimary_id); + my %udomdefaults = &Apache::lonnet::get_domain_defaults($udom); + $remotesessions = $udomdefaults{'remotesessions'}; + } foreach my $try_server (@{ $spareid{'primary'} }) { + if ($uint_dom) { + next unless (&spare_can_host($udom,$uint_dom,$remotesessions, + $try_server)); + } ($spare_server, $lowest_load) = &compare_server_load($try_server, $spare_server, $lowest_load); } @@ -766,6 +800,10 @@ sub spareserver { if (!$found_server) { foreach my $try_server (@{ $spareid{'default'} }) { + if ($uint_dom) { + next unless (&spare_can_host($udom,$uint_dom,$remotesessions, + $try_server)); + } ($spare_server, $lowest_load) = &compare_server_load($try_server, $spare_server, $lowest_load); } @@ -778,7 +816,7 @@ sub spareserver { } if (defined($spare_server)) { my $hostname = &hostname($spare_server); - if (defined($hostname)) { + if (defined($hostname)) { $spare_server = $protocol.'://'.$hostname; } } @@ -995,15 +1033,19 @@ sub can_host_session { } if ($canhost) { if (ref($hostedsessions) eq 'HASH') { + my $uprimary_id = &Apache::lonnet::domain($udom,'primary'); + my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id); if (ref($hostedsessions->{'excludedomain'}) eq 'ARRAY') { - if (grep(/^\Q$udom\E$/,@{$hostedsessions->{'excludedomain'}})) { + if (($uint_dom ne '') && + (grep(/^\Q$uint_dom\E$/,@{$hostedsessions->{'excludedomain'}}))) { $canhost = 0; } else { $canhost = 1; } } if (ref($hostedsessions->{'includedomain'}) eq 'ARRAY') { - if (grep(/^\Q$udom\E$/,@{$hostedsessions->{'includedomain'}})) { + if (($uint_dom ne '') && + (grep(/^\Q$uint_dom\E$/,@{$hostedsessions->{'includedomain'}}))) { $canhost = 1; } else { $canhost = 0; @@ -1014,6 +1056,26 @@ sub can_host_session { return $canhost; } +sub spare_can_host { + my ($udom,$uint_dom,$remotesessions,$try_server)=@_; + my $canhost=1; + my @intdoms; + my $internet_names = &Apache::lonnet::get_internet_names($try_server); + if (ref($internet_names) eq 'ARRAY') { + @intdoms = @{$internet_names}; + } + unless (grep(/^\Q$uint_dom\E$/,@intdoms)) { + my $serverhomeID = &Apache::lonnet::get_server_homeID($try_server); + my $serverhomedom = &Apache::lonnet::host_domain($serverhomeID); + my %defdomdefaults = &Apache::lonnet::get_domain_defaults($serverhomedom); + my $remoterev = &Apache::lonnet::get_server_loncaparev(undef,$try_server); + $canhost = &can_host_session($udom,$try_server,$remoterev, + $remotesessions, + $defdomdefaults{'hostedsessions'}); + } + return $canhost; +} + # ---------------------- Find the homebase for a user from domain's lib servers my %homecache; @@ -1723,7 +1785,8 @@ sub getsection { # If there is a role which has expired, return it. # $courseid = &courseid_to_courseurl($courseid); - my %roleshash = &dump('roles',$udom,$unam,$courseid); + my $extra = &freeze_escape({'skipcheck' => 1}); + my %roleshash = &dump('roles',$udom,$unam,$courseid,undef,$extra); foreach my $key (keys(%roleshash)) { next if ($key !~/^\Q$courseid\E(?:\/)*(\w+)*\_st$/); my $section=$1; @@ -2164,6 +2227,8 @@ sub allowuploaded { # path to file, source of file, instruction to parse file for objects, # ref to hash for embedded objects, # ref to hash for codebase of java objects. +# reference to scalar to accommodate mime type determined +# from File::MMagic if $parser = parse. # # output: url to file (if action was uploaddoc), # ok if successful, or diagnostic message otherwise (if action was propagate or copy) @@ -2190,7 +2255,8 @@ sub allowuploaded { # sub process_coursefile { - my ($action,$docuname,$docudom,$file,$source,$parser,$allfiles,$codebase)=@_; + my ($action,$docuname,$docudom,$file,$source,$parser,$allfiles,$codebase, + $mimetype)=@_; my $fetchresult; my $home=&homeserver($docuname,$docudom); if ($action eq 'propagate') { @@ -2218,13 +2284,16 @@ sub process_coursefile { close($fh); if ($parser eq 'parse') { my $mm = new File::MMagic; - my $mime_type = $mm->checktype_filename($filepath.'/'.$fname); - if ($mime_type eq 'text/html') { + my $type = $mm->checktype_filename($filepath.'/'.$fname); + if ($type eq 'text/html') { my $parse_result = &extract_embedded_items($filepath.'/'.$fname,$allfiles,$codebase); unless ($parse_result eq 'ok') { &logthis('Failed to parse '.$filepath.'/'.$fname.' for embedded media: '.$parse_result); } } + if (ref($mimetype)) { + $$mimetype = $type; + } } $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file, $home); @@ -2340,9 +2409,13 @@ sub resizeImage { # --------------- Take an uploaded file and put it into the userfiles directory # input: $formname - the contents of the file are in $env{"form.$formname"} -# the desired filenam is in $env{"form.$formname.filename"} -# $coursedoc - if true up to the current course -# if false +# the desired filename is in $env{"form.$formname.filename"} +# $context - possible values: coursedoc, existingfile, overwrite, +# canceloverwrite, or ''. +# if 'coursedoc': upload to the current course +# if 'existingfile': write file to tmp/overwrites directory +# if 'canceloverwrite': delete file written to tmp/overwrites directory +# $context is passed as argument to &finishuserfileupload # $subdir - directory in userfile to store the file into # $parser - instruction to parse file for objects ($parser = parse) # $allfiles - reference to hash for embedded objects @@ -2353,37 +2426,60 @@ sub resizeImage { # $thumbheight - height (pixels) of thumbnail to make for uploaded image # $resizewidth - width (pixels) to which to resize uploaded image # $resizeheight - height (pixels) to which to resize uploaded image +# $mimetype - reference to scalar to accommodate mime type determined +# from File::MMagic if $parser = parse. # # output: url of file in userspace, or error: # or /adm/notfound.html if failure to upload occurse sub userfileupload { - my ($formname,$coursedoc,$subdir,$parser,$allfiles,$codebase,$destuname, - $destudom,$thumbwidth,$thumbheight,$resizewidth,$resizeheight)=@_; + my ($formname,$context,$subdir,$parser,$allfiles,$codebase,$destuname, + $destudom,$thumbwidth,$thumbheight,$resizewidth,$resizeheight,$mimetype)=@_; if (!defined($subdir)) { $subdir='unknown'; } my $fname=$env{'form.'.$formname.'.filename'}; $fname=&clean_filename($fname); -# See if there is anything left + # See if there is anything left unless ($fname) { return 'error: no uploaded file'; } - chop($env{'form.'.$formname}); - if (($formname eq 'screenshot') && ($subdir eq 'helprequests')) { #files uploaded to help request form are handled differently + # Files uploaded to help request form, or uploaded to "create course" page are handled differently + if ((($formname eq 'screenshot') && ($subdir eq 'helprequests')) || + (($formname eq 'coursecreatorxml') && ($subdir eq 'batchupload')) || + ($context eq 'existingfile') || ($context eq 'canceloverwrite')) { my $now = time; - my $filepath = 'tmp/helprequests/'.$now; - my @parts=split(/\//,$filepath); - my $fullpath = $perlvar{'lonDaemons'}; - for (my $i=0;$i<@parts;$i++) { - $fullpath .= '/'.$parts[$i]; - if ((-e $fullpath)!=1) { - mkdir($fullpath,0777); + my $filepath; + if (($formname eq 'screenshot') && ($subdir eq 'helprequests')) { + $filepath = 'tmp/helprequests/'.$now; + } elsif (($formname eq 'coursecreatorxml') && ($subdir eq 'batchupload')) { + $filepath = 'tmp/addcourse/'.$destudom.'/web/'.$env{'user.name'}. + '_'.$env{'user.domain'}.'/pending'; + } elsif (($context eq 'existingfile') || ($context eq 'canceloverwrite')) { + my ($docuname,$docudom); + if ($destudom) { + $docudom = $destudom; + } else { + $docudom = $env{'user.domain'}; + } + if ($destuname) { + $docuname = $destuname; + } else { + $docuname = $env{'user.name'}; + } + if (exists($env{'form.group'})) { + $docuname=$env{'course.'.$env{'request.course.id'}.'.num'}; + $docudom=$env{'course.'.$env{'request.course.id'}.'.domain'}; + } + $filepath = 'tmp/overwrites/'.$docudom.'/'.$docuname.'/'.$subdir; + if ($context eq 'canceloverwrite') { + my $tempfile = $perlvar{'lonDaemons'}.'/'.$filepath.'/'.$fname; + if (-e $tempfile) { + my @info = stat($tempfile); + if ($info[9] eq $env{'form.timestamp'}) { + unlink($tempfile); + } + } + return; } } - open(my $fh,'>'.$fullpath.'/'.$fname); - print $fh $env{'form.'.$formname}; - close($fh); - return $fullpath.'/'.$fname; - } elsif (($formname eq 'coursecreatorxml') && ($subdir eq 'batchupload')) { #files uploaded to create course page are handled differently - my $filepath = 'tmp/addcourse/'.$destudom.'/web/'.$env{'user.name'}. - '_'.$env{'user.domain'}.'/pending'; + # Create the directory if not present my @parts=split(/\//,$filepath); my $fullpath = $perlvar{'lonDaemons'}; for (my $i=0;$i<@parts;$i++) { @@ -2395,27 +2491,31 @@ sub userfileupload { open(my $fh,'>'.$fullpath.'/'.$fname); print $fh $env{'form.'.$formname}; close($fh); - return $fullpath.'/'.$fname; + if ($context eq 'existingfile') { + my @info = stat($fullpath.'/'.$fname); + return ($fullpath.'/'.$fname,$info[9]); + } else { + return $fullpath.'/'.$fname; + } } if ($subdir eq 'scantron') { $fname = 'scantron_orig_'.$fname; - } else { -# Create the directory if not present + } else { $fname="$subdir/$fname"; } - if ($coursedoc) { + if ($context eq 'coursedoc') { my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'}; my $docudom=$env{'course.'.$env{'request.course.id'}.'.domain'}; if ($env{'form.folder'} =~ m/^(default|supplemental)/) { return &finishuserfileupload($docuname,$docudom, $formname,$fname,$parser,$allfiles, $codebase,$thumbwidth,$thumbheight, - $resizewidth,$resizeheight); + $resizewidth,$resizeheight,$context,$mimetype); } else { $fname=$env{'form.folder'}.'/'.$fname; return &process_coursefile('uploaddoc',$docuname,$docudom, $fname,$formname,$parser, - $allfiles,$codebase); + $allfiles,$codebase,$mimetype); } } elsif (defined($destuname)) { my $docuname=$destuname; @@ -2423,8 +2523,7 @@ sub userfileupload { return &finishuserfileupload($docuname,$docudom,$formname,$fname, $parser,$allfiles,$codebase, $thumbwidth,$thumbheight, - $resizewidth,$resizeheight); - + $resizewidth,$resizeheight,$context,$mimetype); } else { my $docuname=$env{'user.name'}; my $docudom=$env{'user.domain'}; @@ -2435,13 +2534,13 @@ sub userfileupload { return &finishuserfileupload($docuname,$docudom,$formname,$fname, $parser,$allfiles,$codebase, $thumbwidth,$thumbheight, - $resizewidth,$resizeheight); + $resizewidth,$resizeheight,$context,$mimetype); } } sub finishuserfileupload { my ($docuname,$docudom,$formname,$fname,$parser,$allfiles,$codebase, - $thumbwidth,$thumbheight,$resizewidth,$resizeheight) = @_; + $thumbwidth,$thumbheight,$resizewidth,$resizeheight,$context,$mimetype) = @_; my $path=$docudom.'/'.$docuname.'/'; my $filepath=$perlvar{'lonDocRoot'}; @@ -2467,7 +2566,23 @@ sub finishuserfileupload { print STDERR ('Failed to create '.$filepath.'/'.$file."\n"); return '/adm/notfound.html'; } - if (!print FH ($env{'form.'.$formname})) { + if ($context eq 'overwrite') { + my $source = $perlvar{'lonDaemons'}.'/tmp/overwrites/'.$docudom.'/'.$docuname.'/'.$fname; + my $target = $filepath.'/'.$file; + if (-e $source) { + my @info = stat($source); + if ($info[9] eq $env{'form.timestamp'}) { + unless (&File::Copy::move($source,$target)) { + &logthis('Failed to overwrite '.$filepath.'/'.$file); + return "Moving from $source failed"; + } + } else { + return "Temporary file: $source had unexpected date/time for last modification"; + } + } else { + return "Temporary file: $source missing"; + } + } elsif (!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'; @@ -2483,8 +2598,8 @@ sub finishuserfileupload { } if ($parser eq 'parse') { my $mm = new File::MMagic; - my $mime_type = $mm->checktype_filename($filepath.'/'.$file); - if ($mime_type eq 'text/html') { + my $type = $mm->checktype_filename($filepath.'/'.$file); + if ($type eq 'text/html') { my $parse_result = &extract_embedded_items($filepath.'/'.$file, $allfiles,$codebase); unless ($parse_result eq 'ok') { @@ -2492,6 +2607,9 @@ sub finishuserfileupload { ' for embedded media: '.$parse_result); } } + if (ref($mimetype)) { + $$mimetype = $type; + } } if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) { my $input = $filepath.'/'.$file; @@ -3026,7 +3144,8 @@ sub get_my_roles { unless (defined($udom)) { $udom=$env{'user.domain'}; } my (%dumphash,%nothide); if ($context eq 'userroles') { - %dumphash = &dump('roles',$udom,$uname); + my $extra = &freeze_escape({'skipcheck' => 1}); + %dumphash = &dump('roles',$udom,$uname,'.',undef,$extra); } else { %dumphash= &dump('nohist_userroles',$udom,$uname); @@ -4013,6 +4132,44 @@ sub coursedescription { return %returnhash; } +sub update_released_required { + my ($needsrelease,$cdom,$cnum,$chome,$cid) = @_; + if ($cdom eq '' || $cnum eq '' || $chome eq '' || $cid eq '') { + $cid = $env{'request.course.id'}; + $cdom = $env{'course.'.$cid.'.domain'}; + $cnum = $env{'course.'.$cid.'.num'}; + $chome = $env{'course.'.$cid.'.home'}; + } + if ($needsrelease) { + my %curr_reqd_hash = &userenvironment($cdom,$cnum,'internal.releaserequired'); + my $needsupdate; + if ($curr_reqd_hash{'internal.releaserequired'} eq '') { + $needsupdate = 1; + } else { + my ($currmajor,$currminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'}); + my ($needsmajor,$needsminor) = split(/\./,$needsrelease); + if (($currmajor < $needsmajor) || ($currmajor == $needsmajor && $currminor < $needsminor)) { + $needsupdate = 1; + } + } + if ($needsupdate) { + my %needshash = ( + 'internal.releaserequired' => $needsrelease, + ); + my $putresult = &put('environment',\%needshash,$cdom,$cnum); + if ($putresult eq 'ok') { + &appenv({'course.'.$cid.'.internal.releaserequired' => $needsrelease}); + my %crsinfo = &courseiddump($cdom,'.',1,'.','.',$cnum,undef,undef,'.'); + if (ref($crsinfo{$cid}) eq 'HASH') { + $crsinfo{$cid}{'releaserequired'} = $needsrelease; + &courseidput($cdom,\%crsinfo,$chome,'notime'); + } + } + } + } + return; +} + # -------------------------------------------------See if a user is privileged sub privileged { @@ -4052,7 +4209,7 @@ sub rolesinit { my ($domain,$username,$authhost)=@_; my $now=time; my %userroles = ('user.login.time' => $now); - my $extra = &freeze_escape({'clientcheckrole' => 1}); + my $extra = &freeze_escape({'skipcheck' => 1}); my $rolesdump=reply("dump:$domain:$username:roles:.::$extra",$authhost); if (($rolesdump eq 'con_lost') || ($rolesdump eq '') || ($rolesdump =~ /^error:/)) { @@ -4268,7 +4425,6 @@ sub role_status { my %rolehash = &get('roles',[$$where.'_'.$$role],$env{'user.domain'}, $env{'user.name'}); my ($trole) = split('_',$rolehash{$$where.'_'.$$role},2); - (undef,my $group_privs) = split(/\//,$trole); $group_privs = &unescape($group_privs); &group_roleprivs(\%allgroups,$$where,$group_privs,$$tend,$$tstart); @@ -4323,22 +4479,22 @@ sub role_status { } sub check_adhoc_privs { - my ($cdom,$cnum,$then,$refresh,$now,$checkrole) = @_; + my ($cdom,$cnum,$then,$refresh,$now,$checkrole,$caller) = @_; my $cckey = 'user.role.'.$checkrole.'./'.$cdom.'/'.$cnum; if ($env{$cckey}) { my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus,$tpstart,$tpend); &role_status($cckey,$then,$refresh,$now,\$role,\$where,\$trolecode,\$tstatus,\$tstart,\$tend); unless (($tstatus eq 'is') || ($tstatus eq 'will_not')) { - &set_adhoc_privileges($cdom,$cnum,$checkrole); + &set_adhoc_privileges($cdom,$cnum,$checkrole,$caller); } } else { - &set_adhoc_privileges($cdom,$cnum,$checkrole); + &set_adhoc_privileges($cdom,$cnum,$checkrole,$caller); } } sub set_adhoc_privileges { # role can be cc or ca - my ($dcdom,$pickedcourse,$role) = @_; + my ($dcdom,$pickedcourse,$role,$caller) = @_; my $area = '/'.$dcdom.'/'.$pickedcourse; my $spec = $role.'.'.$area; my %userroles = &set_arearole($role,$area,'','',$env{'user.domain'}, @@ -4348,14 +4504,16 @@ sub set_adhoc_privileges { my ($author,$adv)= &set_userprivs(\%userroles,\%ccrole); &appenv(\%userroles,[$role,'cm']); &log($env{'user.domain'},$env{'user.name'},$env{'user.home'},"Role ".$role); - &appenv( {'request.role' => $spec, - 'request.role.domain' => $dcdom, - 'request.course.sec' => '' - } - ); - my $tadv=0; - if (&allowed('adv') eq 'F') { $tadv=1; } - &appenv({'request.role.adv' => $tadv}); + unless ($caller eq 'constructaccess' && $env{'request.course.id'}) { + &appenv( {'request.role' => $spec, + 'request.role.domain' => $dcdom, + 'request.course.sec' => '' + } + ); + my $tadv=0; + if (&allowed('adv') eq 'F') { $tadv=1; } + &appenv({'request.role.adv' => $tadv}); + } } # --------------------------------------------------------------- get interface @@ -4404,7 +4562,7 @@ sub del { # -------------------------------------------------------------- dump interface sub dump { - my ($namespace,$udomain,$uname,$regexp,$range)=@_; + my ($namespace,$udomain,$uname,$regexp,$range,$extra)=@_; if (!$udomain) { $udomain=$env{'user.domain'}; } if (!$uname) { $uname=$env{'user.name'}; } my $uhome=&homeserver($uname,$udomain); @@ -4413,7 +4571,7 @@ sub dump { } else { $regexp='.'; } - my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome); + my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range:$extra",$uhome); my @pairs=split(/\&/,$rep); my %returnhash=(); foreach my $item (@pairs) { @@ -4958,7 +5116,7 @@ sub is_portfolio_file { } sub usertools_access { - my ($uname,$udom,$tool,$action,$context) = @_; + my ($uname,$udom,$tool,$action,$context,$userenvref,$domdefref,$is_advref) = @_; my ($access,%tools); if ($context eq '') { $context = 'tools'; @@ -5000,9 +5158,14 @@ sub usertools_access { $toolstatus = $env{'environment.'.$context.'.'.$tool}; $inststatus = $env{'environment.inststatus'}; } else { - my %userenv = &userenvironment($udom,$uname,$context.'.'.$tool,'inststatus'); - $toolstatus = $userenv{$context.'.'.$tool}; - $inststatus = $userenv{'inststatus'}; + if (ref($userenvref) eq 'HASH') { + $toolstatus = $userenvref->{$context.'.'.$tool}; + $inststatus = $userenvref->{'inststatus'}; + } else { + my %userenv = &userenvironment($udom,$uname,$context.'.'.$tool,'inststatus'); + $toolstatus = $userenv{$context.'.'.$tool}; + $inststatus = $userenv{'inststatus'}; + } } if ($toolstatus ne '') { @@ -5014,8 +5177,17 @@ sub usertools_access { return $access; } - my $is_adv = &is_advanced_user($udom,$uname); - my %domdef = &get_domain_defaults($udom); + my ($is_adv,%domdef); + if (ref($is_advref) eq 'HASH') { + $is_adv = $is_advref->{'is_adv'}; + } else { + $is_adv = &is_advanced_user($udom,$uname); + } + if (ref($domdefref) eq 'HASH') { + %domdef = %{$domdefref}; + } else { + %domdef = &get_domain_defaults($udom); + } if (ref($domdef{$tool}) eq 'HASH') { if ($is_adv) { if ($domdef{$tool}{'_LC_adv'} ne '') { @@ -5089,6 +5261,11 @@ sub is_course_owner { sub is_advanced_user { my ($udom,$uname) = @_; + if ($udom ne '' && $uname ne '') { + if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'})) { + return $env{'user.adv'}; + } + } my %roleshash = &get_my_roles($uname,$udom,'userroles',undef,undef,undef,1); my %allroles; my $is_adv; @@ -5604,7 +5781,7 @@ sub allowed { my $unamedom=$env{'user.name'}.':'.$env{'user.domain'}; if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.roles.denied'} =~/\Q$rolecode\E/) { - if ($priv ne 'pch') { + if (($priv ne 'pch') && ($priv ne 'plc')) { &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'. 'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode.' in '. $env{'request.course.id'}); @@ -5614,7 +5791,7 @@ sub allowed { if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.users.denied'} =~/\Q$unamedom\E/) { - if ($priv ne 'pch') { + if (($priv ne 'pch') && ($priv ne 'plc')) { &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}. 'Denied by user: '.$priv.' for '.$uri.' as '.$unamedom.' in '. $env{'request.course.id'}); @@ -5628,7 +5805,7 @@ sub allowed { if ($thisallowed=~/R/) { my $rolecode=(split(/\./,$env{'request.role'}))[0]; if (&metadata($uri,'roledeny')=~/\Q$rolecode\E/) { - if ($priv ne 'pch') { + if (($priv ne 'pch') && ($priv ne 'plc')) { &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'. 'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode); } @@ -5981,9 +6158,9 @@ sub auto_get_sections { } sub auto_new_course { - my ($cnum,$cdom,$inst_course_id,$owner) = @_; + my ($cnum,$cdom,$inst_course_id,$owner,$coowners) = @_; my $homeserver = &homeserver($cnum,$cdom); - my $response=&unescape(&reply('autonewcourse:'.$inst_course_id.':'.$owner.':'.$cdom,$homeserver)); + my $response=&unescape(&reply('autonewcourse:'.$inst_course_id.':'.&escape($owner).':'.$cdom.':'.&escape($coowners),$homeserver)); return $response; } @@ -6374,7 +6551,8 @@ sub get_users_groups { } else { $grouplist = ''; my $courseurl = &courseid_to_courseurl($courseid); - my %roleshash = &dump('roles',$udom,$uname,$courseurl); + my $extra = &freeze_escape({'skipcheck' => 1}); + my %roleshash = &dump('roles',$udom,$uname,$courseurl,undef,$extra); my $access_end = $env{'course.'.$courseid. '.default_enrollment_end_date'}; my $now = time; @@ -6738,7 +6916,6 @@ sub modifyuser { if ($uhome eq 'no_host') { $newuser = 1; } - # ----------------------------------------------------------------- Create User if (($uhome eq 'no_host') && (($umode && $upass) || ($umode eq 'localauth'))) { @@ -6798,6 +6975,7 @@ sub modifyuser { %names = @tmp; %oldnames = %names; } +# # If name, email and/or uid are blank (e.g., because an uploaded file # of users did not contain them), do not overwrite existing values # unless field is in $candelete array ref. @@ -6849,10 +7027,6 @@ sub modifyuser { } } } - my $reply = &put('environment', \%names, $udom,$uname); - if ($reply ne 'ok') { return 'error: '.$reply; } - my $sqlresult = &update_allusers_table($uname,$udom,\%names); - &devalidate_cache_new('namescache',$uname.':'.$udom); my $logmsg = $udom.', '.$uname.', '.$uid.', '. $umode.', '.$first.', '.$middle.', '. $last.', '.$gene.', '.$email.', '.$inststatus; @@ -6881,6 +7055,9 @@ sub modifyuser { if ($reply ne 'ok') { return 'error: '.$reply; } + if ($names{'permanentemail'} ne $oldnames{'permanentemail'}) { + &Apache::lonnet::devalidate_cache_new('emailscache',$uname.':'.$udom); + } my $sqlresult = &update_allusers_table($uname,$udom,\%names); &devalidate_cache_new('namescache',$uname.':'.$udom); $logmsg = 'Success modifying user '.$logmsg; @@ -7200,8 +7377,8 @@ sub store_userdata { $namevalue.=&escape($key).'='.&freeze_escape($$storehash{$key}).'&'; } $namevalue=~s/\&$//; - $result = &reply("store:$env{'user.domain'}:$env{'user.name'}:". - "$namespace:$datakey:$namevalue",$uhome); + $result = &reply("store:$udom:$uname:$namespace:$datakey:". + $namevalue,$uhome); } } else { $result = 'error: data to store was not a hash reference'; @@ -7254,10 +7431,10 @@ sub diskusage { } sub is_locked { - my ($file_name, $domain, $user) = @_; + my ($file_name, $domain, $user, $which) = @_; my @check; my $is_locked; - push @check, $file_name; + push(@check,$file_name); my %locked = &get('file_permissions',\@check, $env{'user.domain'},$env{'user.name'}); my ($tmp)=keys(%locked); @@ -7266,14 +7443,19 @@ sub is_locked { if (ref($locked{$file_name}) eq 'ARRAY') { $is_locked = 'false'; foreach my $entry (@{$locked{$file_name}}) { - if (ref($entry) eq 'ARRAY') { + if (ref($entry) eq 'ARRAY') { $is_locked = 'true'; - last; + if (ref($which) eq 'ARRAY') { + push(@{$which},$entry); + } else { + last; + } } } } else { $is_locked = 'false'; } + return $is_locked; } sub declutter_portfile { @@ -8423,7 +8605,7 @@ sub metadata { if (($uri eq '') || (($uri =~ m|^/*adm/|) && ($uri !~ m|^adm/includes|) && ($uri !~ m|/bulletinboard$|)) || - ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) ) { + ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ m{^/*uploaded/.+\.sequence$})) { return undef; } if (($uri =~ /^~/ || $uri =~ m{home/$match_username/public_html/}) @@ -8465,7 +8647,8 @@ sub metadata { &Apache::lonnet::ssi_body($which, ('grade_target' => 'meta')); $cachetime = 1; # only want this cached in the child not long term - } elsif ($uri !~ m -^(editupload)/-) { + } elsif (($uri !~ m -^(editupload)/-) && + ($uri !~ m{^/*uploaded/$match_domain/$match_courseid/docs/})) { my $file=&filelocation('',&clutter($filename)); #push(@{$metaentry{$uri.'.file'}},$file); $metastring=&getfile($file); @@ -8555,7 +8738,6 @@ sub metadata { } } } else { - if (defined($token->[2]->{'name'})) { $unikey.='_'.$token->[2]->{'name'}; } @@ -8814,7 +8996,8 @@ sub symbverify { } my $ids=$bighash{'ids_'.&clutter($thisurl)}; unless ($ids) { - $ids=$bighash{'ids_/'.$thisurl}; + my $idkey = 'ids_'.($thisurl =~ m{^/}? '' : '/').$thisurl; + $ids=$bighash{$idkey}; } if ($ids) { # ------------------------------------------------------------------- Has ID(s) @@ -8827,7 +9010,8 @@ sub symbverify { &symbclean(&declutter($bighash{'map_id_'.$mapid}).'___'.$resid.'___'.$thisfn) eq $symb) { if (($env{'request.role.adv'}) || - $bighash{'encrypted_'.$id} eq $env{'request.enc'}) { + ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) || + ($thisurl eq '/adm/navmaps')) { $okay=1; } } @@ -9905,14 +10089,21 @@ sub get_dns { my %libserv; my $loaded; my %name_to_host; + my %internetdom; + my %LC_dns_serv; sub parse_hosts_tab { my ($file) = @_; foreach my $configline (@$file) { next if ($configline =~ /^(\#|\s*$ )/x); - next if ($configline =~ /^\^/); - chomp($configline); - my ($id,$domain,$role,$name,$protocol)=split(/:/,$configline); + chomp($configline); + if ($configline =~ /^\^/) { + if ($configline =~ /^\^([\w.\-]+)/) { + $LC_dns_serv{$1} = 1; + } + next; + } + my ($id,$domain,$role,$name,$protocol,$intdom)=split(/:/,$configline); $name=~s/\s//g; if ($id && $domain && $role && $name) { $hostname{$id}=$name; @@ -9928,6 +10119,9 @@ sub get_dns { } else { $protocol{$id} = 'http'; } + if (defined($intdom)) { + $internetdom{$id} = $intdom; + } } } } @@ -10045,6 +10239,13 @@ sub get_dns { return $internetdom{$lonid}; } + sub is_LC_dns { + &load_hosts_tab() if (!$loaded); + + my ($hostname) = @_; + return exists($LC_dns_serv{$hostname}); + } + } { @@ -10301,6 +10502,25 @@ BEGIN { } } +{ + my $file = $Apache::lonnet::perlvar{'lonTabDir'}.'/releaseslist.xml'; + if (-e $file) { + my $parser = HTML::LCParser->new($file); + while (my $token = $parser->get_token()) { + if ($token->[0] eq 'S') { + my $item = $token->[1]; + my $name = $token->[2]{'name'}; + my $value = $token->[2]{'value'}; + if ($item ne '' && $name ne '' && $value ne '') { + my $release = $parser->get_text(); + $release =~ s/(^\s*|\s*$ )//gx; + $needsrelease{$item.':'.$name.':'.$value} = $release; + } + } + } + } +} + # ------------- set up temporary directory { $tmpdir = $perlvar{'lonDaemons'}.'/tmp/'; @@ -11287,8 +11507,10 @@ userfileupload(): main rotine for puttin filename, and the contents of the file to create/modifed exist the filename is in $env{'form.'.$formname.'.filename'} and the contents of the file is located in $env{'form.'.$formname} - coursedoc - if true, store the file in the course of the active role - of the current user + context - if coursedoc, store the file in the course of the active role + of the current user; + if 'existingfile': store in 'overwrites' in /home/httpd/perl/tmp + if 'canceloverwrite': delete file in tmp/overwrites directory subdir - required - subdirectory to put the file in under ../userfiles/ if undefined, it will be placed in "unknown" @@ -11310,16 +11532,29 @@ returns: the new clean filename =item * -finishuserfileupload(): routine that creaes and sends the file to +finishuserfileupload(): routine that creates and sends the file to userspace, probably shouldn't be called directly docuname: username or courseid of destination for the file docudom: domain of user/course of destination for the file formname: same as for userfileupload() - fname: filename (inculding subdirectories) for the file + fname: filename (including subdirectories) for the file + parser: if 'parse', will parse (html) file to extract references to objects, links etc. + allfiles: reference to hash used to store objects found by parser + codebase: reference to hash used for codebases of java objects found by parser + thumbwidth: width (pixels) of thumbnail to be created for uploaded image + thumbheight: height (pixels) of thumbnail to be created for uploaded image + resizewidth: width to be used to resize image using resizeImage from ImageMagick + resizeheight: height to be used to resize image using resizeImage from ImageMagick + context: if 'overwrite', will move the uploaded file from its temporary location to + userfiles to facilitate overwriting a previously uploaded file with same name. + mimetype: reference to scalar to accommodate mime type determined + from File::MMagic if $parser = parse. returns either the url of the uploaded file (/uploaded/....) if successful - and /adm/notfound.html if unsuccessful + and /adm/notfound.html if unsuccessful (or an error message if context + was 'overwrite'). + =item *