![]() ![]() | ![]() |
- bluh, user.name isn't neccessarily unique
1: # The LearningOnline Network with CAPA 2: # Directory Indexer 3: # 4: # $Id: lonindexer.pm,v 1.65 2003/06/13 23:42:45 albertel Exp $ 5: # 6: # Copyright Michigan State University Board of Trustees 7: # 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA). 9: # 10: # LON-CAPA is free software; you can redistribute it and/or modify 11: # it under the terms of the GNU General Public License as published by 12: # the Free Software Foundation; either version 2 of the License, or 13: # (at your option) any later version. 14: # 15: # LON-CAPA is distributed in the hope that it will be useful, 16: # but WITHOUT ANY WARRANTY; without even the implied warranty of 17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18: # GNU General Public License for more details. 19: # 20: # You should have received a copy of the GNU General Public License 21: # along with LON-CAPA; if not, write to the Free Software 22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23: # 24: # /home/httpd/html/adm/gpl.txt 25: # 26: # http://www.lon-capa.org/ 27: # 28: # YEAR=1999 29: # 5/21/99, 5/22,5/25,5/26,5/31,6/2,6/10,7/12,7/14 Gerd Kortemeyer) 30: # 11/23 Gerd Kortemeyer 31: # YEAR=2000 32: # 07/20-08/04 H.K. Ng 33: # YEAR=2001 34: # 05/9-05/19/2001 H. K. Ng 35: # 05/21/2001 H. K. Ng 36: # 05/23/2001 H. K. Ng 37: # 6/26,7/8 H. K. Ng 38: # 8/14 H. K. Ng 39: # 11/30 Matthew Hall 40: # YEAR=2002 41: # 6/29/2002 H. K. Ng 42: # 43: ### 44: 45: ############################################################################### 46: ## ## 47: ## ORGANIZATION OF THIS PERL MODULE ## 48: ## ## 49: ## 1. Description of functions ## 50: ## 2. Modules used by this module ## 51: ## 3. Choices for different output views (detailed, summary, xml, etc) ## 52: ## 4. BEGIN block (to be run once after compilation) ## 53: ## 5. Handling routine called via Apache and mod_perl ## 54: ## 6. Other subroutines ## 55: ## ## 56: ############################################################################### 57: 58: package Apache::lonindexer; 59: 60: # ------------------------------------------------- modules used by this module 61: use strict; 62: use Apache::lonnet(); 63: use Apache::loncommon(); 64: use Apache::Constants qw(:common); 65: use Apache::File; 66: use GDBM_File; 67: 68: # ---------------------------------------- variables used throughout the module 69: my %hash; # tied to a user-specific gdbm file 70: my %dirs; # keys are directories, values are the open/close status 71: my %language; # has the reference information present in language.tab 72: 73: # ----- Values which are set by the handler subroutine and are accessible to 74: # ----- other methods. 75: my $extrafield; # default extra table cell 76: my $fnum; # file counter 77: my $dnum; # directory counter 78: 79: # ----- Used to include or exclude files with certain extensions. 80: my @Only = (); 81: my @Omit = (); 82: 83: 84: # ----------------------------- Handling routine called via Apache and mod_perl 85: sub handler { 86: my $r = shift; 87: $r->content_type('text/html'); 88: &Apache::loncommon::no_cache($r); 89: $r->send_http_header; 90: return OK if $r->header_only; 91: $fnum=0; 92: $dnum=0; 93: untie %hash; 94: 95: # Deal with stupid global variables (is there a way around making 96: # these global to this package? It is just so wrong....) 97: undef (@Only); 98: undef (@Omit); 99: 100: # ------------------------------------- read in machine configuration variables 101: my $iconpath= $r->dir_config('lonIconsURL') . "/"; 102: my $domain = $r->dir_config('lonDefDomain'); 103: my $role = $r->dir_config('lonRole'); 104: my $loadlim = $r->dir_config('lonLoadLim'); 105: my $servadm = $r->dir_config('lonAdmEMail'); 106: my $sysadm = $r->dir_config('lonSysEMail'); 107: my $lonhost = $r->dir_config('lonHostID'); 108: my $tabdir = $r->dir_config('lonTabDir'); 109: 110: my $fileclr='#ffffe6'; 111: my $line; 112: my (@attrchk,@openpath); 113: my $uri=$r->uri; 114: 115: # -------------------------------------- see if called from an interactive mode 116: # Get the parameters from the query string 117: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, 118: ['catalogmode','launch','acts','mode','form','element', 119: 'only','omit']); 120: #------------------------------------------------------------------- 121: my $closebutton=''; 122: my $groupimportbutton=''; 123: my $colspan=''; 124: 125: $extrafield=''; 126: my $diropendb = 127: "/home/httpd/perl/tmp/$domain\_$ENV{'user.name'}_$ENV{'user.domain'}_indexer.db"; 128: 129: if (tie(%hash,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) { 130: if ($ENV{'form.launch'} eq '1') { 131: &start_fresh_session(); 132: } 133: # -------------------- refresh environment with user database values (in %hash) 134: &setvalues(\%hash,'form.catalogmode',\%ENV,'form.catalogmode' ); 135: 136: # --------------------- define extra fields and buttons in case of special mode 137: if ($ENV{'form.catalogmode'} eq 'interactive') { 138: $extrafield='<td bgcolor="'.$fileclr.'" valign="bottom">'. 139: '<a name="$anchor"><img src="'.$iconpath.'whitespace1.gif"'. 140: ' border="0" /></td>'; 141: $colspan=" colspan='2' "; 142: $closebutton=<<END; 143: <input type="button" name="close" value='CLOSE' onClick="self.close()"> 144: END 145: } 146: elsif ($ENV{'form.catalogmode'} eq 'groupimport') { 147: $extrafield='<td bgcolor="'.$fileclr.'" valign="bottom">'. 148: '<a name="$anchor"><img src="'.$iconpath.'whitespace1.gif"'. 149: ' border="0" /></td>'; 150: $colspan=" colspan='2' "; 151: $closebutton=<<END; 152: <input type="button" name="close" value='CLOSE' onClick="self.close()"> 153: END 154: $groupimportbutton=<<END; 155: <input type="button" name="groupimport" value='GROUP IMPORT' 156: onClick="javascript:select_group()"> 157: END 158: } 159: # Additions made by Matthew to make the browser a little easier to deal 160: # with in the future. 161: # 162: # $mode (at this time) indicates if we are in edit mode. 163: # $form is the name of the form that the URL is placed when the 164: # selection is made. 165: # $element is the name of the element in $formname which receives 166: # the URL. 167: # &Apache::lonxml::debug('Checking mode, form, element'); 168: &setvalues(\%hash,'form.mode' ,\%ENV,'form.mode' ); 169: &setvalues(\%hash,'form.form' ,\%ENV,'form.form' ); 170: &setvalues(\%hash,'form.element',\%ENV,'form.element'); 171: &setvalues(\%hash,'form.only' ,\%ENV,'form.only' ); 172: &setvalues(\%hash,'form.omit' ,\%ENV,'form.omit' ); 173: 174: # Deal with 'omit' and 'only' 175: if (exists $ENV{'form.omit'}) { 176: @Omit = split(',',$ENV{'form.omit'}); 177: } 178: if (exists $ENV{'form.only'}) { 179: @Only = split(',',$ENV{'form.only'}); 180: } 181: 182: my $mode = $ENV{'form.mode'}; 183: my ($form,$element); 184: if ($mode eq 'edit' || $mode eq 'parmset') { 185: $form = $ENV{'form.form'}; 186: $element = $ENV{'form.element'}; 187: } 188: &Apache::lonxml::debug("mode=$mode form=$form element=$element"); 189: # ------ set catalogmodefunctions to have extra needed javascript functionality 190: my $catalogmodefunctions=''; 191: if ($ENV{'form.catalogmode'} eq 'interactive' or 192: $ENV{'form.catalogmode'} eq 'groupimport') { 193: # The if statement below sets us up to use the old version 194: # by default (ie. if $mode is undefined). This is the easy 195: # way out. Hopefully in the future I'll find a way to get 196: # the calls dealt with in a more comprehensive manner. 197: 198: # 199: # There is now also mode "simple", which is for the simple version of the rat 200: # 201: # 202: if (!defined($mode) || ($mode ne 'edit' && $mode ne 'parmset')) { 203: my $location = "/adm/groupsort?catalogmode=groupimport&"; 204: $location .= "mode=".$mode."&"; 205: $location .= "acts="; 206: $catalogmodefunctions=<<"END"; 207: function select_data(title,url) { 208: changeTitle(title); 209: changeURL(url); 210: self.close(); 211: } 212: function select_group() { 213: window.location="$location"+document.forms.fileattr.acts.value; 214: } 215: function changeTitle(val) { 216: if (opener.inf) { 217: if (opener.inf.document.forms.resinfo.elements.t) { 218: opener.inf.document.forms.resinfo.elements.t.value=val; 219: } 220: } 221: } 222: function changeURL(val) { 223: if (opener.inf) { 224: if (opener.inf.document.forms.resinfo.elements.u) { 225: opener.inf.document.forms.resinfo.elements.u.value=val; 226: } 227: } 228: } 229: END 230: } elsif ($mode eq 'edit') { # we are in 'edit' mode 231: my $location = "/adm/groupsort?catalogmode=interactive&"; 232: $location .= "form=$form&element=$element&mode=edit&acts="; 233: $catalogmodefunctions=<<END; 234: // mode = $mode 235: function select_data(title,url) { 236: changeURL(url); 237: self.close(); 238: } 239: 240: function select_group() { 241: window.location="$location"+document.forms.fileattr.acts.value; 242: } 243: 244: function changeURL(val) { 245: if (window.opener.document) { 246: window.opener.document.forms["$form"].elements["$element"].value=val; 247: } else { 248: alert("The file you selected is: "+val); 249: } 250: } 251: 252: END 253: } elsif ($mode eq 'parmset') { 254: my $location = "/adm/groupsort?catalogmode=interactive&"; 255: $location .= "form=$form&element=$element&mode=parmset&acts="; 256: $catalogmodefunctions=<<END; 257: // mode = $mode 258: function select_data(title,url) { 259: changeURL(url); 260: self.close(); 261: } 262: 263: function select_group() { 264: window.location="$location"+document.forms.fileattr.acts.value; 265: } 266: 267: function changeURL(val) { 268: if (window.opener.document) { 269: var elementname = "$element"+"_value"; 270: var checkboxname = "$element"+"_setparmval"; 271: window.opener.document.forms["$form"].elements[elementname].value=val; 272: window.opener.document.forms["$form"].elements[checkboxname].checked=true; 273: } else { 274: alert("The file you selected is: "+val); 275: } 276: } 277: 278: END 279: } 280: } 281: $catalogmodefunctions.=<<END; 282: var acts=''; 283: function rep_dirpath(suffix,val) { 284: eval("document.forms.dirpath"+suffix+".acts.value=val"); 285: } 286: END 287: if ($ENV{'form.catalogmode'} eq 'groupimport') { 288: $catalogmodefunctions.=<<END; 289: function queue(val) { 290: if (eval("document.forms."+val+".filelink.checked")) { 291: var l=val.length; 292: var v=val.substring(4,l); 293: document.forms.fileattr.acts.value+='1a'+v+'b'; 294: } 295: else { 296: var l=val.length; 297: var v=val.substring(4,l); 298: document.forms.fileattr.acts.value+='0a'+v+'b'; 299: } 300: } 301: END 302: } 303: 304: # ---------------------------------------------------------------- Print Header 305: $r->print(<<ENDHEADER); 306: <html> 307: <head> 308: <title>The LearningOnline Network With CAPA Directory Browser</title> 309: 310: <script type="text/javascript"> 311: $catalogmodefunctions 312: function openWindow(url, wdwName, w, h, toolbar,scrollbar) { 313: var options = "width=" + w + ",height=" + h + ","; 314: options += "resizable=yes,scrollbars="+scrollbar+",status=no,"; 315: options += "menubar=no,toolbar="+toolbar+",location=no,directories=no"; 316: var newWin = window.open(url, wdwName, options); 317: newWin.focus(); 318: } 319: function gothere(val) { 320: window.location=val+'?acts='+document.forms.fileattr.acts.value; 321: } 322: </script> 323: 324: </head> 325: ENDHEADER 326: $r->print(&Apache::loncommon::bodytag('Browse Resources')); 327: # - Evaluate actions from previous page (both cumulatively and chronologically) 328: if ($ENV{'form.catalogmode'} eq 'groupimport') { 329: my $acts=$ENV{'form.acts'}; 330: my @Acts=split(/b/,$acts); 331: my %ahash; 332: my %achash; 333: my $ac=0; 334: # some initial hashes for working with data 335: foreach (@Acts) { 336: my ($state,$ref)=split(/a/); 337: $ahash{$ref}=$state; 338: $achash{$ref}=$ac; 339: $ac++; 340: } 341: # sorting through the actions and changing the tied database hash 342: foreach (sort {$achash{$a}<=>$achash{$b}} (keys %ahash)) { 343: my $key=$_; 344: if ($ahash{$key} eq '1') { 345: $hash{'store_'.$hash{'pre_'.$key.'_link'}}= 346: $hash{'pre_'.$key.'_title'}; 347: $hash{'storectr_'.$hash{'pre_'.$key.'_link'}}= 348: $hash{'storectr'}+0; 349: $hash{'storectr'}++; 350: } 351: if ($ahash{$key} eq '0') { 352: if ($hash{'store_'.$hash{'pre_'.$key.'_link'}}) { 353: delete $hash{'store_'.$hash{'pre_'.$key.'_link'}}; 354: } 355: } 356: } 357: # deleting the previously cached listing 358: foreach (keys %hash) { 359: if ($_ =~ /^pre_/ && $_ =~/link$/) { 360: my $key = $_; 361: $key =~ s/^pre_//; 362: $key =~ s/_[^_]*$//; 363: delete $hash{'pre_'.$key.'_title'}; 364: delete $hash{'pre_'.$key.'_link'}; 365: } 366: } 367: } 368: 369: # ---------------------------------- get state of file attributes to be showing 370: if ($ENV{'form.attrs'} ne '') { 371: for (my $i=0; $i<=8; $i++) { 372: delete $hash{'display_attrs_'.$i}; 373: if ($ENV{'form.attr'.$i} == 1) { 374: $attrchk[$i] = 'checked'; 375: $hash{'display_attrs_'.$i} = 1; 376: } 377: } 378: } else { 379: for (my $i=0; $i<=8; $i++) { 380: $attrchk[$i] = 'checked' if $hash{'display_attrs_'.$i} == 1; 381: } 382: } 383: # ------------------------------- output state of file attributes to be showing 384: $r->print(<<END); 385: <form method="post" name="fileattr" action="$uri" 386: enctype="application/x-www-form-urlencoded"> 387: <b><font color="#666666">Display file attributes</font></b><br /> 388: <table border=0><tr> 389: <td><input type="checkbox" name="attr0" value="1" $attrchk[0] /> Title</td> 390: <td><input type="checkbox" name="attr1" value="1" $attrchk[1] /> Size</td> 391: <td><input type="checkbox" name="attr2" value="1" $attrchk[2] /> Last access</td> 392: <td><input type="checkbox" name="attr3" value="1" $attrchk[3] /> Last modified</td> 393: <td><input type="checkbox" name="attr8" value="1" $attrchk[8] /> All versions</td></tr><tr> 394: <td><input type="checkbox" name="attr4" value="1" $attrchk[4] /> Author</td> 395: <td><input type="checkbox" name="attr5" value="1" $attrchk[5] /> Keywords</td> 396: <td><input type="checkbox" name="attr6" value="1" $attrchk[6] /> Language</td> 397: <td><input type="checkbox" name="attr7" value="1" $attrchk[7] /> Show Resource</td> 398: <td> </td> 399: </tr></table> 400: <input type="hidden" name="dirPointer" value="on" /> 401: <input type="hidden" name="acts" value="" /> 402: <input type="submit" name="attrs" value="Review" /> 403: <input type="submit" name="attrs" value="Refresh" /> 404: $closebutton 405: $groupimportbutton 406: </form> 407: END 408: 409: # ----------------- output starting row to the indexed file/directory hierarchy 410: my $titleclr="#ddffff"; 411: # $r->print(&initdebug()); 412: # $r->print(&writedebug("Omit:@Omit")) if (@Omit); 413: # $r->print(&writedebug("Only:@Only")) if (@Only); 414: $r->print("<table width='100\%' border=0><tr><td bgcolor=#777777>\n"); 415: $r->print("<table width='100\%' border=0><tr bgcolor=$titleclr>\n"); 416: $r->print("<td $colspan><b>Name</b></td>\n"); 417: $r->print("<td><b>Title</b></td>\n") 418: if ($hash{'display_attrs_0'} == 1); 419: $r->print("<td align=right><b>Size (bytes) ". 420: "</b></td>\n") if ($hash{'display_attrs_1'} == 1); 421: $r->print("<td><b>Last accessed</b></td>\n") 422: if ($hash{'display_attrs_2'} == 1); 423: $r->print("<td><b>Last modified</b></td>\n") 424: if ($hash{'display_attrs_3'} == 1); 425: $r->print("<td><b>Author(s)</b></td>\n") 426: if ($hash{'display_attrs_4'} == 1); 427: $r->print("<td><b>Keywords</b></td>\n") 428: if ($hash{'display_attrs_5'} == 1); 429: $r->print("<td><b>Language</b></td>\n") 430: if ($hash{'display_attrs_6'} == 1); 431: $r->print("<td><b>Resource</b></td>\n") 432: if ($hash{'display_attrs_7'} == 1); 433: $r->print('</tr>'); 434: 435: # ----------------- read in what directories have previously been set to "open" 436: foreach (keys %hash) { 437: if ($_ =~ /^diropen_status_/) { 438: my $key = $_; 439: $key =~ s/^diropen_status_//; 440: $dirs{$key} = $hash{$_}; 441: } 442: } 443: 444: if ($ENV{'form.openuri'}) { # take care of review and refresh options 445: my $uri=$ENV{'form.openuri'}; 446: if (exists($hash{'diropen_status_'.$uri})) { 447: my $cursta = $hash{'diropen_status_'.$uri}; 448: $dirs{$uri} = 'open'; 449: $hash{'diropen_status_'.$uri} = 'open'; 450: if ($cursta eq 'open') { 451: $dirs{$uri} = 'closed'; 452: $hash{'diropen_status_'.$uri} = 'closed'; 453: } 454: } else { 455: $hash{'diropen_status_'.$uri} = 'open'; 456: $dirs{$uri} = 'open'; 457: } 458: } 459: 460: my $bredir = $ENV{'form.dirPointer'}; 461: my $toplevel; 462: my $indent = 0; 463: $uri = $uri.'/' if $uri !~ /.*\/$/; 464: 465: if ($bredir ne 'on') { 466: $hash{'top.level'} = $uri; 467: $toplevel = $uri; 468: 469: } else { 470: $toplevel = $hash{'top.level'}; 471: } 472: 473: # -------------------------------- if not at top level, provide an uplink arrow 474: if ($toplevel ne '/res/'){ 475: my (@uri_com) = split(/\//,$uri); 476: pop @uri_com; 477: my $upone = join('/',@uri_com); 478: my @list = qw (0); 479: &display_line ($r,'opened',$upone.'&viewOneUp',0,$upone,@list); 480: $indent = 1; 481: } 482: 483: # -------- recursively go through all the directories and output as appropriate 484: &scanDir ($r,$toplevel,$indent,\%hash); 485: 486: # ---------------------------- embed hidden information useful for group import 487: $r->print("<form name='fnum'>"); 488: $r->print("<input type='hidden' name='fnum' value='$fnum'></form>"); 489: 490: # -------------------------------------------------------------- end the tables 491: $r->print('</table>'); 492: $r->print('</td></tr></table>'); 493: 494: # --------------------------------------------------- end the output and return 495: $r->print('</body></html>'."\n"); 496: untie(%hash); 497: } else { 498: $r->print('<html><head></head><body>Unable to tie hash to db '. 499: 'file</body></html>'); 500: return OK; 501: } 502: return OK; 503: } 504: 505: # ----------------------------------------------- recursive scan of a directory 506: sub scanDir { 507: my ($r,$startdir,$indent,$hashref)=@_; 508: my ($compuri,$curdir); 509: my $dirptr=16384; 510: $indent++; 511: 512: my %dupdirs = %dirs; 513: my @list=&get_list($r,$startdir); 514: foreach my $line (@list) { 515: my ($strip,$dom,undef,$testdir,undef)=split(/\&/,$line,5); 516: next if $strip =~ /.*\.meta$/; 517: my (@fileparts) = split(/\./,$strip); 518: if ($hash{'display_attrs_8'} != 1) { 519: if (scalar(@fileparts) >= 3) { 520: my $fext = pop @fileparts; 521: my $ov = pop @fileparts; 522: my $fname = join ('.',@fileparts,$fext); 523: next if (grep /\Q$fname\E/,@list and $ov =~ /\d+/); 524: } 525: } 526: 527: if ($dom eq 'domain') { 528: $compuri = join('',$strip,'/'); # dom list has /res/<domain name> 529: $curdir = $compuri; 530: } else { 531: # user, dir & file have name only, i.e., w/o path 532: $compuri = join('',$startdir,$strip,'/'); 533: $curdir = $startdir; 534: } 535: my $diropen = 'closed'; 536: if (($dirptr&$testdir) or ($dom =~ /^(domain|user)$/)) { 537: while (my ($key,$val)= each %dupdirs) { 538: if ($key eq $compuri and $val eq "open") { 539: $diropen = "opened"; 540: delete($dupdirs{$key}); 541: delete($dirs{$key}); 542: } 543: } 544: } 545: &display_line($r,$diropen,$line,$indent,$curdir,$hashref,@list); 546: &scanDir ($r,$compuri,$indent) if $diropen eq 'opened'; 547: } 548: $indent--; 549: } 550: 551: # --------------- get complete matched list based on the uri (returns an array) 552: sub get_list { 553: my ($r,$uri)=@_; 554: my @list; 555: (my $luri = $uri) =~ s/\//_/g; 556: 557: if ($ENV{'form.attrs'} eq 'Refresh') { 558: foreach (keys %hash) { 559: delete $hash{$_} if ($_ =~ /^dirlist_files_/); 560: } 561: } 562: 563: if ($hash{'dirlist_files'.$luri}) { 564: @list = split(/\n/,$hash{'dirlist_files_'.$luri}); 565: } else { 566: @list = &Apache::lonnet::dirlist($uri); 567: $hash{'dirlist_files_'.$luri} = join('\n',@list); 568: } 569: return @list=&match_ext($r,@list); 570: } 571: 572: sub initdebug { 573: return <<ENDJS; 574: <script> 575: var debugging = true; 576: if (debugging) { 577: var debuggingWindow = window.open('','Debug','width=400,height=300',true); 578: } 579: 580: function output(text) { 581: if (debugging) { 582: debuggingWindow.document.writeln(text); 583: } 584: } 585: output("<html><head><title>Debugging Window</title></head><body><pre>"); 586: </script> 587: ENDJS 588: } 589: 590: sub writedebug { 591: my $text = shift; 592: return "<script>output('$text');</script>"; 593: } 594: 595: # -------------------- filters out files based on extensions (returns an array) 596: sub match_ext { 597: my ($r,@packlist)=@_; 598: my @trimlist; 599: my $nextline; 600: my @fileext; 601: my $dirptr=16384; 602: 603: foreach my $line (@packlist) { 604: chomp $line; 605: $line =~ s/^\/home\/httpd\/html//; 606: my @unpackline = split (/\&/,$line); 607: next if ($unpackline[0] eq '.'); 608: next if ($unpackline[0] eq '..'); 609: my @filecom = split (/\./,$unpackline[0]); 610: my $fext = pop(@filecom); 611: my $fnptr = $unpackline[3]&$dirptr; 612: if ($fnptr == 0 and $unpackline[3] ne "") { 613: my $embstyle = &Apache::loncommon::fileembstyle($fext); 614: push @trimlist,$line if (defined($embstyle) && 615: ($embstyle ne 'hdn' or $fext eq 'meta')); 616: } else { 617: push @trimlist,$line; 618: } 619: } 620: @trimlist = sort (@trimlist); 621: return @trimlist; 622: } 623: 624: # ------------------------------- displays one line in appropriate table format 625: sub display_line { 626: my ($r,$diropen,$line,$indent,$startdir,$hashref,@list)=@_; 627: my (@pathfn, $fndir); 628: my $dirptr=16384; 629: my $fileclr="#ffffe6"; 630: my $iconpath= $r->dir_config('lonIconsURL') . '/'; 631: 632: my @filecom = split (/\&/,$line); 633: my @pathcom = split (/\//,$filecom[0]); 634: my $listname = $pathcom[scalar(@pathcom)-1]; 635: my $fnptr = $filecom[3]&$dirptr; 636: my $msg = 'View '.$filecom[0].' resources'; 637: $msg = 'Close '.$filecom[0].' directory' if $diropen eq 'opened'; 638: 639: my $tabtag='</td>'; 640: my $i=0; 641: 642: while ($i<=7) { 643: $tabtag=join('',$tabtag,"<td> </td>") 644: if $hash{'display_attrs_'.$i} == 1; 645: $i++; 646: } 647: 648: my $valign = ($hash{'display_attrs_7'} == 1 ? 'top' : 'bottom'); 649: 650: # display uplink arrow 651: if ($filecom[1] eq 'viewOneUp') { 652: $r->print("<tr bgcolor=$fileclr>$extrafield"); 653: $r->print("<td valign=$valign>\n"); 654: $r->print ('<form method="post" name="dirpathUP" action="'.$startdir. 655: '/" '. 656: 'onSubmit="return rep_dirpath(\'UP\','. 657: 'document.forms.fileattr.acts.value)" '. 658: 'enctype="application/x-www-form-urlencoded"'. 659: '>'."\n"); 660: $r->print ('<input type=hidden name=openuri value="'. 661: $startdir.'">'."\n"); 662: $r->print ('<input type="hidden" name="acts" value="">'."\n"); 663: $r->print ('<input src="'.$iconpath.'arrow_up.gif"'); 664: $r->print (' name="'.$msg.'" height="22" type="image" border="0">'. 665: "\n"); 666: $r->print("Up $tabtag</tr></form>\n"); 667: return OK; 668: } 669: # Do we have permission to look at this? 670: 671: return OK if (!&Apache::lonnet::allowed('bre',$startdir.$filecom[0])); 672: 673: # display domain 674: if ($filecom[1] eq 'domain') { 675: $r->print ('<input type="hidden" name="dirPointer" value="on">'."\n") 676: if ($ENV{'form.dirPointer'} eq "on"); 677: $r->print("<tr bgcolor=$fileclr>$extrafield"); 678: $r->print("<td valign=$valign>"); 679: &begin_form ($r,$filecom[0].'/'); 680: my $anchor = $filecom[0].'/'; 681: $anchor =~ s/\///g; 682: $r->print ('<a name="'.$anchor.'">'); 683: $r->print ('<input type="hidden" name="acts" value="">'); 684: $r->print ('<input src="'.$iconpath.'folder_pointer_'. 685: $diropen.'.gif"'); 686: $r->print (' name="'.$msg.'" height="22" type="image" border="0">'. 687: "\n"); 688: $r->print ('<a href="javascript:gothere(\''.$filecom[0]. 689: '/\')"><img src="'.$iconpath.'server.gif"'); 690: $r->print (' border="0" /></a>'."\n"); 691: $r->print ("Domain - $listname "); 692: if ($Apache::lonnet::domaindescription{$listname}) { 693: $r->print("(".$Apache::lonnet::domaindescription{$listname}. 694: ")"); 695: } 696: $r->print (" $tabtag</tr></form>\n"); 697: return OK; 698: 699: # display user directory 700: } 701: if ($filecom[1] eq 'user') { 702: $r->print("<tr bgcolor=$fileclr>$extrafield"); 703: $r->print("<td valign=$valign nowrap>\n"); 704: my $curdir = $startdir.$filecom[0].'/'; 705: my $anchor = $curdir; 706: $anchor =~ s/\///g; 707: &begin_form ($r,$curdir); 708: $r->print ('<a name="'.$anchor.'"><img src="'.$iconpath. 709: 'whitespace1.gif" border="0" />'."\n"); 710: $r->print ('<input type="hidden" name="acts" value="">'); 711: $r->print ('<input src="'.$iconpath.'folder_pointer_'.$diropen. 712: '.gif"'); 713: $r->print (' name="'.$msg.'" height="22" type="image" border="0">'. 714: "\n"); 715: $r->print ('<a href="javascript:gothere(\''.$curdir.'\')"><img src='. 716: $iconpath.'quill.gif border="0" name="'.$msg. 717: '" height="22" /></a>'); 718: my $domain=(split(m|/|,$startdir))[2]; 719: my $plainname=&Apache::loncommon::plainname($listname,$domain); 720: $r->print ($listname); 721: if (defined($plainname) && $plainname) { $r->print(" ($plainname) "); } 722: $r->print ($tabtag.'</tr></form>'."\n"); 723: return OK; 724: } 725: 726: # display file 727: if ($fnptr == 0 and $filecom[3] ne '') { 728: my $filelink = $startdir.$filecom[0]; 729: my @file_ext = split (/\./,$listname); 730: my $curfext = $file_ext[-1]; 731: if (@Omit) { 732: foreach (@Omit) { return OK if ($curfext eq $_); } 733: } 734: if (@Only) { 735: my $skip = 1; 736: foreach (@Only) { $skip = 0 if ($curfext eq $_); } 737: return OK if ($skip > 0); 738: } 739: # Set the icon for the file 740: my $iconname = "unknown.gif"; 741: my $embstyle = &Apache::loncommon::fileembstyle($curfext); 742: # The unless conditional that follows is a bit of overkill 743: $iconname = $curfext.".gif" unless 744: (!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn'); 745: # 746: $r->print("<tr bgcolor=$fileclr><td nowrap valign='$valign'>"); 747: my $metafile = grep /^\Q$filecom[0]\E\.meta\&/, @list; 748: my $title; 749: if ($ENV{'form.catalogmode'} eq 'interactive') { 750: $title=$listname; 751: $title = &Apache::lonnet::metadata($filelink,'title') 752: if ($metafile == 1); 753: $title=$listname unless $title; 754: my $titleesc=HTML::Entities::encode($title); 755: $titleesc=~s/\'/\\'/; #' (clean up this spare quote) 756: $r->print("<a href=\"javascript:select_data(\'", 757: $titleesc,"','",$filelink,"')\">"); 758: $r->print("<img src='",$iconpath,"select.gif' border='0' /></a>". 759: "\n"); 760: $r->print("</td><td valign='$valign' nowrap>"); 761: } 762: elsif ($ENV{'form.catalogmode'} eq 'groupimport') { 763: $title=$listname; 764: $title = &Apache::lonnet::metadata($filelink,'title') 765: if ($metafile == 1); 766: $title=$listname unless $title; 767: my $titleesc=&HTML::Entities::encode($title); 768: $r->print("<form name='form$fnum'>\n"); 769: $r->print("<input type='checkbox' name='filelink"."' ". 770: "value='$filelink' onClick='". 771: "javascript:queue(\"form$fnum\")' "); 772: if ($hash{'store_'.$filelink}) { 773: $r->print("checked"); 774: } 775: $r->print(">\n"); 776: $r->print("<input type='hidden' name='title"."' ". 777: "value='$titleesc'>\n"); 778: $r->print("</form>\n"); 779: $r->print("</td><td valign='$valign' nowrap>"); 780: $hash{"pre_${fnum}_link"}=$filelink; 781: $hash{"pre_${fnum}_title"}=$titleesc; 782: $fnum++; 783: } 784: 785: if ($indent > 0 and $indent < 11) { 786: $r->print("<img src=",$iconpath,"whitespace",$indent, 787: ".gif border='0' />\n"); 788: } elsif ($indent >0) { 789: my $ten = int($indent/10.); 790: my $rem = $indent%10.0; 791: my $count = 0; 792: while ($count < $ten) { 793: $r->print("<img src=",$iconpath, 794: "whitespace10.gif border='0' />\n"); 795: $count++; 796: } 797: $r->print("<img src=",$iconpath,"whitespace",$rem, 798: ".gif border='0' />\n") if $rem > 0; 799: } 800: 801: $r->print("<img src=$iconpath$iconname border='0' />\n"); 802: $r->print (" <a href=\"javascript:openWindow('".$filelink. 803: "', 'metadatafile', '450', '500', 'no', 'yes')\";". 804: " TARGET=_self>$listname</a> "); 805: 806: $r->print (" (<a href=\"javascript:openWindow('".$filelink. 807: ".meta', 'metadatafile', '400', '450', 'no', 'yes')\"; ". 808: "TARGET=_self>metadata</a>) ") if ($metafile == 1); 809: 810: $r->print("</td>\n"); 811: if ($hash{'display_attrs_0'} == 1) { 812: my $title = &Apache::lonnet::metadata($filelink,'title') 813: if ($metafile == 1); 814: $r->print('<td valign=$valign> '.($title eq '' ? ' ' : $title). 815: ' </td>'."\n"); 816: } 817: $r->print('<td align=right valign=$valign> ', 818: $filecom[8]," </td>\n") 819: if $hash{'display_attrs_1'} == 1; 820: $r->print('<td valign=$valign> '. 821: (localtime($filecom[9]))." </td>\n") 822: if $hash{'display_attrs_2'} == 1; 823: $r->print('<td valign=$valign> '. 824: (localtime($filecom[10]))." </td>\n") 825: if $hash{'display_attrs_3'} == 1; 826: 827: if ($hash{'display_attrs_4'} == 1) { 828: my $author = &Apache::lonnet::metadata($filelink,'author') 829: if ($metafile == 1); 830: $r->print('<td valign=$valign> '.($author eq '' ? ' ' : $author). 831: " </td>\n"); 832: } 833: if ($hash{'display_attrs_5'} == 1) { 834: my $keywords = &Apache::lonnet::metadata($filelink,'keywords') 835: if ($metafile == 1); 836: # $keywords = ' ' if (!$keywords); 837: $r->print('<td valign=$valign> '.($keywords eq '' ? ' ' : $keywords). 838: " </td>\n"); 839: } 840: if ($hash{'display_attrs_6'} == 1) { 841: my $lang = &Apache::lonnet::metadata($filelink,'language') 842: if ($metafile == 1); 843: $lang = &Apache::loncommon::languagedescription($lang); 844: $r->print('<td valign=$valign> '.($lang eq '' ? ' ' : $lang). 845: " </td>\n"); 846: } 847: if ($hash{'display_attrs_7'} == 1) { 848: my $output=''; 849: my $embstyle=&Apache::loncommon::fileembstyle($curfext); 850: if ($embstyle eq 'ssi') { 851: $output=&Apache::lonnet::ssi_body($filelink); 852: $output='<font size="-2">'.$output.'</font>'; 853: } elsif ($embstyle eq 'img') { 854: $output='<img src="'.$filelink.'" />'; 855: } elsif ($filelink=~/^\/res\/(\w+)\/(\w+)\//) { 856: $output='<img src="http://'. 857: $Apache::lonnet::hostname{&Apache::lonnet::homeserver($2,$1)}. 858: '/cgi-bin/thumbnail.gif?url='.$filelink.'" />'; 859: } 860: $r->print('<td valign=$valign> '.($output eq '' ? ' ':$output). 861: " </td>\n"); 862: } 863: $r->print("</tr>\n"); 864: } 865: 866: # -- display directory 867: if ($fnptr == $dirptr) { 868: my @file_ext = split (/\./,$listname); 869: my $curfext = $file_ext[scalar(@file_ext)-1]; 870: my $curdir = $startdir.$filecom[0].'/'; 871: my $anchor = $curdir; 872: $anchor =~ s/\///g; 873: $r->print("<tr bgcolor=$fileclr>$extrafield<td valign=$valign>"); 874: &begin_form ($r,$curdir); 875: my $indentm1 = $indent-1; 876: if ($indentm1 < 11 and $indentm1 > 0) { 877: $r->print("<img src=",$iconpath,"whitespace",$indentm1, 878: ".gif border='0' />\n"); 879: } else { 880: my $ten = int($indentm1/10.); 881: my $rem = $indentm1%10.0; 882: my $count = 0; 883: while ($count < $ten) { 884: $r->print ("<img src=",$iconpath 885: ,"whitespace10.gif border='0' />\n"); 886: $count++; 887: } 888: $r->print ("<img src=",$iconpath,"whitespace",$rem, 889: ".gif border='0' />\n") if $rem > 0; 890: } 891: $r->print ('<input type="hidden" name="acts" value="">'); 892: $r->print ('<a name="'.$anchor.'"><input src="'.$iconpath. 893: 'folder_pointer_'.$diropen.'.gif"'); 894: $r->print (' name="'.$msg.'" height="22" type="image" border="0">'. 895: "\n"); 896: $r->print ('<a href="javascript:gothere(\''.$curdir.'\')"><img src="'. 897: $iconpath.'folder_'.$diropen.'.gif" border="0" /></a>'. 898: "\n"); 899: $r->print ("$listname$tabtag</tr></form>\n"); 900: } 901: 902: } 903: 904: # ------------------- prints the beginning of a form for directory or file link 905: sub begin_form { 906: my ($r,$uri) = @_; 907: my $anchor = $uri; 908: $anchor =~ s/\///g; 909: $r->print ('<form method="post" name="dirpath'.$dnum.'" action="'.$uri. 910: '#'.$anchor. 911: '" onSubmit="return rep_dirpath(\''.$dnum.'\''. 912: ',document.forms.fileattr.acts.value)" '. 913: 'enctype="application/x-www-form-urlencoded">'."\n"); 914: $r->print ('<input type="hidden" name="openuri" value="'.$uri.'">'. 915: "\n"); 916: $r->print ('<input type="hidden" name="dirPointer" value="on">'."\n"); 917: $dnum++; 918: } 919: 920: # --------- settings whenever the user causes the indexer window to be launched 921: sub start_fresh_session { 922: delete $hash{'form.catalogmode'}; 923: delete $hash{'form.mode'}; 924: delete $hash{'form.form'}; 925: delete $hash{'form.element'}; 926: delete $hash{'form.omit'}; 927: delete $hash{'form.only'}; 928: foreach (keys %hash) { 929: delete $hash{$_} if (/^(pre_|store)/); 930: } 931: } 932: 933: # ------------------------------------------------------------------- setvalues 934: sub setvalues { 935: # setvalues is used in registerurl to synchronize the database 936: # hash and environment hashes 937: my ($H1,$h1key,$H2,$h2key) =@_; 938: # 939: if (exists $H2->{$h2key}) { 940: $H1->{$h1key} = $H2->{$h2key}; 941: } elsif (exists $H1->{$h1key}) { 942: $H2->{$h2key} = $H1->{$h1key}; 943: } 944: } 945: 946: 1; 947: 948: sub cleanup { 949: if (tied(%hash)){ 950: &Apache::lonnet::logthis('Cleanup indexer: hash'); 951: unless (untie(%hash)) { 952: &Apache::lonnet::logthis('Failed cleanup indexer: hash'); 953: } 954: } 955: } 956: 957: =head1 NAME 958: 959: Apache::lonindexer - mod_perl module for cross server filesystem browsing 960: 961: =head1 SYNOPSIS 962: 963: Invoked by /etc/httpd/conf/srm.conf: 964: 965: <LocationMatch "^/res.*/$"> 966: SetHandler perl-script 967: PerlHandler Apache::lonindexer 968: </LocationMatch> 969: 970: =head1 INTRODUCTION 971: 972: This module enables a scheme of browsing across a cross server. 973: 974: This is part of the LearningOnline Network with CAPA project 975: described at http://www.lon-capa.org. 976: 977: =head1 BEGIN SUBROUTINE 978: 979: This routine is only run once after compilation. 980: 981: =over 4 982: 983: =item * 984: 985: Initializes %language hash table. 986: 987: =back 988: 989: =head1 HANDLER SUBROUTINE 990: 991: This routine is called by Apache and mod_perl. 992: 993: =over 4 994: 995: =item * 996: 997: read in machine configuration variables 998: 999: =item * 1000: 1001: see if called from an interactive mode 1002: 1003: =item * 1004: 1005: refresh environment with user database values (in %hash) 1006: 1007: =item * 1008: 1009: define extra fields and buttons in case of special mode 1010: 1011: =item * 1012: 1013: set catalogmodefunctions to have extra needed javascript functionality 1014: 1015: =item * 1016: 1017: print header 1018: 1019: =item * 1020: 1021: evaluate actions from previous page (both cumulatively and chronologically) 1022: 1023: =item * 1024: 1025: output title 1026: 1027: =item * 1028: 1029: get state of file attributes to be showing 1030: 1031: =item * 1032: 1033: output state of file attributes to be showing 1034: 1035: =item * 1036: 1037: output starting row to the indexed file/directory hierarchy 1038: 1039: =item * 1040: 1041: read in what directories have previously been set to "open" 1042: 1043: =item * 1044: 1045: if not at top level, provide an uplink arrow 1046: 1047: =item * 1048: 1049: recursively go through all the directories and output as appropriate 1050: 1051: =item * 1052: 1053: information useful for group import 1054: 1055: =item * 1056: 1057: end the tables 1058: 1059: =item * 1060: 1061: end the output and return 1062: 1063: =back 1064: 1065: =head1 OTHER SUBROUTINES 1066: 1067: =over 4 1068: 1069: =item * 1070: 1071: scanDir - recursive scan of a directory 1072: 1073: =item * 1074: 1075: get_list - get complete matched list based on the uri (returns an array) 1076: 1077: =item * 1078: 1079: match_ext - filters out files based on extensions (returns an array) 1080: 1081: =item * 1082: 1083: display_line - displays one line in appropriate table format 1084: 1085: =item * 1086: 1087: begin_form - prints the beginning of a form for directory or file link 1088: 1089: =item * 1090: 1091: start_fresh_session - settings whenever the user causes the indexer window 1092: to be launched 1093: 1094: =back 1095: 1096: =cut