File:  [LON-CAPA] / loncom / lonnet / perl / lonnet.pm
Revision 1.48: download - view: text, annotated - select for diffs
Wed Oct 25 10:55:46 2000 UTC (23 years, 8 months ago) by www
Branches: MAIN
CVS tags: HEAD
Work on varval

    1: # The LearningOnline Network
    2: # TCP networking package
    3: #
    4: # Functions for use by content handlers:
    5: #
    6: # plaintext(short)   : plain text explanation of short term
    7: # fileembstyle(ext)  : embed style in page for file extension
    8: # filedescription(ext) : descriptor text for file extension
    9: # allowed(short,url) : returns codes for allowed actions 
   10: #                      F: full access
   11: #                      U,I,K: authentication modes (cxx only)
   12: #                      '': forbidden
   13: #                      1: user needs to choose course
   14: #                      2: browse allowed
   15: # definerole(rolename,sys,dom,cou) : define a custom role rolename
   16: #                      set priviledges in format of lonTabs/roles.tab for
   17: #                      system, domain and course level, 
   18: # assignrole(udom,uname,url,role,end,start) : give a role to a user for the
   19: #                      level given by url. Optional start and end dates
   20: #                      (leave empty string or zero for "no date") 
   21: # assigncustomrole (udom,uname,url,rdom,rnam,rolename,end,start) : give a
   22: #                      custom role to a user for the level given by url.
   23: #                      Specify name and domain of role author, and role name
   24: # revokerole (udom,uname,url,role) : Revoke a role for url
   25: # revokecustomrole (udom,uname,url,rdom,rnam,rolename) : Revoke a custom role
   26: # appenv(hash)       : adds hash to session environment
   27: # store(hash)        : stores hash permanently for this url
   28: # cstore(hash)       : critical store
   29: # restore            : returns hash for this url
   30: # eget(namesp,array) : returns hash with keys from array filled in from namesp
   31: # get(namesp,array)  : returns hash with keys from array filled in from namesp
   32: # del(namesp,array)  : deletes keys out of array from namesp
   33: # put(namesp,hash)   : stores hash in namesp
   34: # cput(namesp,hash)  : critical put
   35: # dump(namesp)       : dumps the complete namespace into a hash
   36: # ssi(url,hash)      : does a complete request cycle on url to localhost, posts
   37: #                      hash
   38: # coursedescription(id) : returns and caches course description for id
   39: # repcopy(filename)  : replicate file
   40: # dirlist(url)       : gets a directory listing
   41: # directcondval(index) : reading condition value of single condition from 
   42: #                        state string
   43: # condval(index)     : value of condition index based on state
   44: # varval(name)       : value of a variable
   45: # refreshstate()     : refresh the state information string
   46: # symblist(map,hash) : Updates symbolic storage links
   47: # symbread([filename]) : returns the data handle (filename optional)
   48: # rndseed()          : returns a random seed  
   49: # getfile(filename)  : returns the contents of filename, or a -1 if it can't
   50: #                      be found, replicates and subscribes to the file
   51: # filelocation(dir,file) : returns a farily clean absolute reference to file 
   52: #                          from the directory dir
   53: # hreflocation(dir,file) : same as filelocation, but for hrefs
   54: # log(domain,user,home,msg) : write to permanent log for user
   55: #
   56: # 6/1/99,6/2,6/10,6/11,6/12,6/14,6/26,6/28,6/29,6/30,
   57: # 7/1,7/2,7/9,7/10,7/12,7/14,7/15,7/19,
   58: # 11/8,11/16,11/18,11/22,11/23,12/22,
   59: # 01/06,01/13,02/24,02/28,02/29,
   60: # 03/01,03/02,03/06,03/07,03/13,
   61: # 04/05,05/29,05/31,06/01,
   62: # 06/05,06/26 Gerd Kortemeyer
   63: # 06/26 Ben Tyszka
   64: # 06/30,07/15,07/17,07/18,07/20,07/21,07/22,07/25 Gerd Kortemeyer
   65: # 08/14 Ben Tyszka
   66: # 08/22,08/28,08/31,09/01,09/02,09/04,09/05,09/25,09/28,09/30 Gerd Kortemeyer
   67: # 10/04 Gerd Kortemeyer
   68: # 10/04 Guy Albertelli
   69: # 10/06,10/09,10/10,10/11,10/14,10/20,10/23,10/25 Gerd Kortemeyer
   70: 
   71: package Apache::lonnet;
   72: 
   73: use strict;
   74: use Apache::File;
   75: use LWP::UserAgent();
   76: use HTTP::Headers;
   77: use vars 
   78: qw(%perlvar %hostname %homecache %spareid %hostdom %libserv %pr %prp %fe %fd $readit);
   79: use IO::Socket;
   80: use GDBM_File;
   81: use Apache::Constants qw(:common :http);
   82: 
   83: # --------------------------------------------------------------------- Logging
   84: 
   85: sub logthis {
   86:     my $message=shift;
   87:     my $execdir=$perlvar{'lonDaemons'};
   88:     my $now=time;
   89:     my $local=localtime($now);
   90:     my $fh=Apache::File->new(">>$execdir/logs/lonnet.log");
   91:     print $fh "$local ($$): $message\n";
   92:     return 1;
   93: }
   94: 
   95: sub logperm {
   96:     my $message=shift;
   97:     my $execdir=$perlvar{'lonDaemons'};
   98:     my $now=time;
   99:     my $local=localtime($now);
  100:     my $fh=Apache::File->new(">>$execdir/logs/lonnet.perm.log");
  101:     print $fh "$now:$message:$local\n";
  102:     return 1;
  103: }
  104: 
  105: # -------------------------------------------------- Non-critical communication
  106: sub subreply {
  107:     my ($cmd,$server)=@_;
  108:     my $peerfile="$perlvar{'lonSockDir'}/$server";
  109:     my $client=IO::Socket::UNIX->new(Peer    =>"$peerfile",
  110:                                      Type    => SOCK_STREAM,
  111:                                      Timeout => 10)
  112:        or return "con_lost";
  113:     print $client "$cmd\n";
  114:     my $answer=<$client>;
  115:     if (!$answer) { $answer="con_lost"; }
  116:     chomp($answer);
  117:     return $answer;
  118: }
  119: 
  120: sub reply {
  121:     my ($cmd,$server)=@_;
  122:     my $answer=subreply($cmd,$server);
  123:     if ($answer eq 'con_lost') { $answer=subreply($cmd,$server); }
  124:     if (($answer=~/^error:/) || ($answer=~/^refused/) || 
  125:         ($answer=~/^rejected/)) {
  126:        &logthis("<font color=blue>WARNING:".
  127:                 " $cmd to $server returned $answer</font>");
  128:     }
  129:     return $answer;
  130: }
  131: 
  132: # ----------------------------------------------------------- Send USR1 to lonc
  133: 
  134: sub reconlonc {
  135:     my $peerfile=shift;
  136:     &logthis("Trying to reconnect for $peerfile");
  137:     my $loncfile="$perlvar{'lonDaemons'}/logs/lonc.pid";
  138:     if (my $fh=Apache::File->new("$loncfile")) {
  139: 	my $loncpid=<$fh>;
  140:         chomp($loncpid);
  141:         if (kill 0 => $loncpid) {
  142: 	    &logthis("lonc at pid $loncpid responding, sending USR1");
  143:             kill USR1 => $loncpid;
  144:             sleep 1;
  145:             if (-e "$peerfile") { return; }
  146:             &logthis("$peerfile still not there, give it another try");
  147:             sleep 5;
  148:             if (-e "$peerfile") { return; }
  149:             &logthis(
  150:   "<font color=blue>WARNING: $peerfile still not there, giving up</font>");
  151:         } else {
  152: 	    &logthis(
  153:                "<font color=blue>WARNING:".
  154:                " lonc at pid $loncpid not responding, giving up</font>");
  155:         }
  156:     } else {
  157:      &logthis('<font color=blue>WARNING: lonc not running, giving up</font>');
  158:     }
  159: }
  160: 
  161: # ------------------------------------------------------ Critical communication
  162: 
  163: sub critical {
  164:     my ($cmd,$server)=@_;
  165:     my $answer=reply($cmd,$server);
  166:     if ($answer eq 'con_lost') {
  167:         my $pingreply=reply('ping',$server);
  168: 	&reconlonc("$perlvar{'lonSockDir'}/$server");
  169:         my $pongreply=reply('pong',$server);
  170:         &logthis("Ping/Pong for $server: $pingreply/$pongreply");
  171:         $answer=reply($cmd,$server);
  172:         if ($answer eq 'con_lost') {
  173:             my $now=time;
  174:             my $middlename=$cmd;
  175:             $middlename=substr($middlename,0,16);
  176:             $middlename=~s/\W//g;
  177:             my $dfilename=
  178:              "$perlvar{'lonSockDir'}/delayed/$now.$middlename.$server";
  179:             {
  180:              my $dfh;
  181:              if ($dfh=Apache::File->new(">$dfilename")) {
  182:                 print $dfh "$cmd\n";
  183: 	     }
  184:             }
  185:             sleep 2;
  186:             my $wcmd='';
  187:             {
  188: 	     my $dfh;
  189:              if ($dfh=Apache::File->new("$dfilename")) {
  190:                 $wcmd=<$dfh>;
  191: 	     }
  192:             }
  193:             chomp($wcmd);
  194:             if ($wcmd eq $cmd) {
  195: 		&logthis("<font color=blue>WARNING: ".
  196:                          "Connection buffer $dfilename: $cmd</font>");
  197:                 &logperm("D:$server:$cmd");
  198: 	        return 'con_delayed';
  199:             } else {
  200:                 &logthis("<font color=red>CRITICAL:"
  201:                         ." Critical connection failed: $server $cmd</font>");
  202:                 &logperm("F:$server:$cmd");
  203:                 return 'con_failed';
  204:             }
  205:         }
  206:     }
  207:     return $answer;
  208: }
  209: 
  210: # ---------------------------------------------------------- Append Environment
  211: 
  212: sub appenv {
  213:     my %newenv=@_;
  214:     map {
  215: 	if (($newenv{$_}=~/^user\.role/) || ($newenv{$_}=~/^user\.priv/)) {
  216:             &logthis("<font color=blue>WARNING: ".
  217:                 "Attempt to modify environment ".$_." to ".$newenv{$_});
  218: 	    delete($newenv{$_});
  219:         } else {
  220:             $ENV{$_}=$newenv{$_};
  221:         }
  222:     } keys %newenv;
  223:     my @oldenv;
  224:     {
  225:      my $fh;
  226:      unless ($fh=Apache::File->new("$ENV{'user.environment'}")) {
  227: 	return 'error';
  228:      }
  229:      @oldenv=<$fh>;
  230:     }
  231:     for (my $i=0; $i<=$#oldenv; $i++) {
  232:         chomp($oldenv[$i]);
  233:         if ($oldenv[$i] ne '') {
  234:            my ($name,$value)=split(/=/,$oldenv[$i]);
  235:            unless (defined($newenv{$name})) {
  236: 	      $newenv{$name}=$value;
  237: 	   }
  238:         }
  239:     }
  240:     {
  241:      my $fh;
  242:      unless ($fh=Apache::File->new(">$ENV{'user.environment'}")) {
  243: 	return 'error';
  244:      }
  245:      my $newname;
  246:      foreach $newname (keys %newenv) {
  247: 	 print $fh "$newname=$newenv{$newname}\n";
  248:      }
  249:     }
  250:     return 'ok';
  251: }
  252: 
  253: # ------------------------------ Find server with least workload from spare.tab
  254: 
  255: sub spareserver {
  256:     my $tryserver;
  257:     my $spareserver='';
  258:     my $lowestserver=100;
  259:     foreach $tryserver (keys %spareid) {
  260:        my $answer=reply('load',$tryserver);
  261:        if (($answer =~ /\d/) && ($answer<$lowestserver)) {
  262: 	   $spareserver="http://$hostname{$tryserver}";
  263:            $lowestserver=$answer;
  264:        }
  265:     }    
  266:     return $spareserver;
  267: }
  268: 
  269: # --------- Try to authenticate user from domain's lib servers (first this one)
  270: 
  271: sub authenticate {
  272:     my ($uname,$upass,$udom)=@_;
  273:     $upass=escape($upass);
  274:     if (($perlvar{'lonRole'} eq 'library') && 
  275:         ($udom eq $perlvar{'lonDefDomain'})) {
  276:     my $answer=reply("encrypt:auth:$udom:$uname:$upass",$perlvar{'lonHostID'});
  277:         if ($answer =~ /authorized/) {
  278:               if ($answer eq 'authorized') {
  279:                  &logthis("User $uname at $udom authorized by local server"); 
  280:                  return $perlvar{'lonHostID'}; 
  281:               }
  282:               if ($answer eq 'non_authorized') {
  283:                  &logthis("User $uname at $udom rejected by local server"); 
  284:                  return 'no_host'; 
  285:               }
  286: 	}
  287:     }
  288: 
  289:     my $tryserver;
  290:     foreach $tryserver (keys %libserv) {
  291: 	if ($hostdom{$tryserver} eq $udom) {
  292:            my $answer=reply("encrypt:auth:$udom:$uname:$upass",$tryserver);
  293:            if ($answer =~ /authorized/) {
  294:               if ($answer eq 'authorized') {
  295:                  &logthis("User $uname at $udom authorized by $tryserver"); 
  296:                  return $tryserver; 
  297:               }
  298:               if ($answer eq 'non_authorized') {
  299:                  &logthis("User $uname at $udom rejected by $tryserver");
  300:                  return 'no_host';
  301:               } 
  302: 	   }
  303:        }
  304:     }
  305:     &logthis("User $uname at $udom could not be authenticated");    
  306:     return 'no_host';
  307: }
  308: 
  309: # ---------------------- Find the homebase for a user from domain's lib servers
  310: 
  311: sub homeserver {
  312:     my ($uname,$udom)=@_;
  313: 
  314:     my $index="$uname:$udom";
  315:     if ($homecache{$index}) { return "$homecache{$index}"; }
  316: 
  317:     my $tryserver;
  318:     foreach $tryserver (keys %libserv) {
  319: 	if ($hostdom{$tryserver} eq $udom) {
  320:            my $answer=reply("home:$udom:$uname",$tryserver);
  321:            if ($answer eq 'found') { 
  322: 	      $homecache{$index}=$tryserver;
  323:               return $tryserver; 
  324: 	   }
  325:        }
  326:     }    
  327:     return 'no_host';
  328: }
  329: 
  330: # ----------------------------- Subscribe to a resource, return URL if possible
  331: 
  332: sub subscribe {
  333:     my $fname=shift;
  334:     my $author=$fname;
  335:     $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;
  336:     my ($udom,$uname)=split(/\//,$author);
  337:     my $home=homeserver($uname,$udom);
  338:     if (($home eq 'no_host') || ($home eq $perlvar{'lonHostID'})) { 
  339:         return 'not_found'; 
  340:     }
  341:     my $answer=reply("sub:$fname",$home);
  342:     return $answer;
  343: }
  344:     
  345: # -------------------------------------------------------------- Replicate file
  346: 
  347: sub repcopy {
  348:     my $filename=shift;
  349:     $filename=~s/\/+/\//g;
  350:     my $transname="$filename.in.transfer";
  351:     if ((-e $filename) || (-e $transname)) { return OK; }
  352:     my $remoteurl=subscribe($filename);
  353:     if ($remoteurl eq 'con_lost') {
  354: 	   &logthis("Subscribe returned con_lost: $filename");
  355:            return HTTP_SERVICE_UNAVAILABLE;
  356:     } elsif ($remoteurl eq 'not_found') {
  357: 	   &logthis("Subscribe returned not_found: $filename");
  358: 	   return HTTP_NOT_FOUND;
  359:     } elsif ($remoteurl eq 'rejected') {
  360: 	   &logthis("Subscribe returned rejected: $filename");
  361:            return FORBIDDEN;
  362:     } elsif ($remoteurl eq 'directory') {
  363:            return OK;
  364:     } else {
  365:            my @parts=split(/\//,$filename);
  366:            my $path="/$parts[1]/$parts[2]/$parts[3]/$parts[4]";
  367:            if ($path ne "$perlvar{'lonDocRoot'}/res") {
  368:                &logthis("Malconfiguration for replication: $filename");
  369: 	       return HTTP_BAD_REQUEST;
  370:            }
  371:            my $count;
  372:            for ($count=5;$count<$#parts;$count++) {
  373:                $path.="/$parts[$count]";
  374:                if ((-e $path)!=1) {
  375: 		   mkdir($path,0777);
  376:                }
  377:            }
  378:            my $ua=new LWP::UserAgent;
  379:            my $request=new HTTP::Request('GET',"$remoteurl");
  380:            my $response=$ua->request($request,$transname);
  381:            if ($response->is_error()) {
  382: 	       unlink($transname);
  383:                my $message=$response->status_line;
  384:                &logthis("<font color=blue>WARNING:"
  385:                        ." LWP get: $message: $filename</font>");
  386:                return HTTP_SERVICE_UNAVAILABLE;
  387:            } else {
  388: 	       if ($remoteurl!~/\.meta$/) {
  389:                   my $mrequest=new HTTP::Request('GET',$remoteurl.'.meta');
  390:                   my $mresponse=$ua->request($mrequest,$filename.'.meta');
  391:                   if ($mresponse->is_error()) {
  392: 		      unlink($filename.'.meta');
  393:                       &logthis(
  394:                      "<font color=yellow>INFO: No metadata: $filename</font>");
  395:                   }
  396: 	       }
  397:                rename($transname,$filename);
  398:                return OK;
  399:            }
  400:     }
  401: }
  402: 
  403: # --------------------------------------------------------- Server Side Include
  404: 
  405: sub ssi {
  406: 
  407:     my ($fn,%form)=@_;
  408: 
  409:     my $ua=new LWP::UserAgent;
  410:     
  411:     my $request;
  412:     
  413:     if (%form) {
  414:       $request=new HTTP::Request('POST',"http://".$ENV{'HTTP_HOST'}.$fn);
  415:       $request->content(join '&', map { "$_=$form{$_}" } keys %form);
  416:     } else {
  417:       $request=new HTTP::Request('GET',"http://".$ENV{'HTTP_HOST'}.$fn);
  418:     }
  419: 
  420:     $request->header(Cookie => $ENV{'HTTP_COOKIE'});
  421:     my $response=$ua->request($request);
  422: 
  423:     return $response->content;
  424: }
  425: 
  426: # ------------------------------------------------------------------------- Log
  427: 
  428: sub log {
  429:     my ($dom,$nam,$hom,$what)=@_;
  430:     return critical("log:$dom:$nam:$what",$hom);
  431: }
  432: 
  433: # ----------------------------------------------------------------------- Store
  434: 
  435: sub store {
  436:     my %storehash=@_;
  437:     my $symb;
  438:     unless ($symb=escape(&symbread())) { return ''; }
  439:     my $namespace;
  440:     unless ($namespace=$ENV{'request.course.id'}) { return ''; }
  441:     my $namevalue='';
  442:     map {
  443:         $namevalue.=escape($_).'='.escape($storehash{$_}).'&';
  444:     } keys %storehash;
  445:     $namevalue=~s/\&$//;
  446:     return reply(
  447:      "store:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$symb:$namevalue",
  448: 		 "$ENV{'user.home'}");
  449: }
  450: 
  451: # -------------------------------------------------------------- Critical Store
  452: 
  453: sub cstore {
  454:     my %storehash=@_;
  455:     my $symb;
  456:     unless ($symb=escape(&symbread())) { return ''; }
  457:     my $namespace;
  458:     unless ($namespace=$ENV{'request.course.id'}) { return ''; }
  459:     my $namevalue='';
  460:     map {
  461:         $namevalue.=escape($_).'='.escape($storehash{$_}).'&';
  462:     } keys %storehash;
  463:     $namevalue=~s/\&$//;
  464:     return critical(
  465:      "store:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$symb:$namevalue",
  466: 		 "$ENV{'user.home'}");
  467: }
  468: 
  469: # --------------------------------------------------------------------- Restore
  470: 
  471: sub restore {
  472:     my $symb;
  473:     unless ($symb=escape(&symbread())) { return ''; }
  474:     my $namespace;
  475:     unless ($namespace=$ENV{'request.course.id'}) { return ''; }
  476:     my $answer=reply(
  477:               "restore:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$symb",
  478:               "$ENV{'user.home'}");
  479:     my %returnhash=();
  480:     map {
  481: 	my ($name,$value)=split(/\=/,$_);
  482:         $returnhash{&unescape($name)}=&unescape($value);
  483:     } split(/\&/,$answer);
  484:     map {
  485:         $returnhash{$_}=$returnhash{$returnhash{'version'}.':'.$_};
  486:     } split(/\:/,$returnhash{$returnhash{'version'}.':keys'});
  487:     return %returnhash;
  488: }
  489: 
  490: # ---------------------------------------------------------- Course Description
  491: 
  492: sub coursedescription {
  493:     my $courseid=shift;
  494:     $courseid=~s/^\///;
  495:     my ($cdomain,$cnum)=split(/\//,$courseid);
  496:     my $chome=homeserver($cnum,$cdomain);
  497:     if ($chome ne 'no_host') {
  498:        my $rep=reply("dump:$cdomain:$cnum:environment",$chome);
  499:        if ($rep ne 'con_lost') {
  500: 	   my %cachehash=();
  501:            my %returnhash=('home'   => $chome, 
  502:                            'domain' => $cdomain,
  503:                            'num'    => $cnum);
  504:            map {
  505:                my ($name,$value)=split(/\=/,$_);
  506:                $name=&unescape($name);
  507:                $value=&unescape($value);
  508:                $returnhash{$name}=$value;
  509:                if ($name eq 'description') {
  510: 		   $cachehash{$courseid}=$value;
  511:                }
  512:            } split(/\&/,$rep);
  513:            $returnhash{'url'}='/res/'.declutter($returnhash{'url'});
  514:            $returnhash{'fn'}=$perlvar{'lonDaemons'}.'/tmp/'.
  515: 	       $ENV{'user.name'}.'_'.$cdomain.'_'.$cnum;
  516: 	   put ('coursedescriptions',%cachehash);
  517:            return %returnhash;
  518:        }
  519:     }
  520:     return ();
  521: }
  522: 
  523: # -------------------------------------------------------- Get user priviledges
  524: 
  525: sub rolesinit {
  526:     my ($domain,$username,$authhost)=@_;
  527:     my $rolesdump=reply("dump:$domain:$username:roles",$authhost);
  528:     if (($rolesdump eq 'con_lost') || ($rolesdump eq '')) { return ''; }
  529:     my %allroles=();
  530:     my %thesepriv=();
  531:     my $now=time;
  532:     my $userroles="user.login.time=$now\n";
  533:     my $thesestr;
  534: 
  535:     if ($rolesdump ne '') {
  536:         map {
  537: 	  if ($_!~/^rolesdef\&/) {
  538:             my ($area,$role)=split(/=/,$_);
  539:             $area=~s/\_\w\w$//;
  540:             my ($trole,$tend,$tstart)=split(/_/,$role);
  541:             $userroles.='user.role.'.$trole.'.'.$area.'='.
  542:                         $tstart.'.'.$tend."\n";
  543:             if ($tend!=0) {
  544: 	        if ($tend<$now) {
  545: 	            $trole='';
  546:                 } 
  547:             }
  548:             if ($tstart!=0) {
  549:                 if ($tstart>$now) {
  550:                    $trole='';        
  551:                 }
  552:             }
  553:             if (($area ne '') && ($trole ne '')) {
  554:                my ($tdummy,$tdomain,$trest)=split(/\//,$area);
  555:                if ($trole =~ /^cr\//) {
  556: 		   my ($rdummy,$rdomain,$rauthor,$rrole)=split(/\//,$trole);
  557:                    my $homsvr=homeserver($rauthor,$rdomain);
  558:                    if ($hostname{$homsvr} ne '') {
  559:                       my $roledef=
  560: 			  reply("get:$rdomain:$rauthor:roles:rolesdef_$rrole",
  561:                                 $homsvr);
  562:                       if (($roledef ne 'con_lost') && ($roledef ne '')) {
  563:                          my ($syspriv,$dompriv,$coursepriv)=
  564: 			     split(/\_/,unescape($roledef));
  565:  	                 $allroles{'/'}.=':'.$syspriv;
  566:                          if ($tdomain ne '') {
  567:                              $allroles{'/'.$tdomain.'/'}.=':'.$dompriv;
  568:                              if ($trest ne '') {
  569: 		                $allroles{$area}.=':'.$coursepriv;
  570:                              }
  571: 	                 }
  572:                       }
  573:                    }
  574:                } else {
  575: 	           $allroles{'/'}.=':'.$pr{$trole.':s'};
  576:                    if ($tdomain ne '') {
  577:                       $allroles{'/'.$tdomain.'/'}.=':'.$pr{$trole.':d'};
  578:                       if ($trest ne '') {
  579: 		          $allroles{$area}.=':'.$pr{$trole.':c'};
  580:                       }
  581: 	           }
  582: 	       }
  583:             }
  584:           } 
  585:         } split(/&/,$rolesdump);
  586:         map {
  587:             %thesepriv=();
  588:             map {
  589:                 if ($_ ne '') {
  590: 		    my ($priviledge,$restrictions)=split(/&/,$_);
  591:                     if ($restrictions eq '') {
  592: 			$thesepriv{$priviledge}='F';
  593:                     } else {
  594:                         if ($thesepriv{$priviledge} ne 'F') {
  595: 			    $thesepriv{$priviledge}.=$restrictions;
  596:                         }
  597:                     }
  598:                 }
  599:             } split(/:/,$allroles{$_});
  600:             $thesestr='';
  601:             map { $thesestr.=':'.$_.'&'.$thesepriv{$_}; } keys %thesepriv;
  602:             $userroles.='user.priv.'.$_.'='.$thesestr."\n";
  603:         } keys %allroles;            
  604:     }
  605:     return $userroles;  
  606: }
  607: 
  608: # --------------------------------------------------------------- get interface
  609: 
  610: sub get {
  611:    my ($namespace,@storearr)=@_;
  612:    my $items='';
  613:    map {
  614:        $items.=escape($_).'&';
  615:    } @storearr;
  616:    $items=~s/\&$//;
  617:  my $rep=reply("get:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$items",
  618:                  $ENV{'user.home'});
  619:    my @pairs=split(/\&/,$rep);
  620:    my %returnhash=();
  621:    my $i=0;
  622:    map {
  623:       $returnhash{$_}=unescape($pairs[$i]);
  624:       $i++;
  625:    } @storearr;
  626:    return %returnhash;
  627: }
  628: 
  629: # --------------------------------------------------------------- del interface
  630: 
  631: sub del {
  632:    my ($namespace,@storearr)=@_;
  633:    my $items='';
  634:    map {
  635:        $items.=escape($_).'&';
  636:    } @storearr;
  637:    $items=~s/\&$//;
  638:    return reply("del:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$items",
  639:                  $ENV{'user.home'});
  640: }
  641: 
  642: # -------------------------------------------------------------- dump interface
  643: 
  644: sub dump {
  645:    my $namespace=shift;
  646:    my $rep=reply("dump:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace",
  647:                 $ENV{'user.home'});
  648:    my @pairs=split(/\&/,$rep);
  649:    my %returnhash=();
  650:    map {
  651:       my ($key,$value)=split(/=/,$_);
  652:       $returnhash{unescape($key)}=unescape($value);
  653:    } @pairs;
  654:    return %returnhash;
  655: }
  656: 
  657: # --------------------------------------------------------------- put interface
  658: 
  659: sub put {
  660:    my ($namespace,%storehash)=@_;
  661:    my $items='';
  662:    map {
  663:        $items.=escape($_).'='.escape($storehash{$_}).'&';
  664:    } keys %storehash;
  665:    $items=~s/\&$//;
  666:    return reply("put:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$items",
  667:                  $ENV{'user.home'});
  668: }
  669: 
  670: # ------------------------------------------------------ critical put interface
  671: 
  672: sub cput {
  673:    my ($namespace,%storehash)=@_;
  674:    my $items='';
  675:    map {
  676:        $items.=escape($_).'='.escape($storehash{$_}).'&';
  677:    } keys %storehash;
  678:    $items=~s/\&$//;
  679:    return critical
  680:            ("put:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$items",
  681:                  $ENV{'user.home'});
  682: }
  683: 
  684: # -------------------------------------------------------------- eget interface
  685: 
  686: sub eget {
  687:    my ($namespace,@storearr)=@_;
  688:    my $items='';
  689:    map {
  690:        $items.=escape($_).'&';
  691:    } @storearr;
  692:    $items=~s/\&$//;
  693:  my $rep=reply("eget:$ENV{'user.domain'}:$ENV{'user.name'}:$namespace:$items",
  694:                  $ENV{'user.home'});
  695:    my @pairs=split(/\&/,$rep);
  696:    my %returnhash=();
  697:    my $i=0;
  698:    map {
  699:       $returnhash{$_}=unescape($pairs[$i]);
  700:       $i++;
  701:    } @storearr;
  702:    return %returnhash;
  703: }
  704: 
  705: # ------------------------------------------------- Check for a user priviledge
  706: 
  707: sub allowed {
  708:     my ($priv,$uri)=@_;
  709:     $uri=~s/^\/res//;
  710:     $uri=~s/^\///;
  711: 
  712: # Free bre access to adm resources
  713: 
  714:     if (($uri=~/^adm\//) && ($priv eq 'bre')) {
  715: 	return 'F';
  716:     }
  717: 
  718: # Gather priviledges over system and domain
  719: 
  720:     my $thisallowed='';
  721:     if ($ENV{'user.priv./'}=~/$priv\&([^\:]*)/) {
  722:        $thisallowed.=$1;
  723:     }
  724:     if ($ENV{'user.priv./'.(split(/\//,$uri))[0].'/'}=~/$priv\&([^\:]*)/) {
  725:        $thisallowed.=$1;
  726:     }
  727: 
  728: # Full access at system or domain level? Exit.
  729: 
  730:     if ($thisallowed=~/F/) {
  731: 	return 'F';
  732:     }
  733: 
  734: # The user does not have full access at system or domain level
  735: # Course level access control
  736: 
  737: # uri itself refering to a course?
  738:     
  739:     if ($uri=~/\.course$/) {
  740:        if ($ENV{'user.priv./'.$uri}=~/$priv\&([^\:]*)/) {
  741:           $thisallowed.=$1;
  742:        }
  743: # Full access on course level? Exit.
  744:        if ($thisallowed=~/F/) {
  745: 	  return 'F';
  746:        }
  747: 
  748: # uri is refering to an individual resource; user needs to be in a course
  749: 
  750:    } else {
  751: 
  752:        unless(defined($ENV{'request.course.id'})) {
  753: 	   return '1';
  754:        }
  755: 
  756: # Get access priviledges for course
  757: 
  758:        if ($ENV{'user.priv./'.$ENV{'request.course.id'}}=~/$priv\&([^\:]*)/) {
  759:           $thisallowed.=$1;
  760:        }
  761: 
  762: # See if resource or referer is part of this course
  763:           
  764:        my @uriparts=split(/\//,$uri);
  765:        my $urifile=$uriparts[$#uriparts];
  766:        $urifile=~/\.(\w+)$/;
  767:        my $uritype=$1;
  768:        $#uriparts--;
  769:        my $uripath=join('/',@uriparts);
  770:        my $uricond=-1;
  771:        if ($ENV{'acc.res.'.$ENV{'request.course.id'}.'.'.$uripath}=~
  772: 	   /\&$urifile\:(\d+)\&/) {
  773: 	   $uricond=$1;
  774:        } elsif (($fe{$uritype} eq 'emb') || ($fe{$uritype} eq 'img')) {
  775: 	  my $refuri=$ENV{'HTTP_REFERER'};
  776:           $refuri=~s/^\/res//;
  777:           $refuri=~s/^\///;
  778:           @uriparts=split(/\//,$refuri);
  779:           $urifile=$uriparts[$#uriparts];
  780:           $#uriparts--;
  781:           $uripath=join('/',@uriparts);
  782:           if ($ENV{'acc.res.'.$ENV{'request.course.id'}.'.'.$uripath}=~
  783: 	     /\&$urifile\:(\d+)\&/) {
  784: 	     $uricond=$1;
  785: 	  }
  786:        }
  787: 
  788:        if ($uricond>=0) {
  789: 
  790: # The resource is part of the course
  791: # If user had full access on course level, go ahead
  792: 
  793:            if ($thisallowed=~/F/) {
  794: 	       return 'F';
  795:            }
  796: 
  797: # Restricted by state?
  798: 
  799:            if ($thisallowed=~/X/) {
  800: 	      if (&condval($uricond)) {
  801: 	         return '2';
  802:               } else {
  803:                  return '';
  804:               }
  805: 	   }
  806:        }
  807:     }
  808:     return $thisallowed;
  809: }
  810: 
  811: # ---------------------------------------------------------- Refresh State Info
  812: 
  813: sub refreshstate {
  814: }
  815: 
  816: # ----------------------------------------------------------------- Define Role
  817: 
  818: sub definerole {
  819:   if (allowed('mcr','/')) {
  820:     my ($rolename,$sysrole,$domrole,$courole)=@_;
  821:     map {
  822: 	my ($crole,$cqual)=split(/\&/,$_);
  823:         if ($pr{'cr:s'}!~/$crole/) { return "refused:s:$crole"; }
  824:         if ($pr{'cr:s'}=~/$crole\&/) {
  825: 	    if ($pr{'cr:s'}!~/$crole\&\w*$cqual/) { 
  826:                return "refused:s:$crole&$cqual"; 
  827:             }
  828:         }
  829:     } split('/',$sysrole);
  830:     map {
  831: 	my ($crole,$cqual)=split(/\&/,$_);
  832:         if ($pr{'cr:d'}!~/$crole/) { return "refused:d:$crole"; }
  833:         if ($pr{'cr:d'}=~/$crole\&/) {
  834: 	    if ($pr{'cr:d'}!~/$crole\&\w*$cqual/) { 
  835:                return "refused:d:$crole&$cqual"; 
  836:             }
  837:         }
  838:     } split('/',$domrole);
  839:     map {
  840: 	my ($crole,$cqual)=split(/\&/,$_);
  841:         if ($pr{'cr:c'}!~/$crole/) { return "refused:c:$crole"; }
  842:         if ($pr{'cr:c'}=~/$crole\&/) {
  843: 	    if ($pr{'cr:c'}!~/$crole\&\w*$cqual/) { 
  844:                return "refused:c:$crole&$cqual"; 
  845:             }
  846:         }
  847:     } split('/',$courole);
  848:     my $command="encrypt:rolesput:$ENV{'user.domain'}:$ENV{'user.name'}:".
  849:                 "$ENV{'user.domain'}:$ENV{'user.name'}:".
  850: 	        "rolesdef_$rolename=".
  851:                 escape($sysrole.'_'.$domrole.'_'.$courole);
  852:     return reply($command,$ENV{'user.home'});
  853:   } else {
  854:     return 'refused';
  855:   }
  856: }
  857: 
  858: # ------------------------------------------------------------------ Plain Text
  859: 
  860: sub plaintext {
  861:     my $short=shift;
  862:     return $prp{$short};
  863: }
  864: 
  865: # ------------------------------------------------------------------ Plain Text
  866: 
  867: sub fileembstyle {
  868:     my $ending=shift;
  869:     return $fe{$ending};
  870: }
  871: 
  872: # ------------------------------------------------------------ Description Text
  873: 
  874: sub filedecription {
  875:     my $ending=shift;
  876:     return $fd{$ending};
  877: }
  878: 
  879: # ----------------------------------------------------------------- Assign Role
  880: 
  881: sub assignrole {
  882:     my ($udom,$uname,$url,$role,$end,$start)=@_;
  883:     my $mrole;
  884:     $url=declutter($url);
  885:     if ($role =~ /^cr\//) {
  886:         unless ($url=~/\.course$/) { return 'invalid'; }
  887: 	unless (allowed('ccr',$url)) { return 'refused'; }
  888:         $mrole='cr';
  889:     } else {
  890:         unless (($url=~/\.course$/) || ($url=~/\/$/)) { return 'invalid'; }
  891:         unless (allowed('c'+$role)) { return 'refused'; }
  892:         $mrole=$role;
  893:     }
  894:     my $command="encrypt:rolesput:$ENV{'user.domain'}:$ENV{'user.name'}:".
  895:                 "$udom:$uname:$url".'_'."$mrole=$role";
  896:     if ($end) { $command.='_$end'; }
  897:     if ($start) {
  898: 	if ($end) { 
  899:            $command.='_$start'; 
  900:         } else {
  901:            $command.='_0_$start';
  902:         }
  903:     }
  904:     return &reply($command,&homeserver($uname,$udom));
  905: }
  906: 
  907: # ---------------------------------------------------------- Assign Custom Role
  908: 
  909: sub assigncustomrole {
  910:     my ($udom,$uname,$url,$rdom,$rnam,$rolename,$end,$start)=@_;
  911:     return &assignrole($udom,$uname,$url,'cr/'.$rdom.'/'.$rnam.'/'.$rolename,
  912:                        $end,$start);
  913: }
  914: 
  915: # ----------------------------------------------------------------- Revoke Role
  916: 
  917: sub revokerole {
  918:     my ($udom,$uname,$url,$role)=@_;
  919:     my $now=time;
  920:     return &assignrole($udom,$uname,$url,$role,$now);
  921: }
  922: 
  923: # ---------------------------------------------------------- Revoke Custom Role
  924: 
  925: sub revokecustomrole {
  926:     my ($udom,$uname,$url,$rdom,$rnam,$rolename)=@_;
  927:     my $now=time;
  928:     return &assigncustomrole($udom,$uname,$url,$rdom,$rnam,$rolename,$now);
  929: }
  930: 
  931: # ------------------------------------------------------------ Directory lister
  932: 
  933: sub dirlist {
  934:     my $uri=shift;
  935:     $uri=~s/^\///;
  936:     $uri=~s/\/$//;
  937:     my ($res,$udom,$uname,@rest)=split(/\//,$uri);
  938:     if ($udom) {
  939:      if ($uname) {
  940:        my $listing=reply('ls:'.$perlvar{'lonDocRoot'}.'/'.$uri,
  941:                       homeserver($uname,$udom));
  942:        return split(/:/,$listing);
  943:      } else {
  944:        my $tryserver;
  945:        my %allusers=();
  946:        foreach $tryserver (keys %libserv) {
  947: 	  if ($hostdom{$tryserver} eq $udom) {
  948:              my $listing=reply('ls:'.$perlvar{'lonDocRoot'}.'/res/'.$udom,
  949: 			       $tryserver);
  950:              if (($listing ne 'no_such_dir') && ($listing ne 'empty')
  951:               && ($listing ne 'con_lost')) {
  952:                 map {
  953:                   my ($entry,@stat)=split(/&/,$_);
  954:                   $allusers{$entry}=1;
  955:                 } split(/:/,$listing);
  956:              }
  957: 	  }
  958:        }
  959:        my $alluserstr='';
  960:        map {
  961:            $alluserstr.=$_.'&user:';
  962:        } sort keys %allusers;
  963:        $alluserstr=~s/:$//;
  964:        return split(/:/,$alluserstr);
  965:      } 
  966:    } else {
  967:        my $tryserver;
  968:        my %alldom=();
  969:        foreach $tryserver (keys %libserv) {
  970: 	   $alldom{$hostdom{$tryserver}}=1;
  971:        }
  972:        my $alldomstr='';
  973:        map {
  974:           $alldomstr.=$perlvar{'lonDocRoot'}.'/res/'.$_.'&domain:';
  975:        } sort keys %alldom;
  976:        $alldomstr=~s/:$//;
  977:        return split(/:/,$alldomstr);       
  978:    }
  979: }
  980: 
  981: # -------------------------------------------------------- Value of a Condition
  982: 
  983: sub directcondval {
  984:     my $number=shift;
  985:     if ($ENV{'user.state.'.$ENV{'request.course.id'}}) {
  986:        return substr($ENV{'user.state.'.$ENV{'request.course.id'}},$number,1);
  987:     } else {
  988:        return 2;
  989:     }
  990: }
  991: 
  992: sub condval {
  993:     my $condidx=shift;
  994:     my $result=0;
  995:     if ($ENV{'request.course.id'}) {
  996:        if (defined($ENV{'acc.cond.'.$ENV{'request.course.id'}.'.'.$condidx})) {
  997:           my $operand='|';
  998: 	  my @stack;
  999:           map {
 1000:               if ($_ eq '(') {
 1001:                  push @stack,($operand,$result)
 1002:               } elsif ($_ eq ')') {
 1003:                   my $before=pop @stack;
 1004: 		  if (pop @stack eq '&') {
 1005: 		      $result=$result>$before?$before:$result;
 1006:                   } else {
 1007:                       $result=$result>$before?$result:$before;
 1008:                   }
 1009:               } elsif (($_ eq '&') || ($_ eq '|')) {
 1010:                   $operand=$_;
 1011:               } else {
 1012:                   my $new=directcondval($_);
 1013:                   if ($operand eq '&') {
 1014:                      $result=$result>$new?$new:$result;
 1015:                   } else {
 1016:                      $result=$result>$new?$result:$new;
 1017:                   }                  
 1018:               }
 1019:           } ($ENV{'acc.cond.'.$ENV{'request.course.id'}.'.'.$condidx}=~
 1020:              /(\d+|\(|\)|\&|\|)/g);
 1021:        }
 1022:     }
 1023:     return $result;
 1024: }
 1025: 
 1026: # --------------------------------------------------------- Value of a Variable
 1027: 
 1028: sub varval {
 1029:     my $varname=shift;
 1030:     my ($realm,$space,$qualifier,@therest)=split(/\./,$varname);
 1031:     my $rest;
 1032:     if ($therest[0]) {
 1033:        $rest=join('.',@therest);
 1034:     } else {
 1035:        $rest='';
 1036:     }
 1037:     if ($realm eq 'user') {
 1038: # --------------------------------------------------------------- user.resource
 1039: 	if ($space eq 'resource') {
 1040: # ----------------------------------------------------------------- user.access
 1041:         } elsif ($space eq 'access') {
 1042:             return &allowed($qualifier,$rest);
 1043: # ------------------------------------------ user.preferences, user.environment
 1044:         } elsif (($space eq 'preferences') || ($space eq 'environment')) {
 1045:             return $ENV{join('.',('environment',$qualifier,$rest))};
 1046: # ----------------------------------------------------------------- user.course
 1047:         } elsif ($space eq 'course') {
 1048:             return $ENV{join('.',('request.course',$qualifier))};
 1049: # ------------------------------------------------------------------- user.role
 1050:         } elsif ($space eq 'role') {
 1051:             my ($role,$where)=split(/\./,$ENV{'request.role'});
 1052:             if ($qualifier eq 'value') {
 1053: 		return $role;
 1054:             } elsif ($qualifier eq 'extent') {
 1055:                 return $where;
 1056:             }
 1057: # ----------------------------------------------------------------- user.domain
 1058:         } elsif ($space eq 'domain') {
 1059:             return $ENV{'user.domain'};
 1060: # ------------------------------------------------------------------- user.name
 1061:         } elsif ($space eq 'name') {
 1062:             return $ENV{'user.name'};
 1063: # ---------------------------------------------------- Any other user namespace
 1064:         } else {
 1065:             my $item=($rest)?$qualifier.'.'.$rest:$qualifier;
 1066:             my %reply=&get($space,$item);
 1067:             return $reply{$item};
 1068:         }
 1069:     } elsif ($realm eq 'request') {
 1070: # ------------------------------------------------------------- request.browser
 1071:         if ($space eq 'browser') {
 1072: 	    return $ENV{'browser.'.$qualifier};
 1073:         } elsif ($space eq 'filename') {
 1074:             return $ENV{'request.filename'};
 1075:         }
 1076:     } elsif ($realm eq 'course') {
 1077: # ---------------------------------------------------------- course.description
 1078:         if ($space eq 'description') {
 1079: 	    return &coursedescription($ENV{'request.course.id'});
 1080: # ------------------------------------------------------------------- course.id
 1081:         } elsif ($space eq 'id') {
 1082:             return $ENV{'request.course.id'};
 1083: # -------------------------------------------------- Any other course namespace
 1084:         } else {
 1085: 	    my ($cdom,$cnam)=split(/\_/,$ENV{'request.course.id'});
 1086: 	    my $chome=&homeserver($cnam,$cdom);
 1087:             my $item=join('.',($qualifier,$rest));
 1088:             return &unescape
 1089:                    (&reply('get:'.$cdom.':'.$cnam.':'.&escape($space).':'.
 1090: 			   &escape($item),$chome));
 1091:         }
 1092:     } elsif ($realm eq 'userdata') {
 1093:         my $uhome=&homeserver($qualifier,$space);
 1094: # ----------------------------------------------- userdata.domain.name.resource
 1095: # ---------------------------------------------------- Any other user namespace
 1096:     } elsif ($realm eq 'environment') {
 1097: # ----------------------------------------------------------------- environment
 1098:         return $ENV{join('.',($space,$qualifier,$rest))};
 1099:     } elsif ($realm eq 'system') {
 1100: # ----------------------------------------------------------------- system.time
 1101: 	if ($space eq 'time') {
 1102: 	    return time;
 1103:         }
 1104:     }
 1105:     return '';
 1106: }
 1107: 
 1108: # ------------------------------------------------- Update symbolic store links
 1109: 
 1110: sub symblist {
 1111:     my ($mapname,%newhash)=@_;
 1112:     $mapname=declutter($mapname);
 1113:     my %hash;
 1114:     if (($ENV{'request.course.fn'}) && (%newhash)) {
 1115:         if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db',
 1116:                       &GDBM_WRCREAT,0640)) {
 1117: 	    map {
 1118:                 $hash{declutter($_)}=$mapname.'___'.$newhash{$_};
 1119:             } keys %newhash;
 1120:             if (untie(%hash)) {
 1121: 		return 'ok';
 1122:             }
 1123:         }
 1124:     }
 1125:     return 'error';
 1126: }
 1127: 
 1128: # ------------------------------------------------------ Return symb list entry
 1129: 
 1130: sub symbread {
 1131:     my $thisfn=shift;
 1132:     unless ($thisfn) {
 1133: 	$thisfn=$ENV{'request.filename'};
 1134:     }
 1135:     $thisfn=declutter($thisfn);
 1136:     my %hash;
 1137:     my %bighash;
 1138:     my $syval='';
 1139:     if (($ENV{'request.course.fn'}) && ($thisfn)) {
 1140:         if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.'_symb.db',
 1141:                       &GDBM_READER,0640)) {
 1142: 	    $syval=$hash{$thisfn};
 1143:             untie(%hash);
 1144:         }
 1145: # ---------------------------------------------------------- There was an entry
 1146:         if ($syval) {
 1147:            unless ($syval=~/\_\d+$/) {
 1148: 	       unless ($ENV{'form.request.prefix'}=~/\.(\d+)\_$/) {
 1149:                   &appenv('request.ambiguous' => $thisfn);
 1150:                   return '';
 1151:                }    
 1152:                $syval.=$1;
 1153: 	   }
 1154:         } else {
 1155: # ------------------------------------------------------- Was not in symb table
 1156:            if (tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',
 1157:                             &GDBM_READER,0640)) {
 1158: # ---------------------------------------------- Get ID(s) for current resource
 1159:               my $ids=$bighash{'ids_/res/'.$thisfn};
 1160:               if ($ids) {
 1161: # ------------------------------------------------------------------- Has ID(s)
 1162:                  my @possibilities=split(/\,/,$ids);
 1163:                  if ($#possibilities==0) {
 1164: # ----------------------------------------------- There is only one possibility
 1165: 		     my ($mapid,$resid)=split(/\./,$ids);
 1166:                      $syval=declutter($bighash{'map_id_'.$mapid}).'___'.$resid;
 1167:                  } else {
 1168: # ------------------------------------------ There is more than one possibility
 1169:                      my $realpossible=0;
 1170:                      map {
 1171: 			 my $file=$bighash{'src_'.$_};
 1172:                          if (&allowed('bre',$file)) {
 1173:          		    my ($mapid,$resid)=split(/\./,$_);
 1174:                             if ($bighash{'map_type_'.$mapid} ne 'page') {
 1175: 				$realpossible++;
 1176:                                 $syval=declutter($bighash{'map_id_'.$mapid}).
 1177:                                        '___'.$resid;
 1178:                             }
 1179: 			 }
 1180:                      } @possibilities;
 1181: 		     if ($realpossible!=1) { $syval=''; }
 1182:                  }
 1183: 	      }
 1184:               untie(%bighash)
 1185:            } 
 1186:         }
 1187:         if ($syval) { return $syval.'___'.$thisfn; }
 1188:     }
 1189:     &appenv('request.ambiguous' => $thisfn);
 1190:     return '';
 1191: }
 1192: 
 1193: # ---------------------------------------------------------- Return random seed
 1194: 
 1195: sub numval {
 1196:     my $txt=shift;
 1197:     $txt=~tr/A-J/0-9/;
 1198:     $txt=~tr/a-j/0-9/;
 1199:     $txt=~tr/K-T/0-9/;
 1200:     $txt=~tr/k-t/0-9/;
 1201:     $txt=~tr/U-Z/0-5/;
 1202:     $txt=~tr/u-z/0-5/;
 1203:     $txt=~s/\D//g;
 1204:     return int($txt);
 1205: }    
 1206: 
 1207: sub rndseed {
 1208:     my $symb;
 1209:     unless ($symb=&symbread()) { return time; }
 1210:     my $symbchck=unpack("%32C*",$symb);
 1211:     my $symbseed=numval($symb)%$symbchck;
 1212:     my $namechck=unpack("%32C*",$ENV{'user.name'});
 1213:     my $nameseed=numval($ENV{'user.name'})%$namechck;
 1214:     return int( $symbseed
 1215: 	       .$nameseed
 1216:                .unpack("%32C*",$ENV{'user.domain'})
 1217:                .unpack("%32C*",$ENV{'request.course.id'})
 1218:                .$namechck
 1219:                .$symbchck);
 1220: }
 1221: 
 1222: # ------------------------------------------------------------ Serves up a file
 1223: # returns either the contents of the file or a -1
 1224: sub getfile {
 1225:   my $file=shift;
 1226:   &repcopy($file);
 1227:   if (! -e $file ) { return -1; };
 1228:   my $fh=Apache::File->new($file);
 1229:   my $a='';
 1230:   while (<$fh>) { $a .=$_; }
 1231:   return $a
 1232: }
 1233: 
 1234: sub filelocation {
 1235:   my ($dir,$file) = @_;
 1236:   my $location;
 1237:   $file=~ s/^\s*(\S+)\s*$/$1/; ## strip off leading and trailing spaces
 1238:   $file=~s/^$perlvar{'lonDocRoot'}//;
 1239:   $file=~s:^/*res::;
 1240:   if ( !( $file =~ m:^/:) ) {
 1241:     $location = $dir. '/'.$file;
 1242:   } else {
 1243:     $location = '/home/httpd/html/res'.$file;
 1244:   }
 1245:   $location=~s://+:/:g; # remove duplicate /
 1246:   while ($location=~m:/\.\./:) {$location=~ s:/[^/]+/\.\./:/:g;} #remove dir/..
 1247:   return $location;
 1248: }
 1249: 
 1250: sub hreflocation {
 1251:     my ($dir,$file)=@_;
 1252:     unless (($_=~/^http:\/\//i) || ($_=~/^\//)) {
 1253:        my $finalpath=filelocation($dir,$file);
 1254:        $finalpath=~s/^\/home\/httpd\/html//;
 1255:        return $finalpath;
 1256:     } else {
 1257:        return $file;
 1258:     }
 1259: }
 1260: 
 1261: # ------------------------------------------------------------- Declutters URLs
 1262: 
 1263: sub declutter {
 1264:     my $thisfn=shift;
 1265:     $thisfn=~s/^$perlvar{'lonDocRoot'}//;
 1266:     $thisfn=~s/^\///;
 1267:     $thisfn=~s/^res\///;
 1268:     return $thisfn;
 1269: }
 1270: 
 1271: # -------------------------------------------------------- Escape Special Chars
 1272: 
 1273: sub escape {
 1274:     my $str=shift;
 1275:     $str =~ s/(\W)/"%".unpack('H2',$1)/eg;
 1276:     return $str;
 1277: }
 1278: 
 1279: # ----------------------------------------------------- Un-Escape Special Chars
 1280: 
 1281: sub unescape {
 1282:     my $str=shift;
 1283:     $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
 1284:     return $str;
 1285: }
 1286: 
 1287: # ================================================================ Main Program
 1288: 
 1289: sub BEGIN {
 1290: if ($readit ne 'done') {
 1291: # ------------------------------------------------------------ Read access.conf
 1292: {
 1293:     my $config=Apache::File->new("/etc/httpd/conf/access.conf");
 1294: 
 1295:     while (my $configline=<$config>) {
 1296:         if ($configline =~ /PerlSetVar/) {
 1297: 	   my ($dummy,$varname,$varvalue)=split(/\s+/,$configline);
 1298:            chomp($varvalue);
 1299:            $perlvar{$varname}=$varvalue;
 1300:         }
 1301:     }
 1302: }
 1303: 
 1304: # ------------------------------------------------------------- Read hosts file
 1305: {
 1306:     my $config=Apache::File->new("$perlvar{'lonTabDir'}/hosts.tab");
 1307: 
 1308:     while (my $configline=<$config>) {
 1309:        my ($id,$domain,$role,$name,$ip)=split(/:/,$configline);
 1310:        $hostname{$id}=$name;
 1311:        $hostdom{$id}=$domain;
 1312:        if ($role eq 'library') { $libserv{$id}=$name; }
 1313:     }
 1314: }
 1315: 
 1316: # ------------------------------------------------------ Read spare server file
 1317: {
 1318:     my $config=Apache::File->new("$perlvar{'lonTabDir'}/spare.tab");
 1319: 
 1320:     while (my $configline=<$config>) {
 1321:        chomp($configline);
 1322:        if (($configline) && ($configline ne $perlvar{'lonHostID'})) {
 1323:           $spareid{$configline}=1;
 1324:        }
 1325:     }
 1326: }
 1327: # ------------------------------------------------------------ Read permissions
 1328: {
 1329:     my $config=Apache::File->new("$perlvar{'lonTabDir'}/roles.tab");
 1330: 
 1331:     while (my $configline=<$config>) {
 1332:        chomp($configline);
 1333:        my ($role,$perm)=split(/ /,$configline);
 1334:        if ($perm ne '') { $pr{$role}=$perm; }
 1335:     }
 1336: }
 1337: 
 1338: # -------------------------------------------- Read plain texts for permissions
 1339: {
 1340:     my $config=Apache::File->new("$perlvar{'lonTabDir'}/rolesplain.tab");
 1341: 
 1342:     while (my $configline=<$config>) {
 1343:        chomp($configline);
 1344:        my ($short,$plain)=split(/:/,$configline);
 1345:        if ($plain ne '') { $prp{$short}=$plain; }
 1346:     }
 1347: }
 1348: 
 1349: # ------------------------------------------------------------- Read file types
 1350: {
 1351:     my $config=Apache::File->new("$perlvar{'lonTabDir'}/filetypes.tab");
 1352: 
 1353:     while (my $configline=<$config>) {
 1354:        chomp($configline);
 1355:        my ($ending,$emb,@descr)=split(/\s+/,$configline);
 1356:        if ($descr[0] ne '') { 
 1357:          $fe{$ending}=$emb;
 1358:          $fd{$ending}=join(' ',@descr);
 1359:        }
 1360:     }
 1361: }
 1362: 
 1363: 
 1364: $readit='done';
 1365: &logthis('<font color=yellow>INFO: Read configuration</font>');
 1366: }
 1367: }
 1368: 1;

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