Diff for /loncom/lond between versions 1.448 and 1.476

version 1.448, 2010/07/20 02:42:27 version 1.476, 2011/07/28 15:12:03
Line 15 Line 15
 #  #
 # LON-CAPA is distributed in the hope that it will be useful,  # LON-CAPA is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of  # but WITHOUT ANY WARRANTY; without even the implied warranty of
   
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.  # GNU General Public License for more details.
 #  #
Line 52  use LONCAPA::lonlocal; Line 53  use LONCAPA::lonlocal;
 use LONCAPA::lonssl;  use LONCAPA::lonssl;
 use Fcntl qw(:flock);  use Fcntl qw(:flock);
 use Apache::lonnet;  use Apache::lonnet;
   use Mail::Send;
   
 my $DEBUG = 0;       # Non zero to enable debug log entries.  my $DEBUG = 0;       # Non zero to enable debug log entries.
   
Line 419  sub ReadManagerTable { Line 421  sub ReadManagerTable {
   
    my $tablename = $perlvar{'lonTabDir'}."/managers.tab";     my $tablename = $perlvar{'lonTabDir'}."/managers.tab";
    if (!open (MANAGERS, $tablename)) {     if (!open (MANAGERS, $tablename)) {
       logthis('<font color="red">No manager table.  Nobody can manage!!</font>');         my $hostname = &Apache::lonnet::hostname($perlvar{'lonHostID'});
       return;         if (&Apache::lonnet::is_LC_dns($hostname)) {
              &logthis('<font color="red">No manager table.  Nobody can manage!!</font>');
          }
          return;
    }     }
    while(my $host = <MANAGERS>) {     while(my $host = <MANAGERS>) {
       chomp($host);        chomp($host);
Line 445  sub ReadManagerTable { Line 450  sub ReadManagerTable {
          }           }
       } else {        } else {
          logthis('<font color="green"> existing host'." $host</font>\n");           logthis('<font color="green"> existing host'." $host</font>\n");
          $managers{&Apache::lonnet::get_host_ip($host)} = $host;  # Use info from cluster tab if clumemeber           $managers{&Apache::lonnet::get_host_ip($host)} = $host;  # Use info from cluster tab if cluster memeber
       }        }
    }     }
 }  }
Line 507  sub AdjustHostContents { Line 512  sub AdjustHostContents {
     my $me        = $perlvar{'lonHostID'};      my $me        = $perlvar{'lonHostID'};
   
     foreach my $line (split(/\n/,$contents)) {      foreach my $line (split(/\n/,$contents)) {
  if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/))) {   if(!(($line eq "") || ($line =~ /^ *\#/) || ($line =~ /^ *$/) ||
                ($line =~ /^\s*\^/))) {
     chomp($line);      chomp($line);
     my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon)=split(/:/,$line);      my ($id,$domain,$role,$name,$ip,$maxcon,$idleto,$mincon)=split(/:/,$line);
     if ($id eq $me) {      if ($id eq $me) {
Line 595  sub InstallFile { Line 601  sub InstallFile {
 #  #
 #   ConfigFileFromSelector: converts a configuration file selector  #   ConfigFileFromSelector: converts a configuration file selector
 #                 into a configuration file pathname.  #                 into a configuration file pathname.
 #                 It's probably no longer necessary to preserve  #                 Supports the following file selectors: 
 #                 special handling of hosts or domain as those  #                 hosts, domain, dns_hosts, dns_domain  
 #                 files have been superceded by dns_hosts, dns_domain.  
 #                 The default action is just to prepend the directory  
 #                 and append .tab  
 #  #
 #  #
 #  Parameters:  #  Parameters:
Line 612  sub ConfigFileFromSelector { Line 615  sub ConfigFileFromSelector {
     my $tablefile;      my $tablefile;
   
     my $tabledir = $perlvar{'lonTabDir'}.'/';      my $tabledir = $perlvar{'lonTabDir'}.'/';
     if ($selector eq "hosts") {      if (($selector eq "hosts") || ($selector eq "domain") || 
  $tablefile = $tabledir."hosts.tab";          ($selector eq "dns_hosts") || ($selector eq "dns_domain")) {
     } elsif ($selector eq "domain") {  
  $tablefile = $tabledir."domain.tab";  
     } else {  
  $tablefile =  $tabledir.$selector.'.tab';   $tablefile =  $tabledir.$selector.'.tab';
     }      }
     return $tablefile;      return $tablefile;
   
 }  }
 #  #
 #   PushFile:  Called to do an administrative push of a file.  #   PushFile:  Called to do an administrative push of a file.
Line 646  sub PushFile { Line 645  sub PushFile {
     #  supported:      #  supported:
     #   hosts.tab  ($filename eq host).      #   hosts.tab  ($filename eq host).
     #   domain.tab ($filename eq domain).      #   domain.tab ($filename eq domain).
       #   dns_hosts.tab ($filename eq dns_host).
       #   dns_domain.tab ($filename eq dns_domain). 
     # Construct the destination filename or reject the request.      # Construct the destination filename or reject the request.
     #      #
     # lonManage is supposed to ensure this, however this session could be      # lonManage is supposed to ensure this, however this session could be
Line 677  sub PushFile { Line 678  sub PushFile {
  return "error:$!";   return "error:$!";
     } else {      } else {
  &logthis('<font color="green"> Installed new '.$tablefile   &logthis('<font color="green"> Installed new '.$tablefile
  ."</font>");   ." - transaction by: $clientname ($clientip)</font>");
           my $adminmail = $perlvar{'lonAdmEMail'};
           my $admindom = &Apache::lonnet::host_domain($perlvar{'lonHostID'});
           if ($admindom ne '') {
               my %domconfig =
                   &Apache::lonnet::get_dom('configuration',['contacts'],$admindom);
               if (ref($domconfig{'contacts'}) eq 'HASH') {
                   if ($domconfig{'contacts'}{'adminemail'} ne '') {
                       $adminmail = $domconfig{'contacts'}{'adminemail'};
                   }
               }
           }
           if ($adminmail =~ /^[^\@]+\@[^\@]+$/) {
               my $msg = new Mail::Send;
               $msg->to($adminmail);
               $msg->subject('LON-CAPA DNS update on '.$perlvar{'lonHostID'});
               $msg->add('Content-type','text/plain; charset=UTF-8');
               if (my $fh = $msg->open()) {
                   print $fh 'Update to '.$tablefile.' from Cluster Manager '.
                             "$clientname ($clientip)\n";
                   $fh->close;
               }
           }
     }      }
   
   
     #  Indicate success:      #  Indicate success:
     
     return "ok";      return "ok";
Line 1121  sub establish_key_handler { Line 1142  sub establish_key_handler {
 sub load_handler {  sub load_handler {
     my ($cmd, $tail, $replyfd) = @_;      my ($cmd, $tail, $replyfd) = @_;
   
   
   
    # Get the load average from /proc/loadavg and calculate it as a percentage of     # Get the load average from /proc/loadavg and calculate it as a percentage of
    # the allowed load limit as set by the perl global variable lonLoadLim     # the allowed load limit as set by the perl global variable lonLoadLim
   
Line 1666  sub server_homeID_handler { Line 1689  sub server_homeID_handler {
 }  }
 &register_handler("serverhomeID", \&server_homeID_handler, 0, 1, 0);  &register_handler("serverhomeID", \&server_homeID_handler, 0, 1, 0);
   
   sub server_distarch_handler {
       my ($cmd,$tail,$client) = @_;
       my $userinput = "$cmd:$tail";
       my $reply = &distro_and_arch();
       &Reply($client,\$reply,$userinput);
       return 1;
   }
   &register_handler("serverdistarch", \&server_distarch_handler, 0, 1, 0);
   
 #   Process a reinit request.  Reinit requests that either  #   Process a reinit request.  Reinit requests that either
 #   lonc or lond be reinitialized so that an updated   #   lonc or lond be reinitialized so that an updated 
 #   host.tab or domain.tab can be processed.  #   host.tab or domain.tab can be processed.
Line 1789  sub authenticate_handler { Line 1821  sub authenticate_handler {
         unless ($clientcancheckhost) {          unless ($clientcancheckhost) {
             my $uprimary_id = &Apache::lonnet::domain($udom,'primary');              my $uprimary_id = &Apache::lonnet::domain($udom,'primary');
             my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id);              my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id);
             my @intdoms = &Apache::lonnet::get_internet_names($clientname);                my @intdoms;
               my $internet_names = &Apache::lonnet::get_internet_names($clientname);
               if (ref($internet_names) eq 'ARRAY') {
                   @intdoms = @{$internet_names};
               }
             unless ($uint_dom ne '' && grep(/^\Q$uint_dom\E$/,@intdoms)) {              unless ($uint_dom ne '' && grep(/^\Q$uint_dom\E$/,@intdoms)) {
                 my ($remote,$hosted);                  my ($remote,$hosted);
                 my $remotesession = &get_usersession_config($udom,'remotesession');                  my $remotesession = &get_usersession_config($udom,'remotesession');
Line 1800  sub authenticate_handler { Line 1836  sub authenticate_handler {
                 if (ref($hostedsession) eq 'HASH') {                  if (ref($hostedsession) eq 'HASH') {
                     $hosted = $hostedsession->{'hosted'};                      $hosted = $hostedsession->{'hosted'};
                 }                  }
                   my $loncaparev = $clientversion;
                   if ($loncaparev eq '') {
                       $loncaparev = $Apache::lonnet::loncaparevs{$clientname};
                   }
                 $canhost = &Apache::lonnet::can_host_session($udom,$clientname,                  $canhost = &Apache::lonnet::can_host_session($udom,$clientname,
                                                              $clientversion,                                                               $loncaparev,
                                                              $remote,$hosted);                                                               $remote,$hosted);
             }              }
         }          }
Line 2147  sub update_resource_handler { Line 2187  sub update_resource_handler {
  my $transname="$fname.in.transfer";   my $transname="$fname.in.transfer";
  my $remoteurl=&Apache::lonnet::reply("sub:$fname","$clientname");   my $remoteurl=&Apache::lonnet::reply("sub:$fname","$clientname");
  my $response;   my $response;
  alarm(120);  # FIXME: cannot replicate files that take more than two minutes to transfer?
   # alarm(120);
   # FIXME: this should use the LWP mechanism, not internal alarms.
                   alarm(1200);
  {   {
     my $ua=new LWP::UserAgent;      my $ua=new LWP::UserAgent;
     my $request=new HTTP::Request('GET',"$remoteurl");      my $request=new HTTP::Request('GET',"$remoteurl");
Line 2155  sub update_resource_handler { Line 2198  sub update_resource_handler {
  }   }
  alarm(0);   alarm(0);
  if ($response->is_error()) {   if ($response->is_error()) {
   # FIXME: we should probably clean up here instead of just whine
     unlink($transname);      unlink($transname);
     my $message=$response->status_line;      my $message=$response->status_line;
     &logthis("LWP GET: $message for $fname ($remoteurl)");      &logthis("LWP GET: $message for $fname ($remoteurl)");
  } else {   } else {
     if ($remoteurl!~/\.meta$/) {      if ($remoteurl!~/\.meta$/) {
   # FIXME: isn't there an internal LWP mechanism for this?
  alarm(120);   alarm(120);
  {   {
     my $ua=new LWP::UserAgent;      my $ua=new LWP::UserAgent;
Line 2233  sub fetch_user_file_handler { Line 2278  sub fetch_user_file_handler {
   
  my $destname=$udir.'/'.$ufile;   my $destname=$udir.'/'.$ufile;
  my $transname=$udir.'/'.$ufile.'.in.transit';   my $transname=$udir.'/'.$ufile.'.in.transit';
  my $remoteurl='http://'.$clientip.'/userfiles/'.$fname;          my $clientprotocol=$Apache::lonnet::protocol{$clientname};
           $clientprotocol = 'http' if ($clientprotocol ne 'https');
    my $remoteurl=$clientprotocol.'://'.$clientip.'/userfiles/'.$fname;
  my $response;   my $response;
  Debug("Remote URL : $remoteurl Transfername $transname Destname: $destname");   Debug("Remote URL : $remoteurl Transfername $transname Destname: $destname");
  alarm(120);   alarm(120);
Line 2409  sub user_has_session_handler { Line 2456  sub user_has_session_handler {
   
     my ($udom, $uname) = map { &unescape($_) } (split(/:/, $tail));      my ($udom, $uname) = map { &unescape($_) } (split(/:/, $tail));
           
     &logthis("Looking for $udom $uname");  
     opendir(DIR,$perlvar{'lonIDsDir'});      opendir(DIR,$perlvar{'lonIDsDir'});
     my $filename;      my $filename;
     while ($filename=readdir(DIR)) {      while ($filename=readdir(DIR)) {
Line 3140  sub dump_with_regexp { Line 3186  sub dump_with_regexp {
   
     my $userinput = "$cmd:$tail";      my $userinput = "$cmd:$tail";
   
     my ($udom,$uname,$namespace,$regexp,$range)=split(/:/,$tail);      my ($udom,$uname,$namespace,$regexp,$range,$extra)=split(/:/,$tail);
     if (defined($regexp)) {      if (defined($regexp)) {
  $regexp=&unescape($regexp);   $regexp=&unescape($regexp);
     } else {      } else {
Line 3158  sub dump_with_regexp { Line 3204  sub dump_with_regexp {
     }      }
     my $hashref = &tie_user_hash($udom, $uname, $namespace,      my $hashref = &tie_user_hash($udom, $uname, $namespace,
  &GDBM_READER());   &GDBM_READER());
       my $skipcheck;
     if ($hashref) {      if ($hashref) {
         my $qresult='';          my $qresult='';
  my $count=0;   my $count=0;
           if ($extra ne '') {
               $extra = &Apache::lonnet::thaw_unescape($extra);
               $skipcheck = $extra->{'skipcheck'};
           }
           my @ids = &Apache::lonnet::current_machine_ids();
           my (%homecourses,$major,$minor,$now);
           if (($namespace eq 'roles') && (!$skipcheck)) {
               my $loncaparev = $clientversion;
               if ($loncaparev eq '') {
                   $loncaparev = $Apache::lonnet::loncaparevs{$clientname};
               }
               if ($loncaparev =~ /^\'?(\d+)\.(\d+)\.[\w.\-]+\'?/) {
                   $major = $1;
                   $minor = $2;
               }
               $now = time;
           }
  while (my ($key,$value) = each(%$hashref)) {   while (my ($key,$value) = each(%$hashref)) {
             if ($namespace eq 'roles') {              if ($namespace eq 'roles') {
                 if ($key =~ m{^/($LONCAPA::match_domain)/($LONCAPA::match_community)_(cc|co|in|ta|ep|ad|st|cr)}) {                  if ($key =~ m{^/($LONCAPA::match_domain)/($LONCAPA::match_courseid)(/?[^_]*)_(cc|co|in|ta|ep|ad|st|cr)$}) {
                     my $cdom = $1;                      my $cdom = $1;
                     my $cnum = $2;                      my $cnum = $2;
                     if ($clientversion =~ /^\'?(\d+)\.(\d+)/) {                      unless ($skipcheck) {
                         my $major = $1;                          my ($role,$end,$start) = split(/\_/,$value);
                         my $minor = $2;                          if (!$end || $end > $now) {
                         next if (($major < 2) || (($major == 2) && ($minor < 9)));                              next unless (&releasereqd_check($cnum,$cdom,$key,$value,$major,
                     } else {                                                              $minor,\%homecourses,\@ids));
                         my $homeserver = &Apache::lonnet::homeserver($cnum,$cdom);                          }
                         next unless ($currenthostid eq $homeserver);  
                     }                      }
                 }                  }
             }              }
Line 3192  sub dump_with_regexp { Line 3255  sub dump_with_regexp {
     }      }
  }   }
  if (&untie_user_hash($hashref)) {   if (&untie_user_hash($hashref)) {
               if (($namespace eq 'roles') && (!$skipcheck)) {
                   if (keys(%homecourses) > 0) {
                       $qresult .= &check_homecourses(\%homecourses,$udom,$regexp,$count,
                                                      $range,$start,$end,$major,$minor);
                   }
               }
     chop($qresult);      chop($qresult);
     &Reply($client, \$qresult, $userinput);      &Reply($client, \$qresult, $userinput);
  } else {   } else {
Line 4242  sub put_domain_handler { Line 4311  sub put_domain_handler {
 sub get_domain_handler {  sub get_domain_handler {
     my ($cmd, $tail, $client) = @_;      my ($cmd, $tail, $client) = @_;
   
   
     my $userinput = "$client:$tail";      my $userinput = "$client:$tail";
   
     my ($udom,$namespace,$what)=split(/:/,$tail,3);      my ($udom,$namespace,$what)=split(/:/,$tail,3);
Line 4386  sub get_id_handler { Line 4456  sub get_id_handler {
 sub put_dcmail_handler {  sub put_dcmail_handler {
     my ($cmd,$tail,$client) = @_;      my ($cmd,$tail,$client) = @_;
     my $userinput = "$cmd:$tail";      my $userinput = "$cmd:$tail";
                                                                                   
   
     my ($udom,$what)=split(/:/,$tail);      my ($udom,$what)=split(/:/,$tail);
     chomp($what);      chomp($what);
     my $hashref = &tie_domain_hash($udom, "nohist_dcmail", &GDBM_WRCREAT());      my $hashref = &tie_domain_hash($udom, "nohist_dcmail", &GDBM_WRCREAT());
Line 4650  sub tmp_put_handler { Line 4721  sub tmp_put_handler {
     }      }
     my ($id,$store);      my ($id,$store);
     $tmpsnum++;      $tmpsnum++;
     if ($context eq 'resetpw') {      if (($context eq 'resetpw') || ($context eq 'createaccount')) {
         $id = &md5_hex(&md5_hex(time.{}.rand().$$));          $id = &md5_hex(&md5_hex(time.{}.rand().$$));
     } else {      } else {
         $id = $$.'_'.$clientip.'_'.$tmpsnum;          $id = $$.'_'.$clientip.'_'.$tmpsnum;
Line 4968  sub get_sections_handler { Line 5039  sub get_sections_handler {
 sub validate_course_owner_handler {  sub validate_course_owner_handler {
     my ($cmd, $tail, $client)  = @_;      my ($cmd, $tail, $client)  = @_;
     my $userinput = "$cmd:$tail";      my $userinput = "$cmd:$tail";
     my ($inst_course_id, $owner, $cdom) = split(/:/, $tail);      my ($inst_course_id, $owner, $cdom, $coowners) = split(/:/, $tail);
       
     $owner = &unescape($owner);      $owner = &unescape($owner);
     my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom);      $coowners = &unescape($coowners);
       my $outcome = &localenroll::new_course($inst_course_id,$owner,$cdom,$coowners);
     &Reply($client, \$outcome, $userinput);      &Reply($client, \$outcome, $userinput);
   
   
Line 5959  if (-e $pidfile) { Line 6031  if (-e $pidfile) {
 $server = IO::Socket::INET->new(LocalPort => $perlvar{'londPort'},  $server = IO::Socket::INET->new(LocalPort => $perlvar{'londPort'},
                                 Type      => SOCK_STREAM,                                  Type      => SOCK_STREAM,
                                 Proto     => 'tcp',                                  Proto     => 'tcp',
                                 Reuse     => 1,                                  ReuseAddr     => 1,
                                 Listen    => 10 )                                  Listen    => 10 )
   or die "making socket: $@\n";    or die "making socket: $@\n";
   
Line 6022  sub HUPSMAN {                      # sig Line 6094  sub HUPSMAN {                      # sig
 #  a setuid perl script that can be root for us to do this job.  #  a setuid perl script that can be root for us to do this job.
 #  #
 sub ReloadApache {  sub ReloadApache {
     my $execdir = $perlvar{'lonDaemons'};  # --------------------------- Handle case of another apachereload process (locking)
     my $script  = $execdir."/apachereload";      if (&LONCAPA::try_to_lock('/tmp/lock_apachereload')) {
     system($script);          my $execdir = $perlvar{'lonDaemons'};
           my $script  = $execdir."/apachereload";
           system($script);
           unlink('/tmp/lock_apachereload'); #  Remove the lock file.
       }
 }  }
   
 #  #
Line 6197  sub logstatus { Line 6273  sub logstatus {
 sub initnewstatus {  sub initnewstatus {
     my $docdir=$perlvar{'lonDocRoot'};      my $docdir=$perlvar{'lonDocRoot'};
     my $fh=IO::File->new(">$docdir/lon-status/londstatus.txt");      my $fh=IO::File->new(">$docdir/lon-status/londstatus.txt");
     my $now=time;      my $now=time();
     my $local=localtime($now);      my $local=localtime($now);
     print $fh "LOND status $local - parent $$\n\n";      print $fh "LOND status $local - parent $$\n\n";
     opendir(DIR,"$docdir/lon-status/londchld");      opendir(DIR,"$docdir/lon-status/londchld");
Line 6290  my %iphost = &Apache::lonnet::get_iphost Line 6366  my %iphost = &Apache::lonnet::get_iphost
   
 my $dist=`$perlvar{'lonDaemons'}/distprobe`;  my $dist=`$perlvar{'lonDaemons'}/distprobe`;
   
   my $arch = `uname -i`;
   chomp($arch);
   if ($arch eq 'unknown') {
       $arch = `uname -m`;
       chomp($arch);
   }
   
 # --------------------------------------------------------------  # --------------------------------------------------------------
 #   Accept connections.  When a connection comes in, it is validated  #   Accept connections.  When a connection comes in, it is validated
 #   and if good, a child process is created to process transactions  #   and if good, a child process is created to process transactions
Line 6347  sub make_new_child { Line 6430  sub make_new_child {
             or die "Can't unblock SIGINT for fork: $!\n";              or die "Can't unblock SIGINT for fork: $!\n";
         $children{$pid} = $clientip;          $children{$pid} = $clientip;
         &status('Started child '.$pid);          &status('Started child '.$pid);
    close($client);
         return;          return;
     } else {      } else {
         # Child can *not* return from this subroutine.          # Child can *not* return from this subroutine.
Line 6355  sub make_new_child { Line 6439  sub make_new_child {
                                 #don't get intercepted                                  #don't get intercepted
         $SIG{USR1}= \&logstatus;          $SIG{USR1}= \&logstatus;
         $SIG{ALRM}= \&timeout;          $SIG{ALRM}= \&timeout;
    #
    # Block sigpipe as it gets thrownon socket disconnect and we want to 
    # deal with that as a read faiure instead.
    #
    my $blockset = POSIX::SigSet->new(SIGPIPE);
    sigprocmask(SIG_BLOCK, $blockset);
   
         $lastlog='Forked ';          $lastlog='Forked ';
         $status='Forked';          $status='Forked';
   
Line 7078  sub subscribe { Line 7169  sub subscribe {
                 # the metadata                  # the metadata
  unless ($fname=~/\.meta$/) { &unsub("$fname.meta",$clientip); }   unless ($fname=~/\.meta$/) { &unsub("$fname.meta",$clientip); }
  $fname=~s/\/home\/httpd\/html\/res/raw/;   $fname=~s/\/home\/httpd\/html\/res/raw/;
  $fname="http://".&Apache::lonnet::hostname($perlvar{'lonHostID'})."/".$fname;                  my $protocol = $Apache::lonnet::protocol{$perlvar{'lonHostID'}};
                   $protocol = 'http' if ($protocol ne 'https');
    $fname=$protocol.'://'.&Apache::lonnet::hostname($perlvar{'lonHostID'})."/".$fname;
  $result="$fname\n";   $result="$fname\n";
     }      }
  } else {   } else {
Line 7266  sub get_usersession_config { Line 7359  sub get_usersession_config {
     return;      return;
 }  }
   
   sub releasereqd_check {
       my ($cnum,$cdom,$key,$value,$major,$minor,$homecourses,$ids) = @_;
       my $home = &Apache::lonnet::homeserver($cnum,$cdom);
       return if ($home eq 'no_host');
       my ($reqdmajor,$reqdminor,$displayrole);
       if ($cnum =~ /$LONCAPA::match_community/) {
           if ($major eq '' && $minor eq '') {
               return unless ((ref($ids) eq 'ARRAY') && 
                              (grep(/^\Q$home\E$/,@{$ids})));
           } else {
               $reqdmajor = 2;
               $reqdminor = 9;
               return unless (&useable_role($reqdmajor,$reqdminor,$major,$minor));
           }
       }
       my $hashid = $cdom.':'.$cnum;
       my ($courseinfo,$cached) =
           &Apache::lonnet::is_cached_new('courseinfo',$hashid);
       if (defined($cached)) {
           if (ref($courseinfo) eq 'HASH') {
               if (exists($courseinfo->{'releaserequired'})) {
                   my ($reqdmajor,$reqdminor) = split(/\./,$courseinfo->{'releaserequired'});
                   return unless (&useable_role($reqdmajor,$reqdminor,$major,$minor));
               }
           }
       } else {
           if (ref($ids) eq 'ARRAY') {
               if (grep(/^\Q$home\E$/,@{$ids})) {
                   if (ref($homecourses) eq 'HASH') {
                       if (ref($homecourses->{$hashid}) eq 'ARRAY') {
                           push(@{$homecourses->{$hashid}},{$key=>$value});
                       } else {
                           $homecourses->{$hashid} = [{$key=>$value}];
                       }
                   }
                   return;
               }
           }
           my $courseinfo = &get_courseinfo_hash($cnum,$cdom,$home);
           if (ref($courseinfo) eq 'HASH') {
               if (exists($courseinfo->{'releaserequired'})) {
                   my ($reqdmajor,$reqdminor) = split(/\./,$courseinfo->{'releaserequired'});
                   return unless (&useable_role($reqdmajor,$reqdminor,$major,$minor));
               }
           } else {
               return;
           }
       }
       return 1;
   }
   
   sub get_courseinfo_hash {
       my ($cnum,$cdom,$home) = @_;
       my %info;
       eval {
           local($SIG{ALRM}) = sub { die "timeout\n"; };
           local($SIG{__DIE__})='DEFAULT';
           alarm(3);
           %info = &Apache::lonnet::courseiddump($cdom,'.',1,'.','.',$cnum,1,[$home],'.');
           alarm(0);
       };
       if ($@) {
           if ($@ eq "timeout\n") {
               &logthis("<font color='blue'>WARNING courseiddump for $cnum:$cdom from $home timedout</font>");
           } else {
               &logthis("<font color='yellow'>WARNING unexpected error during eval of call for courseiddump from $home</font>");
           }
       } else {
           if (ref($info{$cdom.'_'.$cnum}) eq 'HASH') {
               my $hashid = $cdom.':'.$cnum;
               return &Apache::lonnet::do_cache_new('courseinfo',$hashid,$info{$cdom.'_'.$cnum},600);
           }
       }
       return;
   }
   
   sub check_homecourses {
       my ($homecourses,$udom,$regexp,$count,$range,$start,$end,$major,$minor) = @_;
       my ($result,%addtocache);
       my $yesterday = time - 24*3600; 
       if (ref($homecourses) eq 'HASH') {
           my (%okcourses,%courseinfo,%recent);
           my $hashref = &tie_domain_hash($udom, "nohist_courseids", &GDBM_WRCREAT());
           if ($hashref) {
               while (my ($key,$value) = each(%$hashref)) {
                   my $unesc_key = &unescape($key);
                   if ($unesc_key =~ /^lasttime:(\w+)$/) {
                       my $cid = $1;
                       $cid =~ s/_/:/;
                       if ($value > $yesterday ) {
                           $recent{$cid} = 1;
                       }
                       next;
                   }
                   my $items = &Apache::lonnet::thaw_unescape($value);
                   if (ref($items) eq 'HASH') {
                       my $hashid = $unesc_key;
                       $hashid =~ s/_/:/;
                       $courseinfo{$hashid} = $items;
                       if (ref($homecourses->{$hashid}) eq 'ARRAY') {
                           my ($reqdmajor,$reqdminor) = split(/\./,$items->{'releaserequired'});
                           if (&useable_role($reqdmajor,$reqdminor,$major,$minor)) {
                               $okcourses{$hashid} = 1;
                           }
                       }
                   }
               }
               unless (&untie_domain_hash($hashref)) {
                   &logthis('Failed to untie tied hash for nohist_courseids.db');
               }
           } else {
               &logthis('Failed to tie hash for nohist_courseids.db');
               return;
           }
           foreach my $hashid (keys(%recent)) {
               my ($result,$cached)=&Apache::lonnet::is_cached_new('courseinfo',$hashid);
               unless ($cached) {
                   &Apache::lonnet::do_cache_new('courseinfo',$hashid,$courseinfo{$hashid},600);
               }
           }
           foreach my $hashid (keys(%{$homecourses})) {
               next if ($recent{$hashid});
               &Apache::lonnet::do_cache_new('courseinfo',$hashid,$courseinfo{$hashid},600);
           }
           foreach my $hashid (keys(%okcourses)) {
               if (ref($homecourses->{$hashid}) eq 'ARRAY') {
                   foreach my $role (@{$homecourses->{$hashid}}) {
                       if (ref($role) eq 'HASH') {
                           while (my ($key,$value) = each(%{$role})) {
                               if ($regexp eq '.') {
                                   $count++;
                                   if (defined($range) && $count >= $end)   { last; }
                                   if (defined($range) && $count <  $start) { next; }
                                   $result.=$key.'='.$value.'&';
                               } else {
                                   my $unescapeKey = &unescape($key);
                                   if (eval('$unescapeKey=~/$regexp/')) {
                                       $count++;
                                       if (defined($range) && $count >= $end)   { last; }
                                       if (defined($range) && $count <  $start) { next; }
                                       $result.="$key=$value&";
                                   }
                               }
                           }
                       }
                   }
               }
           }
       }
       return $result;
   }
   
   sub useable_role {
       my ($reqdmajor,$reqdminor,$major,$minor) = @_; 
       if ($reqdmajor ne '' && $reqdminor ne '') {
           return if (($major eq '' && $minor eq '') ||
                      ($major < $reqdmajor) ||
                      (($major == $reqdmajor) && ($minor < $reqdminor)));
       }
       return 1;
   }
   
   sub distro_and_arch {
       return $dist.':'.$arch;
   }
   
 # ----------------------------------- POD (plain old documentation, CPAN style)  # ----------------------------------- POD (plain old documentation, CPAN style)
   
 =head1 NAME  =head1 NAME

Removed from v.1.448  
changed lines
  Added in v.1.476


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