Diff for /loncom/lonnet/perl/lonnet.pm between versions 1.523.2.8 and 1.745

version 1.523.2.8, 2004/09/27 19:02:11 version 1.745, 2006/06/07 18:41:57
Line 35  use HTTP::Headers; Line 35  use HTTP::Headers;
 use HTTP::Date;  use HTTP::Date;
 # use Date::Parse;  # use Date::Parse;
 use vars   use vars 
 qw(%perlvar %hostname %homecache %badServerCache %hostip %iphost %spareid %hostdom   qw(%perlvar %hostname %badServerCache %iphost %spareid %hostdom 
    %libserv %pr %prp %metacache %packagetab %titlecache %courseresversioncache %resversioncache     %libserv %pr %prp $memcache %packagetab 
    %courselogs %accesshash %userrolehash $processmarker $dumpcount      %courselogs %accesshash %userrolehash %domainrolehash $processmarker $dumpcount 
    %coursedombuf %coursenumbuf %coursehombuf %coursedescrbuf %courseinstcodebuf %courseresdatacache      %coursedombuf %coursenumbuf %coursehombuf %coursedescrbuf %courseinstcodebuf %courseownerbuf %coursetypebuf
    %userresdatacache %usectioncache %domaindescription %domain_auth_def %domain_auth_arg_def      %domaindescription %domain_auth_def %domain_auth_arg_def 
    %domain_lang_def %domain_city %domain_longi %domain_lati $tmpdir);     %domain_lang_def %domain_city %domain_longi %domain_lati %domain_primary
      $tmpdir $_64bit %env);
   
 use IO::Socket;  use IO::Socket;
 use GDBM_File;  use GDBM_File;
 use Apache::Constants qw(:common :http);  
 use HTML::LCParser;  use HTML::LCParser;
   use HTML::Parser;
 use Fcntl qw(:flock);  use Fcntl qw(:flock);
 use Apache::loncoursedata;  use Storable qw(lock_store lock_nstore lock_retrieve freeze thaw nfreeze);
 use Apache::lonlocal;  
 use Storable qw(lock_store lock_nstore lock_retrieve freeze thaw);  
 use Time::HiRes qw( gettimeofday tv_interval );  use Time::HiRes qw( gettimeofday tv_interval );
   use Cache::Memcached;
   use Digest::MD5;
   use lib '/home/httpd/lib/perl';
   use LONCAPA;
   use LONCAPA::Configuration;
   
 my $readit;  my $readit;
   my $max_connection_retries = 10;     # Or some such value.
   
   require Exporter;
   
   our @ISA = qw (Exporter);
   our @EXPORT = qw(%env);
   
 =pod  =pod
   
Line 77  delayed. Line 88  delayed.
   
   
 # --------------------------------------------------------------------- Logging  # --------------------------------------------------------------------- Logging
   {
       my $logid;
       sub instructor_log {
    my ($hash_name,$storehash,$delflag,$uname,$udom)=@_;
    $logid++;
    my $id=time().'00000'.$$.'00000'.$logid;
    return &Apache::lonnet::put('nohist_'.$hash_name,
       { $id => {
    'exe_uname' => $env{'user.name'},
    'exe_udom'  => $env{'user.domain'},
    'exe_time'  => time(),
    'exe_ip'    => $ENV{'REMOTE_ADDR'},
    'delflag'   => $delflag,
    'logentry'  => $storehash,
    'uname'     => $uname,
    'udom'      => $udom,
       }
     },
       $env{'course.'.$env{'request.course.id'}.'.domain'},
       $env{'course.'.$env{'request.course.id'}.'.num'}
       );
       }
   }
   
 sub logtouch {  sub logtouch {
     my $execdir=$perlvar{'lonDaemons'};      my $execdir=$perlvar{'lonDaemons'};
Line 115  sub logperm { Line 149  sub logperm {
 # -------------------------------------------------- Non-critical communication  # -------------------------------------------------- Non-critical communication
 sub subreply {  sub subreply {
     my ($cmd,$server)=@_;      my ($cmd,$server)=@_;
     my $peerfile="$perlvar{'lonSockDir'}/$server";      my $peerfile="$perlvar{'lonSockDir'}/".$hostname{$server};
     my $client=IO::Socket::UNIX->new(Peer    =>"$peerfile",      #
                                      Type    => SOCK_STREAM,      #  With loncnew process trimming, there's a timing hole between lonc server
                                      Timeout => 10)      #  process exit and the master server picking up the listen on the AF_UNIX
        or return "con_lost";      #  socket.  In that time interval, a lock file will exist:
     print $client "$cmd\n";  
     my $answer=<$client>;      my $lockfile=$peerfile.".lock";
     if (!$answer) { $answer="con_lost"; }      while (-e $lockfile) { # Need to wait for the lockfile to disappear.
     chomp($answer);   sleep(1);
       }
       # At this point, either a loncnew parent is listening or an old lonc
       # or loncnew child is listening so we can connect or everything's dead.
       #
       #   We'll give the connection a few tries before abandoning it.  If
       #   connection is not possible, we'll con_lost back to the client.
       #   
       my $client;
       for (my $retries = 0; $retries < $max_connection_retries; $retries++) {
    $client=IO::Socket::UNIX->new(Peer    =>"$peerfile",
         Type    => SOCK_STREAM,
         Timeout => 10);
    if($client) {
       last; # Connected!
    }
    sleep(1); # Try again later if failed connection.
       }
       my $answer;
       if ($client) {
    print $client "sethost:$server:$cmd\n";
    $answer=<$client>;
    if (!$answer) { $answer="con_lost"; }
    chomp($answer);
       } else {
    $answer = 'con_lost'; # Failed connection.
       }
     return $answer;      return $answer;
 }  }
   
Line 131  sub reply { Line 191  sub reply {
     my ($cmd,$server)=@_;      my ($cmd,$server)=@_;
     unless (defined($hostname{$server})) { return 'no_such_host'; }      unless (defined($hostname{$server})) { return 'no_such_host'; }
     my $answer=subreply($cmd,$server);      my $answer=subreply($cmd,$server);
     if ($answer eq 'con_lost') {  
         #sleep 5;   
         #$answer=subreply($cmd,$server);  
         #if ($answer eq 'con_lost') {  
  #   &logthis("Second attempt con_lost on $server");  
         #   my $peerfile="$perlvar{'lonSockDir'}/$server";  
         #   my $client=IO::Socket::UNIX->new(Peer    =>"$peerfile",  
         #                                    Type    => SOCK_STREAM,  
         #                                    Timeout => 10)  
         #              or return "con_lost";  
         #   &logthis("Killing socket");  
         #   print $client "close_connection_exit\n";  
            #sleep 5;  
         #   $answer=subreply($cmd,$server);         
        #}     
     }  
     if (($answer=~/^refused/) || ($answer=~/^rejected/)) {      if (($answer=~/^refused/) || ($answer=~/^rejected/)) {
        &logthis("<font color=blue>WARNING:".         &logthis("<font color=\"blue\">WARNING:".
                 " $cmd to $server returned $answer</font>");                  " $cmd to $server returned $answer</font>");
     }      }
     return $answer;      return $answer;
Line 172  sub reconlonc { Line 216  sub reconlonc {
             sleep 5;              sleep 5;
             if (-e "$peerfile") { return; }              if (-e "$peerfile") { return; }
             &logthis(              &logthis(
   "<font color=blue>WARNING: $peerfile still not there, giving up</font>");    "<font color=\"blue\">WARNING: $peerfile still not there, giving up</font>");
         } else {          } else {
     &logthis(      &logthis(
                "<font color=blue>WARNING:".                 "<font color=\"blue\">WARNING:".
                " lonc at pid $loncpid not responding, giving up</font>");                 " lonc at pid $loncpid not responding, giving up</font>");
         }          }
     } else {      } else {
      &logthis('<font color=blue>WARNING: lonc not running, giving up</font>');       &logthis('<font color="blue">WARNING: lonc not running, giving up</font>');
     }      }
 }  }
   
Line 188  sub reconlonc { Line 232  sub reconlonc {
 sub critical {  sub critical {
     my ($cmd,$server)=@_;      my ($cmd,$server)=@_;
     unless ($hostname{$server}) {      unless ($hostname{$server}) {
         &logthis("<font color=blue>WARNING:".          &logthis("<font color=\"blue\">WARNING:".
                " Critical message to unknown server ($server)</font>");                 " Critical message to unknown server ($server)</font>");
         return 'no_such_host';          return 'no_such_host';
     }      }
     my $answer=reply($cmd,$server);      my $answer=reply($cmd,$server);
     if ($answer eq 'con_lost') {      if ($answer eq 'con_lost') {
         my $pingreply=reply('ping',$server);  
  &reconlonc("$perlvar{'lonSockDir'}/$server");   &reconlonc("$perlvar{'lonSockDir'}/$server");
         my $pongreply=reply('pong',$server);   my $answer=reply($cmd,$server);
         &logthis("Ping/Pong for $server: $pingreply/$pongreply");  
         $answer=reply($cmd,$server);  
         if ($answer eq 'con_lost') {          if ($answer eq 'con_lost') {
             my $now=time;              my $now=time;
             my $middlename=$cmd;              my $middlename=$cmd;
Line 225  sub critical { Line 266  sub critical {
             }              }
             chomp($wcmd);              chomp($wcmd);
             if ($wcmd eq $cmd) {              if ($wcmd eq $cmd) {
  &logthis("<font color=blue>WARNING: ".   &logthis("<font color=\"blue\">WARNING: ".
                          "Connection buffer $dfilename: $cmd</font>");                           "Connection buffer $dfilename: $cmd</font>");
                 &logperm("D:$server:$cmd");                  &logperm("D:$server:$cmd");
         return 'con_delayed';          return 'con_delayed';
             } else {              } else {
                 &logthis("<font color=red>CRITICAL:"                  &logthis("<font color=\"red\">CRITICAL:"
                         ." Critical connection failed: $server $cmd</font>");                          ." Critical connection failed: $server $cmd</font>");
                 &logperm("F:$server:$cmd");                  &logperm("F:$server:$cmd");
                 return 'con_failed';                  return 'con_failed';
Line 240  sub critical { Line 281  sub critical {
     return $answer;      return $answer;
 }  }
   
 #  
 # -------------- Remove all key from the env that start witha lowercase letter  
 #                (Which is always a lon-capa value)  
   
 sub cleanenv {  
 #    unless (defined(&Apache::exists_config_define("MODPERL2"))) { return; }  
 #    unless (&Apache::exists_config_define("MODPERL2")) { return; }  
     foreach my $key (keys(%ENV)) {  
  if ($key =~ /^[a-z]/) {  
     delete($ENV{$key});  
  }  
     }  
 }  
    
 # ------------------------------------------- Transfer profile into environment  # ------------------------------------------- Transfer profile into environment
   
 sub transfer_profile_to_env {  sub transfer_profile_to_env {
     my ($lonidsdir,$handle)=@_;      my ($lonidsdir,$handle)=@_;
       if (!defined($lonidsdir)) {
    $lonidsdir = $perlvar{'lonIDsDir'};
       }
       if (!defined($handle)) {
           ($handle) = ($env{'user.environment'} =~m|/([^/]+)\.id$| );
       }
   
     my @profile;      my @profile;
     {      {
  open(my $idf,"$lonidsdir/$handle.id");   open(my $idf,"$lonidsdir/$handle.id");
Line 269  sub transfer_profile_to_env { Line 303  sub transfer_profile_to_env {
     my %Remove;      my %Remove;
     for ($envi=0;$envi<=$#profile;$envi++) {      for ($envi=0;$envi<=$#profile;$envi++) {
  chomp($profile[$envi]);   chomp($profile[$envi]);
  my ($envname,$envvalue)=split(/=/,$profile[$envi]);   my ($envname,$envvalue)=split(/=/,$profile[$envi],2);
  $ENV{$envname} = $envvalue;   $envname=&unescape($envname);
    $envvalue=&unescape($envvalue);
    $env{$envname} = $envvalue;
         if (my ($key,$time) = ($envname =~ /^(cgi\.(\d+)_\d+\.)/)) {          if (my ($key,$time) = ($envname =~ /^(cgi\.(\d+)_\d+\.)/)) {
             if ($time < time-300) {              if ($time < time-300) {
                 $Remove{$key}++;                  $Remove{$key}++;
             }              }
         }          }
     }      }
     $ENV{'user.environment'} = "$lonidsdir/$handle.id";      $env{'user.environment'} = "$lonidsdir/$handle.id";
     foreach my $expired_key (keys(%Remove)) {      foreach my $expired_key (keys(%Remove)) {
         &delenv($expired_key);          &delenv($expired_key);
     }      }
Line 287  sub transfer_profile_to_env { Line 323  sub transfer_profile_to_env {
   
 sub appenv {  sub appenv {
     my %newenv=@_;      my %newenv=@_;
     foreach (keys %newenv) {      foreach my $key (keys(%newenv)) {
  if (($newenv{$_}=~/^user\.role/) || ($newenv{$_}=~/^user\.priv/)) {   if (($newenv{$key}=~/^user\.role/) || ($newenv{$key}=~/^user\.priv/)) {
             &logthis("<font color=blue>WARNING: ".              &logthis("<font color=\"blue\">WARNING: ".
                 "Attempt to modify environment ".$_." to ".$newenv{$_}                  "Attempt to modify environment ".$key." to ".$newenv{$key}
                 .'</font>');                  .'</font>');
     delete($newenv{$_});      delete($newenv{$key});
         } else {          } else {
             $ENV{$_}=$newenv{$_};              $env{$key}=$newenv{$key};
         }          }
     }      }
   
     my $lockfh;      my $lockfh;
     unless (open($lockfh,"$ENV{'user.environment'}")) {      unless (open($lockfh,"$env{'user.environment'}")) {
  return 'error: '.$!;   return 'error: '.$!;
     }      }
     unless (flock($lockfh,LOCK_EX)) {      unless (flock($lockfh,LOCK_EX)) {
          &logthis("<font color=blue>WARNING: ".           &logthis("<font color=\"blue\">WARNING: ".
                   'Could not obtain exclusive lock in appenv: '.$!);                    'Could not obtain exclusive lock in appenv: '.$!);
          close($lockfh);           close($lockfh);
          return 'error: '.$!;           return 'error: '.$!;
Line 312  sub appenv { Line 348  sub appenv {
     my @oldenv;      my @oldenv;
     {      {
  my $fh;   my $fh;
  unless (open($fh,"$ENV{'user.environment'}")) {   unless (open($fh,"$env{'user.environment'}")) {
     return 'error: '.$!;      return 'error: '.$!;
  }   }
  @oldenv=<$fh>;   @oldenv=<$fh>;
Line 321  sub appenv { Line 357  sub appenv {
     for (my $i=0; $i<=$#oldenv; $i++) {      for (my $i=0; $i<=$#oldenv; $i++) {
         chomp($oldenv[$i]);          chomp($oldenv[$i]);
         if ($oldenv[$i] ne '') {          if ($oldenv[$i] ne '') {
     my ($name,$value)=split(/=/,$oldenv[$i]);      my ($name,$value)=split(/=/,$oldenv[$i],2);
       $name=&unescape($name);
       $value=&unescape($value);
     unless (defined($newenv{$name})) {      unless (defined($newenv{$name})) {
  $newenv{$name}=$value;   $newenv{$name}=$value;
     }      }
Line 329  sub appenv { Line 367  sub appenv {
     }      }
     {      {
  my $fh;   my $fh;
  unless (open($fh,">$ENV{'user.environment'}")) {   unless (open($fh,">$env{'user.environment'}")) {
     return 'error';      return 'error';
  }   }
  my $newname;   my $newname;
  foreach $newname (keys %newenv) {   foreach $newname (keys %newenv) {
     print $fh "$newname=$newenv{$newname}\n";      print $fh &escape($newname).'='.&escape($newenv{$newname})."\n";
  }   }
  close($fh);   close($fh);
     }      }
Line 346  sub appenv { Line 384  sub appenv {
   
 sub delenv {  sub delenv {
     my $delthis=shift;      my $delthis=shift;
     my %newenv=();  
     if (($delthis=~/user\.role/) || ($delthis=~/user\.priv/)) {      if (($delthis=~/user\.role/) || ($delthis=~/user\.priv/)) {
         &logthis("<font color=blue>WARNING: ".          &logthis("<font color=\"blue\">WARNING: ".
                 "Attempt to delete from environment ".$delthis);                  "Attempt to delete from environment ".$delthis);
         return 'error';          return 'error';
     }      }
     my @oldenv;      my @oldenv;
     {      {
  my $fh;   my $fh;
  unless (open($fh,"$ENV{'user.environment'}")) {   unless (open($fh,"$env{'user.environment'}")) {
     return 'error';      return 'error';
  }   }
  unless (flock($fh,LOCK_SH)) {   unless (flock($fh,LOCK_SH)) {
     &logthis("<font color=blue>WARNING: ".      &logthis("<font color=\"blue\">WARNING: ".
      'Could not obtain shared lock in delenv: '.$!);       'Could not obtain shared lock in delenv: '.$!);
     close($fh);      close($fh);
     return 'error: '.$!;      return 'error: '.$!;
Line 369  sub delenv { Line 406  sub delenv {
     }      }
     {      {
  my $fh;   my $fh;
  unless (open($fh,">$ENV{'user.environment'}")) {   unless (open($fh,">$env{'user.environment'}")) {
     return 'error';      return 'error';
  }   }
  unless (flock($fh,LOCK_EX)) {   unless (flock($fh,LOCK_EX)) {
     &logthis("<font color=blue>WARNING: ".      &logthis("<font color=\"blue\">WARNING: ".
      'Could not obtain exclusive lock in delenv: '.$!);       'Could not obtain exclusive lock in delenv: '.$!);
     close($fh);      close($fh);
     return 'error: '.$!;      return 'error: '.$!;
  }   }
  foreach (@oldenv) {   foreach my $cur_key (@oldenv) {
     if ($_=~/^$delthis/) {       my $unescaped_cur_key = &unescape($cur_key);
                 my ($key,undef) = split('=',$_);      if ($unescaped_cur_key=~/^$delthis/) { 
                 delete($ENV{$key});                  my ($key) = split('=',$cur_key,2);
    $key = &unescape($key);
                   delete($env{$key});
             } else {              } else {
                 print $fh $_;                   print $fh $cur_key; 
             }              }
  }   }
  close($fh);   close($fh);
Line 434  sub overloaderror { Line 473  sub overloaderror {
     if ($overload>0) {      if ($overload>0) {
  $r->err_headers_out->{'Retry-After'}=$overload;   $r->err_headers_out->{'Retry-After'}=$overload;
         $r->log_error('Overload of '.$overload.' on '.$checkserver);          $r->log_error('Overload of '.$overload.' on '.$checkserver);
         return 409;          return 413;
     }          }    
     return '';      return '';
 }  }
Line 442  sub overloaderror { Line 481  sub overloaderror {
 # ------------------------------ Find server with least workload from spare.tab  # ------------------------------ Find server with least workload from spare.tab
   
 sub spareserver {  sub spareserver {
     my ($loadpercent,$userloadpercent) = @_;      my ($loadpercent,$userloadpercent,$want_server_name) = @_;
     my $tryserver;      my $tryserver;
     my $spareserver='';      my $spareserver='';
     if ($userloadpercent !~ /\d/) { $userloadpercent=0; }      if ($userloadpercent !~ /\d/) { $userloadpercent=0; }
     my $lowestserver=$loadpercent > $userloadpercent?      my $lowestserver=$loadpercent > $userloadpercent?
              $loadpercent :  $userloadpercent;               $loadpercent :  $userloadpercent;
     foreach $tryserver (keys %spareid) {      foreach $tryserver (keys(%spareid)) {
  my $loadans=reply('load',$tryserver);   my $loadans=&reply('load',$tryserver);
  my $userloadans=reply('userload',$tryserver);   my $userloadans=&reply('userload',$tryserver);
  if ($loadans !~ /\d/ && $userloadans !~ /\d/) {   if ($loadans !~ /\d/ && $userloadans !~ /\d/) {
     next; #didn't get a number from the server      next; #didn't get a number from the server
  }   }
Line 467  sub spareserver { Line 506  sub spareserver {
     $answer = $userloadans;      $answer = $userloadans;
  }   }
  if (($answer =~ /\d/) && ($answer<$lowestserver)) {   if (($answer =~ /\d/) && ($answer<$lowestserver)) {
     $spareserver="http://$hostname{$tryserver}";      if ($want_server_name) {
    $spareserver=$tryserver;
       } else {
    $spareserver="http://$hostname{$tryserver}";
       }
     $lowestserver=$answer;      $lowestserver=$answer;
  }   }
     }      }
Line 551  sub authenticate { Line 594  sub authenticate {
   
 # ---------------------- Find the homebase for a user from domain's lib servers  # ---------------------- Find the homebase for a user from domain's lib servers
   
   my %homecache;
 sub homeserver {  sub homeserver {
     my ($uname,$udom,$ignoreBadCache)=@_;      my ($uname,$udom,$ignoreBadCache)=@_;
     my $index="$uname:$udom";      my $index="$uname:$udom";
   
     my ($result,$cached)=&is_cached(\%homecache,$index,'home',86400);      if (exists($homecache{$index})) { return $homecache{$index}; }
     if (defined($cached)) { return $result; }  
     my $tryserver;      my $tryserver;
     foreach $tryserver (keys %libserv) {      foreach $tryserver (keys %libserv) {
         next if ($ignoreBadCache ne 'true' &&           next if ($ignoreBadCache ne 'true' && 
Line 564  sub homeserver { Line 607  sub homeserver {
  if ($hostdom{$tryserver} eq $udom) {   if ($hostdom{$tryserver} eq $udom) {
            my $answer=reply("home:$udom:$uname",$tryserver);             my $answer=reply("home:$udom:$uname",$tryserver);
            if ($answer eq 'found') {              if ($answer eq 'found') { 
        return &do_cache(\%homecache,$index,$tryserver,'home');         return $homecache{$index}=$tryserver;
            } elsif ($answer eq 'no_host') {             } elsif ($answer eq 'no_host') {
        $badServerCache{$tryserver}=1;         $badServerCache{$tryserver}=1;
            }             }
Line 644  sub assign_access_key { Line 687  sub assign_access_key {
 #  #
     my ($ckey,$kdom,$knum,$cdom,$cnum,$udom,$uname,$logentry)=@_;      my ($ckey,$kdom,$knum,$cdom,$cnum,$udom,$uname,$logentry)=@_;
     $kdom=      $kdom=
    $ENV{'course.'.$ENV{'request.course.id'}.'.domain'} unless (defined($kdom));     $env{'course.'.$env{'request.course.id'}.'.domain'} unless (defined($kdom));
     $knum=      $knum=
    $ENV{'course.'.$ENV{'request.course.id'}.'.num'} unless (defined($knum));     $env{'course.'.$env{'request.course.id'}.'.num'} unless (defined($knum));
     $cdom=      $cdom=
    $ENV{'course.'.$ENV{'request.course.id'}.'.domain'} unless (defined($cdom));     $env{'course.'.$env{'request.course.id'}.'.domain'} unless (defined($cdom));
     $cnum=      $cnum=
    $ENV{'course.'.$ENV{'request.course.id'}.'.num'} unless (defined($cnum));     $env{'course.'.$env{'request.course.id'}.'.num'} unless (defined($cnum));
     $udom=$ENV{'user.name'} unless (defined($udom));      $udom=$env{'user.name'} unless (defined($udom));
     $uname=$ENV{'user.domain'} unless (defined($uname));      $uname=$env{'user.domain'} unless (defined($uname));
     my %existing=&get('accesskeys',[$ckey],$kdom,$knum);      my %existing=&get('accesskeys',[$ckey],$kdom,$knum);
     if (($existing{$ckey}=~/^\#(.*)$/) || # - new key      if (($existing{$ckey}=~/^\#(.*)$/) || # - new key
         ($existing{$ckey}=~/^\Q$uname\E\:\Q$udom\E\#(.*)$/)) {           ($existing{$ckey}=~/^\Q$uname\E\:\Q$udom\E\#(.*)$/)) { 
Line 694  sub comment_access_key { Line 737  sub comment_access_key {
 #  #
     my ($ckey,$cdom,$cnum,$logentry)=@_;      my ($ckey,$cdom,$cnum,$logentry)=@_;
     $cdom=      $cdom=
    $ENV{'course.'.$ENV{'request.course.id'}.'.domain'} unless (defined($cdom));     $env{'course.'.$env{'request.course.id'}.'.domain'} unless (defined($cdom));
     $cnum=      $cnum=
    $ENV{'course.'.$ENV{'request.course.id'}.'.num'} unless (defined($cnum));     $env{'course.'.$env{'request.course.id'}.'.num'} unless (defined($cnum));
     my %existing=&get('accesskeys',[$ckey],$cdom,$cnum);      my %existing=&get('accesskeys',[$ckey],$cdom,$cnum);
     if ($existing{$ckey}) {      if ($existing{$ckey}) {
         $existing{$ckey}.='; '.$logentry;          $existing{$ckey}.='; '.$logentry;
Line 718  sub comment_access_key { Line 761  sub comment_access_key {
 sub generate_access_keys {  sub generate_access_keys {
     my ($number,$cdom,$cnum,$logentry)=@_;      my ($number,$cdom,$cnum,$logentry)=@_;
     $cdom=      $cdom=
    $ENV{'course.'.$ENV{'request.course.id'}.'.domain'} unless (defined($cdom));     $env{'course.'.$env{'request.course.id'}.'.domain'} unless (defined($cdom));
     $cnum=      $cnum=
    $ENV{'course.'.$ENV{'request.course.id'}.'.num'} unless (defined($cnum));     $env{'course.'.$env{'request.course.id'}.'.num'} unless (defined($cnum));
     unless (&allowed('mky',$cdom)) { return 0; }      unless (&allowed('mky',$cdom)) { return 0; }
     unless (($cdom) && ($cnum)) { return 0; }      unless (($cdom) && ($cnum)) { return 0; }
     if ($number>10000) { return 0; }      if ($number>10000) { return 0; }
Line 739  sub generate_access_keys { Line 782  sub generate_access_keys {
        } else {         } else {
   if (&put('accesskeys',    if (&put('accesskeys',
               { $newkey => '# generated '.localtime().                { $newkey => '# generated '.localtime().
                            ' by '.$ENV{'user.name'}.'@'.$ENV{'user.domain'}.                             ' by '.$env{'user.name'}.'@'.$env{'user.domain'}.
                            '; '.$logentry },                             '; '.$logentry },
    $cdom,$cnum) eq 'ok') {     $cdom,$cnum) eq 'ok') {
               $total++;                $total++;
   }    }
        }         }
     }      }
     &log($ENV{'user.domain'},$ENV{'user.name'},$ENV{'user.home'},      &log($env{'user.domain'},$env{'user.name'},$env{'user.home'},
          'Generated '.$total.' keys for '.$cnum.' at '.$cdom);           'Generated '.$total.' keys for '.$cnum.' at '.$cdom);
     return $total;      return $total;
 }  }
Line 756  sub generate_access_keys { Line 799  sub generate_access_keys {
 sub validate_access_key {  sub validate_access_key {
     my ($ckey,$cdom,$cnum,$udom,$uname)=@_;      my ($ckey,$cdom,$cnum,$udom,$uname)=@_;
     $cdom=      $cdom=
    $ENV{'course.'.$ENV{'request.course.id'}.'.domain'} unless (defined($cdom));     $env{'course.'.$env{'request.course.id'}.'.domain'} unless (defined($cdom));
     $cnum=      $cnum=
    $ENV{'course.'.$ENV{'request.course.id'}.'.num'} unless (defined($cnum));     $env{'course.'.$env{'request.course.id'}.'.num'} unless (defined($cnum));
     $udom=$ENV{'user.domain'} unless (defined($udom));      $udom=$env{'user.domain'} unless (defined($udom));
     $uname=$ENV{'user.name'} unless (defined($uname));      $uname=$env{'user.name'} unless (defined($uname));
     my %existing=&get('accesskeys',[$ckey],$cdom,$cnum);      my %existing=&get('accesskeys',[$ckey],$cdom,$cnum);
     return ($existing{$ckey}=~/^\Q$uname\E\:\Q$udom\E\#/);      return ($existing{$ckey}=~/^\Q$uname\E\:\Q$udom\E\#/);
 }  }
   
 # ------------------------------------- Find the section of student in a course  # ------------------------------------- Find the section of student in a course
   sub devalidate_getsection_cache {
       my ($udom,$unam,$courseid)=@_;
       $courseid=~s/\_/\//g;
       $courseid=~s/^(\w)/\/$1/;
       my $hashid="$udom:$unam:$courseid";
       &devalidate_cache_new('getsection',$hashid);
   }
   
 sub getsection {  sub getsection {
     my ($udom,$unam,$courseid)=@_;      my ($udom,$unam,$courseid)=@_;
       my $cachetime=1800;
     $courseid=~s/\_/\//g;      $courseid=~s/\_/\//g;
     $courseid=~s/^(\w)/\/$1/;      $courseid=~s/^(\w)/\/$1/;
   
       my $hashid="$udom:$unam:$courseid";
       my ($result,$cached)=&is_cached_new('getsection',$hashid);
       if (defined($cached)) { return $result; }
   
     my %Pending;       my %Pending; 
     my %Expired;      my %Expired;
     #      #
Line 803  sub getsection { Line 859  sub getsection {
             $Pending{$start}=$section;              $Pending{$start}=$section;
             next;              next;
         }          }
         return $section;          return &do_cache_new('getsection',$hashid,$section,$cachetime);
     }      }
     #      #
     # Presumedly there will be few matching roles from the above      # Presumedly there will be few matching roles from the above
     # loop and the sorting time will be negligible.      # loop and the sorting time will be negligible.
     if (scalar(keys(%Pending))) {      if (scalar(keys(%Pending))) {
         my ($time) = sort {$a <=> $b} keys(%Pending);          my ($time) = sort {$a <=> $b} keys(%Pending);
         return $Pending{$time};          return &do_cache_new('getsection',$hashid,$Pending{$time},$cachetime);
     }       } 
     if (scalar(keys(%Expired))) {      if (scalar(keys(%Expired))) {
         my @sorted = sort {$a <=> $b} keys(%Expired);          my @sorted = sort {$a <=> $b} keys(%Expired);
         my $time = pop(@sorted);          my $time = pop(@sorted);
         return $Expired{$time};          return &do_cache_new('getsection',$hashid,$Expired{$time},$cachetime);
     }      }
     return '-1';      return &do_cache_new('getsection',$hashid,'-1',$cachetime);
 }  }
   
   sub save_cache {
 my $disk_caching_disabled=1;      &purge_remembered();
       #&Apache::loncommon::validate_page();
 sub devalidate_cache {      undef(%env);
     my ($cache,$id,$name) = @_;  }
     delete $$cache{$id.'.time'};  
     delete $$cache{$id.'.file'};  my $to_remember=-1;
     delete $$cache{$id};  my %remembered;
     if (1 || $disk_caching_disabled) { return; }  my %accessed;
     my $filename=$perlvar{'lonDaemons'}.'/tmp/lonnet_internal_cache_'.$name.".db";  my $kicks=0;
     if (!-e $filename) { return; }  my $hits=0;
     open(DB,">$filename.lock");  sub devalidate_cache_new {
     flock(DB,LOCK_EX);      my ($name,$id,$debug) = @_;
     my %hash;      if ($debug) { &Apache::lonnet::logthis("deleting $name:$id"); }
     if (tie(%hash,'GDBM_File',$filename,&GDBM_WRCREAT(),0640)) {      $id=&escape($name.':'.$id);
  eval <<'EVALBLOCK';      $memcache->delete($id);
     delete($hash{$id});      delete($remembered{$id});
     delete($hash{$id.'.time'});      delete($accessed{$id});
 EVALBLOCK  }
         if ($@) {  
     &logthis("<font color='red'>devalidate_cache blew up :$@:$name</font>");  sub is_cached_new {
     unlink($filename);      my ($name,$id,$debug) = @_;
  }      $id=&escape($name.':'.$id);
     } else {      if (exists($remembered{$id})) {
  if (-e $filename) {   if ($debug) { &Apache::lonnet::logthis("Earyl return $id of $remembered{$id} "); }
     &logthis("Unable to tie hash (devalidate cache): $name");   $accessed{$id}=[&gettimeofday()];
     unlink($filename);   $hits++;
  }   return ($remembered{$id},1);
     }      }
     untie(%hash);      my $value = $memcache->get($id);
     flock(DB,LOCK_UN);      if (!(defined($value))) {
     close(DB);   if ($debug) { &Apache::lonnet::logthis("getting $id is not defined"); }
 }  
   
 sub is_cached {  
     my ($cache,$id,$name,$time) = @_;  
     if (!$time) { $time=300; }  
     if (!exists($$cache{$id.'.time'})) {  
  &load_cache_item($cache,$name,$id,$time);  
     }  
     if (!exists($$cache{$id.'.time'})) {  
 # &logthis("Didn't find $id");  
  return (undef,undef);   return (undef,undef);
     } else {  
  if (time-($$cache{$id.'.time'})>$time) {  
     if (exists($$cache{$id.'.file'})) {  
  foreach my $filename (@{ $$cache{$id.'.file'} }) {  
     my $mtime=(stat($filename))[9];  
     #+1 is to take care of edge effects  
     if ($mtime && (($mtime+1) < ($$cache{$id.'.time'}))) {  
 # &logthis("Upping $mtime - ".$$cache{$id.'.time'}.  
 # "$id because of $filename");  
     } else {  
 # &logthis("Devalidating $filename $id - ".(time-($$cache{$id.'.time'})));  
  &devalidate_cache($cache,$id,$name);  
  return (undef,undef);  
     }  
  }  
  $$cache{$id.'.time'}=time;  
     } else {  
 # &logthis("Devalidating $id - ".time-($$cache{$id.'.time'}));  
  &devalidate_cache($cache,$id,$name);  
  return (undef,undef);  
     }  
  }  
     }      }
     return ($$cache{$id},1);      if ($value eq '__undef__') {
 }   if ($debug) { &Apache::lonnet::logthis("getting $id is __undef__"); }
    $value=undef;
 sub do_cache {      }
     my ($cache,$id,$value,$name) = @_;      &make_room($id,$value,$debug);
     $$cache{$id.'.time'}=time;      if ($debug) { &Apache::lonnet::logthis("getting $id is $value"); }
     $$cache{$id}=$value;      return ($value,1);
 #    &logthis("Caching $id as :$value:");  }
     &save_cache_item($cache,$name,$id);  
     # do_cache implictly return the set value  sub do_cache_new {
     $$cache{$id};      my ($name,$id,$value,$time,$debug) = @_;
 }      $id=&escape($name.':'.$id);
       my $setvalue=$value;
 my %do_save_item;      if (!defined($setvalue)) {
 my %do_save;   $setvalue='__undef__';
 sub save_cache_item {      }
     my ($cache,$name,$id)=@_;      if (!defined($time) ) {
     if ($disk_caching_disabled) { return; }   $time=600;
     $do_save{$name}=$cache;      }
     if (!exists($do_save_item{$name})) { $do_save_item{$name}={} }      if ($debug) { &Apache::lonnet::logthis("Setting $id to $value"); }
     $do_save_item{$name}->{$id}=1;      $memcache->set($id,$setvalue,$time);
       # need to make a copy of $value
       #&make_room($id,$value,$debug);
       return $value;
   }
   
   sub make_room {
       my ($id,$value,$debug)=@_;
       $remembered{$id}=$value;
       if ($to_remember<0) { return; }
       $accessed{$id}=[&gettimeofday()];
       if (scalar(keys(%remembered)) <= $to_remember) { return; }
       my $to_kick;
       my $max_time=0;
       foreach my $other (keys(%accessed)) {
    if (&tv_interval($accessed{$other}) > $max_time) {
       $to_kick=$other;
       $max_time=&tv_interval($accessed{$other});
    }
       }
       delete($remembered{$to_kick});
       delete($accessed{$to_kick});
       $kicks++;
       if ($debug) { &logthis("kicking $to_kick $max_time $kicks\n"); }
     return;      return;
 }  }
   
 sub save_cache {  sub purge_remembered {
     if ($disk_caching_disabled) { return; }      #&logthis("Tossing ".scalar(keys(%remembered)));
     my ($cache,$name,$id);      #&logthis(sprintf("%-20s is %s",'%remembered',length(&freeze(\%remembered))));
     foreach $name (keys(%do_save)) {      undef(%remembered);
  $cache=$do_save{$name};      undef(%accessed);
   
  my $starttime=&Time::HiRes::time();  
  &logthis("Saving :$name:");  
  my %hash;  
  my $filename=$perlvar{'lonDaemons'}.'/tmp/lonnet_internal_cache_'.$name.".db";  
  open(DB,">$filename.lock");  
  flock(DB,LOCK_EX);  
  if (tie(%hash,'GDBM_File',$filename,&GDBM_WRCREAT(),0640)) {  
     foreach $id (keys(%{ $do_save_item{$name} })) {  
  eval <<'EVALBLOCK';  
  $hash{$id.'.time'}=$$cache{$id.'.time'};  
  $hash{$id}=freeze({'item'=>$$cache{$id}});  
  if (exists($$cache{$id.'.file'})) {  
     $hash{$id.'.file'}=freeze({'item'=>$$cache{$id.'.file'}});  
  }  
 EVALBLOCK  
                 if ($@) {  
     &logthis("<font color='red'>save_cache blew up :$@:$name</font>");  
     unlink($filename);  
     last;  
  }  
     }  
  } else {  
     if (-e $filename) {  
  &logthis("Unable to tie hash (save cache): $name ($!)");  
  unlink($filename);  
     }  
  }  
  untie(%hash);  
  flock(DB,LOCK_UN);  
  close(DB);  
  &logthis("save_cache $name took ".(&Time::HiRes::time()-$starttime));  
     }  
     undef(%do_save);  
     undef(%do_save_item);  
   
 }  
   
 sub load_cache_item {  
     my ($cache,$name,$id,$time)=@_;  
     if ($disk_caching_disabled) { return; }  
     my $starttime=&Time::HiRes::time();  
 #    &logthis("Before Loading $name  for $id size is ".scalar(%$cache));  
     my %hash;  
     my $filename=$perlvar{'lonDaemons'}.'/tmp/lonnet_internal_cache_'.$name.".db";  
     if (!-e $filename) { return; }  
     open(DB,">$filename.lock");  
     flock(DB,LOCK_SH);  
     if (tie(%hash,'GDBM_File',$filename,&GDBM_READER(),0640)) {  
  eval <<'EVALBLOCK';  
     if (!%$cache) {  
  my $count;  
  while (my ($key,$value)=each(%hash)) {   
     $count++;  
     if ($key =~ /\.time$/) {  
  $$cache{$key}=$value;  
     } else {  
  my $hashref=thaw($value);  
  $$cache{$key}=$hashref->{'item'};  
     }  
  }  
 #    &logthis("Initial load: $count");  
     } else {  
  if (($$cache{$id.'.time'}+$time) < time) {  
     $$cache{$id.'.time'}=$hash{$id.'.time'};  
     {  
  my $hashref=thaw($hash{$id});  
  $$cache{$id}=$hashref->{'item'};  
     }  
     if (exists($hash{$id.'.file'})) {  
  my $hashref=thaw($hash{$id.'.file'});  
  $$cache{$id.'.file'}=$hashref->{'item'};  
     }  
  }  
     }  
 EVALBLOCK  
         if ($@) {  
     &logthis("<font color='red'>load_cache blew up :$@:$name</font>");  
     unlink($filename);  
  }          
     } else {  
  if (-e $filename) {  
     &logthis("Unable to tie hash (load cache item): $name ($!)");  
     unlink($filename);  
  }  
     }  
     untie(%hash);  
     flock(DB,LOCK_UN);  
     close(DB);  
 #    &logthis("After Loading $name size is ".scalar(%$cache));  
 #    &logthis("load_cache_item $name took ".(&Time::HiRes::time()-$starttime));  
 }  }
   
 sub usection {  
     my ($udom,$unam,$courseid)=@_;  
     my $hashid="$udom:$unam:$courseid";  
       
     my ($result,$cached)=&is_cached(\%usectioncache,$hashid,'usection');  
     if (defined($cached)) { return $result; }  
     $courseid=~s/\_/\//g;  
     $courseid=~s/^(\w)/\/$1/;  
     foreach (split(/\&/,&reply('dump:'.$udom.':'.$unam.':roles',  
                         &homeserver($unam,$udom)))) {  
         my ($key,$value)=split(/\=/,$_);  
         $key=&unescape($key);  
         if ($key=~/^\Q$courseid\E(?:\/)*(\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 &do_cache(\%usectioncache,$hashid,$section,'usection');  
     }  
         }  
     }  
     return &do_cache(\%usectioncache,$hashid,'-1','usection');  
 }  
   
 # ------------------------------------- Read an entry from a user's environment  # ------------------------------------- Read an entry from a user's environment
   
 sub userenvironment {  sub userenvironment {
Line 1055  sub userenvironment { Line 978  sub userenvironment {
     return %returnhash;      return %returnhash;
 }  }
   
   # ---------------------------------------------------------- Get a studentphoto
   sub studentphoto {
       my ($udom,$unam,$ext) = @_;
       my $home=&Apache::lonnet::homeserver($unam,$udom);
       if (defined($env{'request.course.id'})) {
           if ($env{'course.'.$env{'request.course.id'}.'.internal.showphoto'}) {
               if ($udom eq $env{'course.'.$env{'request.course.id'}.'.domain'}) {
                   return(&retrievestudentphoto($udom,$unam,$ext)); 
               } else {
                   my ($result,$perm_reqd)=
       &Apache::lonnet::auto_photo_permission($unam,$udom);
                   if ($result eq 'ok') {
                       if (!($perm_reqd eq 'yes')) {
                           return(&retrievestudentphoto($udom,$unam,$ext));
                       }
                   }
               }
           }
       } else {
           my ($result,$perm_reqd) = 
       &Apache::lonnet::auto_photo_permission($unam,$udom);
           if ($result eq 'ok') {
               if (!($perm_reqd eq 'yes')) {
                   return(&retrievestudentphoto($udom,$unam,$ext));
               }
           }
       }
       return '/adm/lonKaputt/lonlogo_broken.gif';
   }
   
   sub retrievestudentphoto {
       my ($udom,$unam,$ext,$type) = @_;
       my $home=&Apache::lonnet::homeserver($unam,$udom);
       my $ret=&Apache::lonnet::reply("studentphoto:$udom:$unam:$ext:$type",$home);
       if ($ret eq 'ok') {
           my $url="/uploaded/$udom/$unam/internal/studentphoto.$ext";
           if ($type eq 'thumbnail') {
               $url="/uploaded/$udom/$unam/internal/studentphoto_tn.$ext"; 
           }
           my $tokenurl=&Apache::lonnet::tokenwrapper($url);
           return $tokenurl;
       } else {
           if ($type eq 'thumbnail') {
               return '/adm/lonKaputt/genericstudent_tn.gif';
           } else { 
               return '/adm/lonKaputt/lonlogo_broken.gif';
           }
       }
   }
   
 # -------------------------------------------------------------------- New chat  # -------------------------------------------------------------------- New chat
   
 sub chatsend {  sub chatsend {
     my ($newentry,$anon)=@_;      my ($newentry,$anon,$group)=@_;
     my $cnum=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};      my $cnum=$env{'course.'.$env{'request.course.id'}.'.num'};
     my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};      my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
     my $chome=$ENV{'course.'.$ENV{'request.course.id'}.'.home'};      my $chome=$env{'course.'.$env{'request.course.id'}.'.home'};
     &reply('chatsend:'.$cdom.':'.$cnum.':'.      &reply('chatsend:'.$cdom.':'.$cnum.':'.
    &escape($ENV{'user.domain'}.':'.$ENV{'user.name'}.':'.$anon.':'.     &escape($env{'user.domain'}.':'.$env{'user.name'}.':'.$anon.':'.
    &escape($newentry)),$chome);     &escape($newentry)).':'.$group,$chome);
 }  }
   
 # ------------------------------------------ Find current version of a resource  # ------------------------------------------ Find current version of a resource
Line 1077  sub getversion { Line 1050  sub getversion {
   
 sub currentversion {  sub currentversion {
     my $fname=shift;      my $fname=shift;
     my ($result,$cached)=&is_cached(\%resversioncache,$fname,'resversion',600);      my ($result,$cached)=&is_cached_new('resversion',$fname);
     if (defined($cached)) { return $result; }      if (defined($cached)) { return $result; }
     my $author=$fname;      my $author=$fname;
     $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;      $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;
Line 1090  sub currentversion { Line 1063  sub currentversion {
     if (($answer eq 'con_lost') || ($answer eq 'rejected')) {      if (($answer eq 'con_lost') || ($answer eq 'rejected')) {
  return -1;   return -1;
     }      }
     return &do_cache(\%resversioncache,$fname,$answer,'resversion');      return &do_cache_new('resversion',$fname,$answer,600);
 }  }
   
 # ----------------------------- Subscribe to a resource, return URL if possible  # ----------------------------- Subscribe to a resource, return URL if possible
Line 1118  sub subscribe { Line 1091  sub subscribe {
 sub repcopy {  sub repcopy {
     my $filename=shift;      my $filename=shift;
     $filename=~s/\/+/\//g;      $filename=~s/\/+/\//g;
     if ($filename=~/^\/home\/httpd\/html\/adm\//) { return OK; }      if ($filename=~m|^/home/httpd/html/adm/|) { return 'ok'; }
       if ($filename=~m|^/home/httpd/html/lonUsers/|) { return 'ok'; }
       if ($filename=~m|^/home/httpd/html/userfiles/| or
    $filename=~m -^/*(uploaded|editupload)/-) { 
    return &repcopy_userfile($filename);
       }
     $filename=~s/[\n\r]//g;      $filename=~s/[\n\r]//g;
     my $transname="$filename.in.transfer";      my $transname="$filename.in.transfer";
     if ((-e $filename) || (-e $transname)) { return OK; }      if ((-e $filename) || (-e $transname)) { return 'ok'; }
     my $remoteurl=subscribe($filename);      my $remoteurl=subscribe($filename);
     if ($remoteurl =~ /^con_lost by/) {      if ($remoteurl =~ /^con_lost by/) {
    &logthis("Subscribe returned $remoteurl: $filename");     &logthis("Subscribe returned $remoteurl: $filename");
            return HTTP_SERVICE_UNAVAILABLE;             return 'unavailable';
     } elsif ($remoteurl eq 'not_found') {      } elsif ($remoteurl eq 'not_found') {
    #&logthis("Subscribe returned not_found: $filename");     #&logthis("Subscribe returned not_found: $filename");
    return HTTP_NOT_FOUND;     return 'not_found';
     } elsif ($remoteurl =~ /^rejected by/) {      } elsif ($remoteurl =~ /^rejected by/) {
    &logthis("Subscribe returned $remoteurl: $filename");     &logthis("Subscribe returned $remoteurl: $filename");
            return FORBIDDEN;             return 'forbidden';
     } elsif ($remoteurl eq 'directory') {      } elsif ($remoteurl eq 'directory') {
            return OK;             return 'ok';
     } else {      } else {
         my $author=$filename;          my $author=$filename;
         $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;          $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;
Line 1144  sub repcopy { Line 1122  sub repcopy {
            my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";             my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";
            if ($path ne "$perlvar{'lonDocRoot'}/res") {             if ($path ne "$perlvar{'lonDocRoot'}/res") {
                &logthis("Malconfiguration for replication: $filename");                 &logthis("Malconfiguration for replication: $filename");
        return HTTP_BAD_REQUEST;         return 'bad_request';
            }             }
            my $count;             my $count;
            for ($count=5;$count<$#parts;$count++) {             for ($count=5;$count<$#parts;$count++) {
Line 1159  sub repcopy { Line 1137  sub repcopy {
            if ($response->is_error()) {             if ($response->is_error()) {
        unlink($transname);         unlink($transname);
                my $message=$response->status_line;                 my $message=$response->status_line;
                &logthis("<font color=blue>WARNING:"                 &logthis("<font color=\"blue\">WARNING:"
                        ." LWP get: $message: $filename</font>");                         ." LWP get: $message: $filename</font>");
                return HTTP_SERVICE_UNAVAILABLE;                 return 'unavailable';
            } else {             } else {
        if ($remoteurl!~/\.meta$/) {         if ($remoteurl!~/\.meta$/) {
                   my $mrequest=new HTTP::Request('GET',$remoteurl.'.meta');                    my $mrequest=new HTTP::Request('GET',$remoteurl.'.meta');
Line 1169  sub repcopy { Line 1147  sub repcopy {
                   if ($mresponse->is_error()) {                    if ($mresponse->is_error()) {
       unlink($filename.'.meta');        unlink($filename.'.meta');
                       &logthis(                        &logthis(
                      "<font color=yellow>INFO: No metadata: $filename</font>");                       "<font color=\"yellow\">INFO: No metadata: $filename</font>");
                   }                    }
        }         }
                rename($transname,$filename);                 rename($transname,$filename);
                return OK;                 return 'ok';
            }             }
        }         }
     }      }
Line 1182  sub repcopy { Line 1160  sub repcopy {
 # ------------------------------------------------ Get server side include body  # ------------------------------------------------ Get server side include body
 sub ssi_body {  sub ssi_body {
     my ($filelink,%form)=@_;      my ($filelink,%form)=@_;
       if (! exists($form{'LONCAPA_INTERNAL_no_discussion'})) {
           $form{'LONCAPA_INTERNAL_no_discussion'}='true';
       }
     my $output=($filelink=~/^http\:/?&externalssi($filelink):      my $output=($filelink=~/^http\:/?&externalssi($filelink):
                                      &ssi($filelink,%form));                                       &ssi($filelink,%form));
       $output=~s|//(\s*<!--)? BEGIN LON-CAPA Internal.+// END LON-CAPA Internal\s*(-->)?\s||gs;
     $output=~s/^.*?\<body[^\>]*\>//si;      $output=~s/^.*?\<body[^\>]*\>//si;
     $output=~s/(.*)\<\/body\s*\>.*?$/$1/si;      $output=~s/(.*)\<\/body\s*\>.*?$/$1/si;
     $output=~  
             s/\/\/ BEGIN LON\-CAPA Internal.+\/\/ END LON\-CAPA Internal\s//gs;  
     return $output;      return $output;
 }  }
   
Line 1200  sub ssi { Line 1180  sub ssi {
     my $ua=new LWP::UserAgent;      my $ua=new LWP::UserAgent;
           
     my $request;      my $request;
       
       $form{'no_update_last_known'}=1;
   
     if (%form) {      if (%form) {
       $request=new HTTP::Request('POST',"http://".$ENV{'HTTP_HOST'}.$fn);        $request=new HTTP::Request('POST',"http://".$ENV{'HTTP_HOST'}.$fn);
       $request->content(join('&',map { &escape($_).'='.&escape($form{$_}) } keys %form));        $request->content(join('&',map { &escape($_).'='.&escape($form{$_}) } keys %form));
Line 1236  sub allowuploaded { Line 1218  sub allowuploaded {
 }  }
   
 # --------- File operations in /home/httpd/html/userfiles/$domain/1/2/3/$course  # --------- File operations in /home/httpd/html/userfiles/$domain/1/2/3/$course
 # input: action, courseID, current domain, home server for course, intended  # input: action, courseID, current domain, intended
 #        path to file, source of file.  #        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.
   #
 # output: url to file (if action was uploaddoc),   # output: url to file (if action was uploaddoc), 
 #         ok if successful, or diagnostic message otherwise (if action was propagate or copy)  #         ok if successful, or diagnostic message otherwise (if action was propagate or copy)
 #  #
Line 1256  sub allowuploaded { Line 1241  sub allowuploaded {
 #         course's home server.  #         course's home server.
 #  #
 # action = uploaddoc - /home/httpd/html/userfiles/$domain/1/2/3/$course/$file  # action = uploaddoc - /home/httpd/html/userfiles/$domain/1/2/3/$course/$file
 #         will be retrived from $ENV{form.uploaddoc} (from DOCS interface) to  #         will be retrived from $env{form.uploaddoc} (from DOCS interface) to
 #         /home/httpd/html/userfiles/$domain/1/2/3/$course/$file  #         /home/httpd/html/userfiles/$domain/1/2/3/$course/$file
 #         and will then be copied to /home/httpd/lonUsers/1/2/3/$course/userfiles/$file  #         and will then be copied to /home/httpd/lonUsers/1/2/3/$course/userfiles/$file
 #         in course's home server.  #         in course's home server.
   #
   
 sub process_coursefile {  sub process_coursefile {
     my ($action,$docuname,$docudom,$docuhome,$file,$source)=@_;      my ($action,$docuname,$docudom,$file,$source,$parser,$allfiles,$codebase)=@_;
     my $fetchresult;      my $fetchresult;
       my $home=&homeserver($docuname,$docudom);
     if ($action eq 'propagate') {      if ($action eq 'propagate') {
         $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file          $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file,
                             ,$docuhome);       $home);
     } else {      } else {
         my $fetchresult = '';  
         my $fpath = '';          my $fpath = '';
         my $fname = $file;          my $fname = $file;
         ($fpath,$fname) = ($file =~ m|^(.*)/([^/]+)$|);          ($fpath,$fname) = ($file =~ m|^(.*)/([^/]+)$|);
         $fpath=$docudom.'/'.$docuname.'/'.$fpath;          $fpath=$docudom.'/'.$docuname.'/'.$fpath;
         my $filepath=$perlvar{'lonDocRoot'}.'/userfiles';          my $filepath = &build_filepath($fpath);
         unless ($fpath eq '') {  
             my @parts=split('/',$fpath);  
             foreach my $part (@parts) {  
                 $filepath.= '/'.$part;  
                 if ((-e $filepath)!=1) {  
                     mkdir($filepath,0777);  
                 }  
             }  
         }  
         if ($action eq 'copy') {          if ($action eq 'copy') {
             if ($source eq '') {              if ($source eq '') {
                 $fetchresult = 'no source file';                  $fetchresult = 'no source file';
Line 1292  sub process_coursefile { Line 1268  sub process_coursefile {
                 my $destination = $filepath.'/'.$fname;                  my $destination = $filepath.'/'.$fname;
                 rename($source,$destination);                  rename($source,$destination);
                 $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file,                  $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file,
                                  $docuhome);                                   $home);
             }              }
         } elsif ($action eq 'uploaddoc') {          } elsif ($action eq 'uploaddoc') {
             open(my $fh,'>'.$filepath.'/'.$fname);              open(my $fh,'>'.$filepath.'/'.$fname);
             print $fh $ENV{'form.'.$source};              print $fh $env{'form.'.$source};
             close($fh);              close($fh);
               if ($parser eq 'parse') {
                   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);
                   }
               }
             $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file,              $fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file,
                                  $docuhome);                                   $home);
             if ($fetchresult eq 'ok') {              if ($fetchresult eq 'ok') {
                 return '/uploaded/'.$fpath.'/'.$fname;                  return '/uploaded/'.$fpath.'/'.$fname;
             } else {              } else {
                 &logthis('Failed to transfer '.$docudom.'/'.$docuname.'/'.$file.                  &logthis('Failed to transfer '.$docudom.'/'.$docuname.'/'.$file.
                         ' to host '.$docuhome.': '.$fetchresult);                          ' to host '.$home.': '.$fetchresult);
                 return '/adm/notfound.html';                  return '/adm/notfound.html';
             }              }
         }          }
     }      }
     unless ( $fetchresult eq 'ok') {      unless ( $fetchresult eq 'ok') {
         &logthis('Failed to transfer '.$docudom.'/'.$docuname.'/'.$file.          &logthis('Failed to transfer '.$docudom.'/'.$docuname.'/'.$file.
              ' to host '.$docuhome.': '.$fetchresult);               ' to host '.$home.': '.$fetchresult);
     }      }
     return $fetchresult;      return $fetchresult;
 }  }
   
 # --------------- Take an uploaded file and put it into the userfiles directory  sub build_filepath {
 # input: name of form element, coursedoc=1 means this is for the course      my ($fpath) = @_;
 # output: url of file in userspace      my $filepath=$perlvar{'lonDocRoot'}.'/userfiles';
       unless ($fpath eq '') {
           my @parts=split('/',$fpath);
           foreach my $part (@parts) {
               $filepath.= '/'.$part;
               if ((-e $filepath)!=1) {
                   mkdir($filepath,0777);
               }
           }
       }
       return $filepath;
   }
   
 sub userfileupload {  sub store_edited_file {
     my ($formname,$coursedoc,$subdir)=@_;      my ($primary_url,$content,$docudom,$docuname,$fetchresult) = @_;
     if (!defined($subdir)) { $subdir='unknown'; }      my $file = $primary_url;
     my $fname=$ENV{'form.'.$formname.'.filename'};      $file =~ s#^/uploaded/$docudom/$docuname/##;
       my $fpath = '';
       my $fname = $file;
       ($fpath,$fname) = ($file =~ m|^(.*)/([^/]+)$|);
       $fpath=$docudom.'/'.$docuname.'/'.$fpath;
       my $filepath = &build_filepath($fpath);
       open(my $fh,'>'.$filepath.'/'.$fname);
       print $fh $content;
       close($fh);
       my $home=&homeserver($docuname,$docudom);
       $$fetchresult= &reply('fetchuserfile:'.$docudom.'/'.$docuname.'/'.$file,
     $home);
       if ($$fetchresult eq 'ok') {
           return '/uploaded/'.$fpath.'/'.$fname;
       } else {
           &logthis('Failed to transfer '.$docudom.'/'.$docuname.'/'.$file.
    ' to host '.$home.': '.$$fetchresult);
           return '/adm/notfound.html';
       }
   }
   
   sub clean_filename {
       my ($fname)=@_;
 # Replace Windows backslashes by forward slashes  # Replace Windows backslashes by forward slashes
     $fname=~s/\\/\//g;      $fname=~s/\\/\//g;
 # Get rid of everything but the actual filename  # Get rid of everything but the actual filename
Line 1332  sub userfileupload { Line 1347  sub userfileupload {
     $fname=~s/\s+/\_/g;      $fname=~s/\s+/\_/g;
 # Replace all other weird characters by nothing  # Replace all other weird characters by nothing
     $fname=~s/[^\w\.\-]//g;      $fname=~s/[^\w\.\-]//g;
   # Replace all .\d. sequences with _\d. so they no longer look like version
   # numbers
       $fname=~s/\.(\d+)(?=\.)/_$1/g;
       return $fname;
   }
   
   # --------------- 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
   #        $subdir - directory in userfile to store the file into
   #        $parser, $allfiles, $codebase - unknown
   #
   # output: url of file in userspace, or error: <message> 
   #             or /adm/notfound.html if failure to upload occurse
   
   
   sub userfileupload {
       my ($formname,$coursedoc,$subdir,$parser,$allfiles,$codebase,$destuname,$destudom)=@_;
       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'; }      unless ($fname) { return 'error: no uploaded file'; }
     chop($ENV{'form.'.$formname});      chop($env{'form.'.$formname});
     if (($formname eq 'screenshot') && ($subdir eq 'helprequests')) { #files uploaded to help request form are handled differently      if (($formname eq 'screenshot') && ($subdir eq 'helprequests')) { #files uploaded to help request form are handled differently
         my $now = time;          my $now = time;
         my $filepath = 'tmp/helprequests/'.$now;          my $filepath = 'tmp/helprequests/'.$now;
Line 1347  sub userfileupload { Line 1385  sub userfileupload {
             }              }
         }          }
         open(my $fh,'>'.$fullpath.'/'.$fname);          open(my $fh,'>'.$fullpath.'/'.$fname);
         print $fh $ENV{'form.'.$formname};          print $fh $env{'form.'.$formname};
         close($fh);          close($fh);
         return $fullpath.'/'.$fname;           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';
           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);
               }
           }
           open(my $fh,'>'.$fullpath.'/'.$fname);
           print $fh $env{'form.'.$formname};
           close($fh);
           return $fullpath.'/'.$fname;
     }      }
       
 # Create the directory if not present  # Create the directory if not present
     my $docuname='';  
     my $docudom='';  
     my $docuhome='';  
     $fname="$subdir/$fname";      $fname="$subdir/$fname";
     if ($coursedoc) {      if ($coursedoc) {
  $docuname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};   my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'};
  $docudom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};   my $docudom=$env{'course.'.$env{'request.course.id'}.'.domain'};
  $docuhome=$ENV{'course.'.$ENV{'request.course.id'}.'.home'};          if ($env{'form.folder'} =~ m/^(default|supplemental)/) {
         if ($ENV{'form.folder'} =~ m/^default/) {              return &finishuserfileupload($docuname,$docudom,
             return &finishuserfileupload($docuname,$docudom,$docuhome,$formname,$fname);   $formname,$fname,$parser,$allfiles,
    $codebase);
         } else {          } else {
             $fname=$ENV{'form.folder'}.'/'.$fname;              $fname=$env{'form.folder'}.'/'.$fname;
             return &process_coursefile('uploaddoc',$docuname,$docudom,$docuhome,$fname,$formname);              return &process_coursefile('uploaddoc',$docuname,$docudom,
          $fname,$formname,$parser,
          $allfiles,$codebase);
           }
       } elsif (defined($destuname)) {
           my $docuname=$destuname;
           my $docudom=$destudom;
    return &finishuserfileupload($docuname,$docudom,$formname,
        $fname,$parser,$allfiles,$codebase);
           
       } else {
           my $docuname=$env{'user.name'};
           my $docudom=$env{'user.domain'};
           if (exists($env{'form.group'})) {
               $docuname=$env{'course.'.$env{'request.course.id'}.'.num'};
               $docudom=$env{'course.'.$env{'request.course.id'}.'.domain'};
         }          }
     } else {   return &finishuserfileupload($docuname,$docudom,$formname,
         $docuname=$ENV{'user.name'};       $fname,$parser,$allfiles,$codebase);
         $docudom=$ENV{'user.domain'};  
         $docuhome=$ENV{'user.home'};  
         return &finishuserfileupload($docuname,$docudom,$docuhome,$formname,$fname);  
     }      }
 }  }
   
 sub finishuserfileupload {  sub finishuserfileupload {
     my ($docuname,$docudom,$docuhome,$formname,$fname)=@_;      my ($docuname,$docudom,$formname,$fname,$parser,$allfiles,$codebase) = @_;
     my $path=$docudom.'/'.$docuname.'/';      my $path=$docudom.'/'.$docuname.'/';
     my $filepath=$perlvar{'lonDocRoot'};      my $filepath=$perlvar{'lonDocRoot'};
     my ($fnamepath,$file);      my ($fnamepath,$file);
Line 1394  sub finishuserfileupload { Line 1458  sub finishuserfileupload {
     }      }
 # Save the file  # Save the file
     {      {
  #&Apache::lonnet::logthis("Saving to $filepath $file");   if (!open(FH,'>'.$filepath.'/'.$file)) {
        open(my $fh,'>'.$filepath.'/'.$file);      &logthis('Failed to create '.$filepath.'/'.$file);
        print $fh $ENV{'form.'.$formname};      print STDERR ('Failed to create '.$filepath.'/'.$file."\n");
        close($fh);      return '/adm/notfound.html';
    }
    if (!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';
    }
    close(FH);
       }
       if ($parser eq 'parse') {
           my $parse_result = &extract_embedded_items($filepath,$file,$allfiles,
      $codebase);
           unless ($parse_result eq 'ok') {
               &logthis('Failed to parse '.$filepath.$file.
        ' for embedded media: '.$parse_result); 
           }
     }      }
 # Notify homeserver to grep it  # Notify homeserver to grep it
 #  #
       my $docuhome=&homeserver($docuname,$docudom);
     my $fetchresult= &reply('fetchuserfile:'.$path.$file,$docuhome);      my $fetchresult= &reply('fetchuserfile:'.$path.$file,$docuhome);
     if ($fetchresult eq 'ok') {      if ($fetchresult eq 'ok') {
 #  #
Line 1413  sub finishuserfileupload { Line 1493  sub finishuserfileupload {
     }          }    
 }  }
   
   sub extract_embedded_items {
       my ($filepath,$file,$allfiles,$codebase,$content) = @_;
       my @state = ();
       my %javafiles = (
                         codebase => '',
                         code => '',
                         archive => ''
                       );
       my %mediafiles = (
                         src => '',
                         movie => '',
                        );
       my $p;
       if ($content) {
           $p = HTML::LCParser->new($content);
       } else {
           $p = HTML::LCParser->new($filepath.'/'.$file);
       }
       while (my $t=$p->get_token()) {
    if ($t->[0] eq 'S') {
       my ($tagname, $attr) = ($t->[1],$t->[2]);
       push (@state, $tagname);
               if (lc($tagname) eq 'allow') {
                   &add_filetype($allfiles,$attr->{'src'},'src');
               }
       if (lc($tagname) eq 'img') {
    &add_filetype($allfiles,$attr->{'src'},'src');
       }
               if (lc($tagname) eq 'script') {
                   if ($attr->{'archive'} =~ /\.jar$/i) {
                       &add_filetype($allfiles,$attr->{'archive'},'archive');
                   } else {
                       &add_filetype($allfiles,$attr->{'src'},'src');
                   }
               }
               if (lc($tagname) eq 'link') {
                   if (lc($attr->{'rel'}) eq 'stylesheet') { 
                       &add_filetype($allfiles,$attr->{'href'},'href');
                   }
               }
       if (lc($tagname) eq 'object' ||
    (lc($tagname) eq 'embed' && lc($state[-2]) ne 'object')) {
    foreach my $item (keys(%javafiles)) {
       $javafiles{$item} = '';
    }
       }
       if (lc($state[-2]) eq 'object' && lc($tagname) eq 'param') {
    my $name = lc($attr->{'name'});
    foreach my $item (keys(%javafiles)) {
       if ($name eq $item) {
    $javafiles{$item} = $attr->{'value'};
    last;
       }
    }
    foreach my $item (keys(%mediafiles)) {
       if ($name eq $item) {
    &add_filetype($allfiles, $attr->{'value'}, 'value');
    last;
       }
    }
       }
       if (lc($tagname) eq 'embed' || lc($tagname) eq 'applet') {
    foreach my $item (keys(%javafiles)) {
       if ($attr->{$item}) {
    $javafiles{$item} = $attr->{$item};
    last;
       }
    }
    foreach my $item (keys(%mediafiles)) {
       if ($attr->{$item}) {
    &add_filetype($allfiles,$attr->{$item},$item);
    last;
       }
    }
       }
    } elsif ($t->[0] eq 'E') {
       my ($tagname) = ($t->[1]);
       if ($javafiles{'codebase'} ne '') {
    $javafiles{'codebase'} .= '/';
       }  
       if (lc($tagname) eq 'applet' ||
    lc($tagname) eq 'object' ||
    (lc($tagname) eq 'embed' && lc($state[-2]) ne 'object')
    ) {
    foreach my $item (keys(%javafiles)) {
       if ($item ne 'codebase' && $javafiles{$item} ne '') {
    my $file=$javafiles{'codebase'}.$javafiles{$item};
    &add_filetype($allfiles,$file,$item);
       }
    }
       } 
       pop @state;
    }
       }
       return 'ok';
   }
   
   sub add_filetype {
       my ($allfiles,$file,$type)=@_;
       if (exists($allfiles->{$file})) {
    unless (grep/^\Q$type\E$/, @{$allfiles->{$file}}) {
       push(@{$allfiles->{$file}}, &escape($type));
    }
       } else {
    @{$allfiles->{$file}} = (&escape($type));
       }
   }
   
 sub removeuploadedurl {  sub removeuploadedurl {
     my ($url)=@_;      my ($url)=@_;
     my (undef,undef,$udom,$uname,$fname)=split('/',$url,5);      my (undef,undef,$udom,$uname,$fname)=split('/',$url,5);
     return &Apache::lonnet::removeuserfile($uname,$udom,$fname);      return &removeuserfile($uname,$udom,$fname);
 }  }
   
 sub removeuserfile {  sub removeuserfile {
Line 1425  sub removeuserfile { Line 1613  sub removeuserfile {
     return &reply("removeuserfile:$docudom/$docuname/$fname",$home);      return &reply("removeuserfile:$docudom/$docuname/$fname",$home);
 }  }
   
   sub mkdiruserfile {
       my ($docuname,$docudom,$dir)=@_;
       my $home=&homeserver($docuname,$docudom);
       return &reply("mkdiruserfile:".&escape("$docudom/$docuname/$dir"),$home);
   }
   
   sub renameuserfile {
       my ($docuname,$docudom,$old,$new)=@_;
       my $home=&homeserver($docuname,$docudom);
       return &reply("renameuserfile:$docudom:$docuname:".&escape("$old").':'.
     &escape("$new"),$home);
   }
   
 # ------------------------------------------------------------------------- Log  # ------------------------------------------------------------------------- Log
   
 sub log {  sub log {
Line 1457  sub flushcourselogs { Line 1658  sub flushcourselogs {
         } else {          } else {
             &logthis('Failed to flush log buffer for '.$crsid);              &logthis('Failed to flush log buffer for '.$crsid);
             if (length($courselogs{$crsid})>40000) {              if (length($courselogs{$crsid})>40000) {
                &logthis("<font color=blue>WARNING: Buffer for ".$crsid.                 &logthis("<font color=\"blue\">WARNING: Buffer for ".$crsid.
                         " exceeded maximum size, deleting.</font>");                          " exceeded maximum size, deleting.</font>");
                delete $courselogs{$crsid};                 delete $courselogs{$crsid};
             }              }
Line 1465  sub flushcourselogs { Line 1666  sub flushcourselogs {
         if ($courseidbuffer{$coursehombuf{$crsid}}) {          if ($courseidbuffer{$coursehombuf{$crsid}}) {
            $courseidbuffer{$coursehombuf{$crsid}}.='&'.             $courseidbuffer{$coursehombuf{$crsid}}.='&'.
  &escape($crsid).'='.&escape($coursedescrbuf{$crsid}).   &escape($crsid).'='.&escape($coursedescrbuf{$crsid}).
                          '='.&escape($courseinstcodebuf{$crsid});                           ':'.&escape($courseinstcodebuf{$crsid}).':'.&escape($courseownerbuf{$crsid}).':'.&escape($coursetypebuf{$crsid});
         } else {          } else {
            $courseidbuffer{$coursehombuf{$crsid}}=             $courseidbuffer{$coursehombuf{$crsid}}=
  &escape($crsid).'='.&escape($coursedescrbuf{$crsid}).   &escape($crsid).'='.&escape($coursedescrbuf{$crsid}).
                          '='.&escape($courseinstcodebuf{$crsid});                           ':'.&escape($courseinstcodebuf{$crsid}).':'.&escape($courseownerbuf{$crsid}).':'.&escape($coursetypebuf{$crsid});
         }              }
     }      }
 #  #
 # Write course id database (reverse lookup) to homeserver of courses   # Write course id database (reverse lookup) to homeserver of courses 
Line 1489  sub flushcourselogs { Line 1690  sub flushcourselogs {
             ($dom,$name,undef)=($entry=~m:___(\w+)/(\w+)/(.*)___count$:);              ($dom,$name,undef)=($entry=~m:___(\w+)/(\w+)/(.*)___count$:);
             if (! defined($dom) || $dom eq '' ||               if (! defined($dom) || $dom eq '' || 
                 ! defined($name) || $name eq '') {                  ! defined($name) || $name eq '') {
                 my $cid = $ENV{'request.course.id'};                  my $cid = $env{'request.course.id'};
                 $dom  = $ENV{'request.'.$cid.'.domain'};                  $dom  = $env{'request.'.$cid.'.domain'};
                 $name = $ENV{'request.'.$cid.'.num'};                  $name = $env{'request.'.$cid.'.num'};
             }              }
             my $value = $accesshash{$entry};              my $value = $accesshash{$entry};
             my (undef,$url,undef) = ($entry =~ /^(.*)___(.*)___count$/);              my (undef,$url,undef) = ($entry =~ /^(.*)___(.*)___count$/);
Line 1528  sub flushcourselogs { Line 1729  sub flushcourselogs {
     delete $userrolehash{$entry};      delete $userrolehash{$entry};
         }          }
     }      }
   #
   # Reverse lookup of domain roles (dc, ad, li, sc, au)
   #
       my %domrolebuffer = ();
       foreach my $entry (keys %domainrolehash) {
           my ($role,$uname,$udom,$runame,$rudom,$rsec)=split/:/,$entry;
           if ($domrolebuffer{$rudom}) {
               $domrolebuffer{$rudom}.='&'.&escape($entry).
                         '='.&escape($domainrolehash{$entry});
           } else {
               $domrolebuffer{$rudom}.=&escape($entry).
                         '='.&escape($domainrolehash{$entry});
           }
           delete $domainrolehash{$entry};
       }
       foreach my $dom (keys(%domrolebuffer)) {
           foreach my $tryserver (keys %libserv) {
               if ($hostdom{$tryserver} eq $dom) {
                   unless (&reply('domroleput:'.$dom.':'.
                     $domrolebuffer{$dom},$tryserver) eq 'ok') {
                       &logthis('Put of domain roles failed for '.$dom.' and  '.$tryserver);
                   }
               }
           }
       }
     $dumpcount++;      $dumpcount++;
 }  }
   
 sub courselog {  sub courselog {
     my $what=shift;      my $what=shift;
     $what=time.':'.$what;      $what=time.':'.$what;
     unless ($ENV{'request.course.id'}) { return ''; }      unless ($env{'request.course.id'}) { return ''; }
     $coursedombuf{$ENV{'request.course.id'}}=      $coursedombuf{$env{'request.course.id'}}=
        $ENV{'course.'.$ENV{'request.course.id'}.'.domain'};         $env{'course.'.$env{'request.course.id'}.'.domain'};
     $coursenumbuf{$ENV{'request.course.id'}}=      $coursenumbuf{$env{'request.course.id'}}=
        $ENV{'course.'.$ENV{'request.course.id'}.'.num'};         $env{'course.'.$env{'request.course.id'}.'.num'};
     $coursehombuf{$ENV{'request.course.id'}}=      $coursehombuf{$env{'request.course.id'}}=
        $ENV{'course.'.$ENV{'request.course.id'}.'.home'};         $env{'course.'.$env{'request.course.id'}.'.home'};
     $coursedescrbuf{$ENV{'request.course.id'}}=      $coursedescrbuf{$env{'request.course.id'}}=
        $ENV{'course.'.$ENV{'request.course.id'}.'.description'};         $env{'course.'.$env{'request.course.id'}.'.description'};
     $courseinstcodebuf{$ENV{'request.course.id'}}=      $courseinstcodebuf{$env{'request.course.id'}}=
        $ENV{'course.'.$ENV{'request.course.id'}.'.internal.coursecode'};         $env{'course.'.$env{'request.course.id'}.'.internal.coursecode'};
     if (defined $courselogs{$ENV{'request.course.id'}}) {      $courseownerbuf{$env{'request.course.id'}}=
  $courselogs{$ENV{'request.course.id'}}.='&'.$what;         $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'};
       $coursetypebuf{$env{'request.course.id'}}=
          $env{'course.'.$env{'request.course.id'}.'.type'};
       if (defined $courselogs{$env{'request.course.id'}}) {
    $courselogs{$env{'request.course.id'}}.='&'.$what;
     } else {      } else {
  $courselogs{$ENV{'request.course.id'}}.=$what;   $courselogs{$env{'request.course.id'}}.=$what;
     }      }
     if (length($courselogs{$ENV{'request.course.id'}})>4048) {      if (length($courselogs{$env{'request.course.id'}})>4048) {
  &flushcourselogs();   &flushcourselogs();
     }      }
 }  }
   
 sub courseacclog {  sub courseacclog {
     my $fnsymb=shift;      my $fnsymb=shift;
     unless ($ENV{'request.course.id'}) { return ''; }      unless ($env{'request.course.id'}) { return ''; }
     my $what=$fnsymb.':'.$ENV{'user.name'}.':'.$ENV{'user.domain'};      my $what=$fnsymb.':'.$env{'user.name'}.':'.$env{'user.domain'};
     if ($fnsymb=~/(problem|exam|quiz|assess|survey|form|page)$/) {      if ($fnsymb=~/(problem|exam|quiz|assess|survey|form|task|page)$/) {
         $what.=':POST';          $what.=':POST';
  foreach (keys %ENV) {          # FIXME: Probably ought to escape things....
    foreach (keys %env) {
             if ($_=~/^form\.(.*)/) {              if ($_=~/^form\.(.*)/) {
  $what.=':'.$1.'='.$ENV{$_};   $what.=':'.$1.'='.$env{$_};
               }
           }
       } elsif ($fnsymb =~ m:^/adm/searchcat:) {
           # FIXME: We should not be depending on a form parameter that someone
           # editing lonsearchcat.pm might change in the future.
           if ($env{'form.phase'} eq 'course_search') {
               $what.= ':POST';
               # FIXME: Probably ought to escape things....
               foreach my $element ('courseexp','crsfulltext','crsrelated',
                                    'crsdiscuss') {
                   $what.=':'.$element.'='.$env{'form.'.$element};
             }              }
         }          }
     }      }
Line 1573  sub courseacclog { Line 1815  sub courseacclog {
 sub countacc {  sub countacc {
     my $url=&declutter(shift);      my $url=&declutter(shift);
     return if (! defined($url) || $url eq '');      return if (! defined($url) || $url eq '');
     unless ($ENV{'request.course.id'}) { return ''; }      unless ($env{'request.course.id'}) { return ''; }
     $accesshash{$ENV{'request.course.id'}.'___'.$url.'___course'}=1;      $accesshash{$env{'request.course.id'}.'___'.$url.'___course'}=1;
     my $key=$$.$processmarker.'_'.$dumpcount.'___'.$url.'___count';      my $key=$$.$processmarker.'_'.$dumpcount.'___'.$url.'___count';
     $accesshash{$key}++;      $accesshash{$key}++;
 }  }
Line 1589  sub linklog { Line 1831  sub linklog {
       
 sub userrolelog {  sub userrolelog {
     my ($trole,$username,$domain,$area,$tstart,$tend)=@_;      my ($trole,$username,$domain,$area,$tstart,$tend)=@_;
     if (($trole=~/^ca/) || ($trole=~/^in/) ||       if (($trole=~/^ca/) || ($trole=~/^aa/) ||
         ($trole=~/^cc/) || ($trole=~/^ep/) ||          ($trole=~/^in/) || ($trole=~/^cc/) ||
         ($trole=~/^cr/) || ($trole=~/^ta/)) {          ($trole=~/^ep/) || ($trole=~/^cr/) ||
           ($trole=~/^ta/)) {
        my (undef,$rudom,$runame,$rsec)=split(/\//,$area);         my (undef,$rudom,$runame,$rsec)=split(/\//,$area);
        $userrolehash         $userrolehash
          {$trole.':'.$username.':'.$domain.':'.$runame.':'.$rudom.':'.$rsec}           {$trole.':'.$username.':'.$domain.':'.$runame.':'.$rudom.':'.$rsec}
                     =$tend.':'.$tstart;                      =$tend.':'.$tstart;
    }      }
       if (($trole=~/^dc/) || ($trole=~/^ad/) ||
           ($trole=~/^li/) || ($trole=~/^li/) ||
           ($trole=~/^au/) || ($trole=~/^dg/) ||
           ($trole=~/^sc/)) {
          my (undef,$rudom,$runame,$rsec)=split(/\//,$area);
          $domainrolehash
            {$trole.':'.$username.':'.$domain.':'.$runame.':'.$rudom.':'.$rsec}
                       = $tend.':'.$tstart;
       }
 }  }
   
 sub get_course_adv_roles {  sub get_course_adv_roles {
     my $cid=shift;      my $cid=shift;
     $cid=$ENV{'request.course.id'} unless (defined($cid));      $cid=$env{'request.course.id'} unless (defined($cid));
     my %coursehash=&coursedescription($cid);      my %coursehash=&coursedescription($cid);
     my %nothide=();      my %nothide=();
     foreach (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {      foreach (split(/\s*\,\s*/,$coursehash{'nothideprivileged'})) {
Line 1617  sub get_course_adv_roles { Line 1869  sub get_course_adv_roles {
         if (($tend) && ($tend<$now)) { next; }          if (($tend) && ($tend<$now)) { next; }
         if (($tstart) && ($now<$tstart)) { next; }          if (($tstart) && ($now<$tstart)) { next; }
         my ($role,$username,$domain,$section)=split(/\:/,$_);          my ($role,$username,$domain,$section)=split(/\:/,$_);
    if ($username eq '' || $domain eq '') { next; }
  if ((&privileged($username,$domain)) &&    if ((&privileged($username,$domain)) && 
     (!$nothide{$username.':'.$domain})) { next; }      (!$nothide{$username.':'.$domain})) { next; }
    if ($role eq 'cr') { next; }
         my $key=&plaintext($role);          my $key=&plaintext($role);
    if ($role =~ /^cr/) {
       $key=(split('/',$role))[3];
    }
         if ($section) { $key.=' (Sec/Grp '.$section.')'; }          if ($section) { $key.=' (Sec/Grp '.$section.')'; }
         if ($returnhash{$key}) {          if ($returnhash{$key}) {
     $returnhash{$key}.=','.$username.':'.$domain;      $returnhash{$key}.=','.$username.':'.$domain;
Line 1632  sub get_course_adv_roles { Line 1889  sub get_course_adv_roles {
   
 sub get_my_roles {  sub get_my_roles {
     my ($uname,$udom)=@_;      my ($uname,$udom)=@_;
     unless (defined($uname)) { $uname=$ENV{'user.name'}; }      unless (defined($uname)) { $uname=$env{'user.name'}; }
     unless (defined($udom)) { $udom=$ENV{'user.domain'}; }      unless (defined($udom)) { $udom=$env{'user.domain'}; }
     my %dumphash=      my %dumphash=
             &dump('nohist_userroles',$udom,$uname);              &dump('nohist_userroles',$udom,$uname);
     my %returnhash=();      my %returnhash=();
Line 1688  sub courseidput { Line 1945  sub courseidput {
 }  }
   
 sub courseiddump {  sub courseiddump {
     my ($domfilter,$descfilter,$sincefilter,$hostidflag,$hostidref)=@_;      my ($domfilter,$descfilter,$sincefilter,$instcodefilter,$ownerfilter,$coursefilter,$hostidflag,$hostidref,$typefilter)=@_;
     my %returnhash=();      my %returnhash=();
     unless ($domfilter) { $domfilter=''; }      unless ($domfilter) { $domfilter=''; }
     foreach my $tryserver (keys %libserv) {      foreach my $tryserver (keys %libserv) {
Line 1696  sub courseiddump { Line 1953  sub courseiddump {
     if ((!$domfilter) || ($hostdom{$tryserver} eq $domfilter)) {      if ((!$domfilter) || ($hostdom{$tryserver} eq $domfilter)) {
         foreach (          foreach (
                  split(/\&/,&reply('courseiddump:'.$hostdom{$tryserver}.':'.                   split(/\&/,&reply('courseiddump:'.$hostdom{$tryserver}.':'.
        $sincefilter.':'.&escape($descfilter),         $sincefilter.':'.&escape($descfilter).':'.
                                  &escape($instcodefilter).':'.&escape($ownerfilter).':'.&escape($coursefilter).':'.&escape($typefilter),
                                $tryserver))) {                                 $tryserver))) {
     my ($key,$value)=split(/\=/,$_);      my ($key,$value)=split(/\=/,$_);
                     if (($key) && ($value)) {                      if (($key) && ($value)) {
Line 1709  sub courseiddump { Line 1967  sub courseiddump {
     return %returnhash;      return %returnhash;
 }  }
   
 #  # ---------------------------------------------------------- DC e-mail
   
   sub dcmailput {
       my ($domain,$msgid,$message,$server)=@_;
       my $status = &Apache::lonnet::critical(
          'dcmailput:'.$domain.':'.&escape($msgid).'='.
          &escape($message),$server);
       return $status;
   }
   
   sub dcmaildump {
       my ($dom,$startdate,$enddate,$senders) = @_;
       my %returnhash=();
       if (exists($domain_primary{$dom})) {
           my $cmd='dcmaildump:'.$dom.':'.&escape($startdate).':'.
                                                            &escape($enddate).':';
    my @esc_senders=map { &escape($_)} @$senders;
    $cmd.=&escape(join('&',@esc_senders));
    foreach (split(/\&/,&reply($cmd,$domain_primary{$dom}))) {
               my ($key,$value) = split(/\=/,$_);
               if (($key) && ($value)) {
                   $returnhash{&unescape($key)} = &unescape($value);
               }
           }
       }
       return %returnhash;
   }
   # ---------------------------------------------------------- Domain roles
   
   sub get_domain_roles {
       my ($dom,$roles,$startdate,$enddate)=@_;
       if (undef($startdate) || $startdate eq '') {
           $startdate = '.';
       }
       if (undef($enddate) || $enddate eq '') {
           $enddate = '.';
       }
       my $rolelist = join(':',@{$roles});
       my %personnel = ();
       foreach my $tryserver (keys(%libserv)) {
           if ($hostdom{$tryserver} eq $dom) {
               %{$personnel{$tryserver}}=();
               foreach (
                   split(/\&/,&reply('domrolesdump:'.$dom.':'.
                      &escape($startdate).':'.&escape($enddate).':'.
                      &escape($rolelist), $tryserver))) {
                   my($key,$value) = split(/\=/,$_);
                   if (($key) && ($value)) {
                       $personnel{$tryserver}{&unescape($key)} = &unescape($value);
                   }
               }
           }
       }
       return %personnel;
   }
   
 # ----------------------------------------------------------- Check out an item  # ----------------------------------------------------------- Check out an item
   
 sub get_first_access {  sub get_first_access {
Line 1717  sub get_first_access { Line 2030  sub get_first_access {
     my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser();      my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser();
     if ($argsymb) { $symb=$argsymb; }      if ($argsymb) { $symb=$argsymb; }
     my ($map,$id,$res)=&decode_symb($symb);      my ($map,$id,$res)=&decode_symb($symb);
     if ($type eq 'map') { $res=$map; }      if ($type eq 'map') {
     my %times=&get('firstaccesstimes',[$res],$udom,$uname);   $res=&symbread($map);
     return $times{$res};      } else {
    $res=$symb;
       }
       my %times=&get('firstaccesstimes',["$courseid\0$res"],$udom,$uname);
       return $times{"$courseid\0$res"};
 }  }
   
 sub set_first_access {  sub set_first_access {
     my ($type)=@_;      my ($type)=@_;
     my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser();      my ($symb,$courseid,$udom,$uname)=&Apache::lonxml::whichuser();
     my ($map,$id,$res)=&decode_symb($symb);      my ($map,$id,$res)=&decode_symb($symb);
     if ($type eq 'map') { $res=$map; }      if ($type eq 'map') {
     my $firstaccess=&get_first_access($type);   $res=&symbread($map);
       } else {
    $res=$symb;
       }
       my $firstaccess=&get_first_access($type,$symb);
     if (!$firstaccess) {      if (!$firstaccess) {
  return &put('firstaccesstimes',{$res=>time},$udom,$uname);   return &put('firstaccesstimes',{"$courseid\0$res"=>time},$udom,$uname);
     }      }
     return 'already_set';      return 'already_set';
 }  }
Line 1747  sub checkout { Line 2068  sub checkout {
  $now.'&'.$ENV{'REMOTE_ADDR'});   $now.'&'.$ENV{'REMOTE_ADDR'});
     my $token=&reply('tmpput:'.$infostr,$lonhost);      my $token=&reply('tmpput:'.$infostr,$lonhost);
     if ($token=~/^error\:/) {       if ($token=~/^error\:/) { 
         &logthis("<font color=blue>WARNING: ".          &logthis("<font color=\"blue\">WARNING: ".
                 "Checkout tmpput failed ".$tudom.' - '.$tuname.' - '.$symb.                  "Checkout tmpput failed ".$tudom.' - '.$tuname.' - '.$symb.
                  "</font>");                   "</font>");
         return '';           return ''; 
Line 1763  sub checkout { Line 2084  sub checkout {
     unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') {      unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') {
        return '';         return '';
     } else {      } else {
         &logthis("<font color=blue>WARNING: ".          &logthis("<font color=\"blue\">WARNING: ".
                 "Checkout cstore failed ".$tudom.' - '.$tuname.' - '.$symb.                  "Checkout cstore failed ".$tudom.' - '.$tuname.' - '.$symb.
                  "</font>");                   "</font>");
     }          }    
Line 1773  sub checkout { Line 2094  sub checkout {
                                                  $token)) ne 'ok') {                                                   $token)) ne 'ok') {
  return '';   return '';
     } else {      } else {
         &logthis("<font color=blue>WARNING: ".          &logthis("<font color=\"blue\">WARNING: ".
                 "Checkout log failed ".$tudom.' - '.$tuname.' - '.$symb.                  "Checkout log failed ".$tudom.' - '.$tuname.' - '.$symb.
                  "</font>");                   "</font>");
     }      }
Line 1787  sub checkin { Line 2108  sub checkin {
     my $now=time;      my $now=time;
     my ($ta,$tb,$lonhost)=split(/\*/,$token);      my ($ta,$tb,$lonhost)=split(/\*/,$token);
     $lonhost=~tr/A-Z/a-z/;      $lonhost=~tr/A-Z/a-z/;
     my $dtoken=$ta.'_'.$hostip{$lonhost}.'_'.$tb;      my $dtoken=$ta.'_'.$hostname{$lonhost}.'_'.$tb;
     $dtoken=~s/\W/\_/g;      $dtoken=~s/\W/\_/g;
     my ($dummy,$tuname,$tudom,$tcrsid,$symb,$chtim,$rmaddr)=      my ($dummy,$tuname,$tudom,$tcrsid,$symb,$chtim,$rmaddr)=
                  split(/\&/,&unescape(&reply('tmpget:'.$dtoken,$lonhost)));                   split(/\&/,&unescape(&reply('tmpget:'.$dtoken,$lonhost)));
Line 1799  sub checkin { Line 2120  sub checkin {
           
     unless (&allowed('mgr',$tcrsid)) {      unless (&allowed('mgr',$tcrsid)) {
         &logthis('Check in '.$token.' ('.$dtoken.') unauthorized: '.          &logthis('Check in '.$token.' ('.$dtoken.') unauthorized: '.
                  $ENV{'user.name'}.' - '.$ENV{'user.domain'});                   $env{'user.name'}.' - '.$env{'user.domain'});
         return '';          return '';
     }      }
   
Line 1823  sub checkin { Line 2144  sub checkin {
   
 sub expirespread {  sub expirespread {
     my ($uname,$udom,$stype,$usymb)=@_;      my ($uname,$udom,$stype,$usymb)=@_;
     my $cid=$ENV{'request.course.id'};       my $cid=$env{'request.course.id'}; 
     if ($cid) {      if ($cid) {
        my $now=time;         my $now=time;
        my $key=$uname.':'.$udom.':'.$stype.':'.$usymb;         my $key=$uname.':'.$udom.':'.$stype.':'.$usymb;
        return &reply('put:'.$ENV{'course.'.$cid.'.domain'}.':'.         return &reply('put:'.$env{'course.'.$cid.'.domain'}.':'.
                             $ENV{'course.'.$cid.'.num'}.                              $env{'course.'.$cid.'.num'}.
             ':nohist_expirationdates:'.              ':nohist_expirationdates:'.
                             &escape($key).'='.$now,                              &escape($key).'='.$now,
                             $ENV{'course.'.$cid.'.home'})                              $env{'course.'.$cid.'.home'})
     }      }
     return 'ok';      return 'ok';
 }  }
Line 1840  sub expirespread { Line 2161  sub expirespread {
   
 sub devalidate {  sub devalidate {
     my ($symb,$uname,$udom)=@_;      my ($symb,$uname,$udom)=@_;
     my $cid=$ENV{'request.course.id'};       my $cid=$env{'request.course.id'}; 
     if ($cid) {      if ($cid) {
         # delete the stored spreadsheets for          # delete the stored spreadsheets for
         # - the student level sheet of this user in course's homespace          # - the student level sheet of this user in course's homespace
         # - the assessment level sheet for this resource           # - the assessment level sheet for this resource 
         #   for this user in user's homespace          #   for this user in user's homespace
    # - current conditional state info
  my $key=$uname.':'.$udom.':';   my $key=$uname.':'.$udom.':';
         my $status=          my $status=
     &del('nohist_calculatedsheets',      &del('nohist_calculatedsheets',
  [$key.'studentcalc:'],   [$key.'studentcalc:'],
  $ENV{'course.'.$cid.'.domain'},   $env{'course.'.$cid.'.domain'},
  $ENV{'course.'.$cid.'.num'})   $env{'course.'.$cid.'.num'})
  .' '.   .' '.
     &del('nohist_calculatedsheets_'.$cid,      &del('nohist_calculatedsheets_'.$cid,
  [$key.'assesscalc:'.$symb],$udom,$uname);   [$key.'assesscalc:'.$symb],$udom,$uname);
Line 1860  sub devalidate { Line 2182  sub devalidate {
                     $uname.' at '.$udom.' for '.                      $uname.' at '.$udom.' for '.
     $symb.': '.$status);      $symb.': '.$status);
         }          }
    &delenv('user.state.'.$cid);
     }      }
 }  }
   
Line 2060  sub tmpreset { Line 2383  sub tmpreset {
   my ($symb,$namespace,$domain,$stuname) = @_;    my ($symb,$namespace,$domain,$stuname) = @_;
   if (!$symb) {    if (!$symb) {
     $symb=&symbread();      $symb=&symbread();
     if (!$symb) { $symb= $ENV{'request.url'}; }      if (!$symb) { $symb= $env{'request.url'}; }
   }    }
   $symb=escape($symb);    $symb=escape($symb);
   
   if (!$namespace) { $namespace=$ENV{'request.state'}; }    if (!$namespace) { $namespace=$env{'request.state'}; }
   $namespace=~s/\//\_/g;    $namespace=~s/\//\_/g;
   $namespace=~s/\W//g;    $namespace=~s/\W//g;
   
   #FIXME needs to do something for /pub resources    if (!$domain) { $domain=$env{'user.domain'}; }
   if (!$domain) { $domain=$ENV{'user.domain'}; }    if (!$stuname) { $stuname=$env{'user.name'}; }
   if (!$stuname) { $stuname=$ENV{'user.name'}; }    if ($domain eq 'public' && $stuname eq 'public') {
         $stuname=$ENV{'REMOTE_ADDR'};
     }
   my $path=$perlvar{'lonDaemons'}.'/tmp';    my $path=$perlvar{'lonDaemons'}.'/tmp';
   my %hash;    my %hash;
   if (tie(%hash,'GDBM_File',    if (tie(%hash,'GDBM_File',
Line 2089  sub tmpstore { Line 2414  sub tmpstore {
   
   if (!$symb) {    if (!$symb) {
     $symb=&symbread();      $symb=&symbread();
     if (!$symb) { $symb= $ENV{'request.url'}; }      if (!$symb) { $symb= $env{'request.url'}; }
   }    }
   $symb=escape($symb);    $symb=escape($symb);
   
   if (!$namespace) {    if (!$namespace) {
     # I don't think we would ever want to store this for a course.      # I don't think we would ever want to store this for a course.
     # it seems this will only be used if we don't have a course.      # it seems this will only be used if we don't have a course.
     #$namespace=$ENV{'request.course.id'};      #$namespace=$env{'request.course.id'};
     #if (!$namespace) {      #if (!$namespace) {
       $namespace=$ENV{'request.state'};        $namespace=$env{'request.state'};
     #}      #}
   }    }
   $namespace=~s/\//\_/g;    $namespace=~s/\//\_/g;
   $namespace=~s/\W//g;    $namespace=~s/\W//g;
 #FIXME needs to do something for /pub resources    if (!$domain) { $domain=$env{'user.domain'}; }
   if (!$domain) { $domain=$ENV{'user.domain'}; }    if (!$stuname) { $stuname=$env{'user.name'}; }
   if (!$stuname) { $stuname=$ENV{'user.name'}; }    if ($domain eq 'public' && $stuname eq 'public') {
         $stuname=$ENV{'REMOTE_ADDR'};
     }
   my $now=time;    my $now=time;
   my %hash;    my %hash;
   my $path=$perlvar{'lonDaemons'}.'/tmp';    my $path=$perlvar{'lonDaemons'}.'/tmp';
Line 2117  sub tmpstore { Line 2444  sub tmpstore {
     my $allkeys='';       my $allkeys=''; 
     foreach my $key (keys(%$storehash)) {      foreach my $key (keys(%$storehash)) {
       $allkeys.=$key.':';        $allkeys.=$key.':';
       $hash{"$version:$symb:$key"}=$$storehash{$key};        $hash{"$version:$symb:$key"}=&freeze_escape($$storehash{$key});
     }      }
     $hash{"$version:$symb:timestamp"}=$now;      $hash{"$version:$symb:timestamp"}=$now;
     $allkeys.='timestamp';      $allkeys.='timestamp';
Line 2139  sub tmprestore { Line 2466  sub tmprestore {
   
   if (!$symb) {    if (!$symb) {
     $symb=&symbread();      $symb=&symbread();
     if (!$symb) { $symb= $ENV{'request.url'}; }      if (!$symb) { $symb= $env{'request.url'}; }
   }    }
   $symb=escape($symb);    $symb=escape($symb);
   
   if (!$namespace) { $namespace=$ENV{'request.state'}; }    if (!$namespace) { $namespace=$env{'request.state'}; }
   #FIXME needs to do something for /pub resources  
   if (!$domain) { $domain=$ENV{'user.domain'}; }  
   if (!$stuname) { $stuname=$ENV{'user.name'}; }  
   
     if (!$domain) { $domain=$env{'user.domain'}; }
     if (!$stuname) { $stuname=$env{'user.name'}; }
     if ($domain eq 'public' && $stuname eq 'public') {
         $stuname=$ENV{'REMOTE_ADDR'};
     }
   my %returnhash;    my %returnhash;
   $namespace=~s/\//\_/g;    $namespace=~s/\//\_/g;
   $namespace=~s/\W//g;    $namespace=~s/\W//g;
Line 2165  sub tmprestore { Line 2494  sub tmprestore {
       my $key;        my $key;
       $returnhash{"$scope:keys"}=$vkeys;        $returnhash{"$scope:keys"}=$vkeys;
       foreach $key (@keys) {        foreach $key (@keys) {
  $returnhash{"$scope:$key"}=$hash{"$scope:$symb:$key"};   $returnhash{"$scope:$key"}=&thaw_unescape($hash{"$scope:$symb:$key"});
  $returnhash{"$key"}=$hash{"$scope:$symb:$key"};   $returnhash{"$key"}=&thaw_unescape($hash{"$scope:$symb:$key"});
       }        }
     }      }
     if (!(untie(%hash))) {      if (!(untie(%hash))) {
Line 2189  sub store { Line 2518  sub store {
     $symb=&symbclean($symb);      $symb=&symbclean($symb);
     if (!$symb) { unless ($symb=&symbread()) { return ''; } }      if (!$symb) { unless ($symb=&symbread()) { return ''; } }
   
     if (!$domain) { $domain=$ENV{'user.domain'}; }      if (!$domain) { $domain=$env{'user.domain'}; }
     if (!$stuname) { $stuname=$ENV{'user.name'}; }      if (!$stuname) { $stuname=$env{'user.name'}; }
   
     &devalidate($symb,$stuname,$domain);      &devalidate($symb,$stuname,$domain);
   
     $symb=escape($symb);      $symb=escape($symb);
     if (!$namespace) {       if (!$namespace) { 
        unless ($namespace=$ENV{'request.course.id'}) {          unless ($namespace=$env{'request.course.id'}) { 
           return '';             return ''; 
        }          } 
     }      }
     if (!$home) { $home=$ENV{'user.home'}; }      if (!$home) { $home=$env{'user.home'}; }
   
     $$storehash{'ip'}=$ENV{'REMOTE_ADDR'};      $$storehash{'ip'}=$ENV{'REMOTE_ADDR'};
     $$storehash{'host'}=$perlvar{'lonHostID'};      $$storehash{'host'}=$perlvar{'lonHostID'};
   
     my $namevalue='';      my $namevalue='';
     foreach (keys %$storehash) {      foreach (keys %$storehash) {
         $namevalue.=escape($_).'='.escape($$storehash{$_}).'&';          $namevalue.=&escape($_).'='.&freeze_escape($$storehash{$_}).'&';
     }      }
     $namevalue=~s/\&$//;      $namevalue=~s/\&$//;
     &courselog($symb.':'.$stuname.':'.$domain.':STORE:'.$namevalue);      &courselog($symb.':'.$stuname.':'.$domain.':STORE:'.$namevalue);
Line 2225  sub cstore { Line 2554  sub cstore {
     $symb=&symbclean($symb);      $symb=&symbclean($symb);
     if (!$symb) { unless ($symb=&symbread()) { return ''; } }      if (!$symb) { unless ($symb=&symbread()) { return ''; } }
   
     if (!$domain) { $domain=$ENV{'user.domain'}; }      if (!$domain) { $domain=$env{'user.domain'}; }
     if (!$stuname) { $stuname=$ENV{'user.name'}; }      if (!$stuname) { $stuname=$env{'user.name'}; }
   
     &devalidate($symb,$stuname,$domain);      &devalidate($symb,$stuname,$domain);
   
     $symb=escape($symb);      $symb=escape($symb);
     if (!$namespace) {       if (!$namespace) { 
        unless ($namespace=$ENV{'request.course.id'}) {          unless ($namespace=$env{'request.course.id'}) { 
           return '';             return ''; 
        }          } 
     }      }
     if (!$home) { $home=$ENV{'user.home'}; }      if (!$home) { $home=$env{'user.home'}; }
   
     $$storehash{'ip'}=$ENV{'REMOTE_ADDR'};      $$storehash{'ip'}=$ENV{'REMOTE_ADDR'};
     $$storehash{'host'}=$perlvar{'lonHostID'};      $$storehash{'host'}=$perlvar{'lonHostID'};
   
     my $namevalue='';      my $namevalue='';
     foreach (keys %$storehash) {      foreach (keys %$storehash) {
         $namevalue.=escape($_).'='.escape($$storehash{$_}).'&';          $namevalue.=&escape($_).'='.&freeze_escape($$storehash{$_}).'&';
     }      }
     $namevalue=~s/\&$//;      $namevalue=~s/\&$//;
     &courselog($symb.':'.$stuname.':'.$domain.':CSTORE:'.$namevalue);      &courselog($symb.':'.$stuname.':'.$domain.':CSTORE:'.$namevalue);
Line 2265  sub restore { Line 2594  sub restore {
       $symb=&escape(&symbclean($symb));        $symb=&escape(&symbclean($symb));
     }      }
     if (!$namespace) {       if (!$namespace) { 
        unless ($namespace=$ENV{'request.course.id'}) {          unless ($namespace=$env{'request.course.id'}) { 
           return '';             return ''; 
        }          } 
     }      }
     if (!$domain) { $domain=$ENV{'user.domain'}; }      if (!$domain) { $domain=$env{'user.domain'}; }
     if (!$stuname) { $stuname=$ENV{'user.name'}; }      if (!$stuname) { $stuname=$env{'user.name'}; }
     if (!$home) { $home=$ENV{'user.home'}; }      if (!$home) { $home=$env{'user.home'}; }
     my $answer=&reply("restore:$domain:$stuname:$namespace:$symb","$home");      my $answer=&reply("restore:$domain:$stuname:$namespace:$symb","$home");
   
     my %returnhash=();      my %returnhash=();
     foreach (split(/\&/,$answer)) {      foreach (split(/\&/,$answer)) {
  my ($name,$value)=split(/\=/,$_);   my ($name,$value)=split(/\=/,$_);
         $returnhash{&unescape($name)}=&unescape($value);          $returnhash{&unescape($name)}=&thaw_unescape($value);
     }      }
     my $version;      my $version;
     for ($version=1;$version<=$returnhash{'version'};$version++) {      for ($version=1;$version<=$returnhash{'version'};$version++) {
Line 2291  sub restore { Line 2620  sub restore {
 # ---------------------------------------------------------- Course Description  # ---------------------------------------------------------- Course Description
   
 sub coursedescription {  sub coursedescription {
     my $courseid=shift;      my ($courseid,$args)=@_;
     $courseid=~s/^\///;      $courseid=~s/^\///;
     $courseid=~s/\_/\//g;      $courseid=~s/\_/\//g;
     my ($cdomain,$cnum)=split(/\//,$courseid);      my ($cdomain,$cnum)=split(/\//,$courseid);
Line 2301  sub coursedescription { Line 2630  sub coursedescription {
     # trying and trying and trying to get the course description.      # trying and trying and trying to get the course description.
     my %envhash=();      my %envhash=();
     my %returnhash=();      my %returnhash=();
     $envhash{'course.'.$normalid.'.last_cache'}=time;      
       my $expiretime=600;
       if ($env{'request.course.id'} eq $normalid) {
    $expiretime=120;
       }
   
       my $prefix='course.'.$cdomain.'_'.$cnum.'.';
       if (!$args->{'freshen_cache'}
    && ((time-$env{$prefix.'last_cache'}) < $expiretime) ) {
    foreach my $key (keys(%env)) {
       next if ($key !~ /^\Q$prefix\E(.*)/);
       my ($setting) = $1;
       $returnhash{$setting} = $env{$key};
    }
    return %returnhash;
       }
   
       # get the data agin
       if (!$args->{'one_time'}) {
    $envhash{'course.'.$normalid.'.last_cache'}=time;
       }
     if ($chome ne 'no_host') {      if ($chome ne 'no_host') {
        %returnhash=&dump('environment',$cdomain,$cnum);         %returnhash=&dump('environment',$cdomain,$cnum);
        if (!exists($returnhash{'con_lost'})) {         if (!exists($returnhash{'con_lost'})) {
            $returnhash{'home'}= $chome;             $returnhash{'home'}= $chome;
    $returnhash{'domain'} = $cdomain;     $returnhash{'domain'} = $cdomain;
    $returnhash{'num'} = $cnum;     $returnhash{'num'} = $cnum;
              if (!defined($returnhash{'type'})) {
                  $returnhash{'type'} = 'Course';
              }
            while (my ($name,$value) = each %returnhash) {             while (my ($name,$value) = each %returnhash) {
                $envhash{'course.'.$normalid.'.'.$name}=$value;                 $envhash{'course.'.$normalid.'.'.$name}=$value;
            }             }
            $returnhash{'url'}=&clutter($returnhash{'url'});             $returnhash{'url'}=&clutter($returnhash{'url'});
            $returnhash{'fn'}=$perlvar{'lonDaemons'}.'/tmp/'.             $returnhash{'fn'}=$perlvar{'lonDaemons'}.'/tmp/'.
        $ENV{'user.name'}.'_'.$cdomain.'_'.$cnum;         $env{'user.name'}.'_'.$cdomain.'_'.$cnum;
            $envhash{'course.'.$normalid.'.home'}=$chome;             $envhash{'course.'.$normalid.'.home'}=$chome;
            $envhash{'course.'.$normalid.'.domain'}=$cdomain;             $envhash{'course.'.$normalid.'.domain'}=$cdomain;
            $envhash{'course.'.$normalid.'.num'}=$cnum;             $envhash{'course.'.$normalid.'.num'}=$cnum;
        }         }
     }      }
     &appenv(%envhash);      if (!$args->{'one_time'}) {
    &appenv(%envhash);
       }
     return %returnhash;      return %returnhash;
 }  }
   
Line 2333  sub privileged { Line 2687  sub privileged {
     my $now=time;      my $now=time;
     if ($rolesdump ne '') {      if ($rolesdump ne '') {
         foreach (split(/&/,$rolesdump)) {          foreach (split(/&/,$rolesdump)) {
     if ($_!~/^rolesdef\&/) {      if ($_!~/^rolesdef_/) {
  my ($area,$role)=split(/=/,$_);   my ($area,$role)=split(/=/,$_);
  $area=~s/\_\w\w$//;   $area=~s/\_\w\w$//;
  my ($trole,$tend,$tstart)=split(/_/,$role);   my ($trole,$tend,$tstart)=split(/_/,$role);
Line 2360  sub rolesinit { Line 2714  sub rolesinit {
     my $rolesdump=reply("dump:$domain:$username:roles",$authhost);      my $rolesdump=reply("dump:$domain:$username:roles",$authhost);
     if (($rolesdump eq 'con_lost') || ($rolesdump eq '')) { return ''; }      if (($rolesdump eq 'con_lost') || ($rolesdump eq '')) { return ''; }
     my %allroles=();      my %allroles=();
     my %thesepriv=();      my %allgroups=();   
     my $now=time;      my $now=time;
     my $userroles="user.login.time=$now\n";      my %userroles = ('user.login.time' => $now);
     my $thesestr;      my $group_privs;
   
     if ($rolesdump ne '') {      if ($rolesdump ne '') {
         foreach (split(/&/,$rolesdump)) {          foreach (split(/&/,$rolesdump)) {
   if ($_!~/^rolesdef\&/) {    if ($_!~/^rolesdef_/) {
             my ($area,$role)=split(/=/,$_);              my ($area,$role)=split(/=/,$_);
             $area=~s/\_\w\w$//;      $area=~s/\_\w\w$//;
             my ($trole,$tend,$tstart)=split(/_/,$role);              my ($trole,$tend,$tstart,$group_privs);
             $userroles.='user.role.'.$trole.'.'.$area.'='.      if ($role=~/^cr/) { 
                         $tstart.'.'.$tend."\n";   if ($role=~m|^(cr/\w+/\w+/[a-zA-Z0-9]+)_(.*)$|) {
 # log the associated role with the area      ($trole,my $trest)=($role=~m|^(cr/\w+/\w+/[a-zA-Z0-9]+)_(.*)$|);
             &userrolelog($trole,$username,$domain,$area,$tstart,$tend);      ($tend,$tstart)=split('_',$trest);
             if ($tend!=0) {   } else {
         if ($tend<$now) {      $trole=$role;
             $trole='';   }
                 }               } elsif ($role =~ m|^gr/|) {
             }                  ($trole,$tend,$tstart) = split(/_/,$role);
             if ($tstart!=0) {                  ($trole,$group_privs) = split(/\//,$trole);
                 if ($tstart>$now) {                  $group_privs = &unescape($group_privs);
                    $trole='';              } else {
                 }   ($trole,$tend,$tstart)=split(/_/,$role);
             }      }
       my %new_role = &set_arearole($trole,$area,$tstart,$tend,$domain,
    $username);
       @userroles{keys(%new_role)} = @new_role{keys(%new_role)};
               if (($tend!=0) && ($tend<$now)) { $trole=''; }
               if (($tstart!=0) && ($tstart>$now)) { $trole=''; }
             if (($area ne '') && ($trole ne '')) {              if (($area ne '') && ($trole ne '')) {
  my $spec=$trole.'.'.$area;   my $spec=$trole.'.'.$area;
  my ($tdummy,$tdomain,$trest)=split(/\//,$area);   my ($tdummy,$tdomain,$trest)=split(/\//,$area);
  if ($trole =~ /^cr\//) {   if ($trole =~ /^cr\//) {
     my ($rdummy,$rdomain,$rauthor,$rrole)=split(/\//,$trole);                      &custom_roleprivs(\%allroles,$trole,$tdomain,$trest,$spec,$area);
      my $homsvr=homeserver($rauthor,$rdomain);                  } elsif ($trole eq 'gr') {
     if ($hostname{$homsvr} ne '') {                      &group_roleprivs(\%allgroups,$area,$group_privs,$tend,$tstart);
  my ($rdummy,$roledef)=  
    &get('roles',["rolesdef_$rrole"],$rdomain,$rauthor);  
   
  if (($rdummy ne 'con_lost') && ($roledef ne '')) {  
     my ($syspriv,$dompriv,$coursepriv)=  
  split(/\_/,$roledef);  
     if (defined($syspriv)) {  
  $allroles{'cm./'}.=':'.$syspriv;  
  $allroles{$spec.'./'}.=':'.$syspriv;  
     }  
     if ($tdomain ne '') {  
  if (defined($dompriv)) {  
     $allroles{'cm./'.$tdomain.'/'}.=':'.$dompriv;  
     $allroles{$spec.'./'.$tdomain.'/'}.=':'.$dompriv;  
  }  
  if ($trest ne '') {  
     if (defined($coursepriv)) {  
  $allroles{'cm.'.$area}.=':'.$coursepriv;  
  $allroles{$spec.'.'.$area}.=':'.$coursepriv;  
     }  
  }  
     }  
  }  
     }  
  } else {   } else {
     if (defined($pr{$trole.':s'})) {                      &standard_roleprivs(\%allroles,$trole,$tdomain,$spec,$trest,$area);
  $allroles{'cm./'}.=':'.$pr{$trole.':s'};  
  $allroles{$spec.'./'}.=':'.$pr{$trole.':s'};  
     }  
     if ($tdomain ne '') {  
  if (defined($pr{$trole.':d'})) {  
     $allroles{'cm./'.$tdomain.'/'}.=':'.$pr{$trole.':d'};  
     $allroles{$spec.'./'.$tdomain.'/'}.=':'.$pr{$trole.':d'};  
  }  
  if ($trest ne '') {  
     if (defined($pr{$trole.':c'})) {  
  $allroles{'cm.'.$area}.=':'.$pr{$trole.':c'};  
  $allroles{$spec.'.'.$area}.=':'.$pr{$trole.':c'};  
     }  
  }  
     }  
  }   }
             }              }
           }             }
           }
           my ($author,$adv) = &set_userprivs(\%userroles,\%allroles,\%allgroups);
           $userroles{'user.adv'}    = $adv;
    $userroles{'user.author'} = $author;
           $env{'user.adv'}=$adv;
       }
       return \%userroles;  
   }
   
   sub set_arearole {
       my ($trole,$area,$tstart,$tend,$domain,$username) = @_;
   # log the associated role with the area
       &userrolelog($trole,$username,$domain,$area,$tstart,$tend);
       return ('user.role.'.$trole.'.'.$area => $tstart.'.'.$tend);
   }
   
   sub custom_roleprivs {
       my ($allroles,$trole,$tdomain,$trest,$spec,$area) = @_;
       my ($rdummy,$rdomain,$rauthor,$rrole)=split(/\//,$trole);
       my $homsvr=homeserver($rauthor,$rdomain);
       if ($hostname{$homsvr} ne '') {
           my ($rdummy,$roledef)=
               &get('roles',["rolesdef_$rrole"],$rdomain,$rauthor);
           if (($rdummy ne 'con_lost') && ($roledef ne '')) {
               my ($syspriv,$dompriv,$coursepriv)=split(/\_/,$roledef);
               if (defined($syspriv)) {
                   $$allroles{'cm./'}.=':'.$syspriv;
                   $$allroles{$spec.'./'}.=':'.$syspriv;
               }
               if ($tdomain ne '') {
                   if (defined($dompriv)) {
                       $$allroles{'cm./'.$tdomain.'/'}.=':'.$dompriv;
                       $$allroles{$spec.'./'.$tdomain.'/'}.=':'.$dompriv;
                   }
                   if (($trest ne '') && (defined($coursepriv))) {
                       $$allroles{'cm.'.$area}.=':'.$coursepriv;
                       $$allroles{$spec.'.'.$area}.=':'.$coursepriv;
                   }
               }
         }          }
         my $adv=0;      }
         my $author=0;  }
         foreach (keys %allroles) {  
             %thesepriv=();  sub group_roleprivs {
             if (($_!~/^st/) && ($_!~/^ta/) && ($_!~/^cm/)) { $adv=1; }      my ($allgroups,$area,$group_privs,$tend,$tstart) = @_;
             if (($_=~/^au/) || ($_=~/^ca/)) { $author=1; }      my $access = 1;
             foreach (split(/:/,$allroles{$_})) {      my $now = time;
                 if ($_ ne '') {      if (($tend!=0) && ($tend<$now)) { $access = 0; }
     my ($privilege,$restrictions)=split(/&/,$_);      if (($tstart!=0) && ($tstart>$now)) { $access=0; }
                     if ($restrictions eq '') {      if ($access) {
  $thesepriv{$privilege}='F';          my ($course,$group) = ($area =~ m|(/\w+/\w+)/([^/]+)$|);
                     } else {          $$allgroups{$course}{$group} .=':'.$group_privs;
                         if ($thesepriv{$privilege} ne 'F') {      }
     $thesepriv{$privilege}.=$restrictions;  }
                         }  
   sub standard_roleprivs {
       my ($allroles,$trole,$tdomain,$spec,$trest,$area) = @_;
       if (defined($pr{$trole.':s'})) {
           $$allroles{'cm./'}.=':'.$pr{$trole.':s'};
           $$allroles{$spec.'./'}.=':'.$pr{$trole.':s'};
       }
       if ($tdomain ne '') {
           if (defined($pr{$trole.':d'})) {
               $$allroles{'cm./'.$tdomain.'/'}.=':'.$pr{$trole.':d'};
               $$allroles{$spec.'./'.$tdomain.'/'}.=':'.$pr{$trole.':d'};
           }
           if (($trest ne '') && (defined($pr{$trole.':c'}))) {
               $$allroles{'cm.'.$area}.=':'.$pr{$trole.':c'};
               $$allroles{$spec.'.'.$area}.=':'.$pr{$trole.':c'};
           }
       }
   }
   
   sub set_userprivs {
       my ($userroles,$allroles,$allgroups) = @_; 
       my $author=0;
       my $adv=0;
       my %grouproles = ();
       if (keys(%{$allgroups}) > 0) {
           foreach my $role (keys %{$allroles}) {
               my ($trole,$area,$sec,$extendedarea);
               if ($role =~ m|^(\w+)\.(/\w+/\w+)(/?\w*)|) {
                   $trole = $1;
                   $area = $2;
                   $sec = $3;
                   $extendedarea = $area.$sec;
                   if (exists($$allgroups{$area})) {
                       foreach my $group (keys(%{$$allgroups{$area}})) {
                           my $spec = $trole.'.'.$extendedarea;
                           $grouproles{$spec.'.'.$area.'/'.$group} = 
                                                   $$allgroups{$area}{$group};
                     }                      }
                 }                  }
             }              }
             $thesestr='';          }
             foreach (keys %thesepriv) { $thesestr.=':'.$_.'&'.$thesepriv{$_}; }      }
             $userroles.='user.priv.'.$_.'='.$thesestr."\n";      foreach (keys(%grouproles)) {
         }          $$allroles{$_} = $grouproles{$_};
         $userroles.='user.adv='.$adv."\n".      }
             'user.author='.$author."\n";      foreach (keys %{$allroles}) {
         $ENV{'user.adv'}=$adv;          my %thesepriv=();
           if (($_=~/^au/) || ($_=~/^ca/)) { $author=1; }
           foreach (split(/:/,$$allroles{$_})) {
               if ($_ ne '') {
                   my ($privilege,$restrictions)=split(/&/,$_);
                   if ($restrictions eq '') {
                       $thesepriv{$privilege}='F';
                   } elsif ($thesepriv{$privilege} ne 'F') {
                       $thesepriv{$privilege}.=$restrictions;
                   }
                   if ($thesepriv{'adv'} eq 'F') { $adv=1; }
               }
           }
           my $thesestr='';
           foreach (keys %thesepriv) { $thesestr.=':'.$_.'&'.$thesepriv{$_}; }
           $userroles->{'user.priv.'.$_} = $thesestr;
     }      }
     return $userroles;        return ($author,$adv);
 }  }
   
 # --------------------------------------------------------------- get interface  # --------------------------------------------------------------- get interface
Line 2475  sub get { Line 2885  sub get {
        $items.=escape($_).'&';         $items.=escape($_).'&';
    }     }
    $items=~s/\&$//;     $items=~s/\&$//;
    if (!$udomain) { $udomain=$ENV{'user.domain'}; }     if (!$udomain) { $udomain=$env{'user.domain'}; }
    if (!$uname) { $uname=$ENV{'user.name'}; }     if (!$uname) { $uname=$env{'user.name'}; }
    my $uhome=&homeserver($uname,$udomain);     my $uhome=&homeserver($uname,$udomain);
   
    my $rep=&reply("get:$udomain:$uname:$namespace:$items",$uhome);     my $rep=&reply("get:$udomain:$uname:$namespace:$items",$uhome);
Line 2487  sub get { Line 2897  sub get {
    my %returnhash=();     my %returnhash=();
    my $i=0;     my $i=0;
    foreach (@$storearr) {     foreach (@$storearr) {
       $returnhash{$_}=unescape($pairs[$i]);        $returnhash{$_}=&thaw_unescape($pairs[$i]);
       $i++;        $i++;
    }     }
    return %returnhash;     return %returnhash;
Line 2502  sub del { Line 2912  sub del {
        $items.=escape($_).'&';         $items.=escape($_).'&';
    }     }
    $items=~s/\&$//;     $items=~s/\&$//;
    if (!$udomain) { $udomain=$ENV{'user.domain'}; }     if (!$udomain) { $udomain=$env{'user.domain'}; }
    if (!$uname) { $uname=$ENV{'user.name'}; }     if (!$uname) { $uname=$env{'user.name'}; }
    my $uhome=&homeserver($uname,$udomain);     my $uhome=&homeserver($uname,$udomain);
   
    return &reply("del:$udomain:$uname:$namespace:$items",$uhome);     return &reply("del:$udomain:$uname:$namespace:$items",$uhome);
Line 2512  sub del { Line 2922  sub del {
 # -------------------------------------------------------------- dump interface  # -------------------------------------------------------------- dump interface
   
 sub dump {  sub dump {
    my ($namespace,$udomain,$uname,$regexp)=@_;     my ($namespace,$udomain,$uname,$regexp,$range)=@_;
    if (!$udomain) { $udomain=$ENV{'user.domain'}; }     if (!$udomain) { $udomain=$env{'user.domain'}; }
    if (!$uname) { $uname=$ENV{'user.name'}; }     if (!$uname) { $uname=$env{'user.name'}; }
    my $uhome=&homeserver($uname,$udomain);     my $uhome=&homeserver($uname,$udomain);
    if ($regexp) {     if ($regexp) {
        $regexp=&escape($regexp);         $regexp=&escape($regexp);
    } else {     } else {
        $regexp='.';         $regexp='.';
    }     }
    my $rep=reply("dump:$udomain:$uname:$namespace:$regexp",$uhome);     my $rep=reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome);
    my @pairs=split(/\&/,$rep);     my @pairs=split(/\&/,$rep);
    my %returnhash=();     my %returnhash=();
    foreach (@pairs) {     foreach (@pairs) {
       my ($key,$value)=split(/=/,$_);        my ($key,$value)=split(/=/,$_,2);
       $returnhash{unescape($key)}=unescape($value);        $returnhash{unescape($key)}=&thaw_unescape($value);
    }     }
    return %returnhash;     return %returnhash;
 }  }
   
   # --------------------------------------------------------- dumpstore interface
   
   sub dumpstore {
      my ($namespace,$udomain,$uname,$regexp,$range)=@_;
      return &dump($namespace,$udomain,$uname,$regexp,$range);
   }
   
 # -------------------------------------------------------------- keys interface  # -------------------------------------------------------------- keys interface
   
 sub getkeys {  sub getkeys {
    my ($namespace,$udomain,$uname)=@_;     my ($namespace,$udomain,$uname)=@_;
    if (!$udomain) { $udomain=$ENV{'user.domain'}; }     if (!$udomain) { $udomain=$env{'user.domain'}; }
    if (!$uname) { $uname=$ENV{'user.name'}; }     if (!$uname) { $uname=$env{'user.name'}; }
    my $uhome=&homeserver($uname,$udomain);     my $uhome=&homeserver($uname,$udomain);
    my $rep=reply("keys:$udomain:$uname:$namespace",$uhome);     my $rep=reply("keys:$udomain:$uname:$namespace",$uhome);
    my @keyarray=();     my @keyarray=();
Line 2549  sub getkeys { Line 2966  sub getkeys {
 # --------------------------------------------------------------- currentdump  # --------------------------------------------------------------- currentdump
 sub currentdump {  sub currentdump {
    my ($courseid,$sdom,$sname)=@_;     my ($courseid,$sdom,$sname)=@_;
    $courseid = $ENV{'request.course.id'} if (! defined($courseid));     $courseid = $env{'request.course.id'} if (! defined($courseid));
    $sdom     = $ENV{'user.domain'}       if (! defined($sdom));     $sdom     = $env{'user.domain'}       if (! defined($sdom));
    $sname    = $ENV{'user.name'}         if (! defined($sname));     $sname    = $env{'user.name'}         if (! defined($sname));
    my $uhome = &homeserver($sname,$sdom);     my $uhome = &homeserver($sname,$sdom);
    my $rep=reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome);     my $rep=reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome);
    return if ($rep =~ /^(error:|no_such_host)/);     return if ($rep =~ /^(error:|no_such_host)/);
Line 2572  sub currentdump { Line 2989  sub currentdump {
            my ($key,$value)=split(/=/,$_);             my ($key,$value)=split(/=/,$_);
            my ($symb,$param) = split(/:/,$key);             my ($symb,$param) = split(/:/,$key);
            $returnhash{&unescape($symb)}->{&unescape($param)} =              $returnhash{&unescape($symb)}->{&unescape($param)} = 
                                                           &unescape($value);                                                          &thaw_unescape($value);
        }         }
    }     }
    return %returnhash;     return %returnhash;
Line 2605  sub convert_dump_to_currentdump{ Line 3022  sub convert_dump_to_currentdump{
     return \%returnhash;      return \%returnhash;
 }  }
   
   # ------------------------------------------------------ critical inc interface
   
   sub cinc {
       return &inc(@_,'critical');
   }
   
 # --------------------------------------------------------------- inc interface  # --------------------------------------------------------------- inc interface
   
 sub inc {  sub inc {
     my ($namespace,$store,$udomain,$uname) = @_;      my ($namespace,$store,$udomain,$uname,$critical) = @_;
     if (!$udomain) { $udomain=$ENV{'user.domain'}; }      if (!$udomain) { $udomain=$env{'user.domain'}; }
     if (!$uname) { $uname=$ENV{'user.name'}; }      if (!$uname) { $uname=$env{'user.name'}; }
     my $uhome=&homeserver($uname,$udomain);      my $uhome=&homeserver($uname,$udomain);
     my $items='';      my $items='';
     if (! ref($store)) {      if (! ref($store)) {
Line 2626  sub inc { Line 3049  sub inc {
         }          }
     }      }
     $items=~s/\&$//;      $items=~s/\&$//;
     return &reply("inc:$udomain:$uname:$namespace:$items",$uhome);      if ($critical) {
    return &critical("inc:$udomain:$uname:$namespace:$items",$uhome);
       } else {
    return &reply("inc:$udomain:$uname:$namespace:$items",$uhome);
       }
 }  }
   
 # --------------------------------------------------------------- put interface  # --------------------------------------------------------------- put interface
   
 sub put {  sub put {
    my ($namespace,$storehash,$udomain,$uname)=@_;     my ($namespace,$storehash,$udomain,$uname)=@_;
    if (!$udomain) { $udomain=$ENV{'user.domain'}; }     if (!$udomain) { $udomain=$env{'user.domain'}; }
    if (!$uname) { $uname=$ENV{'user.name'}; }     if (!$uname) { $uname=$env{'user.name'}; }
    my $uhome=&homeserver($uname,$udomain);     my $uhome=&homeserver($uname,$udomain);
    my $items='';     my $items='';
    foreach (keys %$storehash) {     foreach (keys %$storehash) {
        $items.=&escape($_).'='.&escape($$storehash{$_}).'&';         $items.=&escape($_).'='.&freeze_escape($$storehash{$_}).'&';
    }     }
    $items=~s/\&$//;     $items=~s/\&$//;
    return &reply("put:$udomain:$uname:$namespace:$items",$uhome);     return &reply("put:$udomain:$uname:$namespace:$items",$uhome);
 }  }
   
   # ------------------------------------------------------------ newput interface
   
   sub newput {
      my ($namespace,$storehash,$udomain,$uname)=@_;
      if (!$udomain) { $udomain=$env{'user.domain'}; }
      if (!$uname) { $uname=$env{'user.name'}; }
      my $uhome=&homeserver($uname,$udomain);
      my $items='';
      foreach my $key (keys(%$storehash)) {
          $items.=&escape($key).'='.&freeze_escape($$storehash{$key}).'&';
      }
      $items=~s/\&$//;
      return &reply("newput:$udomain:$uname:$namespace:$items",$uhome);
   }
   
   # ---------------------------------------------------------  putstore interface
   
   sub putstore {
      my ($namespace,$symb,$version,$storehash,$udomain,$uname)=@_;
      if (!$udomain) { $udomain=$env{'user.domain'}; }
      if (!$uname) { $uname=$env{'user.name'}; }
      my $uhome=&homeserver($uname,$udomain);
      my $items='';
      foreach my $key (keys(%$storehash)) {
          $items.= &escape($key).'='.&freeze_escape($storehash->{$key}).'&';
      }
      $items=~s/\&$//;
      my $esc_symb=&escape($symb);
      my $esc_v=&escape($version);
      my $reply =
          &reply("putstore:$udomain:$uname:$namespace:$esc_symb:$esc_v:$items",
         $uhome);
      if ($reply eq 'unknown_cmd') {
          # gfall back to way things use to be done
          return &old_putstore($namespace,$symb,$version,$storehash,$udomain,
       $uname);
      }
      return $reply;
   }
   
   sub old_putstore {
       my ($namespace,$symb,$version,$storehash,$udomain,$uname)=@_;
       if (!$udomain) { $udomain=$env{'user.domain'}; }
       if (!$uname) { $uname=$env{'user.name'}; }
       my $uhome=&homeserver($uname,$udomain);
       my %newstorehash;
       foreach (keys %$storehash) {
    my $key = $version.':'.&escape($symb).':'.$_;
    $newstorehash{$key} = $storehash->{$_};
       }
       my $items='';
       my %allitems = ();
       foreach (keys %newstorehash) {
    if ($_ =~ m/^([^\:]+):([^\:]+):([^\:]+)$/) {
       my $key = $1.':keys:'.$2;
       $allitems{$key} .= $3.':';
    }
    $items.=$_.'='.&freeze_escape($newstorehash{$_}).'&';
       }
       foreach (keys %allitems) {
    $allitems{$_} =~ s/\:$//;
    $items.= $_.'='.$allitems{$_}.'&';
       }
       $items=~s/\&$//;
       return &reply("put:$udomain:$uname:$namespace:$items",$uhome);
   }
   
 # ------------------------------------------------------ critical put interface  # ------------------------------------------------------ critical put interface
   
 sub cput {  sub cput {
    my ($namespace,$storehash,$udomain,$uname)=@_;     my ($namespace,$storehash,$udomain,$uname)=@_;
    if (!$udomain) { $udomain=$ENV{'user.domain'}; }     if (!$udomain) { $udomain=$env{'user.domain'}; }
    if (!$uname) { $uname=$ENV{'user.name'}; }     if (!$uname) { $uname=$env{'user.name'}; }
    my $uhome=&homeserver($uname,$udomain);     my $uhome=&homeserver($uname,$udomain);
    my $items='';     my $items='';
    foreach (keys %$storehash) {     foreach (keys %$storehash) {
        $items.=escape($_).'='.escape($$storehash{$_}).'&';         $items.=&escape($_).'='.&freeze_escape($$storehash{$_}).'&';
    }     }
    $items=~s/\&$//;     $items=~s/\&$//;
    return &critical("put:$udomain:$uname:$namespace:$items",$uhome);     return &critical("put:$udomain:$uname:$namespace:$items",$uhome);
Line 2668  sub eget { Line 3162  sub eget {
        $items.=escape($_).'&';         $items.=escape($_).'&';
    }     }
    $items=~s/\&$//;     $items=~s/\&$//;
    if (!$udomain) { $udomain=$ENV{'user.domain'}; }     if (!$udomain) { $udomain=$env{'user.domain'}; }
    if (!$uname) { $uname=$ENV{'user.name'}; }     if (!$uname) { $uname=$env{'user.name'}; }
    my $uhome=&homeserver($uname,$udomain);     my $uhome=&homeserver($uname,$udomain);
    my $rep=&reply("eget:$udomain:$uname:$namespace:$items",$uhome);     my $rep=&reply("eget:$udomain:$uname:$namespace:$items",$uhome);
    my @pairs=split(/\&/,$rep);     my @pairs=split(/\&/,$rep);
    my %returnhash=();     my %returnhash=();
    my $i=0;     my $i=0;
    foreach (@$storearr) {     foreach (@$storearr) {
       $returnhash{$_}=unescape($pairs[$i]);        $returnhash{$_}=&thaw_unescape($pairs[$i]);
       $i++;        $i++;
    }     }
    return %returnhash;     return %returnhash;
 }  }
   
   # ------------------------------------------------------------ tmpput interface
   sub tmpput {
       my ($storehash,$server)=@_;
       my $items='';
       foreach (keys(%$storehash)) {
    $items.=&escape($_).'='.&freeze_escape($$storehash{$_}).'&';
       }
       $items=~s/\&$//;
       return &reply("tmpput:$items",$server);
   }
   
   # ------------------------------------------------------------ tmpget interface
   sub tmpget {
       my ($token,$server)=@_;
       if (!defined($server)) { $server = $perlvar{'lonHostID'}; }
       my $rep=&reply("tmpget:$token",$server);
       my %returnhash;
       foreach my $item (split(/\&/,$rep)) {
    my ($key,$value)=split(/=/,$item);
    $returnhash{&unescape($key)}=&thaw_unescape($value);
       }
       return %returnhash;
   }
   
   # ------------------------------------------------------------ tmpget interface
   sub tmpdel {
       my ($token,$server)=@_;
       if (!defined($server)) { $server = $perlvar{'lonHostID'}; }
       return &reply("tmpdel:$token",$server);
   }
   
 # ---------------------------------------------- Custom access rule evaluation  # ---------------------------------------------- Custom access rule evaluation
   
 sub customaccess {  sub customaccess {
     my ($priv,$uri)=@_;      my ($priv,$uri)=@_;
     my ($urole,$urealm)=split(/\./,$ENV{'request.role'});      my ($urole,$urealm)=split(/\./,$env{'request.role'});
     $urealm=~s/^\W//;      $urealm=~s/^\W//;
     my ($udom,$ucrs,$usec)=split(/\//,$urealm);      my ($udom,$ucrs,$usec)=split(/\//,$urealm);
     my $access=0;      my $access=0;
Line 2719  sub customaccess { Line 3244  sub customaccess {
 # ------------------------------------------------- Check for a user privilege  # ------------------------------------------------- Check for a user privilege
   
 sub allowed {  sub allowed {
     my ($priv,$uri)=@_;      my ($priv,$uri,$symb)=@_;
       my $ver_orguri=$uri;
     $uri=&deversion($uri);      $uri=&deversion($uri);
     my $orguri=$uri;      my $orguri=$uri;
     $uri=&declutter($uri);      $uri=&declutter($uri);
       
     if (defined($ENV{'allowed.'.$priv})) { return $ENV{'allowed.'.$priv}; }      if (defined($env{'allowed.'.$priv})) { return $env{'allowed.'.$priv}; }
 # Free bre access to adm and meta resources  # Free bre access to adm and meta resources
       if (((($uri=~/^adm\//) && ($uri !~ m|/bulletinboard$|)) 
     if ((($uri=~/^adm\//) || ($uri=~/\.meta$/)) && ($priv eq 'bre')) {   || ($uri=~/\.meta$/)) && ($priv eq 'bre')) {
  return 'F';   return 'F';
     }      }
   
   # Free bre access to user's own portfolio contents
       my ($space,$domain,$name,@dir)=split('/',$uri);
       if (($space=~/^(uploaded|editupload)$/) && ($env{'user.name'} eq $name) && 
    ($env{'user.domain'} eq $domain) && ('portfolio' eq $dir[0])) {
           return 'F';
       }
   
   # bre access to group if user has rgf priv for this group and course.
       if (($space=~/^(uploaded|editupload)$/) && ($dir[0] eq 'groups') 
            && ($dir[2] eq 'portfolio') && ($priv eq 'bre')) {
           if (exists($env{'request.course.id'})) {
               my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
               my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
               if (($domain eq $cdom) && ($name eq $cnum)) {
                   my $courseprivid=$env{'request.course.id'};
                   $courseprivid=~s/\_/\//;
                   if ($env{'user.priv.'.$env{'request.role'}.'./'.$courseprivid
                       .'/'.$dir[1]} =~/rgf\&([^\:]*)/) {
                       return $1; 
                   }
               }
           }
       }
   
 # Free bre to public access  # Free bre to public access
   
     if ($priv eq 'bre') {      if ($priv eq 'bre') {
         my $copyright=&metadata($uri,'copyright');          my $copyright=&metadata($uri,'copyright');
  if (($copyright eq 'public') && (!$ENV{'request.course.id'})) {    if (($copyright eq 'public') && (!$env{'request.course.id'})) { 
            return 'F';              return 'F'; 
         }          }
         if ($copyright eq 'priv') {          if ($copyright eq 'priv') {
             $uri=~/([^\/]+)\/([^\/]+)\//;              $uri=~/([^\/]+)\/([^\/]+)\//;
     unless (($ENV{'user.name'} eq $2) && ($ENV{'user.domain'} eq $1)) {      unless (($env{'user.name'} eq $2) && ($env{'user.domain'} eq $1)) {
  return '';   return '';
             }              }
         }          }
         if ($copyright eq 'domain') {          if ($copyright eq 'domain') {
             $uri=~/([^\/]+)\/([^\/]+)\//;              $uri=~/([^\/]+)\/([^\/]+)\//;
     unless (($ENV{'user.domain'} eq $1) ||      unless (($env{'user.domain'} eq $1) ||
                  ($ENV{'course.'.$ENV{'request.course.id'}.'.domain'} eq $1)) {                   ($env{'course.'.$env{'request.course.id'}.'.domain'} eq $1)) {
  return '';   return '';
             }              }
         }          }
         if ($ENV{'request.role'}=~ /li\.\//) {          if ($env{'request.role'}=~ /li\.\//) {
             # Library role, so allow browsing of resources in this domain.              # Library role, so allow browsing of resources in this domain.
             return 'F';              return 'F';
         }          }
Line 2760  sub allowed { Line 3310  sub allowed {
         }          }
     }      }
     # Domain coordinator is trying to create a course      # Domain coordinator is trying to create a course
     if (($priv eq 'ccc') && ($ENV{'request.role'} =~ /^dc\./)) {      if (($priv eq 'ccc') && ($env{'request.role'} =~ /^dc\./)) {
         # uri is the requested domain in this case.          # uri is the requested domain in this case.
         # comparison to 'request.role.domain' shows if the user has selected          # comparison to 'request.role.domain' shows if the user has selected
         # a role of dc for the domain in question.           # a role of dc for the domain in question.
         return 'F' if ($uri eq $ENV{'request.role.domain'});          return 'F' if ($uri eq $env{'request.role.domain'});
     }      }
   
     my $thisallowed='';      my $thisallowed='';
Line 2773  sub allowed { Line 3323  sub allowed {
   
 # Course  # Course
   
     if ($ENV{'user.priv.'.$ENV{'request.role'}.'./'}=~/\Q$priv\E\&([^\:]*)/) {      if ($env{'user.priv.'.$env{'request.role'}.'./'}=~/\Q$priv\E\&([^\:]*)/) {
        $thisallowed.=$1;         $thisallowed.=$1;
     }      }
   
 # Domain  # Domain
   
     if ($ENV{'user.priv.'.$ENV{'request.role'}.'./'.(split(/\//,$uri))[0].'/'}      if ($env{'user.priv.'.$env{'request.role'}.'./'.(split(/\//,$uri))[0].'/'}
        =~/\Q$priv\E\&([^\:]*)/) {         =~/\Q$priv\E\&([^\:]*)/) {
        $thisallowed.=$1;         $thisallowed.=$1;
     }      }
Line 2789  sub allowed { Line 3339  sub allowed {
     $courseuri=~s/\_(\d)/\/$1/;      $courseuri=~s/\_(\d)/\/$1/;
     $courseuri=~s/^([^\/])/\/$1/;      $courseuri=~s/^([^\/])/\/$1/;
   
     if ($ENV{'user.priv.'.$ENV{'request.role'}.'.'.$courseuri}      if ($env{'user.priv.'.$env{'request.role'}.'.'.$courseuri}
        =~/\Q$priv\E\&([^\:]*)/) {         =~/\Q$priv\E\&([^\:]*)/) {
        $thisallowed.=$1;         $thisallowed.=$1;
     }      }
   
 # URI is an uploaded document for this course  # Group: uri itself is a group
       my $groupuri=$uri;
       $groupuri=~s/^([^\/])/\/$1/;
       if ($env{'user.priv.'.$env{'request.role'}.'.'.$groupuri}
          =~/\Q$priv\E\&([^\:]*)/) {
          $thisallowed.=$1;
       }
   
   # URI is an uploaded document for this course, default permissions don't matter
   # not allowing 'edit' access (editupload) to uploaded course docs
     if (($priv eq 'bre') && ($uri=~m|^uploaded/|)) {      if (($priv eq 'bre') && ($uri=~m|^uploaded/|)) {
  my $refuri=$ENV{'httpref.'.$orguri};   $thisallowed='';
  if ($refuri) {          my ($match)=&is_on_map($uri);
     if ($refuri =~ m|^/adm/|) {          if ($match) {
  $thisallowed='F';              if ($env{'user.priv.'.$env{'request.role'}.'./'}
     }                    =~/\Q$priv\E\&([^\:]*)/) {
  }                  $thisallowed.=$1;
               }
           } else {
               my $refuri = $env{'httpref.'.$orguri} || $env{'httpref.'.$ver_orguri};
               if ($refuri) {
                   if ($refuri =~ m|^/adm/|) {
                       $thisallowed='F';
                   } else {
                       $refuri=&declutter($refuri);
                       my ($match) = &is_on_map($refuri);
                       if ($match) {
                           $thisallowed='F';
                       }
                   }
               }
           }
     }      }
   
 # Full access at system, domain or course-wide level? Exit.  # Full access at system, domain or course-wide level? Exit.
Line 2813  sub allowed { Line 3386  sub allowed {
   
 # If this is generating or modifying users, exit with special codes  # If this is generating or modifying users, exit with special codes
   
     if (':csu:cdc:ccc:cin:cta:cep:ccr:cst:cad:cli:cau:cdg:cca:'=~/\:\Q$priv\E\:/) {      if (':csu:cdc:ccc:cin:cta:cep:ccr:cst:cad:cli:cau:cdg:cca:caa:'=~/\:\Q$priv\E\:/) {
    if (($priv eq 'cca') || ($priv eq 'caa')) {
       my ($audom,$auname)=split('/',$uri);
   # no author name given, so this just checks on the general right to make a co-author in this domain
       unless ($auname) { return $thisallowed; }
   # an author name is given, so we are about to actually make a co-author for a certain account
       if (($auname ne $env{'user.name'} && $env{'request.role'} !~ /^dc\./) ||
    (($audom ne $env{'user.domain'} && $env{'request.role'} !~ /^dc\./) &&
    ($audom ne $env{'request.role.domain'}))) { return ''; }
    }
  return $thisallowed;   return $thisallowed;
     }      }
 #  #
Line 2822  sub allowed { Line 3404  sub allowed {
 # Course: See if uri or referer is an individual resource that is part of   # Course: See if uri or referer is an individual resource that is part of 
 # the course  # the course
   
     if ($ENV{'request.course.id'}) {      if ($env{'request.course.id'}) {
   
        $courseprivid=$ENV{'request.course.id'};         $courseprivid=$env{'request.course.id'};
        if ($ENV{'request.course.sec'}) {         if ($env{'request.course.sec'}) {
           $courseprivid.='/'.$ENV{'request.course.sec'};            $courseprivid.='/'.$env{'request.course.sec'};
        }         }
        $courseprivid=~s/\_/\//;         $courseprivid=~s/\_/\//;
        my $checkreferer=1;         my $checkreferer=1;
        my ($match,$cond)=&is_on_map($uri);         my ($match,$cond)=&is_on_map($uri);
        if ($match) {         if ($match) {
            $statecond=$cond;             $statecond=$cond;
            if ($ENV{'user.priv.'.$ENV{'request.role'}.'./'.$courseprivid}             if ($env{'user.priv.'.$env{'request.role'}.'./'.$courseprivid}
                =~/\Q$priv\E\&([^\:]*)/) {                 =~/\Q$priv\E\&([^\:]*)/) {
                $thisallowed.=$1;                 $thisallowed.=$1;
                $checkreferer=0;                 $checkreferer=0;
Line 2841  sub allowed { Line 3423  sub allowed {
        }         }
                 
        if ($checkreferer) {         if ($checkreferer) {
   my $refuri=$ENV{'httpref.'.$orguri};    my $refuri=$env{'httpref.'.$orguri};
             unless ($refuri) {              unless ($refuri) {
                 foreach (keys %ENV) {                  foreach (keys %env) {
     if ($_=~/^httpref\..*\*/) {      if ($_=~/^httpref\..*\*/) {
  my $pattern=$_;   my $pattern=$_;
                         $pattern=~s/^httpref\.\/res\///;                          $pattern=~s/^httpref\.\/res\///;
                         $pattern=~s/\*/\[\^\/\]\+/g;                          $pattern=~s/\*/\[\^\/\]\+/g;
                         $pattern=~s/\//\\\//g;                          $pattern=~s/\//\\\//g;
                         if ($orguri=~/$pattern/) {                          if ($orguri=~/$pattern/) {
     $refuri=$ENV{$_};      $refuri=$env{$_};
                         }                          }
                     }                      }
                 }                  }
Line 2861  sub allowed { Line 3443  sub allowed {
           my ($match,$cond)=&is_on_map($refuri);            my ($match,$cond)=&is_on_map($refuri);
             if ($match) {              if ($match) {
               my $refstatecond=$cond;                my $refstatecond=$cond;
               if ($ENV{'user.priv.'.$ENV{'request.role'}.'./'.$courseprivid}                if ($env{'user.priv.'.$env{'request.role'}.'./'.$courseprivid}
                   =~/\Q$priv\E\&([^\:]*)/) {                    =~/\Q$priv\E\&([^\:]*)/) {
                   $thisallowed.=$1;                    $thisallowed.=$1;
                   $uri=$refuri;                    $uri=$refuri;
Line 2901  sub allowed { Line 3483  sub allowed {
   
     my $envkey;      my $envkey;
     if ($thisallowed=~/L/) {      if ($thisallowed=~/L/) {
         foreach $envkey (keys %ENV) {          foreach $envkey (keys %env) {
            if ($envkey=~/^user\.role\.(st|ta)\.([^\.]*)/) {             if ($envkey=~/^user\.role\.(st|ta)\.([^\.]*)/) {
                my $courseid=$2;                 my $courseid=$2;
                my $roleid=$1.'.'.$2;                 my $roleid=$1.'.'.$2;
                $courseid=~s/^\///;                 $courseid=~s/^\///;
                my $expiretime=600;                 my $expiretime=600;
                if ($ENV{'request.role'} eq $roleid) {                 if ($env{'request.role'} eq $roleid) {
   $expiretime=120;    $expiretime=120;
                }                 }
        my ($cdom,$cnum,$csec)=split(/\//,$courseid);         my ($cdom,$cnum,$csec)=split(/\//,$courseid);
                my $prefix='course.'.$cdom.'_'.$cnum.'.';                 my $prefix='course.'.$cdom.'_'.$cnum.'.';
                if ((time-$ENV{$prefix.'last_cache'})>$expiretime) {                 if ((time-$env{$prefix.'last_cache'})>$expiretime) {
    &coursedescription($courseid);     &coursedescription($courseid,{'freshen_cache' => 1});
                }                 }
                if (($ENV{$prefix.'res.'.$uri.'.lock.sections'}=~/\,\Q$csec\E\,/)                 if (($env{$prefix.'res.'.$uri.'.lock.sections'}=~/\,\Q$csec\E\,/)
                 || ($ENV{$prefix.'res.'.$uri.'.lock.sections'} eq 'all')) {                  || ($env{$prefix.'res.'.$uri.'.lock.sections'} eq 'all')) {
    if ($ENV{$prefix.'res.'.$uri.'.lock.expire'}>time) {     if ($env{$prefix.'res.'.$uri.'.lock.expire'}>time) {
                        &log($ENV{'user.domain'},$ENV{'user.name'},                         &log($env{'user.domain'},$env{'user.name'},
                             $ENV{'user.home'},                              $env{'user.home'},
                             'Locked by res: '.$priv.' for '.$uri.' due to '.                              'Locked by res: '.$priv.' for '.$uri.' due to '.
                             $cdom.'/'.$cnum.'/'.$csec.' expire '.                              $cdom.'/'.$cnum.'/'.$csec.' expire '.
                             $ENV{$prefix.'priv.'.$priv.'.lock.expire'});                              $env{$prefix.'priv.'.$priv.'.lock.expire'});
        return '';         return '';
                    }                     }
                }                 }
                if (($ENV{$prefix.'priv.'.$priv.'.lock.sections'}=~/\,\Q$csec\E\,/)                 if (($env{$prefix.'priv.'.$priv.'.lock.sections'}=~/\,\Q$csec\E\,/)
                 || ($ENV{$prefix.'priv.'.$priv.'.lock.sections'} eq 'all')) {                  || ($env{$prefix.'priv.'.$priv.'.lock.sections'} eq 'all')) {
    if ($ENV{'priv.'.$priv.'.lock.expire'}>time) {     if ($env{'priv.'.$priv.'.lock.expire'}>time) {
                        &log($ENV{'user.domain'},$ENV{'user.name'},                         &log($env{'user.domain'},$env{'user.name'},
                             $ENV{'user.home'},                              $env{'user.home'},
                             'Locked by priv: '.$priv.' for '.$uri.' due to '.                              'Locked by priv: '.$priv.' for '.$uri.' due to '.
                             $cdom.'/'.$cnum.'/'.$csec.' expire '.                              $cdom.'/'.$cnum.'/'.$csec.' expire '.
                             $ENV{$prefix.'priv.'.$priv.'.lock.expire'});                              $env{$prefix.'priv.'.$priv.'.lock.expire'});
        return '';         return '';
                    }                     }
                }                 }
Line 2945  sub allowed { Line 3527  sub allowed {
 # Rest of the restrictions depend on selected course  # Rest of the restrictions depend on selected course
 #  #
   
     unless ($ENV{'request.course.id'}) {      unless ($env{'request.course.id'}) {
        return '1';         return '1';
     }      }
   
Line 2957  sub allowed { Line 3539  sub allowed {
 # Course preferences  # Course preferences
   
    if ($thisallowed=~/C/) {     if ($thisallowed=~/C/) {
        my $rolecode=(split(/\./,$ENV{'request.role'}))[0];         my $rolecode=(split(/\./,$env{'request.role'}))[0];
        my $unamedom=$ENV{'user.name'}.':'.$ENV{'user.domain'};         my $unamedom=$env{'user.name'}.':'.$env{'user.domain'};
        if ($ENV{'course.'.$ENV{'request.course.id'}.'.'.$priv.'.roles.denied'}         if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.roles.denied'}
    =~/\Q$rolecode\E/) {     =~/\Q$rolecode\E/) {
            &log($ENV{'user.domain'},$ENV{'user.name'},$ENV{'user.host'},     if ($priv ne 'pch') { 
                 'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode.' in '.         &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'.
                 $ENV{'request.course.id'});   'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode.' in '.
    $env{'request.course.id'});
      }
            return '';             return '';
        }         }
   
        if ($ENV{'course.'.$ENV{'request.course.id'}.'.'.$priv.'.users.denied'}         if ($env{'course.'.$env{'request.course.id'}.'.'.$priv.'.users.denied'}
    =~/\Q$unamedom\E/) {     =~/\Q$unamedom\E/) {
            &log($ENV{'user.domain'},$ENV{'user.name'},$ENV{'user.host'},     if ($priv ne 'pch') { 
                 'Denied by user: '.$priv.' for '.$uri.' as '.$unamedom.' in '.         &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.
                 $ENV{'request.course.id'});   'Denied by user: '.$priv.' for '.$uri.' as '.$unamedom.' in '.
    $env{'request.course.id'});
      }
            return '';             return '';
        }         }
    }     }
Line 2979  sub allowed { Line 3565  sub allowed {
 # Resource preferences  # Resource preferences
   
    if ($thisallowed=~/R/) {     if ($thisallowed=~/R/) {
        my $rolecode=(split(/\./,$ENV{'request.role'}))[0];         my $rolecode=(split(/\./,$env{'request.role'}))[0];
        if (&metadata($uri,'roledeny')=~/\Q$rolecode\E/) {         if (&metadata($uri,'roledeny')=~/\Q$rolecode\E/) {
   &log($ENV{'user.domain'},$ENV{'user.name'},$ENV{'user.host'},     if ($priv ne 'pch') { 
                     'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode);         &logthis($env{'user.domain'}.':'.$env{'user.name'}.':'.$env{'user.home'}.':'.
           return '';   'Denied by role: '.$priv.' for '.$uri.' as '.$rolecode);
      }
      return '';
        }         }
    }     }
   
 # Restricted by state or randomout?  # Restricted by state or randomout?
   
    if ($thisallowed=~/X/) {     if ($thisallowed=~/X/) {
       if ($ENV{'acc.randomout'}) {        if ($env{'acc.randomout'}) {
          my $symb=&symbread($uri,1);   if (!$symb) { $symb=&symbread($uri,1); }
          if (($symb) && ($ENV{'acc.randomout'}=~/\&\Q$symb\E\&/)) {            if (($symb) && ($env{'acc.randomout'}=~/\&\Q$symb\E\&/)) { 
             return '';               return ''; 
          }           }
       }        }
Line 3006  sub allowed { Line 3594  sub allowed {
    return 'F';     return 'F';
 }  }
   
   sub split_uri_for_cond {
       my $uri=&deversion(&declutter(shift));
       my @uriparts=split(/\//,$uri);
       my $filename=pop(@uriparts);
       my $pathname=join('/',@uriparts);
       return ($pathname,$filename);
   }
 # --------------------------------------------------- Is a resource on the map?  # --------------------------------------------------- Is a resource on the map?
   
 sub is_on_map {  sub is_on_map {
     my $uri=&declutter(shift);      my ($pathname,$filename) = &split_uri_for_cond(shift);
     $uri=~s/\.\d+\.(\w+)$/\.$1/;  
     my @uriparts=split(/\//,$uri);  
     my $filename=$uriparts[$#uriparts];  
     my $pathname=$uri;  
     $pathname=~s|/\Q$filename\E$||;  
     $pathname=~s/^adm\/wrapper\///;      
     #Trying to find the conditional for the file      #Trying to find the conditional for the file
     my $match=($ENV{'acc.res.'.$ENV{'request.course.id'}.'.'.$pathname}=~      my $match=($env{'acc.res.'.$env{'request.course.id'}.'.'.$pathname}=~
        /\&\Q$filename\E\:([\d\|]+)\&/);         /\&\Q$filename\E\:([\d\|]+)\&/);
     if ($match) {      if ($match) {
  return (1,$1);   return (1,$1);
Line 3036  sub get_symb_from_alias { Line 3625  sub get_symb_from_alias {
 # Must be an alias  # Must be an alias
     my $aliassymb='';      my $aliassymb='';
     my %bighash;      my %bighash;
     if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',      if (tie(%bighash,'GDBM_File',$env{'request.course.fn'}.'.db',
                             &GDBM_READER(),0640)) {                              &GDBM_READER(),0640)) {
         my $rid=$bighash{'mapalias_'.$symb};          my $rid=$bighash{'mapalias_'.$symb};
  if ($rid) {   if ($rid) {
Line 3081  sub definerole { Line 3670  sub definerole {
             }              }
         }          }
     }      }
     my $command="encrypt:rolesput:$ENV{'user.domain'}:$ENV{'user.name'}:".      my $command="encrypt:rolesput:$env{'user.domain'}:$env{'user.name'}:".
                 "$ENV{'user.domain'}:$ENV{'user.name'}:".                  "$env{'user.domain'}:$env{'user.name'}:".
         "rolesdef_$rolename=".          "rolesdef_$rolename=".
                 escape($sysrole.'_'.$domrole.'_'.$courole);                  escape($sysrole.'_'.$domrole.'_'.$courole);
     return reply($command,$ENV{'user.home'});      return reply($command,$env{'user.home'});
   } else {    } else {
     return 'refused';      return 'refused';
   }    }
Line 3147  sub fetch_enrollment_query { Line 3736  sub fetch_enrollment_query {
     $cmd =~ s/%%$//;      $cmd =~ s/%%$//;
     $cmd = &escape($cmd);      $cmd = &escape($cmd);
     my $query = 'fetchenrollment';      my $query = 'fetchenrollment';
     my $queryid=&reply("querysend:".$query.':'.$dom.':'.$ENV{'user.name'}.':'.$cmd,$homeserver);      my $queryid=&reply("querysend:".$query.':'.$dom.':'.$env{'user.name'}.':'.$cmd,$homeserver);
     unless ($queryid=~/^\Q$host\E\_/) { return 'error: '.$queryid; }      unless ($queryid=~/^\Q$host\E\_/) { 
           &logthis('fetch_enrollment_query: invalid queryid: '.$queryid.' for host: '.$host.' and homeserver: '.$homeserver.' context: '.$context.' '.$cnum); 
           return 'error: '.$queryid;
       }
     my $reply = &get_query_reply($queryid);      my $reply = &get_query_reply($queryid);
     my $tries = 1;      my $tries = 1;
     while (($reply=~/^timeout/) && ($tries < $maxtries)) {      while (($reply=~/^timeout/) && ($tries < $maxtries)) {
  $reply = &get_query_reply($queryid);          $reply = &get_query_reply($queryid);
  $tries++;          $tries ++;
     }      }
     if ( ($reply =~/^timeout/) || ($reply =~/^error/) ) {      if ( ($reply =~/^timeout/) || ($reply =~/^error/) ) {
  &logthis('fetch_enrollment_query error: '.$reply.' for '.$dom.' '.          &logthis('fetch_enrollment_query error: '.$reply.' for '.$dom.' '.$env{'user.name'}.' for '.$queryid.' context: '.$context.' '.$cnum.' maxtries: '.$maxtries.' tries: '.$tries);
  $ENV{'user.name'}.' for '.$queryid.' context: '.$context.' '.      } else {
  $cnum.' maxtries: '.$maxtries.' tries: '.$tries);  
     }  
     unless ( ($reply =~/^timeout/) || ($reply =~/^error/) ) {  
         my @responses = split/:/,$reply;          my @responses = split/:/,$reply;
         if ($homeserver eq $perlvar{'lonHostID'}) {          if ($homeserver eq $perlvar{'lonHostID'}) {
             foreach (@responses) {              foreach (@responses) {
Line 3177  sub fetch_enrollment_query { Line 3766  sub fetch_enrollment_query {
                         my $filename = $dom.'_'.$key.'_'.$_.'_classlist.xml';                          my $filename = $dom.'_'.$key.'_'.$_.'_classlist.xml';
                         my $destname = $pathname.'/'.$filename;                          my $destname = $pathname.'/'.$filename;
                         my $xml_classlist = &reply("autoretrieve:".$filename,$homeserver);                          my $xml_classlist = &reply("autoretrieve:".$filename,$homeserver);
                         unless ($xml_classlist =~ /^error/) {                          if ($xml_classlist =~ /^error/) {
                               &logthis('fetch_enrollment_query - autoretrieve error: '.$xml_classlist.' for '.$filename.' from server: '.$homeserver.' '.$context.' '.$cnum);
                           } else {
                             if ( open(FILE,">$destname") ) {                              if ( open(FILE,">$destname") ) {
                                 print FILE &unescape($xml_classlist);                                  print FILE &unescape($xml_classlist);
                                 close(FILE);                                  close(FILE);
                               } else {
                                   &logthis('fetch_enrollment_query - error opening classlist file '.$destname.' '.$context.' '.$cnum);
                             }                              }
                         }                          }
                     }                      }
Line 3220  sub courselog_query { Line 3813  sub courselog_query {
 # end: timestamp  # end: timestamp
 #  #
     my (%filters)=@_;      my (%filters)=@_;
     unless ($ENV{'request.course.id'}) { return 'no_course'; }      unless ($env{'request.course.id'}) { return 'no_course'; }
     if ($filters{'url'}) {      if ($filters{'url'}) {
  $filters{'url'}=&symbclean(&declutter($filters{'url'}));   $filters{'url'}=&symbclean(&declutter($filters{'url'}));
         $filters{'url'}=~s/\.(\w+)$/(\\.\\d+)*\\.$1/;          $filters{'url'}=~s/\.(\w+)$/(\\.\\d+)*\\.$1/;
         $filters{'url'}=~s/\.(\w+)\_\_\_/(\\.\\d+)*\\.$1/;          $filters{'url'}=~s/\.(\w+)\_\_\_/(\\.\\d+)*\\.$1/;
     }      }
     my $cname=$ENV{'course.'.$ENV{'request.course.id'}.'.num'};      my $cname=$env{'course.'.$env{'request.course.id'}.'.num'};
     my $cdom=$ENV{'course.'.$ENV{'request.course.id'}.'.domain'};      my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'};
     return &log_query($cname,$cdom,'courselog',%filters);      return &log_query($cname,$cdom,'courselog',%filters);
 }  }
   
Line 3284  sub auto_create_password { Line 3877  sub auto_create_password {
     return ($authparam,$create_passwd,$authchk);      return ($authparam,$create_passwd,$authchk);
 }  }
   
   sub auto_photo_permission {
       my ($cnum,$cdom,$students) = @_;
       my $homeserver = &homeserver($cnum,$cdom);
       my ($outcome,$perm_reqd,$conditions) = 
    split(/:/,&unescape(&reply('autophotopermission:'.$cdom,$homeserver)),3);
       if ($outcome =~ /^(con_lost|unknown_cmd|no_such_host)$/) {
    return (undef,undef);
       }
       return ($outcome,$perm_reqd,$conditions);
   }
   
   sub auto_checkphotos {
       my ($uname,$udom,$pid) = @_;
       my $homeserver = &homeserver($uname,$udom);
       my ($result,$resulttype);
       my $outcome = &unescape(&reply('autophotocheck:'.&escape($udom).':'.
      &escape($uname).':'.&escape($pid),
      $homeserver));
       if ($outcome =~ /^(con_lost|unknown_cmd|no_such_host)$/) {
    return (undef,undef);
       }
       if ($outcome) {
           ($result,$resulttype) = split(/:/,$outcome);
       } 
       return ($result,$resulttype);
   }
   
   sub auto_photochoice {
       my ($cnum,$cdom) = @_;
       my $homeserver = &homeserver($cnum,$cdom);
       my ($update,$comment) = split(/:/,&unescape(&reply('autophotochoice:'.
          &escape($cdom),
          $homeserver)));
       if ($update =~ /^(con_lost|unknown_cmd|no_such_host)$/) {
    return (undef,undef);
       }
       return ($update,$comment);
   }
   
   sub auto_photoupdate {
       my ($affiliatesref,$dom,$cnum,$photo) = @_;
       my $homeserver = &homeserver($cnum,$dom);
       my $host=$hostname{$homeserver};
       my $cmd = '';
       my $maxtries = 1;
       foreach (keys %{$affiliatesref}) {
           $cmd .= $_.'='.join(",",@{$$affiliatesref{$_}}).'%%';
       }
       $cmd =~ s/%%$//;
       $cmd = &escape($cmd);
       my $query = 'institutionalphotos';
       my $queryid=&reply("querysend:".$query.':'.$dom.':'.$cnum.':'.$cmd,$homeserver);
       unless ($queryid=~/^\Q$host\E\_/) {
           &logthis('institutionalphotos: invalid queryid: '.$queryid.' for host: '.$host.' and homeserver: '.$homeserver.' and course: '.$cnum);
           return 'error: '.$queryid;
       }
       my $reply = &get_query_reply($queryid);
       my $tries = 1;
       while (($reply=~/^timeout/) && ($tries < $maxtries)) {
           $reply = &get_query_reply($queryid);
           $tries ++;
       }
       if ( ($reply =~/^timeout/) || ($reply =~/^error/) ) {
           &logthis('institutionalphotos error: '.$reply.' for '.$dom.' '.$env{'user.name'}.' for '.$queryid.' course: '.$cnum.' maxtries: '.$maxtries.' tries: '.$tries);
       } else {
           my @responses = split(/:/,$reply);
           my $outcome = shift(@responses); 
           foreach my $item (@responses) {
               my ($key,$value) = split(/=/,$item);
               $$photo{$key} = $value;
           }
           return $outcome;
       }
       return 'error';
   }
   
 sub auto_instcode_format {  sub auto_instcode_format {
     my ($caller,$codedom,$instcodes,$codes,$codetitles,$cat_titles,$cat_order) = @_;      my ($caller,$codedom,$instcodes,$codes,$codetitles,$cat_titles,$cat_order) = @_;
     my $courses = '';      my $courses = '';
     my $homeserver;      my $homeserver;
     if ($caller eq 'global') {      if ($caller eq 'global') {
         $homeserver = $perlvar{'lonHostID'};          foreach my $tryserver (keys %libserv) {
               if ($hostdom{$tryserver} eq $codedom) {
                   $homeserver = $tryserver;
                   last;
               }
           }
           if (($env{'user.name'}) && ($env{'user.domain'} eq $codedom)) {
               $homeserver = &homeserver($env{'user.name'},$codedom);
           }
     } else {      } else {
         $homeserver = &homeserver($caller,$codedom);          $homeserver = &homeserver($caller,$codedom);
     }      }
     my $host=$hostname{$homeserver};  
     foreach (keys %{$instcodes}) {      foreach (keys %{$instcodes}) {
         $courses .= &escape($_).'='.&escape($$instcodes{$_}).'&';          $courses .= &escape($_).'='.&escape($$instcodes{$_}).'&';
     }      }
Line 3310  sub auto_instcode_format { Line 3986  sub auto_instcode_format {
     return $response;      return $response;
 }  }
   
   # ------------------------------------------------------- Course Group routines
   
   sub get_coursegroups {
       my ($cdom,$cnum,$group) = @_;
       return(&dump('coursegroups',$cdom,$cnum,$group));
   }
   
   sub modify_coursegroup {
       my ($cdom,$cnum,$groupsettings) = @_;
       return(&put('coursegroups',$groupsettings,$cdom,$cnum));
   }
   
   sub modify_group_roles {
       my ($cdom,$cnum,$group_id,$user,$end,$start,$userprivs) = @_;
       my $url = '/'.$cdom.'/'.$cnum.'/'.$group_id;
       my $role = 'gr/'.&escape($userprivs);
       my ($uname,$udom) = split(/:/,$user);
       my $result = &assignrole($udom,$uname,$url,$role,$end,$start);
       if ($result eq 'ok') {
           &devalidate_getgroups_cache($udom,$uname,$cdom,$cnum);
       }
       return $result;
   }
   
   sub modify_coursegroup_membership {
       my ($cdom,$cnum,$membership) = @_;
       my $result = &put('groupmembership',$membership,$cdom,$cnum);
       return $result;
   }
   
   sub get_active_groups {
       my ($udom,$uname,$cdom,$cnum) = @_;
       my $now = time;
       my %groups = ();
       foreach my $key (keys(%env)) {
           if ($key =~ m-user\.role\.gr\./([^/]+)/([^/]+)/(\w+)$-) {
               my ($start,$end) = split(/\./,$env{$key});
               if (($end!=0) && ($end<$now)) { next; }
               if (($start!=0) && ($start>$now)) { next; }
               if ($1 eq $cdom && $2 eq $cnum) {
                   $groups{$3} = $env{$key} ;
               }
           }
       }
       return %groups;
   }
   
   sub get_group_membership {
       my ($cdom,$cnum,$group) = @_;
       return(&dump('groupmembership',$cdom,$cnum,$group));
   }
   
   sub get_users_groups {
       my ($udom,$uname,$courseid) = @_;
       my @usersgroups;
       my $cachetime=1800;
       $courseid=~s/\_/\//g;
       $courseid=~s/^(\w)/\/$1/;
   
       my $hashid="$udom:$uname:$courseid";
       my ($grouplist,$cached)=&is_cached_new('getgroups',$hashid);
       if (defined($cached)) {
           @usersgroups = split(/:/,$grouplist);
       } else {  
           $grouplist = '';
           my %roleshash = &dump('roles',$udom,$uname,$courseid);
           my ($tmp) = keys(%roleshash);
           if ($tmp=~/^error:/) {
               &logthis('Error retrieving roles: '.$tmp.' for '.$uname.':'.$udom);
           } else {
               my $access_end = $env{'course.'.$courseid.
                                     '.default_enrollment_end_date'};
               my $now = time;
               foreach my $key (keys(%roleshash)) {
                   if ($key =~ /^\Q$courseid\E\/(\w+)\_gr$/) {
                       my $group = $1;
                       if ($roleshash{$key} =~ /_(\d+)_(\d+)$/) {
                           my $start = $2;
                           my $end = $1;
                           if ($start == -1) { next; } # deleted from group
                           if (($start!=0) && ($start>$now)) { next; }
                           if (($end!=0) && ($end<$now)) {
                               if ($access_end && $access_end < $now) {
                                   if ($access_end - $end < 86400) {
                                       push(@usersgroups,$group);
                                   }
                               }
                               next;
                           }
                           push(@usersgroups,$group);
                       }
                   }
               }
               @usersgroups = &sort_course_groups($courseid,@usersgroups);
               $grouplist = join(':',@usersgroups);
               &do_cache_new('getgroups',$hashid,$grouplist,$cachetime);
           }
       }
       return @usersgroups;
   }
   
   sub devalidate_getgroups_cache {
       my ($udom,$uname,$cdom,$cnum)=@_;
       my $courseid = $cdom.'_'.$cnum;
       $courseid=~s/\_/\//g;
       $courseid=~s/^(\w)/\/$1/;
       my $hashid="$udom:$uname:$courseid";
       &devalidate_cache_new('getgroups',$hashid);
   }
   
 # ------------------------------------------------------------------ Plain Text  # ------------------------------------------------------------------ Plain Text
   
 sub plaintext {  sub plaintext {
     my $short=shift;      my ($short,$type,$cid) = @_;
     return &mt($prp{$short});      if (!defined($cid)) {
           $cid = $env{'request.course.id'};
       }
       if (defined($cid) && defined($env{'course.'.$cid.'.'.$short.'.plaintext'})) {
           return &Apache::lonlocal::mt($env{'course.'.$cid.'.'.$short.
                                             '.plaintext'});
       }
       my %rolenames = (
                         Course => 'std',
                         Group => 'alt1',
                       );
       if (defined($type) && 
            defined($rolenames{$type}) && 
            defined($prp{$short}{$rolenames{$type}})) {
           return &Apache::lonlocal::mt($prp{$short}{$rolenames{$type}});
       } else {
           return &Apache::lonlocal::mt($prp{$short}{'std'});
       }
 }  }
   
 # ----------------------------------------------------------------- Assign Role  # ----------------------------------------------------------------- Assign Role
Line 3328  sub assignrole { Line 4131  sub assignrole {
  unless (&allowed('ccr',$cwosec)) {   unless (&allowed('ccr',$cwosec)) {
            &logthis('Refused custom assignrole: '.             &logthis('Refused custom assignrole: '.
              $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start.' by '.               $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start.' by '.
     $ENV{'user.name'}.' at '.$ENV{'user.domain'});      $env{'user.name'}.' at '.$env{'user.domain'});
            return 'refused';              return 'refused'; 
         }          }
         $mrole='cr';          $mrole='cr';
       } elsif ($role =~ /^gr\//) {
           my $cwogrp=$url;
           $cwogrp=~s/^\/(\w+)\/(\w+)\/.*/$1\/$2/;
           unless (&allowed('mdg',$cwogrp)) {
               &logthis('Refused group assignrole: '.
                 $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start.' by '.
                       $env{'user.name'}.' at '.$env{'user.domain'});
               return 'refused';
           }
           $mrole='gr';
     } else {      } else {
         my $cwosec=$url;          my $cwosec=$url;
         $cwosec=~s/^\/(\w+)\/(\w+)\/.*/$1\/$2/;          $cwosec=~s/^\/(\w+)\/(\w+)\/.*/$1\/$2/;
         unless ((&allowed('c'.$role,$cwosec)) || &allowed('c'.$role,$udom)) {           unless ((&allowed('c'.$role,$cwosec)) || &allowed('c'.$role,$udom)) { 
            &logthis('Refused assignrole: '.             &logthis('Refused assignrole: '.
              $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start.' by '.               $udom.' '.$uname.' '.$url.' '.$role.' '.$end.' '.$start.' by '.
     $ENV{'user.name'}.' at '.$ENV{'user.domain'});      $env{'user.name'}.' at '.$env{'user.domain'});
            return 'refused';              return 'refused'; 
         }          }
         $mrole=$role;          $mrole=$role;
     }      }
     my $command="encrypt:rolesput:$ENV{'user.domain'}:$ENV{'user.name'}:".      my $command="encrypt:rolesput:$env{'user.domain'}:$env{'user.name'}:".
                 "$udom:$uname:$url".'_'."$mrole=$role";                  "$udom:$uname:$url".'_'."$mrole=$role";
     if ($end) { $command.='_'.$end; }      if ($end) { $command.='_'.$end; }
     if ($start) {      if ($start) {
Line 3353  sub assignrole { Line 4166  sub assignrole {
            $command.='_0_'.$start;             $command.='_0_'.$start;
         }          }
     }      }
       my $origstart = $start;
       my $origend = $end;
 # actually delete  # actually delete
     if ($deleteflag) {      if ($deleteflag) {
  if ((&allowed('dro',$udom)) || (&allowed('dro',$url))) {   if ((&allowed('dro',$udom)) || (&allowed('dro',$url))) {
 # modify command to delete the role  # modify command to delete the role
            $command="encrypt:rolesdel:$ENV{'user.domain'}:$ENV{'user.name'}:".             $command="encrypt:rolesdel:$env{'user.domain'}:$env{'user.name'}:".
                 "$udom:$uname:$url".'_'."$mrole";                  "$udom:$uname:$url".'_'."$mrole";
    &logthis("$ENV{'user.name'} at $ENV{'user.domain'} deletes $mrole in $url for $uname at $udom");      &logthis("$env{'user.name'} at $env{'user.domain'} deletes $mrole in $url for $uname at $udom"); 
 # set start and finish to negative values for userrolelog  # set start and finish to negative values for userrolelog
            $start=-1;             $start=-1;
            $end=-1;             $end=-1;
Line 3369  sub assignrole { Line 4184  sub assignrole {
     my $answer=&reply($command,&homeserver($uname,$udom));      my $answer=&reply($command,&homeserver($uname,$udom));
 # log new user role if status is ok  # log new user role if status is ok
     if ($answer eq 'ok') {      if ($answer eq 'ok') {
  &userrolelog($mrole,$uname,$udom,$url,$start,$end);   &userrolelog($role,$uname,$udom,$url,$start,$end);
   # for course roles, perform group memberships changes triggered by role change.
           unless ($role =~ /^gr/) {
               &Apache::longroup::group_changes($udom,$uname,$url,$role,$origend,
                                                $origstart);
           }
     }      }
     return $answer;      return $answer;
 }  }
Line 3382  sub modifyuserauth { Line 4202  sub modifyuserauth {
     my $uhome=&homeserver($uname,$udom);      my $uhome=&homeserver($uname,$udom);
     unless (&allowed('mau',$udom)) { return 'refused'; }      unless (&allowed('mau',$udom)) { return 'refused'; }
     &logthis('Call to modify user authentication '.$udom.', '.$uname.', '.      &logthis('Call to modify user authentication '.$udom.', '.$uname.', '.
              $umode.' by '.$ENV{'user.name'}.' at '.$ENV{'user.domain'}.               $umode.' by '.$env{'user.name'}.' at '.$env{'user.domain'}.
              ' in domain '.$ENV{'request.role.domain'});                 ' in domain '.$env{'request.role.domain'});  
     my $reply=&reply('encrypt:changeuserauth:'.$udom.':'.$uname.':'.$umode.':'.      my $reply=&reply('encrypt:changeuserauth:'.$udom.':'.$uname.':'.$umode.':'.
      &escape($upass),$uhome);       &escape($upass),$uhome);
     &log($ENV{'user.domain'},$ENV{'user.name'},$ENV{'user.home'},      &log($env{'user.domain'},$env{'user.name'},$env{'user.home'},
         'Authentication changed for '.$udom.', '.$uname.', '.$umode.          'Authentication changed for '.$udom.', '.$uname.', '.$umode.
          '(Remote '.$ENV{'REMOTE_ADDR'}.'): '.$reply);           '(Remote '.$ENV{'REMOTE_ADDR'}.'): '.$reply);
     &log($udom,,$uname,$uhome,      &log($udom,,$uname,$uhome,
         'Authentication changed by '.$ENV{'user.domain'}.', '.          'Authentication changed by '.$env{'user.domain'}.', '.
                                      $ENV{'user.name'}.', '.$umode.                                       $env{'user.name'}.', '.$umode.
          '(Remote '.$ENV{'REMOTE_ADDR'}.'): '.$reply);           '(Remote '.$ENV{'REMOTE_ADDR'}.'): '.$reply);
     unless ($reply eq 'ok') {      unless ($reply eq 'ok') {
         &logthis('Authentication mode error: '.$reply);          &logthis('Authentication mode error: '.$reply);
Line 3414  sub modifyuser { Line 4234  sub modifyuser {
      $last.', '.$gene.'(forceid: '.$forceid.')'.       $last.', '.$gene.'(forceid: '.$forceid.')'.
              (defined($desiredhome) ? ' desiredhome = '.$desiredhome :               (defined($desiredhome) ? ' desiredhome = '.$desiredhome :
                                      ' desiredhome not specified').                                        ' desiredhome not specified'). 
              ' by '.$ENV{'user.name'}.' at '.$ENV{'user.domain'}.               ' by '.$env{'user.name'}.' at '.$env{'user.domain'}.
              ' in domain '.$ENV{'request.role.domain'});               ' in domain '.$env{'request.role.domain'});
     my $uhome=&homeserver($uname,$udom,'true');      my $uhome=&homeserver($uname,$udom,'true');
 # ----------------------------------------------------------------- Create User  # ----------------------------------------------------------------- Create User
     if (($uhome eq 'no_host') &&       if (($uhome eq 'no_host') && 
Line 3423  sub modifyuser { Line 4243  sub modifyuser {
         my $unhome='';          my $unhome='';
         if (defined($desiredhome) && $hostdom{$desiredhome} eq $udom) {           if (defined($desiredhome) && $hostdom{$desiredhome} eq $udom) { 
             $unhome = $desiredhome;              $unhome = $desiredhome;
  } elsif($ENV{'course.'.$ENV{'request.course.id'}.'.domain'} eq $udom) {   } elsif($env{'course.'.$env{'request.course.id'}.'.domain'} eq $udom) {
     $unhome=$ENV{'course.'.$ENV{'request.course.id'}.'.home'};      $unhome=$env{'course.'.$env{'request.course.id'}.'.home'};
         } else { # load balancing routine for determining $unhome          } else { # load balancing routine for determining $unhome
             my $tryserver;              my $tryserver;
             my $loadm=10000000;              my $loadm=10000000;
Line 3484  sub modifyuser { Line 4304  sub modifyuser {
     if (defined($middle)) { $names{'middlename'} = $middle; }      if (defined($middle)) { $names{'middlename'} = $middle; }
     if ($last)   { $names{'lastname'}   = $last; }      if ($last)   { $names{'lastname'}   = $last; }
     if (defined($gene))   { $names{'generation'} = $gene; }      if (defined($gene))   { $names{'generation'} = $gene; }
     if ($email)  { $names{'notification'} = $email;      if ($email) {
                    $names{'critnotification'} = $email; }         $email=~s/[^\w\@\.\-\,]//gs;
          if ($email=~/\@/) { $names{'notification'} = $email;
      $names{'critnotification'} = $email;
      $names{'permanentemail'} = $email; }
       }
     my $reply = &put('environment', \%names, $udom,$uname);      my $reply = &put('environment', \%names, $udom,$uname);
     if ($reply ne 'ok') { return 'error: '.$reply; }      if ($reply ne 'ok') { return 'error: '.$reply; }
       &devalidate_cache_new('namescache',$uname.':'.$udom);
     &logthis('Success modifying user '.$udom.', '.$uname.', '.$uid.', '.      &logthis('Success modifying user '.$udom.', '.$uname.', '.$uid.', '.
              $umode.', '.$first.', '.$middle.', '.               $umode.', '.$first.', '.$middle.', '.
      $last.', '.$gene.' by '.       $last.', '.$gene.' by '.
              $ENV{'user.name'}.' at '.$ENV{'user.domain'});               $env{'user.name'}.' at '.$env{'user.domain'});
     return 'ok';      return 'ok';
 }  }
   
Line 3502  sub modifystudent { Line 4326  sub modifystudent {
     my ($udom,$uname,$uid,$umode,$upass,$first,$middle,$last,$gene,$usec,      my ($udom,$uname,$uid,$umode,$upass,$first,$middle,$last,$gene,$usec,
         $end,$start,$forceid,$desiredhome,$email,$type,$locktype,$cid)=@_;          $end,$start,$forceid,$desiredhome,$email,$type,$locktype,$cid)=@_;
     if (!$cid) {      if (!$cid) {
  unless ($cid=$ENV{'request.course.id'}) {   unless ($cid=$env{'request.course.id'}) {
     return 'not_in_class';      return 'not_in_class';
  }   }
     }      }
Line 3523  sub modify_student_enrollment { Line 4347  sub modify_student_enrollment {
     my ($udom,$uname,$uid,$first,$middle,$last,$gene,$usec,$end,$start,$type,$locktype,$cid) = @_;      my ($udom,$uname,$uid,$first,$middle,$last,$gene,$usec,$end,$start,$type,$locktype,$cid) = @_;
     my ($cdom,$cnum,$chome);      my ($cdom,$cnum,$chome);
     if (!$cid) {      if (!$cid) {
  unless ($cid=$ENV{'request.course.id'}) {   unless ($cid=$env{'request.course.id'}) {
     return 'not_in_class';      return 'not_in_class';
  }   }
  $cdom=$ENV{'course.'.$cid.'.domain'};   $cdom=$env{'course.'.$cid.'.domain'};
  $cnum=$ENV{'course.'.$cid.'.num'};   $cnum=$env{'course.'.$cid.'.num'};
     } else {      } else {
  ($cdom,$cnum)=split(/_/,$cid);   ($cdom,$cnum)=split(/_/,$cid);
     }      }
     $chome=$ENV{'course.'.$cid.'.home'};      $chome=$env{'course.'.$cid.'.home'};
     if (!$chome) {      if (!$chome) {
  $chome=&homeserver($cnum,$cdom);   $chome=&homeserver($cnum,$cdom);
     }      }
Line 3562  sub modify_student_enrollment { Line 4386  sub modify_student_enrollment {
         $gene   = $tmp{'generation'} if (!defined($gene)   || $gene eq '');          $gene   = $tmp{'generation'} if (!defined($gene)   || $gene eq '');
         $uid    = $tmp{'id'}         if (!defined($uid)    || $uid  eq '');          $uid    = $tmp{'id'}         if (!defined($uid)    || $uid  eq '');
     }      }
     my $fullname = &Apache::loncoursedata::ProcessFullName($last,$gene,      my $fullname = &format_name($first,$middle,$last,$gene,'lastname');
                                                            $first,$middle);  
     my $reply=cput('classlist',      my $reply=cput('classlist',
    {"$uname:$udom" =>      {"$uname:$udom" => 
  join(':',$end,$start,$uid,$usec,$fullname,$type,$locktype) },   join(':',$end,$start,$uid,$usec,$fullname,$type,$locktype) },
    $cdom,$cnum);     $cdom,$cnum);
     unless (($reply eq 'ok') || ($reply eq 'delayed')) {      unless (($reply eq 'ok') || ($reply eq 'delayed')) {
  return 'error: '.$reply;   return 'error: '.$reply;
       } else {
    &devalidate_getsection_cache($udom,$uname,$cid);
     }      }
     # Add student role to user      # Add student role to user
     my $uurl='/'.$cid;      my $uurl='/'.$cid;
Line 3580  sub modify_student_enrollment { Line 4405  sub modify_student_enrollment {
     return &assignrole($udom,$uname,$uurl,'st',$end,$start);      return &assignrole($udom,$uname,$uurl,'st',$end,$start);
 }  }
   
   sub format_name {
       my ($firstname,$middlename,$lastname,$generation,$first)=@_;
       my $name;
       if ($first ne 'lastname') {
    $name=$firstname.' '.$middlename.' '.$lastname.' '.$generation;
       } else {
    if ($lastname=~/\S/) {
       $name.= $lastname.' '.$generation.', '.$firstname.' '.$middlename;
       $name=~s/\s+,/,/;
    } else {
       $name.= $firstname.' '.$middlename.' '.$generation;
    }
       }
       $name=~s/^\s+//;
       $name=~s/\s+$//;
       $name=~s/\s+/ /g;
       return $name;
   }
   
 # ------------------------------------------------- Write to course preferences  # ------------------------------------------------- Write to course preferences
   
 sub writecoursepref {  sub writecoursepref {
Line 3602  sub writecoursepref { Line 4446  sub writecoursepref {
 # ---------------------------------------------------------- Make/modify course  # ---------------------------------------------------------- Make/modify course
   
 sub createcourse {  sub createcourse {
     my ($udom,$description,$url,$course_server,$nonstandard,$inst_code)=@_;      my ($udom,$description,$url,$course_server,$nonstandard,$inst_code,
           $course_owner,$crstype)=@_;
     $url=&declutter($url);      $url=&declutter($url);
     my $cid='';      my $cid='';
     unless (&allowed('ccc',$udom)) {      unless (&allowed('ccc',$udom)) {
         return 'refused';          return 'refused';
     }      }
 # ------------------------------------------------------------------- Create ID  # ------------------------------------------------------------------- Create ID
    my $uname=substr($$.time,0,5).unpack("H8",pack("I32",time)).     my $uname=int(1+rand(9)).
          ('a'..'z','A'..'Z','0'..'9')[int(rand(62))].
          substr($$.time,0,5).unpack("H8",pack("I32",time)).
        unpack("H2",pack("I32",int(rand(255)))).$perlvar{'lonHostID'};         unpack("H2",pack("I32",int(rand(255)))).$perlvar{'lonHostID'};
 # ----------------------------------------------- Make sure that does not exist  # ----------------------------------------------- Make sure that does not exist
    my $uhome=&homeserver($uname,$udom,'true');     my $uhome=&homeserver($uname,$udom,'true');
Line 3622  sub createcourse { Line 4469  sub createcourse {
        }          } 
    }     }
 # ------------------------------------------------ Check supplied server name  # ------------------------------------------------ Check supplied server name
     $course_server = $ENV{'user.homeserver'} if (! defined($course_server));      $course_server = $env{'user.homeserver'} if (! defined($course_server));
     if (! exists($libserv{$course_server})) {      if (! exists($libserv{$course_server})) {
         return 'error:bad server name '.$course_server;          return 'error:bad server name '.$course_server;
     }      }
Line 3637  sub createcourse { Line 4484  sub createcourse {
 # ----------------------------------------------------------------- Course made  # ----------------------------------------------------------------- Course made
 # log existence  # log existence
     &courseidput($udom,&escape($udom.'_'.$uname).'='.&escape($description).      &courseidput($udom,&escape($udom.'_'.$uname).'='.&escape($description).
                  '='.&escape($inst_code),$uhome);                   ':'.&escape($inst_code).':'.&escape($course_owner).':'.
                     &escape($crstype),$uhome);
     &flushcourselogs();      &flushcourselogs();
 # set toplevel url  # set toplevel url
     my $topurl=$url;      my $topurl=$url;
Line 3645  sub createcourse { Line 4493  sub createcourse {
 # ------------------------------------------ For standard courses, make top url  # ------------------------------------------ For standard courses, make top url
         my $mapurl=&clutter($url);          my $mapurl=&clutter($url);
         if ($mapurl eq '/res/') { $mapurl=''; }          if ($mapurl eq '/res/') { $mapurl=''; }
         $ENV{'form.initmap'}=(<<ENDINITMAP);          $env{'form.initmap'}=(<<ENDINITMAP);
 <map>  <map>
 <resource id="1" type="start"></resource>  <resource id="1" type="start"></resource>
 <resource id="2" src="$mapurl"></resource>  <resource id="2" src="$mapurl"></resource>
Line 3655  sub createcourse { Line 4503  sub createcourse {
 </map>  </map>
 ENDINITMAP  ENDINITMAP
         $topurl=&declutter(          $topurl=&declutter(
         &finishuserfileupload($uname,$udom,$uhome,'initmap','default.sequence')          &finishuserfileupload($uname,$udom,'initmap','default.sequence')
                           );                            );
     }      }
 # ----------------------------------------------------------- Write preferences  # ----------------------------------------------------------- Write preferences
Line 3690  sub revokecustomrole { Line 4538  sub revokecustomrole {
            $deleteflag);             $deleteflag);
 }  }
   
   # ------------------------------------------------------------ Disk usage
   sub diskusage {
       my ($udom,$uname,$directoryRoot)=@_;
       $directoryRoot =~ s/\/$//;
       my $listing=&reply('du:'.$directoryRoot,homeserver($uname,$udom));
       return $listing;
   }
   
 # ------------------------------------------------------------ Portfolio Director Lister  sub is_locked {
 # returns listing of contents of user's /userfiles/portfolio/ directory      my ($file_name, $domain, $user) = @_;
 #       my @check;
       my $is_locked;
       push @check, $file_name;
       my %locked = &get('file_permissions',\@check,
         $env{'user.domain'},$env{'user.name'});
       my ($tmp)=keys(%locked);
       if ($tmp=~/^error:/) { undef(%locked); }
   
 sub portfoliolist {      
     my ($currentPath, $currentFile) = @_;      if (ref($locked{$file_name}) eq 'ARRAY') {
     my ($udom, $uname, $portfolioRoot);          $is_locked = 'false';
     $uname=$ENV{'user.name'};          foreach my $entry (@{$locked{$file_name}}) {
     $udom=$ENV{'user.domain'};             if (ref($entry) eq 'ARRAY') { 
     # really should interrogate the system for home directory information, but . . .                 if ($$entry[0] eq 'access' || $$entry[0] eq 'accesscount') {
     $portfolioRoot = '/home/httpd/lonUsers/'.$udom.'/';                     next;
     $uname =~ /^(.?)(.?)(.?)/;                 } else {
     $portfolioRoot = $portfolioRoot.$1.'/'.$2.'/'.$3.'/'.$uname.'/userfiles/portfolio';                     $is_locked = 'true';
     my $listing = &reply('ls:'.$portfolioRoot.$currentPath, &homeserver($uname,$udom));                     last;
     return $listing;                 }
              }
          }
       } else {
           $is_locked = 'false';
       }
 }  }
   
 sub portfoliomanage {  # ------------------------------------------------------------- Mark as Read Only
   
 #FIXME please user the existing remove userfile function instead and  sub mark_as_readonly {
 #add a userfilerename functions.      my ($domain,$user,$files,$what) = @_;
 #FIXME uhome should never be an argument to any lonnet functions      my %current_permissions = &dump('file_permissions',$domain,$user);
       my ($tmp)=keys(%current_permissions);
     # handles deleting and renaming files in user's userfiles/portfolio/ directory      if ($tmp=~/^error:/) { undef(%current_permissions); }
     #       foreach my $file (@{$files}) {
     my ($filename, $fileaction, $filenewname) = @_;          push(@{$current_permissions{$file}},$what);
     my ($udom, $uname, $uhome);      }
     $uname=$ENV{'user.name'};      &put('file_permissions',\%current_permissions,$domain,$user);
     $udom=$ENV{'user.domain'};      return;
     $uhome=$ENV{'user.home'};  
     my $listing = reply('portfoliomanage:'.$uname.':'.$udom.':'.$filename.':'.$fileaction.':'.$filenewname, $uhome);  
     return $listing;  
 }  }
   
   # ------------------------------------------------------------Save Selected Files
   
   sub save_selected_files {
       my ($user, $path, @files) = @_;
       my $filename = $user."savedfiles";
       my @other_files = &files_not_in_path($user, $path);
       open (OUT, '>'.$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename);
       foreach my $file (@files) {
           print (OUT $env{'form.currentpath'}.$file."\n");
       }
       foreach my $file (@other_files) {
           print (OUT $file."\n");
       }
       close (OUT);
       return 'ok';
   }
   
   sub clear_selected_files {
       my ($user) = @_;
       my $filename = $user."savedfiles";
       open (OUT, '>'.$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename);
       print (OUT undef);
       close (OUT);
       return ("ok");    
   }
   
   sub files_in_path {
       my ($user, $path) = @_;
       my $filename = $user."savedfiles";
       my %return_files;
       open (IN, '<'.$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename);
       while (my $line_in = <IN>) {
           chomp ($line_in);
           my @paths_and_file = split (m!/!, $line_in);
           my $file_part = pop (@paths_and_file);
           my $path_part = join ('/', @paths_and_file);
           $path_part.='/';
           my $path_and_file = $path_part.$file_part;
           if ($path_part eq $path) {
               $return_files{$file_part}= 'selected';
           }
       }
       close (IN);
       return (\%return_files);
   }
   
   # called in portfolio select mode, to show files selected NOT in current directory
   sub files_not_in_path {
       my ($user, $path) = @_;
       my $filename = $user."savedfiles";
       my @return_files;
       my $path_part;
       open (IN, '<'.$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename);
       while (<IN>) {
           #ok, I know it's clunky, but I want it to work
           my @paths_and_file = split m!/!, $_;
           my $file_part = pop (@paths_and_file);
           chomp ($file_part);
           my $path_part = join ('/', @paths_and_file);
           $path_part .= '/';
           my $path_and_file = $path_part.$file_part;
           if ($path_part ne $path) {
               push (@return_files, ($path_and_file));
           }
       }
       close (OUT);
       return (@return_files);
   }
   
   #----------------------------------------------Get portfolio file permissions
   
   sub get_portfile_permissions {
       my ($domain,$user) = @_;
       my %current_permissions = &dump('file_permissions',$domain,$user);
       my ($tmp)=keys(%current_permissions);
       if ($tmp=~/^error:/) { undef(%current_permissions); }
       return \%current_permissions;
   }
   
   #---------------------------------------------Get portfolio file access controls
   
   sub get_access_controls  {
       my ($current_permissions,$group,$file) = @_;
       my @access_checks = ();
       my %access; 
       if (defined($file)) {
           @access_checks = ($file);
       } else {
           @access_checks = keys(%{$current_permissions});
       }
       foreach my $file_name (@access_checks) {
           my $value = $$current_permissions{$file_name};
           if (defined($group)) {
               if ($file_name !~ m-^\Q$group\E/-) {
                   next;
               }
           }
           if (ref($value) eq "ARRAY") {
               foreach my $stored_what (@{$value}) {
                   if (ref($stored_what) eq 'ARRAY') {
                       if ($$stored_what[0] eq 'access') {
                           if (!defined($access{$file_name})) {
                               %{$access{$file_name}} = ();
                           } 
                           $access{$file_name}{$$stored_what[1]}=$$stored_what[2];
                       } else {
                           next;
                       }
                   }
               }
           }
       }
       return %access;
   }
   
   #------------------------------------------------------Get Marked as Read Only
   
   sub get_marked_as_readonly {
       my ($domain,$user,$what,$group) = @_;
       my $current_permissions = &get_portfile_permissions($domain,$user);
       my @readonly_files;
       my $cmp1=$what;
       if (ref($what)) { $cmp1=join('',@{$what}) };
       while (my ($file_name,$value) = each(%{$current_permissions})) {
           if (defined($group)) {
               if ($file_name !~ m-^\Q$group\E/-) {
                   next;
               }
           }
           if (ref($value) eq "ARRAY"){
               foreach my $stored_what (@{$value}) {
                   my $cmp2=$stored_what;
                   if (ref($stored_what)) {
                       if ($$stored_what[0] eq 'access' || 
                           $$stored_what[0] eq 'accesscount') {
                           next;
                       } else {
                           $cmp2=join('',@{$stored_what});
                       }
                   }
                   if ($cmp1 eq $cmp2) {
                       push(@readonly_files, $file_name);
                       last;
                   } elsif (!defined($what)) {
                       push(@readonly_files, $file_name);
                       last;
                   }
               }
           }
       }
       return @readonly_files;
   }
   #-----------------------------------------------------------Get Marked as Read Only Hash
   
   sub get_marked_as_readonly_hash {
       my ($current_permissions,$group,$what) = @_;
       my %readonly_files;
       while (my ($file_name,$value) = each(%{$current_permissions})) {
           if (defined($group)) {
               if ($file_name !~ m-^\Q$group\E/-) {
                   next;
               }
           }
           if (ref($value) eq "ARRAY"){
               foreach my $stored_what (@{$value}) {
                   if (ref($stored_what) eq 'ARRAY') {
                       if ($$stored_what[0] eq 'access' ||
                           $$stored_what[0] eq 'accesscount') {
                           next;
                       }
                   }
                   if ($stored_what eq $what) {
                       $readonly_files{$file_name} = 'locked';
                   } elsif (!defined($what)) {
                       $readonly_files{$file_name} = 'locked';
                   }
               }
           } 
       }
       return %readonly_files;
   }
   # ------------------------------------------------------------ Unmark as Read Only
   
   sub unmark_as_readonly {
       # unmarks $file_name (if $file_name is defined), or all files locked by $what 
       # for portfolio submissions, $what contains [$symb,$crsid] 
       my ($domain,$user,$what,$file_name,$group) = @_;
       my $symb_crs = $what;
       if (ref($what)) { $symb_crs=join('',@$what); }
       my %current_permissions = &dump('file_permissions',$domain,$user,$group);
       my ($tmp)=keys(%current_permissions);
       if ($tmp=~/^error:/) { undef(%current_permissions); }
       my @readonly_files = &get_marked_as_readonly($domain,$user,$what,$group);
       foreach my $file (@readonly_files) {
    if (defined($file_name) && ($file_name ne $file)) { next; }
    my $current_locks = $current_permissions{$file};
           my @new_locks;
           my @del_keys;
           if (ref($current_locks) eq "ARRAY"){
               foreach my $locker (@{$current_locks}) {
                   my $compare=$locker;
                   if (ref($locker) eq 'ARRAY') {
                       if ($$locker[0] eq 'access' || 
                           $$locker[0] eq 'accesscount') {
                           push(@new_locks,$locker);
                           next;
                       }   
                       $compare=join('',@{$locker});
                   }
                   if ($compare ne $symb_crs) {
                       push(@new_locks, $locker);
                   }
               }
               if (scalar(@new_locks) > 0) {
                   $current_permissions{$file} = \@new_locks;
               } else {
                   push(@del_keys, $file);
                   &del('file_permissions',\@del_keys, $domain, $user);
                   delete($current_permissions{$file});
               }
           }
       }
       &put('file_permissions',\%current_permissions,$domain,$user);
       return;
   }
   
 # ------------------------------------------------------------ Directory lister  # ------------------------------------------------------------ Directory lister
   
Line 3750  sub dirlist { Line 4838  sub dirlist {
   
     if($udom) {      if($udom) {
         if($uname) {          if($uname) {
             my $listing=reply('ls:'.$dirRoot.'/'.$uri,              my $listing=reply('ls2:'.$dirRoot.'/'.$uri,
                               homeserver($uname,$udom));                                homeserver($uname,$udom));
             return split(/:/,$listing);              my @listing_results;
               if ($listing eq 'unknown_cmd') {
                   $listing=reply('ls:'.$dirRoot.'/'.$uri,
                                  homeserver($uname,$udom));
                   @listing_results = split(/:/,$listing);
               } else {
                   @listing_results = map { &unescape($_); } split(/:/,$listing);
               }
               return @listing_results;
         } elsif(!defined($alternateDirectoryRoot)) {          } elsif(!defined($alternateDirectoryRoot)) {
             my $tryserver;              my $tryserver;
             my %allusers=();              my %allusers=();
             foreach $tryserver (keys %libserv) {              foreach $tryserver (keys %libserv) {
                 if($hostdom{$tryserver} eq $udom) {                  if($hostdom{$tryserver} eq $udom) {
                     my $listing=reply('ls:'.$perlvar{'lonDocRoot'}.'/res/'.                      my $listing=reply('ls2:'.$perlvar{'lonDocRoot'}.'/res/'.
                                       $udom, $tryserver);                                        $udom, $tryserver);
                     if (($listing ne 'no_such_dir') && ($listing ne 'empty')                      my @listing_results;
                         && ($listing ne 'con_lost')) {                      if ($listing eq 'unknown_cmd') {
                         foreach (split(/:/,$listing)) {                          $listing=reply('ls:'.$perlvar{'lonDocRoot'}.'/res/'.
                                          $udom, $tryserver);
                           @listing_results = split(/:/,$listing);
                       } else {
                           @listing_results =
                               map { &unescape($_); } split(/:/,$listing);
                       }
                       if ($listing_results[0] ne 'no_such_dir' && 
                           $listing_results[0] ne 'empty'       &&
                           $listing_results[0] ne 'con_lost') {
                           foreach (@listing_results) {
                             my ($entry,@stat)=split(/&/,$_);                              my ($entry,@stat)=split(/&/,$_);
                             $allusers{$entry}=1;                              $allusers{$entry}=1;
                         }                          }
Line 3830  sub GetFileTimestamp { Line 4936  sub GetFileTimestamp {
     }      }
 }  }
   
   sub stat_file {
       my ($uri) = @_;
       $uri = &clutter($uri);
   
       # we want just the url part without the unneeded accessor url bits
       if ($uri =~ m-^/adm/-) {
    $uri=~s-^/adm/wrapper/-/-;
    $uri=~s-^/adm/coursedocs/showdoc/-/-;
       }
       my ($udom,$uname,$file,$dir);
       if ($uri =~ m-^/(uploaded|editupload)/-) {
    ($udom,$uname,$file) =
       ($uri =~ m-/(?:uploaded|editupload)/?([^/]*)/?([^/]*)/?(.*)-);
    $file = 'userfiles/'.$file;
    $dir = &propath($udom,$uname);
       }
       if ($uri =~ m-^/res/-) {
    ($udom,$uname) = 
       ($uri =~ m-/(?:res)/?([^/]*)/?([^/]*)/-);
    $file = $uri;
       }
   
       if (!$udom || !$uname || !$file) {
    # unable to handle the uri
    return ();
       }
   
       my ($result) = &dirlist($file,$udom,$uname,$dir);
       my @stats = split('&', $result);
       
       if($stats[0] ne 'empty' && $stats[0] ne 'no_such_dir') {
    shift(@stats); #filename is first
    return @stats;
       }
       return ();
   }
   
 # -------------------------------------------------------- Value of a Condition  # -------------------------------------------------------- Value of a Condition
   
   # gets the value of a specific preevaluated condition
   #    stored in the string  $env{user.state.<cid>}
   # or looks up a condition reference in the bighash and if if hasn't
   # already been evaluated recurses into docondval to get the value of
   # the condition, then memoizing it to 
   #   $env{user.state.<cid>.<condition>}
 sub directcondval {  sub directcondval {
     my $number=shift;      my $number=shift;
     if ($ENV{'user.state.'.$ENV{'request.course.id'}}) {      if (!defined($env{'user.state.'.$env{'request.course.id'}})) {
        return substr($ENV{'user.state.'.$ENV{'request.course.id'}},$number,1);   &Apache::lonuserstate::evalstate();
       }
       if (exists($env{'user.state.'.$env{'request.course.id'}.".$number"})) {
    return $env{'user.state.'.$env{'request.course.id'}.".$number"};
       } elsif ($number =~ /^_/) {
    my $sub_condition;
    if (tie(my %bighash,'GDBM_File',$env{'request.course.fn'}.'.db',
    &GDBM_READER(),0640)) {
       $sub_condition=$bighash{'conditions'.$number};
       untie(%bighash);
    }
    my $value = &docondval($sub_condition);
    &appenv('user.state.'.$env{'request.course.id'}.".$number" => $value);
    return $value;
       }
       if ($env{'user.state.'.$env{'request.course.id'}}) {
          return substr($env{'user.state.'.$env{'request.course.id'}},$number,1);
     } else {      } else {
        return 2;         return 2;
     }      }
 }  }
   
   # get the collection of conditions for this resource
 sub condval {  sub condval {
     my $condidx=shift;      my $condidx=shift;
     my $result=0;  
     my $allpathcond='';      my $allpathcond='';
     foreach (split(/\|/,$condidx)) {      foreach my $cond (split(/\|/,$condidx)) {
        if (defined($ENV{'acc.cond.'.$ENV{'request.course.id'}.'.'.$_})) {   if (defined($env{'acc.cond.'.$env{'request.course.id'}.'.'.$cond})) {
    $allpathcond.=      $allpathcond.=
                '('.$ENV{'acc.cond.'.$ENV{'request.course.id'}.'.'.$_}.')|';   '('.$env{'acc.cond.'.$env{'request.course.id'}.'.'.$cond}.')|';
        }   }
     }      }
     $allpathcond=~s/\|$//;      $allpathcond=~s/\|$//;
     if ($ENV{'request.course.id'}) {      return &docondval($allpathcond);
        if ($allpathcond) {  }
           my $operand='|';  
   my @stack;  #evaluates an expression of conditions
            foreach ($allpathcond=~/(\d+|\(|\)|\&|\|)/g) {  sub docondval {
               if ($_ eq '(') {      my ($allpathcond) = @_;
                  push @stack,($operand,$result)      my $result=0;
               } elsif ($_ eq ')') {      if ($env{'request.course.id'}
                   my $before=pop @stack;   && defined($allpathcond)) {
   if (pop @stack eq '&') {   my $operand='|';
       $result=$result>$before?$before:$result;   my @stack;
                   } else {   foreach my $chunk ($allpathcond=~/(\d+|_\d+\.\d+|\(|\)|\&|\|)/g) {
                       $result=$result>$before?$result:$before;      if ($chunk eq '(') {
                   }   push @stack,($operand,$result);
               } elsif (($_ eq '&') || ($_ eq '|')) {      } elsif ($chunk eq ')') {
                   $operand=$_;   my $before=pop @stack;
               } else {   if (pop @stack eq '&') {
                   my $new=directcondval($_);      $result=$result>$before?$before:$result;
                   if ($operand eq '&') {   } else {
                      $result=$result>$new?$new:$result;      $result=$result>$before?$result:$before;
                   } else {   }
                      $result=$result>$new?$result:$new;      } elsif (($chunk eq '&') || ($chunk eq '|')) {
                   }   $operand=$chunk;
               }      } else {
           }   my $new=directcondval($chunk);
        }   if ($operand eq '&') {
       $result=$result>$new?$new:$result;
    } else {
       $result=$result>$new?$result:$new;
    }
       }
    }
     }      }
     return $result;      return $result;
 }  }
Line 3887  sub condval { Line 5058  sub condval {
 sub devalidatecourseresdata {  sub devalidatecourseresdata {
     my ($coursenum,$coursedomain)=@_;      my ($coursenum,$coursedomain)=@_;
     my $hashid=$coursenum.':'.$coursedomain;      my $hashid=$coursenum.':'.$coursedomain;
     &devalidate_cache(\%courseresdatacache,$hashid,'courseres');      &devalidate_cache_new('courseres',$hashid);
 }  }
   
 # --------------------------------------------------- Course Resourcedata Query  # --------------------------------------------------- Course Resourcedata Query
   
 sub courseresdata {  sub get_courseresdata {
     my ($coursenum,$coursedomain,@which)=@_;      my ($coursenum,$coursedomain)=@_;
     my $coursehom=&homeserver($coursenum,$coursedomain);      my $coursehom=&homeserver($coursenum,$coursedomain);
     my $hashid=$coursenum.':'.$coursedomain;      my $hashid=$coursenum.':'.$coursedomain;
     my ($result,$cached)=&is_cached(\%courseresdatacache,$hashid,'courseres');      my ($result,$cached)=&is_cached_new('courseres',$hashid);
       my %dumpreply;
     unless (defined($cached)) {      unless (defined($cached)) {
  my %dumpreply=&dump('resourcedata',$coursedomain,$coursenum);   %dumpreply=&dump('resourcedata',$coursedomain,$coursenum);
  $result=\%dumpreply;   $result=\%dumpreply;
  my ($tmp) = keys(%dumpreply);   my ($tmp) = keys(%dumpreply);
  if ($tmp !~ /^(con_lost|error|no_such_host)/i) {   if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
     &do_cache(\%courseresdatacache,$hashid,$result,'courseres');      &do_cache_new('courseres',$hashid,$result,600);
  } elsif ($tmp =~ /^(con_lost|no_such_host)/) {   } elsif ($tmp =~ /^(con_lost|no_such_host)/) {
     return $tmp;      return $tmp;
  } elsif ($tmp =~ /^(error)/) {   } elsif ($tmp =~ /^(error)/) {
     $result=undef;      $result=undef;
     &do_cache(\%courseresdatacache,$hashid,$result,'courseres');      &do_cache_new('courseres',$hashid,$result,600);
  }   }
     }      }
       return $result;
   }
   
   sub devalidateuserresdata {
       my ($uname,$udom)=@_;
       my $hashid="$udom:$uname";
       &devalidate_cache_new('userres',$hashid);
   }
   
   sub get_userresdata {
       my ($uname,$udom)=@_;
       #most student don\'t have any data set, check if there is some data
       if (&EXT_cache_status($udom,$uname)) { return undef; }
   
       my $hashid="$udom:$uname";
       my ($result,$cached)=&is_cached_new('userres',$hashid);
       if (!defined($cached)) {
    my %resourcedata=&dump('resourcedata',$udom,$uname);
    $result=\%resourcedata;
    &do_cache_new('userres',$hashid,$result,600);
       }
       my ($tmp)=keys(%$result);
       if (($tmp!~/^error\:/) && ($tmp!~/^con_lost/)) {
    return $result;
       }
       #error 2 occurs when the .db doesn't exist
       if ($tmp!~/error: 2 /) {
    &logthis("<font color=\"blue\">WARNING:".
    " Trying to get resource data for ".
    $uname." at ".$udom.": ".
    $tmp."</font>");
       } elsif ($tmp=~/error: 2 /) {
    #&EXT_cache_set($udom,$uname);
    &do_cache_new('userres',$hashid,undef,600);
    undef($tmp); # not really an error so don't send it back
       }
       return $tmp;
   }
   
   sub resdata {
       my ($name,$domain,$type,@which)=@_;
       my $result;
       if ($type eq 'course') {
    $result=&get_courseresdata($name,$domain);
       } elsif ($type eq 'user') {
    $result=&get_userresdata($name,$domain);
       }
       if (!ref($result)) { return $result; }    
     foreach my $item (@which) {      foreach my $item (@which) {
  if (defined($result->{$item})) {   if (defined($result->{$item})) {
     return $result->{$item};      return $result->{$item};
Line 3929  sub clear_EXT_cache_status { Line 5149  sub clear_EXT_cache_status {
 sub EXT_cache_status {  sub EXT_cache_status {
     my ($target_domain,$target_user) = @_;      my ($target_domain,$target_user) = @_;
     my $cachename = 'cache.EXT.'.$target_user.'.'.$target_domain;      my $cachename = 'cache.EXT.'.$target_user.'.'.$target_domain;
     if (exists($ENV{$cachename}) && ($ENV{$cachename}+600) > time) {      if (exists($env{$cachename}) && ($env{$cachename}+600) > time) {
         # We know already the user has no data          # We know already the user has no data
         return 1;          return 1;
     } else {      } else {
Line 3940  sub EXT_cache_status { Line 5160  sub EXT_cache_status {
 sub EXT_cache_set {  sub EXT_cache_set {
     my ($target_domain,$target_user) = @_;      my ($target_domain,$target_user) = @_;
     my $cachename = 'cache.EXT.'.$target_user.'.'.$target_domain;      my $cachename = 'cache.EXT.'.$target_user.'.'.$target_domain;
     &appenv($cachename => time);      #&appenv($cachename => time);
 }  }
   
 # --------------------------------------------------------- Value of a Variable  # --------------------------------------------------------- Value of a Variable
 sub EXT {  sub EXT {
     my ($varname,$symbparm,$udom,$uname,$usection,$recurse)=@_;  
   
       my ($varname,$symbparm,$udom,$uname,$usection,$recurse)=@_;
     unless ($varname) { return ''; }      unless ($varname) { return ''; }
     #get real user name/domain, courseid and symb      #get real user name/domain, courseid and symb
     my $courseid;      my $courseid;
Line 3959  sub EXT { Line 5179  sub EXT {
   &Apache::lonxml::whichuser($symbparm);    &Apache::lonxml::whichuser($symbparm);
       if (!$symbparm) { $symbparm=$cursymb; }        if (!$symbparm) { $symbparm=$cursymb; }
     } else {      } else {
  $courseid=$ENV{'request.course.id'};   $courseid=$env{'request.course.id'};
     }      }
     my ($realm,$space,$qualifier,@therest)=split(/\./,$varname);      my ($realm,$space,$qualifier,@therest)=split(/\./,$varname);
     my $rest;      my $rest;
Line 3976  sub EXT { Line 5196  sub EXT {
     if ($realm eq 'user') {      if ($realm eq 'user') {
 # --------------------------------------------------------------- user.resource  # --------------------------------------------------------------- user.resource
  if ($space eq 'resource') {   if ($space eq 'resource') {
     if (defined($Apache::lonhomework::parsing_a_problem)) {      if ( (defined($Apache::lonhomework::parsing_a_problem)
  return $Apache::lonhomework::history{$qualifierrest};    || defined($Apache::lonhomework::parsing_a_task))
    &&
    ($symbparm eq &symbread()) ) {
    # if we are in the middle of processing the resource the
    # get the value we are planning on committing
                   if (defined($Apache::lonhomework::results{$qualifierrest})) {
                       return $Apache::lonhomework::results{$qualifierrest};
                   } else {
                       return $Apache::lonhomework::history{$qualifierrest};
                   }
     } else {      } else {
  my %restored;   my %restored;
  if ($publicuser || $ENV{'request.state'} eq 'construct') {   if ($publicuser || $env{'request.state'} eq 'construct') {
     %restored=&tmprestore($symbparm,$courseid,$udom,$uname);      %restored=&tmprestore($symbparm,$courseid,$udom,$uname);
  } else {   } else {
     %restored=&restore($symbparm,$courseid,$udom,$uname);      %restored=&restore($symbparm,$courseid,$udom,$uname);
Line 3993  sub EXT { Line 5222  sub EXT {
             return &allowed($qualifier,$rest);              return &allowed($qualifier,$rest);
 # ------------------------------------------ user.preferences, user.environment  # ------------------------------------------ user.preferences, user.environment
         } elsif (($space eq 'preferences') || ($space eq 'environment')) {          } elsif (($space eq 'preferences') || ($space eq 'environment')) {
     if (($uname eq $ENV{'user.name'}) &&      if (($uname eq $env{'user.name'}) &&
  ($udom eq $ENV{'user.domain'})) {   ($udom eq $env{'user.domain'})) {
  return $ENV{join('.',('environment',$qualifierrest))};   return $env{join('.',('environment',$qualifierrest))};
     } else {      } else {
  my %returnhash;   my %returnhash;
  if (!$publicuser) {   if (!$publicuser) {
Line 4007  sub EXT { Line 5236  sub EXT {
 # ----------------------------------------------------------------- user.course  # ----------------------------------------------------------------- user.course
         } elsif ($space eq 'course') {          } elsif ($space eq 'course') {
     # FIXME - not supporting calls for a specific user      # FIXME - not supporting calls for a specific user
             return $ENV{join('.',('request.course',$qualifier))};              return $env{join('.',('request.course',$qualifier))};
 # ------------------------------------------------------------------- user.role  # ------------------------------------------------------------------- user.role
         } elsif ($space eq 'role') {          } elsif ($space eq 'role') {
     # FIXME - not supporting calls for a specific user      # FIXME - not supporting calls for a specific user
             my ($role,$where)=split(/\./,$ENV{'request.role'});              my ($role,$where)=split(/\./,$env{'request.role'});
             if ($qualifier eq 'value') {              if ($qualifier eq 'value') {
  return $role;   return $role;
             } elsif ($qualifier eq 'extent') {              } elsif ($qualifier eq 'extent') {
Line 4035  sub EXT { Line 5264  sub EXT {
 # ---------------------------------------------- pull stuff out of query string  # ---------------------------------------------- pull stuff out of query string
         &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},          &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
  [$spacequalifierrest]);   [$spacequalifierrest]);
  return $ENV{'form.'.$spacequalifierrest};    return $env{'form.'.$spacequalifierrest}; 
    } elsif ($realm eq 'request') {     } elsif ($realm eq 'request') {
 # ------------------------------------------------------------- request.browser  # ------------------------------------------------------------- request.browser
         if ($space eq 'browser') {          if ($space eq 'browser') {
     if ($qualifier eq 'textremote') {      if ($qualifier eq 'textremote') {
  if (&mt('textual_remote_display') eq 'on') {   if (&Apache::lonlocal::mt('textual_remote_display') eq 'on') {
     return 1;      return 1;
  } else {   } else {
     return 0;      return 0;
  }   }
     } else {      } else {
  return $ENV{'browser.'.$qualifier};   return $env{'browser.'.$qualifier};
     }      }
 # ------------------------------------------------------------ request.filename  # ------------------------------------------------------------ request.filename
         } else {          } else {
             return $ENV{'request.'.$spacequalifierrest};              return $env{'request.'.$spacequalifierrest};
         }          }
     } elsif ($realm eq 'course') {      } elsif ($realm eq 'course') {
 # ---------------------------------------------------------- course.description  # ---------------------------------------------------------- course.description
         return $ENV{'course.'.$courseid.'.'.$spacequalifierrest};          return $env{'course.'.$courseid.'.'.$spacequalifierrest};
     } elsif ($realm eq 'resource') {      } elsif ($realm eq 'resource') {
   
  my $section;   if (defined($courseid) && $courseid eq $env{'request.course.id'}) {
  if (defined($courseid) && $courseid eq $ENV{'request.course.id'}) {  
     if (!$symbparm) { $symbparm=&symbread(); }      if (!$symbparm) { $symbparm=&symbread(); }
  }   }
   
    if ($space eq 'title') {
       if (!$symbparm) { $symbparm = $env{'request.filename'}; }
       return &gettitle($symbparm);
    }
   
    if ($space eq 'map') {
       my ($map) = &decode_symb($symbparm);
       return &symbread($map);
    }
   
    my ($section, $group, @groups);
    my ($courselevelm,$courselevel);
  if ($symbparm && defined($courseid) &&    if ($symbparm && defined($courseid) && 
     $courseid eq $ENV{'request.course.id'}) {      $courseid eq $env{'request.course.id'}) {
   
     #print '<br>'.$space.' - '.$qualifier.' - '.$spacequalifierrest;      #print '<br>'.$space.' - '.$qualifier.' - '.$spacequalifierrest;
   
 # ----------------------------------------------------- Cascading lookup scheme  # ----------------------------------------------------- Cascading lookup scheme
     my $symbp=$symbparm;      my $symbp=$symbparm;
     my $mapp=(&decode_symb($symbp))[0];      my $mapp=&deversion((&decode_symb($symbp))[0]);
   
     my $symbparm=$symbp.'.'.$spacequalifierrest;      my $symbparm=$symbp.'.'.$spacequalifierrest;
     my $mapparm=$mapp.'___(all).'.$spacequalifierrest;      my $mapparm=$mapp.'___(all).'.$spacequalifierrest;
   
     if (($ENV{'user.name'} eq $uname) &&      if (($env{'user.name'} eq $uname) &&
  ($ENV{'user.domain'} eq $udom)) {   ($env{'user.domain'} eq $udom)) {
  $section=$ENV{'request.course.sec'};   $section=$env{'request.course.sec'};
                   @groups = split(/:/,$env{'request.course.groups'});  
                   @groups=&sort_course_groups($courseid,@groups); 
     } else {      } else {
  if (! defined($usection)) {   if (! defined($usection)) {
     $section=&usection($udom,$uname,$courseid);      $section=&getsection($udom,$uname,$courseid);
  } else {   } else {
     $section = $usection;      $section = $usection;
  }   }
                   @groups = &get_users_groups($udom,$uname,$courseid);
     }      }
   
     my $seclevel=$courseid.'.['.$section.'].'.$spacequalifierrest;      my $seclevel=$courseid.'.['.$section.'].'.$spacequalifierrest;
     my $seclevelr=$courseid.'.['.$section.'].'.$symbparm;      my $seclevelr=$courseid.'.['.$section.'].'.$symbparm;
     my $seclevelm=$courseid.'.['.$section.'].'.$mapparm;      my $seclevelm=$courseid.'.['.$section.'].'.$mapparm;
   
     my $courselevel=$courseid.'.'.$spacequalifierrest;      $courselevel=$courseid.'.'.$spacequalifierrest;
     my $courselevelr=$courseid.'.'.$symbparm;      my $courselevelr=$courseid.'.'.$symbparm;
     my $courselevelm=$courseid.'.'.$mapparm;      $courselevelm=$courseid.'.'.$mapparm;
   
 # ----------------------------------------------------------- first, check user  # ----------------------------------------------------------- first, check user
     #most student don\'t have any data set, check if there is some data  
     if (! &EXT_cache_status($udom,$uname)) {  
  my $hashid="$udom:$uname";  
  my ($result,$cached)=&is_cached(\%userresdatacache,$hashid,  
  'userres');  
  if (!defined($cached)) {  
     my %resourcedata=&dump('resourcedata',$udom,$uname);  
     $result=\%resourcedata;  
     &do_cache(\%userresdatacache,$hashid,$result,'userres');  
  }  
  my ($tmp)=keys(%$result);  
  if (($tmp!~/^error\:/) && ($tmp!~/^con_lost/)) {  
     if ($$result{$courselevelr}) {  
  return $$result{$courselevelr}; }  
     if ($$result{$courselevelm}) {  
  return $$result{$courselevelm}; }  
     if ($$result{$courselevel}) {  
  return $$result{$courselevel}; }  
  } else {  
     #error 2 occurs when the .db doesn't exist  
     if ($tmp!~/error: 2 /) {  
  &logthis("<font color=blue>WARNING:".  
  " Trying to get resource data for ".  
  $uname." at ".$udom.": ".  
  $tmp."</font>");  
     } elsif ($tmp=~/error: 2 /) {  
  &EXT_cache_set($udom,$uname);  
     } elsif ($tmp =~ /^(con_lost|no_such_host)/) {  
  return $tmp;  
     }  
  }  
     }  
   
 # -------------------------------------------------------- second, check course      my $userreply=&resdata($uname,$udom,'user',
          ($courselevelr,$courselevelm,
    $courselevel));
       if (defined($userreply)) { return $userreply; }
   
   # ------------------------------------------------ second, check some of course
               my $coursereply;
               if (@groups > 0) {
                   $coursereply = &check_group_parms($courseid,\@groups,$symbparm,
                                          $mapparm,$spacequalifierrest);
                   if (defined($coursereply)) { return $coursereply; }
               }
   
     my $coursereply=&courseresdata($ENV{'course.'.$courseid.'.num'},      $coursereply=&resdata($env{'course.'.$courseid.'.num'},
    $ENV{'course.'.$courseid.'.domain'},       $env{'course.'.$courseid.'.domain'},
    ($seclevelr,$seclevelm,$seclevel,       'course',
     $courselevelr,$courselevelm,       ($seclevelr,$seclevelm,$seclevel,
     $courselevel));        $courselevelr));
     if (defined($coursereply)) { return $coursereply; }      if (defined($coursereply)) { return $coursereply; }
   
 # ------------------------------------------------------ third, check map parms  # ------------------------------------------------------ third, check map parms
     my %parmhash=();      my %parmhash=();
     my $thisparm='';      my $thisparm='';
     if (tie(%parmhash,'GDBM_File',      if (tie(%parmhash,'GDBM_File',
     $ENV{'request.course.fn'}.'_parms.db',      $env{'request.course.fn'}.'_parms.db',
     &GDBM_READER(),0640)) {      &GDBM_READER(),0640)) {
  $thisparm=$parmhash{$symbparm};   $thisparm=$parmhash{$symbparm};
  untie(%parmhash);   untie(%parmhash);
     }      }
     if ($thisparm) { return $thisparm; }      if ($thisparm) { return $thisparm; }
  }   }
 # --------------------------------------------- last, look in resource metadata  # ------------------------------------------ fourth, look in resource metadata
   
  $spacequalifierrest=~s/\./\_/;   $spacequalifierrest=~s/\./\_/;
  my $filename;   my $filename;
Line 4154  sub EXT { Line 5377  sub EXT {
  if ($symbparm) {   if ($symbparm) {
     $filename=(&decode_symb($symbparm))[2];      $filename=(&decode_symb($symbparm))[2];
  } else {   } else {
     $filename=$ENV{'request.filename'};      $filename=$env{'request.filename'};
  }   }
  my $metadata=&metadata($filename,$spacequalifierrest);   my $metadata=&metadata($filename,$spacequalifierrest);
  if (defined($metadata)) { return $metadata; }   if (defined($metadata)) { return $metadata; }
  $metadata=&metadata($filename,'parameter_'.$spacequalifierrest);   $metadata=&metadata($filename,'parameter_'.$spacequalifierrest);
  if (defined($metadata)) { return $metadata; }   if (defined($metadata)) { return $metadata; }
   
   # ---------------------------------------------- fourth, look in rest pf course
    if ($symbparm && defined($courseid) && 
       $courseid eq $env{'request.course.id'}) {
       my $coursereply=&resdata($env{'course.'.$courseid.'.num'},
        $env{'course.'.$courseid.'.domain'},
        'course',
        ($courselevelm,$courselevel));
       if (defined($coursereply)) { return $coursereply; }
    }
 # ------------------------------------------------------------------ Cascade up  # ------------------------------------------------------------------ Cascade up
  unless ($space eq '0') {   unless ($space eq '0') {
     my @parts=split(/_/,$space);      my @parts=split(/_/,$space);
Line 4178  sub EXT { Line 5410  sub EXT {
 # ---------------------------------------------------- Any other user namespace  # ---------------------------------------------------- Any other user namespace
     } elsif ($realm eq 'environment') {      } elsif ($realm eq 'environment') {
 # ----------------------------------------------------------------- environment  # ----------------------------------------------------------------- environment
  if (($uname eq $ENV{'user.name'})&&($udom eq $ENV{'user.domain'})) {   if (($uname eq $env{'user.name'})&&($udom eq $env{'user.domain'})) {
     return $ENV{'environment.'.$spacequalifierrest};      return $env{'environment.'.$spacequalifierrest};
  } else {   } else {
     my %returnhash=&userenvironment($udom,$uname,      my %returnhash=&userenvironment($udom,$uname,
     $spacequalifierrest);      $spacequalifierrest);
Line 4190  sub EXT { Line 5422  sub EXT {
  if ($space eq 'time') {   if ($space eq 'time') {
     return time;      return time;
         }          }
       } elsif ($realm eq 'server') {
   # ----------------------------------------------------------------- system.time
    if ($space eq 'name') {
       return $ENV{'SERVER_NAME'};
           }
     }      }
     return '';      return '';
 }  }
   
   sub check_group_parms {
       my ($courseid,$groups,$symbparm,$mapparm,$what) = @_;
       my @groupitems = ();
       my $resultitem;
       my @levels = ($symbparm,$mapparm,$what);
       foreach my $group (@{$groups}) {
           foreach my $level (@levels) {
                my $item = $courseid.'.['.$group.'].'.$level;
                push(@groupitems,$item);
           }
       }
       my $coursereply = &resdata($env{'course.'.$courseid.'.num'},
                               $env{'course.'.$courseid.'.domain'},
                                        'course',@groupitems);
       return $coursereply;
   }
   
   sub sort_course_groups { # Sort groups based on defined rankings. Default is sort().
       my ($courseid,@groups) = @_;
       @groups = sort(@groups);
       return @groups;
   }
   
 sub packages_tab_default {  sub packages_tab_default {
     my ($uri,$varname)=@_;      my ($uri,$varname)=@_;
     my (undef,$part,$name)=split(/\./,$varname);      my (undef,$part,$name)=split(/\./,$varname);
     my $packages=&metadata($uri,'packages');  
     foreach my $package (split(/,/,$packages)) {      my (@extension,@specifics,$do_default);
       foreach my $package (split(/,/,&metadata($uri,'packages'))) {
  my ($pack_type,$pack_part)=split(/_/,$package,2);   my ($pack_type,$pack_part)=split(/_/,$package,2);
    if ($pack_type eq 'default') {
       $do_default=1;
    } elsif ($pack_type eq 'extension') {
       push(@extension,[$package,$pack_type,$pack_part]);
    } else {
       push(@specifics,[$package,$pack_type,$pack_part]);
    }
       }
       # first look for a package that matches the requested part id
       foreach my $package (@specifics) {
    my (undef,$pack_type,$pack_part)=@{$package};
    next if ($pack_part ne $part);
    if (defined($packagetab{"$pack_type&$name&default"})) {
       return $packagetab{"$pack_type&$name&default"};
    }
       }
       # look for any possible matching non extension_ package
       foreach my $package (@specifics) {
    my (undef,$pack_type,$pack_part)=@{$package};
  if (defined($packagetab{"$pack_type&$name&default"})) {   if (defined($packagetab{"$pack_type&$name&default"})) {
     return $packagetab{"$pack_type&$name&default"};      return $packagetab{"$pack_type&$name&default"};
  }   }
    if ($pack_type eq 'part') { $pack_part='0'; }
  if (defined($packagetab{$pack_type."_".$pack_part."&$name&default"})) {   if (defined($packagetab{$pack_type."_".$pack_part."&$name&default"})) {
     return $packagetab{$pack_type."_".$pack_part."&$name&default"};      return $packagetab{$pack_type."_".$pack_part."&$name&default"};
  }   }
     }      }
       # look for any posible extension_ match
       foreach my $package (@extension) {
    my ($package,$pack_type)=@{$package};
    if (defined($packagetab{"$pack_type&$name&default"})) {
       return $packagetab{"$pack_type&$name&default"};
    }
    if (defined($packagetab{$package."&$name&default"})) {
       return $packagetab{$package."&$name&default"};
    }
       }
       # look for a global default setting
       if ($do_default && defined($packagetab{"default&$name&default"})) {
    return $packagetab{"default&$name&default"};
       }
     return undef;      return undef;
 }  }
   
Line 4228  sub add_prefix_and_part { Line 5523  sub add_prefix_and_part {
   
 # ---------------------------------------------------------------- Get metadata  # ---------------------------------------------------------------- Get metadata
   
   my %metaentry;
 sub metadata {  sub metadata {
     my ($uri,$what,$liburi,$prefix,$depthcount)=@_;      my ($uri,$what,$liburi,$prefix,$depthcount)=@_;
     $uri=&declutter($uri);      $uri=&declutter($uri);
     # if it is a non metadata possible uri return quickly      # if it is a non metadata possible uri return quickly
     if (($uri eq '') || (($uri =~ m|^/*adm/|) && ($uri !~ m|^adm/includes|)) ||      if (($uri eq '') || 
    (($uri =~ m|^/*adm/|) && 
        ($uri !~ m|^adm/includes|) && ($uri !~ m|/bulletinboard$|)) ||
         ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ /^~/) ||          ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ /^~/) ||
  ($uri =~ m|home/[^/]+/public_html/|)) {   ($uri =~ m|home/[^/]+/public_html/|)) {
  return undef;   return undef;
Line 4245  sub metadata { Line 5543  sub metadata {
 # Everything is cached by the main uri, libraries are never directly cached  # Everything is cached by the main uri, libraries are never directly cached
 #  #
     if (!defined($liburi)) {      if (!defined($liburi)) {
  my ($result,$cached)=&is_cached(\%metacache,$uri,'meta');   my ($result,$cached)=&is_cached_new('meta',$uri);
  if (defined($cached)) { return $result->{':'.$what}; }   if (defined($cached)) { return $result->{':'.$what}; }
     }      }
     {      {
 #  #
 # Is this a recursive call for a library?  # Is this a recursive call for a library?
 #  #
  if (! exists($metacache{$uri})) {  # if (! exists($metacache{$uri})) {
     $metacache{$uri}={};  #    $metacache{$uri}={};
  }  # }
         if ($liburi) {          if ($liburi) {
     $liburi=&declutter($liburi);      $liburi=&declutter($liburi);
             $filename=$liburi;              $filename=$liburi;
         } else {          } else {
     &devalidate_cache(\%metacache,$uri,'meta');      &devalidate_cache_new('meta',$uri);
       undef(%metaentry);
  }   }
         my %metathesekeys=();          my %metathesekeys=();
         unless ($filename=~/\.meta$/) { $filename.='.meta'; }          unless ($filename=~/\.meta$/) { $filename.='.meta'; }
  my $metastring;   my $metastring;
  if ($uri !~ m|^uploaded/|) {   if ($uri !~ m -^(uploaded|editupload)/-) {
     my $file=&filelocation('',&clutter($filename));      my $file=&filelocation('',&clutter($filename));
     push(@{$metacache{$uri.'.file'}},$file);      #push(@{$metaentry{$uri.'.file'}},$file);
     $metastring=&getfile($file);      $metastring=&getfile($file);
  }   }
         my $parser=HTML::LCParser->new(\$metastring);          my $parser=HTML::LCParser->new(\$metastring);
Line 4283  sub metadata { Line 5582  sub metadata {
     if (defined($token->[2]->{'id'})) {       if (defined($token->[2]->{'id'})) { 
  $keyroot.='_'.$token->[2]->{'id'};    $keyroot.='_'.$token->[2]->{'id'}; 
     }      }
     if ($metacache{$uri}->{':packages'}) {      if ($metaentry{':packages'}) {
  $metacache{$uri}->{':packages'}.=','.$package.$keyroot;   $metaentry{':packages'}.=','.$package.$keyroot;
     } else {      } else {
  $metacache{$uri}->{':packages'}=$package.$keyroot;   $metaentry{':packages'}=$package.$keyroot;
     }      }
     foreach (keys %packagetab) {      foreach my $pack_entry (keys(%packagetab)) {
  my $part=$keyroot;   my $part=$keyroot;
  $part=~s/^\_//;   $part=~s/^\_//;
  if ($_=~/^\Q$package\E\&/ ||    if ($pack_entry=~/^\Q$package\E\&/ || 
     $_=~/^\Q$package\E_0\&/) {      $pack_entry=~/^\Q$package\E_0\&/) {
     my ($pack,$name,$subp)=split(/\&/,$_);      my ($pack,$name,$subp)=split(/\&/,$pack_entry);
     # ignore package.tab specified default values      # ignore package.tab specified default values
                             # here &package_tab_default() will fetch those                              # here &package_tab_default() will fetch those
     if ($subp eq 'default') { next; }      if ($subp eq 'default') { next; }
     my $value=$packagetab{$_};      my $value=$packagetab{$pack_entry};
     my $unikey;      my $unikey;
     if ($pack =~ /_0$/) {      if ($pack =~ /_0$/) {
  $unikey='parameter_0_'.$name;   $unikey='parameter_0_'.$name;
Line 4308  sub metadata { Line 5607  sub metadata {
     if ($subp eq 'display') {      if ($subp eq 'display') {
  $value.=' [Part: '.$part.']';   $value.=' [Part: '.$part.']';
     }      }
     $metacache{$uri}->{':'.$unikey.'.part'}=$part;      $metaentry{':'.$unikey.'.part'}=$part;
     $metathesekeys{$unikey}=1;      $metathesekeys{$unikey}=1;
     unless (defined($metacache{$uri}->{':'.$unikey.'.'.$subp})) {      unless (defined($metaentry{':'.$unikey.'.'.$subp})) {
  $metacache{$uri}->{':'.$unikey.'.'.$subp}=$value;   $metaentry{':'.$unikey.'.'.$subp}=$value;
     }      }
     if (defined($metacache{$uri}->{':'.$unikey.'.default'})) {      if (defined($metaentry{':'.$unikey.'.default'})) {
  $metacache{$uri}->{':'.$unikey}=   $metaentry{':'.$unikey}=
     $metacache{$uri}->{':'.$unikey.'.default'};      $metaentry{':'.$unikey.'.default'};
     }      }
  }   }
     }      }
Line 4345  sub metadata { Line 5644  sub metadata {
     my $dir=$filename;      my $dir=$filename;
     $dir=~s|[^/]*$||;      $dir=~s|[^/]*$||;
     $location=&filelocation($dir,$location);      $location=&filelocation($dir,$location);
     foreach (sort(split(/\,/,&metadata($uri,'keys',      my $metadata = 
        $location,$unikey,   &metadata($uri,'keys', $location,$unikey,
        $depthcount+1)))) {    $depthcount+1);
  $metacache{$uri}->{':'.$_}=$metacache{$uri}->{':'.$_};      foreach my $meta (split(',',$metadata)) {
  $metathesekeys{$_}=1;   $metaentry{':'.$meta}=$metaentry{':'.$meta};
    $metathesekeys{$meta}=1;
     }      }
  }   }
     } else {       } else { 
Line 4358  sub metadata { Line 5658  sub metadata {
     $unikey.='_'.$token->[2]->{'name'};       $unikey.='_'.$token->[2]->{'name'}; 
  }   }
  $metathesekeys{$unikey}=1;   $metathesekeys{$unikey}=1;
  foreach (@{$token->[3]}) {   foreach my $param (@{$token->[3]}) {
     $metacache{$uri}->{':'.$unikey.'.'.$_}=$token->[2]->{$_};      $metaentry{':'.$unikey.'.'.$param} =
    $token->[2]->{$param};
  }   }
  my $internaltext=&HTML::Entities::decode($parser->get_text('/'.$entry));   my $internaltext=&HTML::Entities::decode($parser->get_text('/'.$entry));
  my $default=$metacache{$uri}->{':'.$unikey.'.default'};   my $default=$metaentry{':'.$unikey.'.default'};
  if ( $internaltext =~ /^\s*$/ && $default !~ /^\s*$/) {   if ( $internaltext =~ /^\s*$/ && $default !~ /^\s*$/) {
  # only ws inside the tag, and not in default, so use default   # only ws inside the tag, and not in default, so use default
  # as value   # as value
     $metacache{$uri}->{':'.$unikey}=$default;      $metaentry{':'.$unikey}=$default;
  } else {   } else {
   # either something interesting inside the tag or default    # either something interesting inside the tag or default
                   # uninteresting                    # uninteresting
     $metacache{$uri}->{':'.$unikey}=$internaltext;      $metaentry{':'.$unikey}=$internaltext;
  }   }
 # end of not-a-package not-a-library import  # end of not-a-package not-a-library import
     }      }
Line 4380  sub metadata { Line 5681  sub metadata {
     }      }
  }   }
  my ($extension) = ($uri =~ /\.(\w+)$/);   my ($extension) = ($uri =~ /\.(\w+)$/);
  foreach my $key (sort(keys(%packagetab))) {   foreach my $key (keys(%packagetab)) {
     #&logthis("extsion1 $extension $key !!");  
     #no specific packages #how's our extension      #no specific packages #how's our extension
     if ($key!~/^extension_\Q$extension\E&/) { next; }      if ($key!~/^extension_\Q$extension\E&/) { next; }
     &metadata_create_package_def($uri,$key,'extension_'.$extension,      &metadata_create_package_def($uri,$key,'extension_'.$extension,
  \%metathesekeys);   \%metathesekeys);
  }   }
  if (!exists($metacache{$uri}->{':packages'})) {   if (!exists($metaentry{':packages'})) {
     foreach my $key (sort(keys(%packagetab))) {      foreach my $key (keys(%packagetab)) {
  #no specific packages well let's get default then   #no specific packages well let's get default then
  if ($key!~/^default&/) { next; }   if ($key!~/^default&/) { next; }
  &metadata_create_package_def($uri,$key,'default',   &metadata_create_package_def($uri,$key,'default',
Line 4396  sub metadata { Line 5696  sub metadata {
     }      }
  }   }
 # are there custom rights to evaluate  # are there custom rights to evaluate
  if ($metacache{$uri}->{':copyright'} eq 'custom') {   if ($metaentry{':copyright'} eq 'custom') {
   
     #      #
     # Importing a rights file here      # Importing a rights file here
     #      #
     unless ($depthcount) {      unless ($depthcount) {
  my $location=$metacache{$uri}->{':customdistributionfile'};   my $location=$metaentry{':customdistributionfile'};
  my $dir=$filename;   my $dir=$filename;
  $dir=~s|[^/]*$||;   $dir=~s|[^/]*$||;
  $location=&filelocation($dir,$location);   $location=&filelocation($dir,$location);
  foreach (sort(split(/\,/,&metadata($uri,'keys',   my $rights_metadata =
    $location,'_rights',      &metadata($uri,'keys',$location,'_rights',
    $depthcount+1)))) {        $depthcount+1);
     $metacache{$uri}->{':'.$_}=$metacache{$uri}->{':'.$_};   foreach my $rights (split(',',$rights_metadata)) {
     $metathesekeys{$_}=1;      #$metaentry{':'.$rights}=$metacache{$uri}->{':'.$rights};
       $metathesekeys{$rights}=1;
  }   }
     }      }
  }   }
  $metacache{$uri}->{':keys'}=join(',',keys %metathesekeys);   # uniqifiy package listing
  &metadata_generate_part0(\%metathesekeys,$metacache{$uri},$uri);   my %seen;
  $metacache{$uri}->{':allpossiblekeys'}=join(',',keys %metathesekeys);   my @uniq_packages =
  &do_cache(\%metacache,$uri,$metacache{$uri},'meta');      grep { ! $seen{$_} ++ } (split(',',$metaentry{':packages'}));
    $metaentry{':packages'} = join(',',@uniq_packages);
   
    $metaentry{':keys'} = join(',',keys(%metathesekeys));
    &metadata_generate_part0(\%metathesekeys,\%metaentry,$uri);
    $metaentry{':allpossiblekeys'}=join(',',keys %metathesekeys);
    &do_cache_new('meta',$uri,\%metaentry,60*60);
 # this is the end of "was not already recently cached  # this is the end of "was not already recently cached
     }      }
     return $metacache{$uri}->{':'.$what};      return $metaentry{':'.$what};
 }  }
   
 sub metadata_create_package_def {  sub metadata_create_package_def {
Line 4428  sub metadata_create_package_def { Line 5735  sub metadata_create_package_def {
     my ($pack,$name,$subp)=split(/\&/,$key);      my ($pack,$name,$subp)=split(/\&/,$key);
     if ($subp eq 'default') { next; }      if ($subp eq 'default') { next; }
           
     if (defined($metacache{$uri}->{':packages'})) {      if (defined($metaentry{':packages'})) {
  $metacache{$uri}->{':packages'}.=','.$package;   $metaentry{':packages'}.=','.$package;
     } else {      } else {
  $metacache{$uri}->{':packages'}=$package;   $metaentry{':packages'}=$package;
     }      }
     my $value=$packagetab{$key};      my $value=$packagetab{$key};
     my $unikey;      my $unikey;
     $unikey='parameter_0_'.$name;      $unikey='parameter_0_'.$name;
     $metacache{$uri}->{':'.$unikey.'.part'}=0;      $metaentry{':'.$unikey.'.part'}=0;
     $$metathesekeys{$unikey}=1;      $$metathesekeys{$unikey}=1;
     unless (defined($metacache{$uri}->{':'.$unikey.'.'.$subp})) {      unless (defined($metaentry{':'.$unikey.'.'.$subp})) {
  $metacache{$uri}->{':'.$unikey.'.'.$subp}=$value;   $metaentry{':'.$unikey.'.'.$subp}=$value;
     }      }
     if (defined($metacache{$uri}->{':'.$unikey.'.default'})) {      if (defined($metaentry{':'.$unikey.'.default'})) {
  $metacache{$uri}->{':'.$unikey}=   $metaentry{':'.$unikey}=
     $metacache{$uri}->{':'.$unikey.'.default'};      $metaentry{':'.$unikey.'.default'};
     }      }
 }  }
   
 sub metadata_generate_part0 {  sub metadata_generate_part0 {
     my ($metadata,$metacache,$uri) = @_;      my ($metadata,$metacache,$uri) = @_;
     my %allnames;      my %allnames;
     foreach my $metakey (sort keys %$metadata) {      foreach my $metakey (keys(%$metadata)) {
  if ($metakey=~/^parameter\_(.*)/) {   if ($metakey=~/^parameter\_(.*)/) {
   my $part=$$metacache{':'.$metakey.'.part'};    my $part=$$metacache{':'.$metakey.'.part'};
   my $name=$$metacache{':'.$metakey.'.name'};    my $name=$$metacache{':'.$metakey.'.name'};
Line 4469  sub metadata_generate_part0 { Line 5776  sub metadata_generate_part0 {
    '.type'};     '.type'};
       my $olddis=$$metacache{':parameter_'.$allnames{$name}.'_'.$name.        my $olddis=$$metacache{':parameter_'.$allnames{$name}.'_'.$name.
      '.display'};       '.display'};
       my $expr='\\[Part: '.$allnames{$name}.'\\]';        my $expr='[Part: '.$allnames{$name}.']';
       $olddis=~s/\Q$expr\E/\[Part: 0\]/;        $olddis=~s/\Q$expr\E/\[Part: 0\]/;
       $$metacache{"$key.display"}=$olddis;        $$metacache{"$key.display"}=$olddis;
     }      }
Line 4480  sub metadata_generate_part0 { Line 5787  sub metadata_generate_part0 {
 sub gettitle {  sub gettitle {
     my $urlsymb=shift;      my $urlsymb=shift;
     my $symb=&symbread($urlsymb);      my $symb=&symbread($urlsymb);
     unless ($symb) {      if ($symb) {
  unless ($urlsymb) { $urlsymb=$ENV{'request.filename'}; }   my $key=$env{'request.course.id'}."\0".$symb;
         return &metadata($urlsymb,'title');    my ($result,$cached)=&is_cached_new('title',$key);
    if (defined($cached)) { 
       return $result;
    }
    my ($map,$resid,$url)=&decode_symb($symb);
    my $title='';
    my %bighash;
    if (tie(%bighash,'GDBM_File',$env{'request.course.fn'}.'.db',
    &GDBM_READER(),0640)) {
       my $mapid=$bighash{'map_pc_'.&clutter($map)};
       $title=$bighash{'title_'.$mapid.'.'.$resid};
       untie %bighash;
    }
    $title=~s/\&colon\;/\:/gs;
    if ($title) {
       return &do_cache_new('title',$key,$title,600);
    }
    $urlsymb=$url;
       }
       my $title=&metadata($urlsymb,'title');
       if (!$title) { $title=(split('/',$urlsymb))[-1]; }    
       return $title;
   }
   
   sub get_slot {
       my ($which,$cnum,$cdom)=@_;
       if (!$cnum || !$cdom) {
    (undef,my $courseid)=&Apache::lonxml::whichuser();
    $cdom=$env{'course.'.$courseid.'.domain'};
    $cnum=$env{'course.'.$courseid.'.num'};
       }
       my $key=join("\0",'slots',$cdom,$cnum,$which);
       my %slotinfo;
       if (exists($remembered{$key})) {
    $slotinfo{$which} = $remembered{$key};
       } else {
    %slotinfo=&get('slots',[$which],$cdom,$cnum);
    &Apache::lonhomework::showhash(%slotinfo);
    my ($tmp)=keys(%slotinfo);
    if ($tmp=~/^error:/) { return (); }
    $remembered{$key} = $slotinfo{$which};
     }      }
     my ($result,$cached)=&is_cached(\%titlecache,$symb,'title',600);      if (ref($slotinfo{$which}) eq 'HASH') {
     if (defined($cached)) { return $result; }   return %{$slotinfo{$which}};
     my ($map,$resid,$url)=&decode_symb($symb);  
     my $title='';  
     my %bighash;  
     if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',  
                             &GDBM_READER(),0640)) {  
         my $mapid=$bighash{'map_pc_'.&clutter($map)};  
         $title=$bighash{'title_'.$mapid.'.'.$resid};  
         untie %bighash;  
     }  
     $title=~s/\&colon\;/\:/gs;  
     if ($title) {  
         return &do_cache(\%titlecache,$symb,$title,'title');  
     } else {  
  return &metadata($urlsymb,'title');  
     }      }
       return $slotinfo{$which};
 }  }
       
 # ------------------------------------------------- Update symbolic store links  # ------------------------------------------------- Update symbolic store links
   
 sub symblist {  sub symblist {
     my ($mapname,%newhash)=@_;      my ($mapname,%newhash)=@_;
     $mapname=&deversion(&declutter($mapname));      $mapname=&deversion(&declutter($mapname));
     my %hash;      my %hash;
     if (($ENV{'request.course.fn'}) && (%newhash)) {      if (($env{'request.course.fn'}) && (%newhash)) {
         if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db',          if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
                       &GDBM_WRCREAT(),0640)) {                        &GDBM_WRCREAT(),0640)) {
     foreach (keys %newhash) {      foreach my $url (keys %newhash) {
                 $hash{declutter($_)}=$mapname.'___'.&deversion($newhash{$_});   next if ($url eq 'last_known'
    && $env{'form.no_update_last_known'});
    $hash{declutter($url)}=&encode_symb($mapname,
       $newhash{$url}->[1],
       $newhash{$url}->[0]);
             }              }
             if (untie(%hash)) {              if (untie(%hash)) {
  return 'ok';   return 'ok';
Line 4530  sub symbverify { Line 5867  sub symbverify {
     my $thisfn=$thisurl;      my $thisfn=$thisurl;
 # wrapper not part of symbs  # wrapper not part of symbs
     $thisfn=~s/^\/adm\/wrapper//;      $thisfn=~s/^\/adm\/wrapper//;
       $thisfn=~s/^\/adm\/coursedocs\/showdoc\///;
     $thisfn=&declutter($thisfn);      $thisfn=&declutter($thisfn);
 # direct jump to resource in page or to a sequence - will construct own symbs  # direct jump to resource in page or to a sequence - will construct own symbs
     if ($thisfn=~/\.(page|sequence)$/) { return 1; }      if ($thisfn=~/\.(page|sequence)$/) { return 1; }
Line 4545  sub symbverify { Line 5883  sub symbverify {
     my %bighash;      my %bighash;
     my $okay=0;      my $okay=0;
   
     if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',      if (tie(%bighash,'GDBM_File',$env{'request.course.fn'}.'.db',
                             &GDBM_READER(),0640)) {                              &GDBM_READER(),0640)) {
         my $ids=$bighash{'ids_'.&clutter($thisurl)};          my $ids=$bighash{'ids_'.&clutter($thisurl)};
         unless ($ids) {           unless ($ids) { 
Line 4554  sub symbverify { Line 5892  sub symbverify {
         if ($ids) {          if ($ids) {
 # ------------------------------------------------------------------- Has ID(s)  # ------------------------------------------------------------------- Has ID(s)
     foreach (split(/\,/,$ids)) {      foreach (split(/\,/,$ids)) {
                my ($mapid,$resid)=split(/\./,$_);         my ($mapid,$resid)=split(/\./,$_);
                if (                 if (
   &symbclean(&declutter($bighash{'map_id_'.$mapid}).'___'.$resid.'___'.$thisfn)    &symbclean(&declutter($bighash{'map_id_'.$mapid}).'___'.$resid.'___'.$thisfn)
    eq $symb) {      eq $symb) { 
                   $okay=1;      if (($env{'request.role.adv'}) ||
                }         $bighash{'encrypted_'.$_} eq $env{'request.enc'}) {
          $okay=1; 
      }
          }
    }     }
         }          }
  untie(%bighash);   untie(%bighash);
Line 4571  sub symbverify { Line 5912  sub symbverify {
   
 sub symbclean {  sub symbclean {
     my $symb=shift;      my $symb=shift;
       if ($symb=~m|^/enc/|) { $symb=&Apache::lonenc::unencrypted($symb); }
 # remove version from map  # remove version from map
     $symb=~s/\.(\d+)\.(\w+)\_\_\_/\.$2\_\_\_/;      $symb=~s/\.(\d+)\.(\w+)\_\_\_/\.$2\_\_\_/;
   
Line 4581  sub symbclean { Line 5922  sub symbclean {
 # remove wrapper  # remove wrapper
   
     $symb=~s/(\_\_\_\d+\_\_\_)adm\/wrapper\/(res\/)*/$1/;      $symb=~s/(\_\_\_\d+\_\_\_)adm\/wrapper\/(res\/)*/$1/;
       $symb=~s/(\_\_\_\d+\_\_\_)adm\/coursedocs\/showdoc\/(res\/)*/$1/;
     return $symb;      return $symb;
 }  }
   
Line 4592  sub encode_symb { Line 5934  sub encode_symb {
 }  }
   
 sub decode_symb {  sub decode_symb {
     my ($map,$resid,$url)=split(/\_\_\_/,shift);      my $symb=shift;
       if ($symb=~m|^/enc/|) { $symb=&Apache::lonenc::unencrypted($symb); }
       my ($map,$resid,$url)=split(/___/,$symb);
     return (&fixversion($map),$resid,&fixversion($url));      return (&fixversion($map),$resid,&fixversion($url));
 }  }
   
 sub fixversion {  sub fixversion {
     my $fn=shift;      my $fn=shift;
     if ($fn=~/^(adm|uploaded|public)/) { return $fn; }      if ($fn=~/^(adm|uploaded|editupload|public)/) { return $fn; }
     my %bighash;      my %bighash;
     my $uri=&clutter($fn);      my $uri=&clutter($fn);
     my $key=$ENV{'request.course.id'}.'_'.$uri;      my $key=$env{'request.course.id'}.'_'.$uri;
 # is this cached?  # is this cached?
     my ($result,$cached)=&is_cached(\%courseresversioncache,$key,      my ($result,$cached)=&is_cached_new('courseresversion',$key);
     'courseresversion',600);  
     if (defined($cached)) { return $result; }      if (defined($cached)) { return $result; }
 # unfortunately not cached, or expired  # unfortunately not cached, or expired
     if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',      if (tie(%bighash,'GDBM_File',$env{'request.course.fn'}.'.db',
     &GDBM_READER(),0640)) {      &GDBM_READER(),0640)) {
   if ($bighash{'version_'.$uri}) {    if ($bighash{'version_'.$uri}) {
      my $version=$bighash{'version_'.$uri};       my $version=$bighash{'version_'.$uri};
Line 4618  sub fixversion { Line 5961  sub fixversion {
   }    }
   untie %bighash;    untie %bighash;
     }      }
     return &do_cache      return &do_cache_new('courseresversion',$key,&declutter($uri),600);
  (\%courseresversioncache,$key,&declutter($uri),'courseresversion');  
 }  }
   
 sub deversion {  sub deversion {
Line 4633  sub deversion { Line 5975  sub deversion {
 sub symbread {  sub symbread {
     my ($thisfn,$donotrecurse)=@_;      my ($thisfn,$donotrecurse)=@_;
     my $cache_str='request.symbread.cached.'.$thisfn;      my $cache_str='request.symbread.cached.'.$thisfn;
     if (defined($ENV{$cache_str})) { return $ENV{$cache_str}; }      if (defined($env{$cache_str})) { return $env{$cache_str}; }
 # no filename provided? try from environment  # no filename provided? try from environment
     unless ($thisfn) {      unless ($thisfn) {
         if ($ENV{'request.symb'}) {          if ($env{'request.symb'}) {
     return $ENV{$cache_str}=&symbclean($ENV{'request.symb'});      return $env{$cache_str}=&symbclean($env{'request.symb'});
  }   }
  $thisfn=$ENV{'request.filename'};   $thisfn=$env{'request.filename'};
     }      }
       if ($thisfn=~m|^/enc/|) { $thisfn=&Apache::lonenc::unencrypted($thisfn); }
 # is that filename actually a symb? Verify, clean, and return  # is that filename actually a symb? Verify, clean, and return
     if ($thisfn=~/\_\_\_\d+\_\_\_(.*)$/) {      if ($thisfn=~/\_\_\_\d+\_\_\_(.*)$/) {
  if (&symbverify($thisfn,$1)) {   if (&symbverify($thisfn,$1)) {
     return $ENV{$cache_str}=&symbclean($thisfn);      return $env{$cache_str}=&symbclean($thisfn);
  }   }
     }      }
     $thisfn=declutter($thisfn);      $thisfn=declutter($thisfn);
     my %hash;      my %hash;
     my %bighash;      my %bighash;
     my $syval='';      my $syval='';
     if (($ENV{'request.course.fn'}) && ($thisfn)) {      if (($env{'request.course.fn'}) && ($thisfn)) {
         my $targetfn = $thisfn;          my $targetfn = $thisfn;
         if ( ($thisfn =~ m/^uploaded\//) && ($thisfn !~ m/\.(page|sequence)$/) ) {          if ( ($thisfn =~ m/^(uploaded|editupload)\//) && ($thisfn !~ m/\.(page|sequence)$/) ) {
             $targetfn = 'adm/wrapper/'.$thisfn;              $targetfn = 'adm/wrapper/'.$thisfn;
         }          }
         if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db',   if ($targetfn =~ m|^adm/wrapper/(ext/.*)|) {
       $targetfn=$1;
    }
           if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db',
                       &GDBM_READER(),0640)) {                        &GDBM_READER(),0640)) {
     $syval=$hash{$targetfn};      $syval=$hash{$targetfn};
             untie(%hash);              untie(%hash);
         }          }
 # ---------------------------------------------------------- There was an entry  # ---------------------------------------------------------- There was an entry
         if ($syval) {          if ($syval) {
            unless ($syval=~/\_\d+$/) {      #unless ($syval=~/\_\d+$/) {
        unless ($ENV{'form.request.prefix'}=~/\.(\d+)\_$/) {   #unless ($env{'form.request.prefix'}=~/\.(\d+)\_$/) {
                   &appenv('request.ambiguous' => $thisfn);      #&appenv('request.ambiguous' => $thisfn);
   return $ENV{$cache_str}='';      #return $env{$cache_str}='';
                }       #}    
                $syval.=$1;   #$syval.=$1;
    }      #}
         } else {          } else {
 # ------------------------------------------------------- Was not in symb table  # ------------------------------------------------------- Was not in symb table
            if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',             if (tie(%bighash,'GDBM_File',$env{'request.course.fn'}.'.db',
                             &GDBM_READER(),0640)) {                              &GDBM_READER(),0640)) {
 # ---------------------------------------------- Get ID(s) for current resource  # ---------------------------------------------- Get ID(s) for current resource
               my $ids=$bighash{'ids_'.&clutter($thisfn)};                my $ids=$bighash{'ids_'.&clutter($thisfn)};
Line 4689  sub symbread { Line 6035  sub symbread {
                  if ($#possibilities==0) {                   if ($#possibilities==0) {
 # ----------------------------------------------- There is only one possibility  # ----------------------------------------------- There is only one possibility
      my ($mapid,$resid)=split(/\./,$ids);       my ($mapid,$resid)=split(/\./,$ids);
                      $syval=declutter($bighash{'map_id_'.$mapid}).'___'.$resid;       $syval=&encode_symb($bighash{'map_id_'.$mapid},
       $resid,$thisfn);
                  } elsif (!$donotrecurse) {                   } elsif (!$donotrecurse) {
 # ------------------------------------------ There is more than one possibility  # ------------------------------------------ There is more than one possibility
                      my $realpossible=0;                       my $realpossible=0;
Line 4699  sub symbread { Line 6046  sub symbread {
              my ($mapid,$resid)=split(/\./,$_);               my ($mapid,$resid)=split(/\./,$_);
                             if ($bighash{'map_type_'.$mapid} ne 'page') {                              if ($bighash{'map_type_'.$mapid} ne 'page') {
  $realpossible++;   $realpossible++;
                                 $syval=declutter($bighash{'map_id_'.$mapid}).                                  $syval=&encode_symb($bighash{'map_id_'.$mapid},
                                        '___'.$resid;      $resid,$thisfn);
                             }                              }
  }   }
                      }                       }
Line 4713  sub symbread { Line 6060  sub symbread {
            }             }
         }          }
         if ($syval) {          if ($syval) {
     return $ENV{$cache_str}=&symbclean($syval.'___'.$thisfn);      return $env{$cache_str}=$syval;
         }          }
     }      }
     &appenv('request.ambiguous' => $thisfn);      &appenv('request.ambiguous' => $thisfn);
     return $ENV{$cache_str}='';      return $env{$cache_str}='';
 }  }
   
 # ---------------------------------------------------------- Return random seed  # ---------------------------------------------------------- Return random seed
Line 4731  sub numval { Line 6078  sub numval {
     $txt=~tr/U-Z/0-5/;      $txt=~tr/U-Z/0-5/;
     $txt=~tr/u-z/0-5/;      $txt=~tr/u-z/0-5/;
     $txt=~s/\D//g;      $txt=~s/\D//g;
       if ($_64bit) { if ($txt > 2**32) { return -1; } }
     return int($txt);      return int($txt);
 }  }
   
Line 4746  sub numval2 { Line 6094  sub numval2 {
     my @txts=split(/(\d\d\d\d\d\d\d\d\d)/,$txt);      my @txts=split(/(\d\d\d\d\d\d\d\d\d)/,$txt);
     my $total;      my $total;
     foreach my $val (@txts) { $total+=$val; }      foreach my $val (@txts) { $total+=$val; }
       if ($_64bit) { if ($total > 2**32) { return -1; } }
     return int($total);      return int($total);
 }  }
   
   sub numval3 {
       use integer;
       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;
       my @txts=split(/(\d\d\d\d\d\d\d\d\d)/,$txt);
       my $total;
       foreach my $val (@txts) { $total+=$val; }
       if ($_64bit) { $total=(($total<<32)>>32); }
       return $total;
   }
   
   sub digest {
       my ($data)=@_;
       my $digest=&Digest::MD5::md5($data);
       my ($a,$b,$c,$d)=unpack("iiii",$digest);
       my ($e,$f);
       {
           use integer;
           $e=($a+$b);
           $f=($c+$d);
           if ($_64bit) {
               $e=(($e<<32)>>32);
               $f=(($f<<32)>>32);
           }
       }
       if (wantarray) {
    return ($e,$f);
       } else {
    my $g;
    {
       use integer;
       $g=($e+$f);
       if ($_64bit) {
    $g=(($g<<32)>>32);
       }
    }
    return $g;
       }
   }
   
 sub latest_rnd_algorithm_id {  sub latest_rnd_algorithm_id {
     return '64bit3';      return '64bit5';
 }  }
   
 sub get_rand_alg {  sub get_rand_alg {
     my ($courseid)=@_;      my ($courseid)=@_;
     if (!$courseid) { $courseid=(&Apache::lonxml::whichuser())[1]; }      if (!$courseid) { $courseid=(&Apache::lonxml::whichuser())[1]; }
     if ($courseid) {      if ($courseid) {
  return $ENV{"course.$courseid.rndseed"};   return $env{"course.$courseid.rndseed"};
     }      }
     return &latest_rnd_algorithm_id();      return &latest_rnd_algorithm_id();
 }  }
   
   sub validCODE {
       my ($CODE)=@_;
       if (defined($CODE) && $CODE ne '' && $CODE =~ /^\w+$/) { return 1; }
       return 0;
   }
   
 sub getCODE {  sub getCODE {
     if (defined($ENV{'form.CODE'})) { return $ENV{'form.CODE'}; }      if (&validCODE($env{'form.CODE'})) { return $env{'form.CODE'}; }
     if (defined($Apache::lonhomework::parsing_a_problem) &&      if ( (defined($Apache::lonhomework::parsing_a_problem) ||
  defined($Apache::lonhomework::history{'resource.CODE'})) {    defined($Apache::lonhomework::parsing_a_task) ) &&
    &validCODE($Apache::lonhomework::history{'resource.CODE'})) {
  return $Apache::lonhomework::history{'resource.CODE'};   return $Apache::lonhomework::history{'resource.CODE'};
     }      }
     return undef;      return undef;
Line 4783  sub rndseed { Line 6185  sub rndseed {
     if (!$username) { $username=$wusername }      if (!$username) { $username=$wusername }
     my $which=&get_rand_alg();      my $which=&get_rand_alg();
     if (defined(&getCODE())) {      if (defined(&getCODE())) {
  return &rndseed_CODE_64bit($symb,$courseid,$domain,$username);   if ($which eq '64bit5') {
       return &rndseed_CODE_64bit5($symb,$courseid,$domain,$username);
    } elsif ($which eq '64bit4') {
       return &rndseed_CODE_64bit4($symb,$courseid,$domain,$username);
    } else {
       return &rndseed_CODE_64bit($symb,$courseid,$domain,$username);
    }
       } elsif ($which eq '64bit5') {
    return &rndseed_64bit5($symb,$courseid,$domain,$username);
       } elsif ($which eq '64bit4') {
    return &rndseed_64bit4($symb,$courseid,$domain,$username);
     } elsif ($which eq '64bit3') {      } elsif ($which eq '64bit3') {
  return &rndseed_64bit3($symb,$courseid,$domain,$username);   return &rndseed_64bit3($symb,$courseid,$domain,$username);
     } elsif ($which eq '64bit2') {      } elsif ($which eq '64bit2') {
Line 4807  sub rndseed_32bit { Line 6219  sub rndseed_32bit {
  my $num=$symbseed+$nameseed+$domainseed+$courseseed+$namechck+$symbchck;   my $num=$symbseed+$nameseed+$domainseed+$courseseed+$namechck+$symbchck;
  #&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");   #&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
  #&Apache::lonxml::debug("rndseed :$num:$symb");   #&Apache::lonxml::debug("rndseed :$num:$symb");
    if ($_64bit) { $num=(($num<<32)>>32); }
  return $num;   return $num;
     }      }
 }  }
Line 4827  sub rndseed_64bit { Line 6240  sub rndseed_64bit {
  my $num2=$nameseed+$domainseed+$courseseed;   my $num2=$nameseed+$domainseed+$courseseed;
  #&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");   #&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
  #&Apache::lonxml::debug("rndseed :$num:$symb");   #&Apache::lonxml::debug("rndseed :$num:$symb");
    if ($_64bit) { $num1=(($num1<<32)>>32); $num2=(($num2<<32)>>32); }
    if ($_64bit) { $num1=(($num1<<32)>>32); $num2=(($num2<<32)>>32); }
  return "$num1,$num2";   return "$num1,$num2";
     }      }
 }  }
Line 4870  sub rndseed_64bit3 { Line 6285  sub rndseed_64bit3 {
  my $num1=$symbchck+$symbseed+$namechck;   my $num1=$symbchck+$symbseed+$namechck;
  my $num2=$nameseed+$domainseed+$courseseed;   my $num2=$nameseed+$domainseed+$courseseed;
  #&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");   #&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
  #&Apache::lonxml::debug("rndseed :$num:$symb");   #&Apache::lonxml::debug("rndseed :$num1:$num2:$_64bit");
    if ($_64bit) { $num1=(($num1<<32)>>32); $num2=(($num2<<32)>>32); }
   
    return "$num1:$num2";
       }
   }
   
   sub rndseed_64bit4 {
       my ($symb,$courseid,$domain,$username)=@_;
       {
    use integer;
    # strings need to be an even # of cahracters long, it it is odd the
           # last characters gets thrown away
    my $symbchck=unpack("%32S*",$symb.' ') << 21;
    my $symbseed=numval3($symb) << 10;
    my $namechck=unpack("%32S*",$username.' ');
   
    my $nameseed=numval3($username) << 21;
    my $domainseed=unpack("%32S*",$domain.' ') << 10;
    my $courseseed=unpack("%32S*",$courseid.' ');
   
    my $num1=$symbchck+$symbseed+$namechck;
    my $num2=$nameseed+$domainseed+$courseseed;
    #&Apache::lonxml::debug("$symbseed:$nameseed;$domainseed|$courseseed;$namechck:$symbchck");
    #&Apache::lonxml::debug("rndseed :$num1:$num2:$_64bit");
    if ($_64bit) { $num1=(($num1<<32)>>32); $num2=(($num2<<32)>>32); }
   
  return "$num1:$num2";   return "$num1:$num2";
     }      }
 }  }
   
   sub rndseed_64bit5 {
       my ($symb,$courseid,$domain,$username)=@_;
       my ($num1,$num2)=&digest("$symb,$courseid,$domain,$username");
       return "$num1:$num2";
   }
   
 sub rndseed_CODE_64bit {  sub rndseed_CODE_64bit {
     my ($symb,$courseid,$domain,$username)=@_;      my ($symb,$courseid,$domain,$username)=@_;
     {      {
Line 4888  sub rndseed_CODE_64bit { Line 6335  sub rndseed_CODE_64bit {
  my $num2=$CODEseed+$courseseed+$symbchck;   my $num2=$CODEseed+$courseseed+$symbchck;
  #&Apache::lonxml::debug("$symbseed:$CODEchck|$CODEseed:$courseseed:$symbchck");   #&Apache::lonxml::debug("$symbseed:$CODEchck|$CODEseed:$courseseed:$symbchck");
  #&Apache::lonxml::debug("rndseed :$num1:$num2:$symb");   #&Apache::lonxml::debug("rndseed :$num1:$num2:$symb");
    if ($_64bit) { $num1=(($num1<<32)>>32); }
    if ($_64bit) { $num2=(($num2<<32)>>32); }
    return "$num1:$num2";
       }
   }
   
   sub rndseed_CODE_64bit4 {
       my ($symb,$courseid,$domain,$username)=@_;
       {
    use integer;
    my $symbchck=unpack("%32S*",$symb.' ') << 16;
    my $symbseed=numval3($symb);
    my $CODEchck=unpack("%32S*",&getCODE().' ') << 16;
    my $CODEseed=numval3(&getCODE());
    my $courseseed=unpack("%32S*",$courseid.' ');
    my $num1=$symbseed+$CODEchck;
    my $num2=$CODEseed+$courseseed+$symbchck;
    #&Apache::lonxml::debug("$symbseed:$CODEchck|$CODEseed:$courseseed:$symbchck");
    #&Apache::lonxml::debug("rndseed :$num1:$num2:$symb");
    if ($_64bit) { $num1=(($num1<<32)>>32); }
    if ($_64bit) { $num2=(($num2<<32)>>32); }
  return "$num1:$num2";   return "$num1:$num2";
     }      }
 }  }
   
   sub rndseed_CODE_64bit5 {
       my ($symb,$courseid,$domain,$username)=@_;
       my $code = &getCODE();
       my ($num1,$num2)=&digest("$symb,$courseid,$code");
       return "$num1:$num2";
   }
   
 sub setup_random_from_rndseed {  sub setup_random_from_rndseed {
     my ($rndseed)=@_;      my ($rndseed)=@_;
     if ($rndseed =~/([,:])/) {      if ($rndseed =~/([,:])/) {
Line 4909  sub latest_receipt_algorithm_id { Line 6384  sub latest_receipt_algorithm_id {
 sub recunique {  sub recunique {
     my $fucourseid=shift;      my $fucourseid=shift;
     my $unique;      my $unique;
     if ($ENV{"course.$fucourseid.receiptalg"} eq 'receipt2') {      if ($env{"course.$fucourseid.receiptalg"} eq 'receipt2') {
  $unique=$ENV{"course.$fucourseid.internal.encseed"};   $unique=$env{"course.$fucourseid.internal.encseed"};
     } else {      } else {
  $unique=$perlvar{'lonReceipt'};   $unique=$perlvar{'lonReceipt'};
     }      }
Line 4920  sub recunique { Line 6395  sub recunique {
 sub recprefix {  sub recprefix {
     my $fucourseid=shift;      my $fucourseid=shift;
     my $prefix;      my $prefix;
     if ($ENV{"course.$fucourseid.receiptalg"} eq 'receipt2') {      if ($env{"course.$fucourseid.receiptalg"} eq 'receipt2') {
  $prefix=$ENV{"course.$fucourseid.internal.encpref"};   $prefix=$env{"course.$fucourseid.internal.encpref"};
     } else {      } else {
  $prefix=$perlvar{'lonHostID'};   $prefix=$perlvar{'lonHostID'};
     }      }
Line 4937  sub ireceipt { Line 6412  sub ireceipt {
     my $cunique=&recunique($fucourseid);      my $cunique=&recunique($fucourseid);
     my $cpart=unpack("%32S*",$part);      my $cpart=unpack("%32S*",$part);
     my $return =&recprefix($fucourseid).'-';      my $return =&recprefix($fucourseid).'-';
     if ($ENV{"course.$fucourseid.receiptalg"} eq 'receipt2' ||      if ($env{"course.$fucourseid.receiptalg"} eq 'receipt2' ||
  $ENV{'request.state'} eq 'construct') {   $env{'request.state'} eq 'construct') {
  &Apache::lonxml::debug("doing receipt2  using parts $cpart, uname $cuname and udom $cudom gets  ".($cpart%$cuname).   &Apache::lonxml::debug("doing receipt2  using parts $cpart, uname $cuname and udom $cudom gets  ".($cpart%$cuname).
        " and ".($cpart%$cudom));         " and ".($cpart%$cudom));
                 
Line 4978  sub receipt { Line 6453  sub receipt {
 # the local server.     # the local server.   
   
 sub getfile {  sub getfile {
     my ($file,$caller) = @_;      my ($file) = @_;
       if ($file =~ m -^/*(uploaded|editupload)/-) { $file=&filelocation("",$file); }
     if ($file !~ m|^/*uploaded/(\w+)/(\w+)/(.+)$|) {      &repcopy($file);
  # normal file from res space      return &readfile($file);
  &repcopy($file);  }
         return &readfile($file);  
     }  sub repcopy_userfile {
       my ($file)=@_;
     my $info;      if ($file =~ m -^/*(uploaded|editupload)/-) { $file=&filelocation("",$file); }
     my $cdom = $1;      if ($file =~ m|^/home/httpd/html/lonUsers/|) { return 'ok'; }
     my $cnum = $2;      my ($cdom,$cnum,$filename) = 
     my $filename = $3;   ($file=~m|^\Q$perlvar{'lonDocRoot'}\E/+userfiles/+([^/]+)/+([^/]+)/+(.*)|);
     my $path = $Apache::lonnet::perlvar{'lonDocRoot'}.'/userfiles';      my ($info,$rtncode);
     my ($lwpresp,$rtncode);      my $uri="/uploaded/$cdom/$cnum/$filename";
     my $localfile = $path.'/'.$cdom.'/'.$cnum.'/'.$filename;      if (-e "$file") {
     if (-e "$localfile") {   my @fileinfo = stat($file);
  my @fileinfo = stat($localfile);   my $lwpresp = &getuploaded('HEAD',$uri,$cdom,$cnum,\$info,\$rtncode);
  $lwpresp = &getuploaded('HEAD',$file,$cdom,$cnum,\$info,\$rtncode);  
  if ($lwpresp ne 'ok') {   if ($lwpresp ne 'ok') {
     if ($rtncode eq '404') {      if ($rtncode eq '404') {
  unlink($localfile);   unlink($file);
     }      }
     #my $ua=new LWP::UserAgent;      #my $ua=new LWP::UserAgent;
     #my $request=new HTTP::Request('GET',&tokenwrapper($file));      #my $request=new HTTP::Request('GET',&tokenwrapper($uri));
     #my $response=$ua->request($request);      #my $response=$ua->request($request);
     #if ($response->is_success()) {      #if ($response->is_success()) {
  # return $response->content;   # return $response->content;
Line 5011  sub getfile { Line 6485  sub getfile {
     return -1;      return -1;
  }   }
  if ($info < $fileinfo[9]) {   if ($info < $fileinfo[9]) {
     return &readfile($localfile);      return 'ok';
  }   }
  $info = '';   $info = '';
  $lwpresp = &getuploaded('GET',$file,$cdom,$cnum,\$info,\$rtncode);   $lwpresp = &getuploaded('GET',$uri,$cdom,$cnum,\$info,\$rtncode);
  if ($lwpresp ne 'ok') {   if ($lwpresp ne 'ok') {
     return -1;      return -1;
  }   }
     } else {      } else {
  $lwpresp = &getuploaded('GET',$file,$cdom,$cnum,\$info,\$rtncode);   my $lwpresp = &getuploaded('GET',$uri,$cdom,$cnum,\$info,\$rtncode);
  if ($lwpresp ne 'ok') {   if ($lwpresp ne 'ok') {
     my $ua=new LWP::UserAgent;      my $ua=new LWP::UserAgent;
     my $request=new HTTP::Request('GET',&tokenwrapper($file));      my $request=new HTTP::Request('GET',&tokenwrapper($uri));
     my $response=$ua->request($request);      my $response=$ua->request($request);
     if ($response->is_success()) {      if ($response->is_success()) {
  return $response->content;   $info=$response->content;
     } else {      } else {
  return -1;   return -1;
     }      }
Line 5034  sub getfile { Line 6508  sub getfile {
  if ($filename =~ m|^(.+)/[^/]+$|) {   if ($filename =~ m|^(.+)/[^/]+$|) {
     push @parts, split(/\//,$1);      push @parts, split(/\//,$1);
  }   }
    my $path = $perlvar{'lonDocRoot'}.'/userfiles';
  foreach my $part (@parts) {   foreach my $part (@parts) {
     $path .= '/'.$part;      $path .= '/'.$part;
     if (!-e $path) {      if (!-e $path) {
Line 5041  sub getfile { Line 6516  sub getfile {
     }      }
  }   }
     }      }
     open (FILE,">$localfile");      open(FILE,">$file");
     print FILE $info;      print FILE $info;
     close(FILE);      close(FILE);
     if ($caller eq 'uploadrep') {      return 'ok';
  return 'ok';  
     }  
     return $info;  
 }  }
   
 sub tokenwrapper {  sub tokenwrapper {
     my $uri=shift;      my $uri=shift;
     $uri=~s/^http\:\/\/([^\/]+)//;      $uri=~s|^http\://([^/]+)||;
     $uri=~s/^\///;      $uri=~s|^/||;
     $ENV{'user.environment'}=~/\/([^\/]+)\.id/;      $env{'user.environment'}=~/\/([^\/]+)\.id/;
     my $token=$1;      my $token=$1;
     if ($uri=~/^uploaded\/([^\/]+)\/([^\/]+)\/([^\/]+)(\?\.*)*$/) {      my (undef,$udom,$uname,$file)=split('/',$uri,4);
         &appenv('userfile.'.$1.'/'.$2.'/'.$3 => $ENV{'request.course.id'});      if ($udom && $uname && $file) {
         return 'http://'.$hostname{ &homeserver($2,$1)}.'/'.$uri.   $file=~s|(\?\.*)*$||;
           &appenv("userfile.$udom/$uname/$file" => $env{'request.course.id'});
           return 'http://'.$hostname{ &homeserver($uname,$udom)}.'/'.$uri.
                (($uri=~/\?/)?'&':'?').'token='.$token.                 (($uri=~/\?/)?'&':'?').'token='.$token.
                                '&tokenissued='.$perlvar{'lonHostID'};                                 '&tokenissued='.$perlvar{'lonHostID'};
     } else {      } else {
Line 5096  sub readfile { Line 6570  sub readfile {
 }  }
   
 sub filelocation {  sub filelocation {
   my ($dir,$file) = @_;      my ($dir,$file) = @_;
   my $location;      my $location;
   $file=~ s/^\s*(\S+)\s*$/$1/; ## strip off leading and trailing spaces      $file=~ s/^\s*(\S+)\s*$/$1/; ## strip off leading and trailing spaces
   if ($file=~m:^/~:) { # is a contruction space reference  
     $location = $file;      if ($file =~ m-^/adm/-) {
     $location =~ s:/~(.*?)/(.*):/home/$1/public_html/$2:;   $file=~s-^/adm/wrapper/-/-;
   } elsif ($file=~/^\/*uploaded/) { # is an uploaded file   $file=~s-^/adm/coursedocs/showdoc/-/-;
     $location=$file;      }
   } else {      if ($file=~m:^/~:) { # is a contruction space reference
     $file=~s/^\Q$perlvar{'lonDocRoot'}\E//;          $location = $file;
     $file=~s:^/res/:/:;          $location =~ s:/~(.*?)/(.*):/home/$1/public_html/$2:;
     if ( !( $file =~ m:^/:) ) {      } elsif ($file=~m:^/home/[^/]*/public_html/:) {
       $location = $dir. '/'.$file;   # is a correct contruction space reference
           $location = $file;
       } elsif ($file=~/^\/*(uploaded|editupload)/) { # is an uploaded file
           my ($udom,$uname,$filename)=
        ($file=~m -^/+(?:uploaded|editupload)/+([^/]+)/+([^/]+)/+(.*)$-);
           my $home=&homeserver($uname,$udom);
           my $is_me=0;
           my @ids=&current_machine_ids();
           foreach my $id (@ids) { if ($id eq $home) { $is_me=1; } }
           if ($is_me) {
        $location=&propath($udom,$uname).
          '/userfiles/'.$filename;
           } else {
      $location=$Apache::lonnet::perlvar{'lonDocRoot'}.'/userfiles/'.
          $udom.'/'.$uname.'/'.$filename;
           }
     } else {      } else {
       $location = '/home/httpd/html/res'.$file;          $file=~s/^\Q$perlvar{'lonDocRoot'}\E//;
           $file=~s:^/res/:/:;
           if ( !( $file =~ m:^/:) ) {
               $location = $dir. '/'.$file;
           } else {
               $location = '/home/httpd/html/res'.$file;
           }
     }      }
   }      $location=~s://+:/:g; # remove duplicate /
   $location=~s://+:/:g; # remove duplicate /      while ($location=~m:/\.\./:) {$location=~ s:/[^/]+/\.\./:/:g;} #remove dir/..
   while ($location=~m:/\.\./:) {$location=~ s:/[^/]+/\.\./:/:g;} #remove dir/..      while ($location=~m:/\./:) {$location=~ s:/\./:/:g;} #remove /./
   while ($location=~m:/\./:) {$location=~ s:/\./:/:g;} #remove /./      return $location;
   return $location;  
 }  }
   
 sub hreflocation {  sub hreflocation {
     my ($dir,$file)=@_;      my ($dir,$file)=@_;
     unless (($file=~m-^http://-i) || ($file=~m-^/-)) {      unless (($file=~m-^http://-i) || ($file=~m-^/-)) {
  my $finalpath=filelocation($dir,$file);   $file=filelocation($dir,$file);
  $finalpath=~s-^/home/httpd/html--;      } elsif ($file=~m-^/adm/-) {
  $finalpath=~s-^/home/(\w+)/public_html/-/~$1/-;   $file=~s-^/adm/wrapper/-/-;
  return $finalpath;   $file=~s-^/adm/coursedocs/showdoc/-/-;
     } elsif ($file=~m-^/home-) {      }
  $file=~s-^/home/httpd/html--;      if ($file=~m-^\Q$perlvar{'lonDocRoot'}\E-) {
    $file=~s-^\Q$perlvar{'lonDocRoot'}\E--;
       } elsif ($file=~m-/home/(\w+)/public_html/-) {
  $file=~s-^/home/(\w+)/public_html/-/~$1/-;   $file=~s-^/home/(\w+)/public_html/-/~$1/-;
  return $file;      } elsif ($file=~m-^\Q$perlvar{'lonUsersDir'}\E-) {
    $file=~s-^/home/httpd/lonUsers/([^/]*)/./././([^/]*)/userfiles/
       -/uploaded/$1/$2/-x;
     }      }
     return $file;      return $file;
 }  }
Line 5162  sub current_machine_ids { Line 6660  sub current_machine_ids {
   
 sub declutter {  sub declutter {
     my $thisfn=shift;      my $thisfn=shift;
       if ($thisfn=~m|^/enc/|) { $thisfn=&Apache::lonenc::unencrypted($thisfn); }
     $thisfn=~s/^\Q$perlvar{'lonDocRoot'}\E//;      $thisfn=~s/^\Q$perlvar{'lonDocRoot'}\E//;
     $thisfn=~s/^\///;      $thisfn=~s/^\///;
       $thisfn=~s|^adm/wrapper/||;
       $thisfn=~s|^adm/coursedocs/showdoc/||;
     $thisfn=~s/^res\///;      $thisfn=~s/^res\///;
     $thisfn=~s/\?.+$//;      $thisfn=~s/\?.+$//;
     return $thisfn;      return $thisfn;
Line 5173  sub declutter { Line 6674  sub declutter {
   
 sub clutter {  sub clutter {
     my $thisfn='/'.&declutter(shift);      my $thisfn='/'.&declutter(shift);
     unless ($thisfn=~/^\/(uploaded|adm|userfiles|ext|raw|priv|public)\//) {       unless ($thisfn=~/^\/(uploaded|editupload|adm|userfiles|ext|raw|priv|public)\//) { 
        $thisfn='/res'.$thisfn;          $thisfn='/res'.$thisfn; 
     }      }
       if ($thisfn !~m|/adm|) {
    if ($thisfn =~ m|/ext/|) {
       $thisfn='/adm/wrapper'.$thisfn;
    } else {
       my ($ext) = ($thisfn =~ /\.(\w+)$/);
       my $embstyle=&Apache::loncommon::fileembstyle($ext);
       if ($embstyle eq 'ssi'
    || ($embstyle eq 'hdn')
    || ($embstyle eq 'rat')
    || ($embstyle eq 'prv')
    || ($embstyle eq 'ign')) {
    #do nothing with these
       } elsif (($embstyle eq 'img') 
    || ($embstyle eq 'emb')
    || ($embstyle eq 'wrp')) {
    $thisfn='/adm/wrapper'.$thisfn;
       } elsif ($embstyle eq 'unk'
        && $thisfn!~/\.(sequence|page)$/) {
    $thisfn='/adm/coursedocs/showdoc'.$thisfn;
       } else {
   # &logthis("Got a blank emb style");
       }
    }
       }
     return $thisfn;      return $thisfn;
 }  }
   
 # -------------------------------------------------------- Escape Special Chars  sub freeze_escape {
       my ($value)=@_;
 sub escape {      if (ref($value)) {
     my $str=shift;   $value=&nfreeze($value);
     $str =~ s/(\W)/"%".unpack('H2',$1)/eg;   return '__FROZEN__'.&escape($value);
     return $str;      }
       return &escape($value);
 }  }
   
 # ----------------------------------------------------- Un-Escape Special Chars  
   
 sub unescape {  
     my $str=shift;  
     $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;  
     return $str;  
 }  
   
 sub mod_perl_version {  sub thaw_unescape {
     if (defined($perlvar{'MODPERL2'})) {      my ($value)=@_;
  return 2;      if ($value =~ /^__FROZEN__/) {
    substr($value,0,10,undef);
    $value=&unescape($value);
    return &thaw($value);
     }      }
     return 1;      return &unescape($value);
 }  }
   
 sub correct_line_ends {  sub correct_line_ends {
Line 5212  sub correct_line_ends { Line 6734  sub correct_line_ends {
 sub goodbye {  sub goodbye {
    &logthis("Starting Shut down");     &logthis("Starting Shut down");
 #not converted to using infrastruture and probably shouldn't be  #not converted to using infrastruture and probably shouldn't be
    &logthis(sprintf("%-20s is %s",'%badServerCache',scalar(%badServerCache)));     &logthis(sprintf("%-20s is %s",'%badServerCache',length(&freeze(\%badServerCache))));
 #converted  #converted
    &logthis(sprintf("%-20s is %s",'%metacache',scalar(%metacache)));  #   &logthis(sprintf("%-20s is %s",'%metacache',scalar(%metacache)));
    &logthis(sprintf("%-20s is %s",'%homecache',scalar(%homecache)));     &logthis(sprintf("%-20s is %s",'%homecache',length(&freeze(\%homecache))));
    &logthis(sprintf("%-20s is %s",'%titlecache',scalar(%titlecache)));  #   &logthis(sprintf("%-20s is %s",'%titlecache',length(&freeze(\%titlecache))));
    &logthis(sprintf("%-20s is %s",'%courseresdatacache',scalar(%courseresdatacache)));  #   &logthis(sprintf("%-20s is %s",'%courseresdatacache',length(&freeze(\%courseresdatacache))));
 #1.1 only  #1.1 only
    &logthis(sprintf("%-20s is %s",'%userresdatacache',scalar(%userresdatacache)));  #   &logthis(sprintf("%-20s is %s",'%userresdatacache',length(&freeze(\%userresdatacache))));
    &logthis(sprintf("%-20s is %s",'%usectioncache',scalar(%usectioncache)));  #   &logthis(sprintf("%-20s is %s",'%getsectioncache',length(&freeze(\%getsectioncache))));
    &logthis(sprintf("%-20s is %s",'%courseresversioncache',scalar(%courseresversioncache)));  #   &logthis(sprintf("%-20s is %s",'%courseresversioncache',length(&freeze(\%courseresversioncache))));
    &logthis(sprintf("%-20s is %s",'%resversioncache',scalar(%resversioncache)));  #   &logthis(sprintf("%-20s is %s",'%resversioncache',length(&freeze(\%resversioncache))));
      &logthis(sprintf("%-20s is %s",'%remembered',length(&freeze(\%remembered))));
      &logthis(sprintf("%-20s is %s",'kicks',$kicks));
      &logthis(sprintf("%-20s is %s",'hits',$hits));
    &flushcourselogs();     &flushcourselogs();
    &logthis("Shutting down");     &logthis("Shutting down");
    return DONE;  
 }  }
   
 BEGIN {  BEGIN {
 # ----------------------------------- Read loncapa.conf and loncapa_apache.conf  # ----------------------------------- Read loncapa.conf and loncapa_apache.conf
     unless ($readit) {      unless ($readit) {
 {  {
       # FIXME: Use LONCAPA::Configuration::read_conf here and omit next block
     open(my $config,"</etc/httpd/conf/loncapa.conf");      open(my $config,"</etc/httpd/conf/loncapa.conf");
   
     while (my $configline=<$config>) {      while (my $configline=<$config>) {
Line 5268  BEGIN { Line 6793  BEGIN {
 #           next if /^\#/;  #           next if /^\#/;
            chomp;             chomp;
            my ($domain, $domain_description, $def_auth, $def_auth_arg,             my ($domain, $domain_description, $def_auth, $def_auth_arg,
        $def_lang, $city, $longi, $lati) = split(/:/,$_);         $def_lang, $city, $longi, $lati, $primary) = split(/:/,$_);
    $domain_auth_def{$domain}=$def_auth;     $domain_auth_def{$domain}=$def_auth;
            $domain_auth_arg_def{$domain}=$def_auth_arg;             $domain_auth_arg_def{$domain}=$def_auth_arg;
    $domaindescription{$domain}=$domain_description;     $domaindescription{$domain}=$domain_description;
Line 5276  BEGIN { Line 6801  BEGIN {
    $domain_city{$domain}=$city;     $domain_city{$domain}=$city;
    $domain_longi{$domain}=$longi;     $domain_longi{$domain}=$longi;
    $domain_lati{$domain}=$lati;     $domain_lati{$domain}=$lati;
              $domain_primary{$domain}=$primary;
   
  #         &logthis("Domain.tab: $domain, $domain_auth_def{$domain}, $domain_auth_arg_def{$domain},$domaindescription{$domain}");   #         &logthis("Domain.tab: $domain, $domain_auth_def{$domain}, $domain_auth_arg_def{$domain},$domaindescription{$domain}");
 #          &logthis("Domain.tab: $domain ".$domaindescription{$domain} );  #          &logthis("Domain.tab: $domain ".$domaindescription{$domain} );
Line 5292  BEGIN { Line 6818  BEGIN {
     while (my $configline=<$config>) {      while (my $configline=<$config>) {
        next if ($configline =~ /^(\#|\s*$)/);         next if ($configline =~ /^(\#|\s*$)/);
        chomp($configline);         chomp($configline);
        my ($id,$domain,$role,$name,$ip,$domdescr)=split(/:/,$configline);         my ($id,$domain,$role,$name)=split(/:/,$configline);
        if ($id && $domain && $role && $name && $ip) {         $name=~s/\s//g;
          if ($id && $domain && $role && $name) {
  $hostname{$id}=$name;   $hostname{$id}=$name;
  $hostdom{$id}=$domain;   $hostdom{$id}=$domain;
  $hostip{$id}=$ip;  
  $iphost{$ip}=$id;  
  if ($role eq 'library') { $libserv{$id}=$name; }   if ($role eq 'library') { $libserv{$id}=$name; }
        } else {  
  if ($configline) {  
    &logthis("Skipping hosts.tab line -$configline-");  
  }  
        }         }
     }      }
     close($config);      close($config);
       # FIXME: dev server don't want this, production servers _do_ want this
       #&get_iphost();
   }
   
   sub get_iphost {
       if (%iphost) { return %iphost; }
       my %name_to_ip;
       foreach my $id (keys(%hostname)) {
    my $name=$hostname{$id};
    my $ip;
    if (!exists($name_to_ip{$name})) {
       $ip = gethostbyname($name);
       if (!$ip || length($ip) ne 4) {
    &logthis("Skipping host $id name $name no IP found\n");
    next;
       }
       $ip=inet_ntoa($ip);
       $name_to_ip{$name} = $ip;
    } else {
       $ip = $name_to_ip{$name};
    }
    push(@{$iphost{$ip}},$id);
       }
       return %iphost;
 }  }
   
 # ------------------------------------------------------ Read spare server file  # ------------------------------------------------------ Read spare server file
Line 5341  BEGIN { Line 6886  BEGIN {
     while (my $configline=<$config>) {      while (my $configline=<$config>) {
  chomp($configline);   chomp($configline);
  if ($configline) {   if ($configline) {
     my ($short,$plain)=split(/:/,$configline);      my ($short,@plain)=split(/:/,$configline);
     if ($plain ne '') { $prp{$short}=$plain; }              %{$prp{$short}} = ();
       if (@plain > 0) {
                   $prp{$short}{'std'} = $plain[0];
                   for (my $i=1; $i<@plain; $i++) {
                       $prp{$short}{'alt'.$i} = $plain[$i];  
                   }
               }
  }   }
     }      }
     close($config);      close($config);
Line 5371  BEGIN { Line 6922  BEGIN {
   
 }  }
   
 %metacache=();  $memcache=new Cache::Memcached({'servers'=>['127.0.0.1:11211']});
   
 $processmarker='_'.time.'_'.$perlvar{'lonHostID'};  $processmarker='_'.time.'_'.$perlvar{'lonHostID'};
 $dumpcount=0;  $dumpcount=0;
   
 &logtouch();  &logtouch();
 &logthis('<font color=yellow>INFO: Read configuration</font>');  &logthis('<font color="yellow">INFO: Read configuration</font>');
 $readit=1;  $readit=1;
       {
    use integer;
    my $test=(2**32)+1;
    if ($test != 0) { $_64bit=1; } else { $_64bit=0; }
    &logthis(" Detected 64bit platform ($_64bit)");
       }
 }  }
 }  }
   
Line 5553  that was requested Line 7110  that was requested
 X<appenv()>  X<appenv()>
 B<appenv(%hash)>: the value of %hash is written to  B<appenv(%hash)>: the value of %hash is written to
 the user envirnoment file, and will be restored for each access this  the user envirnoment file, and will be restored for each access this
 user makes during this session, also modifies the %ENV for the current  user makes during this session, also modifies the %env for the current
 process  process
   
 =item *  =item *
 X<delenv()>  X<delenv()>
 B<delenv($regexp)>: removes all items from the session  B<delenv($regexp)>: removes all items from the session
 environment file that matches the regular expression in $regexp. The  environment file that matches the regular expression in $regexp. The
 values are also delted from the current processes %ENV.  values are also delted from the current processes %env.
   
 =back  =back
   
Line 5606  X<rolesinit()> Line 7163  X<rolesinit()>
 B<rolesinit($udom,$username,$authhost)>: get user privileges  B<rolesinit($udom,$username,$authhost)>: get user privileges
   
 =item *  =item *
 X<usection()>  X<getsection()>
 B<usection($udom,$uname,$cname)>: finds the section of student in the  B<getsection($udom,$uname,$cname)>: finds the section of student in the
 course $cname, return section name/number or '' for "not in course"  course $cname, return section name/number or '' for "not in course"
 and '-1' for "no section"  and '-1' for "no section"
   
Line 5773  revokecustomrole($udom,$uname,$url,$role Line 7330  revokecustomrole($udom,$uname,$url,$role
   
 =item *  =item *
   
 coursedescription($courseid) : course description  coursedescription($courseid) : returns a hash of information about the
   specified course id, including all environment settings for the
   course, the description of the course will be in the hash under the
   key 'description'
   
 =item *  =item *
   
 courseresdata($coursenum,$coursedomain,@which) : request for current  resdata($name,$domain,$type,@which) : request for current parameter
 parameter setting for a specific course, @what should be a list of  setting for a specific $type, where $type is either 'course' or 'user',
 parameters to ask about. This routine caches answers for 5 minutes.  @what should be a list of parameters to ask about. This routine caches
   answers for 5 minutes.
   
 =back  =back
   
Line 5810  subscribe($fname) : subscribe to a resou Line 7371  subscribe($fname) : subscribe to a resou
   
 repcopy($filename) : subscribes to the requested file, and attempts to  repcopy($filename) : subscribes to the requested file, and attempts to
 replicate from the owning library server, Might return  replicate from the owning library server, Might return
 HTTP_SERVICE_UNAVAILABLE, HTTP_NOT_FOUND, FORBIDDEN, OK, or  'unavailable', 'not_found', 'forbidden', 'ok', or
 HTTP_BAD_REQUEST, also attempts to grab the metadata for the  'bad_request', also attempts to grab the metadata for the
 resource. Expects the local filesystem pathname  resource. Expects the local filesystem pathname
 (/home/httpd/html/res/....)  (/home/httpd/html/res/....)
   
Line 5865  returns the data handle Line 7426  returns the data handle
 =item *  =item *
   
 symbverify($symb,$thisfn) : verifies that $symb actually exists and is  symbverify($symb,$thisfn) : verifies that $symb actually exists and is
 a possible symb for the URL in $thisfn, returns a 1 on success, 0 on  a possible symb for the URL in $thisfn, and if is an encryypted
 failure, user must be in a course, as it assumes the existance of the  resource that the user accessed using /enc/ returns a 1 on success, 0
 course initi hash, and uses $ENV('request.course.id'}  on failure, user must be in a course, as it assumes the existance of
   the course initial hash, and uses $env('request.course.id'}
   
   
 =item *  =item *
Line 5898  unfakeable, receipt Line 7460  unfakeable, receipt
   
 =item *  =item *
   
 receipt() : API to ireceipt working off of ENV values; given out to users  receipt() : API to ireceipt working off of env values; given out to users
   
 =item *  =item *
   
Line 5932  forcing spreadsheet to reevaluate the re Line 7494  forcing spreadsheet to reevaluate the re
 store($storehash,$symb,$namespace,$udom,$uname) : stores hash permanently  store($storehash,$symb,$namespace,$udom,$uname) : stores hash permanently
 for this url; hashref needs to be given and should be a \%hashname; the  for this url; hashref needs to be given and should be a \%hashname; the
 remaining args aren't required and if they aren't passed or are '' they will  remaining args aren't required and if they aren't passed or are '' they will
 be derived from the ENV  be derived from the env
   
 =item *  =item *
   
Line 5946  all args are optional Line 7508  all args are optional
   
 =item *  =item *
   
   dumpstore($namespace,$udom,$uname,$regexp,$range) : 
   dumps the complete (or key matching regexp) namespace into a hash
   ($udom, $uname, $regexp, $range are optional) for a namespace that is
   normally &store()ed into
   
   $range should be either an integer '100' (give me the first 100
                                              matching records)
                 or be  two integers sperated by a - with no spaces
                    '30-50' (give me the 30th through the 50th matching
                             records)
   
   
   =item *
   
   putstore($namespace,$symb,$version,$storehash,$udomain,$uname) :
   replaces a &store() version of data with a replacement set of data
   for a particular resource in a namespace passed in the $storehash hash 
   reference
   
   =item *
   
 tmpstore($storehash,$symb,$namespace,$udom,$uname) : storage that  tmpstore($storehash,$symb,$namespace,$udom,$uname) : storage that
 works very similar to store/cstore, but all data is stored in a  works very similar to store/cstore, but all data is stored in a
 temporary location and can be reset using tmpreset, $storehash should  temporary location and can be reset using tmpreset, $storehash should
Line 5975  namesp ($udom and $uname are optional) Line 7558  namesp ($udom and $uname are optional)
   
 =item *  =item *
   
 dump($namespace,$udom,$uname,$regexp) :   dump($namespace,$udom,$uname,$regexp,$range) : 
 dumps the complete (or key matching regexp) namespace into a hash  dumps the complete (or key matching regexp) namespace into a hash
 ($udom, $uname and $regexp are optional)  ($udom, $uname, $regexp, $range are optional)
   
   $range should be either an integer '100' (give me the first 100
                                              matching records)
                 or be  two integers sperated by a - with no spaces
                    '30-50' (give me the 30th through the 50th matching
                             records)
 =item *  =item *
   
 inc($namespace,$store,$udom,$uname) : increments $store in $namespace.  inc($namespace,$store,$udom,$uname) : increments $store in $namespace.
Line 6123  getfile($file,$caller) : two cases - req Line 7711  getfile($file,$caller) : two cases - req
    - returns the entire contents of a file or -1;      - returns the entire contents of a file or -1; 
    it properly subscribes to and replicates the file if neccessary.     it properly subscribes to and replicates the file if neccessary.
   
   
   =item *
   
   stat_file($url) : $url is expected to be a /res/ or /uploaded/ style file
                     reference
   
   returns either a stat() list of data about the file or an empty list
   if the file doesn't exist or couldn't find out about it (connection
   problems or user unknown)
   
 =item *  =item *
   
 filelocation($dir,$file) : returns file system location of a file  filelocation($dir,$file) : returns file system location of a file
Line 6141  declutter() : declutters URLs (remove do Line 7739  declutter() : declutters URLs (remove do
   
 =back  =back
   
   =head2 Usererfile file routines (/uploaded*)
   
   =over 4
   
   =item *
   
   userfileupload(): main rotine for putting a file in a user or course's
                     filespace, arguments are,
   
    formname - required - this is the name of the element in $env where the
              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
    subdir - required - subdirectory to put the file in under ../userfiles/
            if undefined, it will be placed in "unknown"
   
    (This routine calls clean_filename() to remove any dangerous
    characters from the filename, and then calls finuserfileupload() to
    complete the transaction)
   
    returns either the url of the uploaded file (/uploaded/....) if successful
    and /adm/notfound.html if unsuccessful
   
   =item *
   
   clean_filename(): routine for cleaing a filename up for storage in
                    userfile space, argument is:
   
    filename - proposed filename
   
   returns: the new clean filename
   
   =item *
   
   finishuserfileupload(): routine that creaes 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
   
    returns either the url of the uploaded file (/uploaded/....) if successful
    and /adm/notfound.html if unsuccessful
   
   =item *
   
   renameuserfile(): renames an existing userfile to a new name
   
     Args:
      docuname: username or courseid of destination for the file
      docudom: domain of user/course of destination for the file
      old: current file name (including any subdirs under userfiles)
      new: desired file name (including any subdirs under userfiles)
   
   =item *
   
   mkdiruserfile(): creates a directory is a userfiles dir
   
     Args:
      docuname: username or courseid of destination for the file
      docudom: domain of user/course of destination for the file
      dir: dir to create (including any subdirs under userfiles)
   
   =item *
   
   removeuserfile(): removes a file that exists in userfiles
   
     Args:
      docuname: username or courseid of destination for the file
      docudom: domain of user/course of destination for the file
      fname: filname to delete (including any subdirs under userfiles)
   
   =item *
   
   removeuploadedurl(): convience function for removeuserfile()
   
     Args:
      url:  a full /uploaded/... url to delete
   
   =back
   
 =head2 HTTP Helper Routines  =head2 HTTP Helper Routines
   
 =over 4  =over 4

Removed from v.1.523.2.8  
changed lines
  Added in v.1.745


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>