Diff for /loncom/lonnet/perl/lonnet.pm between versions 1.1172.2.118.2.7 and 1.1296

version 1.1172.2.118.2.7, 2020/09/08 02:08:27 version 1.1296, 2015/12/03 20:40:42
Line 74  use strict; Line 74  use strict;
 use LWP::UserAgent();  use LWP::UserAgent();
 use HTTP::Date;  use HTTP::Date;
 use Image::Magick;  use Image::Magick;
 use CGI::Cookie;  
   
 use vars qw(%perlvar %spareid %pr %prp $memcache %packagetab $tmpdir $deftex  
   use Encode;
   
   use vars qw(%perlvar %spareid %pr %prp $memcache %packagetab $tmpdir
             $_64bit %env %protocol %loncaparevs %serverhomeIDs %needsrelease              $_64bit %env %protocol %loncaparevs %serverhomeIDs %needsrelease
             %managerstab $passwdmin);              %managerstab);
   
 my (%badServerCache, $memcache, %courselogs, %accesshash, %domainrolehash,  my (%badServerCache, $memcache, %courselogs, %accesshash, %domainrolehash,
     %userrolehash, $processmarker, $dumpcount, %coursedombuf,      %userrolehash, $processmarker, $dumpcount, %coursedombuf,
Line 99  use LONCAPA qw(:DEFAULT :match); Line 101  use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::Configuration;  use LONCAPA::Configuration;
 use LONCAPA::lonmetadata;  use LONCAPA::lonmetadata;
 use LONCAPA::Lond;  use LONCAPA::Lond;
 use LONCAPA::transliterate;  
   
 use File::Copy;  use File::Copy;
   
Line 111  require Exporter; Line 112  require Exporter;
 our @ISA = qw (Exporter);  our @ISA = qw (Exporter);
 our @EXPORT = qw(%env);  our @EXPORT = qw(%env);
   
   
 # ------------------------------------ Logging (parameters, docs, slots, roles)  # ------------------------------------ Logging (parameters, docs, slots, roles)
 {  {
     my $logid;      my $logid;
Line 125  our @EXPORT = qw(%env); Line 127  our @EXPORT = qw(%env);
  $logid ++;   $logid ++;
         my $now = time();          my $now = time();
  my $id=$now.'00000'.$$.'00000'.$logid;   my $id=$now.'00000'.$$.'00000'.$logid;
         my $logentry = {          my $logentry = { 
                          $id => {                            $id => {
                                   'exe_uname' => $env{'user.name'},                                     'exe_uname' => $env{'user.name'},
                                   'exe_udom'  => $env{'user.domain'},                                     'exe_udom'  => $env{'user.domain'},
                                   'exe_time'  => $now,                                     'exe_time'  => $now,
                                   'exe_ip'    => $ENV{'REMOTE_ADDR'},                                     'exe_ip'    => $ENV{'REMOTE_ADDR'},
                                   'delflag'   => $delflag,                                     'delflag'   => $delflag,
                                   'logentry'  => $storehash,                                     'logentry'  => $storehash,
                                   'uname'     => $uname,                                     'uname'     => $uname,
                                   'udom'      => $udom,                                     'udom'      => $udom,
                                 }                                    }
                        };                         };
         return &put('nohist_'.$hash_name,$logentry,$cdom,$cnum);   return &put('nohist_'.$hash_name,$logentry,$cdom,$cnum);
     }      }
 }  }
   
 sub logtouch {  sub logtouch {
     my $execdir=$perlvar{'lonDaemons'};      my $execdir=$perlvar{'lonDaemons'};
     unless (-e "$execdir/logs/lonnet.log") {      unless (-e "$execdir/logs/lonnet.log") {
  open(my $fh,">>","$execdir/logs/lonnet.log");   open(my $fh,">>$execdir/logs/lonnet.log");
  close $fh;   close $fh;
     }      }
     my ($wwwuid,$wwwgid)=(getpwnam('www'))[2,3];      my ($wwwuid,$wwwgid)=(getpwnam('www'))[2,3];
Line 156  sub logthis { Line 158  sub logthis {
     my $execdir=$perlvar{'lonDaemons'};      my $execdir=$perlvar{'lonDaemons'};
     my $now=time;      my $now=time;
     my $local=localtime($now);      my $local=localtime($now);
     if (open(my $fh,">>","$execdir/logs/lonnet.log")) {      if (open(my $fh,">>$execdir/logs/lonnet.log")) {
  my $logstring = $local. " ($$): ".$message."\n"; # Keep any \'s in string.   my $logstring = $local. " ($$): ".$message."\n"; # Keep any \'s in string.
  print $fh $logstring;   print $fh $logstring;
  close($fh);   close($fh);
Line 169  sub logperm { Line 171  sub logperm {
     my $execdir=$perlvar{'lonDaemons'};      my $execdir=$perlvar{'lonDaemons'};
     my $now=time;      my $now=time;
     my $local=localtime($now);      my $local=localtime($now);
     if (open(my $fh,">>","$execdir/logs/lonnet.perm.log")) {      if (open(my $fh,">>$execdir/logs/lonnet.perm.log")) {
  print $fh "$now:$message:$local\n";   print $fh "$now:$message:$local\n";
  close($fh);   close($fh);
     }      }
Line 263  sub get_server_loncaparev { Line 265  sub get_server_loncaparev {
                 if ($caller eq 'loncron') {                  if ($caller eq 'loncron') {
                     my $ua=new LWP::UserAgent;                      my $ua=new LWP::UserAgent;
                     $ua->timeout(4);                      $ua->timeout(4);
                     my $hostname = &hostname($lonhost);  
                     my $protocol = $protocol{$lonhost};                      my $protocol = $protocol{$lonhost};
                     $protocol = 'http' if ($protocol ne 'https');                      $protocol = 'http' if ($protocol ne 'https');
                     my $url = $protocol.'://'.$hostname.'/adm/about.html';                      my $url = $protocol.'://'.&hostname($lonhost).'/adm/about.html';
                     my $request=new HTTP::Request('GET',$url);                      my $request=new HTTP::Request('GET',$url);
                     my $response=$ua->request($request);                      my $response=$ua->request($request);
                     unless ($response->is_error()) {                      unless ($response->is_error()) {
Line 359  sub remote_devalidate_cache { Line 360  sub remote_devalidate_cache {
     my $items;      my $items;
     return unless (ref($cachekeys) eq 'ARRAY');      return unless (ref($cachekeys) eq 'ARRAY');
     my $cachestr = join('&',@{$cachekeys});      my $cachestr = join('&',@{$cachekeys});
     return &reply('devalidatecache:'.&escape($cachestr),$lonhost);      my $response = &reply('devalidatecache:'.&escape($cachestr),$lonhost);
       return $response;
 }  }
   
 # -------------------------------------------------- Non-critical communication  # -------------------------------------------------- Non-critical communication
Line 391  sub subreply { Line 393  sub subreply {
  } else {   } else {
     &create_connection(&hostname($server),$server);      &create_connection(&hostname($server),$server);
  }   }
         sleep(0.1); # Try again later if failed connection.          sleep(0.1); # Try again later if failed connection.
     }      }
     my $answer;      my $answer;
     if ($client) {      if ($client) {
Line 410  sub reply { Line 412  sub reply {
     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=~/^refused/) || ($answer=~/^rejected/)) {      if (($answer=~/^refused/) || ($answer=~/^rejected/)) {
         my $logged = $cmd;         &logthis("<font color=\"blue\">WARNING:".
         if ($cmd =~ /^encrypt:([^:]+):/) {                  " $cmd to $server returned $answer</font>");
             my $subcmd = $1;  
             if (($subcmd eq 'auth') || ($subcmd eq 'passwd') ||  
                 ($subcmd eq 'changeuserauth') || ($subcmd eq 'makeuser') ||  
                 ($subcmd eq 'putdom') || ($subcmd eq 'autoexportgrades')) {  
                 (undef,undef,my @rest) = split(/:/,$cmd);  
                 if (($subcmd eq 'auth') || ($subcmd eq 'putdom')) {  
                     splice(@rest,2,1,'Hidden');  
                 } elsif ($subcmd eq 'passwd') {  
                     splice(@rest,2,2,('Hidden','Hidden'));  
                 } elsif (($subcmd eq 'changeuserauth') || ($subcmd eq 'makeuser') ||  
                          ($subcmd eq 'autoexportgrades')) {  
                     splice(@rest,3,1,'Hidden');  
                 }  
                 $logged = join(':',('encrypt:'.$subcmd,@rest));  
             }  
         }  
         &logthis("<font color=\"blue\">WARNING:".  
                  " $logged to $server returned $answer</font>");  
     }      }
     return $answer;      return $answer;
 }  }
Line 457  sub reconlonc { Line 441  sub reconlonc {
   
     &logthis("Trying to reconnect lonc");      &logthis("Trying to reconnect lonc");
     my $loncfile="$perlvar{'lonDaemons'}/logs/lonc.pid";      my $loncfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
     if (open(my $fh,"<",$loncfile)) {      if (open(my $fh,"<$loncfile")) {
  my $loncpid=<$fh>;   my $loncpid=<$fh>;
         chomp($loncpid);          chomp($loncpid);
         if (kill 0 => $loncpid) {          if (kill 0 => $loncpid) {
     &logthis("lonc at pid $loncpid responding, sending USR1");      &logthis("lonc at pid $loncpid responding, sending USR1");
             kill USR1 => $loncpid;              kill USR1 => $loncpid;
             sleep 1;              sleep 1;
          } 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>");
Line 497  sub critical { Line 481  sub critical {
             $dumpcount++;              $dumpcount++;
             {              {
  my $dfh;   my $dfh;
  if (open($dfh,">",$dfilename)) {   if (open($dfh,">$dfilename")) {
     print $dfh "$cmd\n";       print $dfh "$cmd\n"; 
     close($dfh);      close($dfh);
  }   }
Line 506  sub critical { Line 490  sub critical {
             my $wcmd='';              my $wcmd='';
             {              {
  my $dfh;   my $dfh;
  if (open($dfh,"<",$dfilename)) {   if (open($dfh,"<$dfilename")) {
     $wcmd=<$dfh>;       $wcmd=<$dfh>; 
     close($dfh);      close($dfh);
  }   }
Line 622  sub transfer_profile_to_env { Line 606  sub transfer_profile_to_env {
   
 # ---------------------------------------------------- Check for valid session   # ---------------------------------------------------- Check for valid session 
 sub check_for_valid_session {  sub check_for_valid_session {
     my ($r,$name,$userhashref,$domref) = @_;      my ($r,$name,$userhashref) = @_;
     my %cookies=CGI::Cookie->parse($r->header_in('Cookie'));      my %cookies=CGI::Cookie->parse($r->header_in('Cookie'));
     my ($lonidsdir,$linkname,$pubname,$secure,$lonid);      if ($name eq '') {
     if ($name eq 'lonDAV') {          $name = 'lonID';
         $lonidsdir=$r->dir_config('lonDAVsessDir');  
     } else {  
         $lonidsdir=$r->dir_config('lonIDsDir');  
         if ($name eq '') {  
             $name = 'lonID';  
         }  
     }  
     if ($name eq 'lonID') {  
         $secure = 'lonSID';  
         $linkname = 'lonLinkID';  
         $pubname = 'lonPubID';  
         if (exists($cookies{$secure})) {  
             $lonid=$cookies{$secure};  
         } elsif (exists($cookies{$name})) {  
             $lonid=$cookies{$name};  
         } elsif ((exists($cookies{$linkname})) && ($ENV{'SERVER_PORT'} != 443)) {  
             $lonid=$cookies{$linkname};  
         } elsif (exists($cookies{$pubname})) {  
             $lonid=$cookies{$pubname};  
         }  
     } else {  
         $lonid=$cookies{$name};  
     }      }
       my $lonid=$cookies{$name};
     return undef if (!$lonid);      return undef if (!$lonid);
   
     my $handle=&LONCAPA::clean_handle($lonid->value);      my $handle=&LONCAPA::clean_handle($lonid->value);
     if (-l "$lonidsdir/$handle.id") {      my $lonidsdir;
         my $link = readlink("$lonidsdir/$handle.id");      if ($name eq 'lonDAV') {
         if ((-e $link) && ($link =~ m{^\Q$lonidsdir\E/(.+)\.id$})) {          $lonidsdir=$r->dir_config('lonDAVsessDir');
             $handle = $1;      } else {
         }          $lonidsdir=$r->dir_config('lonIDsDir');
     }  
     if (!-e "$lonidsdir/$handle.id") {  
         if ((ref($domref)) && ($name eq 'lonID') &&  
             ($handle =~ /^($match_username)\_\d+\_($match_domain)\_(.+)$/)) {  
             my ($possuname,$possudom,$possuhome) = ($1,$2,$3);  
             if ((&domain($possudom) ne '') && (&homeserver($possuname,$possudom) eq $possuhome)) {  
                 $$domref = $possudom;  
             }  
         }  
         return undef;  
     }      }
       return undef if (!-e "$lonidsdir/$handle.id");
   
     my $opened = open(my $idf,'+<',"$lonidsdir/$handle.id");      my $opened = open(my $idf,'+<',"$lonidsdir/$handle.id");
     return undef if (!$opened);      return undef if (!$opened);
Line 681  sub check_for_valid_session { Line 635  sub check_for_valid_session {
   
     if (!defined($disk_env{'user.name'})      if (!defined($disk_env{'user.name'})
  || !defined($disk_env{'user.domain'})) {   || !defined($disk_env{'user.domain'})) {
         untie(%disk_env);  
  return undef;   return undef;
     }      }
   
Line 689  sub check_for_valid_session { Line 642  sub check_for_valid_session {
         $userhashref->{'name'} = $disk_env{'user.name'};          $userhashref->{'name'} = $disk_env{'user.name'};
         $userhashref->{'domain'} = $disk_env{'user.domain'};          $userhashref->{'domain'} = $disk_env{'user.domain'};
     }      }
     untie(%disk_env);  
   
     return $handle;      return $handle;
 }  }
Line 714  sub timed_flock { Line 666  sub timed_flock {
     }      }
 }  }
   
 sub get_sessionfile_vars {  
     my ($handle,$lonidsdir,$storearr) = @_;  
     my %returnhash;  
     unless (ref($storearr) eq 'ARRAY') {  
         return %returnhash;  
     }  
     if (-l "$lonidsdir/$handle.id") {  
         my $link = readlink("$lonidsdir/$handle.id");  
         if ((-e $link) && ($link =~ m{^\Q$lonidsdir\E/(.+)\.id$})) {  
             $handle = $1;  
         }  
     }  
     if ((-e "$lonidsdir/$handle.id") &&  
         ($handle =~ /^($match_username)\_\d+\_($match_domain)\_(.+)$/)) {  
         my ($possuname,$possudom,$possuhome) = ($1,$2,$3);  
         if ((&domain($possudom) ne '') && (&homeserver($possuname,$possudom) eq $possuhome)) {  
             if (open(my $idf,'+<',"$lonidsdir/$handle.id")) {  
                 flock($idf,LOCK_SH);  
                 if (tie(my %disk_env,'GDBM_File',"$lonidsdir/$handle.id",  
                         &GDBM_READER(),0640)) {  
                     foreach my $item (@{$storearr}) {  
                         $returnhash{$item} = $disk_env{$item};  
                     }  
                     untie(%disk_env);  
                 }  
             }  
         }  
     }  
     return %returnhash;  
 }  
   
 # ---------------------------------------------------------- Append Environment  # ---------------------------------------------------------- Append Environment
   
 sub appenv {  sub appenv {
Line 770  sub appenv { Line 691  sub appenv {
                 $env{$key}=$newenv->{$key};                  $env{$key}=$newenv->{$key};
             }              }
         }          }
         my $lonids = $perlvar{'lonIDsDir'};          my $opened = open(my $env_file,'+<',$env{'user.environment'});
         if ($env{'user.environment'} =~ m{^\Q$lonids/\E$match_username\_\d+\_$match_domain\_[\w\-.]+\.id$}) {          if ($opened
             my $opened = open(my $env_file,'+<',$env{'user.environment'});      && &timed_flock($env_file,LOCK_EX)
             if ($opened      &&
         && &timed_flock($env_file,LOCK_EX)      tie(my %disk_env,'GDBM_File',$env{'user.environment'},
         &&          (&GDBM_WRITER()|&GDBM_NOLOCK()),0640)) {
         tie(my %disk_env,'GDBM_File',$env{'user.environment'},      while (my ($key,$value) = each(%{$newenv})) {
             (&GDBM_WRITER()|&GDBM_NOLOCK()),0640)) {          $disk_env{$key} = $value;
         while (my ($key,$value) = each(%{$newenv})) {      }
             $disk_env{$key} = $value;      untie(%disk_env);
         }  
         untie(%disk_env);  
             }  
         }          }
     }      }
     return 'ok';      return 'ok';
Line 898  sub userload { Line 816  sub userload {
  while ($filename=readdir(LONIDS)) {   while ($filename=readdir(LONIDS)) {
     next if ($filename eq '.' || $filename eq '..');      next if ($filename eq '.' || $filename eq '..');
     next if ($filename =~ /publicuser_\d+\.id/);      next if ($filename =~ /publicuser_\d+\.id/);
             next if ($filename =~ /^[a-f0-9]+_linked\.id$/);  
     my ($mtime)=(stat($perlvar{'lonIDsDir'}.'/'.$filename))[9];      my ($mtime)=(stat($perlvar{'lonIDsDir'}.'/'.$filename))[9];
     if ($curtime-$mtime < 1800) { $numusers++; }      if ($curtime-$mtime < 1800) { $numusers++; }
  }   }
Line 954  sub spareserver { Line 871  sub spareserver {
     }      }
   
     if (!$want_server_name) {      if (!$want_server_name) {
           my $protocol = 'http';
           if ($protocol{$spare_server} eq 'https') {
               $protocol = $protocol{$spare_server};
           }
         if (defined($spare_server)) {          if (defined($spare_server)) {
             my $hostname = &hostname($spare_server);              my $hostname = &hostname($spare_server);
             if (defined($hostname)) {              if (defined($hostname)) {
                 my $protocol = 'http';  
                 if ($protocol{$spare_server} eq 'https') {  
                     $protocol = $protocol{$spare_server};  
                 }  
         $spare_server = $protocol.'://'.$hostname;          $spare_server = $protocol.'://'.$hostname;
             }              }
         }          }
Line 1027  sub find_existing_session { Line 944  sub find_existing_session {
     return;      return;
 }  }
   
 # check if user's browser sent load balancer cookie and server still has session  
 # and is not overloaded.  
 sub check_for_balancer_cookie {  
     my ($r,$update_mtime) = @_;  
     my ($otherserver,$cookie);  
     my %cookies=CGI::Cookie->parse($r->header_in('Cookie'));  
     if (exists($cookies{'balanceID'})) {  
         my $balid = $cookies{'balanceID'};  
         $cookie=&LONCAPA::clean_handle($balid->value);  
         my $balancedir=$r->dir_config('lonBalanceDir');  
         if ((-d $balancedir) && (-e "$balancedir/$cookie.id")) {  
             if ($cookie =~ /^($match_domain)_($match_username)_[a-f0-9]+$/) {  
                 my ($possudom,$possuname) = ($1,$2);  
                 my $has_session = 0;  
                 if ((&domain($possudom) ne '') &&  
                     (&homeserver($possuname,$possudom) ne 'no_host')) {  
                     my $try_server;  
                     my $opened = open(my $idf,'+<',"$balancedir/$cookie.id");  
                     if ($opened) {  
                         flock($idf,LOCK_SH);  
                         while (my $line = <$idf>) {  
                             chomp($line);  
                             if (&hostname($line) ne '') {  
                                 $try_server = $line;  
                                 last;  
                             }  
                         }  
                         close($idf);  
                         if (($try_server) &&  
                             (&has_user_session($try_server,$possudom,$possuname))) {  
                             my $lowest_load = 30000;  
                             ($otherserver,$lowest_load) =  
                                 &compare_server_load($try_server,undef,$lowest_load);  
                             if ($otherserver ne '' && $lowest_load < 100) {  
                                 $has_session = 1;  
                             } else {  
                                 undef($otherserver);  
                             }  
                         }  
                     }  
                 }  
                 if ($has_session) {  
                     if ($update_mtime) {  
                         my $atime = my $mtime = time;  
                         utime($atime,$mtime,"$balancedir/$cookie.id");  
                     }  
                 } else {  
                     unlink("$balancedir/$cookie.id");  
                 }  
             }  
         }  
     }  
     return ($otherserver,$cookie);  
 }  
   
 sub delbalcookie {  
     my ($cookie,$balancer) =@_;  
     if ($cookie =~ /^($match_domain)\_($match_username)\_[a-f0-9]{32}$/) {  
         my ($udom,$uname) = ($1,$2);  
         my $uprimary_id = &domain($udom,'primary');  
         my $uintdom = &internet_dom($uprimary_id);  
         my $intdom = &internet_dom($balancer);  
         my $serverhomedom = &host_domain($balancer);  
         if (($uintdom ne '') && ($uintdom eq $intdom)) {  
             return &reply("delbalcookie:$cookie",$balancer);  
         }  
     }  
 }  
   
 # -------------------------------- ask if server already has a session for user  # -------------------------------- ask if server already has a session for user
 sub has_user_session {  sub has_user_session {
     my ($lonid,$udom,$uname) = @_;      my ($lonid,$udom,$uname) = @_;
Line 1127  sub choose_server { Line 975  sub choose_server {
         }          }
     }      }
     foreach my $lonhost (keys(%servers)) {      foreach my $lonhost (keys(%servers)) {
         my $loginvia;  
         if ($skiploadbal) {          if ($skiploadbal) {
             if (ref($balancers) eq 'HASH') {              if (ref($balancers) eq 'HASH') {
                 next if (exists($balancers->{$lonhost}));                  next if (exists($balancers->{$lonhost}));
             }              }
         }          }   
           my $loginvia;
         if ($checkloginvia) {          if ($checkloginvia) {
             $loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost};              $loginvia = $domconfhash{$udom.'.login.loginvia_'.$lonhost};
             if ($loginvia) {              if ($loginvia) {
Line 1159  sub choose_server { Line 1007  sub choose_server {
     if ($login_host ne '') {      if ($login_host ne '') {
         $hostname = &hostname($login_host);          $hostname = &hostname($login_host);
     }      }
     return ($login_host,$hostname,$portal_path,$isredirect,$lowest_load);      return ($login_host,$hostname,$portal_path,$isredirect);
 }  
   
 sub get_course_sessions {  
     my ($cnum,$cdom,$lastactivity) = @_;  
     my %servers = &internet_dom_servers($cdom);  
     my %returnhash;  
     foreach my $server (sort(keys(%servers))) {  
         my $rep = &reply("coursesessions:$cdom:$cnum:$lastactivity",$server);  
         my @pairs=split(/\&/,$rep);  
         unless (($rep eq 'unknown_cmd') || ($rep =~ /^error/)) {  
             foreach my $item (@pairs) {  
                 my ($key,$value)=split(/=/,$item,2);  
                 $key = &unescape($key);  
                 next if ($key =~ /^error: 2 /);  
                 if (exists($returnhash{$key})) {  
                     next if ($value < $returnhash{$key});  
                 }  
                 $returnhash{$key}=$value;  
             }  
         }  
     }  
     return %returnhash;  
 }  }
   
 # --------------------------------------------- Try to change a user's password  # --------------------------------------------- Try to change a user's password
Line 1219  sub changepass { Line 1045  sub changepass {
     } elsif ($answer =~ "invalid_client") {      } elsif ($answer =~ "invalid_client") {
         &logthis("$server refused to change $uname in $udom password because ".          &logthis("$server refused to change $uname in $udom password because ".
                  "it was a reset by e-mail originating from an invalid server.");                   "it was a reset by e-mail originating from an invalid server.");
     } elsif ($answer =~ "^prioruse") {  
        &logthis("$server refused to change $uname in $udom password because ".  
                 "the password had been used before");  
     }      }
     return $answer;      return $answer;
 }  }
Line 1456  sub get_lonbalancer_config { Line 1279  sub get_lonbalancer_config {
 }  }
   
 sub check_loadbalancing {  sub check_loadbalancing {
     my ($uname,$udom,$caller) = @_;      my ($uname,$udom) = @_;
     my ($is_balancer,$currtargets,$currrules,$dom_in_use,$homeintdom,      my ($is_balancer,$currtargets,$currrules,$dom_in_use,$homeintdom,
         $rule_in_effect,$offloadto,$otherserver,$setcookie);          $rule_in_effect,$offloadto,$otherserver);
     my $lonhost = $perlvar{'lonHostID'};      my $lonhost = $perlvar{'lonHostID'};
     my @hosts = &current_machine_ids();      my @hosts = &current_machine_ids();
     my $uprimary_id = &Apache::lonnet::domain($udom,'primary');      my $uprimary_id = &Apache::lonnet::domain($udom,'primary');
     my $uintdom = &Apache::lonnet::internet_dom($uprimary_id);      my $uintdom = &Apache::lonnet::internet_dom($uprimary_id);
     my $intdom = &Apache::lonnet::internet_dom($lonhost);      my $intdom = &Apache::lonnet::internet_dom($lonhost);
     my $serverhomedom = &host_domain($lonhost);      my $serverhomedom = &host_domain($lonhost);
     my $domneedscache;   
     my $cachetime = 60*60*24;      my $cachetime = 60*60*24;
   
     if (($uintdom ne '') && ($uintdom eq $intdom)) {      if (($uintdom ne '') && ($uintdom eq $intdom)) {
Line 1480  sub check_loadbalancing { Line 1303  sub check_loadbalancing {
             &Apache::lonnet::get_dom('configuration',['loadbalancing'],$dom_in_use);              &Apache::lonnet::get_dom('configuration',['loadbalancing'],$dom_in_use);
         if (ref($domconfig{'loadbalancing'}) eq 'HASH') {          if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
             $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'loadbalancing'},$cachetime);              $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'loadbalancing'},$cachetime);
         } else {  
             $domneedscache = $dom_in_use;  
         }          }
     }      }
     if (ref($result) eq 'HASH') {      if (ref($result) eq 'HASH') {
         ($is_balancer,$currtargets,$currrules,$setcookie) =          ($is_balancer,$currtargets,$currrules) = 
             &check_balancer_result($result,@hosts);              &check_balancer_result($result,@hosts);
         if ($is_balancer) {          if ($is_balancer) {
             if (ref($currrules) eq 'HASH') {              if (ref($currrules) eq 'HASH') {
Line 1540  sub check_loadbalancing { Line 1361  sub check_loadbalancing {
             my %domconfig =              my %domconfig =
                 &Apache::lonnet::get_dom('configuration',['loadbalancing'],$serverhomedom);                  &Apache::lonnet::get_dom('configuration',['loadbalancing'],$serverhomedom);
             if (ref($domconfig{'loadbalancing'}) eq 'HASH') {              if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
                 $result = &do_cache_new('loadbalancing',$serverhomedom,$domconfig{'loadbalancing'},$cachetime);                  $result = &do_cache_new('loadbalancing',$dom_in_use,$domconfig{'loadbalancing'},$cachetime);
             } else {  
                 $domneedscache = $serverhomedom;  
             }              }
         }          }
         if (ref($result) eq 'HASH') {          if (ref($result) eq 'HASH') {
             ($is_balancer,$currtargets,$currrules,$setcookie) =              ($is_balancer,$currtargets,$currrules) = 
                 &check_balancer_result($result,@hosts);                  &check_balancer_result($result,@hosts);
             if ($is_balancer) {              if ($is_balancer) {
                 if (ref($currrules) eq 'HASH') {                  if (ref($currrules) eq 'HASH') {
Line 1562  sub check_loadbalancing { Line 1381  sub check_loadbalancing {
                 $is_balancer = 1;                  $is_balancer = 1;
                 $offloadto = &this_host_spares($dom_in_use);                  $offloadto = &this_host_spares($dom_in_use);
             }              }
             unless (defined($cached)) {  
                 $domneedscache = $serverhomedom;  
             }  
         }          }
     } else {      } else {
         if ($perlvar{'lonBalancer'} eq 'yes') {          if ($perlvar{'lonBalancer'} eq 'yes') {
             $is_balancer = 1;              $is_balancer = 1;
             $offloadto = &this_host_spares($dom_in_use);              $offloadto = &this_host_spares($dom_in_use);
         }          }
         unless (defined($cached)) {  
             $domneedscache = $serverhomedom;  
         }  
     }  
     if ($domneedscache) {  
         &do_cache_new('loadbalancing',$domneedscache,$is_balancer,$cachetime);  
     }      }
     if ($is_balancer) {      if ($is_balancer) {
         my $lowest_load = 30000;          my $lowest_load = 30000;
Line 1607  sub check_loadbalancing { Line 1417  sub check_loadbalancing {
                 }                  }
             }              }
         }          }
         unless ($caller eq 'login') {          if (($otherserver ne '') && (grep(/^\Q$otherserver\E$/,@hosts))) {
             if (($otherserver ne '') && (grep(/^\Q$otherserver\E$/,@hosts))) {              $is_balancer = 0;
                 $is_balancer = 0;              if ($uname ne '' && $udom ne '') {
                 if ($uname ne '' && $udom ne '') {                  if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) {
                     if (($env{'user.name'} eq $uname) && ($env{'user.domain'} eq $udom)) {                      
                         &appenv({'user.loadbalexempt'     => $lonhost,                      &appenv({'user.loadbalexempt'     => $lonhost,  
                                  'user.loadbalcheck.time' => time});                               'user.loadbalcheck.time' => time});
                     }  
                 }                  }
             }              }
         }          }
         unless ($homeintdom) {  
             undef($setcookie);  
         }  
     }      }
     return ($is_balancer,$otherserver,$setcookie);      return ($is_balancer,$otherserver);
 }  }
   
 sub check_balancer_result {  sub check_balancer_result {
     my ($result,@hosts) = @_;      my ($result,@hosts) = @_;
     my ($is_balancer,$currtargets,$currrules,$setcookie);      my ($is_balancer,$currtargets,$currrules);
     if (ref($result) eq 'HASH') {      if (ref($result) eq 'HASH') {
         if ($result->{'lonhost'} ne '') {          if ($result->{'lonhost'} ne '') {
             my $currbalancer = $result->{'lonhost'};              my $currbalancer = $result->{'lonhost'};
Line 1643  sub check_balancer_result { Line 1449  sub check_balancer_result {
                     $is_balancer = 1;                      $is_balancer = 1;
                     $currrules = $result->{$key}{'rules'};                      $currrules = $result->{$key}{'rules'};
                     $currtargets = $result->{$key}{'targets'};                      $currtargets = $result->{$key}{'targets'};
                     $setcookie = $result->{$key}{'cookie'};  
                     last;                      last;
                 }                  }
             }              }
         }          }
     }      }
     return ($is_balancer,$currtargets,$currrules,$setcookie);      return ($is_balancer,$currtargets,$currrules);
 }  }
   
 sub get_loadbalancer_targets {  sub get_loadbalancer_targets {
Line 1754  sub idget { Line 1559  sub idget {
           
     my %servers = &get_servers($udom,'library');      my %servers = &get_servers($udom,'library');
     foreach my $tryserver (keys(%servers)) {      foreach my $tryserver (keys(%servers)) {
  my $idlist=join('&', map { &escape($_); } @ids);   my $idlist=join('&',@ids);
  $idlist=~tr/A-Z/a-z/;    $idlist=~tr/A-Z/a-z/; 
  my $reply=&reply("idget:$udom:".$idlist,$tryserver);   my $reply=&reply("idget:$udom:".$idlist,$tryserver);
  my @answer=();   my @answer=();
Line 1764  sub idget { Line 1569  sub idget {
  my $i;   my $i;
  for ($i=0;$i<=$#ids;$i++) {   for ($i=0;$i<=$#ids;$i++) {
     if ($answer[$i]) {      if ($answer[$i]) {
  $returnhash{$ids[$i]}=&unescape($answer[$i]);   $returnhash{$ids[$i]}=$answer[$i];
     }       } 
  }   }
     }       } 
Line 1806  sub idput { Line 1611  sub idput {
     }      }
 }  }
   
 # ---------------------------------------- Delete unwanted IDs from ids.db file  # ---------------------------------------- Delete unwanted IDs from ids.db file 
   
 sub iddel {  sub iddel {
     my ($udom,$idshashref,$uhome)=@_;      my ($udom,$idshashref,$uhome)=@_;
Line 1873  sub get_dom { Line 1678  sub get_dom {
         }          }
     }      }
     if ($udom && $uhome && ($uhome ne 'no_host')) {      if ($udom && $uhome && ($uhome ne 'no_host')) {
         my $rep;          my $rep=&reply("getdom:$udom:$namespace:$items",$uhome);
         if ($namespace =~ /^enc/) {  
             $rep=&reply("encrypt:egetdom:$udom:$namespace:$items",$uhome);  
         } else {  
             $rep=&reply("getdom:$udom:$namespace:$items",$uhome);  
         }  
         my %returnhash;          my %returnhash;
         if ($rep eq '' || $rep =~ /^error: 2 /) {          if ($rep eq '' || $rep =~ /^error: 2 /) {
             return %returnhash;              return %returnhash;
Line 1922  sub put_dom { Line 1722  sub put_dom {
             $items.=&escape($item).'='.&freeze_escape($$storehash{$item}).'&';              $items.=&escape($item).'='.&freeze_escape($$storehash{$item}).'&';
         }          }
         $items=~s/\&$//;          $items=~s/\&$//;
         if ($namespace =~ /^enc/) {          return &reply("putdom:$udom:$namespace:$items",$uhome);
             return &reply("encrypt:putdom:$udom:$namespace:$items",$uhome);  
         } else {  
             return &reply("putdom:$udom:$namespace:$items",$uhome);  
         }  
     } else {      } else {
         &logthis("put_dom failed - no homeserver and/or domain");          &logthis("put_dom failed - no homeserver and/or domain");
     }      }
Line 2002  sub retrieve_inst_usertypes { Line 1798  sub retrieve_inst_usertypes {
   
 sub is_domainimage {  sub is_domainimage {
     my ($url) = @_;      my ($url) = @_;
     if ($url=~m-^/+res/+($match_domain)/+\1\-domainconfig/+(img|logo|domlogo)/+[^/]-) {      if ($url=~m-^/+res/+($match_domain)/+\1\-domainconfig/+(img|logo|domlogo)/+-) {
         if (&domain($1) ne '') {          if (&domain($1) ne '') {
             return '1';              return '1';
         }          }
Line 2017  sub inst_directory_query { Line 1813  sub inst_directory_query {
     my $homeserver = &domain($udom,'primary');      my $homeserver = &domain($udom,'primary');
     my $outcome;      my $outcome;
     if ($homeserver ne '') {      if ($homeserver ne '') {
         unless ($homeserver eq $perlvar{'lonHostID'}) {  
             if ($srch->{'srchby'} eq 'email') {  
                 my $lcrev = &get_server_loncaparev($udom,$homeserver);  
                 my ($major,$minor,$subver) = ($lcrev =~ /^\'?(\d+)\.(\d+)\.(\d+)[\w.\-]+\'?$/);  
                 if (($major eq '' && $minor eq '') || ($major < 2) ||  
                     (($major == 2) && ($minor < 11)) ||  
                     (($major == 2) && ($minor == 11) && ($subver < 3))) {  
                     return;  
                 }  
             }  
         }  
  my $queryid=&reply("querysend:instdirsearch:".   my $queryid=&reply("querysend:instdirsearch:".
    &escape($srch->{'srchby'}).':'.     &escape($srch->{'srchby'}).':'.
    &escape($srch->{'srchterm'}).':'.     &escape($srch->{'srchterm'}).':'.
    &escape($srch->{'srchtype'}),$homeserver);     &escape($srch->{'srchtype'}),$homeserver);
  my $host=&hostname($homeserver);   my $host=&hostname($homeserver);
  if ($queryid !~/^\Q$host\E\_/) {   if ($queryid !~/^\Q$host\E\_/) {
     &logthis('institutional directory search invalid queryid: '.$queryid.' for host: '.$homeserver.' in domain '.$udom);      &logthis('instituional directory search invalid queryid: '.$queryid.' for host: '.$homeserver.'in domain '.$udom);
     return;      return;
  }   }
  my $response = &get_query_reply($queryid);   my $response = &get_query_reply($queryid);
Line 2069  sub usersearch { Line 1854  sub usersearch {
     my $query = 'usersearch';      my $query = 'usersearch';
     foreach my $tryserver (keys(%libserv)) {      foreach my $tryserver (keys(%libserv)) {
         if (&host_domain($tryserver) eq $dom) {          if (&host_domain($tryserver) eq $dom) {
             unless ($tryserver eq $perlvar{'lonHostID'}) {  
                 if ($srch->{'srchby'} eq 'email') {  
                     my $lcrev = &get_server_loncaparev($dom,$tryserver);  
                     my ($major,$minor,$subver) = ($lcrev =~ /^\'?(\d+)\.(\d+)\.(\d+)[\w.\-]+\'?$/);  
                     next if (($major eq '' && $minor eq '') || ($major < 2) ||  
                              (($major == 2) && ($minor < 11)) ||  
                              (($major == 2) && ($minor == 11) && ($subver < 3)));  
                 }  
             }  
             my $host=&hostname($tryserver);              my $host=&hostname($tryserver);
             my $queryid=              my $queryid=
                 &reply("querysend:".&escape($query).':'.                  &reply("querysend:".&escape($query).':'.
Line 2167  sub get_multiple_instusers { Line 1943  sub get_multiple_instusers {
     my ($udom,$users,$caller) = @_;      my ($udom,$users,$caller) = @_;
     my ($outcome,$results);      my ($outcome,$results);
     if (ref($users) eq 'HASH') {      if (ref($users) eq 'HASH') {
         my $count = keys(%{$users});          my $count = keys(%{$users}); 
         my $requested = &freeze_escape($users);          my $requested = &freeze_escape($users);
         my $homeserver = &domain($udom,'primary');          my $homeserver = &domain($udom,'primary');
         if ($homeserver ne '') {          if ($homeserver ne '') {
Line 2211  sub get_multiple_instusers { Line 1987  sub get_multiple_instusers {
                 } else {                  } else {
                     ($outcome,my $userdata) = split(/=/,$response,2);                      ($outcome,my $userdata) = split(/=/,$response,2);
                     if ($outcome eq 'ok') {                      if ($outcome eq 'ok') {
                         $results = &thaw_unescape($userdata);                          $results = &thaw_unescape($userdata); 
                     }                      }
                 }                  }
             }              }
Line 2316  sub get_domain_defaults { Line 2092  sub get_domain_defaults {
                                   'requestcourses','inststatus',                                    'requestcourses','inststatus',
                                   'coursedefaults','usersessions',                                    'coursedefaults','usersessions',
                                   'requestauthor','selfenrollment',                                    'requestauthor','selfenrollment',
                                   'coursecategories','autoenroll',                                    'coursecategories'],$domain);
                                   'helpsettings'],$domain);  
     my @coursetypes = ('official','unofficial','community','textbook');      my @coursetypes = ('official','unofficial','community','textbook');
     if (ref($domconfig{'defaults'}) eq 'HASH') {      if (ref($domconfig{'defaults'}) eq 'HASH') {
         $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'};           $domdefaults{'lang_def'} = $domconfig{'defaults'}{'lang_def'}; 
Line 2326  sub get_domain_defaults { Line 2101  sub get_domain_defaults {
         $domdefaults{'timezone_def'} = $domconfig{'defaults'}{'timezone_def'};          $domdefaults{'timezone_def'} = $domconfig{'defaults'}{'timezone_def'};
         $domdefaults{'datelocale_def'} = $domconfig{'defaults'}{'datelocale_def'};          $domdefaults{'datelocale_def'} = $domconfig{'defaults'}{'datelocale_def'};
         $domdefaults{'portal_def'} = $domconfig{'defaults'}{'portal_def'};          $domdefaults{'portal_def'} = $domconfig{'defaults'}{'portal_def'};
         $domdefaults{'intauth_cost'} = $domconfig{'defaults'}{'intauth_cost'};  
         $domdefaults{'intauth_switch'} = $domconfig{'defaults'}{'intauth_switch'};  
         $domdefaults{'intauth_check'} = $domconfig{'defaults'}{'intauth_check'};  
     } else {      } else {
         $domdefaults{'lang_def'} = &domain($domain,'lang_def');          $domdefaults{'lang_def'} = &domain($domain,'lang_def');
         $domdefaults{'auth_def'} = &domain($domain,'auth_def');          $domdefaults{'auth_def'} = &domain($domain,'auth_def');
Line 2364  sub get_domain_defaults { Line 2136  sub get_domain_defaults {
         }          }
     }      }
     if (ref($domconfig{'coursedefaults'}) eq 'HASH') {      if (ref($domconfig{'coursedefaults'}) eq 'HASH') {
           $domdefaults{'canuse_pdfforms'} = $domconfig{'coursedefaults'}{'canuse_pdfforms'};
         $domdefaults{'usejsme'} = $domconfig{'coursedefaults'}{'usejsme'};          $domdefaults{'usejsme'} = $domconfig{'coursedefaults'}{'usejsme'};
         $domdefaults{'uselcmath'} = $domconfig{'coursedefaults'}{'uselcmath'};          $domdefaults{'uselcmath'} = $domconfig{'coursedefaults'}{'uselcmath'};
         if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') {          if (ref($domconfig{'coursedefaults'}{'postsubmit'}) eq 'HASH') {
Line 2380  sub get_domain_defaults { Line 2153  sub get_domain_defaults {
             }              }
             if ($domdefaults{'postsubmit'} eq 'on') {              if ($domdefaults{'postsubmit'} eq 'on') {
                 if (ref($domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') {                  if (ref($domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}) eq 'HASH') {
                     $domdefaults{$type.'postsubtimeout'} =                      $domdefaults{$type.'postsubtimeout'} = 
                         $domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}{$type};                          $domconfig{'coursedefaults'}{'postsubmit'}{'timeout'}{$type}; 
                 }                  }
             }              }
         }          }
Line 2395  sub get_domain_defaults { Line 2168  sub get_domain_defaults {
         } elsif ($domconfig{'coursedefaults'}{'canclone'}) {          } elsif ($domconfig{'coursedefaults'}{'canclone'}) {
             $domdefaults{'canclone'}=$domconfig{'coursedefaults'}{'canclone'};              $domdefaults{'canclone'}=$domconfig{'coursedefaults'}{'canclone'};
         }          }
         if ($domconfig{'coursedefaults'}{'texengine'}) {  
             $domdefaults{'texengine'} = $domconfig{'coursedefaults'}{'texengine'};  
         }  
     }      }
     if (ref($domconfig{'usersessions'}) eq 'HASH') {      if (ref($domconfig{'usersessions'}) eq 'HASH') {
         if (ref($domconfig{'usersessions'}{'remote'}) eq 'HASH') {          if (ref($domconfig{'usersessions'}{'remote'}) eq 'HASH') {
Line 2441  sub get_domain_defaults { Line 2211  sub get_domain_defaults {
     if (ref($domconfig{'coursecategories'}) eq 'HASH') {      if (ref($domconfig{'coursecategories'}) eq 'HASH') {
         $domdefaults{'catauth'} = 'std';          $domdefaults{'catauth'} = 'std';
         $domdefaults{'catunauth'} = 'std';          $domdefaults{'catunauth'} = 'std';
         if ($domconfig{'coursecategories'}{'auth'}) {          if ($domconfig{'coursecategories'}{'auth'}) { 
             $domdefaults{'catauth'} = $domconfig{'coursecategories'}{'auth'};              $domdefaults{'catauth'} = $domconfig{'coursecategories'}{'auth'};
         }          }
         if ($domconfig{'coursecategories'}{'unauth'}) {          if ($domconfig{'coursecategories'}{'unauth'}) {
             $domdefaults{'catunauth'} = $domconfig{'coursecategories'}{'unauth'};              $domdefaults{'catunauth'} = $domconfig{'coursecategories'}{'unauth'};
         }          }
     }      }
     if (ref($domconfig{'autoenroll'}) eq 'HASH') {  
         $domdefaults{'autofailsafe'} = $domconfig{'autoenroll'}{'autofailsafe'};  
     }  
     if (ref($domconfig{'helpsettings'}) eq 'HASH') {  
         $domdefaults{'submitbugs'} = $domconfig{'helpsettings'}{'submitbugs'};  
         if (ref($domconfig{'helpsettings'}{'adhoc'}) eq 'HASH') {  
             $domdefaults{'adhocroles'} = $domconfig{'helpsettings'}{'adhoc'};  
         }  
     }  
     &do_cache_new('domdefaults',$domain,\%domdefaults,$cachetime);      &do_cache_new('domdefaults',$domain,\%domdefaults,$cachetime);
     return %domdefaults;      return %domdefaults;
 }  }
   
 sub get_dom_cats {  
     my ($dom) = @_;  
     return unless (&domain($dom));  
     my ($cats,$cached)=&is_cached_new('cats',$dom);  
     unless (defined($cached)) {  
         my %domconfig = &get_dom('configuration',['coursecategories'],$dom);  
         if (ref($domconfig{'coursecategories'}) eq 'HASH') {  
             if (ref($domconfig{'coursecategories'}{'cats'}) eq 'HASH') {  
                 %{$cats} = %{$domconfig{'coursecategories'}{'cats'}};  
             } else {  
                 $cats = {};  
             }  
         } else {  
             $cats = {};  
         }  
         &Apache::lonnet::do_cache_new('cats',$dom,$cats,3600);  
     }  
     return $cats;  
 }  
   
 sub get_dom_instcats {  
     my ($dom) = @_;  
     return unless (&domain($dom));  
     my ($instcats,$cached)=&is_cached_new('instcats',$dom);  
     unless (defined($cached)) {  
         my (%coursecodes,%codes,@codetitles,%cat_titles,%cat_order);  
         my $totcodes = &retrieve_instcodes(\%coursecodes,$dom);  
         if ($totcodes > 0) {  
             my $caller = 'global';  
             if (&auto_instcode_format($caller,$dom,\%coursecodes,\%codes,  
                                       \@codetitles,\%cat_titles,\%cat_order) eq 'ok') {  
                 $instcats = {  
                                 codes => \%codes,  
                                 codetitles => \@codetitles,  
                                 cat_titles => \%cat_titles,  
                                 cat_order => \%cat_order,  
                             };  
                 &do_cache_new('instcats',$dom,$instcats,3600);  
             }  
         }  
     }  
     return $instcats;  
 }  
   
 sub retrieve_instcodes {  
     my ($coursecodes,$dom) = @_;  
     my $totcodes;  
     my %courses = &courseiddump($dom,'.',1,'.','.','.',undef,undef,'Course');  
     foreach my $course (keys(%courses)) {  
         if (ref($courses{$course}) eq 'HASH') {  
             if ($courses{$course}{'inst_code'} ne '') {  
                 $$coursecodes{$course} = $courses{$course}{'inst_code'};  
                 $totcodes ++;  
             }  
         }  
     }  
     return $totcodes;  
 }  
   
 # --------------------------------------------- Get domain config for passwords  
   
 sub get_passwdconf {  
     my ($dom) = @_;  
     my (%passwdconf,$gotconf,$lookup);  
     my ($result,$cached)=&is_cached_new('passwdconf',$dom);  
     if (defined($cached)) {  
         if (ref($result) eq 'HASH') {  
             %passwdconf = %{$result};  
             $gotconf = 1;  
         }  
     }  
     unless ($gotconf) {  
         my %domconfig = &get_dom('configuration',['passwords'],$dom);  
         if (ref($domconfig{'passwords'}) eq 'HASH') {  
             %passwdconf = %{$domconfig{'passwords'}};  
         }  
         my $cachetime = 24*60*60;  
         &do_cache_new('passwdconf',$dom,\%passwdconf,$cachetime);  
     }  
     return %passwdconf;  
 }  
   
 sub course_portal_url {  
     my ($cnum,$cdom) = @_;  
     my $chome = &homeserver($cnum,$cdom);  
     my $hostname = &hostname($chome);  
     my $protocol = $protocol{$chome};  
     $protocol = 'http' if ($protocol ne 'https');  
     my %domdefaults = &get_domain_defaults($cdom);  
     my $firsturl;  
     if ($domdefaults{'portal_def'}) {  
         $firsturl = $domdefaults{'portal_def'};  
     } else {  
         $firsturl = $protocol.'://'.$hostname;  
     }  
     return $firsturl;  
 }  
   
 # --------------------------------------------------- Assign a key to a student  # --------------------------------------------------- Assign a key to a student
   
 sub assign_access_key {  sub assign_access_key {
Line 2795  sub make_key { Line 2458  sub make_key {
 sub devalidate_cache_new {  sub devalidate_cache_new {
     my ($name,$id,$debug) = @_;      my ($name,$id,$debug) = @_;
     if ($debug) { &Apache::lonnet::logthis("deleting $name:$id"); }      if ($debug) { &Apache::lonnet::logthis("deleting $name:$id"); }
     my $remembered_id=$name.':'.$id;  
     $id=&make_key($name,$id);      $id=&make_key($name,$id);
     $memcache->delete($id);      $memcache->delete($id);
     delete($remembered{$remembered_id});      delete($remembered{$id});
     delete($accessed{$remembered_id});      delete($accessed{$id});
 }  }
   
 sub is_cached_new {  sub is_cached_new {
     my ($name,$id,$debug) = @_;      my ($name,$id,$debug) = @_;
     my $remembered_id=$name.':'.$id; # this is to avoid make_key (which is slow) for       $id=&make_key($name,$id);
                                      # keys in %remembered hash, which persists for      if (exists($remembered{$id})) {
                                      # duration of request (no restriction on key length).   if ($debug) { &Apache::lonnet::logthis("Early return $id of $remembered{$id} "); }
     if (exists($remembered{$remembered_id})) {   $accessed{$id}=[&gettimeofday()];
  if ($debug) { &Apache::lonnet::logthis("Early return $remembered_id of $remembered{$remembered_id} "); }  
  $accessed{$remembered_id}=[&gettimeofday()];  
  $hits++;   $hits++;
  return ($remembered{$remembered_id},1);   return ($remembered{$id},1);
     }      }
     $id=&make_key($name,$id);  
     my $value = $memcache->get($id);      my $value = $memcache->get($id);
     if (!(defined($value))) {      if (!(defined($value))) {
  if ($debug) { &Apache::lonnet::logthis("getting $id is not defined"); }   if ($debug) { &Apache::lonnet::logthis("getting $id is not defined"); }
Line 2823  sub is_cached_new { Line 2482  sub is_cached_new {
  if ($debug) { &Apache::lonnet::logthis("getting $id is __undef__"); }   if ($debug) { &Apache::lonnet::logthis("getting $id is __undef__"); }
  $value=undef;   $value=undef;
     }      }
     &make_room($remembered_id,$value,$debug);      &make_room($id,$value,$debug);
     if ($debug) { &Apache::lonnet::logthis("getting $id is $value"); }      if ($debug) { &Apache::lonnet::logthis("getting $id is $value"); }
     return ($value,1);      return ($value,1);
 }  }
   
 sub do_cache_new {  sub do_cache_new {
     my ($name,$id,$value,$time,$debug) = @_;      my ($name,$id,$value,$time,$debug) = @_;
     my $remembered_id=$name.':'.$id;  
     $id=&make_key($name,$id);      $id=&make_key($name,$id);
     my $setvalue=$value;      my $setvalue=$value;
     if (!defined($setvalue)) {      if (!defined($setvalue)) {
Line 2846  sub do_cache_new { Line 2504  sub do_cache_new {
  $memcache->disconnect_all();   $memcache->disconnect_all();
     }      }
     # need to make a copy of $value      # need to make a copy of $value
     &make_room($remembered_id,$value,$debug);      &make_room($id,$value,$debug);
     return $value;      return $value;
 }  }
   
 sub make_room {  sub make_room {
     my ($remembered_id,$value,$debug)=@_;      my ($id,$value,$debug)=@_;
   
     $remembered{$remembered_id}= (ref($value)) ? &Storable::dclone($value)      $remembered{$id}= (ref($value)) ? &Storable::dclone($value)
                                     : $value;                                      : $value;
     if ($to_remember<0) { return; }      if ($to_remember<0) { return; }
     $accessed{$remembered_id}=[&gettimeofday()];      $accessed{$id}=[&gettimeofday()];
     if (scalar(keys(%remembered)) <= $to_remember) { return; }      if (scalar(keys(%remembered)) <= $to_remember) { return; }
     my $to_kick;      my $to_kick;
     my $max_time=0;      my $max_time=0;
Line 3094  sub repcopy { Line 2752  sub repcopy {
     }      }
 }  }
   
 # ------------------------------------------------- Unsubscribe from a resource  
   
 sub unsubscribe {  
     my ($fname) = @_;  
     my $answer;  
     if ($fname=~/\/(aboutme|syllabus|bulletinboard|smppg)$/) { return $answer; }  
     $fname=~s/[\n\r]//g;  
     my $author=$fname;  
     $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;  
     my ($udom,$uname)=split(/\//,$author);  
     my $home=homeserver($uname,$udom);  
     if ($home eq 'no_host') {  
         $answer = 'no_host';  
     } elsif (grep { $_ eq $home } &current_machine_ids()) {  
         $answer = 'home';  
     } else {  
         $answer = reply("unsub:$fname",$home);  
     }  
     return $answer;  
 }  
   
 # ------------------------------------------------ Get server side include body  # ------------------------------------------------ Get server side include body
 sub ssi_body {  sub ssi_body {
     my ($filelink,%form)=@_;      my ($filelink,%form)=@_;
Line 3164  sub absolute_url { Line 2801  sub absolute_url {
 sub ssi {  sub ssi {
   
     my ($fn,%form)=@_;      my ($fn,%form)=@_;
     my ($request,$response);      my $ua=new LWP::UserAgent;
       my $request;
   
     $form{'no_update_last_known'}=1;      $form{'no_update_last_known'}=1;
     &Apache::lonenc::check_encrypt(\$fn);      &Apache::lonenc::check_encrypt(\$fn);
     if (%form) {      if (%form) {
       $request=new HTTP::Request('POST',&absolute_url().$fn);        $request=new HTTP::Request('POST',&absolute_url().$fn);
       $request->content(join('&',map {        $request->content(join('&',map { 
             my $name = escape($_);              my $name = escape($_);
             "$name=" . ( ref($form{$_}) eq 'ARRAY'              "$name=" . ( ref($form{$_}) eq 'ARRAY' 
             ? join("&$name=", map {escape($_) } @{$form{$_}})              ? join("&$name=", map {escape($_) } @{$form{$_}}) 
             : &escape($form{$_}) );              : &escape($form{$_}) );    
         } keys(%form)));          } keys(%form)));
     } else {      } else {
       $request=new HTTP::Request('GET',&absolute_url().$fn);        $request=new HTTP::Request('GET',&absolute_url().$fn);
     }      }
   
     $request->header(Cookie => $ENV{'HTTP_COOKIE'});      $request->header(Cookie => $ENV{'HTTP_COOKIE'});
       my $response= $ua->request($request);
       my $content = $response->content;
   
   
     if (($env{'request.course.id'}) &&  
         ($form{'grade_courseid'} eq $env{'request.course.id'}) &&  
         ($form{'grade_username'} ne '') && ($form{'grade_domain'} ne '') &&  
         ($form{'grade_symb'} ne '') &&  
         (&Apache::lonnet::allowed('mgr',$env{'request.course.id'}.  
                                  ($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')))) {  
         if (LWP::UserAgent->VERSION >= 5.834) {  
             my $ua=new LWP::UserAgent;  
             $ua->local_address('127.0.0.1');  
             $response = $ua->request($request);  
         } else {  
             {  
                 require LWP::Protocol::http;  
                 local @LWP::Protocol::http::EXTRA_SOCK_OPTS = (LocalAddr => '127.0.0.1');  
                 my $ua=new LWP::UserAgent;  
                 $response = $ua->request($request);  
                 @LWP::Protocol::http::EXTRA_SOCK_OPTS = ();  
             }  
         }  
     } else {  
         my $ua=new LWP::UserAgent;  
         $response = $ua->request($request);  
     }  
     if (wantarray) {      if (wantarray) {
  return ($response->content, $response);   return ($content, $response);
     } else {      } else {
  return $response->content;   return $content;
     }      }
 }  }
   
Line 3224  sub externalssi { Line 2842  sub externalssi {
     }      }
 }  }
   
 # If the local copy of a replicated resource is outdated, trigger a  
 # connection from the homeserver to flush the delayed queue. If no update  
 # happens, remove local copies of outdated resource (and corresponding  
 # metadata file).  
   
 sub remove_stale_resfile {  
     my ($url) = @_;  
     my $removed;  
     if ($url=~m{^/res/($match_domain)/($match_username)/}) {  
         my $audom = $1;  
         my $auname = $2;  
         unless (($url =~ /\.\d+\.\w+$/) || ($url =~ m{^/res/lib/templates/})) {  
             my $homeserver = &homeserver($auname,$audom);  
             unless (($homeserver eq 'no_host') ||  
                     (grep { $_ eq $homeserver } &current_machine_ids())) {  
                 my $fname = &filelocation('',$url);  
                 if (-e $fname) {  
                     my $hostname = &hostname($homeserver);  
                     if ($hostname) {  
                         my $protocol = $protocol{$homeserver};  
                         $protocol = 'http' if ($protocol ne 'https');  
                         my $uri = $protocol.'://'.$hostname.'/raw/'.&declutter($url);  
                         my $ua=new LWP::UserAgent;  
                         $ua->timeout(5);  
                         my $request=new HTTP::Request('HEAD',$uri);  
                         my $response=$ua->request($request);  
                         if ($response->is_success()) {  
                             my $remmodtime = &HTTP::Date::str2time( $response->header('Last-modified') );  
                             my $locmodtime = (stat($fname))[9];  
                             if ($locmodtime < $remmodtime) {  
                                 my $stale;  
                                 my $answer = &reply('pong',$homeserver);  
                                 if ($answer eq $homeserver.':'.$perlvar{'lonHostID'}) {  
                                     sleep(0.2);  
                                     $locmodtime = (stat($fname))[9];  
                                     if ($locmodtime < $remmodtime) {  
                                         my $posstransfer = $fname.'.in.transfer';  
                                         if ((-e $posstransfer) && ($remmodtime < (stat($posstransfer))[9])) {  
                                             $removed = 1;  
                                         } else {  
                                             $stale = 1;  
                                         }  
                                     } else {  
                                         $removed = 1;  
                                     }  
                                 } else {  
                                     $stale = 1;  
                                 }  
                                 if ($stale) {  
                                     if (unlink($fname)) {  
                                         if ($uri!~/\.meta$/) {  
                                             if (-e $fname.'.meta') {  
                                                 unlink($fname.'.meta');  
                                             }  
                                         }  
                                         my $unsubresult = &unsubscribe($fname);  
                                         unless ($unsubresult eq 'ok') {  
                                             &logthis("no unsub of $fname from $homeserver, reason: $unsubresult");  
                                         }  
                                         $removed = 1;  
                                     }  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     return $removed;  
 }  
   
 # -------------------------------- Allow a /uploaded/ URI to be vouched for  # -------------------------------- Allow a /uploaded/ URI to be vouched for
   
 sub allowuploaded {  sub allowuploaded {
Line 3312  sub allowuploaded { Line 2858  sub allowuploaded {
 #  #
 # Determine if the current user should be able to edit a particular resource,  # Determine if the current user should be able to edit a particular resource,
 # when viewing in course context.  # when viewing in course context.
 # (a) When viewing resource used to determine if "Edit" item is included in  # (a) When viewing resource used to determine if "Edit" item is included in 
 #     Functions.  #     Functions.
 # (b) When displaying folder contents in course editor, used to determine if  # (b) When displaying folder contents in course editor, used to determine if
 #     "Edit" link will be displayed alongside resource.  #     "Edit" link will be displayed alongside resource.
Line 3320  sub allowuploaded { Line 2866  sub allowuploaded {
 #  input: six args -- filename (decluttered), course number, course domain,  #  input: six args -- filename (decluttered), course number, course domain,
 #                   url, symb (if registered) and group (if this is a group  #                   url, symb (if registered) and group (if this is a group
 #                   item -- e.g., bulletin board, group page etc.).  #                   item -- e.g., bulletin board, group page etc.).
 #  output: array of five scalars --  #  output: array of five scalars -- 
 #          $cfile -- url for file editing if editable on current server  #          $cfile -- url for file editing if editable on current server
 #          $home -- homeserver of resource (i.e., for author if published,  #          $home -- homeserver of resource (i.e., for author if published,
 #                                           or course if uploaded.).  #                                           or course if uploaded.).
 #          $switchserver --  1 if server switch will be needed.  #          $switchserver --  1 if server switch will be needed.
 #          $forceedit -- 1 if icon/link should be to go to edit mode  #          $forceedit -- 1 if icon/link should be to go to edit mode 
 #          $forceview -- 1 if icon/link should be to go to view mode  #          $forceview -- 1 if icon/link should be to go to view mode
 #  #
   
Line 3414  sub can_edit_resource { Line 2960  sub can_edit_resource {
                     $forceedit = 1;                      $forceedit = 1;
                 }                  }
                 $cfile = $resurl;                  $cfile = $resurl;
             } elsif (($resurl ne '') && (&is_on_map($resurl))) {              } elsif (($resurl ne '') && (&is_on_map($resurl))) { 
                 if ($resurl =~ m{^/adm/$match_domain/$match_username/\d+/smppg|bulletinboard$}) {                  if ($resurl =~ m{^/adm/$match_domain/$match_username/\d+/smppg|bulletinboard$}) {
                     $incourse = 1;                      $incourse = 1;
                     if ($env{'form.forceedit'}) {                      if ($env{'form.forceedit'}) {
Line 3434  sub can_edit_resource { Line 2980  sub can_edit_resource {
                         $forceedit = 1;                          $forceedit = 1;
                     }                      }
                     $cfile = $resurl;                      $cfile = $resurl;
                 } elsif (($resurl =~ m{^/ext/}) && ($symb ne '')) {  
                     my ($map,$id,$res) = &decode_symb($symb);  
                     if ($map =~ /\.page$/) {  
                         $incourse = 1;  
                         if ($env{'form.forceedit'}) {  
                             $forceview = 1;  
                             $cfile = $map;  
                         } else {  
                             $forceedit = 1;  
                             $cfile =  '/adm/wrapper'.$resurl;  
                         }  
                     }  
                 } elsif ($resurl =~ m{^/adm/wrapper/adm/$cdom/$cnum/\d+/ext\.tool$}) {  
                     $incourse = 1;  
                     if ($env{'form.forceedit'}) {  
                         $forceview = 1;  
                     } else {  
                         $forceedit = 1;  
                     }  
                     $cfile = $resurl;  
                 } elsif ($resurl =~ m{^/?adm/viewclasslist$}) {                  } elsif ($resurl =~ m{^/?adm/viewclasslist$}) {
                     $incourse = 1;                      $incourse = 1;
                     if ($env{'form.forceedit'}) {                      if ($env{'form.forceedit'}) {
Line 3465  sub can_edit_resource { Line 2991  sub can_edit_resource {
                 }                  }
             } elsif ($resurl eq '/res/lib/templates/simpleproblem.problem/smpedit') {              } elsif ($resurl eq '/res/lib/templates/simpleproblem.problem/smpedit') {
                 my $template = '/res/lib/templates/simpleproblem.problem';                  my $template = '/res/lib/templates/simpleproblem.problem';
                 if (&is_on_map($template)) {                  if (&is_on_map($template)) { 
                     $incourse = 1;                      $incourse = 1;
                     $forceview = 1;                      $forceview = 1;
                     $cfile = $template;                      $cfile = $template;
                 }                  }
             } elsif (($resurl =~ m{^/adm/wrapper/ext/}) && ($env{'form.folderpath'} =~ /^supplemental/)) {              } elsif (($resurl =~ m{^/adm/wrapper/ext/}) && ($env{'form.folderpath'} =~ /^supplemental/)) {
                 $incourse = 1;                      $incourse = 1;
                 if ($env{'form.forceedit'}) {                      if ($env{'form.forceedit'}) {
                     $forceview = 1;                          $forceview = 1;
                 } else {                      } else {
                     $forceedit = 1;                          $forceedit = 1;
                 }                      }
                 $cfile = $resurl;                      $cfile = $resurl;
             } elsif (($resurl =~ m{^/adm/wrapper/adm/$cdom/$cnum/\d+/ext\.tool$}) && ($env{'form.folderpath'} =~ /^supplemental/)) {  
                 $incourse = 1;  
                 if ($env{'form.forceedit'}) {  
                     $forceview = 1;  
                 } else {  
                     $forceedit = 1;  
                 }  
                 $cfile = $resurl;  
             } elsif (($resurl eq '/adm/extresedit') && ($symb || $env{'form.folderpath'})) {              } elsif (($resurl eq '/adm/extresedit') && ($symb || $env{'form.folderpath'})) {
                 $incourse = 1;                  $incourse = 1;
                 $forceview = 1;                  $forceview = 1;
Line 3495  sub can_edit_resource { Line 3013  sub can_edit_resource {
                     $cfile = &clutter($res);                      $cfile = &clutter($res);
                 } else {                  } else {
                     $cfile = $env{'form.suppurl'};                      $cfile = $env{'form.suppurl'};
                     my $escfile = &unescape($cfile);                      $cfile =~ s{^http://}{};
                     if ($escfile =~ m{^/adm/$cdom/$cnum/\d+/ext\.tool$}) {                      $cfile = '/adm/wrapper/ext/'.$cfile;
                         $cfile = '/adm/wrapper'.$escfile;  
                     } else {  
                         $escfile =~ s{^http://}{};  
                         $cfile = &escape("/adm/wrapper/ext/$escfile");  
                     }  
                 }                  }
             } elsif ($resurl =~ m{^/?adm/viewclasslist$}) {              } elsif ($resurl =~ m{^/?adm/viewclasslist$}) {
                 if ($env{'form.forceedit'}) {                  if ($env{'form.forceedit'}) {
Line 3525  sub can_edit_resource { Line 3038  sub can_edit_resource {
                 $cfile=$file;                  $cfile=$file;
             }              }
         }          }
         if (($cfile ne '') && (!$incourse || $uploaded) &&          if (($cfile ne '') && (!$incourse || $uploaded) && 
             (($home ne '') && ($home ne 'no_host'))) {              (($home ne '') && ($home ne 'no_host'))) {
             my @ids=&current_machine_ids();              my @ids=&current_machine_ids();
             unless (grep(/^\Q$home\E$/,@ids)) {              unless (grep(/^\Q$home\E$/,@ids)) {
Line 3552  sub in_course { Line 3065  sub in_course {
     if ($hideprivileged) {      if ($hideprivileged) {
         my $skipuser;          my $skipuser;
         my %coursehash = &coursedescription($cdom.'_'.$cnum);          my %coursehash = &coursedescription($cdom.'_'.$cnum);
         my @possdoms = ($cdom);          my @possdoms = ($cdom);  
         if ($coursehash{'checkforpriv'}) {          if ($coursehash{'checkforpriv'}) { 
             push(@possdoms,split(/,/,$coursehash{'checkforpriv'}));              push(@possdoms,split(/,/,$coursehash{'checkforpriv'})); 
         }          }
         if (&privileged($uname,$udom,\@possdoms)) {          if (&privileged($uname,$udom,\@possdoms)) {
             $skipuser = 1;              $skipuser = 1;
Line 3657  sub process_coursefile { Line 3170  sub process_coursefile {
                                  $home);                                   $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') {              if ($parser eq 'parse') {
Line 3715  sub store_edited_file { Line 3228  sub store_edited_file {
     ($fpath,$fname) = ($file =~ m|^(.*)/([^/]+)$|);      ($fpath,$fname) = ($file =~ m|^(.*)/([^/]+)$|);
     $fpath=$docudom.'/'.$docuname.'/'.$fpath;      $fpath=$docudom.'/'.$docuname.'/'.$fpath;
     my $filepath = &build_filepath($fpath);      my $filepath = &build_filepath($fpath);
     open(my $fh,'>',$filepath.'/'.$fname);      open(my $fh,'>'.$filepath.'/'.$fname);
     print $fh $content;      print $fh $content;
     close($fh);      close($fh);
     my $home=&homeserver($docuname,$docudom);      my $home=&homeserver($docuname,$docudom);
Line 3740  sub clean_filename { Line 3253  sub clean_filename {
     }      }
 # Replace spaces by underscores  # Replace spaces by underscores
     $fname=~s/\s+/\_/g;      $fname=~s/\s+/\_/g;
 # Transliterate non-ascii text to ascii  
     my $lang = &Apache::lonlocal::current_language();  
     $fname = &LONCAPA::transliterate::fname_to_ascii($fname,$lang);  
 # 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  # Replace all .\d. sequences with _\d. so they no longer look like version
Line 3750  sub clean_filename { Line 3260  sub clean_filename {
     $fname=~s/\.(\d+)(?=\.)/_$1/g;      $fname=~s/\.(\d+)(?=\.)/_$1/g;
     return $fname;      return $fname;
 }  }
   
 # This Function checks if an Image's dimensions exceed either $resizewidth (width)   # This Function checks if an Image's dimensions exceed either $resizewidth (width) 
 # or $resizeheight (height) - both pixels. If so, the image is scaled to produce an   # or $resizeheight (height) - both pixels. If so, the image is scaled to produce an 
 # image with the same aspect ratio as the original, but with dimensions which do   # image with the same aspect ratio as the original, but with dimensions which do 
Line 3793  sub resizeImage { Line 3302  sub resizeImage {
 # input: $formname - the contents of the file are in $env{"form.$formname"}  # input: $formname - the contents of the file are in $env{"form.$formname"}
 #                    the desired filename is in $env{"form.$formname.filename"}  #                    the desired filename is in $env{"form.$formname.filename"}
 #        $context - possible values: coursedoc, existingfile, overwrite,   #        $context - possible values: coursedoc, existingfile, overwrite, 
 #                                    canceloverwrite, scantron or ''.   #                                    canceloverwrite, or ''. 
 #                   if 'coursedoc': upload to the current course  #                   if 'coursedoc': upload to the current course
 #                   if 'existingfile': write file to tmp/overwrites directory   #                   if 'existingfile': write file to tmp/overwrites directory 
 #                   if 'canceloverwrite': delete file written to tmp/overwrites directory  #                   if 'canceloverwrite': delete file written to tmp/overwrites directory
 #                   $context is passed as argument to &finishuserfileupload  #                   $context is passed as argument to &finishuserfileupload
 #        $subdir - directory in userfile to store the file into  #        $subdir - directory in userfile to store the file into
 #        $parser - instruction to parse file for objects ($parser = parse) or  #        $parser - instruction to parse file for objects ($parser = parse)    
 #                  if context is 'scantron', $parser is hashref of csv column mapping  
 #                  (e.g.,{ PaperID => 0, LastName => 1, FirstName => 2, ID => 3,  
 #                          Section => 4, CODE => 5, FirstQuestion => 9 }).  
 #        $allfiles - reference to hash for embedded objects  #        $allfiles - reference to hash for embedded objects
 #        $codebase - reference to hash for codebase of java objects  #        $codebase - reference to hash for codebase of java objects
 #        $desuname - username for permanent storage of uploaded file  #        $desuname - username for permanent storage of uploaded file
Line 3825  sub userfileupload { Line 3331  sub userfileupload {
     $fname=&clean_filename($fname);      $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'; }
     # If filename now begins with a . prepend unix timestamp _ milliseconds  
     if ($fname =~ /^\./) {  
         my ($s,$usec) = &gettimeofday();  
         while (length($usec) < 6) {  
             $usec = '0'.$usec;  
         }  
         $fname = $s.'_'.substr($usec,0,3).$fname;  
     }  
     # Files uploaded to help request form, or uploaded to "create course" page are handled differently      # Files uploaded to help request form, or uploaded to "create course" page are handled differently
     if ((($formname eq 'screenshot') && ($subdir eq 'helprequests')) ||      if ((($formname eq 'screenshot') && ($subdir eq 'helprequests')) ||
         (($formname eq 'coursecreatorxml') && ($subdir eq 'batchupload')) ||          (($formname eq 'coursecreatorxml') && ($subdir eq 'batchupload')) ||
Line 3846  sub userfileupload { Line 3344  sub userfileupload {
                          '_'.$env{'user.domain'}.'/pending';                           '_'.$env{'user.domain'}.'/pending';
         } elsif (($context eq 'existingfile') || ($context eq 'canceloverwrite')) {          } elsif (($context eq 'existingfile') || ($context eq 'canceloverwrite')) {
             my ($docuname,$docudom);              my ($docuname,$docudom);
             if ($destudom =~ /^$match_domain$/) {              if ($destudom) {
                 $docudom = $destudom;                  $docudom = $destudom;
             } else {              } else {
                 $docudom = $env{'user.domain'};                  $docudom = $env{'user.domain'};
             }              }
             if ($destuname =~ /^$match_username$/) {               if ($destuname) {
                 $docuname = $destuname;                  $docuname = $destuname;
             } else {              } else {
                 $docuname = $env{'user.name'};                  $docuname = $env{'user.name'};
Line 3881  sub userfileupload { Line 3379  sub userfileupload {
                 mkdir($fullpath,0777);                  mkdir($fullpath,0777);
             }              }
         }          }
         open(my $fh,'>',$fullpath.'/'.$fname);          open(my $fh,'>'.$fullpath.'/'.$fname);
         print $fh $env{'form.'.$formname};          print $fh $env{'form.'.$formname};
         close($fh);          close($fh);
         if ($context eq 'existingfile') {          if ($context eq 'existingfile') {
Line 3956  sub finishuserfileupload { Line 3454  sub finishuserfileupload {
   
 # Save the file  # Save the file
     {      {
  if (!open(FH,'>',$filepath.'/'.$file)) {   if (!open(FH,'>'.$filepath.'/'.$file)) {
     &logthis('Failed to create '.$filepath.'/'.$file);      &logthis('Failed to create '.$filepath.'/'.$file);
     print STDERR ('Failed to create '.$filepath.'/'.$file."\n");      print STDERR ('Failed to create '.$filepath.'/'.$file."\n");
     return '/adm/notfound.html';      return '/adm/notfound.html';
Line 4000  sub finishuserfileupload { Line 3498  sub finishuserfileupload {
             }              }
         }          }
     }      }
     if (($context ne 'scantron') && ($parser eq 'parse')) {      if ($parser eq 'parse') {
         if ((ref($mimetype)) && ($$mimetype eq 'text/html')) {          if ((ref($mimetype)) && ($$mimetype eq 'text/html')) {
             my $parse_result = &extract_embedded_items($filepath.'/'.$file,              my $parse_result = &extract_embedded_items($filepath.'/'.$file,
                                                        $allfiles,$codebase);                                                         $allfiles,$codebase);
Line 4009  sub finishuserfileupload { Line 3507  sub finishuserfileupload {
            ' for embedded media: '.$parse_result);              ' for embedded media: '.$parse_result); 
             }              }
         }          }
     } elsif (($context eq 'scantron') && (ref($parser) eq 'HASH')) {  
         my $format = $env{'form.scantron_format'};  
         &bubblesheet_converter($docudom,$filepath.'/'.$file,$parser,$format);  
     }      }
     if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) {      if (($thumbwidth =~ /^\d+$/) && ($thumbheight =~ /^\d+$/)) {
         my $input = $filepath.'/'.$file;          my $input = $filepath.'/'.$file;
         my $output = $filepath.'/'.'tn-'.$file;          my $output = $filepath.'/'.'tn-'.$file;
         my $thumbsize = $thumbwidth.'x'.$thumbheight;          my $thumbsize = $thumbwidth.'x'.$thumbheight;
         my @args = ('convert','-sample',$thumbsize,$input,$output);          system("convert -sample $thumbsize $input $output");
         system({$args[0]} @args);  
         if (-e $filepath.'/'.'tn-'.$file) {          if (-e $filepath.'/'.'tn-'.$file) {
             $fetchthumb  = 1;               $fetchthumb  = 1; 
         }          }
Line 4077  sub extract_embedded_items { Line 3571  sub extract_embedded_items {
     }      }
     if (lc($tagname) eq 'a') {      if (lc($tagname) eq 'a') {
                 unless (($attr->{'href'} =~ /^#/) || ($attr->{'href'} eq '')) {                  unless (($attr->{'href'} =~ /^#/) || ($attr->{'href'} eq '')) {
     &add_filetype($allfiles,$attr->{'href'},'href');                      &add_filetype($allfiles,$attr->{'href'},'href');
                 }                  }
     }      }
             if (lc($tagname) eq 'script') {              if (lc($tagname) eq 'script') {
Line 4252  sub embedded_dependency { Line 3746  sub embedded_dependency {
     return;      return;
 }  }
   
 sub bubblesheet_converter {  
     my ($cdom,$fullpath,$config,$format) = @_;  
     if ((&domain($cdom) ne '') &&  
         ($fullpath =~ m{^\Q$perlvar{'lonDocRoot'}/userfiles/$cdom/\E$match_courseid/scantron_orig}) &&  
         (-e $fullpath) && (ref($config) eq 'HASH') && ($format ne '')) {  
         my (%csvcols,%csvoptions);  
         if (ref($config->{'fields'}) eq 'HASH') {  
             %csvcols = %{$config->{'fields'}};  
         }  
         if (ref($config->{'options'}) eq 'HASH') {  
             %csvoptions = %{$config->{'options'}};  
         }  
         my %csvbynum = reverse(%csvcols);  
         my %scantronconf = &get_scantron_config($format,$cdom);  
         if (keys(%scantronconf)) {  
             my %bynum = (  
                           $scantronconf{CODEstart} => 'CODEstart',  
                           $scantronconf{IDstart}   => 'IDstart',  
                           $scantronconf{PaperID}   => 'PaperID',  
                           $scantronconf{FirstName} => 'FirstName',  
                           $scantronconf{LastName}  => 'LastName',  
                           $scantronconf{Qstart}    => 'Qstart',  
                         );  
             my @ordered;  
             foreach my $item (sort { $a <=> $b } keys(%bynum)) {  
                 push(@ordered,$bynum{$item});  
             }  
             my %mapstart = (  
                               CODEstart => 'CODE',  
                               IDstart   => 'ID',  
                               PaperID   => 'PaperID',  
                               FirstName => 'FirstName',  
                               LastName  => 'LastName',  
                               Qstart    => 'FirstQuestion',  
                            );  
             my %maplength = (  
                               CODEstart => 'CODElength',  
                               IDstart   => 'IDlength',  
                               PaperID   => 'PaperIDlength',  
                               FirstName => 'FirstNamelength',  
                               LastName  => 'LastNamelength',  
             );  
             if (open(my $fh,'<',$fullpath)) {  
                 my $output;  
                 my %lettdig = &letter_to_digits();  
                 my %diglett = reverse(%lettdig);  
                 my $numletts = scalar(keys(%lettdig));  
                 my $num = 0;  
                 while (my $line=<$fh>) {  
                     $num ++;  
                     next if (($num == 1) && ($csvoptions{'hdr'} == 1));  
                     $line =~ s{[\r\n]+$}{};  
                     my %found;  
                     my @values = split(/,/,$line);  
                     my ($qstart,$record);  
                     for (my $i=0; $i<@values; $i++) {  
                         if ((($qstart ne '') && ($i > $qstart)) ||  
                             ($csvbynum{$i} eq 'FirstQuestion')) {  
                             if ($values[$i] eq '') {  
                                 $values[$i] = $scantronconf{'Qoff'};  
                             } elsif ($scantronconf{'Qon'} eq 'number') {  
                                 if ($values[$i] =~ /^[A-Ja-j]$/) {  
                                     $values[$i] = $lettdig{uc($values[$i])};  
                                 }  
                             } elsif ($scantronconf{'Qon'} eq 'letter') {  
                                 if ($values[$i] =~ /^[0-9]$/) {  
                                     $values[$i] = $diglett{$values[$i]};  
                                 }  
                             } else {  
                                 if ($values[$i] =~ /^[0-9A-Ja-j]$/) {  
                                     my $digit;  
                                     if ($values[$i] =~ /^[A-Ja-j]$/) {  
                                         $digit = $lettdig{uc($values[$i])}-1;  
                                         if ($values[$i] eq 'J') {  
                                             $digit += $numletts;  
                                         }  
                                     } elsif ($values[$i] =~ /^[0-9]$/) {  
                                         $digit = $values[$i]-1;  
                                         if ($values[$i] eq '0') {  
                                             $digit += $numletts;  
                                         }  
                                     }  
                                     my $qval='';  
                                     for (my $j=0; $j<$scantronconf{'Qlength'}; $j++) {  
                                         if ($j == $digit) {  
                                             $qval .= $scantronconf{'Qon'};  
                                         } else {  
                                             $qval .= $scantronconf{'Qoff'};  
                                         }  
                                     }  
                                     $values[$i] = $qval;  
                                 }  
                             }  
                             if (length($values[$i]) > $scantronconf{'Qlength'}) {  
                                 $values[$i] = substr($values[$i],0,$scantronconf{'Qlength'});  
                             }  
                             my $numblank = $scantronconf{'Qlength'} - length($values[$i]);  
                             if ($numblank > 0) {  
                                  $values[$i] .= ($scantronconf{'Qoff'} x $numblank);  
                             }  
                             if ($csvbynum{$i} eq 'FirstQuestion') {  
                                 $qstart = $i;  
                                 $found{$csvbynum{$i}} = $values[$i];  
                             } else {  
                                 $found{'FirstQuestion'} .= $values[$i];  
                             }  
                         } elsif (exists($csvbynum{$i})) {  
                             if ($csvoptions{'rem'}) {  
                                 $values[$i] =~ s/^\s+//;  
                             }  
                             if (($csvbynum{$i} eq 'PaperID') && ($csvoptions{'pad'})) {  
                                 while (length($values[$i]) < $scantronconf{$maplength{$csvbynum{$i}}}) {  
                                     $values[$i] = '0'.$values[$i];  
                                 }  
                             }  
                             $found{$csvbynum{$i}} = $values[$i];  
                         }  
                     }  
                     foreach my $item (@ordered) {  
                         my $currlength = 1+length($record);  
                         my $numspaces = $scantronconf{$item} - $currlength;  
                         if ($numspaces > 0) {  
                             $record .= (' ' x $numspaces);  
                         }  
                         if (($mapstart{$item} ne '') && (exists($found{$mapstart{$item}}))) {  
                             unless ($item eq 'Qstart') {  
                                 if (length($found{$mapstart{$item}}) > $scantronconf{$maplength{$item}}) {  
                                     $found{$mapstart{$item}} = substr($found{$mapstart{$item}},0,$scantronconf{$maplength{$item}});  
                                 }  
                             }  
                             $record .= $found{$mapstart{$item}};  
                         }  
                     }  
                     $output .= "$record\n";  
                 }  
                 close($fh);  
                 if ($output) {  
                     if (open(my $fh,'>',$fullpath)) {  
                         print $fh $output;  
                         close($fh);  
                     }  
                 }  
             }  
         }  
         return;  
     }  
 }  
   
 sub letter_to_digits {  
     my %lettdig = (  
                     A => 1,  
                     B => 2,  
                     C => 3,  
                     D => 4,  
                     E => 5,  
                     F => 6,  
                     G => 7,  
                     H => 8,  
                     I => 9,  
                     J => 0,  
                   );  
     return %lettdig;  
 }  
   
 sub get_scantron_config {  
     my ($which,$cdom) = @_;  
     my @lines = &get_scantronformat_file($cdom);  
     my %config;  
     #FIXME probably should move to XML it has already gotten a bit much now  
     foreach my $line (@lines) {  
         my ($name,$descrip)=split(/:/,$line);  
         if ($name ne $which ) { next; }  
         chomp($line);  
         my @config=split(/:/,$line);  
         $config{'name'}=$config[0];  
         $config{'description'}=$config[1];  
         $config{'CODElocation'}=$config[2];  
         $config{'CODEstart'}=$config[3];  
         $config{'CODElength'}=$config[4];  
         $config{'IDstart'}=$config[5];  
         $config{'IDlength'}=$config[6];  
         $config{'Qstart'}=$config[7];  
         $config{'Qlength'}=$config[8];  
         $config{'Qoff'}=$config[9];  
         $config{'Qon'}=$config[10];  
         $config{'PaperID'}=$config[11];  
         $config{'PaperIDlength'}=$config[12];  
         $config{'FirstName'}=$config[13];  
         $config{'FirstNamelength'}=$config[14];  
         $config{'LastName'}=$config[15];  
         $config{'LastNamelength'}=$config[16];  
         $config{'BubblesPerRow'}=$config[17];  
         last;  
     }  
     return %config;  
 }  
   
 sub get_scantronformat_file {  
     my ($cdom) = @_;  
     if ($cdom eq '') {  
         $cdom= $env{'course.'.$env{'request.course.id'}.'.domain'};  
     }  
     my %domconfig = &get_dom('configuration',['scantron'],$cdom);  
     my $gottab = 0;  
     my @lines;  
     if (ref($domconfig{'scantron'}) eq 'HASH') {  
         if ($domconfig{'scantron'}{'scantronformat'} ne '') {  
             my $formatfile = &getfile($perlvar{'lonDocRoot'}.$domconfig{'scantron'}{'scantronformat'});  
             if ($formatfile ne '-1') {  
                 @lines = split("\n",$formatfile,-1);  
                 $gottab = 1;  
             }  
         }  
     }  
     if (!$gottab) {  
         my $confname = $cdom.'-domainconfig';  
         my $default = $perlvar{'lonDocRoot'}.'/res/'.$cdom.'/'.$confname.'/default.tab';  
         my $formatfile = &getfile($default);  
         if ($formatfile ne '-1') {  
             @lines = split("\n",$formatfile,-1);  
             $gottab = 1;  
         }  
     }  
     if (!$gottab) {  
         my @domains = &current_machine_domains();  
         if (grep(/^\Q$cdom\E$/,@domains)) {  
             if (open(my $fh,'<',$perlvar{'lonTabDir'}.'/scantronformat.tab')) {  
                 @lines = <$fh>;  
                 close($fh);  
             }  
         } else {  
             if (open(my $fh,'<',$perlvar{'lonTabDir'}.'/default_scantronformat.tab')) {  
                 @lines = <$fh>;  
                 close($fh);  
             }  
         }  
     }  
     return @lines;  
 }  
   
 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);    
Line 4642  sub flushcourselogs { Line 3896  sub flushcourselogs {
         }          }
     }      }
 #  #
 # Reverse lookup of domain roles (dc, ad, li, sc, dh, da, au)  # Reverse lookup of domain roles (dc, ad, li, sc, au)
 #  #
     my %domrolebuffer = ();      my %domrolebuffer = ();
     foreach my $entry (keys(%domainrolehash)) {      foreach my $entry (keys(%domainrolehash)) {
Line 4657  sub flushcourselogs { Line 3911  sub flushcourselogs {
         delete $domainrolehash{$entry};          delete $domainrolehash{$entry};
     }      }
     foreach my $dom (keys(%domrolebuffer)) {      foreach my $dom (keys(%domrolebuffer)) {
         my %servers;   my %servers = &get_servers($dom,'library');
         if (defined(&domain($dom,'primary'))) {  
             my $primary=&domain($dom,'primary');  
             my $hostname=&hostname($primary);  
             $servers{$primary} = $hostname;  
         } else {  
             %servers = &get_servers($dom,'library');  
         }  
  foreach my $tryserver (keys(%servers)) {   foreach my $tryserver (keys(%servers)) {
     if (&reply('domroleput:'.$dom.':'.      unless (&reply('domroleput:'.$dom.':'.
                $domrolebuffer{$dom},$tryserver) eq 'ok') {     $domrolebuffer{$dom},$tryserver) eq 'ok') {
         last;  
     } else {  
  &logthis('Put of domain roles failed for '.$dom.' and  '.$tryserver);   &logthis('Put of domain roles failed for '.$dom.' and  '.$tryserver);
     }      }
         }          }
Line 4789  sub userrolelog { Line 4034  sub userrolelog {
          {$trole.':'.$username.':'.$domain.':'.$env{'user.name'}.':'.$env{'user.domain'}.':'}           {$trole.':'.$username.':'.$domain.':'.$env{'user.name'}.':'.$env{'user.domain'}.':'}
                     =$tend.':'.$tstart;                      =$tend.':'.$tstart;
     }      }
     if ($trole =~ /^(dc|ad|li|au|dg|sc|dh|da)/ ) {      if ($trole =~ /^(dc|ad|li|au|dg|sc)/ ) {
        my (undef,$rudom,$runame,$rsec)=split(/\//,$area);         my (undef,$rudom,$runame,$rsec)=split(/\//,$area);
        $domainrolehash         $domainrolehash
          {$trole.':'.$username.':'.$domain.':'.$runame.':'.$rudom.':'.$rsec}           {$trole.':'.$username.':'.$domain.':'.$runame.':'.$rudom.':'.$rsec}
Line 4997  sub get_my_roles { Line 4242  sub get_my_roles {
             } else {              } else {
                 my $possdoms = [$domain];                  my $possdoms = [$domain];
                 if (ref($roledoms) eq 'ARRAY') {                  if (ref($roledoms) eq 'ARRAY') {
                    push(@{$possdoms},@{$roledoms});                     push(@{$possdoms},@{$roledoms}); 
                 }                  }
                 if (&privileged($username,$domain,$possdoms,\@privroles)) {                  if (&privileged($username,$domain,$possdoms,\@privroles)) {
                     if (!$nothide{$username.':'.$domain}) {                      if (!$nothide{$username.':'.$domain}) {
Line 5016  sub get_my_roles { Line 4261  sub get_my_roles {
     return %returnhash;      return %returnhash;
 }  }
   
 sub get_all_adhocroles {  
     my ($dom) = @_;  
     my @roles_by_num = ();  
     my %domdefaults = &get_domain_defaults($dom);  
     my (%description,%access_in_dom,%access_info);  
     if (ref($domdefaults{'adhocroles'}) eq 'HASH') {  
         my $count = 0;  
         my %domcurrent = %{$domdefaults{'adhocroles'}};  
         my %ordered;  
         foreach my $role (sort(keys(%domcurrent))) {  
             my ($order,$desc,$access_in_dom);  
             if (ref($domcurrent{$role}) eq 'HASH') {  
                 $order = $domcurrent{$role}{'order'};  
                 $desc = $domcurrent{$role}{'desc'};  
                 $access_in_dom{$role} = $domcurrent{$role}{'access'};  
                 $access_info{$role} = $domcurrent{$role}{$access_in_dom{$role}};  
             }  
             if ($order eq '') {  
                 $order = $count;  
             }  
             $ordered{$order} = $role;  
             if ($desc ne '') {  
                 $description{$role} = $desc;  
             } else {  
                 $description{$role}= $role;  
             }  
             $count++;  
         }  
         foreach my $item (sort {$a <=> $b } (keys(%ordered))) {  
             push(@roles_by_num,$ordered{$item});  
         }  
     }  
     return (\@roles_by_num,\%description,\%access_in_dom,\%access_info);  
 }  
   
 sub get_my_adhocroles {  
     my ($cid,$checkreg) = @_;  
     my ($cdom,$cnum,%info,@possroles,$description,$roles_by_num);  
     if ($env{'request.course.id'} eq $cid) {  
         $cdom = $env{'course.'.$cid.'.domain'};  
         $cnum = $env{'course.'.$cid.'.num'};  
         $info{'internal.coursecode'} = $env{'course.'.$cid.'.internal.coursecode'};  
     } elsif ($cid =~ /^($match_domain)_($match_courseid)$/) {  
         $cdom = $1;  
         $cnum = $2;  
         %info = &Apache::lonnet::get('environment',['internal.coursecode'],  
                                      $cdom,$cnum);  
     }  
     if (($info{'internal.coursecode'} ne '') && ($checkreg)) {  
         my $user = $env{'user.name'}.':'.$env{'user.domain'};  
         my %rosterhash = &get('classlist',[$user],$cdom,$cnum);  
         if ($rosterhash{$user} ne '') {  
             my $type = (split(/:/,$rosterhash{$user}))[5];  
             return ([],{}) if ($type eq 'auto');  
         }  
     }  
     if (($cdom ne '') && ($cnum ne ''))  {  
         if (($env{"user.role.dh./$cdom/"}) || ($env{"user.role.da./$cdom/"})) {  
             my $then=$env{'user.login.time'};  
             my $update=$env{'user.update.time'};  
             if (!$update) {  
                 $update = $then;  
             }  
             my @liveroles;  
             foreach my $role ('dh','da') {  
                 if ($env{"user.role.$role./$cdom/"}) {  
                     my ($tstart,$tend)=split(/\./,$env{"user.role.$role./$cdom/"});  
                     my $limit = $update;  
                     if ($env{'request.role'} eq "$role./$cdom/") {  
                         $limit = $then;  
                     }  
                     my $activerole = 1;  
                     if ($tstart && $tstart>$limit) { $activerole = 0; }  
                     if ($tend   && $tend  <$limit) { $activerole = 0; }  
                     if ($activerole) {  
                         push(@liveroles,$role);  
                     }  
                 }  
             }  
             if (@liveroles) {  
                 if (&homeserver($cnum,$cdom) ne 'no_host') {  
                     my ($accessref,$accessinfo,%access_in_dom);  
                     ($roles_by_num,$description,$accessref,$accessinfo) = &get_all_adhocroles($cdom);  
                     if (ref($roles_by_num) eq 'ARRAY') {  
                         if (@{$roles_by_num}) {  
                             my %settings;  
                             if ($env{'request.course.id'} eq $cid) {  
                                 foreach my $envkey (keys(%env)) {  
                                     if ($envkey =~ /^\Qcourse.$cid.\E(internal\.adhoc.+)$/) {  
                                         $settings{$1} = $env{$envkey};  
                                     }  
                                 }  
                             } else {  
                                 %settings = &dump('environment',$cdom,$cnum,'internal\.adhoc');  
                             }  
                             my %setincrs;  
                             if ($settings{'internal.adhocaccess'}) {  
                                 map { $setincrs{$_} = 1; } split(/,/,$settings{'internal.adhocaccess'});  
                             }  
                             my @statuses;  
                             if ($env{'environment.inststatus'}) {  
                                 @statuses = split(/,/,$env{'environment.inststatus'});  
                             }  
                             my $user = $env{'user.name'}.':'.$env{'user.domain'};  
                             if (ref($accessref) eq 'HASH') {  
                                 %access_in_dom = %{$accessref};  
                             }  
                             foreach my $role (@{$roles_by_num}) {  
                                 my ($curraccess,@okstatus,@personnel);  
                                 if ($setincrs{$role}) {  
                                     ($curraccess,my $rest) = split(/=/,$settings{'internal.adhoc.'.$role});  
                                     if ($curraccess eq 'status') {  
                                         @okstatus = split(/\&/,$rest);  
                                     } elsif (($curraccess eq 'exc') || ($curraccess eq 'inc')) {  
                                         @personnel = split(/\&/,$rest);  
                                     }  
                                 } else {  
                                     $curraccess = $access_in_dom{$role};  
                                     if (ref($accessinfo) eq 'HASH') {  
                                         if ($curraccess eq 'status') {  
                                             if (ref($accessinfo->{$role}) eq 'ARRAY') {  
                                                 @okstatus = @{$accessinfo->{$role}};  
                                             }  
                                         } elsif (($curraccess eq 'exc') || ($curraccess eq 'inc')) {  
                                             if (ref($accessinfo->{$role}) eq 'ARRAY') {  
                                                 @personnel = @{$accessinfo->{$role}};  
                                             }  
                                         }  
                                     }  
                                 }  
                                 if ($curraccess eq 'none') {  
                                     next;  
                                 } elsif ($curraccess eq 'all') {  
                                     push(@possroles,$role);  
                                 } elsif ($curraccess eq 'dh') {  
                                     if (grep(/^dh$/,@liveroles)) {  
                                         push(@possroles,$role);  
                                     } else {  
                                         next;  
                                     }  
                                 } elsif ($curraccess eq 'da') {  
                                     if (grep(/^da$/,@liveroles)) {  
                                         push(@possroles,$role);  
                                     } else {  
                                         next;  
                                     }  
                                 } elsif ($curraccess eq 'status') {  
                                     if (@okstatus) {  
                                         if (!@statuses) {  
                                             if (grep(/^default$/,@okstatus)) {  
                                                 push(@possroles,$role);  
                                             }  
                                         } else {  
                                             foreach my $status (@okstatus) {  
                                                 if (grep(/^\Q$status\E$/,@statuses)) {  
                                                     push(@possroles,$role);  
                                                     last;  
                                                 }  
                                             }  
                                         }  
                                     }  
                                 } elsif (($curraccess eq 'exc') || ($curraccess eq 'inc')) {  
                                     if (grep(/^\Q$user\E$/,@personnel)) {  
                                         if ($curraccess eq 'exc') {  
                                             push(@possroles,$role);  
                                         }  
                                     } elsif ($curraccess eq 'inc') {  
                                         push(@possroles,$role);  
                                     }  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     unless (ref($description) eq 'HASH') {  
         if (ref($roles_by_num) eq 'ARRAY') {  
             my %desc;  
             map { $desc{$_} = $_; } (@{$roles_by_num});  
             $description = \%desc;  
         } else {  
             $description = {};  
         }  
     }  
     return (\@possroles,$description);  
 }  
   
 # ----------------------------------------------------- Frontpage Announcements  # ----------------------------------------------------- Frontpage Announcements
 #  #
 #  #
Line 5218  sub postannounce { Line 4274  sub postannounce {
   
 sub getannounce {  sub getannounce {
   
     if (open(my $fh,"<",$perlvar{'lonDocRoot'}.'/announcement.txt')) {      if (open(my $fh,$perlvar{'lonDocRoot'}.'/announcement.txt')) {
  my $announcement='';   my $announcement='';
  while (my $line = <$fh>) { $announcement .= $line; }   while (my $line = <$fh>) { $announcement .= $line; }
  close($fh);   close($fh);
Line 5294  sub courseiddump { Line 4350  sub courseiddump {
     if (($domfilter eq '') ||      if (($domfilter eq '') ||
  (&host_domain($tryserver) eq $domfilter)) {   (&host_domain($tryserver) eq $domfilter)) {
                 my $rep;                  my $rep;
                 if (grep { $_ eq $tryserver } &current_machine_ids()) {                  if (grep { $_ eq $tryserver } current_machine_ids()) {
                     $rep = &LONCAPA::Lond::dump_course_id_handler(                      $rep = LONCAPA::Lond::dump_course_id_handler(
                         join(":", (&host_domain($tryserver), $sincefilter,                          join(":", (&host_domain($tryserver), $sincefilter, 
                                 &escape($descfilter), &escape($instcodefilter),                                  &escape($descfilter), &escape($instcodefilter), 
                                 &escape($ownerfilter), &escape($coursefilter),                                  &escape($ownerfilter), &escape($coursefilter),
                                 &escape($typefilter), &escape($regexp_ok),                                  &escape($typefilter), &escape($regexp_ok), 
                                 $as_hash, &escape($selfenrollonly),                                  $as_hash, &escape($selfenrollonly), 
                                 &escape($catfilter), $showhidden, $caller,                                  &escape($catfilter), $showhidden, $caller, 
                                 &escape($cloner), &escape($cc_clone), $cloneonly,                                  &escape($cloner), &escape($cc_clone), $cloneonly, 
                                 &escape($createdbefore), &escape($createdafter),                                  &escape($createdbefore), &escape($createdafter), 
                                 &escape($creationcontext),$domcloner,$hasuniquecode,                                  &escape($creationcontext),$domcloner,$hasuniquecode,
                                 $reqcrsdom,&escape($reqinstcode))));                                  $reqcrsdom,&escape($reqinstcode))));
                 } else {                  } else {
Line 5319  sub courseiddump { Line 4375  sub courseiddump {
                              &escape($creationcontext).':'.$domcloner.':'.$hasuniquecode.                               &escape($creationcontext).':'.$domcloner.':'.$hasuniquecode.
                              ':'.$reqcrsdom.':'.&escape($reqinstcode),$tryserver);                               ':'.$reqcrsdom.':'.&escape($reqinstcode),$tryserver);
                 }                  }
                        
                 my @pairs=split(/\&/,$rep);                  my @pairs=split(/\&/,$rep);
                 foreach my $item (@pairs) {                  foreach my $item (@pairs) {
                     my ($key,$value)=split(/\=/,$item,2);                      my ($key,$value)=split(/\=/,$item,2);
Line 5445  sub get_domain_roles { Line 4501  sub get_domain_roles {
     return %personnel;      return %personnel;
 }  }
   
 sub get_active_domroles {  
     my ($dom,$roles) = @_;  
     return () unless (ref($roles) eq 'ARRAY');  
     my $now = time;  
     my %dompersonnel = &get_domain_roles($dom,$roles,$now,$now);  
     my %domroles;  
     foreach my $server (keys(%dompersonnel)) {  
         foreach my $user (sort(keys(%{$dompersonnel{$server}}))) {  
             my ($trole,$uname,$udom,$runame,$rudom,$rsec) = split(/:/,$user);  
             $domroles{$uname.':'.$udom} = $dompersonnel{$server}{$user};  
         }  
     }  
     return %domroles;  
 }  
   
 # ----------------------------------------------------------- Interval timing   # ----------------------------------------------------------- Interval timing 
   
 {  {
Line 5474  my %cachedtimes=(); Line 4515  my %cachedtimes=();
 my $cachedtime='';  my $cachedtime='';
   
 sub load_all_first_access {  sub load_all_first_access {
     my ($uname,$udom,$ignorecache)=@_;      my ($uname,$udom)=@_;
     if (($cachedkey eq $uname.':'.$udom) &&      if (($cachedkey eq $uname.':'.$udom) &&
         (abs($cachedtime-time)<5) && (!$env{'form.markaccess'}) &&          (abs($cachedtime-time)<5) && (!$env{'form.markaccess'})) {
         (!$ignorecache)) {  
         return;          return;
     }      }
     $cachedtime=time;      $cachedtime=time;
Line 5486  sub load_all_first_access { Line 4526  sub load_all_first_access {
 }  }
   
 sub get_first_access {  sub get_first_access {
     my ($type,$argsymb,$argmap,$ignorecache)=@_;      my ($type,$argsymb,$argmap)=@_;
     my ($symb,$courseid,$udom,$uname)=&whichuser();      my ($symb,$courseid,$udom,$uname)=&whichuser();
     if ($argsymb) { $symb=$argsymb; }      if ($argsymb) { $symb=$argsymb; }
     my ($map,$id,$res)=&decode_symb($symb);      my ($map,$id,$res)=&decode_symb($symb);
Line 5498  sub get_first_access { Line 4538  sub get_first_access {
     } else {      } else {
  $res=$symb;   $res=$symb;
     }      }
     &load_all_first_access($uname,$udom,$ignorecache);      &load_all_first_access($uname,$udom);
     return $cachedtimes{"$courseid\0$res"};      return $cachedtimes{"$courseid\0$res"};
 }  }
   
Line 5515  sub set_first_access { Line 4555  sub set_first_access {
     }      }
     $cachedkey='';      $cachedkey='';
     my $firstaccess=&get_first_access($type,$symb,$map);      my $firstaccess=&get_first_access($type,$symb,$map);
     if ($firstaccess) {      if (!$firstaccess) {
         &logthis("First access time already set ($firstaccess) when attempting ".  
                  "to set new value (type: $type, extent: $res) for $uname:$udom ".  
                  "in $courseid");  
         return 'already_set';  
     } else {  
         my $start = time;          my $start = time;
  my $putres = &put('firstaccesstimes',{"$courseid\0$res"=>$start},   my $putres = &put('firstaccesstimes',{"$courseid\0$res"=>$start},
                           $udom,$uname);                            $udom,$uname);
Line 5533  sub set_first_access { Line 4568  sub set_first_access {
                         'course.'.$courseid.'.timerinterval.'.$res => $interval,                          'course.'.$courseid.'.timerinterval.'.$res => $interval,
                      }                       }
                   );                    );
             if (($cachedtime) && (abs($start-$cachedtime) < 5)) {  
                 $cachedtimes{"$courseid\0$res"} = $start;  
             }  
         } elsif ($putres ne 'refused') {  
             &logthis("Result: $putres when attempting to set first access time ".  
                      "(type: $type, extent: $res) for $uname:$udom in $courseid");  
         }          }
         return $putres;          return $putres;
     }      }
Line 5546  sub set_first_access { Line 4575  sub set_first_access {
 }  }
 }  }
   
 sub checkout {  
     my ($symb,$tuname,$tudom,$tcrsid)=@_;  
     my $now=time;  
     my $lonhost=$perlvar{'lonHostID'};  
     my $infostr=&escape(  
                  'CHECKOUTTOKEN&'.  
                  $tuname.'&'.  
                  $tudom.'&'.  
                  $tcrsid.'&'.  
                  $symb.'&'.  
                  $now.'&'.$ENV{'REMOTE_ADDR'});  
     my $token=&reply('tmpput:'.$infostr,$lonhost);  
     if ($token=~/^error\:/) {  
         &logthis("<font color=\"blue\">WARNING: ".  
                 "Checkout tmpput failed ".$tudom.' - '.$tuname.' - '.$symb.  
                  "</font>");  
         return '';  
     }  
   
     $token=~s/^(\d+)\_.*\_(\d+)$/$1\*$2\*$lonhost/;  
     $token=~tr/a-z/A-Z/;  
   
     my %infohash=('resource.0.outtoken' => $token,  
                   'resource.0.checkouttime' => $now,  
                   'resource.0.outremote' => $ENV{'REMOTE_ADDR'});  
   
     unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') {  
        return '';  
     } else {  
         &logthis("<font color=\"blue\">WARNING: ".  
                 "Checkout cstore failed ".$tudom.' - '.$tuname.' - '.$symb.  
                  "</font>");  
     }  
   
     if (&log($tudom,$tuname,&homeserver($tuname,$tudom),  
                          &escape('Checkout '.$infostr.' - '.  
                                                  $token)) ne 'ok') {  
         return '';  
     } else {  
         &logthis("<font color=\"blue\">WARNING: ".  
                 "Checkout log failed ".$tudom.' - '.$tuname.' - '.$symb.  
                  "</font>");  
     }  
     return $token;  
 }  
   
 # ------------------------------------------------------------ Check in an item  
   
 sub checkin {  
     my $token=shift;  
     my $now=time;  
     my ($ta,$tb,$lonhost)=split(/\*/,$token);  
     $lonhost=~tr/A-Z/a-z/;  
     my $dtoken=$ta.'_'.&hostname($lonhost).'_'.$tb;  
     $dtoken=~s/\W/\_/g;  
     my ($dummy,$tuname,$tudom,$tcrsid,$symb,$chtim,$rmaddr)=  
                  split(/\&/,&unescape(&reply('tmpget:'.$dtoken,$lonhost)));  
   
     unless (($tuname) && ($tudom)) {  
         &logthis('Check in '.$token.' ('.$dtoken.') failed');  
         return '';  
     }  
   
     unless (&allowed('mgr',$tcrsid)) {  
         &logthis('Check in '.$token.' ('.$dtoken.') unauthorized: '.  
                  $env{'user.name'}.' - '.$env{'user.domain'});  
         return '';  
     }  
   
     my %infohash=('resource.0.intoken' => $token,  
                   'resource.0.checkintime' => $now,  
                   'resource.0.inremote' => $ENV{'REMOTE_ADDR'});  
   
     unless (&cstore(\%infohash,$symb,$tcrsid,$tudom,$tuname) eq 'ok') {  
        return '';  
     }  
   
     if (&log($tudom,$tuname,&homeserver($tuname,$tudom),  
                          &escape('Checkin - '.$token)) ne 'ok') {  
         return '';  
     }  
   
     return ($symb,$tuname,$tudom,$tcrsid);  
 }  
   
 # --------------------------------------------- Set Expire Date for Spreadsheet  # --------------------------------------------- Set Expire Date for Spreadsheet
   
 sub expirespread {  sub expirespread {
Line 6224  sub privileged { Line 5168  sub privileged {
     my $now = time;      my $now = time;
     my $roles;      my $roles;
     if (ref($possroles) eq 'ARRAY') {      if (ref($possroles) eq 'ARRAY') {
         $roles = $possroles;          $roles = $possroles; 
     } else {      } else {
         $roles = ['dc','su'];          $roles = ['dc','su'];
     }      }
Line 6251  sub privileged { Line 5195  sub privileged {
         for my $role (@rolesdump{grep { ! /^rolesdef_/ } keys(%rolesdump)}) {          for my $role (@rolesdump{grep { ! /^rolesdef_/ } keys(%rolesdump)}) {
             my ($trole, $tend, $tstart) = split(/_/, $role);              my ($trole, $tend, $tstart) = split(/_/, $role);
             if (grep(/^\Q$trole\E$/,@{$roles})) {              if (grep(/^\Q$trole\E$/,@{$roles})) {
                 return 1 unless ($tend && $tend < $now)                  return 1 unless ($tend && $tend < $now) 
                         or ($tstart && $tstart > $now);                          or ($tstart && $tstart > $now);
             }              }
         }          }
Line 6289  sub privileged_by_domain { Line 5233  sub privileged_by_domain {
                         my ($trole,$uname,$udom,$rest) = split(/:/,$item,4);                          my ($trole,$uname,$udom,$rest) = split(/:/,$item,4);
                         my ($end,$start) = split(/:/,$dompersonnel{$server}{$item});                          my ($end,$start) = split(/:/,$dompersonnel{$server}{$item});
                         next if ($end && $end < $now);                          next if ($end && $end < $now);
                         $privileged{$dom}{$trole}{$uname.':'.$udom} =                          $privileged{$dom}{$trole}{$uname.':'.$udom} = 
                             $dompersonnel{$server}{$item};                              $dompersonnel{$server}{$item};
                     }                      }
                 }                  }
Line 6410  sub rolesinit { Line 5354  sub rolesinit {
         }          }
     }      }
   
     @userroles{'user.author','user.adv','user.rar'} = &set_userprivs(\%userroles,      @userroles{'user.author', 'user.adv'} = &set_userprivs(\%userroles,
                                                           \%allroles, \%allgroups);          \%allroles, \%allgroups);
     $env{'user.adv'} = $userroles{'user.adv'};      $env{'user.adv'} = $userroles{'user.adv'};
     $env{'user.rar'} = $userroles{'user.rar'};  
   
     return (\%userroles,\%firstaccenv,\%timerintenv);      return (\%userroles,\%firstaccenv,\%timerintenv);
 }  }
Line 6449  sub custom_roleprivs { Line 5392  sub custom_roleprivs {
                     $$allroles{$spec.'./'.$tdomain.'/'}.=':'.$dompriv;                      $$allroles{$spec.'./'.$tdomain.'/'}.=':'.$dompriv;
                 }                  }
                 if (($trest ne '') && (defined($coursepriv))) {                  if (($trest ne '') && (defined($coursepriv))) {
                     if ($trole =~ m{^cr/$tdomain/$tdomain\Q-domainconfig\E/([^/]+)$}) {  
                         my $rolename = $1;  
                         $coursepriv = &course_adhocrole_privs($rolename,$tdomain,$trest,$coursepriv);  
                     }  
                     $$allroles{'cm.'.$area}.=':'.$coursepriv;                      $$allroles{'cm.'.$area}.=':'.$coursepriv;
                     $$allroles{$spec.'.'.$area}.=':'.$coursepriv;                      $$allroles{$spec.'.'.$area}.=':'.$coursepriv;
                 }                  }
Line 6461  sub custom_roleprivs { Line 5400  sub custom_roleprivs {
     }      }
 }  }
   
 sub course_adhocrole_privs {  
     my ($rolename,$cdom,$cnum,$coursepriv) = @_;  
     my %overrides = &get('environment',["internal.adhocpriv.$rolename"],$cdom,$cnum);  
     if ($overrides{"internal.adhocpriv.$rolename"}) {  
         my (%currprivs,%storeprivs);  
         foreach my $item (split(/:/,$coursepriv)) {  
             my ($priv,$restrict) = split(/\&/,$item);  
             $currprivs{$priv} = $restrict;  
         }  
         my (%possadd,%possremove,%full);  
         foreach my $item (split(/\:/,$Apache::lonnet::pr{'cr:c'})) {  
             my ($priv,$restrict)=split(/\&/,$item);  
             $full{$priv} = $restrict;  
         }  
         foreach my $item (split(/,/,$overrides{"internal.adhocpriv.$rolename"})) {  
              next if ($item eq '');  
              my ($rule,$rest) = split(/=/,$item);  
              next unless (($rule eq 'off') || ($rule eq 'on'));  
              foreach my $priv (split(/:/,$rest)) {  
                  if ($priv ne '') {  
                      if ($rule eq 'off') {  
                          $possremove{$priv} = 1;  
                      } else {  
                          $possadd{$priv} = 1;  
                      }  
                  }  
              }  
          }  
          foreach my $priv (sort(keys(%full))) {  
              if (exists($currprivs{$priv})) {  
                  unless (exists($possremove{$priv})) {  
                      $storeprivs{$priv} = $currprivs{$priv};  
                  }  
              } elsif (exists($possadd{$priv})) {  
                  $storeprivs{$priv} = $full{$priv};  
              }  
          }  
          $coursepriv = ':'.join(':',map { $_.'&'.$storeprivs{$_}; } sort(keys(%storeprivs)));  
      }  
      return $coursepriv;  
 }  
   
 sub group_roleprivs {  sub group_roleprivs {
     my ($allgroups,$area,$group_privs,$tend,$tstart) = @_;      my ($allgroups,$area,$group_privs,$tend,$tstart) = @_;
     my $access = 1;      my $access = 1;
Line 6537  sub set_userprivs { Line 5434  sub set_userprivs {
     my ($userroles,$allroles,$allgroups,$groups_roles) = @_;       my ($userroles,$allroles,$allgroups,$groups_roles) = @_; 
     my $author=0;      my $author=0;
     my $adv=0;      my $adv=0;
     my $rar=0;  
     my %grouproles = ();      my %grouproles = ();
     if (keys(%{$allgroups}) > 0) {      if (keys(%{$allgroups}) > 0) {
         my @groupkeys;           my @groupkeys; 
Line 6585  sub set_userprivs { Line 5481  sub set_userprivs {
                     $thesepriv{$privilege}.=$restrictions;                      $thesepriv{$privilege}.=$restrictions;
                 }                  }
                 if ($thesepriv{'adv'} eq 'F') { $adv=1; }                  if ($thesepriv{'adv'} eq 'F') { $adv=1; }
                 if ($thesepriv{'rar'} eq 'F') { $rar=1; }  
             }              }
         }          }
         my $thesestr='';          my $thesestr='';
Line 6594  sub set_userprivs { Line 5489  sub set_userprivs {
  }   }
         $userroles->{'user.priv.'.$role} = $thesestr;          $userroles->{'user.priv.'.$role} = $thesestr;
     }      }
     return ($author,$adv,$rar);      return ($author,$adv);
 }  }
   
 sub role_status {  sub role_status {
Line 6639  sub role_status { Line 5534  sub role_status {
                                 push(@rolecodes,$$role);                                  push(@rolecodes,$$role);
                                 &standard_roleprivs(\%allroles,$$role,$tdomain,$spec,$trest,$$where);                                  &standard_roleprivs(\%allroles,$$role,$tdomain,$spec,$trest,$$where);
                             }                              }
                             my ($author,$adv,$rar)= &set_userprivs(\%userroles,\%allroles,\%allgroups,                              my ($author,$adv)= &set_userprivs(\%userroles,\%allroles,\%allgroups,\%groups_roles);
                                                                    \%groups_roles);  
                             &appenv(\%userroles,\@rolecodes);                              &appenv(\%userroles,\@rolecodes);
                             &log($env{'user.domain'},$env{'user.name'},$env{'user.home'},"Role ".$spec);                              &log($env{'user.domain'},$env{'user.name'},$env{'user.home'},"Role ".$role);
                         }                          }
                     }                      }
                     $$tstatus = 'is';                      $$tstatus = 'is';
Line 6718  sub delete_env_groupprivs { Line 5612  sub delete_env_groupprivs {
 }  }
   
 sub check_adhoc_privs {  sub check_adhoc_privs {
     my ($cdom,$cnum,$update,$refresh,$now,$checkrole,$caller,$sec) = @_;      my ($cdom,$cnum,$update,$refresh,$now,$checkrole,$caller) = @_;
     my $cckey = 'user.role.'.$checkrole.'./'.$cdom.'/'.$cnum;      my $cckey = 'user.role.'.$checkrole.'./'.$cdom.'/'.$cnum;
     if ($sec) {  
         $cckey .= '/'.$sec;  
     }  
     my $setprivs;      my $setprivs;
     if ($env{$cckey}) {      if ($env{$cckey}) {
         my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus,$tpstart,$tpend);          my ($role,$where,$trolecode,$tstart,$tend,$tremark,$tstatus,$tpstart,$tpend);
         &role_status($cckey,$update,$refresh,$now,\$role,\$where,\$trolecode,\$tstatus,\$tstart,\$tend);          &role_status($cckey,$update,$refresh,$now,\$role,\$where,\$trolecode,\$tstatus,\$tstart,\$tend);
         unless (($tstatus eq 'is') || ($tstatus eq 'will_not')) {          unless (($tstatus eq 'is') || ($tstatus eq 'will_not')) {
             &set_adhoc_privileges($cdom,$cnum,$checkrole,$caller,$sec);              &set_adhoc_privileges($cdom,$cnum,$checkrole,$caller);
             $setprivs = 1;              $setprivs = 1;
         }          }
     } else {      } else {
         &set_adhoc_privileges($cdom,$cnum,$checkrole,$caller,$sec);          &set_adhoc_privileges($cdom,$cnum,$checkrole,$caller);
         $setprivs = 1;          $setprivs = 1;
     }      }
     return $setprivs;      return $setprivs;
 }  }
   
 sub set_adhoc_privileges {  sub set_adhoc_privileges {
 # role can be cc, ca, or cr/<dom>/<dom>-domainconfig/role  # role can be cc or ca
     my ($dcdom,$pickedcourse,$role,$caller,$sec) = @_;      my ($dcdom,$pickedcourse,$role,$caller) = @_;
     my $area = '/'.$dcdom.'/'.$pickedcourse;      my $area = '/'.$dcdom.'/'.$pickedcourse;
     if ($sec ne '') {  
         $area .= '/'.$sec;  
     }  
     my $spec = $role.'.'.$area;      my $spec = $role.'.'.$area;
     my %userroles = &set_arearole($role,$area,'','',$env{'user.domain'},      my %userroles = &set_arearole($role,$area,'','',$env{'user.domain'},
                                   $env{'user.name'},1);                                    $env{'user.name'},1);
     my %rolehash = ();      my %ccrole = ();
     if ($role =~ m{^\Qcr/$dcdom/$dcdom\E\-domainconfig/(\w+)$}) {      &standard_roleprivs(\%ccrole,$role,$dcdom,$spec,$pickedcourse,$area);
         my $rolename = $1;      my ($author,$adv)= &set_userprivs(\%userroles,\%ccrole);
         &custom_roleprivs(\%rolehash,$role,$dcdom,$pickedcourse,$spec,$area);  
         my %domdef = &get_domain_defaults($dcdom);  
         if (ref($domdef{'adhocroles'}) eq 'HASH') {  
             if (ref($domdef{'adhocroles'}{$rolename}) eq 'HASH') {  
                 &appenv({'request.role.desc' => $domdef{'adhocroles'}{$rolename}{'desc'},});  
             }  
         }  
     } else {  
         &standard_roleprivs(\%rolehash,$role,$dcdom,$spec,$pickedcourse,$area);  
     }  
     my ($author,$adv,$rar)= &set_userprivs(\%userroles,\%rolehash);  
     &appenv(\%userroles,[$role,'cm']);      &appenv(\%userroles,[$role,'cm']);
     &log($env{'user.domain'},$env{'user.name'},$env{'user.home'},"Role ".$spec);      &log($env{'user.domain'},$env{'user.name'},$env{'user.home'},"Role ".$role);
     unless ($caller eq 'constructaccess' && $env{'request.course.id'}) {      unless ($caller eq 'constructaccess' && $env{'request.course.id'}) {
         &appenv( {'request.role'        => $spec,          &appenv( {'request.role'        => $spec,
                   'request.role.domain' => $dcdom,                    'request.role.domain' => $dcdom,
                   'request.course.sec'  => $sec,                     'request.course.sec'  => ''
                  }                   }
                );                 );
         my $tadv=0;          my $tadv=0;
Line 6827  sub unserialize { Line 5704  sub unserialize {
     return {} if $rep =~ /^error/;      return {} if $rep =~ /^error/;
   
     my %returnhash=();      my %returnhash=();
     foreach my $item (split(/\&/,$rep)) {   foreach my $item (split(/\&/,$rep)) {
         my ($key, $value) = split(/=/, $item, 2);      my ($key, $value) = split(/=/, $item, 2);
         $key = unescape($key) unless $escapedkeys;      $key = unescape($key) unless $escapedkeys;
         next if $key =~ /^error: 2 /;      next if $key =~ /^error: 2 /;
         $returnhash{$key} = &thaw_unescape($value);      $returnhash{$key} = &thaw_unescape($value);
     }   }
       #return %returnhash;
     return \%returnhash;      return \%returnhash;
 }  }        
   
 # see Lond::dump_with_regexp  # see Lond::dump_with_regexp
 # if $escapedkeys hash keys won't get unescaped.  # if $escapedkeys hash keys won't get unescaped.
Line 6849  sub dump { Line 5727  sub dump {
     } else {      } else {
         $regexp='.';          $regexp='.';
     }      }
     if (grep { $_ eq $uhome } &current_machine_ids()) {      if (grep { $_ eq $uhome } current_machine_ids()) {
         # user is hosted on this machine          # user is hosted on this machine
         my $reply = LONCAPA::Lond::dump_with_regexp(join(':', ($udomain,          my $reply = LONCAPA::Lond::dump_with_regexp(join(":", ($udomain,
                     $uname, $namespace, $regexp, $range)), $perlvar{'lonVersion'});                      $uname, $namespace, $regexp, $range)), $perlvar{'lonVersion'});
         return %{&unserialize($reply, $escapedkeys)};          return %{unserialize($reply, $escapedkeys)};
     }      }
     my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome);      my $rep=&reply("dump:$udomain:$uname:$namespace:$regexp:$range",$uhome);
     my @pairs=split(/\&/,$rep);      my @pairs=split(/\&/,$rep);
Line 6861  sub dump { Line 5739  sub dump {
     if (!($rep =~ /^error/ )) {      if (!($rep =~ /^error/ )) {
  foreach my $item (@pairs) {   foreach my $item (@pairs) {
     my ($key,$value)=split(/=/,$item,2);      my ($key,$value)=split(/=/,$item,2);
             $key = &unescape($key) unless ($escapedkeys);          $key = unescape($key) unless $escapedkeys;
           #$key = &unescape($key);
     next if ($key =~ /^error: 2 /);      next if ($key =~ /^error: 2 /);
     $returnhash{$key}=&thaw_unescape($value);      $returnhash{$key}=&thaw_unescape($value);
  }   }
Line 6905  sub currentdump { Line 5784  sub currentdump {
    my $rep;     my $rep;
   
    if (grep { $_ eq $uhome } current_machine_ids()) {     if (grep { $_ eq $uhome } current_machine_ids()) {
        $rep = LONCAPA::Lond::dump_profile_database(join(":", ($sdom, $sname,         $rep = LONCAPA::Lond::dump_profile_database(join(":", ($sdom, $sname, 
                    $courseid)));                     $courseid)));
    } else {     } else {
        $rep = reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome);         $rep = reply('currentdump:'.$sdom.':'.$sname.':'.$courseid,$uhome);
Line 6915  sub currentdump { Line 5794  sub currentdump {
    #     #
    my %returnhash=();     my %returnhash=();
    #     #
    if ($rep eq 'unknown_cmd') {     if ($rep eq "unknown_cmd") { 
        # an old lond will not know currentdump         # an old lond will not know currentdump
        # Do a dump and make it look like a currentdump         # Do a dump and make it look like a currentdump
        my @tmp = &dumpstore($courseid,$sdom,$sname,'.');         my @tmp = &dumpstore($courseid,$sdom,$sname,'.');
Line 7149  sub tmpget { Line 6028  sub tmpget {
     if (!defined($server)) { $server = $perlvar{'lonHostID'}; }      if (!defined($server)) { $server = $perlvar{'lonHostID'}; }
     my $rep=&reply("tmpget:$token",$server);      my $rep=&reply("tmpget:$token",$server);
     my %returnhash;      my %returnhash;
     if ($rep =~ /^(con_lost|error|no_such_host)/i) {  
         return %returnhash;  
     }  
     foreach my $item (split(/\&/,$rep)) {      foreach my $item (split(/\&/,$rep)) {
  my ($key,$value)=split(/=/,$item);   my ($key,$value)=split(/=/,$item);
           next if ($key =~ /^error: 2 /);
  $returnhash{&unescape($key)}=&thaw_unescape($value);   $returnhash{&unescape($key)}=&thaw_unescape($value);
     }      }
     return %returnhash;      return %returnhash;
Line 7166  sub tmpdel { Line 6043  sub tmpdel {
     return &reply("tmpdel:$token",$server);      return &reply("tmpdel:$token",$server);
 }  }
   
 # ------------------------------------------------------------ get_timebased_id  # ------------------------------------------------------------ get_timebased_id 
   
 sub get_timebased_id {  sub get_timebased_id {
     my ($prefix,$keyid,$namespace,$cdom,$cnum,$idtype,$who,$locktries,      my ($prefix,$keyid,$namespace,$cdom,$cnum,$idtype,$who,$locktries,
         $maxtries) = @_;          $maxtries) = @_;
     my ($newid,$error,$dellock);      my ($newid,$error,$dellock);
     unless (($prefix =~ /^\w+$/) && ($keyid =~ /^\w+$/) && ($namespace ne '')) {      unless (($prefix =~ /^\w+$/) && ($keyid =~ /^\w+$/) && ($namespace ne '')) {  
         return ('','ok','invalid call to get suffix');          return ('','ok','invalid call to get suffix');
     }      }
   
Line 7186  sub get_timebased_id { Line 6063  sub get_timebased_id {
     if (!$maxtries) {      if (!$maxtries) {
         $maxtries = 10;          $maxtries = 10;
     }      }
       
     if (($cdom eq '') || ($cnum eq '')) {      if (($cdom eq '') || ($cnum eq '')) {
         if ($env{'request.course.id'}) {          if ($env{'request.course.id'}) {
             $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};              $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
Line 7341  sub get_portfolio_access { Line 6218  sub get_portfolio_access {
                 if (ref($access_hash->{$ipkey}{'ip'}) eq 'ARRAY') {                  if (ref($access_hash->{$ipkey}{'ip'}) eq 'ARRAY') {
                     if (&Apache::loncommon::check_ip_acc(join(',',@{$access_hash->{$ipkey}{'ip'}}),$clientip)) {                      if (&Apache::loncommon::check_ip_acc(join(',',@{$access_hash->{$ipkey}{'ip'}}),$clientip)) {
                         $allowed = 1;                          $allowed = 1;
                         last;                          last; 
                     }                      }
                 }                  }
             }              }
Line 7569  sub usertools_access { Line 6446  sub usertools_access {
   
     my ($toolstatus,$inststatus,$envkey);      my ($toolstatus,$inststatus,$envkey);
     if ($context eq 'requestauthor') {      if ($context eq 'requestauthor') {
         $envkey = $context;          $envkey = $context; 
     } else {      } else {
         $envkey = $context.'.'.$tool;          $envkey = $context.'.'.$tool;
     }      }
Line 7848  sub allowed { Line 6725  sub allowed {
   
     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{/(?:smppg|bulletinboard|ext\.tool)$}))       if (((($uri=~/^adm\//) && ($uri !~ m{/(?:smppg|bulletinboard)$})) 
  || (($uri=~/\.meta$/) && ($uri!~m|^uploaded/|) ))    || (($uri=~/\.meta$/) && ($uri!~m|^uploaded/|) )) 
  && ($priv eq 'bre')) {   && ($priv eq 'bre')) {
  return 'F';   return 'F';
Line 8013  sub allowed { Line 6890  sub allowed {
   
     if ($env{'user.priv.'.$env{'request.role'}.'.'.$courseuri}      if ($env{'user.priv.'.$env{'request.role'}.'.'.$courseuri}
        =~/\Q$priv\E\&([^\:]*)/) {         =~/\Q$priv\E\&([^\:]*)/) {
         if ($priv eq 'mip') {          unless (($priv eq 'bro') && (!$ownaccess)) {
             my $rem = $1;              $thisallowed.=$1;
             if (($uri ne '') && ($env{'request.course.id'} eq $uri) &&  
                 ($env{'course.'.$env{'request.course.id'}.'.internal.courseowner'} eq $env{'user.name'}.':'.$env{'user.domain'})) {  
                 my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
                 if ($cdom ne '') {  
                     my %passwdconf = &get_passwdconf($cdom);  
                     if (ref($passwdconf{'crsownerchg'}) eq 'HASH') {  
                         if (ref($passwdconf{'crsownerchg'}{'by'}) eq 'ARRAY') {  
                             if (@{$passwdconf{'crsownerchg'}{'by'}}) {  
                                 my @inststatuses = split(':',$env{'environment.inststatus'});  
                                 unless (@inststatuses) {  
                                     @inststatuses = ('default');  
                                 }  
                                 foreach my $status (@inststatuses) {  
                                     if (grep(/^\Q$status\E$/,@{$passwdconf{'crsownerchg'}{'by'}})) {  
                                         $thisallowed.=$rem;  
                                     }  
                                 }  
                             }  
                         }  
                     }  
                 }  
             }  
         } else {  
             unless (($priv eq 'bro') && (!$ownaccess)) {  
                 $thisallowed.=$1;  
             }  
         }          }
     }      }
   
Line 8095  sub allowed { Line 6946  sub allowed {
  && &is_portfolio_url($uri)) {   && &is_portfolio_url($uri)) {
  $thisallowed = &portfolio_access($uri,$clientip);   $thisallowed = &portfolio_access($uri,$clientip);
     }      }
       
 # Full access at system, domain or course-wide level? Exit.  # Full access at system, domain or course-wide level? Exit.
     if ($thisallowed=~/F/) {      if ($thisallowed=~/F/) {
  return 'F';   return 'F';
Line 8123  sub allowed { Line 6974  sub allowed {
   
     if ($env{'request.course.id'}) {      if ($env{'request.course.id'}) {
   
 # If this is modifying password (internal auth) domains must match for user and user's role.  
   
         if ($priv eq 'mip') {  
             if ($env{'user.domain'} eq $env{'request.role.domain'}) {  
                 return $thisallowed;  
             } else {  
                 return '';  
             }  
         }  
   
        $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'};
Line 8372  sub constructaccess { Line 7213  sub constructaccess {
     my ($ownername,$ownerdomain,$ownerhome);      my ($ownername,$ownerdomain,$ownerhome);
   
     ($ownerdomain,$ownername) =      ($ownerdomain,$ownername) =
         ($url=~ m{^(?:\Q$perlvar{'lonDocRoot'}\E|)/priv/($match_domain)/($match_username)(?:/|$)});          ($url=~ m{^(?:\Q$perlvar{'lonDocRoot'}\E|)(?:/daxeopen)?/priv/($match_domain)/($match_username)/});
   
 # The URL does not really point to any authorspace, forget it  # The URL does not really point to any authorspace, forget it
     unless (($ownername) && ($ownerdomain)) { return ''; }      unless (($ownername) && ($ownerdomain)) { return ''; }
Line 8435  sub constructaccess { Line 7276  sub constructaccess {
 #  #
 # User for whom data are being temporarily cached.  # User for whom data are being temporarily cached.
 my $cacheduser='';  my $cacheduser='';
 # Cached blockers for this user (a hash of blocking items).  # Cached blockers for this user (a hash of blocking items). 
 my %cachedblockers=();  my %cachedblockers=();
 # When the data were last cached.  # When the data were last cached.
 my $cachedlast='';  my $cachedlast='';
   
 sub load_all_blockers {  sub load_all_blockers {
     my ($uname,$udom,$blocks)=@_;      my ($uname,$udom,$blocks)=@_;
     if (($uname ne '') && ($udom ne '')) {      if (($uname ne '') && ($udom ne '')) { 
         if (($cacheduser eq $uname.':'.$udom) &&          if (($cacheduser eq $uname.':'.$udom) &&
             (abs($cachedlast-time)<5)) {              (abs($cachedlast-time)<5)) {
             return;              return;
Line 8484  sub get_commblock_resources { Line 7325  sub get_commblock_resources {
     } else {      } else {
         %commblocks = &get_comm_blocks();          %commblocks = &get_comm_blocks();
     }      }
     return %blockers unless (keys(%commblocks) > 0);      return %blockers unless (keys(%commblocks) > 0); 
     my $navmap = Apache::lonnavmaps::navmap->new();      my $navmap = Apache::lonnavmaps::navmap->new();
     return %blockers unless (ref($navmap));      return %blockers unless (ref($navmap));
     my $now = time;      my $now = time;
Line 8496  sub get_commblock_resources { Line 7337  sub get_commblock_resources {
                     if (ref($commblocks{$block}{'blocks'}{'docs'}) eq 'HASH') {                      if (ref($commblocks{$block}{'blocks'}{'docs'}) eq 'HASH') {
                         if (ref($commblocks{$block}{'blocks'}{'docs'}{'maps'}) eq 'HASH') {                          if (ref($commblocks{$block}{'blocks'}{'docs'}{'maps'}) eq 'HASH') {
                             if (keys(%{$commblocks{$block}{'blocks'}{'docs'}{'maps'}})) {                              if (keys(%{$commblocks{$block}{'blocks'}{'docs'}{'maps'}})) {
                                 $blockers{$block}{maps} = $commblocks{$block}{'blocks'}{'docs'}{'maps'};                                  $blockers{$block}{maps} = $commblocks{$block}{'blocks'}{'docs'}{'maps'}; 
                             }                              }
                         }                          }
                         if (ref($commblocks{$block}{'blocks'}{'docs'}{'resources'}) eq 'HASH') {                          if (ref($commblocks{$block}{'blocks'}{'docs'}{'resources'}) eq 'HASH') {
Line 8521  sub get_commblock_resources { Line 7362  sub get_commblock_resources {
                         if ($item =~ /___\d+___/) {                          if ($item =~ /___\d+___/) {
                             $type = 'resource';                              $type = 'resource';
                             @interval=&EXT("resource.0.interval",$item);                              @interval=&EXT("resource.0.interval",$item);
                             if (ref($navmap)) {                              if (ref($navmap)) {                        
                                 my $res = $navmap->getBySymb($item);                                  my $res = $navmap->getBySymb($item); 
                                 push(@to_test,$res);                                  push(@to_test,$res);
                             }                              }
                         } else {                          } else {
Line 8545  sub get_commblock_resources { Line 7386  sub get_commblock_resources {
                             }                              }
                         }                          }
                     }                      }
                     if ($interval[0] =~ /^(\d+)/) {                      if ($interval[0] =~ /^\d+/) {
                         my $timelimit = $1;                           my ($timelimit) = split(/_/,$interval[0]);
                         my $first_access;                          my $first_access;
                         if ($type eq 'resource') {                          if ($type eq 'resource') {
                             $first_access=&get_first_access($interval[1],$item);                              $first_access=&get_first_access($interval[1],$item);
Line 8602  sub has_comm_blocking { Line 7443  sub has_comm_blocking {
     }      }
     if ($symb) {      if ($symb) {
         @symbs = ($symb);          @symbs = ($symb);
     } elsif (keys(%possibles)) {      } elsif (keys(%possibles)) { 
         @symbs = keys(%possibles);          @symbs = keys(%possibles);
     }      }
     my $noblock;      my $noblock;
Line 8640  sub has_comm_blocking { Line 7481  sub has_comm_blocking {
 }  }
 }  }
   
 # -------------------------------- Deversion and split uri into path an filename  # -------------------------------- Deversion and split uri into path an filename   
   
 #  #
 #   Removes the version from a URI and  #   Removes the version from a URI and
Line 8711  sub get_symb_from_alias { Line 7552  sub get_symb_from_alias {
   
 sub definerole {  sub definerole {
   if (allowed('mcr','/')) {    if (allowed('mcr','/')) {
     my ($rolename,$sysrole,$domrole,$courole,$uname,$udom)=@_;      my ($rolename,$sysrole,$domrole,$courole)=@_;
     foreach my $role (split(':',$sysrole)) {      foreach my $role (split(':',$sysrole)) {
  my ($crole,$cqual)=split(/\&/,$role);   my ($crole,$cqual)=split(/\&/,$role);
         if ($pr{'cr:s'}!~/\Q$crole\E/) { return "refused:s:$crole"; }          if ($pr{'cr:s'}!~/\Q$crole\E/) { return "refused:s:$crole"; }
Line 8739  sub definerole { Line 7580  sub definerole {
             }              }
         }          }
     }      }
     my $uhome;  
     if (($uname ne '') && ($udom ne '')) {  
         $uhome = &homeserver($uname,$udom);  
         return $uhome if ($uhome eq 'no_host');  
     } else {  
         $uname = $env{'user.name'};  
         $udom = $env{'user.domain'};  
         $uhome = $env{'user.home'};  
     }  
     my $command="encrypt:rolesput:$env{'user.domain'}:$env{'user.name'}:".      my $command="encrypt:rolesput:$env{'user.domain'}:$env{'user.name'}:".
                 "$udom:$uname:rolesdef_$rolename=".                  "$env{'user.domain'}:$env{'user.name'}:".
           "rolesdef_$rolename=".
                 escape($sysrole.'_'.$domrole.'_'.$courole);                  escape($sysrole.'_'.$domrole.'_'.$courole);
     return reply($command,$uhome);      return reply($command,$env{'user.home'});
   } else {    } else {
     return 'refused';      return 'refused';
   }    }
Line 8766  sub metadata_query { Line 7599  sub metadata_query {
     my @server_list = (defined($server_array) ? @$server_array      my @server_list = (defined($server_array) ? @$server_array
                                               : keys(%libserv) );                                                : keys(%libserv) );
     for my $server (@server_list) {      for my $server (@server_list) {
         my $domains = '';          my $domains = ''; 
         if (ref($domains_hash) eq 'HASH') {          if (ref($domains_hash) eq 'HASH') {
             $domains = $domains_hash->{$server};                  $domains = $domains_hash->{$server}; 
         }          }
  unless ($custom or $customshow) {   unless ($custom or $customshow) {
     my $reply=&reply("querysend:".&escape($query).':::'.&escape($domains),$server);      my $reply=&reply("querysend:".&escape($query).':::'.&escape($domains),$server);
Line 8833  sub update_allusers_table { Line 7666  sub update_allusers_table {
   
 sub fetch_enrollment_query {  sub fetch_enrollment_query {
     my ($context,$affiliatesref,$replyref,$dom,$cnum) = @_;      my ($context,$affiliatesref,$replyref,$dom,$cnum) = @_;
     my ($homeserver,$sleep,$loopmax);      my $homeserver;
     my $maxtries = 1;      my $maxtries = 1;
     if ($context eq 'automated') {      if ($context eq 'automated') {
         $homeserver = $perlvar{'lonHostID'};          $homeserver = $perlvar{'lonHostID'};
         $sleep = 2;  
         $loopmax = 100;  
         $maxtries = 10; # will wait for up to 2000s for retrieval of classlist data before timeout          $maxtries = 10; # will wait for up to 2000s for retrieval of classlist data before timeout
     } else {      } else {
         $homeserver = &homeserver($cnum,$dom);          $homeserver = &homeserver($cnum,$dom);
Line 8856  sub fetch_enrollment_query { Line 7687  sub fetch_enrollment_query {
         &logthis('fetch_enrollment_query: invalid queryid: '.$queryid.' for host: '.$host.' and homeserver: '.$homeserver.' context: '.$context.' '.$cnum);           &logthis('fetch_enrollment_query: invalid queryid: '.$queryid.' for host: '.$host.' and homeserver: '.$homeserver.' context: '.$context.' '.$cnum); 
         return 'error: '.$queryid;          return 'error: '.$queryid;
     }      }
     my $reply = &get_query_reply($queryid,$sleep,$loopmax);      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,$sleep,$loopmax);          $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.' '.$env{'user.name'}.' for '.$queryid.' context: '.$context.' '.$cnum.' maxtries: '.$maxtries.' tries: '.$tries);          &logthis('fetch_enrollment_query error: '.$reply.' for '.$dom.' '.$env{'user.name'}.' for '.$queryid.' context: '.$context.' '.$cnum.' maxtries: '.$maxtries.' tries: '.$tries);
     } else {      } else {
         my @responses = split(/:/,$reply);          my @responses = split(/:/,$reply);
         if (grep { $_ eq $homeserver } &current_machine_ids()) {          if ($homeserver eq $perlvar{'lonHostID'}) {
             foreach my $line (@responses) {              foreach my $line (@responses) {
                 my ($key,$value) = split(/=/,$line,2);                  my ($key,$value) = split(/=/,$line,2);
                 $$replyref{$key} = $value;                  $$replyref{$key} = $value;
Line 8884  sub fetch_enrollment_query { Line 7715  sub fetch_enrollment_query {
                         if ($xml_classlist =~ /^error/) {                          if ($xml_classlist =~ /^error/) {
                             &logthis('fetch_enrollment_query - autoretrieve error: '.$xml_classlist.' for '.$filename.' from server: '.$homeserver.' '.$context.' '.$cnum);                              &logthis('fetch_enrollment_query - autoretrieve error: '.$xml_classlist.' for '.$filename.' from server: '.$homeserver.' '.$context.' '.$cnum);
                         } else {                          } else {
                             if ( open(FILE,">",$destname) ) {                              if ( open(FILE,">$destname") ) {
                                 print FILE &unescape($xml_classlist);                                  print FILE &unescape($xml_classlist);
                                 close(FILE);                                  close(FILE);
                             } else {                              } else {
Line 8901  sub fetch_enrollment_query { Line 7732  sub fetch_enrollment_query {
 }  }
   
 sub get_query_reply {  sub get_query_reply {
     my ($queryid,$sleep,$loopmax) = @_;      my $queryid=shift;
     if (($sleep eq '') || ($sleep !~ /^\d+\.?\d*$/)) {  
         $sleep = 0.2;  
     }  
     if (($loopmax eq '') || ($loopmax =~ /\D/)) {  
         $loopmax = 100;  
     }  
     my $replyfile=LONCAPA::tempdir().$queryid;      my $replyfile=LONCAPA::tempdir().$queryid;
     my $reply='';      my $reply='';
     for (1..$loopmax) {      for (1..100) {
  sleep($sleep);   sleep(0.2);
         if (-e $replyfile.'.end') {          if (-e $replyfile.'.end') {
     if (open(my $fh,"<",$replyfile)) {      if (open(my $fh,$replyfile)) {
  $reply = join('',<$fh>);   $reply = join('',<$fh>);
  close($fh);   close($fh);
    } else { return 'error: reply_file_error'; }     } else { return 'error: reply_file_error'; }
Line 9305  sub auto_validate_class_sec { Line 8130  sub auto_validate_class_sec {
     return $response;      return $response;
 }  }
   
 sub auto_validate_instclasses {  
     my ($cdom,$cnum,$owners,$classesref) = @_;  
     my ($homeserver,%validations);  
     $homeserver = &homeserver($cnum,$cdom);  
     unless ($homeserver eq 'no_host') {  
         my $ownerlist;  
         if (ref($owners) eq 'ARRAY') {  
             $ownerlist = join(',',@{$owners});  
         } else {  
             $ownerlist = $owners;  
         }  
         if (ref($classesref) eq 'HASH') {  
             my $classes = &freeze_escape($classesref);  
             my $response=&reply('autovalidateinstclasses:'.&escape($ownerlist).  
                                 ':'.$cdom.':'.$classes,$homeserver);  
             unless ($response =~ /(con_lost|error|no_such_host|refused)/) {  
                 my @items = split(/&/,$response);  
                 foreach my $item (@items) {  
                     my ($key,$value) = split('=',$item);  
                     $validations{&unescape($key)} = &thaw_unescape($value);  
                 }  
             }  
         }  
     }  
     return %validations;  
 }  
   
 sub auto_crsreq_update {  sub auto_crsreq_update {
     my ($cdom,$cnum,$crstype,$action,$ownername,$ownerdomain,$fullname,$title,      my ($cdom,$cnum,$crstype,$action,$ownername,$ownerdomain,$fullname,$title,
         $code,$accessstart,$accessend,$inbound) = @_;          $code,$accessstart,$accessend,$inbound) = @_;
Line 9348  sub auto_crsreq_update { Line 8146  sub auto_crsreq_update {
                             ':'.&escape($action).':'.&escape($ownername).':'.                              ':'.&escape($action).':'.&escape($ownername).':'.
                             &escape($ownerdomain).':'.&escape($fullname).':'.                              &escape($ownerdomain).':'.&escape($fullname).':'.
                             &escape($title).':'.&escape($code).':'.                              &escape($title).':'.&escape($code).':'.
                             &escape($accessstart).':'.&escape($accessend).':'.$info,$homeserver);                              &escape($accessstart).':'.&escape($accessend).':'.$info,
                               $homeserver);
         unless ($response =~ /(con_lost|error|no_such_host|refused)/) {          unless ($response =~ /(con_lost|error|no_such_host|refused)/) {
             my @items = split(/&/,$response);              my @items = split(/&/,$response);
             foreach my $item (@items) {              foreach my $item (@items) {
Line 9360  sub auto_crsreq_update { Line 8159  sub auto_crsreq_update {
     return \%crsreqresponse;      return \%crsreqresponse;
 }  }
   
 sub auto_export_grades {  
     my ($cdom,$cnum,$inforef,$gradesref) = @_;  
     my ($homeserver,%exportresponse);  
     if ($cdom =~ /^$match_domain$/) {  
         $homeserver = &domain($cdom,'primary');  
     }  
     unless (($homeserver eq 'no_host') || ($homeserver eq '')) {  
         my $info;  
         if (ref($inforef) eq 'HASH') {  
             $info = &freeze_escape($inforef);  
         }  
         if (ref($gradesref) eq 'HASH') {  
             my $grades = &freeze_escape($gradesref);  
             my $response=&reply('encrypt:autoexportgrades:'.$cdom.':'.$cnum.':'.  
                                 $info.':'.$grades,$homeserver);  
             unless ($response =~ /(con_lost|error|no_such_host|refused|unknown_command)/) {  
                 my @items = split(/&/,$response);  
                 foreach my $item (@items) {  
                     my ($key,$value) = split('=',$item);  
                     $exportresponse{&unescape($key)} = &thaw_unescape($value);  
                 }  
             }  
         }  
     }  
     return \%exportresponse;  
 }  
   
 sub check_instcode_cloning {  sub check_instcode_cloning {
     my ($codedefaults,$code_order,$cloner,$clonefromcode,$clonetocode) = @_;      my ($codedefaults,$code_order,$cloner,$clonefromcode,$clonetocode) = @_;
     unless ((ref($codedefaults) eq 'HASH') && (ref($code_order) eq 'ARRAY')) {      unless ((ref($codedefaults) eq 'HASH') && (ref($code_order) eq 'ARRAY')) {
Line 9729  sub assignrole { Line 8501  sub assignrole {
                         }                          }
                     }                      }
                 } elsif ($context eq 'requestauthor') {                  } elsif ($context eq 'requestauthor') {
                     if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'}) &&                      if (($udom eq $env{'user.domain'}) && ($uname eq $env{'user.name'}) && 
                         ($url eq '/'.$udom.'/') && ($role eq 'au')) {                          ($url eq '/'.$udom.'/') && ($role eq 'au')) {
                         if ($env{'environment.requestauthor'} eq 'automatic') {                          if ($env{'environment.requestauthor'} eq 'automatic') {
                             $refused = '';                              $refused = '';
Line 9737  sub assignrole { Line 8509  sub assignrole {
                             my %domdefaults = &get_domain_defaults($udom);                              my %domdefaults = &get_domain_defaults($udom);
                             if (ref($domdefaults{'requestauthor'}) eq 'HASH') {                              if (ref($domdefaults{'requestauthor'}) eq 'HASH') {
                                 my $checkbystatus;                                  my $checkbystatus;
                                 if ($env{'user.adv'}) {                                  if ($env{'user.adv'}) { 
                                     my $disposition = $domdefaults{'requestauthor'}{'_LC_adv'};                                      my $disposition = $domdefaults{'requestauthor'}{'_LC_adv'};
                                     if ($disposition eq 'automatic') {                                      if ($disposition eq 'automatic') {
                                         $refused = '';                                          $refused = '';
                                     } elsif ($disposition eq '') {                                      } elsif ($disposition eq '') {
                                         $checkbystatus = 1;                                          $checkbystatus = 1;
                                     }                                      } 
                                 } else {                                  } else {
                                     $checkbystatus = 1;                                      $checkbystatus = 1;
                                 }                                  }
Line 9825  sub assignrole { Line 8597  sub assignrole {
             &courserolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag,              &courserolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag,
                            $selfenroll,$context);                             $selfenroll,$context);
         } elsif (($role eq 'li') || ($role eq 'dg') || ($role eq 'sc') ||          } elsif (($role eq 'li') || ($role eq 'dg') || ($role eq 'sc') ||
                  ($role eq 'au') || ($role eq 'dc') || ($role eq 'dh') ||                   ($role eq 'au') || ($role eq 'dc')) {
                  ($role eq 'da')) {  
             &domainrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag,              &domainrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag,
                            $context);                             $context);
         } elsif (($role eq 'ca') || ($role eq 'aa')) {          } elsif (($role eq 'ca') || ($role eq 'aa')) {
             &coauthorrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag,              &coauthorrolelog($role,$uname,$udom,$url,$origstart,$origend,$delflag,
                              $context);                               $context); 
         }          }
         if ($role eq 'cc') {          if ($role eq 'cc') {
             &autoupdate_coowners($url,$end,$start,$uname,$udom);              &autoupdate_coowners($url,$end,$start,$uname,$udom);
Line 9930  sub store_coowners { Line 8701  sub store_coowners {
 sub modifyuserauth {  sub modifyuserauth {
     my ($udom,$uname,$umode,$upass)=@_;      my ($udom,$uname,$umode,$upass)=@_;
     my $uhome=&homeserver($uname,$udom);      my $uhome=&homeserver($uname,$udom);
     my $allowed;      unless (&allowed('mau',$udom)) { return 'refused'; }
     if (&allowed('mau',$udom)) {  
         $allowed = 1;  
     } elsif (($umode eq 'internal') && ($udom eq $env{'user.domain'}) &&  
              ($env{'request.course.id'}) && (&allowed('mip',$env{'request.course.id'})) &&  
              (!$env{'course.'.$env{'request.course.id'}.'.internal.nopasswdchg'})) {  
         my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};  
         my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};  
         if (($cdom ne '') && ($cnum ne '')) {  
             my $is_owner = &is_course_owner($cdom,$cnum);  
             if ($is_owner) {  
                 $allowed = 1;  
             }  
         }  
     }  
     unless ($allowed) { 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'});  
Line 10146  sub modifyuser { Line 8902  sub modifyuser {
 sub modifystudent {  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,
         $selfenroll,$context,$inststatus,$credits,$instsec)=@_;          $selfenroll,$context,$inststatus,$credits)=@_;
     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 10161  sub modifystudent { Line 8917  sub modifystudent {
     # student's environment      # student's environment
     $uid = undef if (!$forceid);      $uid = undef if (!$forceid);
     $reply = &modify_student_enrollment($udom,$uname,$uid,$first,$middle,$last,      $reply = &modify_student_enrollment($udom,$uname,$uid,$first,$middle,$last,
  $gene,$usec,$end,$start,$type,$locktype,                                          $gene,$usec,$end,$start,$type,$locktype,
                                         $cid,$selfenroll,$context,$credits,$instsec);                                          $cid,$selfenroll,$context,$credits);
     return $reply;      return $reply;
 }  }
   
 sub modify_student_enrollment {  sub modify_student_enrollment {
     my ($udom,$uname,$uid,$first,$middle,$last,$gene,$usec,$end,$start,$type,      my ($udom,$uname,$uid,$first,$middle,$last,$gene,$usec,$end,$start,$type,
         $locktype,$cid,$selfenroll,$context,$credits,$instsec) = @_;          $locktype,$cid,$selfenroll,$context,$credits) = @_;
     my ($cdom,$cnum,$chome);      my ($cdom,$cnum,$chome);
     if (!$cid) {      if (!$cid) {
  unless ($cid=$env{'request.course.id'}) {   unless ($cid=$env{'request.course.id'}) {
Line 10215  sub modify_student_enrollment { Line 8971  sub modify_student_enrollment {
     my %old_entry = &Apache::lonnet::get('classlist',[$user],$cdom,$cnum);      my %old_entry = &Apache::lonnet::get('classlist',[$user],$cdom,$cnum);
     my $reply=cput('classlist',      my $reply=cput('classlist',
    {$user =>      {$user => 
  join(':',$end,$start,$uid,$usec,$fullname,$type,$locktype,$credits,$instsec) },   join(':',$end,$start,$uid,$usec,$fullname,$type,$locktype,$credits) },
    $cdom,$cnum);     $cdom,$cnum);
     if (($reply eq 'ok') || ($reply eq 'delayed')) {      if (($reply eq 'ok') || ($reply eq 'delayed')) {
         &devalidate_getsection_cache($udom,$uname,$cid);          &devalidate_getsection_cache($udom,$uname,$cid);
Line 10282  sub writecoursepref { Line 9038  sub writecoursepref {
   
 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,$cnum,$context,$category,$callercontext)=@_;          $course_owner,$crstype,$cnum,$context,$category)=@_;
     $url=&declutter($url);      $url=&declutter($url);
     my $cid='';      my $cid='';
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         my $can_create = 0;          my $can_create = 0;
         my ($ownername,$ownerdom) = split(':',$course_owner);          my ($ownername,$ownerdom) = split(':',$course_owner);
         if ($udom eq $ownerdom) {          if ($udom eq $ownerdom) {
             my $reload;              if (&usertools_access($ownername,$ownerdom,$category,undef,
             if (($callercontext eq 'auto') &&  
                ($ownerdom eq $env{'user.domain'}) && ($ownername eq $env{'user.name'})) {  
                 $reload = 'reload';  
             }  
             if (&usertools_access($ownername,$ownerdom,$category,$reload,  
                                   $context)) {                                    $context)) {
                 $can_create = 1;                  $can_create = 1;
             }              }
Line 10443  sub generate_coursenum { Line 9194  sub generate_coursenum {
 sub is_course {  sub is_course {
     my ($cdom, $cnum) = scalar(@_) == 1 ?       my ($cdom, $cnum) = scalar(@_) == 1 ? 
          ($_[0] =~ /^($match_domain)_($match_courseid)$/)  :  @_;           ($_[0] =~ /^($match_domain)_($match_courseid)$/)  :  @_;
     return unless (($cdom =~ /^$match_domain$/) && ($cnum =~ /^$match_courseid$/));  
     my $uhome=&homeserver($cnum,$cdom);      return unless $cdom and $cnum;
     my $iscourse;  
     if (grep { $_ eq $uhome } current_machine_ids()) {      my %courses = &courseiddump($cdom, '.', 1, '.', '.', $cnum, undef, undef,
         $iscourse = &LONCAPA::Lond::is_course($cdom,$cnum);          '.');
     } else {  
         my $hashid = $cdom.':'.$cnum;      return unless(exists($courses{$cdom.'_'.$cnum}));
         ($iscourse,my $cached) = &is_cached_new('iscourse',$hashid);  
         unless (defined($cached)) {  
             my %courses = &courseiddump($cdom, '.', 1, '.', '.',  
                                         $cnum,undef,undef,'.');  
             $iscourse = 0;  
             if (exists($courses{$cdom.'_'.$cnum})) {  
                 $iscourse = 1;  
             }  
             &do_cache_new('iscourse',$hashid,$iscourse,3600);  
         }  
     }  
     return unless($iscourse);  
     return wantarray ? ($cdom, $cnum) : $cdom.'_'.$cnum;      return wantarray ? ($cdom, $cnum) : $cdom.'_'.$cnum;
 }  }
   
Line 10597  sub save_selected_files { Line 9336  sub save_selected_files {
     my ($user, $path, @files) = @_;      my ($user, $path, @files) = @_;
     my $filename = $user."savedfiles";      my $filename = $user."savedfiles";
     my @other_files = &files_not_in_path($user, $path);      my @other_files = &files_not_in_path($user, $path);
     open (OUT,'>',LONCAPA::tempdir().$filename);      open (OUT, '>'.$tmpdir.$filename);
     foreach my $file (@files) {      foreach my $file (@files) {
         print (OUT $env{'form.currentpath'}.$file."\n");          print (OUT $env{'form.currentpath'}.$file."\n");
     }      }
Line 10611  sub save_selected_files { Line 9350  sub save_selected_files {
 sub clear_selected_files {  sub clear_selected_files {
     my ($user) = @_;      my ($user) = @_;
     my $filename = $user."savedfiles";      my $filename = $user."savedfiles";
     open (OUT,'>',LONCAPA::tempdir().$filename);      open (OUT, '>'.LONCAPA::tempdir().$filename);
     print (OUT undef);      print (OUT undef);
     close (OUT);      close (OUT);
     return ("ok");          return ("ok");    
Line 10621  sub files_in_path { Line 9360  sub files_in_path {
     my ($user, $path) = @_;      my ($user, $path) = @_;
     my $filename = $user."savedfiles";      my $filename = $user."savedfiles";
     my %return_files;      my %return_files;
     open (IN,'<',LONCAPA::tempdir().$filename);      open (IN, '<'.LONCAPA::tempdir().$filename);
     while (my $line_in = <IN>) {      while (my $line_in = <IN>) {
         chomp ($line_in);          chomp ($line_in);
         my @paths_and_file = split (m!/!, $line_in);          my @paths_and_file = split (m!/!, $line_in);
Line 10643  sub files_not_in_path { Line 9382  sub files_not_in_path {
     my $filename = $user."savedfiles";      my $filename = $user."savedfiles";
     my @return_files;      my @return_files;
     my $path_part;      my $path_part;
     open(IN, '<',LONCAPA::tempdir().$filename);      open(IN, '<'.LONCAPA::.$filename);
     while (my $line = <IN>) {      while (my $line = <IN>) {
         #ok, I know it's clunky, but I want it to work          #ok, I know it's clunky, but I want it to work
         my @paths_and_file = split(m|/|, $line);          my @paths_and_file = split(m|/|, $line);
Line 10660  sub files_not_in_path { Line 9399  sub files_not_in_path {
     return (@return_files);      return (@return_files);
 }  }
   
   #------------------------------Submitted/Handedback Portfolio Files Versioning
    
   sub portfiles_versioning {
       my ($symb,$domain,$stu_name,$portfiles,$versioned_portfiles) = @_;
       my $portfolio_root = '/userfiles/portfolio';
       return unless ((ref($portfiles) eq 'ARRAY') && (ref($versioned_portfiles) eq 'ARRAY'));
       foreach my $file (@{$portfiles}) {
           &unmark_as_readonly($domain,$stu_name,[$symb,$env{'request.course.id'}],$file);
           my ($directory,$answer_file) =($file =~ /^(.*?)([^\/]*)$/);
           my ($answer_name,$answer_ver,$answer_ext) = &file_name_version_ext($answer_file);
           my $getpropath = 1;
           my ($dir_list,$listerror) = &dirlist($portfolio_root.$directory,$domain,
                                                $stu_name,$getpropath);
           my $version = &get_next_version($answer_name,$answer_ext,$dir_list);
           my $new_answer = 
               &version_selected_portfile($domain,$stu_name,$directory,$answer_file,$version);
           if ($new_answer ne 'problem getting file') {
               push(@{$versioned_portfiles}, $directory.$new_answer);
               &mark_as_readonly($domain,$stu_name,[$directory.$new_answer],
                                 [$symb,$env{'request.course.id'},'graded']);
           }
       }
   }
   
   sub get_next_version {
       my ($answer_name, $answer_ext, $dir_list) = @_;
       my $version;
       if (ref($dir_list) eq 'ARRAY') {
           foreach my $row (@{$dir_list}) {
               my ($file) = split(/\&/,$row,2);
               my ($file_name,$file_version,$file_ext) =
                   &file_name_version_ext($file);
               if (($file_name eq $answer_name) &&
                   ($file_ext eq $answer_ext)) {
                        # gets here if filename and extension match,
                        # regardless of version
                   if ($file_version ne '') {
                       # a versioned file is found  so save it for later
                       if ($file_version > $version) {
                           $version = $file_version;
                       }
                   }
               }
           }
       }
       $version ++;
       return($version);
   }
   
   sub version_selected_portfile {
       my ($domain,$stu_name,$directory,$file_name,$version) = @_;
       my ($answer_name,$answer_ver,$answer_ext) =
           &file_name_version_ext($file_name);
       my $new_answer;
       $env{'form.copy'} =
           &getfile("/uploaded/$domain/$stu_name/portfolio$directory$file_name");
       if($env{'form.copy'} eq '-1') {
           $new_answer = 'problem getting file';
       } else {
           $new_answer = $answer_name.'.'.$version.'.'.$answer_ext;
           my $copy_result = 
               &finishuserfileupload($stu_name,$domain,'copy',
                                     '/portfolio'.$directory.$new_answer);
       }
       undef($env{'form.copy'});
       return ($new_answer);
   }
   
   sub file_name_version_ext {
       my ($file)=@_;
       my @file_parts = split(/\./, $file);
       my ($name,$version,$ext);
       if (@file_parts > 1) {
           $ext=pop(@file_parts);
           if (@file_parts > 1 && $file_parts[-1] =~ /^\d+$/) {
               $version=pop(@file_parts);
           }
           $name=join('.',@file_parts);
       } else {
           $name=join('.',@file_parts);
       }
       return($name,$version,$ext);
   }
   
 #----------------------------------------------Get portfolio file permissions  #----------------------------------------------Get portfolio file permissions
   
 sub get_portfile_permissions {  sub get_portfile_permissions {
Line 10804  sub modify_access_controls { Line 9627  sub modify_access_controls {
 }  }
   
 sub make_public_indefinitely {  sub make_public_indefinitely {
     my ($requrl) = @_;      my (@requrl) = @_;
       return &automated_portfile_access('public',\@requrl);
   }
   
   sub automated_portfile_access {
       my ($accesstype,$addsref,$delsref,$info) = @_;
       unless (($accesstype eq 'public') || ($accesstype eq 'ip')) {
           return 'invalid';
       }
       my %urls;
       if (ref($addsref) eq 'ARRAY') {
           foreach my $requrl (@{$addsref}) {
               if (&is_portfolio_url($requrl)) {
                   unless (exists($urls{$requrl})) {
                       $urls{$requrl} = 'add';
                   }
               }
           }
       }
       if (ref($delsref) eq 'ARRAY') {
           foreach my $requrl (@{$delsref}) { 
               if (&is_portfolio_url($requrl)) {
                   unless (exists($urls{$requrl})) {
                       $urls{$requrl} = 'delete'; 
                   }
               }
           }
       }
       unless (keys(%urls)) {
           return 'invalid';
       }
       my $ip;
       if ($accesstype eq 'ip') {
           if (ref($info) eq 'HASH') {
               if ($info->{'ip'} ne '') {
                   $ip = $info->{'ip'};
               }
           }
           if ($ip eq '') {
               return 'invalid';
           }
       }
       my $errors;
     my $now = time;      my $now = time;
     my $action = 'activate';      my %current_perms;
     my $aclnum = 0;      foreach my $requrl (sort(keys(%urls))) {
     if (&is_portfolio_url($requrl)) {          my $action;
           if ($urls{$requrl} eq 'add') {
               $action = 'activate';
           } else {
               $action = 'none';
           }
           my $aclnum = 0;
         my (undef,$udom,$unum,$file_name,$group) =          my (undef,$udom,$unum,$file_name,$group) =
             &parse_portfolio_url($requrl);              &parse_portfolio_url($requrl);
         my $current_perms = &get_portfile_permissions($udom,$unum);          unless (exists($current_perms{$unum.':'.$udom})) {
         my %access_controls = &get_access_controls($current_perms,              $current_perms{$unum.':'.$udom} = &get_portfile_permissions($udom,$unum);
           }
           my %access_controls = &get_access_controls($current_perms{$unum.':'.$udom},
                                                    $group,$file_name);                                                     $group,$file_name);
         foreach my $key (keys(%{$access_controls{$file_name}})) {          foreach my $key (keys(%{$access_controls{$file_name}})) {
             my ($num,$scope,$end,$start) =               my ($num,$scope,$end,$start) = 
                 ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);                  ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
             if ($scope eq 'public') {              if ($scope eq $accesstype) {
                 if ($start <= $now && $end == 0) {                  if (($start <= $now) && ($end == 0)) {
                     $action = 'none';                      if ($accesstype eq 'ip') {
                 } else {                          if (ref($access_controls{$file_name}{$key}) eq 'HASH') {
                               if (ref($access_controls{$file_name}{$key}{'ip'}) eq 'ARRAY') {
                                   if (grep(/^\Q$ip\E$/,@{$access_controls{$file_name}{$key}{'ip'}})) {
                                       if ($urls{$requrl} eq 'add') {
                                           $action = 'none';
                                           last;
                                       } else {
                                           $action = 'delete';
                                           $aclnum = $num;
                                           last;
                                       }
                                   }
                               }
                           }
                       } elsif ($accesstype eq 'public') {
                           if ($urls{$requrl} eq 'add') {
                               $action = 'none';
                               last;
                           } else {
                               $action = 'delete';
                               $aclnum = $num;
                               last;
                           }
                       }
                   } elsif ($accesstype eq 'public') {
                     $action = 'update';                      $action = 'update';
                     $aclnum = $num;                      $aclnum = $num;
                       last;
                 }                  }
                 last;  
             }              }
         }          }
         if ($action eq 'none') {          if ($action eq 'none') {
              return 'ok';              next;
         } else {          } else {
             my %changes;              my %changes;
             my $newend = 0;              my $newend = 0;
             my $newstart = $now;              my $newstart = $now;
             my $newkey = $aclnum.':public_'.$newend.'_'.$newstart;              my $newkey = $aclnum.':'.$accesstype.'_'.$newend.'_'.$newstart;
             $changes{$action}{$newkey} = {              $changes{$action}{$newkey} = {
                 type => 'public',                  type => $accesstype,
                 time => {                  time => {
                     start => $newstart,                      start => $newstart,
                     end   => $newend,                      end   => $newend,
                 },                  },
             };              };
               if ($accesstype eq 'ip') {
                   $changes{$action}{$newkey}{'ip'} = [$ip];
               }
             my ($outcome,$deloutcome,$new_values,$translation) =              my ($outcome,$deloutcome,$new_values,$translation) =
                 &modify_access_controls($file_name,\%changes,$udom,$unum);                  &modify_access_controls($file_name,\%changes,$udom,$unum);
             return $outcome;              unless ($outcome eq 'ok') {
                   $errors .= $outcome.' ';
               }
         }          }
       }
       if ($errors) {
           $errors =~ s/\s$//;
           return $errors;
     } else {      } else {
         return 'invalid';          return 'ok';
     }      }
 }  }
   
Line 11051  sub dirlist { Line 9957  sub dirlist {
             foreach my $user (sort(keys(%allusers))) {              foreach my $user (sort(keys(%allusers))) {
                 push(@alluserslist,$user.'&user');                  push(@alluserslist,$user.'&user');
             }              }
             if (!%listerror) {              return (\@alluserslist);
                 # no errors  
                 return (\@alluserslist);  
             } elsif (scalar(keys(%servers)) == 1) {  
                 # one library server, one error  
                 my ($key) = keys(%listerror);  
                 return (\@alluserslist, $listerror{$key});  
             } elsif ( grep { $_ eq 'con_lost' } values(%listerror) ) {  
                 # con_lost indicates that we might miss data from at least one  
                 # library server  
                 return (\@alluserslist, 'con_lost');  
             } else {  
                 # multiple library servers and no con_lost -> data should be  
                 # complete.  
                 return (\@alluserslist);  
             }  
   
         } else {          } else {
             return ([],'missing username');              return ([],'missing username');
         }          }
Line 11303  sub get_userresdata { Line 10193  sub get_userresdata {
 #  Parameters:  #  Parameters:
 #     $name      - Course/user name.  #     $name      - Course/user name.
 #     $domain    - Name of the domain the user/course is registered on.  #     $domain    - Name of the domain the user/course is registered on.
 #     $type      - Type of thing $name is (must be 'course' or 'user')  #     $type      - Type of thing $name is (must be 'course' or 'user'
 #     @which     - Array of names of resources desired.  #     @which     - Array of names of resources desired.
 #  Returns:  #  Returns:
 #     The value of the first reasource in @which that is found in the  #     The value of the first reasource in @which that is found in the
Line 11322  sub resdata { Line 10212  sub resdata {
     }      }
     if (!ref($result)) { return $result; }          if (!ref($result)) { return $result; }    
     foreach my $item (@which) {      foreach my $item (@which) {
         if (ref($item) eq 'ARRAY') {   if (defined($result->{$item->[0]})) {
     if (defined($result->{$item->[0]})) {      return [$result->{$item->[0]},$item->[1]];
         return [$result->{$item->[0]},$item->[1]];   }
     }  
         }  
     }      }
     return undef;      return undef;
 }  }
   
 sub get_domain_ltitools {  
     my ($cdom) = @_;  
     my %ltitools;  
     my ($result,$cached)=&is_cached_new('ltitools',$cdom);  
     if (defined($cached)) {  
         if (ref($result) eq 'HASH') {  
             %ltitools = %{$result};  
         }  
     } else {  
         my %domconfig = &get_dom('configuration',['ltitools'],$cdom);  
         if (ref($domconfig{'ltitools'}) eq 'HASH') {  
             %ltitools = %{$domconfig{'ltitools'}};  
             my %encdomconfig = &get_dom('encconfig',['ltitools'],$cdom);  
             if (ref($encdomconfig{'ltitools'}) eq 'HASH') {  
                 foreach my $id (keys(%ltitools)) {  
                     if (ref($encdomconfig{'ltitools'}{$id}) eq 'HASH') {  
                         foreach my $item ('key','secret') {  
                             $ltitools{$id}{$item} = $encdomconfig{'ltitools'}{$id}{$item};  
                         }  
                     }  
                 }  
             }  
         }  
         my $cachetime = 24*60*60;  
         &do_cache_new('ltitools',$cdom,\%ltitools,$cachetime);  
     }  
     return %ltitools;  
 }  
   
 sub get_numsuppfiles {  sub get_numsuppfiles {
     my ($cnum,$cdom,$ignorecache)=@_;      my ($cnum,$cdom,$ignorecache)=@_;
     my $hashid=$cnum.':'.$cdom;      my $hashid=$cnum.':'.$cdom;
Line 11372  sub get_numsuppfiles { Line 10231  sub get_numsuppfiles {
         unless ($chome eq 'no_host') {          unless ($chome eq 'no_host') {
             ($suppcount,my $errors) = (0,0);              ($suppcount,my $errors) = (0,0);
             my $suppmap = 'supplemental.sequence';              my $suppmap = 'supplemental.sequence';
             ($suppcount,$errors) =              ($suppcount,$errors) = 
                 &Apache::loncommon::recurse_supplemental($cnum,$cdom,$suppmap,$suppcount,$errors);                  &Apache::loncommon::recurse_supplemental($cnum,$cdom,$suppmap,$suppcount,$errors);
         }          }
         &do_cache_new('suppcount',$hashid,$suppcount,600);          &do_cache_new('suppcount',$hashid,$suppcount,600);
Line 11567  sub EXT { Line 10426  sub EXT {
             $courseid = $cid;              $courseid = $cid;
         }          }
  if (($symbparm && $courseid) &&    if (($symbparm && $courseid) && 
     (($courseid eq $env{'request.course.id'}) || ($courseid eq $cid))) {      (($courseid eq $env{'request.course.id'}) || ($courseid eq $cid)))  {
   
     #print '<br>'.$space.' - '.$qualifier.' - '.$spacequalifierrest;      #print '<br>'.$space.' - '.$qualifier.' - '.$spacequalifierrest;
   
Line 11808  sub add_prefix_and_part { Line 10667  sub add_prefix_and_part {
   
 my %metaentry;  my %metaentry;
 my %importedpartids;  my %importedpartids;
 my %importedrespids;  
 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 '') ||       if (($uri eq '') || 
  (($uri =~ m|^/*adm/|) &&    (($uri =~ m|^/*adm/|) && 
      ($uri !~ m|^adm/includes|) && ($uri !~ m{/(smppg|bulletinboard|ext\.tool)$})) ||       ($uri !~ m|^adm/includes|) && ($uri !~ m{/(smppg|bulletinboard)$})) ||
         ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ m{^/*uploaded/.+\.sequence$})) {          ($uri =~ m|/$|) || ($uri =~ m|/.meta$|) || ($uri =~ m{^/*uploaded/.+\.sequence$})) {
  return undef;   return undef;
     }      }
Line 11836  sub metadata { Line 10694  sub metadata {
     }      }
     {      {
 # Imported parts would go here  # Imported parts would go here
         my @origfiletagids=();          my %importedids=();
           my @origfileimportpartids=();
         my $importedparts=0;          my $importedparts=0;
   
 # Imported responseids would go here  
         my $importedresponses=0;  
 #  #
 # Is this a recursive call for a library?  # Is this a recursive call for a library?
 #  #
Line 11935  sub metadata { Line 10791  sub metadata {
                         my $dir=$filename;                          my $dir=$filename;
                         $dir=~s|[^/]*$||;                          $dir=~s|[^/]*$||;
                         $location=&filelocation($dir,$location);                          $location=&filelocation($dir,$location);
                          
                         my $importid=$token->[2]->{'id'};  
                         my $importmode=$token->[2]->{'importmode'};                          my $importmode=$token->[2]->{'importmode'};
 #  
 # Check metadata for imported file to  
 # see if it contained response items  
 #  
                         my %currmetaentry = %metaentry;  
                         my $libresponseorder = &metadata($location,'responseorder');  
                         my $origfile;  
                         if ($libresponseorder ne '') {  
                             if ($#origfiletagids<0) {  
                                 undef(%importedrespids);  
                                 undef(%importedpartids);  
                             }  
                             @{$importedrespids{$importid}} = split(/\s*,\s*/,$libresponseorder);  
                             if (@{$importedrespids{$importid}} > 0) {  
                                 $importedresponses = 1;  
 # We need to get the original file and the imported file to get the response order correct  
 # Load and inspect original file  
                                 if ($#origfiletagids<0) {  
                                     my $origfilelocation=$perlvar{'lonDocRoot'}.&clutter($uri);  
                                     $origfile=&getfile($origfilelocation);  
                                     @origfiletagids=($origfile=~/<((?:\w+)response|import|part)[^>]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs);  
                                 }  
                             }  
                         }  
 # Do not overwrite contents of %metaentry hash for resource itself with   
 # hash populated for imported library file  
                         %metaentry = %currmetaentry;  
                         undef(%currmetaentry);  
                         if ($importmode eq 'problem') {                          if ($importmode eq 'problem') {
 # Import as problem/response  # Import as problem/response
                            $unikey=&add_prefix_and_part($prefix,$token->[2]->{'part'});                             $unikey=&add_prefix_and_part($prefix,$token->[2]->{'part'});
Line 11974  sub metadata { Line 10801  sub metadata {
                            $importedparts=1;                             $importedparts=1;
 # We need to get the original file and the imported file to get the part order correct  # We need to get the original file and the imported file to get the part order correct
 # Good news: we do not need to worry about nested libraries, since parts cannot be nested  # Good news: we do not need to worry about nested libraries, since parts cannot be nested
 # Load and inspect original file if we didn't do that already  # Load and inspect original file
                            if ($#origfiletagids<0) {                             if ($#origfileimportpartids<0) {
                                undef(%importedrespids);                                undef(%importedpartids);
                                undef(%importedpartids);                                my $origfilelocation=$perlvar{'lonDocRoot'}.&clutter($uri);
                                if ($origfile eq '') {                                my $origfile=&getfile($origfilelocation);
                                    my $origfilelocation=$perlvar{'lonDocRoot'}.&clutter($uri);                                @origfileimportpartids=($origfile=~/<(part|import)[^>]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs);
                                    $origfile=&getfile($origfilelocation);  
                                    @origfiletagids=($origfile=~/<(part|import)[^>]*id\s*=\s*[\"\']([^\"\']+)[\"\'][^>]*>/gs);  
                                }  
                            }                             }
   
 # Load and inspect imported file  # Load and inspect imported file
Line 12096  sub metadata { Line 10920  sub metadata {
     grep { ! $seen{$_} ++ } (split(',',$metaentry{':packages'}));      grep { ! $seen{$_} ++ } (split(',',$metaentry{':packages'}));
  $metaentry{':packages'} = join(',',@uniq_packages);   $metaentry{':packages'} = join(',',@uniq_packages);
   
         if (($importedresponses) || ($importedparts)) {          if ($importedparts) {
             if ($importedparts) {  
 # We had imported parts and need to rebuild partorder  # We had imported parts and need to rebuild partorder
                 $metaentry{':partorder'}='';             $metaentry{':partorder'}='';
                 $metathesekeys{'partorder'}=1;             $metathesekeys{'partorder'}=1;
             }             for (my $index=0;$index<$#origfileimportpartids;$index+=2) {
             if ($importedresponses) {                 if ($origfileimportpartids[$index] eq 'part') {
 # We had imported responses and need to rebuild responseorder  # original part, part of the problem
                 $metaentry{':responseorder'}='';                    $metaentry{':partorder'}.=','.$origfileimportpartids[$index+1];
                 $metathesekeys{'responseorder'}=1;                 } else {
             }  # we have imported parts at this position
             for (my $index=0;$index<$#origfiletagids;$index+=2) {                    $metaentry{':partorder'}.=','.$importedpartids{$origfileimportpartids[$index+1]};
                 my $origid = $origfiletagids[$index+1];                 }
                 if ($origfiletagids[$index] eq 'part') {             }
 # Original part, part of the problem             $metaentry{':partorder'}=~s/^\,//;
                     if ($importedparts) {  
                         $metaentry{':partorder'}.=','.$origid;  
                     }  
                 } elsif ($origfiletagids[$index] eq 'import') {  
                     if ($importedparts) {  
 # We have imported parts at this position  
                         $metaentry{':partorder'}.=','.$importedpartids{$origid};  
                     }  
                     if ($importedresponses) {  
 # We have imported responses at this position  
                         if (ref($importedrespids{$origid}) eq 'ARRAY') {  
                             $metaentry{':responseorder'}.=','.join(',',map { $origid.'_'.$_ } @{$importedrespids{$origid}});  
                         }  
                     }  
                 } else {  
 # Original response item, part of the problem  
                     if ($importedresponses) {  
                         $metaentry{':responseorder'}.=','.$origid;  
                     }  
                 }  
             }  
             if ($importedparts) {  
                 $metaentry{':partorder'}=~s/^\,//;  
             }  
             if ($importedresponses) {  
                 $metaentry{':responseorder'}=~s/^\,//;  
             }  
         }          }
   
  $metaentry{':keys'} = join(',',keys(%metathesekeys));   $metaentry{':keys'} = join(',',keys(%metathesekeys));
Line 12402  sub symbverify { Line 11198  sub symbverify {
   
     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 $noclutter;
         if (($thisurl =~ m{^/adm/wrapper/ext/}) || ($thisurl =~ m{^ext/})) {          if (($thisurl =~ m{^/adm/wrapper/ext/}) || ($thisurl =~ m{^ext/})) {
             $thisurl =~ s/\?.+$//;              $thisurl =~ s/\?.+$//;
             if ($map =~ m{^uploaded/.+\.page$}) {              if ($map =~ m{^uploaded/.+\.page$}) {
                 $thisurl =~ s{^(/adm/wrapper|)/ext/}{http://};                  $thisurl =~ s{^(/adm/wrapper|)/ext/}{http://};
                 $thisurl =~ s{^\Qhttp://https://\E}{https://};                  $thisurl =~ s{^\Qhttp://https://\E}{https://};
                   $noclutter = 1;
             }              }
         }          }
         my $ids;          my $ids;
         if ($map =~ m{^uploaded/.+\.page$}) {          if ($noclutter) {
             $ids=$bighash{'ids_'.&clutter_with_no_wrapper($thisurl)};              $ids=$bighash{'ids_'.$thisurl};
         } else {          } else {
             $ids=$bighash{'ids_'.&clutter($thisurl)};              $ids=$bighash{'ids_'.&clutter($thisurl)};
         }          }
         unless ($ids) {          unless ($ids) {
             my $idkey = 'ids_'.($thisurl =~ m{^/}? '' : '/').$thisurl;              my $idkey = 'ids_'.($thisurl =~ m{^/}? '' : '/').$thisurl;  
             $ids=$bighash{$idkey};              $ids=$bighash{$idkey};
         }          }
         if ($ids) {          if ($ids) {
Line 12432  sub symbverify { Line 11230  sub symbverify {
                    if (ref($encstate)) {                     if (ref($encstate)) {
                        $$encstate = $bighash{'encrypted_'.$id};                         $$encstate = $bighash{'encrypted_'.$id};
                    }                     }
                    if (($env{'request.role.adv'}) ||     if (($env{'request.role.adv'}) ||
                        ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) ||         ($bighash{'encrypted_'.$id} eq $env{'request.enc'}) ||
                        ($thisurl eq '/adm/navmaps')) {                         ($thisurl eq '/adm/navmaps')) {
                        $okay=1;         $okay=1;
                        last;                         last;
                    }     }
                }         }
            }     }
         }          }
  untie(%bighash);   untie(%bighash);
     }      }
Line 12523  sub symbread { Line 11321  sub symbread {
 # 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); }      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
Line 12582  sub symbread { Line 11380  sub symbread {
      $syval=&encode_symb($bighash{'map_id_'.$mapid},       $syval=&encode_symb($bighash{'map_id_'.$mapid},
     $resid,$thisfn);      $resid,$thisfn);
                      if (ref($possibles) eq 'HASH') {                       if (ref($possibles) eq 'HASH') {
                          $possibles->{$syval} = 1;                           $possibles->{$syval} = 1;    
                      }                       }
                      if ($checkforblock) {                       if ($checkforblock) {
                          my @blockers = &has_comm_blocking('bre',$syval,$bighash{'src_'.$ids});                           my @blockers = &has_comm_blocking('bre',$syval,$bighash{'src_'.$ids});
Line 12591  sub symbread { Line 11389  sub symbread {
                              return;                               return;
                          }                           }
                      }                       }
                  } elsif ((!$donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) {                   } elsif ((!$donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) { 
 # ------------------------------------------ There is more than one possibility  # ------------------------------------------ There is more than one possibility
                      my $realpossible=0;                       my $realpossible=0;
                      foreach my $id (@possibilities) {                       foreach my $id (@possibilities) {
Line 12599  sub symbread { Line 11397  sub symbread {
                          my $canaccess;                           my $canaccess;
                          if (($donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) {                           if (($donotrecurse) || ($checkforblock) || (ref($possibles) eq 'HASH')) {
                              $canaccess = 1;                               $canaccess = 1;
                          } else {                           } else { 
                              $canaccess = &allowed('bre',$file);                               $canaccess = &allowed('bre',$file);
                          }                           }
                          if ($canaccess) {                           if ($canaccess) {
               my ($mapid,$resid)=split(/\./,$id);                my ($mapid,$resid)=split(/\./,$id);
                              if ($bighash{'map_type_'.$mapid} ne 'page') {                               if ($bighash{'map_type_'.$mapid} ne 'page') {
                                  my $poss_syval=&encode_symb($bighash{'map_id_'.$mapid},                                   my $poss_syval=&encode_symb($bighash{'map_id_'.$mapid},
                                                              $resid,$thisfn);               $resid,$thisfn);
                                  if (ref($possibles) eq 'HASH') {                                   if (ref($possibles) eq 'HASH') {
                                      $possibles->{$syval} = 1;                                       $possibles->{$syval} = 1;
                                  }                                   }
Line 12781  sub rndseed { Line 11579  sub rndseed {
  $which =&get_rand_alg($courseid);   $which =&get_rand_alg($courseid);
     }      }
     if (defined(&getCODE())) {      if (defined(&getCODE())) {
   
  if ($which eq '64bit5') {   if ($which eq '64bit5') {
     return &rndseed_CODE_64bit5($symb,$courseid,$domain,$username);      return &rndseed_CODE_64bit5($symb,$courseid,$domain,$username);
  } elsif ($which eq '64bit4') {   } elsif ($which eq '64bit4') {
Line 12966  sub rndseed_CODE_64bit5 { Line 11765  sub rndseed_CODE_64bit5 {
 sub setup_random_from_rndseed {  sub setup_random_from_rndseed {
     my ($rndseed)=@_;      my ($rndseed)=@_;
     if ($rndseed =~/([,:])/) {      if ($rndseed =~/([,:])/) {
  my ($num1,$num2) = map { abs($_); } (split(/[,:]/,$rndseed));          my ($num1,$num2) = map { abs($_); } (split(/[,:]/,$rndseed));
         if ((!$num1) || (!$num2) || ($num1 > 2147483562) || ($num2 > 2147483398)) {          if ((!$num1) || (!$num2) || ($num1 > 2147483562) || ($num2 > 2147483398)) {
             &Math::Random::random_set_seed_from_phrase($rndseed);              &Math::Random::random_set_seed_from_phrase($rndseed);
         } else {          } else {
Line 13157  sub repcopy_userfile { Line 11956  sub repcopy_userfile {
     my $request;      my $request;
     $uri=~s/^\///;      $uri=~s/^\///;
     my $homeserver = &homeserver($cnum,$cdom);      my $homeserver = &homeserver($cnum,$cdom);
     my $hostname = &hostname($homeserver);  
     my $protocol = $protocol{$homeserver};      my $protocol = $protocol{$homeserver};
     $protocol = 'http' if ($protocol ne 'https');      $protocol = 'http' if ($protocol ne 'https');
     $request=new HTTP::Request('GET',$protocol.'://'.$hostname.'/raw/'.$uri);      $request=new HTTP::Request('GET',$protocol.'://'.&hostname($homeserver).'/raw/'.$uri);
     my $response=$ua->request($request,$transferfile);      my $response=$ua->request($request,$transferfile);
 # did it work?  # did it work?
     if ($response->is_error()) {      if ($response->is_error()) {
Line 13184  sub tokenwrapper { Line 11982  sub tokenwrapper {
  $file=~s|(\?\.*)*$||;   $file=~s|(\?\.*)*$||;
         &appenv({"userfile.$udom/$uname/$file" => $env{'request.course.id'}});          &appenv({"userfile.$udom/$uname/$file" => $env{'request.course.id'}});
         my $homeserver = &homeserver($uname,$udom);          my $homeserver = &homeserver($uname,$udom);
         my $hostname = &hostname($homeserver);  
         my $protocol = $protocol{$homeserver};          my $protocol = $protocol{$homeserver};
         $protocol = 'http' if ($protocol ne 'https');          $protocol = 'http' if ($protocol ne 'https');
         return $protocol.'://'.$hostname.'/'.$uri.          return $protocol.'://'.&hostname($homeserver).'/'.$uri.
                (($uri=~/\?/)?'&':'?').'token='.$token.                 (($uri=~/\?/)?'&':'?').'token='.$token.
                                '&tokenissued='.$perlvar{'lonHostID'};                                 '&tokenissued='.$perlvar{'lonHostID'};
     } else {      } else {
Line 13203  sub getuploaded { Line 12000  sub getuploaded {
     my ($reqtype,$uri,$cdom,$cnum,$info,$rtncode) = @_;      my ($reqtype,$uri,$cdom,$cnum,$info,$rtncode) = @_;
     $uri=~s/^\///;      $uri=~s/^\///;
     my $homeserver = &homeserver($cnum,$cdom);      my $homeserver = &homeserver($cnum,$cdom);
     my $hostname = &hostname($homeserver);  
     my $protocol = $protocol{$homeserver};      my $protocol = $protocol{$homeserver};
     $protocol = 'http' if ($protocol ne 'https');      $protocol = 'http' if ($protocol ne 'https');
     $uri = $protocol.'://'.$hostname.'/raw/'.$uri;      $uri = $protocol.'://'.&hostname($homeserver).'/raw/'.$uri;
     my $ua=new LWP::UserAgent;      my $ua=new LWP::UserAgent;
     my $request=new HTTP::Request($reqtype,$uri);      my $request=new HTTP::Request($reqtype,$uri);
     my $response=$ua->request($request);      my $response=$ua->request($request);
Line 13226  sub readfile { Line 12022  sub readfile {
     my $file = shift;      my $file = shift;
     if ( (! -e $file ) || ($file eq '') ) { return -1; };      if ( (! -e $file ) || ($file eq '') ) { return -1; };
     my $fh;      my $fh;
     open($fh,"<",$file);      open($fh,"<$file");
     my $a='';      my $a='';
     while (my $line = <$fh>) { $a .= $line; }      while (my $line = <$fh>) { $a .= $line; }
     return $a;      return $a;
Line 13339  sub machine_ids { Line 12135  sub machine_ids {
   
 sub additional_machine_domains {  sub additional_machine_domains {
     my @domains;      my @domains;
     open(my $fh,"<","$perlvar{'lonTabDir'}/expected_domains.tab");      open(my $fh,"<$perlvar{'lonTabDir'}/expected_domains.tab");
     while( my $line = <$fh>) {      while( my $line = <$fh>) {
         $line =~ s/\s//g;          $line =~ s/\s//g;
         push(@domains,$line);          push(@domains,$line);
Line 13360  sub default_login_domain { Line 12156  sub default_login_domain {
     return $domain;      return $domain;
 }  }
   
 sub shared_institution {  
     my ($dom) = @_;  
     my $same_intdom;  
     my $hostintdom = &internet_dom($perlvar{'lonHostID'});  
     if ($hostintdom ne '') {  
         my %iphost = &get_iphost();  
         my $primary_id = &domain($dom,'primary');  
         my $primary_ip = &get_host_ip($primary_id);  
         if (ref($iphost{$primary_ip}) eq 'ARRAY') {  
             foreach my $id (@{$iphost{$primary_ip}}) {  
                 my $intdom = &internet_dom($id);  
                 if ($intdom eq $hostintdom) {  
                     $same_intdom = 1;  
                     last;  
                 }  
             }  
         }  
     }  
     return $same_intdom;  
 }  
   
 sub uses_sts {  
     my ($ignore_cache) = @_;  
     my $lonhost = $perlvar{'lonHostID'};  
     my $hostname = &hostname($lonhost);  
     my $sts_on;  
     if ($protocol{$lonhost} eq 'https') {  
         my $cachetime = 12*3600;  
         if (!$ignore_cache) {  
             ($sts_on,my $cached)=&is_cached_new('stspolicy',$lonhost);  
             if (defined($cached)) {  
                 return $sts_on;  
             }  
         }  
         my $ua=new LWP::UserAgent;  
         my $url = $protocol{$lonhost}.'://'.$hostname.'/index.html';  
         my $request=new HTTP::Request('HEAD',$url);  
         my $response=$ua->request($request);  
         if ($response->is_success) {  
             my $has_sts = $response->header('Strict-Transport-Security');  
             if ($has_sts eq '') {  
                 $sts_on = 0;  
             } else {  
                 if ($has_sts =~ /\Qmax-age=\E(\d+)/) {  
                     my $maxage = $1;  
                     if ($maxage) {  
                         $sts_on = 1;  
                     } else {  
                         $sts_on = 0;  
                     }  
                 } else {  
                     $sts_on = 0;  
                 }  
             }  
             return &do_cache_new('stspolicy',$lonhost,$sts_on,$cachetime);  
         }  
     }  
     return;  
 }  
   
 # ------------------------------------------------------------- Declutters URLs  # ------------------------------------------------------------- Declutters URLs
   
 sub declutter {  sub declutter {
Line 13470  sub clutter { Line 12206  sub clutter {
 # &logthis("Got a blank emb style");  # &logthis("Got a blank emb style");
     }      }
  }   }
     } elsif ($thisfn =~ m{^/adm/$match_domain/$match_courseid/\d+/ext\.tool$}) {  
         $thisfn='/adm/wrapper'.$thisfn;  
     }      }
     return $thisfn;      return $thisfn;
 }  }
Line 13545  sub get_dns { Line 12279  sub get_dns {
     }      }
   
     my %alldns;      my %alldns;
     if (open(my $config,"<","$perlvar{'lonTabDir'}/hosts.tab")) {      open(my $config,"<$perlvar{'lonTabDir'}/hosts.tab");
         foreach my $dns (<$config>) {      foreach my $dns (<$config>) {
     next if ($dns !~ /^\^(\S*)/x);   next if ($dns !~ /^\^(\S*)/x);
             my $line = $1;          my $line = $1;
             my ($host,$protocol) = split(/:/,$line);          my ($host,$protocol) = split(/:/,$line);
             if ($protocol ne 'https') {          if ($protocol ne 'https') {
                 $protocol = 'http';              $protocol = 'http';
             }  
     $alldns{$host} = $protocol;  
         }          }
         close($config);   $alldns{$host} = $protocol;
     }      }
     while (%alldns) {      while (%alldns) {
  my ($dns) = sort { $b cmp $a } keys(%alldns);   my ($dns) = sort { $b cmp $a } keys(%alldns);
Line 13566  sub get_dns { Line 12298  sub get_dns {
         delete($alldns{$dns});          delete($alldns{$dns});
  next if ($response->is_error());   next if ($response->is_error());
  my @content = split("\n",$response->content);   my @content = split("\n",$response->content);
         unless ($nocache) {   unless ($nocache) {
     &do_cache_new('dns',$url,\@content,30*24*60*60);      &do_cache_new('dns',$url,\@content,30*24*60*60);
         }   }
  &$func(\@content,$hashref);   &$func(\@content,$hashref);
  return;   return;
     }      }
       close($config);
     my $which = (split('/',$url))[3];      my $which = (split('/',$url))[3];
     &logthis("unable to contact DNS defaulting to on disk file dns_$which.tab\n");      &logthis("unable to contact DNS defaulting to on disk file dns_$which.tab\n");
     if (open(my $config,"<","$perlvar{'lonTabDir'}/dns_$which.tab")) {      open($config,"<$perlvar{'lonTabDir'}/dns_$which.tab");
         my @content = <$config>;      my @content = <$config>;
         &$func(\@content,$hashref);      &$func(\@content,$hashref);
     }  
     return;      return;
 }  }
   
Line 13605  sub parse_dns_checksums_tab { Line 12337  sub parse_dns_checksums_tab {
     if (ref($lines) eq 'ARRAY') {      if (ref($lines) eq 'ARRAY') {
         chomp(@{$lines});          chomp(@{$lines});
         my $version = shift(@{$lines});          my $version = shift(@{$lines});
         if ($version eq $release) {          if ($version eq $release) {  
             foreach my $line (@{$lines}) {              foreach my $line (@{$lines}) {
                 my ($file,$version,$shasum) = split(/,/,$line);                  my ($file,$version,$shasum) = split(/,/,$line);
                 if ($file =~ m{^/etc/httpd/conf}) {                  if ($file =~ m{^/etc/httpd/conf}) {
Line 13668  sub fetch_dns_checksums { Line 12400  sub fetch_dns_checksums {
  my ($ignore_cache,$nocache) = @_;   my ($ignore_cache,$nocache) = @_;
  &get_dns('/adm/dns/domain',\&parse_domain_tab,$ignore_cache,$nocache);   &get_dns('/adm/dns/domain',\&parse_domain_tab,$ignore_cache,$nocache);
  my $fh;   my $fh;
  if (open($fh,"<",$perlvar{'lonTabDir'}.'/domain.tab')) {   if (open($fh,"<".$perlvar{'lonTabDir'}.'/domain.tab')) {
     my @lines = <$fh>;      my @lines = <$fh>;
     &parse_domain_tab(\@lines);      &parse_domain_tab(\@lines);
  }   }
Line 13720  sub fetch_dns_checksums { Line 12452  sub fetch_dns_checksums {
     my ($id,$domain,$role,$name,$protocol,$intdom)=split(/:/,$configline);      my ($id,$domain,$role,$name,$protocol,$intdom)=split(/:/,$configline);
     $name=~s/\s//g;      $name=~s/\s//g;
     if ($id && $domain && $role && $name) {      if ($id && $domain && $role && $name) {
                 if ((exists($hostname{$id})) && ($hostname{$id} ne '')) {  
                     my $curr = $hostname{$id};  
                     my $skip;  
                     if (ref($name_to_host{$curr}) eq 'ARRAY') {  
                         if (($curr eq $name) && (@{$name_to_host{$curr}} == 1)) {  
                             $skip = 1;  
                         } else {  
                             @{$name_to_host{$curr}} = grep { $_ ne $id } @{$name_to_host{$curr}};  
                         }  
                     }  
                     unless ($skip) {  
                         push(@{$name_to_host{$name}},$id);  
                     }  
                 } else {  
                     push(@{$name_to_host{$name}},$id);  
                 }  
  $hostname{$id}=$name;   $hostname{$id}=$name;
    push(@{$name_to_host{$name}}, $id);
  $hostdom{$id}=$domain;   $hostdom{$id}=$domain;
  if ($role eq 'library') { $libserv{$id}=$name; }   if ($role eq 'library') { $libserv{$id}=$name; }
                 if (defined($protocol)) {                  if (defined($protocol)) {
Line 13769  sub fetch_dns_checksums { Line 12486  sub fetch_dns_checksums {
     sub load_hosts_tab {      sub load_hosts_tab {
  my ($ignore_cache,$nocache) = @_;   my ($ignore_cache,$nocache) = @_;
  &get_dns('/adm/dns/hosts',\&parse_hosts_tab,$ignore_cache,$nocache);   &get_dns('/adm/dns/hosts',\&parse_hosts_tab,$ignore_cache,$nocache);
  open(my $config,"<","$perlvar{'lonTabDir'}/hosts.tab");   open(my $config,"<$perlvar{'lonTabDir'}/hosts.tab");
  my @config = <$config>;   my @config = <$config>;
  &parse_hosts_tab(\@config);   &parse_hosts_tab(\@config);
  close($config);   close($config);
Line 14031  sub all_loncaparevs { Line 12748  sub all_loncaparevs {
     return qw(1.1 1.2 1.3 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11);      return qw(1.1 1.2 1.3 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11);
 }  }
   
 # ------------------------------------------------------- Read loncaparev table  # ---------------------------------------------------------- Read loncaparev table
 {  {
     sub load_loncaparevs {      sub load_loncaparevs { 
         if (-e "$perlvar{'lonTabDir'}/loncaparevs.tab") {          if (-e "$perlvar{'lonTabDir'}/loncaparevs.tab") {
             if (open(my $config,"<","$perlvar{'lonTabDir'}/loncaparevs.tab")) {              if (open(my $config,"<$perlvar{'lonTabDir'}/loncaparevs.tab")) {
                 while (my $configline=<$config>) {                  while (my $configline=<$config>) {
                     chomp($configline);                      chomp($configline);
                     my ($hostid,$loncaparev)=split(/:/,$configline);                      my ($hostid,$loncaparev)=split(/:/,$configline);
Line 14047  sub all_loncaparevs { Line 12764  sub all_loncaparevs {
     }      }
 }  }
   
 # ----------------------------------------------------- Read serverhostID table  # ---------------------------------------------------------- Read serverhostID table
 {  {
     sub load_serverhomeIDs {      sub load_serverhomeIDs {
         if (-e "$perlvar{'lonTabDir'}/serverhomeIDs.tab") {          if (-e "$perlvar{'lonTabDir'}/serverhomeIDs.tab") {
             if (open(my $config,"<","$perlvar{'lonTabDir'}/serverhomeIDs.tab")) {              if (open(my $config,"<$perlvar{'lonTabDir'}/serverhomeIDs.tab")) {
                 while (my $configline=<$config>) {                  while (my $configline=<$config>) {
                     chomp($configline);                      chomp($configline);
                     my ($name,$id)=split(/:/,$configline);                      my ($name,$id)=split(/:/,$configline);
Line 14076  BEGIN { Line 12793  BEGIN {
   
 # ------------------------------------------------------ Read spare server file  # ------------------------------------------------------ Read spare server file
 {  {
     open(my $config,"<","$perlvar{'lonTabDir'}/spare.tab");      open(my $config,"<$perlvar{'lonTabDir'}/spare.tab");
   
     while (my $configline=<$config>) {      while (my $configline=<$config>) {
        chomp($configline);         chomp($configline);
Line 14090  BEGIN { Line 12807  BEGIN {
 }  }
 # ------------------------------------------------------------ Read permissions  # ------------------------------------------------------------ Read permissions
 {  {
     open(my $config,"<","$perlvar{'lonTabDir'}/roles.tab");      open(my $config,"<$perlvar{'lonTabDir'}/roles.tab");
   
     while (my $configline=<$config>) {      while (my $configline=<$config>) {
  chomp($configline);   chomp($configline);
Line 14104  BEGIN { Line 12821  BEGIN {
   
 # -------------------------------------------- Read plain texts for permissions  # -------------------------------------------- Read plain texts for permissions
 {  {
     open(my $config,"<","$perlvar{'lonTabDir'}/rolesplain.tab");      open(my $config,"<$perlvar{'lonTabDir'}/rolesplain.tab");
   
     while (my $configline=<$config>) {      while (my $configline=<$config>) {
  chomp($configline);   chomp($configline);
Line 14124  BEGIN { Line 12841  BEGIN {
   
 # ---------------------------------------------------------- Read package table  # ---------------------------------------------------------- Read package table
 {  {
     open(my $config,"<","$perlvar{'lonTabDir'}/packages.tab");      open(my $config,"<$perlvar{'lonTabDir'}/packages.tab");
   
     while (my $configline=<$config>) {      while (my $configline=<$config>) {
  if ($configline !~ /\S/ || $configline=~/^#/) { next; }   if ($configline !~ /\S/ || $configline=~/^#/) { next; }
Line 14139  BEGIN { Line 12856  BEGIN {
     close($config);      close($config);
 }  }
   
 # --------------------------------------------------------- Read loncaparev table  # ---------------------------------------------------------- Read loncaparev table
   
 &load_loncaparevs();  &load_loncaparevs();
   
 # ------------------------------------------------------- Read serverhostID table  # ---------------------------------------------------------- Read serverhostID table
   
 &load_serverhomeIDs();  &load_serverhomeIDs();
   
Line 14157  BEGIN { Line 12874  BEGIN {
                 my $item = $token->[1];                  my $item = $token->[1];
                 my $name = $token->[2]{'name'};                  my $name = $token->[2]{'name'};
                 my $value = $token->[2]{'value'};                  my $value = $token->[2]{'value'};
                 if ($item ne '' && $name ne '' && $value ne '') {                  my $valuematch = $token->[2]{'valuematch'};
                   if ($item ne '' && $name ne '' && ($value ne '' || $valuematch ne '')) {
                     my $release = $parser->get_text();                      my $release = $parser->get_text();
                     $release =~ s/(^\s*|\s*$ )//gx;                      $release =~ s/(^\s*|\s*$ )//gx;
                     $needsrelease{$item.':'.$name.':'.$value} = $release;                      $needsrelease{$item.':'.$name.':'.$value.':'.$valuematch} = $release;
                 }                  }
             }              }
         }          }
Line 14170  BEGIN { Line 12888  BEGIN {
 # ---------------------------------------------------------- Read managers table  # ---------------------------------------------------------- Read managers table
 {  {
     if (-e "$perlvar{'lonTabDir'}/managers.tab") {      if (-e "$perlvar{'lonTabDir'}/managers.tab") {
         if (open(my $config,"<","$perlvar{'lonTabDir'}/managers.tab")) {          if (open(my $config,"<$perlvar{'lonTabDir'}/managers.tab")) {
             while (my $configline=<$config>) {              while (my $configline=<$config>) {
                 chomp($configline);                  chomp($configline);
                 next if ($configline =~ /^\#/);                  next if ($configline =~ /^\#/);
Line 14189  BEGIN { Line 12907  BEGIN {
   
 }  }
   
 # ------------- set default texengine (domain default overrides this)  
 {  
     $deftex = LONCAPA::texengine();  
 }  
   
 # ------------- set default minimum length for passwords for internal auth users  
 {  
     $passwdmin = LONCAPA::passwd_min();  
 }  
   
 $memcache=new Cache::Memcached({'servers'           => ['127.0.0.1:11211'],  $memcache=new Cache::Memcached({'servers'           => ['127.0.0.1:11211'],
  'compress_threshold'=> 20_000,   'compress_threshold'=> 20_000,
          });           });
Line 14500  The first argument is required, all othe Line 13208  The first argument is required, all othe
   
 $priv is the privilege being checked.  $priv is the privilege being checked.
 $uri contains additional information about what is being checked for access (e.g.,  $uri contains additional information about what is being checked for access (e.g.,
 URL, course ID etc.).  URL, course ID etc.). 
 $symb is the unique resource instance identifier in a course; if needed,  $symb is the unique resource instance identifier in a course; if needed,
 but not provided, it will be retrieved via a call to &symbread().  but not provided, it will be retrieved via a call to &symbread(). 
 $role is the role for which a priv is being checked (only used if priv is evb).  $role is the role for which a priv is being checked (only used if priv is evb). 
 $clientip is the user's IP address (only used when checking for access to portfolio  $clientip is the user's IP address (only used when checking for access to portfolio 
 files).  files).
 $noblockcheck, if true, skips calls to &has_comm_blocking() for the bre priv. This  $noblockcheck, if true, skips calls to &has_comm_blocking() for the bre priv. This 
 prevents recursive calls to &allowed.  prevents recursive calls to &allowed.
   
  F: full access   F: full access
Line 14534  in which case the null string is returne Line 13242  in which case the null string is returne
   
 =item *  =item *
   
 definerole($rolename,$sysrole,$domrole,$courole,$uname,$udom) : define role;  definerole($rolename,$sysrole,$domrole,$courole) : define role; define a custom
 define a custom role rolename set privileges in format of lonTabs/roles.tab  role rolename set privileges in format of lonTabs/roles.tab for system, domain,
 for system, domain, and course level. $uname and $udom are optional (current  and course level
 user's username and domain will be used when either of $uname or $udom are absent.  
   
 =item *  =item *
   
Line 14568  provided for types, will default to retu Line 13275  provided for types, will default to retu
 =item *  =item *
   
 in_course($udom,$uname,$cdom,$cnum,$type,$hideprivileged) : determine if  in_course($udom,$uname,$cdom,$cnum,$type,$hideprivileged) : determine if
 user: $uname:$udom has a role in the course: $cdom_$cnum.  user: $uname:$udom has a role in the course: $cdom_$cnum. 
   
 Additional optional arguments are: $type (if role checking is to be restricted  Additional optional arguments are: $type (if role checking is to be restricted 
 to certain user status types -- previous (expired roles), active (currently  to certain user status types -- previous (expired roles), active (currently
 available roles) or future (roles available in the future), and  available roles) or future (roles available in the future), and
 $hideprivileged -- if true will not report course roles for users who  $hideprivileged -- if true will not report course roles for users who
Line 14741  Inputs: Line 13448  Inputs:
   
 =item $credits, number of credits student will earn from this class  =item $credits, number of credits student will earn from this class
   
 =item $instsec, institutional course section code for student  
   
 =back  =back
   
   
Line 14809  values that are the resource value.  I b Line 13514  values that are the resource value.  I b
 versions are also returned.  versions are also returned.
   
 get_numsuppfiles($cnum,$cdom) : retrieve number of files in a course's  get_numsuppfiles($cnum,$cdom) : retrieve number of files in a course's
 supplemental content area. This routine caches the number of files for  supplemental content area. This routine caches the number of files for 
 10 minutes.  10 minutes.
   
 =back  =back
Line 14846  Returns: Line 13551  Returns:
   
 =back  =back
   
 =head2 Bubblesheet Configuration  
   
 =over 4  
   
 =item *  
   
 get_scantron_config($which)  
   
 $which - the name of the configuration to parse from the file.  
   
 Parses and returns the bubblesheet configuration line selected as a  
 hash of configuration file fields.  
   
   
 Returns:  
     If the named configuration is not in the file, an empty  
     hash is returned.  
   
     a hash with the fields  
       name         - internal name for the this configuration setup  
       description  - text to display to operator that describes this config  
       CODElocation - if 0 or the string 'none'  
                           - no CODE exists for this config  
                      if -1 || the string 'letter'  
                           - a CODE exists for this config and is  
                             a string of letters  
                      Unsupported value (but planned for future support)  
                           if a positive integer  
                                - The CODE exists as the first n items from  
                                  the question section of the form  
                           if the string 'number'  
                                - The CODE exists for this config and is  
                                  a string of numbers  
       CODEstart   - (only matter if a CODE exists) column in the line where  
                      the CODE starts  
       CODElength  - length of the CODE  
       IDstart     - column where the student/employee ID starts  
       IDlength    - length of the student/employee ID info  
       Qstart      - column where the information from the bubbled  
                     'questions' start  
       Qlength     - number of columns comprising a single bubble line from  
                     the sheet. (usually either 1 or 10)  
       Qon         - either a single character representing the character used  
                     to signal a bubble was chosen in the positional setup, or  
                     the string 'letter' if the letter of the chosen bubble is  
                     in the final, or 'number' if a number representing the  
                     chosen bubble is in the file (1->A 0->J)  
       Qoff        - the character used to represent that a bubble was  
                     left blank  
       PaperID     - if the scanning process generates a unique number for each  
                     sheet scanned the column that this ID number starts in  
       PaperIDlength - number of columns that comprise the unique ID number  
                       for the sheet of paper  
       FirstName   - column that the first name starts in  
       FirstNameLength - number of columns that the first name spans  
       LastName    - column that the last name starts in  
       LastNameLength - number of columns that the last name spans  
       BubblesPerRow - number of bubbles available in each row used to  
                       bubble an answer. (If not specified, 10 assumed).  
   
   
 =item *  
   
 get_scantronformat_file($cdom)  
   
 $cdom - the course's domain (optional); if not supplied, uses  
 domain for current $env{'request.course.id'}.  
   
 Returns an array containing lines from the scantron format file for  
 the domain of the course.  
   
 If a url for a custom.tab file is listed in domain's configuration.db,  
 lines are from this file.  
   
 Otherwise, if a default.tab has been published in RES space by the  
 domainconfig user, lines are from this file.  
   
 Otherwise, fall back to getting lines from the legacy file on the  
 local server:  /home/httpd/lonTabs/default_scantronformat.tab  
   
 =back  
   
 =head2 Resource Subroutines  =head2 Resource Subroutines
   
 =over 4  =over 4
Line 14994  will be stored for query Line 13617  will be stored for query
   
 =item *  =item *
   
 symbread($filename,$donotrecurse,$ignorecachednull,$checkforblock,$possibles) :  symbread($filename,$donotrecurse,$ignorecachednull,$checkforblock,$possibles) : 
 return symbolic list entry (all arguments optional).  return symbolic list entry (all arguments optional). 
   
 Args: filename is the filename (including path) for the file for which a symb  Args: filename is the filename (including path) for the file for which a symb 
 is required; donotrecurse, if true will prevent calls to allowed() being made  is required; donotrecurse, if true will prevent calls to allowed() being made 
 to check access status if more than one resource was found in the bighash  to check access status if more than one resource was found in the bighash 
 (see rev. 1.249) to avoid an infinite loop if an ambiguous resource is part of  (see rev. 1.249) to avoid an infinite loop if an ambiguous resource is part of 
 a randompick); ignorecachednull, if true will prevent a symb of '' being  a randompick); ignorecachednull, if true will prevent a symb of '' being 
 returned if $env{$cache_str} is defined as ''; checkforblock if true will  returned if $env{$cache_str} is defined as ''; checkforblock if true will
 cause possible symbs to be checked to determine if they are subject to content  cause possible symbs to be checked to determine if they are subject to content
 blocking, if so they will not be included as possible symbs; possibles is a  blocking, if so they will not be included as possible symbs; possibles is a
 ref to a hash, which, as a side effect, will be populated with all possible  ref to a hash, which, as a side effect, will be populated with all possible 
 symbs (content blocking not tested).  symbs (content blocking not tested).
    
 returns the data handle  returns the data handle
   
 =item *  =item *
Line 15017  and is a possible symb for the URL in $t Line 13640  and is a possible symb for the URL in $t
 resource that the user accessed using /enc/ returns a 1 on success, 0  resource that the user accessed using /enc/ returns a 1 on success, 0
 on failure, user must be in a course, as it assumes the existence of  on failure, user must be in a course, as it assumes the existence of
 the course initial hash, and uses $env('request.course.id'}.  The third  the course initial hash, and uses $env('request.course.id'}.  The third
 arg is an optional reference to a scalar.  If this arg is passed in the  arg is an optional reference to a scalar.  If this arg is passed in the 
 call to symbverify, it will be set to 1 if the symb has been set to be   call to symbverify, it will be set to 1 if the symb has been set to be 
 encrypted; otherwise it will be null.  encrypted; otherwise it will be null.  
   
 =item *  =item *
   
Line 15072  expirespread($uname,$udom,$stype,$usymb) Line 13695  expirespread($uname,$udom,$stype,$usymb)
 devalidate($symb) : devalidate temporary spreadsheet calculations,  devalidate($symb) : devalidate temporary spreadsheet calculations,
 forcing spreadsheet to reevaluate the resource scores next time.  forcing spreadsheet to reevaluate the resource scores next time.
   
 =item *  =item * 
   
 can_edit_resource($file,$cnum,$cdom,$resurl,$symb,$group) : determine if current user can edit a particular resource,  can_edit_resource($file,$cnum,$cdom,$resurl,$symb,$group) : determine if current user can edit a particular resource,
 when viewing in course context.  when viewing in course context.
   
  input: six args -- filename (decluttered), course number, course domain,   input: six args -- filename (decluttered), course number, course domain,
                     url, symb (if registered) and group (if this is a                      url, symb (if registered) and group (if this is a 
                     group item -- e.g., bulletin board, group page etc.).                      group item -- e.g., bulletin board, group page etc.).
   
  output: array of five scalars --   output: array of five scalars --
Line 15086  when viewing in course context. Line 13709  when viewing in course context.
          $home -- homeserver of resource (i.e., for author if published,           $home -- homeserver of resource (i.e., for author if published,
                                           or course if uploaded.).                                            or course if uploaded.).
          $switchserver --  1 if server switch will be needed.           $switchserver --  1 if server switch will be needed.
          $forceedit -- 1 if icon/link should be to go to edit mode           $forceedit -- 1 if icon/link should be to go to edit mode 
          $forceview -- 1 if icon/link should be to go to view mode           $forceview -- 1 if icon/link should be to go to view mode
   
 =item *  =item *
   
 is_course_upload($file,$cnum,$cdom)  is_course_upload($file,$cnum,$cdom)
   
 Used in course context to determine if current file was uploaded to  Used in course context to determine if current file was uploaded to 
 the course (i.e., would be found in /userfiles/docs on the course's  the course (i.e., would be found in /userfiles/docs on the course's 
 homeserver.  homeserver.
   
   input: 3 args -- filename (decluttered), course number and course domain.    input: 3 args -- filename (decluttered), course number and course domain.
Line 15108  homeserver. Line 13731  homeserver.
   
 =item *  =item *
   
 store($storehash,$symb,$namespace,$udom,$uname,$laststore) : stores hash   store($storehash,$symb,$namespace,$udom,$uname,$laststore) : stores hash
 permanently for this url; hashref needs to be given and should be a \%hashname;  permanently 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  the remaining args aren't required and if they aren't passed or are '' they will
 be derived from the env (with the exception of $laststore, which is an  be derived from the env (with the exception of $laststore, which is an 
 optional arg used when a user's submission is stored in grading).  optional arg used when a user's submission is stored in grading).
 $laststore is $version=$timestamp, where $version is the most recent version  $laststore is $version=$timestamp, where $version is the most recent version
 number retrieved for the corresponding $symb in the $namespace db file, and  number retrieved for the corresponding $symb in the $namespace db file, and
 $timestamp is the timestamp for that transaction (UNIX time).  $timestamp is the timestamp for that transaction (UNIX time).
 $laststore is currently only passed when cstore() is called by  $laststore is currently only passed when cstore() is called by 
 structuretags::finalize_storage().  structuretags::finalize_storage().
   
 =item *  =item *
   
 cstore($storehash,$symb,$namespace,$udom,$uname,$laststore) : same as store   cstore($storehash,$symb,$namespace,$udom,$uname,$laststore) : same as store
 but uses critical subroutine  but uses critical subroutine
   
 =item *  =item *
Line 15259  server ($udom and $uhome are optional) Line 13882  server ($udom and $uhome are optional)
   
 =item *   =item * 
   
 get_domain_defaults($target_domain,$ignore_cache) : returns hash with defaults  get_domain_defaults($target_domain,$ignore_cache) : returns hash with defaults 
 for: authentication, language, quotas, timezone, date locale, and portal URL in  for: authentication, language, quotas, timezone, date locale, and portal URL in
 the target domain.  the target domain.
   
Line 15314  for course's uploaded content. Line 13937  for course's uploaded content.
 =over  =over
   
 =item  =item
 canuse_pdfforms, officialcredits, unofficialcredits, textbookcredits, officialquota, unofficialquota,  canuse_pdfforms, officialcredits, unofficialcredits, textbookcredits, officialquota, unofficialquota, 
 communityquota, textbookquota  communityquota, textbookquota
   
 =back  =back
Line 15325  on your servers. Line 13948  on your servers.
   
 =over  =over
   
 =item  =item 
 remotesessions, hostedsessions  remotesessions, hostedsessions
   
 =back  =back
Line 15333  remotesessions, hostedsessions Line 13956  remotesessions, hostedsessions
 =back  =back
   
 In cases where a domain coordinator has never used the "Set Domain Configuration"  In cases where a domain coordinator has never used the "Set Domain Configuration"
 utility to create a configuration.db file on a domain's primary library server  utility to create a configuration.db file on a domain's primary library server 
 only the following domain defaults: auth_def, auth_arg_def, lang_def  only the following domain defaults: auth_def, auth_arg_def, lang_def
 -- corresponding values are authentication type (internal, krb4, krb5,  -- corresponding values are authentication type (internal, krb4, krb5,
 or localauth), initial password or a kerberos realm, language (e.g., en-us) --  or localauth), initial password or a kerberos realm, language (e.g., en-us) -- 
 will be available. Values are retrieved from cache (if current), unless the  will be available. Values are retrieved from cache (if current), unless the
 optional $ignore_cache arg is true, or from domain's configuration.db (if available),  optional $ignore_cache arg is true, or from domain's configuration.db (if available),
 or lastly from values in lonTabs/dns_domain,tab, or lonTabs/domain.tab.  or lastly from values in lonTabs/dns_domain,tab, or lonTabs/domain.tab.
Line 15619  userspace, probably shouldn't be called Line 14242  userspace, probably shouldn't be called
   formname: same as for userfileupload()    formname: same as for userfileupload()
   fname: filename (including subdirectories) for the file    fname: filename (including subdirectories) for the file
   parser: if 'parse', will parse (html) file to extract references to objects, links etc.    parser: if 'parse', will parse (html) file to extract references to objects, links etc.
           if hashref, and context is scantron, will convert csv format to standard format  
   allfiles: reference to hash used to store objects found by parser    allfiles: reference to hash used to store objects found by parser
   codebase: reference to hash used for codebases of java objects found by parser    codebase: reference to hash used for codebases of java objects found by parser
   thumbwidth: width (pixels) of thumbnail to be created for uploaded image    thumbwidth: width (pixels) of thumbnail to be created for uploaded image
Line 15765  Returns: Line 14387  Returns:
   
 get_timebased_id():  get_timebased_id():
   
 Attempts to get a unique timestamp-based suffix for use with items added to a  Attempts to get a unique timestamp-based suffix for use with items added to a 
 course via the Course Editor (e.g., folders, composite pages,  course via the Course Editor (e.g., folders, composite pages, 
 group bulletin boards).  group bulletin boards).
   
 Args: (first three required; six others optional)  Args: (first three required; six others optional)
Line 15777  Args: (first three required; six others Line 14399  Args: (first three required; six others
 2. keyid (alphanumeric): name of temporary locking key in hash,  2. keyid (alphanumeric): name of temporary locking key in hash,
    e.g., num, boardids     e.g., num, boardids
   
 3. namespace: name of gdbm file used to store suffixes already assigned;  3. namespace: name of gdbm file used to store suffixes already assigned;  
    file will be named nohist_namespace.db     file will be named nohist_namespace.db
   
 4. cdom: domain of course; default is current course domain from %env  4. cdom: domain of course; default is current course domain from %env
   
 5. cnum: course number; default is current course number from %env  5. cnum: course number; default is current course number from %env
   
 6. idtype: set to concat if an additional digit is to be appended to the  6. idtype: set to concat if an additional digit is to be appended to the 
    unix timestamp to form the suffix, if the plain timestamp is already     unix timestamp to form the suffix, if the plain timestamp is already
    in use.  Default is to not do this, but simply increment the unix     in use.  Default is to not do this, but simply increment the unix 
    timestamp by 1 until a unique key is obtained.     timestamp by 1 until a unique key is obtained.
   
 7. who: holder of locking key; defaults to user:domain for user.  7. who: holder of locking key; defaults to user:domain for user.
   
 8. locktries: number of attempts to obtain a lock (sleep of 1s before  8. locktries: number of attempts to obtain a lock (sleep of 1s before 
    retrying); default is 3.     retrying); default is 3.
   
 9. maxtries: number of attempts to obtain a unique suffix; default is 20.  9. maxtries: number of attempts to obtain a unique suffix; default is 20.  
   
 Returns:  Returns:
   

Removed from v.1.1172.2.118.2.7  
changed lines
  Added in v.1.1296


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