--- loncom/lonnet/perl/lonnet.pm	2002/12/06 16:34:55	1.311
+++ loncom/lonnet/perl/lonnet.pm	2003/02/13 21:35:50	1.327
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.311 2002/12/06 16:34:55 matthew Exp $
+# $Id: lonnet.pm,v 1.327 2003/02/13 21:35:50 albertel Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -47,23 +47,18 @@
 # 09/01 Guy Albertelli
 # 09/01,10/01,11/01 Gerd Kortemeyer
 # YEAR=2001
-# 02/27/01 Scott Harrison
 # 3/2 Gerd Kortemeyer
-# 3/15,3/19 Scott Harrison
 # 3/19,3/20 Gerd Kortemeyer
-# 3/22,3/27,4/2,4/16,4/17 Scott Harrison
 # 5/26,5/28 Gerd Kortemeyer
 # 5/30 H. K. Ng
 # 6/1 Gerd Kortemeyer
 # July Guy Albertelli
 # 8/4,8/7,8/8,8/9,8/11,8/16,8/17,8/18,8/20,8/23,9/20,9/21,9/26,
 # 10/2 Gerd Kortemeyer
-# 10/5,10/10,11/13,11/15 Scott Harrison
 # 11/17,11/20,11/22,11/29 Gerd Kortemeyer
 # 12/5 Matthew Hall
 # 12/5 Guy Albertelli
 # 12/6,12/7,12/12 Gerd Kortemeyer
-# 12/18 Scott Harrison
 # 12/21,12/22,12/27,12/28 Gerd Kortemeyer
 # YEAR=2002
 # 1/4,2/4,2/7 Gerd Kortemeyer
@@ -81,7 +76,7 @@ qw(%perlvar %hostname %homecache %badSer
    %libserv %pr %prp %metacache %packagetab %titlecache 
    %courselogs %accesshash $processmarker $dumpcount 
    %coursedombuf %coursehombuf %courseresdatacache 
-   %domaindescription);
+   %domaindescription %domain_auth_def %domain_auth_arg_def);
 use IO::Socket;
 use GDBM_File;
 use Apache::Constants qw(:common :http);
@@ -729,6 +724,7 @@ sub currentversion {
 
 sub subscribe {
     my $fname=shift;
+    if ($fname=~/\/(aboutme|syllabus|bulletinboard|smppg)$/) { return ''; }
     my $author=$fname;
     $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;
     my ($udom,$uname)=split(/\//,$author);
@@ -831,6 +827,14 @@ sub ssi {
     return $response->content;
 }
 
+sub externalssi {
+    my ($url)=@_;
+    my $ua=new LWP::UserAgent;
+    my $request=new HTTP::Request('GET',$url);
+    my $response=$ua->request($request);
+    return $response->content;
+}
+
 # ------- Add a token to a remote URI's query string to vouch for access rights
 
 sub tokenwrapper {
@@ -856,8 +860,15 @@ sub tokenwrapper {
 sub userfileupload {
     my ($formname,$coursedoc)=@_;
     my $fname=$ENV{'form.'.$formname.'.filename'};
+# Replace Windows backslashes by forward slashes
     $fname=~s/\\/\//g;
+# Get rid of everything but the actual filename
     $fname=~s/^.*\/([^\/]+)$/$1/;
+# Replace spaces by underscores
+    $fname=~s/\s+/\_/g;
+# Replace all other weird characters by nothing
+    $fname=~s/[^\w\.\-]//g;
+# See if there is anything left
     unless ($fname) { return 'error: no uploaded file'; }
     chop($ENV{'form.'.$formname});
 # Create the directory if not present
@@ -1101,10 +1112,14 @@ sub expirespread {
 # ----------------------------------------------------- Devalidate Spreadsheets
 
 sub devalidate {
-    my $symb=shift;
+    my ($symb,$uname,$udom)=@_;
     my $cid=$ENV{'request.course.id'}; 
     if ($cid) {
-	my $key=$ENV{'user.name'}.':'.$ENV{'user.domain'}.':';
+# delete the stored spreadsheets for
+# - the student level sheet of this user in course's homespace
+# - the assessment level sheet for this resource 
+#   for this user in user's homespace
+	my $key=$uname.':'.$udom.':';
         my $status=
 	    &del('nohist_calculatedsheets',
 		 [$key.'studentcalc'],
@@ -1115,7 +1130,7 @@ sub devalidate {
 		 [$key.'assesscalc:'.$symb]);
         unless ($status eq 'ok ok') {
            &logthis('Could not devalidate spreadsheet '.
-                    $ENV{'user.name'}.' at '.$ENV{'user.domain'}.' for '.
+                    $uname.' at '.$udom.' for '.
 		    $symb.': '.$status);
         }
     }
@@ -1447,7 +1462,10 @@ sub store {
     $symb=&symbclean($symb);
     if (!$symb) { unless ($symb=&symbread()) { return ''; } }
 
-    &devalidate($symb);
+    if (!$domain) { $domain=$ENV{'user.domain'}; }
+    if (!$stuname) { $stuname=$ENV{'user.name'}; }
+
+    &devalidate($symb,$stuname,$domain);
 
     $symb=escape($symb);
     if (!$namespace) { 
@@ -1455,8 +1473,6 @@ sub store {
           return ''; 
        } 
     }
-    if (!$domain) { $domain=$ENV{'user.domain'}; }
-    if (!$stuname) { $stuname=$ENV{'user.name'}; }
     if (!$home) { $home=$ENV{'user.home'}; }
     my $namevalue='';
     foreach (keys %$storehash) {
@@ -1478,7 +1494,10 @@ sub cstore {
     $symb=&symbclean($symb);
     if (!$symb) { unless ($symb=&symbread()) { return ''; } }
 
-    &devalidate($symb);
+    if (!$domain) { $domain=$ENV{'user.domain'}; }
+    if (!$stuname) { $stuname=$ENV{'user.name'}; }
+
+    &devalidate($symb,$stuname,$domain);
 
     $symb=escape($symb);
     if (!$namespace) { 
@@ -1486,8 +1505,6 @@ sub cstore {
           return ''; 
        } 
     }
-    if (!$domain) { $domain=$ENV{'user.domain'}; }
-    if (!$stuname) { $stuname=$ENV{'user.name'}; }
     if (!$home) { $home=$ENV{'user.home'}; }
 
     my $namevalue='';
@@ -1736,6 +1753,58 @@ sub dump {
    return %returnhash;
 }
 
+# --------------------------------------------------------------- currentdump
+sub currentdump {
+   my ($sname,$sdom,$courseid)=@_;
+   $courseid = $ENV{'request.course.id'} if (! defined($courseid));
+   $sdom     = $ENV{'user.domain'}       if (! defined($sdom));
+   $sname    = $ENV{'user.name'}         if (! defined($sname));
+   my $uhome = &homeserver($sname,$sdom);
+   my $rep=reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome);
+   return if ($rep =~ /^(error:|no_such_host)/);
+   #
+   my %returnhash=();
+   #
+   if ($rep eq "unknown_cmd") { 
+       # an old lond will not know currentdump
+       # Do a dump and make it look like a currentdump
+       my @tmp = &dump($courseid,$sdom,$sname,'.');
+       return if ($tmp[0] =~ /^(error:|no_such_host)/);
+       my %hash = @tmp;
+       @tmp=();
+       # Code ripped from lond, essentially.  The only difference
+       # here is the unescaping done by lonnet::dump().  Conceivably
+       # we might run in to problems with parameter names =~ /^v\./
+       while (my ($key,$value) = each(%hash)) {
+           my ($v,$symb,$param) = split(/:/,$key);
+           next if ($v eq 'version' || $symb eq 'keys');
+           next if (exists($returnhash{$symb}) &&
+                    exists($returnhash{$symb}->{$param}) &&
+                    $returnhash{$symb}->{'v.'.$param} > $v);
+           $returnhash{$symb}->{$param}=$value;
+           $returnhash{$symb}->{'v.'.$param}=$v;
+       }
+       #
+       # Remove all of the keys in the hashes which keep track of
+       # the version of the parameter.
+       while (my ($symb,$param_hash) = each(%returnhash)) {
+           # use a foreach because we are going to delete from the hash.
+           foreach my $key (keys(%$param_hash)) {
+               delete($param_hash->{$key}) if ($key =~ /^v\./);
+           }
+       }
+   } else {
+       my @pairs=split(/\&/,$rep);
+       foreach (@pairs) {
+           my ($key,$value)=split(/=/,$_);
+           my ($symb,$param) = split(/:/,$key);
+           $returnhash{&unescape($symb)}->{&unescape($param)} = 
+                                                          &unescape($value);
+       }
+   }
+   return %returnhash;
+}
+
 # --------------------------------------------------------------- put interface
 
 sub put {
@@ -1863,6 +1932,12 @@ sub allowed {
        $thisallowed.=$1;
     }
 
+# URI is an uploaded document for this course
+
+    if (($priv eq 'bre') && 
+        ($uri=~/^uploaded\/$ENV{'course.'.$ENV{'request.course.id'}.'.domain'}\/$ENV{'course.'.$ENV{'request.course.id'}.'.num'}/)) {
+        return 'F';
+    }
 # Full access at system, domain or course-wide level? Exit.
 
     if ($thisallowed=~/F/) {
@@ -2349,10 +2424,15 @@ sub modifyuser {
        }
     }
 # -------------------------------------------------------------- Add names, etc
-    my %names=&get('environment',
+    my @tmp=&get('environment',
 		   ['firstname','middlename','lastname','generation'],
 		   $udom,$uname);
-    if ($names{'firstname'} =~ m/^error:.*/) { %names=(); }
+    my %names;
+    if ($tmp[0] =~ m/^error:.*/) { 
+        %names=(); 
+    } else {
+        %names = @tmp;
+    }
     if ($first)  { $names{'firstname'}  = $first; }
     if ($middle) { $names{'middlename'} = $middle; }
     if ($last)   { $names{'lastname'}   = $last; }
@@ -2747,14 +2827,14 @@ sub EXT {
     } else {
 	$courseid=$ENV{'request.course.id'};
     }
-
     my ($realm,$space,$qualifier,@therest)=split(/\./,$varname);
     my $rest;
-    if ($therest[0]) {
+    if (defined($therest[0])) {
        $rest=join('.',@therest);
     } else {
        $rest='';
     }
+
     my $qualifierrest=$qualifier;
     if ($rest) { $qualifierrest.='.'.$rest; }
     my $spacequalifierrest=$space;
@@ -3015,9 +3095,12 @@ sub metadata {
                       my $unikey='parameter'.$keyroot.'_'.$name;
                       $metathesekeys{$unikey}=1;
                       $metacache{$uri.':'.$unikey.'.part'}=$part;
-                      unless 
-                       (defined($metacache{$uri.':'.$unikey.'.'.$subp})) {
-                         $metacache{$uri.':'.$unikey.'.'.$subp}=$value;
+                      unless (defined($metacache{$uri.':'.$unikey.'.'.$subp})) {
+			  $metacache{$uri.':'.$unikey.'.'.$subp}=$value;
+		      }
+		      if (defined($metacache{$uri.':'.$unikey.'.default'})) {
+			  $metacache{$uri.':'.$unikey}=
+			     $metacache{$uri.':'.$unikey.'.default'}
 		      }
                   }
               }
@@ -3067,11 +3150,17 @@ sub metadata {
               foreach (@{$token->[3]}) {
 		  $metacache{$uri.':'.$unikey.'.'.$_}=$token->[2]->{$_};
               }
-              unless (
-                 $metacache{$uri.':'.$unikey}=&HTML::Entities::decode($parser->get_text('/'.$entry))
-		      ) { $metacache{$uri.':'.$unikey}=
-			      $metacache{$uri.':'.$unikey.'.default'};
-		      }
+	      my $internaltext=&HTML::Entities::decode($parser->get_text('/'.$entry));
+	      my $default=$metacache{$uri.':'.$unikey.'.default'};
+	      if ( $internaltext =~ /^\s*$/ && $default !~ /^\s*$/) {
+		  # only ws inside the tag, and not in default, so use default
+                  # as value
+		  $metacache{$uri.':'.$unikey}=$default;
+	      } else {
+		  # either something interesting inside the tag or default
+                  # uninteresting
+		  $metacache{$uri.':'.$unikey}=$internaltext;
+	      }
 # end of not-a-package not-a-library import
 	   }
 # end of not-a-package start tag
@@ -3484,6 +3573,29 @@ BEGIN {
     }
 }
 
+# ------------------------------------------------------------ Read domain file
+{
+    my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
+                            '/domain.tab');
+    %domaindescription = ();
+    %domain_auth_def = ();
+    %domain_auth_arg_def = ();
+    if ($fh) {
+       while (<$fh>) {
+           next if /^\#/;
+           chomp;
+           my ($domain, $domain_description, $def_auth, $def_auth_arg)
+               = split(/:/,$_,4);
+           $domain_auth_def{$domain}=$def_auth;
+           $domain_auth_arg_def{$domain}=$def_auth_arg;
+           $domaindescription{$domain}=$domain_description;
+#          &logthis("Domain.tab: $domain, $domain_auth_def{$domain}, $domain_auth_arg_def{$domain},$domaindescription{$domain}");
+#          &logthis("Domain.tab: $domain ".$domaindescription{$domain} );
+       }
+    }
+}
+
+
 # ------------------------------------------------------------- Read hosts file
 {
     my $config=Apache::File->new("$perlvar{'lonTabDir'}/hosts.tab");
@@ -3497,7 +3609,6 @@ BEGIN {
 	 $hostdom{$id}=$domain;
 	 $hostip{$id}=$ip;
 	 $iphost{$ip}=$id;
-	 if ($domdescr) { $domaindescription{$domain}=$domdescr; }
 	 if ($role eq 'library') { $libserv{$id}=$name; }
        } else {
 	 if ($configline) {