Diff for /loncom/interface/lonsearchcat.pm between versions 1.143 and 1.145

version 1.143, 2002/07/16 15:02:06 version 1.145, 2002/07/28 20:02:14
Line 87  use Apache::lonnet(); Line 87  use Apache::lonnet();
 use Apache::File();  use Apache::File();
 use CGI qw(:standard);  use CGI qw(:standard);
 use Text::Query;  use Text::Query;
   use DBI;
 use GDBM_File;  use GDBM_File;
 use Apache::loncommon();  use Apache::loncommon();
   use Apache::lonmysql();
   
 # ---------------------------------------- variables used throughout the module  # ---------------------------------------- variables used throughout the module
   
Line 101  use Apache::loncommon(); Line 103  use Apache::loncommon();
   
 =over 4  =over 4
   
 =item $closebutton  
   
 button that closes the search window  
   
 =item $importbutton  =item $importbutton
   
 button to take the select results and go to group sorting  button to take the select results and go to group sorting
Line 125  that produces it.  Adding a new view typ Line 123  that produces it.  Adding a new view typ
 adding a line to the definition of this hash and making sure the function  adding a line to the definition of this hash and making sure the function
 takes the proper parameters.  takes the proper parameters.
   
 =item $results_db  
   
 The name of the database results from searches are put in.  
   
 =back   =back 
   
 =cut  =cut
Line 137  The name of the database results from se Line 131  The name of the database results from se
 ######################################################################  ######################################################################
   
 # -- dynamically rendered interface components  # -- dynamically rendered interface components
 my $closebutton;  # button that closes the search window  
 my $importbutton; # button to take the selected results and go to group sorting  my $importbutton; # button to take the selected results and go to group sorting
   
 # -- miscellaneous variables  # -- miscellaneous variables
 my %groupsearch_db;     # database hash  my %groupsearch_db;     # database hash
 my $diropendb = "";    # db file  my $diropendb = "";    # db file
   
 my $results_db = "";  
 #             View Description           Function Pointer  #             View Description           Function Pointer
 my %Views = ("Detailed Citation View" => \&detailed_citation_view,  my %Views = ("Detailed Citation View" => \&detailed_citation_view,
              "Summary View"           => \&summary_view,               "Summary View"           => \&summary_view,
              "Fielded Format"         => \&fielded_format_view,               "Fielded Format"         => \&fielded_format_view,
              "XML/SGML"               => \&xml_sgml_view );               "XML/SGML"               => \&xml_sgml_view );
   my $persistent_db_file;
   my %persistent_db;
   my $hidden_fields;
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 178  string that holds portions of the screen Line 171  string that holds portions of the screen
 ######################################################################  ######################################################################
 sub handler {  sub handler {
     my $r = shift;      my $r = shift;
     untie %groupsearch_db;      #
       untie %groupsearch_db if (tied(%groupsearch_db));
       #
       my $closebutton;  # button that closes the search window 
                         # This button is different for the RAT compared to
                         # normal invocation.
       #
     $r->content_type('text/html');      $r->content_type('text/html');
     $r->send_http_header;      $r->send_http_header;
     return OK if $r->header_only;      return OK if $r->header_only;
       ## 
       ## Pick up form fields passed in the links.
       ##
       &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                ['catalogmode','launch','acts','mode','form','element',
                 'reqinterface','persistent_db_id','table']);
     ##      ##
     ## Initialize global variables      ## Initialize global variables
     ##      ##
     my $domain  = $r->dir_config('lonDefDomain');      my $domain  = $r->dir_config('lonDefDomain');
     $diropendb= "/home/httpd/perl/tmp/".&Apache::lonnet::escape($domain).      $diropendb= "/home/httpd/perl/tmp/".&Apache::lonnet::escape($domain).
             "\_".&Apache::lonnet::escape($ENV{'user.name'})."_searchcat.db";              "\_".&Apache::lonnet::escape($ENV{'user.name'})."_searchcat.db";
     $results_db = "/home/httpd/perl/tmp/".&Apache::lonnet::escape($domain).      #
         '_'.&Apache::lonnet::escape($ENV{'user.name'})."_searchresults.db";      # set the name of the persistent database
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},      # $ENV{'form.persistent_db_id'} can only have digits in it.
              ['catalogmode','launch','acts','mode','form','element',      if (! exists($ENV{'form.persistent_db_id'}) ||
               'reqinterface']);              $ENV{'form.persistent_db_id'} =~ /\D/ ) {
           $ENV{'form.persistent_db_id'} = time;
       }
       $persistent_db_file = "/home/httpd/perl/tmp/".
           &Apache::lonnet::escape($domain).
               '_'.&Apache::lonnet::escape($ENV{'user.name'}).
                   '_'.$ENV{'form.persistent_db_id'}.'_persistent_search.db';
       #
       # Read in the database.  It should (hopefully) not be catastrophic to
       #    fail in this exercise. 
       if (-e $persistent_db_file) {
           # Read in the previous values, if we can.
    if (tie(%persistent_db,'GDBM_File',$persistent_db_file,
                   &GDBM_READER,0640)) {
               &reconstruct_persistent_form_data($r);
               untie (%persistent_db);
    }
       }
     ##      ##
     ## Clear out old values from groupsearch database      ## Clear out old values from groupsearch database
     ##      ##
Line 208  sub handler { Line 229  sub handler {
  }   }
     }      }
     ##      ##
     ## Produce some output, so people know it is working  
     ##  
     $r->print("\n");  
     $r->rflush;  
     ##  
     ## Configure dynamic components of interface      ## Configure dynamic components of interface
     ##      ##
     my $hidden;       # Holds 'hidden' html forms      $hidden_fields = '<input type="hidden" name="persistent_db_id" value="'.
           $ENV{'form.persistent_db_id'}.'" />';
     if ($ENV{'form.catalogmode'} eq 'interactive') {      if ($ENV{'form.catalogmode'} eq 'interactive') {
  $hidden="<input type='hidden' name='catalogmode' value='interactive'>".  
     "\n";  
         $closebutton="<input type='button' name='close' value='CLOSE' ".          $closebutton="<input type='button' name='close' value='CLOSE' ".
     "onClick='self.close()'>"."\n";      "onClick='self.close()'>"."\n";
     } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') {      } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') {
  $hidden=<<END;  
 <input type='hidden' name='catalogmode' value='groupsearch'>  
 END  
         $closebutton=<<END;          $closebutton=<<END;
 <input type='button' name='close' value='CLOSE' onClick='self.close()'>  <input type='button' name='close' value='CLOSE' onClick='self.close()'>
 END  END
Line 233  END Line 245  END
 onClick='javascript:select_group()'>  onClick='javascript:select_group()'>
 END  END
     }      }
     $hidden .= &make_persistent({ "form.mode"    => $ENV{'form.mode'},  
                                   "form.form"    => $ENV{'form.form'},  
                                   "form.element" => $ENV{'form.element'},  
                                   "form.date"    => 2 });  
     ##      ##
     ##  What are we doing?      ##  Do a search, if needed.
     ##      ##
     my $searchtype;      my $searchtype;
     $searchtype = 'Basic'    if ($ENV{'form.basicsubmit'}    eq 'SEARCH');      $searchtype = 'Basic'    if ($ENV{'form.basicsubmit'}    eq 'SEARCH');
     $searchtype = 'Advanced' if ($ENV{'form.advancedsubmit'} eq 'SEARCH');      $searchtype = 'Advanced' if ($ENV{'form.advancedsubmit'} eq 'SEARCH');
     if ($searchtype) {      if ($searchtype) {
           ##
           ## make query information persistent to allow for subsequent revision
           ##
           tie(%persistent_db,'GDBM_File',$persistent_db_file,&GDBM_WRCREAT,0640);
           &make_persistent(\%ENV);
           untie(%persistent_db);
           #
         # We are running a search          # We are running a search
         my ($query,$customquery,$customshow,$libraries) =           my ($query,$customquery,$customshow,$libraries) = 
             (undef,undef,undef,undef);              (undef,undef,undef,undef);
         my $pretty_string;          my $pretty_string;
         if ($searchtype eq 'Basic') {          if ($searchtype eq 'Basic') {
             ($query,$pretty_string) = &parse_basic_search($r);              ($query,$pretty_string) = &parse_basic_search($r,$closebutton);
         } elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') {          } elsif ($ENV{'form.advancedsubmit'} eq 'SEARCH') {
             ($query,$customquery,$customshow,$libraries,$pretty_string)               ($query,$customquery,$customshow,$libraries,$pretty_string) 
                 = &parse_advanced_search($r);                  = &parse_advanced_search($r,$closebutton);
             return OK if (! defined($query));              return OK if (! defined($query));
         }          }
         # Output some information to the user.          # Output some information to the user.
         $r->print(&search_results_header($searchtype,$pretty_string));          $r->print(&search_results_header($searchtype,$pretty_string));
         $r->print("Sending search request to LON-CAPA servers.<br />\n");          $r->print("Sending search request to LON-CAPA servers.<br />\n");
         $r->rflush();          $r->rflush();
         # Send query statements over the network to be processed by           &run_search($r,$query,$customquery,$customshow,$libraries);
         # either the SQL database or a recursive scheme of 'grep'-like           ##
         # actions (for custom metadata).          ## Display the results
         my $reply=&Apache::lonnet::metadata_query($query,$customquery,          ##
                                                $customshow,$libraries);          &display_results($r,$searchtype,$importbutton,$closebutton);
         $r->rflush();          $r->rflush();
         &output_results($searchtype,$r,$reply,$hidden);  
     } else {      } else {
         #          #
         # We need to get information to search on  
         #  
         # Set the default view if it is not already set.          # Set the default view if it is not already set.
         if (!defined($ENV{'form.viewselect'})) {          if (!defined($ENV{'form.viewselect'})) {
             $ENV{'form.viewselect'} ="Detailed Citation View";              $ENV{'form.viewselect'} ="Detailed Citation View";
         }          }
         # Output the advanced interface          # 
         if ($ENV{'form.reqinterface'} eq 'advanced') {          # remove the requested interface from the environment.
             $r->print(&advanced_search_form($closebutton,$hidden));          my $interface;
         } else {           if ($ENV{'form.reqinterface'}) {
               $interface = lc($ENV{'form.reqinterface'});
           } else {
               $interface = 'basic';
           }
           ##
           ## Determine course of action
           ##
           if ($interface eq 'display') {
               # &display_results($closebutton));
           } elsif ($interface eq 'advanced') {
               $r->print(&advanced_search_form($closebutton));
           } elsif ($interface eq 'basic') { 
             # Output normal search interface              # Output normal search interface
             $r->print(&basic_search_form($closebutton,$hidden));              $r->print(&basic_search_form($closebutton));
         }          }
     }      }
       untie (%persistent_db);
     return OK;      return OK;
 }   } 
   
Line 300  Returns a scalar which holds html for th Line 325  Returns a scalar which holds html for th
 ######################################################################  ######################################################################
   
 sub basic_search_form{  sub basic_search_form{
     my ($closebutton,$hidden) = @_;      my ($closebutton) = @_;
     my $scrout=<<"ENDDOCUMENT";      my $scrout=<<"ENDDOCUMENT";
 <html>  <html>
 <head>  <head>
Line 317  sub basic_search_form{ Line 342  sub basic_search_form{
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  <img align='right' src='/adm/lonIcons/lonlogos.gif' />
 <h1>Search Catalog</h1>  <h1>Search Catalog</h1>
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 $hidden  $hidden_fields
 <h3>Basic Search</h3>  <h3>Basic Search</h3>
 <p>  <p>
 Enter terms or phrases separated by AND, OR, or NOT   Enter terms or phrases separated by AND, OR, or NOT 
Line 369  Returns a scalar which holds html for th Line 394  Returns a scalar which holds html for th
 ######################################################################  ######################################################################
   
 sub advanced_search_form{  sub advanced_search_form{
     my ($closebutton,$hidden) = @_;      my ($closebutton) = @_;
     my $advanced_buttons = <<"END";      my $advanced_buttons = <<"END";
 <p>  <p>
 <input type="submit" name="advancedsubmit" value='SEARCH' />  <input type="submit" name="advancedsubmit" value='SEARCH' />
Line 401  Enter terms or phrases separated by sear Line 426  Enter terms or phrases separated by sear
 such as AND, OR, or NOT.<br />  such as AND, OR, or NOT.<br />
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 $advanced_buttons  $advanced_buttons
 $hidden  $hidden_fields
 <table>  <table>
 <tr><td><font color="#800000" face="helvetica"><b>VIEW:</b></font></td>  <tr><td><font color="#800000" face="helvetica"><b>VIEW:</b></font></td>
 <td>  <td>
Line 453  ENDHEADER Line 478  ENDHEADER
     # adjust the size of the select box      # adjust the size of the select box
     my $size = 4;      my $size = 4;
     my $size = (scalar @domains < ($size - 1) ? scalar @domains + 1 : $size);      my $size = (scalar @domains < ($size - 1) ? scalar @domains + 1 : $size);
     # standalone machines do not get to choose a domain to search.      $scrout.="\n".'<font color="#800000" face="helvetica"><b>'.
     if ((scalar @domains) == 1) {          'DOMAINS</b></font><br />'.
         $scrout .='<input type="hidden" name="domains" value="any" />'."\n";              '<select name="domains" size="'.$size.'" multiple>'."\n".
     } else {                  '<option name="any" value="any" '.
         $scrout.="\n".'<font color="#800000" face="helvetica"><b>'.                      ($domain_hash{'any'}? 'selected ' :'').
             'DOMAINS</b></font><br />'.  
                 '<select name="domains" size="'.$size.'" multiple>'."\n".  
                     '<option name="any" value="any" '.  
                         ($domain_hash{'any'}? 'selected ' :'').  
                         '>all domains</option>'."\n";                          '>all domains</option>'."\n";
         foreach my $dom (sort @domains) {      foreach my $dom (sort @domains) {
             $scrout.="<option name=\"$dom\" ".          $scrout.="<option name=\"$dom\" ".
                 ($domain_hash{$dom} ? 'selected ' :'').">$dom</option>\n";              ($domain_hash{$dom} ? 'selected ' :'').">$dom</option>\n";
         }  
         $scrout.="</select>\n";  
     }      }
       $scrout.="</select>\n";
     #----------------------------------------------------------------      #----------------------------------------------------------------
     $scrout.=&selectbox('Limit by language','language',      $scrout.=&selectbox('Limit by language','language',
  $ENV{'form.language'},'any','Any Language',   $ENV{'form.language'},'any','Any Language',
Line 556  ENDDOCUMENT Line 576  ENDDOCUMENT
   
 =pod   =pod 
   
 =item &make_persistent()   =item &reconstruct_persistent_form_data
   
 Returns a scalar which holds the current ENV{'form.*'} values in  This function is the reverse of &make_persistent();
 a 'hidden' html input tag.  This allows search interface information  Retrieve persistent data from %persistent_db.  Retrieved items will have their
 to be somewhat persistent.  values unescaped.  If the item contains commas (before unescaping), the
   returned value will be an array pointer.  Items will be returned in the
   environment in $ENV{"form.$name"}.
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   sub reconstruct_persistent_form_data {
       foreach my $name (keys %persistent_db) {
           # &Apache::lonnet::logthis("Reconstructing $name = $persistent_db{$name}");
           my @Values = split(',',$persistent_db{$name});
           my @value = map { &Apache::lonnet::unescape($_) } @Values;
           $name = 'form.'.$name;
           if (exists($ENV{$name})) {
               if (ref($ENV{$name})) {
                   # Assume it is an array reference
                   $ENV{$name} = [@{$ENV{$name}},@value];
               } else {
                   $ENV{$name} = [$ENV{$name},@value];
               }
           } else {
               if (@value > 1) {
                   $ENV{$name} = [@value];
               } else {
                   $ENV{$name} = $value[0];
               }
           }
       }
       return;
   }
   
   ######################################################################
   ######################################################################
   
   =pod 
   
   =item &make_persistent() 
   
   Store (environment) variables away to the %persistent_db.  
   Values will be escaped.  Values that are array pointers will have their
   elements escaped and concatenated in a comma seperated string.  
   
   =cut
   
   ######################################################################
   ######################################################################
 sub make_persistent {  sub make_persistent {
     my %save = %{shift()};      my %save = %{shift()};
     my $persistent='';  
     foreach my $name (keys %save) {      foreach my $name (keys %save) {
  if ($name =~ /^form\./ && $name !~ /submit/) {          next if ($name !~ /^form\./ || $name =~ /submit/);
             my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));          my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));
     $name=~s/^form\.//;          # We handle array references, but not recursively.
             foreach (@values) {          my $store = join(',', map { &Apache::lonnet::escape($_); } @values );
                 s/\"/\'/g; # do not mess with html field syntax          $name=~s/^form\.//;
                 next if (! $_ );          $persistent_db{$name} = $store;
                 $persistent.=<<END;  
 <input type="hidden" name="$name" value="$_" />  
 END  
             }  
         }  
     }      }
     return $persistent;      return '';
 }  }
   
 ######################################################################  ######################################################################
Line 893  Parse advanced search form and return th Line 947  Parse advanced search form and return th
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub parse_advanced_search {  sub parse_advanced_search {
     my ($r)=@_;      my ($r,$closebutton)=@_;
     my $fillflag=0;      my $fillflag=0;
     my $pretty_search_string = "<br />\n";      my $pretty_search_string = "<br />\n";
     # Clean up fields for safety      # Clean up fields for safety
Line 929  sub parse_advanced_search { Line 983  sub parse_advanced_search {
  }   }
     }      }
     unless ($fillflag) {      unless ($fillflag) {
  &output_blank_field_error($r);   &output_blank_field_error($r,$closebutton);
  return ;   return ;
     }      }
     # Turn the form input into a SQL-based query      # Turn the form input into a SQL-based query
Line 992  sub parse_advanced_search { Line 1046  sub parse_advanced_search {
  );   );
     # Test to see if date windows are legitimate      # Test to see if date windows are legitimate
     if ($datequery=~/^Incorrect/) {      if ($datequery=~/^Incorrect/) {
  &output_date_error($r,$datequery);   &output_date_error($r,$datequery,$closebutton);
  return ;   return ;
     } elsif ($datequery) {      } elsif ($datequery) {
         # Here is where you would set up pretty_search_string to output          # Here is where you would set up pretty_search_string to output
Line 1072  Parse the basic search form and return a Line 1126  Parse the basic search form and return a
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub parse_basic_search {  sub parse_basic_search {
     my ($r)=@_;      my ($r,$closebutton)=@_;
     # Clean up fields for safety      # Clean up fields for safety
     for my $field ('basicexp') {      for my $field ('basicexp') {
  $ENV{"form.$field"}=~s/[^\w\s\(\)\-]//g;   $ENV{"form.$field"}=~s/[^\w\s\(\)\-]//g;
Line 1086  sub parse_basic_search { Line 1140  sub parse_basic_search {
   
     # Check to see if enough is filled in      # Check to see if enough is filled in
     unless (&filled($ENV{'form.basicexp'})) {      unless (&filled($ENV{'form.basicexp'})) {
  &output_blank_field_error($r);   &output_blank_field_error($r,$closebutton);
  return OK;   return OK;
     }      }
     my $pretty_search_string = '<b>'.$ENV{'form.basicexp'}.'</b>';      my $pretty_search_string = '<b>'.$ENV{'form.basicexp'}.'</b>';
Line 1100  sub parse_basic_search { Line 1154  sub parse_basic_search {
             $pretty_search_string .= " with no related words.";              $pretty_search_string .= " with no related words.";
         }          }
     }      }
     &Apache::lonnet::logthis("Search String: $search_string");  
     # Build SQL query string based on form page      # Build SQL query string based on form page
     my $query='';      my $query='';
     my $concatarg=join(',"    ",',      my $concatarg=join(',"    ",',
Line 1315  sub build_date_queries { Line 1368  sub build_date_queries {
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 =pod   =pod
   
   =item &copyright_check()
   
   =cut
   
   ######################################################################
   ######################################################################
   
   sub copyright_check {
       my $Metadata = shift;
       # Check copyright tags and skip results the user cannot use
       my (undef,undef,$resdom,$resname) = split('/',
                                                 $Metadata->{'url'});
       # Check for priv
       if (($Metadata->{'copyright'} eq 'priv') && 
           (($ENV{'user.name'} ne $resname) &&
            ($ENV{'user.domain'} ne $resdom))) {
           return 0;
       }
       # Check for domain
       if (($Metadata->{'copyright'} eq 'domain') &&
           ($ENV{'user.domain'} ne $resdom)) {
           return 0;
       }
       return 1;
   }
   
   #####################################################################
   #####################################################################
   
   =pod
   
   =item MySQL Table Description
   
   MySQL table creation requires a precise description of the data to be
   stored.  The use of the correct types to hold data is vital to efficient
   storage and quick retrieval of records.  The columns must be described in
   the following format:
   
   =cut
   
   ##
   ## Restrictions:
   ##    columns of type 'text' and 'blob' cannot have defaults.
   ##    columns of type 'enum' cannot be used for FULLTEXT.
   ##
   my @DataOrder = qw/id title author subject url keywords version notes
       abstract mime lang owner copyright creationdate lastrevisiondate hostname
       idx_title idx_author idx_subject idx_abstract idx_mime idx_language 
       idx_owner idx_copyright/;
   
   my %Datatypes = 
       ( id        =>{ type         => 'INT',
                       restrictions => 'NOT NULL',
                       primary_key  => 'yes',
                       auto_inc     => 'yes'
                       },
         title     =>{ type=>'TEXT'},
         author    =>{ type=>'TEXT'},
         subject   =>{ type=>'TEXT'},
         url       =>{ type=>'TEXT',
                       restrictions => 'NOT NULL' },
         keywords  =>{ type=>'TEXT'},
         version   =>{ type=>'TEXT'},
         notes     =>{ type=>'TEXT'},
         abstract  =>{ type=>'TEXT'},
         mime      =>{ type=>'TEXT'},
         lang      =>{ type=>'TEXT'},
         owner     =>{ type=>'TEXT'},
         copyright =>{ type=>'TEXT'},
         hostname  =>{ type=>'TEXT'},
         #--------------------------------------------------
         creationdate     =>{ type=>'DATETIME'},
         lastrevisiondate =>{ type=>'DATETIME'},
         #--------------------------------------------------
         idx_title     =>{ type=>'FULLTEXT', target=>'title'},
         idx_author    =>{ type=>'FULLTEXT', target=>'author'},
         idx_subject   =>{ type=>'FULLTEXT', target=>'subject'},
         idx_abstract  =>{ type=>'FULLTEXT', target=>'abstract'},
         idx_mime      =>{ type=>'FULLTEXT', target=>'mime'},
         idx_language  =>{ type=>'FULLTEXT', target=>'lang'},
         idx_owner     =>{ type=>'FULLTEXT', target=>'owner'},
         idx_copyright =>{ type=>'FULLTEXT', target=>'copyright'},
         );
   
   ######################################################################
   ######################################################################
   
   =pod
   
   =item &write_status()
   
   =cut
   
   ######################################################################
   ######################################################################
   sub write_status {
       my ($r,$string) = @_;
       $r->print("<pre>".$string."</pre>\n");
       $r->rflush();
       return;
   }
   
   ######################################################################
   ######################################################################
   
   =pod
   
   =item &run_search 
   
   =cut
   
   ######################################################################
   ######################################################################
   sub run_search {
       my ($r,$query,$customquery,$customshow,$serverlist) = @_;
       #
       # Timing variables
       #
       my $starttime = time;
       my $max_time  = 120;  # seconds for the search to complete
       #
       # Determine the servers we need to contact.
       #
       my @Servers_to_contact;
       if (defined($serverlist)) {
           @Servers_to_contact = @$serverlist;
       } else {
           @Servers_to_contact = sort(keys(%Apache::lonnet::libserv));
       }
       my %Server_status;
       #
       # Create Table
       #
       my $table = &Apache::lonmysql::create_table
           ( { columns => \%Datatypes,
               column_order => \@DataOrder,
           } );
       if (! defined($table)) {
           # What do I do now?  Print out an error page.
           &Apache::lonnet::logthis("lonmysql attempted to create a table ".
                                    "and this was the result:".
                                    &Apache::lonmysql::get_error());
           $r->print("An internal error occured with the database.<br />".
                     "The error has been logged, but you should probably alert".
                     " your system administrator.");
           return;
       }
       ##
       ## form.table needs to be stored in the persistent database...
       ## 
       $ENV{'form.table'}=$table;
       #
       # Prepare for the big loop.
       #
       my $hitcountsum;
       my $server; 
       my $status;
       while ((time - $starttime < $max_time) && 
              ((@Servers_to_contact) || keys(%Server_status))) {
           # Send out a search request if it needs to be done.
           if (@Servers_to_contact) {
               # Contact one server
               my $server = shift(@Servers_to_contact);
               my $reply=&Apache::lonnet::metadata_query($query,$customquery,
                                                         $customshow,[$server]);
               ($server) = keys(%$reply);
               $Server_status{$server} = $reply->{$server};
               # &write_status($r,"Contacted:$server:reply:".
               #                   $Server_status{$server});
               if ($max_time - (time - $starttime) < 20) {
                   # If there are less than 20 seconds to go in the search,
                   # give the newly contacted servers 20 more seconds to 
                   # respond....
                   $max_time += 20;
               }
           } else {
               sleep(1); # wait a sec. to give time for files to be written
           }
           while (my ($server,$status) = each(%Server_status)) {
               if ($status eq 'con_lost') {
                   delete ($Server_status{$server});
                   # &write_status($r,"server $server is not responding.");
                   next;
               }
               $status=~/^([\.\w]+)$/; 
              my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$1;
               if (-e $datafile && ! -e "$datafile.end") {
                   # Let the user know we are receiving data from the server
                   # &write_status($r,"$server:Receiving file");
                   next;
               }
               if (-e "$datafile.end") {
                   if (-z "$datafile") {
                       delete($Server_status{$server});
                       next;
                   }
                   my $fh;
                   if (!($fh=Apache::File->new($datafile))) { 
                       # Error opening file...
                       # Tell the user and exit...?
                       # Should I give up on opening it?
                       &write_status("Unable to open search results file for ".
                                     "server $server.  Omitting from search");
                       next;
                   }
                   # Read in the whole file.
                   while (my $result = <$fh>) {
                       # handle custom fields?  Someday we will!
                       chomp($result);
                       next unless $result;
                       # Parse the result.
                       my %Fields = &parse_raw_result($result,$server);
                       $Fields{'hostname'} = $server;
                       next if (! &copyright_check(\%Fields));
                       # Store the result in the mysql database
                       my $result = &Apache::lonmysql::store_row($table,\%Fields);
                       if (! defined($result)) {
                           &write_status($r,&Apache::lonmysql::get_error());
                       }
                       # &write_status($r,&Apache::lonmysql::get_debug());
                       $hitcountsum ++;
                   } # End of foreach (@results)
                   $fh->close();
                   # $server is only deleted if the results file has been 
                   # found and (successfully) opened.  This may be a bad idea.
                   delete($Server_status{$server});
                   #&write_status($r,"Received $new_count more results from ".
                   #              $server.".");
               }
           }
           # Finished looping through the servers
       }
       &Apache::lonmysql::disconnect_from_db();
       # Let the user know
       #
       # We have run out of time or run out of servers to talk to and
       # results to get.  
       &write_status($r,"Search completed.");
       if ($hitcountsum) {
           &write_status($r,$hitcountsum." successful matches to your query.");
       } else {
           &write_status($r,"There were no successful matches to your query.");
       }
       return;
   }
   
   ######################################################################
   ######################################################################
   =pod
   
   =item &display_buttons
   
   =cut
   
   ######################################################################
   ######################################################################
   sub display_buttons {
       my ($current_min,$show,$total,$parms) = @_;
       return '' if ($show eq 'all'); # No links if you get them all at once.
       my $links;
       ##
       ## Prev
       my $prev_min = $current_min - $show;
       $prev_min = 0 if $prev_min < 0;
       if ($prev_min < $current_min) {
           $links .= qq{
   <a href="/adm/searchcat?$parms&startwith=$prev_min&show=$show">prev</a>
   };    
       }
       ##
       ## Pages.... Someday.
       ##
   
       ##
       ## Next
       my $next_min = $current_min + $show;
       my $next_min = $current_min if ($next_min > $total);
       if ($next_min != $current_min) {
           $links .= qq{
   <a href="/adm/searchcat?$parms&startwith=$next_min&show=$show">next</a>
   };    
       }
       return $links;
   }
   ######################################################################
   ######################################################################
   
 =item &output_results()   =pod
   
 Format and output results based on a reply list.  =item &display_results
 There are two windows that this function writes to.  The main search  
 window ("srch") has a listing of the results.  A secondary window ("popwin")  
 gives the status of the network search (time elapsed, number of machines  
 contacted, etc.)  
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub output_results {  sub display_results {
 #    &Apache::lonnet::logthis("output_results:".time);      my ($r,$mode,$importbutton,$closebutton) = @_;
     my $fnum; # search result counter  
     my ($mode,$r,$replyref,$hidden)=@_;  
     my %rhash=%{$replyref};  
     my $compiledresult='';  
     my $timeremain=300; # (seconds)  
     my $elapsetime=0;  
     my $resultflag=0;  
     my $tflag=1;  
     ##      ##
     ## Set viewing function      ## Set viewing function
     ##      ##
Line 1348  sub output_results { Line 1676  sub output_results {
         $r->rflush();          $r->rflush();
         return;          return;
     }      }
     #      ##
     # make query information persistent to allow for subsequent revision      ## Get the catalog controls setup
     my $persistent=&make_persistent(\%ENV);      ##
     #  
     # Begin producing output  
     $r->rflush();  
     #  
     # begin showing the cataloged results  
     my $action = "/adm/searchcat";      my $action = "/adm/searchcat";
     if ($mode eq 'Basic') {       if ($mode eq 'Basic') { 
         $action .= "?reqinterface=basic";          $action .= "?reqinterface=basic";
Line 1364  sub output_results { Line 1687  sub output_results {
     }      }
     $r->print(<<CATALOGCONTROLS);      $r->print(<<CATALOGCONTROLS);
 <form name='results' method="post" action="$action">  <form name='results' method="post" action="$action">
 $hidden  $hidden_fields
 <input type='hidden' name='acts' value='' />  <input type='hidden' name='acts' value='' />
 <input type='button' value='Revise search request'  <input type='button' value='Revise search request'
 onClick='this.form.submit();' />  onClick='this.form.submit();' />
 $importbutton  $importbutton
 $closebutton  $closebutton
 $persistent  
 <hr />  <hr />
 CATALOGCONTROLS  CATALOGCONTROLS
     #      if (! tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT,0640)) {
     # make the pop-up window for status          $r->print('Unable to tie hash to db file</body></html>');
     $r->print(&make_popwin(%rhash));          $r->rflush();
     $r->rflush();          return;
       } 
     ##      ##
     ## Prepare for the main loop below      ## Prepare the table for querying
     ##      ##
     my $servercount=0;      my $table = $ENV{'form.table'};
     my $hitcountsum=0;      my $connection_result = &Apache::lonmysql::connect_to_db();
     my $servernum=(keys %rhash);      if (!defined($connection_result)) {
     my $serversleft=$servernum;          &write_status($r,&Apache::lonmysql::get_error());
     ##      }
     ## Run until we run out of time or we run out of servers      my $table_check = &Apache::lonmysql::check_table($table);
     ##      if (! defined($table_check)) {
     while($serversleft && $timeremain) {          $r->print("A MySQL error has occurred.</body></html>");
       ##          &Apache::lonnet::logthis("lonmysql was unable to determine the status".
       ## %rhash has servers deleted from it as results come in                                    " of table ".$table);
       ## (within the foreach loop below).          return;
       ##      } elsif (! $table_check) {
       foreach my $rkey (sort keys %rhash) {          $r->print("The table of results could not be found.");
 #        &Apache::lonnet::logthis("Server $rkey:".time);          &Apache::lonnet::logthis("The user requested a table, ".$table.
  $servercount++;                                   ", that could not be found.");
  $compiledresult='';          return;
  my $reply=$rhash{$rkey};      }
  my @results;      ##
  if ($reply eq 'con_lost') {      ## Get the number of results 
     &popwin_imgupdate($r,$rkey,"srvbad.gif");      ##
     $serversleft--;      my $total_results = &Apache::lonmysql::number_of_rows($table);
             delete $rhash{$rkey};      if (! defined($total_results)) {
  } else {          $r->print("A MySQL error has occurred.</body></html>");
             # must do since 'use strict' checks for tainting          &Apache::lonnet::logthis("lonmysql was unable to determine the number".
     $reply=~/^([\.\w]+)$/;                                    " of rows in table ".$table);
     my $replyfile=$r->dir_config('lonDaemons').'/tmp/'.$1;          &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
     $reply=~/(.*?)\_/;          &Apache::lonnet::logthis(&Apache::lonmysql::get_debug());
             for (my $counter=0;$counter<2;$counter++) {          return;
                 if (-e $replyfile && ! -e "$replyfile.end") {      }
                     &popwin_imgupdate($r,$rkey,"srvhalf.gif");      if ($total_results == 0) {
                     &popwin_js($r,'popwin.hc["'.$rkey.'"]='.          $r->print("There were no results matching your query.\n".
                                '"still transferring..."'.';');                    "</form></body></html>");
                 }          return;
                 # Are we finished transferring data?      }
                 if (-e "$replyfile.end") {      ##
                     $serversleft--;      ## Determine how many results we need to get
                     delete $rhash{$rkey};      ##
                     if (-s $replyfile) {      $ENV{'form.startwith'} = 0      if (! exists($ENV{'form.startwith'}));
                         &popwin_imgupdate($r,$rkey,"srvgood.gif");      $ENV{'form.show'}      = 'all'  if (! exists($ENV{'form.show'}));
                         my $fh;      my $min = $ENV{'form.startwith'};
                         unless ($fh=Apache::File->new($replyfile)){       my $max;
                             # Is it really appropriate to die on this error?      if ($ENV{'form.show'} eq 'all') {
                             $r->print('ERROR: file '.          $max = $total_results ;
                                       $replyfile.' cannot be opened');      } else {
                             return OK;          $max = $min + $ENV{'form.show'};
                         }      }
                         @results=<$fh> if $fh;      ##
                         my $hits =@results;      ## Output links (if necessary) for 'prev' and 'next' pages.
                         &popwin_js($r,'popwin.hc["'.$rkey.'"]='.      ##
                                    $hits.';');      
                         $hitcountsum+=$hits;      ##
                         &popwin_js($r,'popwin.document.forms.popremain.'.      ## Get results from MySQL table
                                    'numhits.value='.$hitcountsum.';');      ##
                     } else {      my @Results = &Apache::lonmysql::get_rows($table,
                         &popwin_imgupdate($r,$rkey,"srvempty.gif");                                                'id>'.$min.' AND id<='.$max);
                         &popwin_js($r,'popwin.hc["'.$rkey.'"]=0;');      ##
                     }      ## Loop through the results and output them.
                     last;      ##
                 } # end of if ( -e "$replyfile.end")      foreach my $row (@Results) {
                 last unless $timeremain;          my %Fields = %{&parse_row(@$row)};
                 sleep 1;    # wait for daemons to write files?          my $output="<p>\n";
                 $timeremain--;          $output.=&catalogmode_output($Fields{'title'},$Fields{'url'});
                 $elapsetime++;          # Render the result into html
                 &popwin_js($r,"popwin.document.popremain.".          $output.= &$viewfunction(%Fields);
                            "elapsetime.value=$elapsetime;");          $output.="</p>\n<hr align='left' width='200' noshade />";
     }          # Print them out as they come in.
     &popwin_js($r,'popwin.document.whirly.'.          $r->print($output);
        'src="/adm/lonIcons/lonanimend.gif";');          $r->rflush();
  } # end of if ($reply eq 'con_lost') else statement      }
         my %Fields = undef;     # Holds the data to be sent to the various       if (@Results < 1) {
                                 # *_view routines.          $r->print("There were no results matching your query");
         my ($extrashow,$customfields,$customhash) =       }
                                     &handle_custom_fields(\@results);      $r->print("</body></html>");
         my @customfields = @$customfields;      $r->rflush();
         my %customhash   = %$customhash;      untie %groupsearch_db;
  untie %groupsearch_db if (tied %groupsearch_db);      return;
         #  }
  if (! tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT,0640)) {  
     $r->print('<html><head></head><body>Unable to tie hash to db '.  ######################################################################
                       'file</body></html>');  ######################################################################
         } else {  
     if ($ENV{'form.launch'} eq '1') {  =pod
  &start_fresh_session();  
     }  =item &catalogmode_output($title,$url)
     foreach my $result (@results) {  
  next if $result=~/^custom\=/;  Returns html needed for the various catalog modes.  Gets inputs from
  chomp $result;  $ENV{'form.catalogmode'}.  Stores data in %groupsearch_db and $fnum 
  next unless $result;  (local variable).
                 %Fields = &parse_raw_result($result,$rkey);  
                 #  =cut
                 # Check copyright tags and skip results the user cannot use  
                 my (undef,undef,$resdom,$resname) = split('/',$Fields{'url'});  ######################################################################
                 # Check for priv  ######################################################################
                 if (($Fields{'copyright'} eq 'priv') &&   { 
                     (($ENV{'user.name'} ne $resname) &&  my $fnum;
                      ($ENV{'user.domain'} ne $resdom))) {  
                     next;  sub catalogmode_output {
                 }      my $output = '';
                 # Check for domain      my ($title,$url) = @_;
                 if (($Fields{'copyright'} eq 'domain') &&      if ($ENV{'form.catalogmode'} eq 'interactive') {
                     ($ENV{'user.domain'} ne $resdom)) {          $title=~ s/\'/\\'/g; # ' Escape single quotes.
                     next;          if ($ENV{'form.catalogmode'} eq 'interactive') {
                 }              $output.=<<END 
                 #  
  $Fields{'extrashow'}=$extrashow;  
  if ($extrashow) {  
     foreach my $field (@customfields) {  
  my $value='';  
  $value = $1 if ($customhash{$Fields{'url'}}=~/\<{$field}[^\>]*\>(.*?)\<\/{$field}[^\>]*\>/s);  
                         $Fields{'extrashow'}=~s/\<\!\-\- $field \-\-\>/ $value/g;  
                     }  
                 }  
                 $compiledresult.="\n<p>\n";  
                 if ($ENV{'form.catalogmode'} eq 'interactive') {  
                     my $titleesc=$Fields{'title'};  
                     $titleesc=~s/\'/\\'/; # '  
                     $compiledresult.=<<END if ($ENV{'form.catalogmode'} eq 'interactive');  
 <font size='-1'><INPUT TYPE="button" NAME="returnvalues" VALUE="SELECT"  <font size='-1'><INPUT TYPE="button" NAME="returnvalues" VALUE="SELECT"
 onClick="javascript:select_data('$titleesc','$Fields{'url'}')">  onClick="javascript:select_data('$title','$url')">
 </font>  </font>
 <br />  
 END  END
                 }          }
                 if ($ENV{'form.catalogmode'} eq 'groupsearch') {      }
     $fnum+=0;      if ($ENV{'form.catalogmode'} eq 'groupsearch') {
     $groupsearch_db{"pre_${fnum}_link"}=$Fields{'url'};          $fnum+=0;
     $groupsearch_db{"pre_${fnum}_title"}=$Fields{'title'};          $groupsearch_db{"pre_${fnum}_link"}=$url;
     $compiledresult.=<<END;          $groupsearch_db{"pre_${fnum}_title"}=$title;
           $output.=<<END;
 <font size='-1'>  <font size='-1'>
 <input type="checkbox" name="returnvalues" value="SELECT"  <input type="checkbox" name="returnvalues" value="SELECT"
 onClick="javascript:queue($fnum)" />  onClick="javascript:queue($fnum)" />
 </font>  </font>
 <br />  
 END  END
 # <input type="hidden" name="title$fnum" value="$title" />          $fnum++;
 # <input type="hidden" name="url$fnum" value="$url" />      }
                     $fnum++;      return $output;
  }  }
                 # Render the result into html  
                 $compiledresult.= &$viewfunction(%Fields, hostname => $rkey );  }
                 if ($compiledresult or $servercount!=$servernum) {  ######################################################################
                     $compiledresult.="<hr align='left' width='200' noshade />";  ######################################################################
                 }  
             }  =pod
             untie %groupsearch_db;  
         }  =item &parse_row
  if ($compiledresult) {  
     $resultflag=1;  Parse a row returned from the database.
             $r->print($compiledresult);  
  }  =cut
       } # End of foreach loop over servers remaining  
     }   # End of big loop - while($serversleft && $timeremain)  ######################################################################
     unless ($resultflag) {  ######################################################################
         $r->print("\nThere were no results that matched your query\n");  sub parse_row {
     }      my @Row = @_;
     $r->print('<script type="text/javascript">'.'popwin.close()</script>'.      my %Fields;
               "\n");       for (my $i=0;$i<=$#Row;$i++) {
     $r->print("</body>\n</html>\n");          $Fields{$DataOrder[$i]}=&Apache::lonnet::unescape($Row[$i]);
     $r->rflush();       }
     return;      $Fields{'language'} = 
           &Apache::loncommon::languagedescription($Fields{'lang'});
       $Fields{'copyrighttag'} =
           &Apache::loncommon::copyrightdescription($Fields{'copyright'});
       $Fields{'mimetag'} =
           &Apache::loncommon::filedescription($Fields{'mime'});
       return \%Fields;
 }  }
   
 ###########################################################  ###########################################################
Line 1611  sub parse_raw_result { Line 1925  sub parse_raw_result {
         $Fields{'title'}='Untitled';           $Fields{'title'}='Untitled'; 
     }      }
     unless ($ENV{'user.adv'}) {      unless ($ENV{'user.adv'}) {
           # What is this anyway?
         $Fields{'keywords'} = '- not displayed -';          $Fields{'keywords'} = '- not displayed -';
         $Fields{'notes'}    = '- not displayed -';          $Fields{'notes'}    = '- not displayed -';
         $Fields{'abstract'} = '- not displayed -';          $Fields{'abstract'} = '- not displayed -';
Line 1820  END Line 2135  END
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
 =pod  
   
 =item &make_popwin()  
   
 Returns html with javascript in it to open up the status window.  
   
 =cut  
   
 ######################################################################  
 ######################################################################  
 sub make_popwin {  
     my %rhash = @_;  
     my $servernum=(keys %rhash);  
     my $hcinit;  
     my $grid="'<br />'+\n";  
     # $sn is the server number, used ONLY to make sure we have  
     # rows of 10 each.  No longer used to index images.  
     my $sn=1;  
     foreach my $sk (sort keys %rhash) {  
  $grid.="'<a href=\"";  
  $grid.="javascript:opener.displayinfo('+";  
  $grid.="\"'\"+'";  
  $grid.=$sk;  
  my $hc;  
  if ($rhash{$sk} eq 'con_lost') {  
     $hc="BAD CONNECTION ";  
  }  
  else {  
     $hc="'+\"'\"+\"+hc['$sk']+\"+\"'\"+'";  
     $hcinit.="hc[\"$sk\"]=\"not yet connected...\";";  
  }  
  $grid.=" hitcount=".$hc;  
  $grid.=" domain=".$Apache::lonnet::hostdom{$sk};  
  $grid.=" IP=".$Apache::lonnet::hostip{$sk};  
  # '+"'"+'">'+  
  $grid.="'+\"'\"+')\">'+";  
  $grid.="\n";  
  $grid.="'<img border=\"0\" name=\"img_".$Apache::lonnet::hostdom{$sk}.  
             '_'.$sk."\" src=\"/adm/lonIcons/srvnull.gif\" alt=\"".$sk.  
                 "\" /></a>'+\n";  
  $grid.="'<br />'+\n" unless $sn%10;  
         $sn++;  
     }  
     my $result.=<<ENDPOP;  
 <script type="text/javascript">  
     popwin=open('','popwin','scrollbars=1,width=400,height=220');  
     popwin.focus();  
     popwin.document.writeln('<'+'html>');  
     popwin.document.writeln('<'+'head>');  
     popwin.document.writeln('<'+'script>');  
     popwin.document.writeln('hc=new Array();$hcinit');  
     popwin.document.writeln('<'+'/script>');  
     popwin.document.writeln('<'+'/head>'+  
         '<'+'body bgcolor="#FFFFFF">'+  
  '<'+'image name="whirly" align="right" src="/adm/lonIcons/'+  
  'lonanim.gif" '+  
  'alt="animated logo" />'+  
  '<'+'h3>Search Results Progress<'+'/h3>'+  
         '<'+'form name="popremain">'+  
         '<'+'tt>'+  
  '<'+'br clear="all"/><i>PLEASE BE PATIENT</i>'+  
  '<'+'br />SCANNING $servernum SERVERS'+  
  '<'+'br clear="all" />Number of record hits found '+  
  '<'+'input type="text" size="10" name="numhits"'+  
  ' value="0" />'+  
  '<'+'br clear="all" />Time elapsed '+  
  '<'+'input type="text" size="10" name="elapsetime"'+  
  ' value="0" />'+  
  '<'+'br />'+  
  'SERVER GRID (click on any cell for details)'+  
         $grid  
         '<'+'br />'+  
  'Server details '+  
  '<'+'input type="text" size="35" name="sdetails"'+  
  ' value="" />'+  
  '<'+'br />'+  
  ' <'+'input type="button" name="button"'+  
  ' value="close this window" '+  
  ' onClick="javascript:opener.abortsearch()" />'+  
  ' <'+'input type="button" name="button"'+  
  ' value="help" onClick="javascript:opener.openhelp()" />'+  
  '<'+'/tt>'+  
         '<'+'/form>'+  
         '<'+'/body><'+'/html>');  
     popwin.document.close();  
 </script>  
 ENDPOP  
     return $result;  
 }  
   
 ######################################################################  
 ######################################################################  
   
 =pod   =pod 
   
 =item Metadata Viewing Functions  =item Metadata Viewing Functions
Line 2096  sub filled { Line 2318  sub filled {
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub output_blank_field_error {  sub output_blank_field_error {
     my ($r)=@_;      my ($r,$closebutton)=@_;
     # make query information persistent to allow for subsequent revision      # make query information persistent to allow for subsequent revision
     my $persistent=&make_persistent(\%ENV);  
   
     $r->print(<<BEGINNING);      $r->print(<<BEGINNING);
 <html>  <html>
 <head>  <head>
Line 2111  BEGINNING Line 2331  BEGINNING
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  <img align='right' src='/adm/lonIcons/lonlogos.gif' />
 <h1>Search Catalog</h1>  <h1>Search Catalog</h1>
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 $persistent  $hidden_fields
 <input type='button' value='Revise search request'  <input type='button' value='Revise search request'
 onClick='this.form.submit();' />  onClick='this.form.submit();' />
 $closebutton  $closebutton
Line 2137  RESULTS Line 2357  RESULTS
   
 Output a full html page with an error message.  Output a full html page with an error message.
   
   Inputs: 
   
       $r, the request pointer.
       $message, the error message for the user.
       $closebutton, the specialized close button needed for groupsearch.
   
 =cut  =cut
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub output_date_error {  sub output_date_error {
     my ($r,$message)=@_;      my ($r,$message,$closebutton)=@_;
     # make query information persistent to allow for subsequent revision      # make query information persistent to allow for subsequent revision
     my $persistent=&make_persistent(\%ENV);  
   
     $r->print(<<RESULTS);      $r->print(<<RESULTS);
 <html>  <html>
 <head>  <head>
Line 2155  sub output_date_error { Line 2379  sub output_date_error {
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  <img align='right' src='/adm/lonIcons/lonlogos.gif' />
 <h1>Search Catalog</h1>  <h1>Search Catalog</h1>
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 $persistent  $hidden_fields
 <input type='button' value='Revise search request'  <input type='button' value='Revise search request'
 onClick='this.form.submit();' />  onClick='this.form.submit();' />
 $closebutton  $closebutton
Line 2195  sub start_fresh_session { Line 2419  sub start_fresh_session {
     }      }
 }  }
   
 ######################################################################  
 ######################################################################  
   
 =pod   
   
 =item &popwin_js() send javascript to popwin  
   
 =cut  
   
 ######################################################################  
 ######################################################################  
 sub popwin_js {  
     # Print javascript out to popwin, but make sure we dont generate  
     # any javascript errors in doing so.  
     my ($r,$text) = @_;  
     $r->print(<<"END");  
 <script type="text/javascript">  
     if (! popwin.closed) {  
  $text  
     }  
 </script>  
 END  
     $r->rflush();  
 }  
   
 ######################################################################  
 ######################################################################  
   
 =pod   
   
 =item &popwin_imgupdate()  
   
 Send a given image (and its location) out to the browser.  Takes as   
 input $r, loncapa server id, and an icon URL.  
   
 =cut  
   
 ######################################################################  
 ######################################################################  
 sub popwin_imgupdate {  
     my ($r,$server,$icon) = @_;  
     &popwin_js($r,'popwin.document.img_'.$Apache::lonnet::hostdom{$server}.  
                '_'.$server.'.'.'src="/adm/lonIcons/'.$icon.'";');  
 }      
   
 1;  1;
   
 __END__  __END__

Removed from v.1.143  
changed lines
  Added in v.1.145


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