--- loncom/lonnet/perl/lonnet.pm	2000/08/22 15:27:35	1.24
+++ loncom/lonnet/perl/lonnet.pm	2000/09/26 20:07:24	1.32
@@ -4,7 +4,14 @@
 # Functions for use by content handlers:
 #
 # plaintext(short)   : plain text explanation of short term
-# allowed(short,url) : returns codes for allowed actions F,R,S,C
+# fileembstyle(ext)  : embed style in page for file extension
+# filedescription(ext) : descriptor text for file extension
+# allowed(short,url) : returns codes for allowed actions 
+#                      F: full access
+#                      U,I,K: authentication modes (cxx only)
+#                      '': forbidden
+#                      1: user needs to choose course
+#                      2: browse allowed
 # definerole(rolename,sys,dom,cou) : define a custom role rolename
 #                      set priviledges in format of lonTabs/roles.tab for
 #                      system, domain and course level, 
@@ -21,12 +28,18 @@
 # restore            : returns hash for this url
 # eget(namesp,array) : returns hash with keys from array filled in from namesp
 # get(namesp,array)  : returns hash with keys from array filled in from namesp
+# del(namesp,array)  : deletes keys out of arry from namesp
 # put(namesp,hash)   : stores hash in namesp
 # dump(namesp)       : dumps the complete namespace into a hash
 # ssi(url,hash)      : does a complete request cycle on url to localhost, posts
 #                      hash
 # repcopy(filename)  : replicate file
 # dirlist(url)       : gets a directory listing
+# condval(index)     : value of condition index based on state
+# varval(name)       : value of a variable
+# refreshstate()     : refresh the state information string
+# symblist(map,hash) : Updates symbolic storage links
+# rndseed()          : returns a random seed  
 #
 # 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,
@@ -38,7 +51,7 @@
 # 06/26 Ben Tyszka
 # 06/30,07/15,07/17,07/18,07/20,07/21,07/22,07/25 Gerd Kortemeyer
 # 08/14 Ben Tyszka
-# 08/22 Gerd Kortemeyer
+# 08/22,08/28,08/31,09/01,09/02,09/04,09/05,09/25 Gerd Kortemeyer
 
 package Apache::lonnet;
 
@@ -47,8 +60,9 @@ use Apache::File;
 use LWP::UserAgent();
 use HTTP::Headers;
 use vars 
-qw(%perlvar %hostname %homecache %spareid %hostdom %libserv %pr %prp $readit);
+qw(%perlvar %hostname %homecache %spareid %hostdom %libserv %pr %prp %fe %fd $readit);
 use IO::Socket;
+use GDBM_File;
 use Apache::Constants qw(:common :http);
 
 # --------------------------------------------------------------------- Logging
@@ -395,28 +409,45 @@ sub log {
 # ----------------------------------------------------------------------- Store
 
 sub store {
-    my %storehash=shift;
+    my %storehash=@_;
+    my $symb;
+    unless ($symb=escape(&symbread())) { return ''; }
+    my $namespace;
+    unless ($namespace=$ENV{'request.course.uri'}) { return ''; }
+    $namespace=~s/\//\_\_/g;
+    $namespace=~s/\./\_/g;
+    $namespace=escape($namespace);
     my $namevalue='';
     map {
         $namevalue.=escape($_).'='.escape($storehash{$_}).'&';
     } keys %storehash;
     $namevalue=~s/\&$//;
-    return reply("store:$ENV{'user.domain'}:$ENV{'user.name'}:"
-               ."$ENV{'user.class'}:$ENV{'request.filename'}:$namevalue",
+    return reply(
+     "store:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$symb:$namevalue",
 		 "$ENV{'user.home'}");
 }
 
 # --------------------------------------------------------------------- Restore
 
 sub restore {
-    my $answer=reply("restore:$ENV{'user.domain'}:$ENV{'user.name'}:"
-               ."$ENV{'user.class'}:$ENV{'request.filename'}",
-                "$ENV{'user.home'}");
+    my $symb;
+    unless ($symb=escape(&symbread())) { return ''; }
+    my $namespace;
+    unless ($namespace=$ENV{'request.course.uri'}) { return ''; }
+    $namespace=~s/\//\_\_/g;
+    $namespace=~s/\./\_/g;
+    $namespace=escape($namespace);
+    my $answer=reply(
+              "restore:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$symb",
+              "$ENV{'user.home'}");
     my %returnhash=();
     map {
 	my ($name,$value)=split(/\=/,$_);
         $returnhash{&unescape($name)}=&unescape($value);
     } split(/\&/,$answer);
+    map {
+        $returnhash{$_}=$returnhash{$returnhash{'version'}.':'.$_};
+    } split(/\:/,$returnhash{$returnhash{'version'}.':keys'});
     return %returnhash;
 }
 
@@ -520,11 +551,24 @@ sub get {
    my %returnhash=();
    map {
       my ($key,$value)=split(/=/,$_);
-      $returnhash{unespace($key)}=unescape($value);
+      $returnhash{unescape($key)}=unescape($value);
    } @pairs;
    return %returnhash;
 }
 
+# --------------------------------------------------------------- del interface
+
+sub del {
+   my ($namespace,@storearr)=@_;
+   my $items='';
+   map {
+       $items.=escape($_).'&';
+   } @storearr;
+   $items=~s/\&$//;
+   return reply("del:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$items",
+                 $ENV{'user.home'});
+}
+
 # -------------------------------------------------------------- dump interface
 
 sub dump {
@@ -535,7 +579,7 @@ sub dump {
    my %returnhash=();
    map {
       my ($key,$value)=split(/=/,$_);
-      $returnhash{unespace($key)}=unescape($value);
+      $returnhash{unescape($key)}=unescape($value);
    } @pairs;
    return %returnhash;
 }
@@ -568,7 +612,7 @@ sub eget {
    my %returnhash=();
    map {
       my ($key,$value)=split(/=/,$_);
-      $returnhash{unespace($key)}=unescape($value);
+      $returnhash{unescape($key)}=unescape($value);
    } @pairs;
    return %returnhash;
 }
@@ -579,9 +623,15 @@ sub allowed {
     my ($priv,$uri)=@_;
     $uri=~s/^\/res//;
     $uri=~s/^\///;
-    if ($uri=~/^adm\//) {
+
+# Free bre access to adm resources
+
+    if (($uri=~/^adm\//) && ($priv eq 'bre')) {
 	return 'F';
     }
+
+# Gather priviledges over system and domain
+
     my $thisallowed='';
     if ($ENV{'user.priv./'}=~/$priv\&([^\:]*)/) {
        $thisallowed.=$1;
@@ -589,12 +639,95 @@ sub allowed {
     if ($ENV{'user.priv./'.(split(/\//,$uri))[0].'/'}=~/$priv\&([^\:]*)/) {
        $thisallowed.=$1;
     }
-    if ($ENV{'user.priv./'.$uri}=~/$priv\&([^\:]*)/) {
-       $thisallowed.=$1;
+
+# Full access at system or domain level? Exit.
+
+    if ($thisallowed=~/F/) {
+	return 'F';
+    }
+
+# The user does not have full access at system or domain level
+# Course level access control
+
+# uri itself refering to a course?
+    
+    if ($uri=~/\.course$/) {
+       if ($ENV{'user.priv./'.$uri}=~/$priv\&([^\:]*)/) {
+          $thisallowed.=$1;
+       }
+# Full access on course level? Exit.
+       if ($thisallowed=~/F/) {
+	  return 'F';
+       }
+
+# uri is refering to an individual resource; user needs to be in a course
+
+   } else {
+
+       unless(defined($ENV{'request.course.uri'})) {
+	   return '1';
+       }
+
+# Get access priviledges for course
+
+       if ($ENV{'user.priv./'.$ENV{'request.course.uri'}}=~/$priv\&([^\:]*)/) {
+          $thisallowed.=$1;
+       }
+
+# See if resource or referer is part of this course
+          
+       my @uriparts=split(/\//,$uri);
+       my $urifile=$uriparts[$#uriparts];
+       $urifile=~/\.(\w+)$/;
+       my $uritype=$1;
+       $#uriparts--;
+       my $uripath=join('/',@uriparts);
+       my $uricond=-1;
+       if ($ENV{'acc.res.'.$ENV{'request.course'}.'.'.$uripath}=~
+	   /\&$urifile\:(\d+)\&/) {
+	   $uricond=$1;
+       } elsif (($fe{$uritype} eq 'emb') || ($fe{$uritype} eq 'img')) {
+	  my $refuri=$ENV{'HTTP_REFERER'};
+          $refuri=~s/^\/res//;
+          $refuri=~s/^\///;
+          @uriparts=split(/\//,$refuri);
+          $urifile=$uriparts[$#uriparts];
+          $#uriparts--;
+          $uripath=join('/',@uriparts);
+          if ($ENV{'acc.res.'.$ENV{'request.course'}.'.'.$uripath}=~
+	     /\&$urifile\:(\d+)\&/) {
+	     $uricond=$1;
+	  }
+       }
+
+       if ($uricond>=0) {
+
+# The resource is part of the course
+# If user had full access on course level, go ahead
+
+           if ($thisallowed=~/F/) {
+	       return 'F';
+           }
+
+# Restricted by state?
+
+           if ($thisallowed=~/X/) {
+	      if (&condval($uricond)>1) {
+	         return '2';
+              } else {
+                 return '';
+              }
+	   }
+       }
     }
     return $thisallowed;
 }
 
+# ---------------------------------------------------------- Refresh State Info
+
+sub refreshstate {
+}
+
 # ----------------------------------------------------------------- Define Role
 
 sub definerole {
@@ -644,11 +777,26 @@ sub plaintext {
     return $prp{$short};
 }
 
+# ------------------------------------------------------------------ Plain Text
+
+sub fileembstyle {
+    my $ending=shift;
+    return $fe{$ending};
+}
+
+# ------------------------------------------------------------ Description Text
+
+sub filedecription {
+    my $ending=shift;
+    return $fd{$ending};
+}
+
 # ----------------------------------------------------------------- Assign Role
 
 sub assignrole {
     my ($udom,$uname,$url,$role,$end,$start)=@_;
     my $mrole;
+    $url=declutter($url);
     if ($role =~ /^cr\//) {
         unless ($url=~/\.course$/) { return 'invalid'; }
 	unless (allowed('ccr',$url)) { return 'refused'; }
@@ -745,6 +893,146 @@ sub dirlist {
    }
 }
 
+# -------------------------------------------------------- Value of a Condition
+
+sub condval {
+    my $condidx=shift;
+    my $result=0;
+    if ($ENV{'request.course'}) {
+       if (defined($ENV{'acc.cond.'.$ENV{'request.course'}.'.'.$condidx})) {
+          my $operand='|';
+	  my @stack;
+          map {
+              if ($_ eq '(') {
+                 push @stack,($operand,$result)
+              } elsif ($_ eq ')') {
+                  my $before=pop @stack;
+		  if (pop @stack eq '&') {
+		      $result=$result>$before?$before:$result;
+                  } else {
+                      $result=$result>$before?$result:$before;
+                  }
+              } elsif (($_ eq '&') || ($_ eq '|')) {
+                  $operand=$_;
+              } else {
+                  my $new=
+                       substr($ENV{'user.state.'.$ENV{'request.course'}},$_,1);
+                  if ($operand eq '&') {
+                     $result=$result>$new?$new:$result;
+                  } else {
+                     $result=$result>$new?$result:$new;
+                  }                  
+              }
+          } ($ENV{'acc.cond.'.$ENV{'request.course'}.'.'.$condidx}=~
+             /(\d+|\(|\)|\&|\|)/g);
+       }
+    }
+    return $result;
+}
+
+# --------------------------------------------------------- Value of a Variable
+
+sub varval {
+    my ($realm,$space,@components)=split(/\./,shift);
+    my $value='';
+    if ($realm eq 'user') {
+	if ($space=~/^resource/) {
+	    $space=~s/^resource\[//;
+            $space=~s/\]$//;
+
+        } else {
+        }
+    } elsif ($realm eq 'course') {
+    } elsif ($realm eq 'session') {
+    } elsif ($realm eq 'system') {
+    }
+    return $value;
+}
+
+# ------------------------------------------------- Update symbolic store links
+
+sub symblist {
+    my ($mapname,%newhash)=@_;
+    $mapname=declutter($mapname);
+    my %hash;
+    if (($ENV{'request.course.fn'}) && (%newhash)) {
+        if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db',
+                      &GDBM_WRCREAT,0640)) {
+	    map {
+                $hash{declutter($_)}=$mapname.'___'.$newhash{$_};
+            } keys %newhash;
+            if (untie(%hash)) {
+		return 'ok';
+            }
+        }
+    }
+    return 'error';
+}
+
+# ------------------------------------------------------ Return symb list entry
+
+sub symbread {
+    my %hash;
+    my $syval;
+    if (($ENV{'request.course.fn'}) && ($ENV{'request.filename'})) {
+        if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db',
+                      &GDBM_READER,0640)) {
+            my $thisfn=declutter($ENV{'request.filename'});
+	    $syval=$hash{$thisfn};
+            if (untie(%hash)) {
+                unless ($syval=~/\_\d+$/) {
+		   unless ($ENV{'form.request.prefix'}=~/\.(\d+)\_$/) {
+                      return '';
+                   }    
+                   $syval.=$1;
+	        }
+                $syval.='___'.$thisfn;
+		return $syval;
+            }
+        }
+    }
+    return '';
+}
+
+# ---------------------------------------------------------- Return random seed
+
+sub numval {
+    my $txt=shift;
+    $txt=~tr/A-J/0-9/;
+    $txt=~tr/a-j/0-9/;
+    $txt=~tr/K-T/0-9/;
+    $txt=~tr/k-t/0-9/;
+    $txt=~tr/U-Z/0-5/;
+    $txt=~tr/u-z/0-5/;
+    $txt=~s/\D//g;
+    return int($txt);
+}    
+
+sub rndseed {
+    my $symb;
+    unless ($symb=&symbread()) { return ''; }
+    my $symbchck=unpack("%32C*",$symb);
+    my $symbseed=numval($symb)%$symbchck;
+    my $namechck=unpack("%32C*",$ENV{'user.name'});
+    my $nameseed=numval($ENV{'user.name'})%$namechck;
+    return int( $symbseed
+	       .$nameseed
+               .unpack("%32C*",$ENV{'user.domain'})
+               .unpack("%32C*",$ENV{'request.course.uri'})
+               .$namechck
+               .$symbchck);
+}
+
+# ------------------------------------------------------------- Declutters URLs
+
+sub declutter {
+    my $thisfn=shift;
+    $thisfn=~s/^$perlvar{'lonDocRoot'}//;
+    $thisfn=~s/^\///;
+    $thisfn=~s/^res\///;
+    return $thisfn;
+}
+
 # -------------------------------------------------------- Escape Special Chars
 
 sub escape {
@@ -823,6 +1111,20 @@ if ($readit ne 'done') {
     }
 }
 
+# ------------------------------------------------------------- Read file types
+{
+    my $config=Apache::File->new("$perlvar{'lonTabDir'}/filetypes.tab");
+
+    while (my $configline=<$config>) {
+       chomp($configline);
+       my ($ending,$emb,@descr)=split(/\s+/,$configline);
+       if ($descr[0] ne '') { 
+         $fe{$ending}=$emb;
+         $fd{$ending}=join(' ',@descr);
+       }
+    }
+}
+
 
 $readit='done';
 &logthis('<font color=yellow>INFO: Read configuration</font>');