--- loncom/lonnet/perl/lonnet.pm 2000/11/14 18:41:40 1.63
+++ loncom/lonnet/perl/lonnet.pm 2000/11/27 20:44:04 1.71
@@ -52,6 +52,15 @@
# from the directory dir
# hreflocation(dir,file) : same as filelocation, but for hrefs
# log(domain,user,home,msg) : write to permanent log for user
+# usection(domain,user,courseid) : output of section name/number or '' for
+# "not in course" and '-1' for "no section"
+# userenvironment(domain,user,what) : puts out any environment parameter
+# for a user
+# idput(domain,hash) : writes IDs for users from hash (name=>id,name=>id)
+# idget(domain,array): returns hash with usernames (id=>name,id=>name) for
+# an array of IDs
+# idrget(domain,array): returns hash with IDs for usernames (name=>id,...) for
+# an array of names
#
# 6/1/99,6/2,6/10,6/11,6/12,6/14,6/26,6/28,6/29,6/30,
# 7/1,7/2,7/9,7/10,7/12,7/14,7/15,7/19,
@@ -67,7 +76,8 @@
# 10/04 Gerd Kortemeyer
# 10/04 Guy Albertelli
# 10/06,10/09,10/10,10/11,10/14,10/20,10/23,10/25,10/26,10/27,10/28,10/29,
-# 10/30,10/31,11/2,11/14 Gerd Kortemeyer
+# 10/30,10/31,
+# 11/2,11/14,11/15,11/16,11/20,11/21,11/22,11/25,11/27 Gerd Kortemeyer
package Apache::lonnet;
@@ -76,10 +86,11 @@ use Apache::File;
use LWP::UserAgent();
use HTTP::Headers;
use vars
-qw(%perlvar %hostname %homecache %spareid %hostdom %libserv %pr %prp %fe %fd $readit);
+qw(%perlvar %hostname %homecache %spareid %hostdom %libserv %pr %prp %fe %fd $readit %metacache);
use IO::Socket;
use GDBM_File;
use Apache::Constants qw(:common :http);
+use HTML::TokeParser;
# --------------------------------------------------------------------- Logging
@@ -122,8 +133,7 @@ sub reply {
my ($cmd,$server)=@_;
my $answer=subreply($cmd,$server);
if ($answer eq 'con_lost') { $answer=subreply($cmd,$server); }
- if (($answer=~/^error:/) || ($answer=~/^refused/) ||
- ($answer=~/^rejected/)) {
+ if (($answer=~/^refused/) || ($answer=~/^rejected/)) {
&logthis("WARNING:".
" $cmd to $server returned $answer");
}
@@ -357,6 +367,111 @@ sub homeserver {
return 'no_host';
}
+# ------------------------------------- Find the usernames behind a list of IDs
+
+sub idget {
+ my ($udom,@ids)=@_;
+ my %returnhash=();
+
+ my $tryserver;
+ foreach $tryserver (keys %libserv) {
+ if ($hostdom{$tryserver} eq $udom) {
+ my $idlist=join('&',@ids);
+ $idlist=~tr/A-Z/a-z/;
+ my $reply=&reply("idget:$udom:".$idlist,$tryserver);
+ my @answer=();
+ if ($reply ne 'con_lost') {
+ @answer=split(/\&/,$reply);
+ } ;
+ my $i;
+ for ($i=0;$i<=$#ids;$i++) {
+ if ($answer[$i]) {
+ $returnhash{$ids[$i]}=$answer[$i];
+ }
+ }
+ }
+ }
+ return %returnhash;
+}
+
+# ------------------------------------- Find the IDs behind a list of usernames
+
+sub idrget {
+ my ($udom,@unames)=@_;
+ my %returnhash=();
+ map {
+ $returnhash{$_}=(&userenvironment($udom,$_,'id'))[1];
+ } @unames;
+ return %returnhash;
+}
+
+# ------------------------------- Store away a list of names and associated IDs
+
+sub idput {
+ my ($udom,%ids)=@_;
+ my %servers=();
+ map {
+ my $uhom=&homeserver($_,$udom);
+ if ($uhom ne 'no_host') {
+ my $id=&escape($ids{$_});
+ $id=~tr/A-Z/a-z/;
+ my $unam=&escape($_);
+ if ($servers{$uhom}) {
+ $servers{$uhom}.='&'.$id.'='.$unam;
+ } else {
+ $servers{$uhom}=$id.'='.$unam;
+ }
+ &critical('put:'.$udom.':'.$unam.':environment:id='.$id,$uhom);
+ }
+ } keys %ids;
+ map {
+ &critical('idput:'.$udom.':'.$servers{$_},$_);
+ } keys %servers;
+}
+
+# ------------------------------------- Find the section of student in a course
+
+sub usection {
+ my ($udom,$unam,$courseid)=@_;
+ $courseid=~s/\_/\//g;
+ $courseid=~s/^(\w)/\/$1/;
+ map {
+ my ($key,$value)=split(/\=/,$_);
+ $key=&unescape($key);
+ if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) {
+ my $section=$1;
+ if ($key eq $courseid.'_st') { $section=''; }
+ my ($dummy,$end,$start)=split(/\_/,&unescape($value));
+ my $now=time;
+ my $notactive=0;
+ if ($start) {
+ if ($now<$start) { $notactive=1; }
+ }
+ if ($end) {
+ if ($now>$end) { $notactive=1; }
+ }
+ unless ($notactive) { return $section; }
+ }
+ } split(/\&/,&reply('dump:'.$udom.':'.$unam.':roles',
+ &homeserver($unam,$udom)));
+ return '-1';
+}
+
+# ------------------------------------- Read an entry from a user's environment
+
+sub userenvironment {
+ my ($udom,$unam,@what)=@_;
+ my %returnhash=();
+ my @answer=split(/\&/,
+ &reply('get:'.$udom.':'.$unam.':environment:'.join('&',@what),
+ &homeserver($unam,$udom)));
+ my $i;
+ for ($i=0;$i<=$#what;$i++) {
+ $returnhash{$what[$i]}=&unescape($answer[$i]);
+ }
+ return %returnhash;
+}
+
# ----------------------------- Subscribe to a resource, return URL if possible
sub subscribe {
@@ -369,6 +484,9 @@ sub subscribe {
return 'not_found';
}
my $answer=reply("sub:$fname",$home);
+ if (($answer eq 'con_lost') || ($answer eq 'rejected')) {
+ $answer.=' by '.$home;
+ }
return $answer;
}
@@ -380,14 +498,14 @@ sub repcopy {
my $transname="$filename.in.transfer";
if ((-e $filename) || (-e $transname)) { return OK; }
my $remoteurl=subscribe($filename);
- if ($remoteurl eq 'con_lost') {
- &logthis("Subscribe returned con_lost: $filename");
+ if ($remoteurl =~ /^con_lost by/) {
+ &logthis("Subscribe returned $remoteurl: $filename");
return HTTP_SERVICE_UNAVAILABLE;
} elsif ($remoteurl eq 'not_found') {
&logthis("Subscribe returned not_found: $filename");
return HTTP_NOT_FOUND;
- } elsif ($remoteurl eq 'rejected') {
- &logthis("Subscribe returned rejected: $filename");
+ } elsif ($remoteurl =~ /^rejected by/) {
+ &logthis("Subscribe returned $remoteurl: $filename");
return FORBIDDEN;
} elsif ($remoteurl eq 'directory') {
return OK;
@@ -774,8 +892,9 @@ sub allowed {
}
# Course: uri itself is a course
-
- if ($ENV{'user.priv.'.$ENV{'request.role'}.'./'.$uri}
+ my $courseuri=$uri;
+ $courseuri=~s/\_(\d)/\/$1/;
+ if ($ENV{'user.priv.'.$ENV{'request.role'}.'./'.$courseuri}
=~/$priv\&([^\:]*)/) {
$thisallowed.=$1;
}
@@ -1191,6 +1310,7 @@ sub condval {
sub EXT {
my $varname=shift;
+ unless ($varname) { return ''; }
my ($realm,$space,$qualifier,@therest)=split(/\./,$varname);
my $rest;
if ($therest[0]) {
@@ -1255,20 +1375,41 @@ sub EXT {
} elsif ($realm eq 'resource') {
if ($ENV{'request.course.id'}) {
# ----------------------------------------------------- Cascading lookup scheme
- my $reslevel=
- $ENV{'request.course.id'}.'.'.&symbread().'.'.$spacequalifierrest;
+ my $symbp=&symbread();
+ my $mapp=(split(/\_\_\_/,$symbp))[0];
+
+ my $symbparm=$symbp.'.'.$spacequalifierrest;
+ my $mapparm=$mapp.'___(all).'.$spacequalifierrest;
+
my $seclevel=
- $ENV{'request.course.id'}.'.'.
- $ENV{'request.course.sec'}.'.'.$spacequalifierrest;
+ $ENV{'request.course.id'}.'.['.
+ $ENV{'request.course.sec'}.'].'.$spacequalifierrest;
+ my $seclevelr=
+ $ENV{'request.course.id'}.'.['.
+ $ENV{'request.course.sec'}.'].'.$symbparm;
+ my $seclevelm=
+ $ENV{'request.course.id'}.'.['.
+ $ENV{'request.course.sec'}.'].'.$mapparm;
+
my $courselevel=
$ENV{'request.course.id'}.'.'.$spacequalifierrest;
+ my $courselevelr=
+ $ENV{'request.course.id'}.'.'.$symbparm;
+ my $courselevelm=
+ $ENV{'request.course.id'}.'.'.$mapparm;
+
# ----------------------------------------------------------- first, check user
- my %resourcedata=get('resourcedata',($reslevel,$seclevel,$courselevel));
- if ($resourcedata{$reslevel}!~/^error\:/) {
- if ($resourcedata{$reslevel}) { return $resourcedata{$reslevel}; }
- if ($resourcedata{$seclevel}) { return $resourcedata{$seclevel}; }
+ my %resourcedata=get('resourcedata',
+ ($courselevelr,$courselevelm,$courselevel));
+ if ($resourcedata{$courselevelr}!~/^error\:/) {
+
+ if ($resourcedata{$courselevelr}) {
+ return $resourcedata{$courselevelr}; }
+ if ($resourcedata{$courselevelm}) {
+ return $resourcedata{$courselevelm}; }
if ($resourcedata{$courselevel}) { return $resourcedata{$courselevel}; }
+
}
# -------------------------------------------------------- second, check course
my $section='';
@@ -1279,39 +1420,43 @@ sub EXT {
$ENV{'course.'.$ENV{'request.course.id'}.$section.'.domain'}.':'.
$ENV{'course.'.$ENV{'request.course.id'}.$section.'.num'}.
':resourcedata:'.
- escape($reslevel).':'.escape($seclevel).':'.escape($courselevel),
+ escape($seclevelr).':'.escape($seclevelm).':'.escape($seclevel).':'.
+ escape($courselevelr).':'.escape($courselevelm).':'.escape($courselevel),
$ENV{'course.'.$ENV{'request.course.id'}.$section.'.home'});
if ($reply!~/^error\:/) {
map {
my ($name,$value)=split(/\=/,$_);
$resourcedata{unescape($name)}=unescape($value);
} split(/\&/,$reply);
- if ($resourcedata{$reslevel}) { return $resourcedata{$reslevel}; }
- if ($resourcedata{$seclevel}) { return $resourcedata{$seclevel}; }
+
+ if ($resourcedata{$seclevelr}) { return $resourcedata{$seclevelr}; }
+ if ($resourcedata{$seclevelm}) { return $resourcedata{$seclevelm}; }
+ if ($resourcedata{$seclevel}) { return $resourcedata{$seclevel}; }
+
+ if ($resourcedata{$courselevelr}) {
+ return $resourcedata{$courselevelr}; }
+ if ($resourcedata{$courselevelm}) {
+ return $resourcedata{$courselevelm}; }
if ($resourcedata{$courselevel}) { return $resourcedata{$courselevel}; }
+
}
# ------------------------------------------------------ third, check map parms
-
- if ($ENV{'resource.parms.'.$reslevel}) {
- return $ENV{'resource.parms.'.$reslevel};
+ my %parmhash=();
+ my $thisparm='';
+ if (tie(%parmhash,'GDBM_File',
+ $ENV{'request.course.fn'}.'_parms.db',&GDBM_READER,0640)) {
+ $thisparm=$parmhash{$symbparm};
+ untie(%parmhash);
}
+ if ($thisparm) { return $thisparm; }
}
# --------------------------------------------- last, look in resource metadata
- my $uri=&declutter($ENV{'request.filename'});
- my $filename=$perlvar{'lonDocRoot'}.'/res/'.$ENV.'.meta';
- if (-e $filename) {
- my @content;
- {
- my $fh=Apache::File->new($filename);
- @content=<$fh>;
- }
- if (join('',@content)=~
- /\<$space[^\>]*\>([^\<]*)\<\/$space\>/) {
- return $1;
- }
- }
+
+ my $metadata=&metadata($ENV{'request.filename'},$spacequalifierrest);
+ if ($metadata) { return $metadata; }
+
# ---------------------------------------------------- Any other user namespace
} elsif ($realm eq 'environment') {
# ----------------------------------------------------------------- environment
@@ -1325,19 +1470,39 @@ sub EXT {
return '';
}
-# ---------------------------------------- Append resource parms to environment
+# ---------------------------------------------------------------- Get metadata
-sub appendparms {
- my ($symb,$parms)=@_;
- my %storehash=();
- my $prefix='resource.parms.'.$ENV{'request.course.id'}.'.'.$symb;
- map {
- my ($typename,$value)=split(/\=/,$_);
- my ($type,$name)=split(/\:/,$typename);
- $storehash{$prefix.'.'.unescape($name)}=unescape($value);
- $storehash{$prefix.'.'.unescape($name).'.type'}=unescape($type);
- } split(/\&/,$parms);
- &appenv(%storehash);
+sub metadata {
+ my ($uri,$what)=@_;
+ $uri=&declutter($uri);
+ unless ($uri=~/\.meta$/) { $uri.='.meta'; }
+ unless ($metacache{$uri.':keys'}) {
+ my $metastring=&getfile($perlvar{'lonDocRoot'}.'/res/'.$uri);
+ my $parser=HTML::TokeParser->new(\$metastring);
+ my $token;
+ while ($token=$parser->get_token) {
+ if ($token->[0] eq 'S') {
+ my $entry=$token->[1];
+ my $unikey=$entry;
+ if ($token->[2]->{'part'}) {
+ $unikey.='_'.$token->[2]->{'part'};
+ }
+ if ($token->[2]->{'name'}) {
+ $unikey.='_'.$token->[2]->{'name'};
+ }
+ if ($metacache{$uri.':keys'}) {
+ $metacache{$uri.':keys'}.=','.$unikey;
+ } else {
+ $metacache{$uri.':keys'}=$unikey;
+ }
+ map {
+ $metacache{$uri.':'.$unikey.'.'.$_}=$token->[2]->{$_};
+ } $token->[3];
+ $metacache{$uri.':'.$unikey}=$parser->get_text('/'.$entry);
+ }
+ }
+ }
+ return $metacache{$uri.':'.$what};
}
# ------------------------------------------------- Update symbolic store links
@@ -1371,7 +1536,6 @@ sub symbread {
my %hash;
my %bighash;
my $syval='';
- my $parms='';
if (($ENV{'request.course.fn'}) && ($thisfn)) {
if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db',
&GDBM_READER,0640)) {
@@ -1393,13 +1557,15 @@ sub symbread {
&GDBM_READER,0640)) {
# ---------------------------------------------- Get ID(s) for current resource
my $ids=$bighash{'ids_/res/'.$thisfn};
+ unless ($ids) {
+ $ids=$bighash{'ids_/'.$thisfn};
+ }
if ($ids) {
# ------------------------------------------------------------------- Has ID(s)
my @possibilities=split(/\,/,$ids);
if ($#possibilities==0) {
# ----------------------------------------------- There is only one possibility
my ($mapid,$resid)=split(/\./,$ids);
- $parms=$bighash{'param_'.$ids};
$syval=declutter($bighash{'map_id_'.$mapid}).'___'.$resid;
} else {
# ------------------------------------------ There is more than one possibility
@@ -1410,7 +1576,6 @@ sub symbread {
my ($mapid,$resid)=split(/\./,$_);
if ($bighash{'map_type_'.$mapid} ne 'page') {
$realpossible++;
- $parms=$bighash{'param_'.$_};
$syval=declutter($bighash{'map_id_'.$mapid}).
'___'.$resid;
}
@@ -1423,9 +1588,6 @@ sub symbread {
}
}
if ($syval) {
- if ($parms) {
- &appendparms($syval.'___'.$thisfn,$parms);
- }
return $syval.'___'.$thisfn;
}
}
@@ -1608,6 +1770,7 @@ if ($readit ne 'done') {
}
}
+%metacache=();
$readit='done';
&logthis('INFO: Read configuration');