--- loncom/lonnet/perl/lonnet.pm 2010/07/06 18:36:56 1.1072
+++ loncom/lonnet/perl/lonnet.pm 2011/01/08 06:13:20 1.1097
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1072 2010/07/06 18:36:56 www Exp $
+# $Id: lonnet.pm,v 1.1097 2011/01/08 06:13:20 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);
+ $_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.
@@ -196,7 +197,7 @@ sub get_server_timezone {
}
sub get_server_loncaparev {
- my ($dom,$lonhost) = @_;
+ my ($dom,$lonhost,$ignore_cache,$caller) = @_;
if (defined($lonhost)) {
if (!defined(&hostname($lonhost))) {
undef($lonhost);
@@ -211,15 +212,74 @@ sub get_server_loncaparev {
}
}
if (defined($lonhost)) {
- my $cachetime = 24*3600;
- my ($loncaparev,$cached)=&is_cached_new('serverloncaparev',$lonhost);
+ my $cachetime = 12*3600;
+ if (!$ignore_cache) {
+ my ($loncaparev,$cached)=&is_cached_new('serverloncaparev',$lonhost);
+ if (defined($cached)) {
+ return $loncaparev;
+ }
+ }
+ my ($answer,$loncaparev);
+ my @ids=¤t_machine_ids();
+ if (grep(/^\Q$lonhost\E$/,@ids)) {
+ $answer = $perlvar{'lonVersion'};
+ if ($answer =~ /^[\'\"]?([\w.\-]+)[\'\"]?$/) {
+ $loncaparev = $1;
+ }
+ } else {
+ $answer = &reply('serverloncaparev',$lonhost);
+ if (($answer eq 'unknown_cmd') || ($answer eq 'con_lost')) {
+ if ($caller eq 'loncron') {
+ my $ua=new LWP::UserAgent;
+ $ua->timeout(4);
+ my $protocol = $protocol{$lonhost};
+ $protocol = 'http' if ($protocol ne 'https');
+ my $url = $protocol.'://'.&hostname($lonhost).'/adm/about.html';
+ my $request=new HTTP::Request('GET',$url);
+ my $response=$ua->request($request);
+ unless ($response->is_error()) {
+ my $content = $response->content;
+ if ($content =~ /
VERSION\:\s*([\w.\-]+)<\/p>/) {
+ $loncaparev = $1;
+ }
+ }
+ } else {
+ $loncaparev = $loncaparevs{$lonhost};
+ }
+ } elsif ($answer =~ /^[\'\"]?([\w.\-]+)[\'\"]?$/) {
+ $loncaparev = $1;
+ }
+ }
+ return &do_cache_new('serverloncaparev',$lonhost,$loncaparev,$cachetime);
+ }
+}
+
+sub get_server_homeID {
+ my ($hostname,$ignore_cache,$caller) = @_;
+ unless ($ignore_cache) {
+ my ($serverhomeID,$cached)=&is_cached_new('serverhomeID',$hostname);
if (defined($cached)) {
- return $loncaparev;
- } else {
- my $loncaparev = &reply('serverloncaparev',$lonhost);
- return &do_cache_new('serverloncaparev',$lonhost,$loncaparev,$cachetime);
+ return $serverhomeID;
+ }
+ }
+ my $cachetime = 12*3600;
+ my $serverhomeID;
+ if ($caller eq 'loncron') {
+ my @machine_ids = &machine_ids($hostname);
+ foreach my $id (@machine_ids) {
+ my $response = &reply('serverhomeID',$id);
+ unless (($response eq 'unknown_cmd') || ($response eq 'con_lost')) {
+ $serverhomeID = $response;
+ last;
+ }
+ }
+ if ($serverhomeID eq '') {
+ $serverhomeID = $machine_ids[-1];
}
+ } else {
+ $serverhomeID = $serverhomeIDs{$hostname};
}
+ return &do_cache_new('serverhomeID',$hostname,$serverhomeID,$cachetime);
}
# -------------------------------------------------- Non-critical communication
@@ -668,13 +728,23 @@ sub userload {
# ------------------------------ 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);
}
@@ -683,6 +753,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);
}
@@ -695,7 +769,7 @@ sub spareserver {
}
if (defined($spare_server)) {
my $hostname = &hostname($spare_server);
- if (defined($hostname)) {
+ if (defined($hostname)) {
$spare_server = $protocol.'://'.$hostname;
}
}
@@ -753,6 +827,27 @@ sub has_user_session {
return 0;
}
+# --------- determine least loaded server in a user's domain which allows login
+
+sub choose_server {
+ my ($udom) = @_;
+ my %domconfhash = &Apache::loncommon::get_domainconf($udom);
+ my %servers = &get_servers($udom);
+ my $lowest_load = 30000;
+ my ($login_host,$hostname);
+ foreach my $lonhost (keys(%servers)) {
+ my $loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost};
+ if ($loginvia eq '') {
+ ($login_host, $lowest_load) =
+ &compare_server_load($lonhost, $login_host, $lowest_load);
+ }
+ }
+ if ($login_host ne '') {
+ $hostname = $servers{$login_host};
+ }
+ return ($login_host,$hostname);
+}
+
# --------------------------------------------- Try to change a user's password
sub changepass {
@@ -811,7 +906,7 @@ sub queryauthenticate {
# --------- Try to authenticate user from domain's lib servers (first this one)
sub authenticate {
- my ($uname,$upass,$udom,$checkdefauth)=@_;
+ my ($uname,$upass,$udom,$checkdefauth,$clientcancheckhost)=@_;
$upass=&escape($upass);
$uname= &LONCAPA::clean_username($uname);
my $uhome=&homeserver($uname,$udom,1);
@@ -834,7 +929,7 @@ sub authenticate {
return 'no_host';
}
}
- my $answer=reply("encrypt:auth:$udom:$uname:$upass:$checkdefauth",$uhome);
+ my $answer=reply("encrypt:auth:$udom:$uname:$upass:$checkdefauth:$clientcancheckhost",$uhome);
if ($answer eq 'authorized') {
if ($newhome) {
&logthis("User $uname at $udom authorized by $uhome, but needs account");
@@ -852,6 +947,84 @@ sub authenticate {
return 'no_host';
}
+sub can_host_session {
+ my ($udom,$lonhost,$remoterev,$remotesessions,$hostedsessions) = @_;
+ my $canhost = 1;
+ my $host_idn = &Apache::lonnet::internet_dom($lonhost);
+ if (ref($remotesessions) eq 'HASH') {
+ if (ref($remotesessions->{'excludedomain'}) eq 'ARRAY') {
+ if (grep(/^\Q$host_idn\E$/,@{$remotesessions->{'excludedomain'}})) {
+ $canhost = 0;
+ } else {
+ $canhost = 1;
+ }
+ }
+ if (ref($remotesessions->{'includedomain'}) eq 'ARRAY') {
+ if (grep(/^\Q$host_idn\E$/,@{$remotesessions->{'includedomain'}})) {
+ $canhost = 1;
+ } else {
+ $canhost = 0;
+ }
+ }
+ if ($canhost) {
+ if ($remotesessions->{'version'} ne '') {
+ my ($reqmajor,$reqminor) = ($remotesessions->{'version'} =~ /^(\d+)\.(\d+)$/);
+ if ($reqmajor ne '' && $reqminor ne '') {
+ if ($remoterev =~ /^\'?(\d+)\.(\d+)/) {
+ my $major = $1;
+ my $minor = $2;
+ if (($major < $reqmajor ) ||
+ (($major == $reqmajor) && ($minor < $reqminor))) {
+ $canhost = 0;
+ }
+ } else {
+ $canhost = 0;
+ }
+ }
+ }
+ }
+ }
+ if ($canhost) {
+ if (ref($hostedsessions) eq 'HASH') {
+ if (ref($hostedsessions->{'excludedomain'}) eq 'ARRAY') {
+ if (grep(/^\Q$udom\E$/,@{$hostedsessions->{'excludedomain'}})) {
+ $canhost = 0;
+ } else {
+ $canhost = 1;
+ }
+ }
+ if (ref($hostedsessions->{'includedomain'}) eq 'ARRAY') {
+ if (grep(/^\Q$udom\E$/,@{$hostedsessions->{'includedomain'}})) {
+ $canhost = 1;
+ } else {
+ $canhost = 0;
+ }
+ }
+ }
+ }
+ 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;
@@ -1328,7 +1501,7 @@ sub get_domain_defaults {
my %domconfig =
&Apache::lonnet::get_dom('configuration',['defaults','quotas',
'requestcourses','inststatus',
- 'coursedefaults'],$domain);
+ 'coursedefaults','usersessions'],$domain);
if (ref($domconfig{'defaults'}) eq 'HASH') {
$domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'};
$domdefaults{'auth_def'} = $domconfig{'defaults'}{'auth_def'};
@@ -1368,6 +1541,14 @@ sub get_domain_defaults {
$domdefaults{$item} = $domconfig{'coursedefaults'}{$item};
}
}
+ if (ref($domconfig{'usersessions'}) eq 'HASH') {
+ if (ref($domconfig{'usersessions'}{'remote'}) eq 'HASH') {
+ $domdefaults{'remotesessions'} = $domconfig{'usersessions'}{'remote'};
+ }
+ if (ref($domconfig{'usersessions'}{'hosted'}) eq 'HASH') {
+ $domdefaults{'hostedsessions'} = $domconfig{'usersessions'}{'hosted'};
+ }
+ }
&Apache::lonnet::do_cache_new('domdefaults',$domain,\%domdefaults,
$cachetime);
return %domdefaults;
@@ -1553,7 +1734,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;
@@ -1994,6 +2176,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)
@@ -2020,7 +2204,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') {
@@ -2048,13 +2233,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);
@@ -2170,9 +2358,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
@@ -2183,37 +2375,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++) {
@@ -2225,27 +2440,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;
@@ -2253,8 +2472,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'};
@@ -2265,13 +2483,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'};
@@ -2297,7 +2515,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';
@@ -2313,8 +2547,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') {
@@ -2322,6 +2556,9 @@ sub finishuserfileupload {
' for embedded media: '.$parse_result);
}
}
+ if (ref($mimetype)) {
+ $$mimetype = $type;
+ }
}
if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) {
my $input = $filepath.'/'.$file;
@@ -2855,8 +3092,9 @@ sub get_my_roles {
unless (defined($uname)) { $uname=$env{'user.name'}; }
unless (defined($udom)) { $udom=$env{'user.domain'}; }
my (%dumphash,%nothide);
- if ($context eq 'userroles') {
- %dumphash = &dump('roles',$udom,$uname);
+ if ($context eq 'userroles') {
+ my $extra = &freeze_escape({'skipcheck' => 1});
+ %dumphash = &dump('roles',$udom,$uname,'.',undef,$extra);
} else {
%dumphash=
&dump('nohist_userroles',$udom,$uname);
@@ -3758,6 +3996,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 {
@@ -3797,9 +4073,10 @@ sub rolesinit {
my ($domain,$username,$authhost)=@_;
my $now=time;
my %userroles = ('user.login.time' => $now);
- my $rolesdump=reply("dump:$domain:$username:roles",$authhost);
+ my $extra = &freeze_escape({'skipcheck' => 1});
+ my $rolesdump=reply("dump:$domain:$username:roles:.::$extra",$authhost);
if (($rolesdump eq 'con_lost') || ($rolesdump eq '') ||
- ($rolesdump =~ /^error:/)) {
+ ($rolesdump =~ /^error:/)) {
return \%userroles;
}
my %allroles=();
@@ -4066,22 +4343,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'},
@@ -4091,14 +4368,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
@@ -4147,7 +4426,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);
@@ -4156,7 +4435,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) {
@@ -4701,7 +4980,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';
@@ -4743,9 +5022,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 '') {
@@ -4757,8 +5041,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 '') {
@@ -4832,6 +5125,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;
@@ -5554,8 +5852,7 @@ sub update_allusers_table {
'generation='.&escape($names->{'generation'}).'%%'.
'permanentemail='.&escape($names->{'permanentemail'}).'%%'.
'id='.&escape($names->{'id'}),$homeserver);
- my $reply = &get_query_reply($queryid);
- return $reply;
+ return;
}
# ------- Request retrieval of institutional classlists for course(s)
@@ -6118,7 +6415,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;
@@ -6478,6 +6776,10 @@ sub modifyuser {
' by '.$env{'user.name'}.' at '.$env{'user.domain'}.
' in domain '.$env{'request.role.domain'});
my $uhome=&homeserver($uname,$udom,'true');
+ my $newuser;
+ if ($uhome eq 'no_host') {
+ $newuser = 1;
+ }
# ----------------------------------------------------------------- Create User
if (($uhome eq 'no_host') &&
(($umode && $upass) || ($umode eq 'localauth'))) {
@@ -6530,11 +6832,12 @@ sub modifyuser {
['firstname','middlename','lastname','generation','id',
'permanentemail','inststatus'],
$udom,$uname);
- my %names;
+ my (%names,%oldnames);
if ($tmp[0] =~ m/^error:.*/) {
%names=();
} else {
%names = @tmp;
+ %oldnames = %names;
}
#
# If name, email and/or uid are blank (e.g., because an uploaded file
@@ -6588,18 +6891,40 @@ 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 = 'Success modifying user '.$udom.', '.$uname.', '.$uid.', '.
+ my $logmsg = $udom.', '.$uname.', '.$uid.', '.
$umode.', '.$first.', '.$middle.', '.
- $last.', '.$gene.', '.$email.', '.$inststatus;
+ $last.', '.$gene.', '.$email.', '.$inststatus;
if ($env{'user.name'} ne '' && $env{'user.domain'}) {
$logmsg .= ' by '.$env{'user.name'}.' at '.$env{'user.domain'};
} else {
$logmsg .= ' during self creation';
}
+ my $changed;
+ if ($newuser) {
+ $changed = 1;
+ } else {
+ foreach my $field (@fields) {
+ if ($names{$field} ne $oldnames{$field}) {
+ $changed = 1;
+ last;
+ }
+ }
+ }
+ unless ($changed) {
+ $logmsg = 'No changes in user information needed for: '.$logmsg;
+ &logthis($logmsg);
+ return 'ok';
+ }
+ my $reply = &put('environment', \%names, $udom,$uname);
+ 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;
&logthis($logmsg);
return 'ok';
}
@@ -6970,10 +7295,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);
@@ -6982,14 +7307,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 {
@@ -8140,7 +8470,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 =~ /^\*uploaded\/.+\.sequence$/) || ($uri =~ m{^/*uploaded/$match_domain/$match_courseid/docs/})) {
return undef;
}
if (($uri =~ /^~/ || $uri =~ m{home/$match_username/public_html/})
@@ -9677,6 +10007,7 @@ sub get_dns {
my %libserv;
my $loaded;
my %name_to_host;
+ my %internetdom;
sub parse_hosts_tab {
my ($file) = @_;
@@ -9684,7 +10015,7 @@ sub get_dns {
next if ($configline =~ /^(\#|\s*$ )/x);
next if ($configline =~ /^\^/);
chomp($configline);
- my ($id,$domain,$role,$name,$protocol)=split(/:/,$configline);
+ my ($id,$domain,$role,$name,$protocol,$intdom)=split(/:/,$configline);
$name=~s/\s//g;
if ($id && $domain && $role && $name) {
$hostname{$id}=$name;
@@ -9700,6 +10031,9 @@ sub get_dns {
} else {
$protocol{$id} = 'http';
}
+ if (defined($intdom)) {
+ $internetdom{$id} = $intdom;
+ }
}
}
}
@@ -9809,6 +10143,13 @@ sub get_dns {
my @uniq = grep(!$seen{$_}++, values(%hostdom));
return @uniq;
}
+
+ sub internet_dom {
+ &load_hosts_tab() if (!$loaded);
+
+ my ($lonid) = @_;
+ return $internetdom{$lonid};
+ }
}
{
@@ -9926,6 +10267,40 @@ sub get_dns {
return undef;
}
+ sub get_internet_names {
+ my ($lonid) = @_;
+ return if ($lonid eq '');
+ my ($idnref,$cached)=
+ &Apache::lonnet::is_cached_new('internetnames',$lonid);
+ if ($cached) {
+ return $idnref;
+ }
+ my $ip = &get_host_ip($lonid);
+ my @hosts = &get_hosts_from_ip($ip);
+ my %iphost = &get_iphost();
+ my (@idns,%seen);
+ foreach my $id (@hosts) {
+ my $dom = &host_domain($id);
+ my $prim_id = &domain($dom,'primary');
+ my $prim_ip = &get_host_ip($prim_id);
+ next if ($seen{$prim_ip});
+ if (ref($iphost{$prim_ip}) eq 'ARRAY') {
+ foreach my $id (@{$iphost{$prim_ip}}) {
+ my $intdom = &internet_dom($id);
+ unless (grep(/^\Q$intdom\E$/,@idns)) {
+ push(@idns,$intdom);
+ }
+ }
+ }
+ $seen{$prim_ip} = 1;
+ }
+ return &Apache::lonnet::do_cache_new('internetnames',$lonid,\@idns,12*60*60);
+ }
+
+}
+
+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);
}
BEGIN {
@@ -10003,6 +10378,53 @@ BEGIN {
close($config);
}
+# ---------------------------------------------------------- Read loncaparev table
+{
+ if (-e "$perlvar{'lonTabDir'}/loncaparevs.tab") {
+ if (open(my $config,"<$perlvar{'lonTabDir'}/loncaparevs.tab")) {
+ while (my $configline=<$config>) {
+ chomp($configline);
+ my ($hostid,$loncaparev)=split(/:/,$configline);
+ $loncaparevs{$hostid}=$loncaparev;
+ }
+ close($config);
+ }
+ }
+}
+
+# ---------------------------------------------------------- Read serverhostID table
+{
+ if (-e "$perlvar{'lonTabDir'}/serverhomeIDs.tab") {
+ if (open(my $config,"<$perlvar{'lonTabDir'}/serverhomeIDs.tab")) {
+ while (my $configline=<$config>) {
+ chomp($configline);
+ my ($name,$id)=split(/:/,$configline);
+ $serverhomeIDs{$name}=$id;
+ }
+ close($config);
+ }
+ }
+}
+
+{
+ 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/';
@@ -10233,9 +10655,14 @@ authentication scheme
=item *
X
-B: try to
+B: try to
authenticate user from domain's lib servers (first use the current
one). C<$upass> should be the users password.
+$checkdefauth is optional (value is 1 if a check should be made to
+ authenticate user using default authentication method, and allow
+ account creation if username does not have account in the domain).
+$clientcancheckhost is optional (value is 1 if checking whether the
+ server can host will occur on the client side in lonauth.pm).
=item *
X
@@ -10984,8 +11411,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"
@@ -11007,16 +11436,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 *