Diff for /loncom/interface/lonsearchcat.pm between versions 1.212 and 1.285

version 1.212, 2004/04/19 21:46:50 version 1.285, 2007/05/01 02:13:40
Line 63  package Apache::lonsearchcat; Line 63  package Apache::lonsearchcat;
   
 use strict;  use strict;
 use Apache::Constants qw(:common :http);  use Apache::Constants qw(:common :http);
 use Apache::lonnet();  use Apache::lonnet;
 use Apache::File();  use Apache::File();
 use CGI qw(:standard);  use CGI qw(:standard);
 use Text::Query;  use Text::Query;
Line 75  use Apache::lonhtmlcommon; Line 75  use Apache::lonhtmlcommon;
 use Apache::lonlocal;  use Apache::lonlocal;
 use LONCAPA::lonmetadata();  use LONCAPA::lonmetadata();
 use HTML::Entities();  use HTML::Entities();
   use Parse::RecDescent;
   use Apache::lonnavmaps;
   use Apache::lonindexer();
   use LONCAPA;
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
Line 91  my %persistent_db;   # gdbm hash which h Line 95  my %persistent_db;   # gdbm hash which h
 # The different view modes and associated functions  # The different view modes and associated functions
   
 my %Views = ("detailed" => \&detailed_citation_view,  my %Views = ("detailed" => \&detailed_citation_view,
                "detailedpreview" => \&detailed_citation_preview,
      "summary"  => \&summary_view,       "summary"  => \&summary_view,
                "summarypreview" => \&summary_preview,
      "fielded"  => \&fielded_format_view,       "fielded"  => \&fielded_format_view,
      "xml"      => \&xml_sgml_view,       "xml"      => \&xml_sgml_view,
      "compact"  => \&compact_view);       "compact"  => \&compact_view);
Line 111  sub handler { Line 117  sub handler {
     my $diropendb;    # The full path to the (temporary) search database file.      my $diropendb;    # The full path to the (temporary) search database file.
                       # This is set and used in &handler() and is also used in                         # This is set and used in &handler() and is also used in 
                       # &output_results().                        # &output_results().
     my $bodytag;  # LON-CAPA standard body tag, gotten from   
                   # &Apache::lonnet::bodytag.   
                   # No title, no table, just a <body> tag.  
   
     my $loaderror=&Apache::lonnet::overloaderror($r);      my $loaderror=&Apache::lonnet::overloaderror($r);
     if ($loaderror) { return $loaderror; }      if ($loaderror) { return $loaderror; }
       #
     my $closebutton;  # button that closes the search window       my $closebutton;  # button that closes the search window 
                       # This button is different for the RAT compared to                        # This button is different for the RAT compared to
                       # normal invocation.                        # normal invocation.
Line 135  sub handler { Line 138  sub handler {
     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
              ['catalogmode','launch','acts','mode','form','element','pause',               ['catalogmode','launch','acts','mode','form','element','pause',
               'phase','persistent_db_id','table','start','show',                'phase','persistent_db_id','table','start','show',
               'cleargroupsort','titleelement']);                'cleargroupsort','titleelement','area']);
     ##      ##
     ## The following is a trick - we wait a few seconds if asked to so      ## The following is a trick - we wait a few seconds if asked to so
     ##     the daemon running the search can get ahead of the daemon      ##     the daemon running the search can get ahead of the daemon
     ##     printing the results.  We only need (theoretically) to do      ##     printing the results.  We only need (theoretically) to do
     ##     this once, so the pause indicator is deleted      ##     this once, so the pause indicator is deleted
     ##      ##
     if (exists($ENV{'form.pause'})) {      if (exists($env{'form.pause'})) {
         sleep(1);          sleep(1);
         delete($ENV{'form.pause'});          delete($env{'form.pause'});
     }      }
     ##      ##
     ## Initialize global variables      ## Initialize global variables
     ##      ##
     my $domain  = $r->dir_config('lonDefDomain');      my $domain  = $r->dir_config('lonDefDomain');
     $diropendb= "/home/httpd/perl/tmp/$ENV{'user.domain'}_$ENV{'user.name'}_searchcat.db";      $diropendb= "/home/httpd/perl/tmp/".
           "$env{'user.domain'}_$env{'user.name'}_sel_res.db";
     #      #
     # set the name of the persistent database      # set the name of the persistent database
     #          $ENV{'form.persistent_db_id'} can only have digits in it.      #          $env{'form.persistent_db_id'} can only have digits in it.
     if (! exists($ENV{'form.persistent_db_id'}) ||      if (! exists($env{'form.persistent_db_id'}) ||
         ($ENV{'form.persistent_db_id'} =~ /\D/) ||          ($env{'form.persistent_db_id'} =~ /\D/) ||
         ($ENV{'form.launch'} eq '1')) {          ($env{'form.launch'} eq '1')) {
         $ENV{'form.persistent_db_id'} = time;          $env{'form.persistent_db_id'} = time;
     }      }
     $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);  
     my $persistent_db_file = "/home/httpd/perl/tmp/".      my $persistent_db_file = "/home/httpd/perl/tmp/".
         &Apache::lonnet::escape($domain).          &escape($domain).
             '_'.&Apache::lonnet::escape($ENV{'user.name'}).              '_'.&escape($env{'user.name'}).
                 '_'.$ENV{'form.persistent_db_id'}.'_persistent_search.db';                  '_'.$env{'form.persistent_db_id'}.'_persistent_search.db';
     ##      ##
     &Apache::lonhtmlcommon::clear_breadcrumbs();      &Apache::lonhtmlcommon::clear_breadcrumbs();
     if (exists($ENV{'request.course.id'}) && $ENV{'request.course.id'} ne '') {  
         &Apache::lonhtmlcommon::add_breadcrumb      my @allowed_searches = ('portfolio');
              ({href=>'/adm/searchcat?'.      if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'})) {
                    'catalogmode='.$ENV{'form.catalogmode'}.          push(@allowed_searches,'res');
                    '&launch='.$ENV{'form.launch'}.      } 
                    '&mode='.$ENV{'form.mode'},      if (exists($env{'request.course.id'}) && $env{'request.course.id'} ne '') {
               text=>"Course and Catalog Search",          push(@allowed_searches,'course');
               bug=>'Searching',});  
     } else {  
         &Apache::lonhtmlcommon::add_breadcrumb  
              ({href=>'/adm/searchcat?'.  
                    'catalogmode='.$ENV{'form.catalogmode'}.  
                    '&launch='.$ENV{'form.launch'}.  
                    '&mode='.$ENV{'form.mode'},  
               text=>"Catalog Search",  
               bug=>'Searching',});  
     }      }
       my $crumb_text = 'Portfolio Search';
       if (@allowed_searches == 3) {
           $crumb_text = 'Course, Portfolio and Catalog Search';
       } elsif (@allowed_searches ==2) {
           if (grep(/^res$/,@allowed_searches)) {
               $crumb_text = 'Portfolio and Catalog Search'; 
           } elsif (grep(/^course$/,@allowed_searches)) {
               $crumb_text = 'Portfolio and Course Search';
           }
       }
       &Apache::lonhtmlcommon::add_breadcrumb
          ({href=>'/adm/searchcat?'.
                  'catalogmode='.$env{'form.catalogmode'}.
                  '&launch='.$env{'form.launch'}.
                  '&mode='.$env{'form.mode'},
                 text=>"$crumb_text",
                 target=>'_top',
                 bug=>'Searching',});
     #      #
     if (! &get_persistent_form_data($persistent_db_file)) {      if ($env{'form.phase'} !~ m/(basic|adv|course)_search/) {
         if ($ENV{'form.phase'} =~ /(run_search|results)/) {          if (! &get_persistent_form_data($persistent_db_file)) {
             &Apache::lonnet::logthis("lonsearchcat:Unable to recover data ".              if ($env{'form.phase'} =~ /(run_search|results)/) {
                                      "from $persistent_db_file");                  &Apache::lonnet::logthis('lonsearchcat:'.
             $r->print(<<END);                                           'Unable to recover data from '.
 <html>                                           $persistent_db_file);
 <head><title>LON-CAPA Search Error</title></head>   my $msg =
 $bodytag      'We were unable to retrieve data describing your search. '.
 We were unable to retrieve data describing your search.  This is a serious      'This is a serious error and has been logged. '.
 error and has been logged.  Please alert your LON-CAPA administrator.      'Please alert your LON-CAPA administrator.';
 </body>   &Apache::loncommon::simple_error_page($r,'Search Error',
 </html>        $msg);
 END   return OK;
             return OK;              }
         }          }
       } else {
           &clean_up_environment();
     }      }
     ##      ##
     ## Clear out old values from groupsearch database      ## Clear out old values from groupsearch database
     ##      ##
     untie %groupsearch_db if (tied(%groupsearch_db));      untie %groupsearch_db if (tied(%groupsearch_db));
     if (($ENV{'form.cleargroupsort'} eq '1') ||       if (($env{'form.cleargroupsort'} eq '1') || 
         (($ENV{'form.launch'} eq '1') &&           (($env{'form.launch'} eq '1') && 
          ($ENV{'form.catalogmode'} eq 'groupsearch'))) {           ($env{'form.catalogmode'} eq 'import'))) {
  if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) {   if (tie(%groupsearch_db,'GDBM_File',$diropendb,&GDBM_WRCREAT(),0640)) {
     &start_fresh_session();      &start_fresh_session();
     untie %groupsearch_db;      untie %groupsearch_db;
             delete($ENV{'form.cleargroupsort'});              delete($env{'form.cleargroupsort'});
  } else {   } else {
             # This is a stupid error to give to the user.                # This is a stupid error to give to the user.  
             # It really tells them nothing.              # It really tells them nothing.
     $r->print('<html><head></head>'.$bodytag.      my $msg = 'Unable to tie hash to db file.';
                       'Unable to tie hash to db file</body></html>');      &Apache::loncommon::simple_error_page($r,'Search Error',
     $msg);
     return OK;      return OK;
  }   }
     }      }
Line 223  END Line 239  END
     ## Configure hidden fields      ## Configure hidden fields
     ##      ##
     $hidden_fields = '<input type="hidden" name="persistent_db_id" value="'.      $hidden_fields = '<input type="hidden" name="persistent_db_id" value="'.
         $ENV{'form.persistent_db_id'}.'" />'."\n";          $env{'form.persistent_db_id'}.'" />'."\n";
     if (exists($ENV{'form.catalogmode'})) {      if (exists($env{'form.catalogmode'})) {
         $hidden_fields .= '<input type="hidden" name="catalogmode" value="'.          $hidden_fields .= &hidden_field('catalogmode');
                 $ENV{'form.catalogmode'}.'" />'."\n";      }
     }      if (exists($env{'form.form'})) {
     if (exists($ENV{'form.form'})) {          $hidden_fields .= &hidden_field('form');
         $hidden_fields .= '<input type="hidden" name="form" value="'.      }
                 $ENV{'form.form'}.'" />'."\n";      if (exists($env{'form.element'})) {
     }          $hidden_fields .= &hidden_field('element');
     if (exists($ENV{'form.element'})) {      }
         $hidden_fields .= '<input type="hidden" name="element" value="'.      if (exists($env{'form.titleelement'})) {
                 $ENV{'form.element'}.'" />'."\n";          $hidden_fields .= &hidden_field('titleelement');
     }      }
     if (exists($ENV{'form.titleelement'})) {      if (exists($env{'form.mode'})) {
         $hidden_fields .= '<input type="hidden" name="titleelement" value="'.          $hidden_fields .= &hidden_field('mode');
                 $ENV{'form.titleelement'}.'" />'."\n";      }
     }      if (exists($env{'form.area'})) {
     if (exists($ENV{'form.mode'})) {          $hidden_fields .= &hidden_field('area');
         $hidden_fields .= '<input type="hidden" name="mode" value="'.  
                 $ENV{'form.mode'}.'" />'."\n";  
     }      }
     ##      ##
     ## Configure dynamic components of interface      ## Configure dynamic components of interface
     ##      ##
     if ($ENV{'form.catalogmode'} eq 'interactive') {      if ($env{'form.catalogmode'} eq 'interactive') {
         $closebutton="<input type='button' name='close' value='CLOSE' ";          $closebutton="<input type='button' name='close' value='CLOSE' ";
         if ($ENV{'form.phase'} =~ /(results|run_search)/) {          if ($env{'form.phase'} =~ /(results|run_search)/) {
     $closebutton .="onClick='parent.close()'";      $closebutton .="onClick='parent.close()'";
         } else {          } else {
             $closebutton .="onClick='self.close()'";              $closebutton .="onClick='self.close()'";
         }          }
         $closebutton .=">\n";          $closebutton .=">\n";
     } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') {      } elsif ($env{'form.catalogmode'} eq 'import') {
         $closebutton="<input type='button' name='close' value='CLOSE' ";          $closebutton="<input type='button' name='close' value='CLOSE' ";
         if ($ENV{'form.phase'} =~ /(results|run_search)/) {          if ($env{'form.phase'} =~ /(results|run_search)/) {
     $closebutton .="onClick='parent.close()'";      $closebutton .="onClick='parent.close()'";
         } else {          } else {
             $closebutton .="onClick='self.close()'";              $closebutton .="onClick='self.close()'";
Line 274  END Line 288  END
     ##      ##
     ## Sanity checks on form elements      ## Sanity checks on form elements
     ##      ##
     if (!defined($ENV{'form.viewselect'})) {      if (!defined($env{'form.viewselect'})) {
         if (($ENV{'form.catalogmode'} eq 'groupsearch') ||   $env{'form.viewselect'} ="summary";
             ($ENV{'form.catalogmode'} eq 'interactive')) {  
             $ENV{'form.viewselect'} ="Compact View";  
         } else {  
             $ENV{'form.viewselect'} ="Detailed Citation View";  
         }  
     }      }
     $ENV{'form.phase'} = 'disp_basic' if (! exists($ENV{'form.phase'}));      $env{'form.phase'} = 'disp_basic' if (! exists($env{'form.phase'}));
     $ENV{'form.show'} = 20 if (! exists($ENV{'form.show'}));      $env{'form.show'} = 20 if (! exists($env{'form.show'}));
     #      #
     $ENV{'form.searchmode'} = 'basic';      $env{'form.searchmode'} = 'basic' if (! exists($env{'form.searchmode'}));
     if ($ENV{'form.phase'} eq 'adv_search' ||      if ($env{'form.phase'} eq 'adv_search' ||
         $ENV{'form.phase'} eq 'disp_adv') {          $env{'form.phase'} eq 'disp_adv') {
         $ENV{'form.searchmode'} = 'advanced';          $env{'form.searchmode'} = 'advanced';
     } elsif ($ENV{'form.phase'} eq 'course_search') {      } elsif ($env{'form.phase'} eq 'course_search') {
         $ENV{'form.searchmode'} = 'course_search';          $env{'form.searchmode'} = 'course_search';
     }      }
     #      #
     if ($ENV{'form.searchmode'} eq 'advanced') {      if ($env{'form.searchmode'} eq 'advanced') {
           my $srchtype = 'Catalog';
           if ($env{'form.area'} eq 'portfolio') {
               $srchtype = 'Portfolio';
           }
         &Apache::lonhtmlcommon::add_breadcrumb          &Apache::lonhtmlcommon::add_breadcrumb
             ({href=>'/adm/searchcat?phase=disp_adv&'.              ({href=>'/adm/searchcat?phase=disp_adv&'.
                   'catalogmode='.$ENV{'form.catalogmode'}.                    'catalogmode='.$env{'form.catalogmode'}.
                   '&launch='.$ENV{'form.launch'}.                    '&launch='.$env{'form.launch'}.
                   '&mode='.$ENV{'form.mode'},                    '&mode='.$env{'form.mode'},
                   text=>"Advanced Search",                    text=>"Advanced $srchtype Search",
                   bug=>'Searching',});                    bug=>'Searching',});
     } elsif ($ENV{'form.searchmode'} eq 'course search') {      } elsif ($env{'form.searchmode'} eq 'course search') {
         &Apache::lonhtmlcommon::add_breadcrumb          &Apache::lonhtmlcommon::add_breadcrumb
             ({href=>'/adm/searchcat?phase=disp_adv&'.              ({href=>'/adm/searchcat?phase=disp_adv&'.
                   'catalogmode='.$ENV{'form.catalogmode'}.                    'catalogmode='.$env{'form.catalogmode'}.
                   '&launch='.$ENV{'form.launch'}.                    '&launch='.$env{'form.launch'}.
                   '&mode='.$ENV{'form.mode'},                    '&mode='.$env{'form.mode'},
                   text=>"Course Search",                    text=>"Course Search",
                   bug=>'Searching',});                    bug=>'Searching',});
     }      }
     ##      ##
     ## Switch on the phase      ## Switch on the phase
     ##      ##
     if ($ENV{'form.phase'} eq 'disp_basic') {      if ($env{'form.phase'} eq 'disp_basic') {
         &print_basic_search_form($r,$closebutton,$hidden_fields);          &print_basic_search_form($r,$closebutton,$hidden_fields);
     } elsif ($ENV{'form.phase'} eq 'disp_adv') {      } elsif ($env{'form.phase'} eq 'disp_adv') {
         &print_advanced_search_form($r,$closebutton,$hidden_fields);          &print_advanced_search_form($r,$closebutton,$hidden_fields);
     } elsif ($ENV{'form.phase'} eq 'results') {      } elsif ($env{'form.phase'} eq 'results') {
         &display_results($r,$importbutton,$closebutton,$diropendb);          &display_results($r,$importbutton,$closebutton,$diropendb,
     } elsif ($ENV{'form.phase'} =~ /^(sort|run_search)$/) {                           $env{'form.area'});
       } elsif ($env{'form.phase'} =~ /^(sort|run_search)$/) {
         my ($query,$customquery,$customshow,$libraries,$pretty_string) =          my ($query,$customquery,$customshow,$libraries,$pretty_string) =
             &get_persistent_data($persistent_db_file,              &get_persistent_data($persistent_db_file,
                  ['query','customquery','customshow',                   ['query','customquery','customshow',
                   'libraries','pretty_string']);                    'libraries','pretty_string']);
         if ($ENV{'form.phase'} eq 'sort') {          if ($env{'form.phase'} eq 'sort') {
             &print_sort_form($r,$pretty_string);              &print_sort_form($r,$pretty_string);
         } elsif ($ENV{'form.phase'} eq 'run_search') {          } elsif ($env{'form.phase'} eq 'run_search') {
             &run_search($r,$query,$customquery,$customshow,              &run_search($r,$query,$customquery,$customshow,
                         $libraries,$pretty_string);                          $libraries,$pretty_string,$env{'form.area'});
         }          }
     } elsif ($ENV{'form.phase'} eq 'course_search') {      } elsif ($env{'form.phase'} eq 'course_search') {
         &course_search($r);          &course_search($r);
     } elsif(($ENV{'form.phase'} eq 'basic_search') ||      } elsif(($env{'form.phase'} eq 'basic_search') ||
             ($ENV{'form.phase'} eq 'adv_search')) {              ($env{'form.phase'} eq 'adv_search')) {
         # Set up table  
         if (! defined(&create_results_table())) {  
     my $errorstring=&Apache::lonmysql::get_error();  
             &Apache::lonnet::logthis('lonsearchcat.pm: Unable to create '.  
                                      'needed table.  lonmysql error:'.  
                                      $errorstring);  
             $r->print(<<END);  
 <html><head><title>Search Error</title></head>  
 $bodytag  
 Unable to create table in which to store search results.    
 The search has been aborted.  
 </body>  
 </html>  
 END  
             return OK;  
         }  
         delete($ENV{'form.launch'});  
         if (! &make_form_data_persistent($r,$persistent_db_file)) {  
             $r->print(<<END);  
 <html><head><title>Search Error</title></head>  
 $bodytag  
 Unable to properly store search information.  The search has been aborted.  
 </body>  
 </html>  
 END  
             return OK;  
         }  
         #          #
         # We are running a search          # We are running a search, try to parse it
         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 ($ENV{'form.phase'} eq 'basic_search') {          if ($env{'form.phase'} eq 'basic_search') {
             ($query,$pretty_string,$libraries) =               ($query,$pretty_string,$libraries) = 
                 &parse_basic_search($r,$closebutton,$hidden_fields);                  &parse_basic_search($r,$closebutton,$hidden_fields);
               return OK if (! defined($query));
               &make_persistent({ basicexp => $env{'form.basicexp'}},
                                $persistent_db_file);
         } else {                      # Advanced search          } else {                      # Advanced search
             ($query,$customquery,$customshow,$libraries,$pretty_string)               ($query,$customquery,$customshow,$libraries,$pretty_string) 
                 = &parse_advanced_search($r,$closebutton,$hidden_fields);                  = &parse_advanced_search($r,$closebutton,$hidden_fields);
Line 380  END Line 370  END
                            libraries => $libraries,                             libraries => $libraries,
                            pretty_string => $pretty_string },                             pretty_string => $pretty_string },
                          $persistent_db_file);                           $persistent_db_file);
           #
           # Set up table
           if (! defined(&create_results_table($env{'form.area'}))) {
       my $errorstring=&Apache::lonmysql::get_error();
               &Apache::lonnet::logthis('lonsearchcat.pm: Unable to create '.
                                        'needed table.  lonmysql error:'.
                                        $errorstring);
   
       my $msg = 
    'Unable to create table in which to store search results. '.
    'The search has been aborted.';
       &Apache::loncommon::simple_error_page($r,'Search Error',
     $msg);
       return OK;
           }
           delete($env{'form.launch'});
           if (! &make_form_data_persistent($r,$persistent_db_file)) {
       my $msg=
    'Unable to properly store search information. '.
    'The search has been aborted.';
       &Apache::loncommon::simple_error_page($r,'Search Error',
     $msg);
       return OK;
    }
         ##          ##
         ## Print out the frames interface          ## Print out the frames interface
         ##          ##
         &print_frames_interface($r);          if (defined($query)) {
               &print_frames_interface($r);
           }
     }      }
     return OK;      return OK;
 }   } 
   
   #
   # The mechanism used to store values away and retrieve them does not
   # handle the case of missing environment variables being significant.
   #
   # This routine sets non existant checkbox form elements to ''.
   #
   sub clean_up_environment {
       if ($env{'form.phase'} eq 'basic_search') {
           if (! exists($env{'form.related'})) {
               $env{'form.related'} = '';
           }
           if (! exists($env{'form.domains'})) {
               $env{'form.domains'} = '';
           }
       } elsif ($env{'form.phase'} eq 'adv_search') {
           foreach my $field ('title','keywords','notes',
                              'abstract','standards','mime') {
               if (! exists($env{'form.'.$field.'_related'})) {
                   $env{'form.'.$field.'_related'} = '';
               }
           }
       } elsif ($env{'form.phase'} eq 'course_search') {
           if (! exists($env{'form.crsrelated'})) {
               $env{'form.crsrelated'} = '';
           }
       }
   }
   
   sub hidden_field {
       my ($name,$value) = @_;
       if (! defined($value)) {
           $value = $env{'form.'.$name};
       }
       return '<input type="hidden" name="'.$name.'" value="'.$value.'" />'.$/;
   }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 ##  ##
Line 402  my %alreadyseen; Line 454  my %alreadyseen;
 my %hash;  my %hash;
 my $totalfound;  my $totalfound;
   
   sub make_symb {
       my ($id)=@_;
       my ($mapid,$resid)=split(/\./,$id);
       my $map=$hash{'map_id_'.$mapid};
       my $res=$hash{'src_'.$id};
       my $symb=&Apache::lonnet::encode_symb($map,$resid,$res);
       return $symb;
   }
   
 sub course_search {  sub course_search {
     my $r=shift;      my $r=shift;
     my $bodytag=&Apache::loncommon::bodytag('Course Search').      my $pretty_search_string = '<b>'.$env{'form.courseexp'}.'</b>';
  &Apache::loncommon::help_open_bug('Searching');      my $search_string = $env{'form.courseexp'};
     my $pretty_search_string = '<b>'.$ENV{'form.courseexp'}.'</b>';  
     my $search_string = $ENV{'form.courseexp'};  
     my @New_Words;      my @New_Words;
     if ($ENV{'form.crsrelated'}) {      undef(%alreadyseen);
         ($search_string,@New_Words) = &related_version($ENV{'form.courseexp'});      if ($env{'form.crsrelated'}) {
           ($search_string,@New_Words) = &related_version($env{'form.courseexp'});
         if (@New_Words) {          if (@New_Words) {
             $pretty_search_string .= ' '.&mt("with related words").": <b>@New_Words</b>.";              $pretty_search_string .= ' '.&mt("with related words").": <b>@New_Words</b>.";
         } else {          } else {
             $pretty_search_string .= ' '.&mt('with no related words').".";              $pretty_search_string .= ' '.&mt('with no related words').".";
         }          }
     }      }
     my $fulltext=$ENV{'form.crsfulltext'};      my $fulltext=$env{'form.crsfulltext'};
       my $discuss=$env{'form.crsdiscuss'};
     my @allwords=($search_string,@New_Words);      my @allwords=($search_string,@New_Words);
     $totalfound=0;      $totalfound=0;
     $r->print('<html><head><title>LON-CAPA Course Search</title></head>'.      $r->print(&Apache::loncommon::start_page('Course Search').
       $bodytag.'<hr /><center><font size="+2" face="arial">'.$pretty_search_string.'</font></center><hr />');        '<hr /><center><font size="+2" face="arial">'.
         $pretty_search_string.'</font></center>'.
         '<hr /><b>'.&mt('Course content').':</b><br />');
     $r->rflush();      $r->rflush();
 # ======================================================= Go through the course  # ======================================================= Go through the course
     undef %alreadyseen;  
     %alreadyseen=();  
     my $c=$r->connection;      my $c=$r->connection;
     if (tie(%hash,'GDBM_File',$ENV{'request.course.fn'}.".db",      if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.".db",
             &GDBM_READER(),0640)) {              &GDBM_READER(),0640)) {
         foreach (keys %hash) {          foreach (sort(keys(%hash))) {
             if ($c->aborted()) { last; }              if ($c->aborted()) { last; }
             if (($_=~/^src\_(.+)$/) && (!$alreadyseen{$hash{$_}})) {              if (($_=~/^src\_(.+)$/)) {
                 &checkonthis($r,$hash{$_},0,$hash{'title_'.$1},$fulltext,   if ($hash{'randomout_'.$1} & !$env{'request.role.adv'}) {
                              @allwords);      next; 
    }
    my $symb=&make_symb($1);
                   &checkonthis($r,$1,$hash{$_},0,&Apache::lonnet::gettitle($symb),
        $fulltext,$symb,@allwords);
             }              }
         }          }
         untie(%hash);          untie(%hash);
     }      }
     unless ($totalfound) {      unless ($totalfound) {
  $r->print('<p>'.&mt('No resources found').'.</p>');   $r->print('<p>'.&mt('No matches found in resources').'.</p>');
     }      }
   
   # Check discussions if requested
       if ($discuss) {
           my $totaldiscussions = 0;
           $r->print('<br /><br /><b>'.&mt('Discussion postings').':</b><br />'); 
           my $navmap = Apache::lonnavmaps::navmap->new();
           my @allres=$navmap->retrieveResources();
           my %discussiontime = &Apache::lonnet::dump('discussiontimes',
                                  $env{'course.'.$env{'request.course.id'}.'.domain'},
                                  $env{'course.'.$env{'request.course.id'}.'.num'});
           foreach my $resource (@allres) {
               my $result = '';
               my $applies = 0;
               my $symb = $resource->symb();
               my $ressymb = $symb;
               if ($symb =~ m#(___adm/$LONCAPA::domain_re/$LONCAPA::username_re)/(\d+)/bulletinboard$#) {
                   $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard';
                   unless ($ressymb =~ m#bulletin___\d+___adm/wrapper#) {
                       $ressymb=~s#(bulletin___\d+___)#$1adm/wrapper/#;
                   }
               }
               if (defined($discussiontime{$ressymb})) { 
                   my %contrib = &Apache::lonnet::restore($ressymb,$env{'request.course.id'},
                        $env{'course.'.$env{'request.course.id'}.'.domain'},
                        $env{'course.'.$env{'request.course.id'}.'.num'});
                   if ($contrib{'version'}) {
                       for (my $id=1;$id<=$contrib{'version'};$id++) {
                           unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) { 
                               if ($contrib{$id.':subject'}) {
                                   $result .= $contrib{$id.':subject'};
                               }
                               if ($contrib{$id.':message'}) {
                                   $result .= $contrib{$id.':message'};
                               }
                               if ($contrib{$id,':attachmenturl'}) {
                                   if ($contrib{$id,':attachmenturl'} =~ m-/([^/]+)$-) {
                                       $result .= $1;
                                   }
                               }
                               $applies = &checkwords($result,$applies,@allwords);
                           }
                       }
                   }
               }
   # Does this discussion apply?
               if ($applies) {
                   my ($map,$ind,$url)=&Apache::lonnet::decode_symb($ressymb);
                   my $disctype = &mt('resource');
                   if ($url =~ m#/bulletinboard$#) {
                       if ($url =~m#^adm/wrapper/adm/.*/bulletinboard$#) {
                           $url =~s#^adm/wrapper##;
                       }
                       $disctype = &mt('bulletin board');
                   } else {
                       $url = '/res/'.$url;
                   }
                   if ($url =~ /\?/) {
                       $url .= '&symb=';
                   } else {
                       $url .= '?symb=';
                   }
                   $url .= &escape($resource->symb());
                   my $title = $resource->compTitle();
                   $r->print('<br /><a href="'.$url.'" target="cat">'.
                        ($title?$title:$url).'</a>&nbsp;&nbsp;-&nbsp;'.$disctype.'<br />');
                   $totaldiscussions++;
               } else {
                   $r->print(' .');
               }
           }
           unless ($totaldiscussions) {
               $r->print('<p>'.&mt('No matches found in postings').'.</p>');
           }
       }
    
 # =================================================== Done going through course  # =================================================== Done going through course
     $r->print('</body></html>');      $r->print(&Apache::loncommon::end_page());
 }  }
   
 # =============================== This pulls up a resource and its dependencies  # =============================== This pulls up a resource and its dependencies
   
 sub checkonthis {  sub checkonthis {
     my ($r,$url,$level,$title,$fulltext,@allwords)=@_;      my ($r,$id,$url,$level,$title,$fulltext,$symb,@allwords)=@_;
     $alreadyseen{$url}=1;      $alreadyseen{$id}=1;
       if (&Apache::loncommon::connection_aborted($r)) { return; }
     $r->rflush();      $r->rflush();
     my $result=&Apache::lonnet::metadata($url,'title').' '.      
                &Apache::lonnet::metadata($url,'subject').' '.      my $result=$title.' ';
                &Apache::lonnet::metadata($url,'abstract').' '.      if ($env{'request.role.adv'} || !$hash{'encrypted_'.$id}) {
                &Apache::lonnet::metadata($url,'keywords');   $result.=&Apache::lonnet::metadata($url,'title').' '.
     if (($url) && ($fulltext)) {      &Apache::lonnet::metadata($url,'subject').' '.
  $result.=&Apache::lonnet::ssi_body($url);      &Apache::lonnet::metadata($url,'abstract').' '.
       &Apache::lonnet::metadata($url,'keywords');
       }
       my ($extension)=($url=~/\.(\w+)$/);
       if (&Apache::loncommon::fileembstyle($extension) eq 'ssi' &&
    ($url) && ($fulltext)) {
    $result.=&Apache::lonnet::ssi_body($url.'?symb='.&escape($symb));
     }      }
     $result=~s/\s+/ /gs;      $result=~s/\s+/ /gs;
     my $applies=0;      my $applies = 0;
     foreach (@allwords) {      $applies = &checkwords($result,$applies,@allwords);
         if ($_=~/\w/) {  
    if ($result=~/$_/si) {  
       $applies++;  
            }  
        }  
     }  
 # Does this resource apply?  # Does this resource apply?
     if ($applies) {      if ($applies) {
        $r->print('<br />');         $r->print('<br />');
        for (my $i=0;$i<=$level*5;$i++) {         for (my $i=0;$i<=$level*5;$i++) {
            $r->print('&nbsp;');             $r->print('&nbsp;');
        }         }
        $r->print('<a href="'.$url.'" target="cat">'.         my $href=$url;
  ($title?$title:$url).'</a><br />');         if ($hash{'encrypted_'.$id} && !$env{'request.role.adv'}) {
      $href=&Apache::lonenc::encrypted($href)
          .'?symb='.&Apache::lonenc::encrypted($symb);
          } else {
      $href.='?symb='.&escape($symb);
          }
          $r->print('<a href="'.$href.'" target="cat">'.($title?$title:$url).
    '</a><br />');
        $totalfound++;         $totalfound++;
     } elsif ($fulltext) {      } elsif ($fulltext) {
        $r->print(' .');         $r->print(' .');
Line 484  sub checkonthis { Line 632  sub checkonthis {
     my $dependencies=      my $dependencies=
                 &Apache::lonnet::metadata($url,'dependencies');                  &Apache::lonnet::metadata($url,'dependencies');
     foreach (split(/\,/,$dependencies)) {      foreach (split(/\,/,$dependencies)) {
        if (($_=~/^\/res\//) && (!$alreadyseen{$_})) {         if (($_=~/^\/res\//) && (!$alreadyseen{$id})) { 
           &checkonthis($r,$_,$level+1,'',$fulltext,@allwords);            &checkonthis($r,$id,$_,$level+1,'',$fulltext,undef,@allwords);
        }         }
     }      }
 }  }
   
   sub checkwords {
       my ($result,$applies,@allwords) = @_;
       foreach (@allwords) {
           if ($_=~/\w/) {
               if ($result=~/$_/si) {
                   $applies++;
               }
           }
       }
       return $applies;
   }
   
 sub untiehash {  sub untiehash {
     if (tied(%hash)) {      if (tied(%hash)) {
         untie(%hash);          untie(%hash);
Line 498  sub untiehash { Line 658  sub untiehash {
   
 } # End of course search scoping  } # End of course search scoping
   
 sub search_html_header {  
     my $Str = <<ENDHEADER;  
 <html>  
 <head>  
 <title>The LearningOnline Network with CAPA</title>  
 <script type="text/javascript">  
     function openhelp(val) {  
  openhelpwin=open('/adm/help/searchcat.html','helpscreen',  
      'scrollbars=1,width=600,height=300');  
  openhelpwin.focus();  
     }  
 </script>  
 </head>  
 ENDHEADER  
     return $Str;  
 }  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
Line 530  Prints the form for the basic search.  S Line 674  Prints the form for the basic search.  S
 ######################################################################  ######################################################################
 sub print_basic_search_form {  sub print_basic_search_form {
     my ($r,$closebutton,$hidden_fields) = @_;      my ($r,$closebutton,$hidden_fields) = @_;
     my $bodytag=&Apache::loncommon::bodytag('Search').      my $result = ($env{'form.catalogmode'} ne 'import');
         &Apache::lonhtmlcommon::breadcrumbs(undef,'Searching','Finding_Resources',      my $bread_crumb =
                                             undef,undef,! $ENV{'form.launch'});          &Apache::lonhtmlcommon::breadcrumbs('Searching','Search_Basic',
     my $scrout = &search_html_header().$bodytag;      $env{'form.catalogmode'} ne 'import');
     if (&Apache::lonnet::allowed('bre',$ENV{'request.role.domain'})) {      my $scrout = &Apache::loncommon::start_page('Search').$bread_crumb;
         my $Statement=&searchhelp();  # Search form for resource space 
         $scrout.=(<<ENDDOCUMENT);      if (&Apache::lonnet::allowed('bre',$env{'request.role.domain'})) {
 <form name="loncapa_search" method="post" action="/adm/searchcat">          $scrout .= &setup_basic_search($r,'res',$hidden_fields,$closebutton);
 <input type="hidden" name="phase" value="basic_search" />          $scrout .= '<hr /><br />';
 $hidden_fields      }
 <p>  # Search form for accessible portfolio files
 $Statement.      $scrout.= &setup_basic_search($r,'portfolio',$hidden_fields,$closebutton);
 </p>      if ($env{'request.course.id'}) {
 <p>   my %lt=&Apache::lonlocal::texthash('srch' => 'Search',
 <table>  
 <tr><td>  
 ENDDOCUMENT  
         $scrout.='&nbsp;'.  
             &Apache::lonhtmlcommon::textbox('basicexp',  
                                         $ENV{'form.basicexp'},40).  
                                         '&nbsp;';  
         my $relatedcheckbox =   
             &Apache::lonhtmlcommon::checkbox('related',  
                                              $ENV{'form.related'});  
         my $domain = $r->dir_config('lonDefDomain');  
         my $domaincheckbox =   
             &Apache::lonhtmlcommon::checkbox('domains',  
                                              $ENV{'form.domains'});  
         my $srch=&mt('Search');  
         my $header=&mt('Advanced Search');  
         my $userelatedwords=&mt('use related words');  
         my $onlysearchdomain=&mt('only search domain');  
         my $view=&viewoptions();  
         $scrout.=<<END;  
 </td><td><a  
 href="/adm/searchcat?phase=disp_adv&catalogmode=$ENV{'form.catalogmode'}&launch=$ENV{'form.launch'}&mode=$ENV{'form.mode'}"  
 >$header</a></td></tr>  
 <tr><td>$relatedcheckbox $userelatedwords</td>  
     <td>$domaincheckbox $onlysearchdomain <b>$domain</b></td></tr>  
 </table>  
 </p>  
 $view  
 <p>  
 &nbsp;<input type="submit" name="basicsubmit" value='$srch' />&nbsp;  
 $closebutton  
 END  
     $scrout.=<<ENDDOCUMENT;  
 </p>  
 </form>  
 ENDDOCUMENT  
     }  
     if ($ENV{'request.course.id'}) {  
  my %lt=&Apache::lonlocal::texthash(  
    'srch' => 'Search',  
                                            'header' => 'Course Search',                                             'header' => 'Course Search',
  'note' => 'Enter terms or phrases, then press "Search" below',   'note' => 'Enter terms or phrases, then press "Search" below',
  'use' => 'use related words',   'use' => 'use related words',
  'full' =>'fulltext search (time consuming)'   'full' =>'fulltext search (time consuming)',
            'disc' => 'search discussion postings (resources and bulletin boards)',
    );     );
         $scrout.=(<<ENDCOURSESEARCH);          $scrout.=(<<ENDCOURSESEARCH);
   <form name="loncapa_search" method="post" action="/adm/searchcat">
   <center>
 <hr />  <hr />
 <h1>$lt{'header'}</h1>      <h1>$lt{'header'}</h1>    
 <form name="course_search" method="post" action="/adm/searchcat">  
 <input type="hidden" name="phase" value="course_search" />  <input type="hidden" name="phase" value="course_search" />
 $hidden_fields  $hidden_fields
 <p>  <p>
Line 604  $lt{'note'}. Line 710  $lt{'note'}.
 ENDCOURSESEARCH  ENDCOURSESEARCH
         $scrout.='&nbsp;'.          $scrout.='&nbsp;'.
             &Apache::lonhtmlcommon::textbox('courseexp',              &Apache::lonhtmlcommon::textbox('courseexp',
                                   $ENV{'form.courseexp'},40);                                    $env{'form.courseexp'},40);
         my $crscheckbox =           my $crscheckbox = 
             &Apache::lonhtmlcommon::checkbox('crsfulltext',              &Apache::lonhtmlcommon::checkbox('crsfulltext',
                                    $ENV{'form.crsfulltext'});                                     $env{'form.crsfulltext'});
         my $relcheckbox =           my $relcheckbox = 
             &Apache::lonhtmlcommon::checkbox('crsrelated',              &Apache::lonhtmlcommon::checkbox('crsrelated',
    $ENV{'form.crsrelated'});     $env{'form.crsrelated'});
           my $discheckbox = 
               &Apache::lonhtmlcommon::checkbox('crsdiscuss',
                                      $env{'form.crsrelated'});
         $scrout.=(<<ENDENDCOURSE);          $scrout.=(<<ENDENDCOURSE);
 </td></tr>  </td></tr>
 <tr><td>$relcheckbox $lt{'use'}</td><td></td></tr>  <tr><td><label>$relcheckbox $lt{'use'}</label></td><td></td></tr>
 <tr><td>$crscheckbox $lt{'full'}</td><td></td></tr>  <tr><td><label>$crscheckbox $lt{'full'}</label></td><td></td></tr>
   <tr><td><label>$discheckbox $lt{'disc'}</label></td><td></td></tr>
 </table><p>  </table><p>
 &nbsp;<input type="submit" name="coursesubmit" value='$lt{'srch'}' />  &nbsp;<input type="submit" name="coursesubmit" value='$lt{'srch'}' />
 </p>  </p>
   </center>
   </form>
 ENDENDCOURSE  ENDENDCOURSE
     }      }
     $scrout.=(<<ENDDOCUMENT);      $scrout .= &Apache::loncommon::end_page();
 </body>  
 </html>  
 ENDDOCUMENT  
     $r->print($scrout);      $r->print($scrout);
     return;      return;
 }  }
   
   sub setup_basic_search {
       my ($r,$area,$hidden_fields,$closebutton) = @_;
       # Define interface components
       my %lt = &Apache::lonlocal::texthash (
                                 res => 'LON-CAPA Catalog Search',
                                 portfolio => 'Portfolio Search',
       );
       my ($userelatedwords,$onlysearchdomain,$inclext,$adv_search_link,$scrout);
       $userelatedwords = '<label>'.&mt('[_1] use related words',
         &Apache::lonhtmlcommon::checkbox('related',$env{'form.related'},'related')).
                          '</label>';
       $onlysearchdomain = '<label>'.&mt('[_1] only search domain [_2]',
         &Apache::lonhtmlcommon::checkbox('domains',$env{'form.domains'},
                                          $r->dir_config('lonDefDomain')),
         $r->dir_config('lonDefDomain')).
                           '</label>';
       if ($area eq 'res') {
           $inclext= '<label>'.&mt('[_1] include external resources',
                &Apache::lonhtmlcommon::checkbox('inclext',$env{'form.inclext'})).
                     '</label>';
       }
       $adv_search_link = '<a href="/adm/searchcat?'.
                          'phase=disp_adv&'.
                          'catalogmode='.$env{'form.catalogmode'}.
                          '&launch='.$env{'form.launch'}.
                          '&mode='.$env{'form.mode'}.
                          '&area='.$area.
                          '&form='.$env{'form.form'}.
                          '&titleelement='.$env{'form.titleelement'}.
                          '&element='.$env{'form.element'}.
                          '">'.&mt('Advanced Search').'</a>';
       #
       $scrout.='<form name="loncapa_search" method="post" '.
                'action="/adm/searchcat">'.
                '<input type="hidden" name="phase" value="basic_search" />'.
                $hidden_fields;
                if (!exists($env{'form.area'})) {
                    $scrout .= '<input type="hidden" name="area" value="'.$area.'" />';
                }
       #
       $scrout .= '<center>'.$/;
   #    if ($env{'request.course.id'}) {
           $scrout .= '<h1>'.$lt{$area}.'</h1>';
   #    } else {
           # No need to tell them they are searching
   #        $scrout.= ('<br />'x2);
   #    }
       $scrout.='<table>'.
                '<tr><td align="center" valign="top">'.
                &Apache::lonhtmlcommon::textbox('basicexp',
                                                $env{'form.basicexp'},50).
                '<br />'.
               '<font size="-1">'.&searchhelp().'</font>'.'</td>'.
               '<td><font size="-1">'.
               '<nobr>'.('&nbsp;'x3).$adv_search_link.'</nobr>'.'<br />'.
               '<nobr>'.('&nbsp;'x1).$userelatedwords.'</nobr>'.'<br />'.
               '<nobr>'.('&nbsp;'x1).$onlysearchdomain.'</nobr>'.'<br />'.
               '<nobr>'.('&nbsp;'x1).$inclext.'</nobr>'.'<br />'.
                '</font></td>'.
               '</tr>'.$/;
       #
       $scrout .= '<tr><td align="center" colspan="2">'.
                  '<font size="-1">'.
                  '<input type="submit" name="basicsubmit" '.
                  'value="'.&mt('Search').'" />'.
                  ('&nbsp;'x2).$closebutton.('&nbsp;'x2). &viewoptions().
                  '</font>'.
                  '</td></tr>'.$/;
       $scrout .= '</table>'.$/.'</center>'.'</form>';
       return $scrout;
   } 
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 642  Prints the advanced search form. Line 824  Prints the advanced search form.
 ######################################################################  ######################################################################
 sub print_advanced_search_form{  sub print_advanced_search_form{
     my ($r,$closebutton,$hidden_fields) = @_;      my ($r,$closebutton,$hidden_fields) = @_;
       my $bread_crumb = 
           &Apache::lonhtmlcommon::breadcrumbs('Searching','Search_Advanced',
       $env{'form.catalogmode'} ne 'import');
     my %lt=&Apache::lonlocal::texthash('srch' => 'Search',      my %lt=&Apache::lonlocal::texthash('srch' => 'Search',
        'reset' => 'Reset',         'reset' => 'Reset',
        'help' => 'Help');         'help' => 'Help');
     my $advanced_buttons = <<"END";      my $advanced_buttons=<<"END";
 <p>  
 <input type="submit" name="advancedsubmit" value='$lt{"srch"}' />  <input type="submit" name="advancedsubmit" value='$lt{"srch"}' />
 <input type="reset" name="reset" value='$lt{"reset"}' />  <input type="reset" name="reset" value='$lt{"reset"}' />
 $closebutton  $closebutton
 <input type="button" value="$lt{'help'}" onClick="openhelp()" />  
 END  END
     my $bodytag=&Apache::loncommon::bodytag('Advanced Catalog Search').      my $srchtype = 'Catalog';
         &Apache::lonhtmlcommon::breadcrumbs(undef,'Searching',      my $jscript;
                                             'Finding_Resources',      if ($env{'form.area'} eq 'portfolio') {
                                             undef,undef,          $srchtype = 'Portfolio';
                                             ! $ENV{'form.launch'});          $jscript = '<script type="text/javascript">
     my $searchhelp=&searchhelp();  function additional_metadata() {
     my $scrout=&search_html_header();      if (document.advsearch.newfield.checked) {
           document.advsearch.phase.value = "disp_adv";
           document.advsearch.numaddedfields.value = parseInt(document.advsearch.numaddedfields.value) +1;
           document.advsearch.submit();
       }
   }
   </script>';
       }
       my $scrout= &Apache::loncommon::start_page("Advanced $srchtype Search",
                                                  $jscript);
     $scrout .= <<"ENDHEADER";      $scrout .= <<"ENDHEADER";
 $bodytag  $bread_crumb
 <form method="post" action="/adm/searchcat" name="advsearch">  <form method="post" action="/adm/searchcat" name="advsearch">
   <p>
 $advanced_buttons  $advanced_buttons
 ENDHEADER  ENDHEADER
     $scrout.=('&nbsp;'x2).&viewoptions().'</p>'.$hidden_fields.       $scrout.=('&nbsp;'x2).&viewoptions().'</p>'.$hidden_fields. 
         '<input type="hidden" name="phase" value="adv_search" />';          '<input type="hidden" name="phase" value="adv_search" />';
     my %fields=&Apache::lonmeta::fieldnames();      my %fields=&Apache::lonmeta::fieldnames();
     #      #
     $scrout.= '<p>'.$searchhelp.'</p>'.      $scrout .= '<h3>'.&mt('Standard [_1] Metadata',$srchtype).'</h3>';
         "<table>\n";      $scrout .= "<table>\n";
       $scrout .= '<tr><td>&nbsp;</td><td colspan="2"><font size="-1">'.
           ('&nbsp;'x2).&searchhelp()."</font></td></tr>\n";
     my %related_word_search =       my %related_word_search = 
         ('title'=>1,          ('title'    => 1,
          'author'=>0,           'author'   => 0,
          'owner'=>0,           'owner'    => 0,
          'authorspace'=>0,           'authorspace'  => 0,
          'modifyinguser'=>0,           'modifyinguser'=> 0,
          'keywords'=>1,           'keywords' => 1,
          'notes'=>1,           'notes'    => 1,
          'abstract'=>1,           'abstract' => 1,
          'standards'=>1,           'standards'=> 1,
          'mime'=>1,           'mime'     => 1,
    'subject'  => 1,
          );           );
     #      #
     foreach my $field ('title','author','owner','authorspace','modifyinguser',      foreach my $field ('title','author','subject','owner','authorspace',
      'keywords','notes','abstract','standards','mime') {         'modifyinguser','keywords','notes','abstract',
          'standards','mime') {
  $scrout.='<tr><td align="right">'.&titlefield($fields{$field}).'</td><td>'.   $scrout.='<tr><td align="right">'.&titlefield($fields{$field}).'</td><td>'.
     &Apache::lonmeta::prettyinput($field,      &Apache::lonmeta::prettyinput($field,
                                           $ENV{'form.'.$field},                                            $env{'form.'.$field},
                                           $field,                                            $field,
                                           'advsearch',                                            'advsearch',
   $related_word_search{$field},    $related_word_search{$field},
                                           '</td><td align="left">',                                            '</td><td align="left">',
                                           $ENV{'form.'.$field.'_related'},                                            $env{'form.'.$field.'_related'},
                                           50);                                            50);
         if ($related_word_search{$field}) {          if ($related_word_search{$field}) {
             $scrout .= 'related words';              $scrout .= 'related words';
Line 706  ENDHEADER Line 903  ENDHEADER
             '<td align="right">'.&titlefield($fields{$field}).'</td>'.              '<td align="right">'.&titlefield($fields{$field}).'</td>'.
             '<td colspan="2">'.              '<td colspan="2">'.
     &Apache::lonmeta::prettyinput($field,      &Apache::lonmeta::prettyinput($field,
                                           $ENV{'form.'.$field},                                            $env{'form.'.$field},
                                           $field,                                            $field,
                                           'advsearch',                                            'advsearch',
   0).    0).
Line 715  ENDHEADER Line 912  ENDHEADER
     $scrout.='<tr><td align="right">'.      $scrout.='<tr><td align="right">'.
  &titlefield(&mt('MIME Type Category')).'</td><td colspan="2">'.    &titlefield(&mt('MIME Type Category')).'</td><td colspan="2">'. 
     &Apache::loncommon::filecategoryselect('category',      &Apache::loncommon::filecategoryselect('category',
    $ENV{'form.category'}).     $env{'form.category'}).
     '</td></tr>'.$/;      '</td></tr>'.$/;
     $scrout.='<tr><td align="right" valign="top">'.      $scrout.='<tr><td align="right" valign="top">'.
  &titlefield(&mt('Domains')).'</td><td colspan="2">'.    &titlefield(&mt('Domains')).'</td><td colspan="2">'. 
     &Apache::loncommon::domain_select('domains',      &Apache::loncommon::domain_select('domains',
    $ENV{'form.domains'},1).     $env{'form.domains'},1).
     '</td></tr>'.$/;     '<br /><label>';
     $scrout .= "</table>\n<br />\n<table>\n";              if ($env{'form.area'} ne 'portfolio') {
     my %dates=&Apache::lonlocal::texthash                  $scrout .= &mt('[_1] include external resources',
         ('creationdatestart'     => 'Creation Date After',                             &Apache::lonhtmlcommon::checkbox
          'creationdateend'       => 'Creation Date Before',                             ('inclext',$env{'form.inclext'})).'</label>'
          'lastrevisiondatestart' => 'Last Revision Date After',              }
          'lastrevisiondateend'   => 'Last Revision Date Before');       $scrout .= '</td></tr>'.$/;
     foreach my $field (sort keys %dates) {      #
  $scrout.='<tr>'.      # Misc metadata
             '<td align="right">'.&titlefield($dates{$field}).'</td><td>'.       if ($env{'form.area'} ne 'portfolio') {
     &Apache::lonhtmlcommon::date_setter('advsearch',$field,0,'',1).          $scrout.='<tr><td align="right" valign="top">'.
     '</td></tr>'.$/;           &titlefield(&mt('Copyright/Distribution')).
                    '</td><td colspan="2">'.
                    &Apache::lonmeta::selectbox('copyright',
                                                $env{'form.copyright'},
                                   \&Apache::loncommon::copyrightdescription,
                                          ( undef,
                                           &Apache::loncommon::copyrightids)
                                   ).'</td></tr>'.$/;
     }      }
       $scrout.='<tr><td align="right" valign="top">'.
    &titlefield(&mt('Language')).'</td><td colspan="2">'.
           &Apache::lonmeta::selectbox('language',
                                       $env{'form.language'},
                                       \&Apache::loncommon::languagedescription,
                                       ('any',&Apache::loncommon::languageids)
                                       ).'</td></tr>';
       $scrout .= "</table>\n";
   
       
       if ($env{'form.area'} eq 'portfolio') {
           # Added fields
           my $curnumadd = $env{'form.numaddedfields'};
           if ($curnumadd eq '') {
               $curnumadd = 1;
           }
           $scrout .= '<h3>'.&mt('Custom Metadata fields').'</h3>';
           $scrout .= "<table>\n";
           $scrout .= '<tr><td>&nbsp;</td><td align="center">'.
                      &mt('Field Name').'</td>'.'<td align="center">'.
                      &mt('Field Value(s)').'</td></tr>';
   
           for (my $j=0; $j<$curnumadd; $j++) {
               my $num = $j+1;
               $scrout .= '<tr><td>'.&mt('Custom metadata [_1]: ',$num).
                          '</td><td align="center">'.
                          '<input type="text" name="addedfield_'.$j.
                          '" size="10" value="'.$env{'form.addedfield_'.$j}.
                          '" /></td>'.
                          '<td align="center"><input type="text" '.
                          'name="addedvalues_'.$j.'" size="15" value="'.
                          $env{'form.addedvalues_'.$j}.'" /></td></tr>';
           }
           $scrout .= '<tr><td align="left" colspan="3"><label>'.
                      '<input type="checkbox" name="newfield" '.
                      'value="1" onclick="javascript:additional_metadata()" />'.
                      &mt('Another custom field/value pair?').'</label>'.
                      '<input type="hidden" name="numaddedfields" value="'.
                      $curnumadd.'" /></td></tr></table>';
       } else {
           #
           # Dynamic metadata
           $scrout .= '<h3>'.&mt('Problem Statistics').'</h3>';
           $scrout .= "<table>\n";
           $scrout .= '<tr><td>&nbsp;</td><td align="center">'.
                      &mt('Minimum').'</td>'.'<td align="center">'.
                      &mt('Maximum').'</td></tr>'."\n";
           foreach my $statistic 
               ({ name=>'count',
                  description=>'Network-wide number of accesses (hits)',},
                { name=>'stdno',
                  description=>
                  'Statistics calculated for number of students',},
                { name => 'avetries',
                  description=>'Average number of tries till solved',},
                { name => 'difficulty',
                  description=>'Degree of difficulty',},
                { name => 'disc',
                  description=>'Degree of discrimination'}) {
                 $scrout .= '<tr><td align="right">'.
                            &titlefield(&mt($statistic->{'description'})).
                            '</td><td align="center">'.
                            '<input type="text" name="'.$statistic->{'name'}.
                            '_min" value="" size="6" /></td><td align="center">'.
                            '<input type="text" name="'.$statistic->{'name'}.
                            '_max" value="" size="6" /></td></tr>'.$/;
           }
           $scrout .= "</table>\n";
           $scrout .= '<h3>'.&mt('Evaluation Data').'</h3>';
           $scrout .= "<table>\n";
           $scrout .= '<tr><td>&nbsp;</td><td align="center">'.
                      &mt('Minimum').'</td>'.'<td align="center">'.
                      &mt('Maximum').'</td></tr>'."\n";
           foreach my $evaluation
               ( { name => 'clear',
                   description => 'Material presented in clear way'},
                 { name =>'depth',
                   description => 'Material covered with sufficient depth'},
                 { name => 'helpful',
                   description => 'Material is helpful'},
                 { name => 'correct',
                   description => 'Material appears to be correct'},
                 { name => 'technical',
                   description => 'Resource is technically correct'}){
               $scrout .= '<tr><td align="right">'.
                          &titlefield(&mt($evaluation->{'description'})).
                          '</td><td align="center">'.
                          '<input type="text" name="'.
                          $evaluation->{'name'}.'_min" value="" size="6" />'.
                          '</td><td align="center"><input type="text" name="'.
                          $evaluation->{'name'}.'_max" value="" size="6" />'.
                          '</td></tr>'.$/;
           }
           $scrout .= "</table>\n";
       }
       #
       # Creation/Modification date limits
       $scrout .= '<h3>'.&mt('Creation and Modification dates').'</h3>';
       $scrout .= "\n<table>\n";
       my $cafter = 
           &Apache::lonhtmlcommon::date_setter('advsearch',         # formname
                                               'creationdate1', # fieldname
                                               0,           # current value
                                               '',          # special 
                                               1,           # includeempty
                                               '',          # state
                                               1,           # no_hh_mm_ss
                                               );
       my $cbefore = 
           &Apache::lonhtmlcommon::date_setter('advsearch',         # formname
                                               'creationdate2', # fieldname
                                               0,           # current value
                                               '',          # special 
                                               1,           # includeempty
                                               '',          # state
                                               1,           # no_hh_mm_ss
                                               );
       $scrout .= &mt('<tr><td align="right">Created between</td>'.
                      '<td>[_1]</td></tr>'.
                      '<tr><td align="right">and </td>'.
                      '<td>[_2]</td></tr>',$cafter,$cbefore);
       my $lafter = 
           &Apache::lonhtmlcommon::date_setter('advsearch',
                                               'revisiondate1', 
                                               0,           # current value
                                               '',          # special 
                                               1,           # includeempty
                                               '',          # state
                                               1,           # no_hh_mm_ss
                                               );
       my $lbefore = 
           &Apache::lonhtmlcommon::date_setter('advsearch',
                                               'revisiondate2',
                                               0,           # current value
                                               '',          # special 
                                               1,           # includeempty
                                               '',          # state
                                               1,           # no_hh_mm_ss
                                               );
       $scrout .= &mt('<tr><td align="right">Last modified between </td>'.
                      '<td>[_1]</td></tr>'.
                      '<tr><td align="right">and</td>'.
                      '<td>[_2]</td></tr>',$lafter,$lbefore);
     $scrout.="</table>\n";      $scrout.="</table>\n";
     $scrout.=<<ENDDOCUMENT;      $scrout.=<<ENDDOCUMENT;
 $advanced_buttons  $advanced_buttons
 </form>  </form>
 </body>  
 </html>  
 ENDDOCUMENT  ENDDOCUMENT
       $scrout .= &Apache::loncommon::end_page();
     $r->print($scrout);      $r->print($scrout);
     return;      return;
 }  }
Line 787  sub viewoptiontext { Line 1133  sub viewoptiontext {
          'xml' => 'XML/SGML',           'xml' => 'XML/SGML',
          'compact' => 'Compact View',           'compact' => 'Compact View',
          'fielded' => 'Fielded Format',           'fielded' => 'Fielded Format',
          'summary' => 'Summary View');           'summary' => 'Summary View',
            'summarypreview' => 'Summary Preview',
            'detailedpreview' => 'Detailed Citation Preview');
     return $desc{$code};      return $desc{$code};
 }  }
   
Line 807  Outputs: text for box with view options Line 1155  Outputs: text for box with view options
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub viewoptions {  sub viewoptions {
     my $scrout="\n".'<nobr>';      my $scrout;
     if (! defined($ENV{'form.viewselect'})) {       if (! defined($env{'form.viewselect'})) { 
         $ENV{'form.viewselect'}='detailed';           $env{'form.viewselect'}='detailed'; 
     }      }
     $scrout.=&Apache::lonmeta::selectbox('viewselect',      $scrout.=&Apache::lonmeta::selectbox('viewselect',
  $ENV{'form.viewselect'},   $env{'form.viewselect'},
  \&viewoptiontext,   \&viewoptiontext,
  sort(keys(%Views)));   sort(keys(%Views)));
     $scrout.= '&nbsp;&nbsp;';      $scrout.= '&nbsp;&nbsp;';
     $scrout.=&Apache::lonmeta::selectbox('show',      my $countselect = &Apache::lonmeta::selectbox('show',
  $ENV{'form.show'},                                                    $env{'form.show'},
  undef,                                                    undef,
  (10,20,50,100,1000,10000));                                                    (10,20,50,100,1000,10000));
     $scrout .= ('&nbsp;'x2).&mt('Records per Page').'</nobr>'.$/;      $scrout .= ('&nbsp;'x2).&mt('[_1] Records per Page',$countselect).
           '</nobr>'.$/;
     return $scrout;      return $scrout;
 }  }
   
Line 840  Outputs: return little blurb on how to e Line 1189  Outputs: return little blurb on how to e
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub searchhelp {  sub searchhelp {
     return &mt('Enter terms or phrases separated by AND, OR, or NOT');      return &mt('Enter words and quoted phrases');
 }  }
   
 ######################################################################  ######################################################################
Line 856  Outputs: returns undef on database error Line 1205  Outputs: returns undef on database error
   
 This function is the reverse of &make_persistent() for form data.  This function is the reverse of &make_persistent() for form data.
 Retrieve persistent data from %persistent_db.  Retrieved items will have their  Retrieve persistent data from %persistent_db.  Retrieved items will have their
 values unescaped.  If a form value already exists in $ENV, it will not be  values unescaped.  If a form value already exists in $env, it will not be
 overwritten.  Form values that are array references may have values appended  overwritten.  Form values that are array references may have values appended
 to them.  to them.
   
Line 878  sub get_persistent_form_data { Line 1227  sub get_persistent_form_data {
         next if ($name !~ /^form./);          next if ($name !~ /^form./);
         # Kludgification begins!          # Kludgification begins!
         if ($name eq 'form.domains' &&           if ($name eq 'form.domains' && 
             $ENV{'form.searchmode'} eq 'basic' &&              $env{'form.searchmode'} eq 'basic' &&
             $ENV{'form.phase'} ne 'disp_basic') {              $env{'form.phase'} ne 'disp_basic') {
             next;              next;
         }          }
         # End kludge (hopefully)          # End kludge (hopefully)
         next if (exists($ENV{$name}));          next if (exists($env{$name}));
         my @values = map {           my @values = map { 
             &Apache::lonnet::unescape($_);              &unescape($_);
         } split(',',$persistent_db{$name});          } split(',',$persistent_db{$name});
         next if (@values <1);          next if (@values <1);
         if ($arrays_allowed{$name}) {          if ($arrays_allowed{$name}) {
             $ENV{$name} = [@values];              $env{$name} = [@values];
         } else {          } else {
             $ENV{$name} = $values[0] if ($values[0]);              $env{$name} = $values[0] if ($values[0]);
         }          }
     }      }
     untie (%persistent_db);      untie (%persistent_db);
Line 931  sub get_persistent_data { Line 1280  sub get_persistent_data {
             next;              next;
         }          }
         my @values = map {           my @values = map { 
             &Apache::lonnet::unescape($_);              &unescape($_);
         } split(',',$persistent_db{$name});          } split(',',$persistent_db{$name});
         if (@values <= 1) {          if (@values <= 1) {
             push @Values,$values[0];              push @Values,$values[0];
Line 968  sub make_persistent { Line 1317  sub make_persistent {
     foreach my $name (keys(%save)) {      foreach my $name (keys(%save)) {
         my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));          my @values = (ref($save{$name}) ? @{$save{$name}} : ($save{$name}));
         # We handle array references, but not recursively.          # We handle array references, but not recursively.
         my $store = join(',', map { &Apache::lonnet::escape($_); } @values );          my $store = join(',', map { &escape($_); } @values );
         $persistent_db{$name} = $store;          $persistent_db{$name} = $store;
     }      }
     untie(%persistent_db);      untie(%persistent_db);
Line 996  sub make_form_data_persistent { Line 1345  sub make_form_data_persistent {
     my $r = shift;      my $r = shift;
     my $filename = shift;      my $filename = shift;
     my %save;      my %save;
     foreach (keys(%ENV)) {      foreach (keys(%env)) {
         next if (!/^form/ || /submit/);          next if (!/^form/ || /submit/);
         $save{$_} = $ENV{$_};          $save{$_} = $env{$_};
     }      }
     return &make_persistent(\%save,$filename);      return &make_persistent(\%save,$filename);
 }  }
Line 1030  Parse advanced search form and return th Line 1379  Parse advanced search form and return th
 ######################################################################  ######################################################################
 sub parse_advanced_search {  sub parse_advanced_search {
     my ($r,$closebutton,$hidden_fields)=@_;      my ($r,$closebutton,$hidden_fields)=@_;
       my @BasicFields = ('title','author','subject','keywords','url','version',
                          'notes','abstract','extension','owner','authorspace',
   #                       'custommetadata','customshow',
                          'modifyinguser','standards','mime');
       my @StatsFields = &statfields();
       my @EvalFields = &evalfields();
     my $fillflag=0;      my $fillflag=0;
     my $pretty_search_string = "<br />\n";      my $pretty_search_string = "";
     # Clean up fields for safety      # Clean up fields for safety
     for my $field ('title','author','subject','keywords','url','version',      for my $field (@BasicFields,
    'creationdatestart_month','creationdatestart_day',                     'creationdatestart_month','creationdatestart_day',
    'creationdatestart_year','creationdateend_month',     'creationdatestart_year','creationdateend_month',
    'creationdateend_day','creationdateend_year',     'creationdateend_day','creationdateend_year',
    'lastrevisiondatestart_month','lastrevisiondatestart_day',     'lastrevisiondatestart_month','lastrevisiondatestart_day',
    'lastrevisiondatestart_year','lastrevisiondateend_month',     'lastrevisiondatestart_year','lastrevisiondateend_month',
    'lastrevisiondateend_day','lastrevisiondateend_year',     'lastrevisiondateend_day','lastrevisiondateend_year') {
    'notes','abstract','extension','language','owner',   $env{'form.'.$field}=~s/[^\w\/\s\(\)\=\-\"\'.]//g;
    'custommetadata','customshow','category') {  
  $ENV{"form.$field"}=~s/[^\w\/\s\(\)\=\-\"\']//g;  
     }      }
     foreach ('mode','form','element') {      foreach ('mode','form','element') {
  # is this required?  Hmmm.   # is this required?  Hmmm.
  next unless (exists($ENV{"form.$_"}));   next if (! exists($env{'form.'.$_}));
  $ENV{"form.$_"}=&Apache::lonnet::unescape($ENV{"form.$_"});   $env{'form.'.$_}=&unescape($env{'form.'.$_});
  $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;   $env{'form.'.$_}=~s/[^\w\/\s\(\)\=\-\"\']//g;
     }      }
     # Preprocess the category form element.      # Preprocess the category form element.
     $ENV{'form.category'} = 'any' if (! defined($ENV{'form.category'}) ||      $env{'form.category'} = 'any' if (! defined($env{'form.category'}) ||
                                       ref($ENV{'form.category'}));                                        ref($env{'form.category'}));
     #      #
     # Check to see if enough information was filled in      # Check to see if enough information was filled in
     for my $field ('title','author','subject','keywords','url','version',      foreach my $field (@BasicFields) {
    'notes','abstract','category','extension','language',   if (&filled($env{'form.'.$field})) {
                    'owner','custommetadata') {  
  if (&filled($ENV{"form.$field"})) {  
     $fillflag++;      $fillflag++;
  }   }
     }      }
       foreach my $field (@StatsFields,@EvalFields) {
           if (&filled($env{'form.'.$field.'_max'})) {
               $fillflag++;
           }
           if (&filled($env{'form.'.$field.'_min'})) {
               $fillflag++;
           }
       }
   
       for my $field ('lowestgradelevel','highestgradelevel') {
           if ( $env{'form.'.$field} =~ /^\d+$/ &&
                $env{'form.'.$field} > 0) {
               $fillflag++;
           }
       }
       if ($env{'form.area'} eq 'portfolio') {
           # Added metadata fields
           for (my $i=0; $i<$env{'form.numaddedfields'} ; $i++) {
               my $field = $env{'form.addedfield_'.$i};
               $field =~ s/^\s*(\S*)\s*$/$1/;
               $field =~ s/\W/_/g;
               if ($field ne '') {
                   $fillflag++;
               }
           }
       }
     if (! $fillflag) {      if (! $fillflag) {
  &output_blank_field_error($r,$closebutton,   &output_blank_field_error($r,$closebutton,
                                   'phase=disp_adv',$hidden_fields);                                    'phase=disp_adv',$hidden_fields);
Line 1072  sub parse_advanced_search { Line 1449  sub parse_advanced_search {
     my @queries;      my @queries;
     my $font = '<font color="#800000" face="helvetica">';      my $font = '<font color="#800000" face="helvetica">';
     # Evaluate logical expression AND/OR/NOT phrase fields.      # Evaluate logical expression AND/OR/NOT phrase fields.
     foreach my $field ('title','author','subject','notes','abstract','url',      foreach my $field (@BasicFields) {
        'keywords','version','owner','standards') {   next if (!defined($env{'form.'.$field}) || $env{'form.'.$field} eq '');
  if ($ENV{'form.'.$field}) {          my ($error,$SQLQuery) = 
             my $searchphrase = $ENV{'form.'.$field};              &process_phrase_input($env{'form.'.$field},
             $pretty_search_string .= $font."$field</font> contains <b>".                                    $env{'form.'.$field.'_related'},$field);
                 $searchphrase."</b>";          if (defined($error)) {
             if ($ENV{'form.'.$field.'_related'}) {              &output_unparsed_phrase_error($r,$closebutton,'phase=disp_adv',
                 my @New_Words;                                           $hidden_fields,$field);
                 ($searchphrase,@New_Words) = &related_version($searchphrase);              return;
                 if (@New_Words) {          } else {
                     $pretty_search_string .= " with related words: ".              $pretty_search_string .= 
                         "<b>@New_Words</b>.";                  $font.$field.'</font>: '.$env{'form.'.$field};
               if ($env{'form.'.$field.'_related'}) {
                   my @Words = 
                       &Apache::loncommon::get_related_words
                       ($env{'form.'.$field});
                   if (@Words) {
                       $pretty_search_string.= ' with related words: '.
                           join(', ',@Words[0..4]);
                 } else {                  } else {
                     $pretty_search_string .= " with no related words.";                      $pretty_search_string.= ' with related words.';
                 }                  }
             }              }
             $pretty_search_string .= "<br />\n";              $pretty_search_string .= '<br />';
     push @queries,&build_SQL_query($field,$searchphrase);              push (@queries,$SQLQuery);
         }          }
     }      }
     #      #
     # Make the 'mime' from 'form.category' and 'form.extension'      # Make the 'mime' from 'form.category' and 'form.extension'
     #      #
     my $searchphrase;      my $searchphrase;
     if (exists($ENV{'form.category'})    &&       if (exists($env{'form.category'})    && 
         $ENV{'form.category'} !~ /^\s*$/ &&          $env{'form.category'} !~ /^\s*$/ &&
         $ENV{'form.category'} ne 'any')     {          $env{'form.category'} ne 'any')     {
         my @extensions = &Apache::loncommon::filecategorytypes          my @extensions = &Apache::loncommon::filecategorytypes
                                                    ($ENV{'form.category'});                                                     ($env{'form.category'});
         if (scalar(@extensions) > 0) {          if (scalar(@extensions) > 0) {
             $searchphrase = join(' OR ',@extensions);              $searchphrase = join(' OR ',@extensions);
         }          }
     }      }
     if (exists($ENV{'form.extension'}) && $ENV{'form.extension'} !~ /^\s*$/) {  
         $searchphrase .= ' OR ' if (defined($searchphrase));  
         my @extensions = split(/,/,$ENV{'form.extension'});  
         $searchphrase .= join(' OR ',@extensions);  
     }  
     if (defined($searchphrase)) {      if (defined($searchphrase)) {
         push @queries,&build_SQL_query('mime',$searchphrase);          my ($error,$SQLsearch) = &process_phrase_input($searchphrase,0,'mime');
           push @queries,$SQLsearch;
         $pretty_search_string .=$font.'mime</font> contains <b>'.          $pretty_search_string .=$font.'mime</font> contains <b>'.
             $searchphrase.'</b><br />';              $searchphrase.'</b><br />';
     }      }
     #      #
     # Evaluate option lists      # Evaluate option lists
     if ($ENV{'form.language'} and $ENV{'form.language'} ne 'any') {      if ($env{'form.lowestgradelevel'}        &&
  push @queries,"(language like \"$ENV{'form.language'}\")";          $env{'form.lowestgradelevel'} ne '0' &&
           $env{'form.lowestgradelevel'} =~ /^\d+$/) {
    push(@queries,
                '(lowestgradelevel>='.$env{'form.lowestgradelevel'}.')');
           $pretty_search_string.="lowestgradelevel>=".
               $env{'form.lowestgradelevel'}."<br />\n";
       }
       if ($env{'form.highestgradelevel'}        &&
           $env{'form.highestgradelevel'} ne '0' &&
           $env{'form.highestgradelevel'} =~ /^\d+$/) {
    push(@queries,
                '(highestgradelevel<='.$env{'form.highestgradelevel'}.')');
           $pretty_search_string.="highestgradelevel<=".
               $env{'form.highestgradelevel'}."<br />\n";
       }
       if ($env{'form.language'} and $env{'form.language'} ne 'any') {
    push @queries,"(language like \"$env{'form.language'}\")";
         $pretty_search_string.=$font."language</font>= ".          $pretty_search_string.=$font."language</font>= ".
             &Apache::loncommon::languagedescription($ENV{'form.language'}).              &Apache::loncommon::languagedescription($env{'form.language'}).
                 "<br />\n";                  "<br />\n";
     }      }
     if ($ENV{'form.copyright'} and $ENV{'form.copyright'} ne 'any') {      if ($env{'form.copyright'} and $env{'form.copyright'} ne 'any') {
  push @queries,"(copyright like \"$ENV{'form.copyright'}\")";   push @queries,"(copyright like \"$env{'form.copyright'}\")";
         $pretty_search_string.=$font."copyright</font> = ".          $pretty_search_string.=$font."copyright</font> = ".
             &Apache::loncommon::copyrightdescription($ENV{'form.copyright'}).              &Apache::loncommon::copyrightdescription($env{'form.copyright'}).
                 "<br \>\n";                  "<br />\n";
       }
       if ($env{'form.area'} eq 'portfolio') {
           #
           # Added metadata fields
           for (my $i=0; $i<$env{'form.numaddedfields'} ; $i++) {
               my $field = $env{'form.addedfield_'.$i};
               $field =~ s/^\s*(\S*)\s*$/$1/;
               $field =~ s/\W/_/g;
               $field =~ tr/A-Z/a-z/; 
               if ($field ne '') {
                   my $value = $env{'form.addedvalues_'.$i};
                   if ($value ne '') {
                       $value =~ s/'/''/g; #' stupid emacs
                       my ($error,$query) = 
                           &process_phrase_input($value,0,'pf.value');
                       if (!defined($error)) {
                           push(@queries,"pf.field = '$field' AND $query");
                           $pretty_search_string .=
                               $font.$field.'</font>: '.
                               $env{'form.addedvalues_'.$i}.'<br />';
                       }
                   } else {
                       push(@queries,"pf.field = '$field' AND pf.value IS NULL");
                   }
               }
           }
       } else {
           #
           # Statistics
           foreach my $field (@StatsFields,@EvalFields) {
               my ($min,$max);
               if (exists($env{'form.'.$field.'_min'}) && 
                   $env{'form.'.$field.'_min'} ne '') {
                   $min = $env{'form.'.$field.'_min'};
               }
               if (exists($env{'form.'.$field.'_max'}) &&
                   $env{'form.'.$field.'_max'} ne '') {
                   $max = $env{'form.'.$field.'_max'};
               }
               next if (! defined($max) && ! defined($min));
               if (defined($min) && defined($max)) {
                   ($min,$max) = sort {$a <=>$b} ($min,$max);
               }
               if (defined($min) && $min =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
                   push(@queries,'('.$field.'>'.$min.')');
                   $pretty_search_string.=$font.$field.'</font>&gt;'.$min.'<br />';
               }
               if (defined($max) && $max =~ /^(\d+\.\d+|\d+|\.\d+)$/) {
                   push(@queries,'('.$field.'<'.$max.')');
                   $pretty_search_string.=$font.$field.'</font>&lt;'.$max.'<br />';
               }
           }
     }      }
     #      #
     # Evaluate date windows      # Evaluate date windows
     my $datequery=&build_date_queries(      my $cafter =
  $ENV{'form.creationdatestart_month'},          &Apache::lonhtmlcommon::get_date_from_form('creationdate1');
  $ENV{'form.creationdatestart_day'},      my $cbefore = 
  $ENV{'form.creationdatestart_year'},          &Apache::lonhtmlcommon::get_date_from_form('creationdate2');
  $ENV{'form.creationdateend_month'},      if ($cafter > $cbefore) {
  $ENV{'form.creationdateend_day'},          my $tmp = $cafter;
  $ENV{'form.creationdateend_year'},          $cafter = $cbefore;
  $ENV{'form.lastrevisiondatestart_month'},          $cbefore = $tmp;
  $ENV{'form.lastrevisiondatestart_day'},      }
  $ENV{'form.lastrevisiondatestart_year'},      my $mafter = 
  $ENV{'form.lastrevisiondateend_month'},          &Apache::lonhtmlcommon::get_date_from_form('revisiondate1');
  $ENV{'form.lastrevisiondateend_day'},      my $mbefore =
  $ENV{'form.lastrevisiondateend_year'},          &Apache::lonhtmlcommon::get_date_from_form('revisiondate2');
  );      if ($mafter > $mbefore) {
     # Test to see if date windows are legitimate          my $tmp = $mafter;
     if ($datequery=~/^Incorrect/) {          $mafter = $mbefore;
  &output_date_error($r,$datequery,$closebutton,$hidden_fields);          $mbefore = $tmp;
  return ;      }
     } elsif ($datequery) {      my ($datequery,$error,$prettydate)=&build_date_queries($cafter,$cbefore,
                                                              $mafter,$mbefore);
       if (defined($error)) {
           &output_date_error($r,$error,$closebutton,$hidden_fields);
       } elsif (defined($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
         # date query information.          # date query information.
           $pretty_search_string .= '<br />'.$prettydate.'<br />';
  push @queries,$datequery;   push @queries,$datequery;
     }      }
     #      #
Line 1162  sub parse_advanced_search { Line 1615  sub parse_advanced_search {
     ## because I was unable to figureout exactly how it worked and could      ## because I was unable to figureout exactly how it worked and could
     ## not imagine people actually using it.  MH      ## not imagine people actually using it.  MH
     ##      ##
     # if ($ENV{'form.custommetadata'}) {      # if ($env{'form.custommetadata'}) {
     #    $pretty_search_string .=$font."Custom Metadata Search</font>: <b>".      #    $pretty_search_string .=$font."Custom Metadata Search</font>: <b>".
     #    $ENV{'form.custommetadata'}."</b><br />\n";      #    $env{'form.custommetadata'}."</b><br />\n";
     #    $customquery=&build_custommetadata_query('custommetadata',      #    $customquery=&build_custommetadata_query('custommetadata',
     #                                             $ENV{'form.custommetadata'});      #                                             $env{'form.custommetadata'});
     # }      # }
     my $customshow=undef;      my $customshow=undef;
     # if ($ENV{'form.customshow'}) {      # if ($env{'form.customshow'}) {
     # $pretty_search_string .=$font."Custom Metadata Display</font>: <b>".      # $pretty_search_string .=$font."Custom Metadata Display</font>: <b>".
     #                         $ENV{'form.customshow'}."</b><br />\n";      #                         $env{'form.customshow'}."</b><br />\n";
     #    $customshow=$ENV{'form.customshow'};      #    $customshow=$env{'form.customshow'};
     #    $customshow=~s/[^\w\s]//g;      #    $customshow=~s/[^\w\s]//g;
     #    my @fields=split(/\s+/,$customshow);      #    my @fields=split(/\s+/,$customshow);
     #    $customshow=join(" ",@fields);      #    $customshow=join(" ",@fields);
Line 1180  sub parse_advanced_search { Line 1633  sub parse_advanced_search {
     ##      ##
     ## Deal with restrictions to given domains      ## Deal with restrictions to given domains
     ##       ## 
     my ($libraries_to_query,$pretty_domains_string) =       my ($libraries_to_query,$pretty_domains_string) = &parse_domain_restrictions();
         &parse_domain_restrictions();      if ($pretty_domains_string) {
     $pretty_search_string .= $pretty_domains_string."<br />\n";         $pretty_search_string .= $pretty_domains_string."<br />\n";
       }
     #      #
     if (@queries) {      if (@queries) {
  $query=join(" AND ",@queries);          if ($env{'form.area'} eq 'portfolio') {
  $query="select * from metadata where $query";              $query ="SELECT pm.*,pa.keynum,pa.scope FROM portfolio_metadata pm, portfolio_access pa, portfolio_addedfields pf WHERE (pm.url = pa.url AND pf.url = pm.url AND (pa.start < NOW() AND (pa.end IS NULL OR pa.end > NOW())) AND (".join(') AND (',@queries).'))';
           } else {
       $query="SELECT * FROM metadata WHERE (".join(") AND (",@queries).')';
           }
     } elsif ($customquery) {      } elsif ($customquery) {
         $query = '';          $query = '';
     }      }
       #&Apache::lonnet::logthis('advanced query = '.$/.$query);
     return ($query,$customquery,$customshow,$libraries_to_query,      return ($query,$customquery,$customshow,$libraries_to_query,
             $pretty_search_string);              $pretty_search_string);
 }  }
   
 sub parse_domain_restrictions {  sub parse_domain_restrictions {
     my $libraries_to_query = undef;      my $libraries_to_query = undef;
     # $ENV{'form.domains'} can be either a scalar or an array reference.      # $env{'form.domains'} can be either a scalar or an array reference.
     # We need an array.      # We need an array.
     if (! exists($ENV{'form.domains'})) {      if (! exists($env{'form.domains'}) || $env{'form.domains'} eq '') {
         return (undef,'');          return (undef,'',undef);
     }  
     my @allowed_domains;  
     if (ref($ENV{'form.domains'})) {  
         @allowed_domains =  @{$ENV{'form.domains'}};  
     } else {  
         @allowed_domains = ($ENV{'form.domains'});  
     }      }
       my @allowed_domains = &Apache::loncommon::get_env_multiple('form.domains');
     #      #
     my %domain_hash = ();      my %domain_hash = ();
     my $pretty_domains_string;      my $pretty_domains_string;
Line 1214  sub parse_domain_restrictions { Line 1667  sub parse_domain_restrictions {
         $domain_hash{$_}++;          $domain_hash{$_}++;
     }      }
     if ($domain_hash{'any'}) {      if ($domain_hash{'any'}) {
         $pretty_domains_string = "In all LON-CAPA domains.";          $pretty_domains_string = &mt("in all LON-CAPA domains.");
     } else {      } else {
         if (@allowed_domains > 1) {          if (@allowed_domains > 1) {
             $pretty_domains_string = "In LON-CAPA domains:";              $pretty_domains_string = &mt("in LON-CAPA domains:");
         } else {          } else {
             $pretty_domains_string = "In LON-CAPA domain ";              $pretty_domains_string = &mt("in LON-CAPA domain ");
         }          }
         foreach (sort @allowed_domains) {          foreach (sort @allowed_domains) {
             $pretty_domains_string .= "<b>".$_."</b> ";              $pretty_domains_string .= "<b>".$_."</b> ";
         }          }
         foreach (keys(%Apache::lonnet::libserv)) {   my %servers = &Apache::lonnet::get_servers(\@allowed_domains,
             if (exists($domain_hash{$Apache::lonnet::hostdom{$_}})) {     'library');
                 push @$libraries_to_query,$_;   $libraries_to_query = [keys(%servers)];
             }  
         }  
     }      }
     return ($libraries_to_query,$pretty_domains_string);      return ($libraries_to_query,
               $pretty_domains_string);
 }  }
   
 ######################################################################  ######################################################################
Line 1251  sub parse_basic_search { Line 1703  sub parse_basic_search {
     #      #
     # 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;
     }      }
     foreach ('mode','form','element') {      foreach ('mode','form','element') {
  # is this required?  Hmmm.   # is this required?  Hmmm.
  next unless (exists($ENV{"form.$_"}));   next unless (exists($env{"form.$_"}));
  $ENV{"form.$_"}=&Apache::lonnet::unescape($ENV{"form.$_"});   $env{"form.$_"}=&unescape($env{"form.$_"});
  $ENV{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;   $env{"form.$_"}=~s/[^\w\/\s\(\)\=\-\"\']//g;
     }      }
     my ($libraries_to_query,$pretty_domains_string) =       my ($libraries_to_query,$pretty_domains_string) = &parse_domain_restrictions();
         &parse_domain_restrictions();  
     #      #
     # Check to see if enough of a query is filled in      # Check to see if enough of a query is filled in
     unless (&filled($ENV{'form.basicexp'})) {      my $search_string = $env{'form.basicexp'};
       if (! &filled($search_string)) {
  &output_blank_field_error($r,$closebutton,'phase=disp_basic');   &output_blank_field_error($r,$closebutton,'phase=disp_basic');
  return OK;   return OK;
     }      }
     my $pretty_search_string = '<b>'.$ENV{'form.basicexp'}.'</b>';      my $pretty_search_string=$search_string;
     my $search_string = $ENV{'form.basicexp'};      my @Queries;
     if ($ENV{'form.related'}) {      my @fields = ('title','author','subject','notes','abstract','keywords');
         my @New_Words;      my $searchfield;
         ($search_string,@New_Words) = &related_version($ENV{'form.basicexp'});      if ($env{'form.area'} eq 'portfolio') {
         if (@New_Words) {          $searchfield = 'concat_ws(" ",pm.'.join(',pm.',@fields).')';
             $pretty_search_string .= " with related words: <b>@New_Words</b>.";      } else {
         } else {          $searchfield = 'concat_ws(" ",'.join(',',@fields).')';
             $pretty_search_string .= " with no related words.";      }
         }      my ($error,$SQLQuery) = &process_phrase_input($search_string,
                                                       $env{'form.related'},
                                                       $searchfield);
       if ($error) {
           &output_unparsed_phrase_error($r,$closebutton,'phase=disp_basic',
                                         '','basicexp');
           return;
       }
       push(@Queries,$SQLQuery);
       #foreach my $q (@Queries) {
       #    &Apache::lonnet::logthis('    '.$q);
       #}
       my $final_query;
       if ($env{'form.area'} eq 'portfolio') {
           $final_query = 'SELECT pm.*,pa.keynum,pa.scope FROM portfolio_metadata pm, portfolio_access pa  WHERE (pm.url = pa.url AND (pa.start < NOW() AND (pa.end IS NULL OR pa.end > NOW())) AND '.join(" AND ",@Queries).')';
       } else {
           $final_query = 'SELECT * FROM metadata WHERE '.join(" AND ",@Queries);
     }      }
     #      #
     # Build SQL query string based on form page      if ($env{'form.related'}) {
     my $query='';   $pretty_search_string.=' '.&mt('(including related words)');
     my $concatarg=join(',',      }
        ('title', 'author', 'subject', 'notes', 'abstract',  
                         'keywords'));  
     $concatarg='title' if $ENV{'form.titleonly'};  
     $query=&build_SQL_query('concat_ws(" ",'.$concatarg.')',$search_string);  
     if (defined($pretty_domains_string) && $pretty_domains_string ne '') {      if (defined($pretty_domains_string) && $pretty_domains_string ne '') {
         $pretty_search_string .= ' '.$pretty_domains_string;          $pretty_search_string .= ' '.$pretty_domains_string;
     }      }
     $pretty_search_string .= "<br />\n";      $pretty_search_string .= "<br />\n";
     my $final_query = 'SELECT * FROM metadata WHERE '.$query;      $pretty_search_string =~ s:^<br /> and ::;
     # &Apache::lonnet::logthis($final_query);      &Apache::lonnet::logthis('simple search final query = '.$/.$final_query);
     return ($final_query,$pretty_search_string,      return ($final_query,$pretty_search_string,
             $libraries_to_query);              $libraries_to_query);
 }  }
   
   
   ###############################################################
   ###############################################################
   
   my @Phrases;
   
   sub concat {
       my ($item) = @_;
       my $results = '';
       foreach (@$item) {
           if (ref($_) eq 'ARRAY') {
               $results .= join(' ',@$_);
           }
       }
       return $results;
   }
   
   sub process_phrase_input {
       my ($phrase,$related,$field)=@_;
       #&Apache::lonnet::logthis('phrase = :'.$phrase.':');
       my $grammar = <<'ENDGRAMMAR';
       searchphrase:
           expression /^\Z/ {
               # &Apache::lonsearchcat::print_item(\@item,0);
               [@item];
           }
       expression:
           phrase(s)   {
               [@item];
           }
       phrase:
           orword {
               [@item];
           }
         | andword {
               [@item];
           }
         | minusword {
               unshift(@::Phrases,$item[1]->[0]);
               unshift(@::Phrases,$item[1]->[1]);
               [@item];
           }
         | word {
               unshift(@::Phrases,$item[1]);
               [@item];
           } 
       #
       orword:
           word 'OR' phrase {
               unshift(@::Phrases,'OR');
               unshift(@::Phrases,$item[1]);
               [@item];
           }
           | word 'or' phrase {
               unshift(@::Phrases,'OR');
               unshift(@::Phrases,$item[1]);
               [@item];
           }    
           | minusword 'OR' phrase {
               unshift(@::Phrases,'OR');
               unshift(@::Phrases,$item[1]->[0]);
               unshift(@::Phrases,$item[1]->[1]);
               [@item];
           }
           | minusword 'or' phrase {
               unshift(@::Phrases,'OR');
               unshift(@::Phrases,$item[1]->[0]);
               unshift(@::Phrases,$item[1]->[1]);
               [@item];
           }    
       andword:
           word phrase {
               unshift(@::Phrases,'AND');
               unshift(@::Phrases,$item[1]);
               [@item];
           }
           | minusword phrase {
               unshift(@::Phrases,'AND');
               unshift(@::Phrases,$item[1]->[0]);
               unshift(@::Phrases,$item[1]->[1]);
               [@item];
           }
       #
       minusword:
           '-' word {
               [$item[2],'NOT'];
           }
       word:
           "'" term(s) "'" {
             &Apache::lonsearchcat::concat(\@item);
           }
         | '"' term(s) '"' {
             &Apache::lonsearchcat::concat(\@item);
           }
         | term {
               $item[1];
           }
       term:
           /[\w\Q:!@#$%^&*()+_=|{}<>,.;\\\/?\E\-]+/ {
               $item[1];
           }
   ENDGRAMMAR
       #
       # The end result of parsing the phrase with the grammar is an array
       # @::Phrases.
       # $phrase = "gene splicing" or cat -> "gene splicing","OR","cat"
       # $phrase = "genetic engineering" -dna ->
       #                      "genetic engineering","AND","NOT","dna"
       # $phrase = cat or dog -poodle -> "cat","OR","dog","AND","NOT","poodle"
       undef(@::Phrases);
       my $p = new Parse::RecDescent($grammar);
       if (! defined($p->searchphrase($phrase))) {
           &Apache::lonnet::logthis('lonsearchcat:unable to process:'.$phrase);
           return 'Unable to process phrase '.$phrase;
       }
       #
       # Go through the phrases and make sense of them.  
       # Apply modifiers NOT OR and AND to the phrases.
       my @NewPhrases;
       while(@::Phrases) {
           my $phrase = shift(@::Phrases);
           # &Apache::lonnet::logthis('phrase = '.$phrase);
           my $phrasedata;
           if ($phrase =~ /^(NOT|OR|AND)$/) {
               if ($phrase eq 'OR') {
                   $phrasedata->{'or'}++;
                   if (! @::Phrases) { $phrasedata = undef; last; }
                   $phrase = shift(@::Phrases);
               } elsif ($phrase eq 'AND') {
                   $phrasedata->{'and'}++;
                   if (! @::Phrases) { $phrasedata = undef; last; }
                   $phrase = shift(@::Phrases);
               }
               if ($phrase eq 'NOT') {
                   $phrasedata->{'negate'}++;
                   if (! @::Phrases) { $phrasedata = undef; last; }
                   $phrase = shift(@::Phrases);
               }
           }
           $phrasedata->{'phrase'} = $phrase;
           if ($related) {
               my @NewWords;
               (undef,@NewWords) = &related_version($phrasedata->{'phrase'});
               $phrasedata->{'related_words'} = \@NewWords;
           }
           push(@NewPhrases,$phrasedata);
       }
       #
       # Actually build the sql query from the phrases
       my $SQLQuery;
       foreach my $phrase (@NewPhrases) {
           my $query;
           if ($phrase->{'negate'}) {
               $query .= $field.' NOT LIKE "%'.$phrase->{'phrase'}.'%"';
           } else {
               $query .= $field.' LIKE "%'.$phrase->{'phrase'}.'%"';
           }
           foreach my $related (@{$phrase->{'related_words'}}) {
               if ($phrase->{'negate'}) {
                   $query .= ' AND '.$field.' NOT LIKE "%'.$related.'%"';
               } else {
                   $query .= ' OR '.$field.' LIKE "%'.$related.'%"';
               }
           }
           if ($SQLQuery) {
               if ($phrase->{'or'}) {
                   $SQLQuery .= ' OR ('.$query.')';
               } else {
                   $SQLQuery .= ' AND ('.$query.')';
               }
           } else {
               $SQLQuery = '('.$query.')';
           }
       }
       #
       # &Apache::lonnet::logthis("SQLQuery = $SQLQuery");
       #
       return undef,$SQLQuery;
   }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 1314  Note: Using this twice on a string is pr Line 1958  Note: Using this twice on a string is pr
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub related_version {  sub related_version {
     my $search_string = shift;      my ($word) = @_;
     my $result = $search_string;      return (undef) if (lc($word) =~ /\b(or|and|not)\b/);
     my %New_Words = ();      my @Words = &Apache::loncommon::get_related_words($word);
     while ($search_string =~ /(\w+)/cg) {      # Only use 4 related words
         my $word = $1;      @Words = ($#Words>4? @Words[0..4] : @Words);
         next if (lc($word) =~ /\b(or|and|not)\b/);      my $result = join " OR ", ($word,@Words);
         my @Words = &Apache::loncommon::get_related_words($word);      return $result,sort(@Words);
         @Words = ($#Words>4? @Words[0..4] : @Words);  
         foreach (@Words) { $New_Words{$_}++;}  
         my $replacement = join " OR ", ($word,@Words);  
         $result =~ s/(\b)$word(\b)/$1($replacement)$2/g;  
     }  
     return $result,sort(keys(%New_Words));  
 }  }
   
 ######################################################################  
 ######################################################################  
   
 =pod   
   
 =item &build_SQL_query()   
   
 Builds a SQL query string from a logical expression with AND/OR keywords  
 using Text::Query and &recursive_SQL_query_builder()  
   
 =cut  
   
 ######################################################################  
 ######################################################################  
 sub build_SQL_query {  
     my ($field_name,$logic_statement)=@_;  
     my $q=new Text::Query('abc',  
   -parse => 'Text::Query::ParseAdvanced',  
   -build => 'Text::Query::Build');  
     $q->prepare($logic_statement);  
     my $matchexp=${$q}{'matchexp'}; chomp $matchexp;  
     my $sql_query=&recursive_SQL_query_build($field_name,$matchexp);  
     return $sql_query;  
 }  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
Line 1387  sub build_custommetadata_query { Line 2001  sub build_custommetadata_query {
     return $matchexp;      return $matchexp;
 }  }
   
 ######################################################################  
 ######################################################################  
   
 =pod   
   
 =item &recursive_SQL_query_build()   
   
 Recursively constructs an SQL query.  Takes as input $dkey and $pattern.  
   
 =cut  
   
 ######################################################################  
 ######################################################################  
 sub recursive_SQL_query_build {  
     my ($dkey,$pattern)=@_;  
     my @matches=($pattern=~/(\[[^\]|\[]*\])/g);  
     return $pattern unless @matches;  
     foreach my $match (@matches) {  
         $match=~/\[ (\w+)\s(.*) \]/;  
         my ($key,$value)=($1,$2);  
         my $replacement='';  
         if ($key eq 'literal') {  
             $replacement="($dkey LIKE \"\%$value\%\")";  
         } elsif (lc($key) eq 'not') {  
             $value=~s/LIKE/NOT LIKE/;  
 #          $replacement="($dkey not like $value)";  
             $replacement="$value";  
         } elsif ($key eq 'and') {  
             $value=~/(.*[\"|\)]) ([|\(|\^].*)/;  
             $replacement="($1 AND $2)";  
  } elsif ($key eq 'or') {  
             $value=~/(.*[\"|\)]) ([|\(|\^].*)/;  
             $replacement="($1 OR $2)";  
  }  
  substr($pattern,  
                index($pattern,$match),  
                length($match),  
                $replacement);  
     }  
     &recursive_SQL_query_build($dkey,$pattern);  
 }  
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
Line 1444  Also reports errors (check for /^Incorre Line 2017  Also reports errors (check for /^Incorre
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub build_date_queries {  sub build_date_queries {
     my ($cmonth1,$cday1,$cyear1,$cmonth2,$cday2,$cyear2,      my ($cafter,$cbefore,$mafter,$mbefore) = @_;
  $lmonth1,$lday1,$lyear1,$lmonth2,$lday2,$lyear2)=@_;      my ($result,$error,$pretty_string);
     my @queries;      #
     if ($cmonth1 or $cday1 or $cyear1 or $cmonth2 or $cday2 or $cyear2) {      # Verify the input
  unless ($cmonth1 and $cday1 and $cyear1 and      if (! defined($cafter) && ! defined($cbefore) &&
  $cmonth2 and $cday2 and $cyear2) {          ! defined($mafter) && ! defined($mbefore)) {
     return "Incorrect entry for the creation date.  You must specify ".          # This is an okay situation, so return undef for the error
    "a starting month, day, and year and an ending month, ".          return (undef,undef,undef);
    "day, and year.";      }
  }      if ((defined($cafter)  && ! defined($cbefore)) ||
  my $cnumeric1=sprintf("%d%2d%2d",$cyear1,$cmonth1,$cday1);          (defined($cbefore) && ! defined($cafter))) {
  $cnumeric1+=0;          # This is bad, so let them know
  my $cnumeric2=sprintf("%d%2d%2d",$cyear2,$cmonth2,$cday2);          $error = &mt('Incorrect entry for the creation date.  '.
  $cnumeric2+=0;                      'You must specify both the beginning and ending dates.');
  if ($cnumeric1>$cnumeric2) {      }
     return "Incorrect entry for the creation date.  The starting ".      if (! defined($error) && 
    "date must occur before the ending date.";          ((defined($mafter)  && ! defined($mbefore)) ||
  }          (defined($mbefore) && ! defined($mafter)))) {
  my $cquery="(creationdate BETWEEN '$cyear1-$cmonth1-$cday1' AND '".          # This is also bad, so let them know
            "$cyear2-$cmonth2-$cday2 23:59:59')";          $error = &mt('Incorrect entry for the last revision date.  '.
  push @queries,$cquery;                       'You must specify both the beginning and ending dates.');
     }  
     if ($lmonth1 or $lday1 or $lyear1 or $lmonth2 or $lday2 or $lyear2) {  
  unless ($lmonth1 and $lday1 and $lyear1 and  
  $lmonth2 and $lday2 and $lyear2) {  
     return "Incorrect entry for the last revision date.  You must ".  
    "specify a starting month, day, and year and an ending ".  
    "month, day, and year.";  
  }  
  my $lnumeric1=sprintf("%d%2d%2d",$lyear1,$lmonth1,$lday1);  
  $lnumeric1+=0;  
  my $lnumeric2=sprintf("%d%2d%2d",$lyear2,$lmonth2,$lday2);  
  $lnumeric2+=0;  
  if ($lnumeric1>$lnumeric2) {  
     return "Incorrect entry for the last revision date.  The ".  
    "starting date must occur before the ending date.";  
  }  
  my $lquery="(lastrevisiondate BETWEEN '$lyear1-$lmonth1-$lday1' AND '".  
            "$lyear2-$lmonth2-$lday2 23:59:59')";  
  push @queries,$lquery;  
     }      }
     if (@queries) {      if (! defined($error)) {
  return join(" AND ",@queries);          #
           # Build the queries
           my @queries;
           if (defined($cbefore) && defined($cafter)) {
               my (undef,undef,undef,$caday,$camon,$cayear) = localtime($cafter);
               my (undef,undef,undef,$cbday,$cbmon,$cbyear) = localtime($cbefore);
               # Correct for year being relative to 1900
               $cayear+=1900; $cbyear+=1900;
               my $cquery=
                   '(creationdate BETWEEN '.
                   "'".$cayear.'-'.$camon.'-'.$caday."'".
                   ' AND '.
                   "'".$cbyear.'-'.$cbmon.'-'.$cbday." 23:59:59')";
               $pretty_string .= '<br />' if (defined($pretty_string));
               $pretty_string .= 
                   &mt('created between [_1] and [_2]',
                       &Apache::lonlocal::locallocaltime($cafter),
                       &Apache::lonlocal::locallocaltime($cbefore+24*60*60-1));
               push(@queries,$cquery);
               $pretty_string =~ s/ 00:00:00//g;
           }
           if (defined($mbefore) && defined($mafter)) {
               my (undef,undef,undef,$maday,$mamon,$mayear) = localtime($mafter);
               my (undef,undef,undef,$mbday,$mbmon,$mbyear) = localtime($mbefore);
               # Correct for year being relative to 1900
               $mayear+=1900; $mbyear+=1900;
               my $mquery=
                   '(lastrevisiondate BETWEEN '.
                   "'".$mayear.'-'.$mamon.'-'.$maday."'".
                   ' AND '.
                   "'".$mbyear.'-'.$mbmon.'-'.$mbday." 23:59:59')";
               push(@queries,$mquery);
               $pretty_string .= '<br />' if (defined($pretty_string));
               $pretty_string .= 
                   &mt('last revised between [_1] and [_2]',
                       &Apache::lonlocal::locallocaltime($mafter),
                       &Apache::lonlocal::locallocaltime($mbefore+24*60*60-1));
               $pretty_string =~ s/ 00:00:00//g;
           }
           if (@queries) {
               $result .= join(" AND ",@queries);
           }
     }      }
     return '';      return ($result,$error,$pretty_string);
 }  }
   
 ######################################################################  ######################################################################
Line 1514  sub copyright_check { Line 2109  sub copyright_check {
                                               $Metadata->{'url'});                                                $Metadata->{'url'});
     # Check for priv      # Check for priv
     if (($Metadata->{'copyright'} eq 'priv') &&       if (($Metadata->{'copyright'} eq 'priv') && 
         (($ENV{'user.name'} ne $resname) &&          (($env{'user.name'} ne $resname) &&
          ($ENV{'user.domain'} ne $resdom))) {           ($env{'user.domain'} ne $resdom))) {
         return 0;          return 0;
     }      }
     # Check for domain      # Check for domain
     if (($Metadata->{'copyright'} eq 'domain') &&      if (($Metadata->{'copyright'} eq 'domain') &&
         ($ENV{'user.domain'} ne $resdom)) {          ($env{'user.domain'} ne $resdom)) {
         return 0;          return 0;
     }      }
     return 1;      return 1;
Line 1552  sub ensure_db_and_table { Line 2147  sub ensure_db_and_table {
     if (! defined($table) || $table eq '' || $table =~ /\D/ ) {      if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
         $r->print("Unable to retrieve search results.  ".          $r->print("Unable to retrieve search results.  ".
                   "Unable to determine the table results were stored in.  ".                    "Unable to determine the table results were stored in.  ".
                   "</body></html>");    &Apache::loncommon::end_page());
         return undef;          return undef;
     }      }
     ##      ##
Line 1561  sub ensure_db_and_table { Line 2156  sub ensure_db_and_table {
     my $connection_result = &Apache::lonmysql::connect_to_db();      my $connection_result = &Apache::lonmysql::connect_to_db();
     if (!defined($connection_result)) {      if (!defined($connection_result)) {
         $r->print("Unable to connect to the MySQL database where your results".          $r->print("Unable to connect to the MySQL database where your results".
                   " are stored. </body></html>");                    " are stored.".
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("lonsearchcat: unable to get lonmysql to".          &Apache::lonnet::logthis("lonsearchcat: unable to get lonmysql to".
                                  " connect to database.");                                   " connect to database.");
         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());          &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
Line 1569  sub ensure_db_and_table { Line 2165  sub ensure_db_and_table {
     }      }
     my $table_check = &Apache::lonmysql::check_table($table);      my $table_check = &Apache::lonmysql::check_table($table);
     if (! defined($table_check)) {      if (! defined($table_check)) {
         $r->print("A MySQL error has occurred.</form></body></html>");          $r->print("A MySQL error has occurred.</form>".
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("lonmysql was unable to determine the status".          &Apache::lonnet::logthis("lonmysql was unable to determine the status".
                                  " of table ".$table);                                   " of table ".$table);
         return undef;          return undef;
Line 1598  a link to change the search query. Line 2195  a link to change the search query.
 ######################################################################  ######################################################################
 sub print_sort_form {  sub print_sort_form {
     my ($r,$pretty_query_string) = @_;      my ($r,$pretty_query_string) = @_;
     my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);  
     ##      ##
     my %SortableFields=&Apache::lonlocal::texthash(       my %SortableFields=&Apache::lonlocal::texthash( 
          id        => 'Default',           id        => 'Default',
Line 1616  sub print_sort_form { Line 2213  sub print_sort_form {
          lastrevisiondate => 'Revision Date'           lastrevisiondate => 'Revision Date'
      );       );
     ##      ##
     my $table = $ENV{'form.table'};      my $table = $env{'form.table'};
     return if (! &ensure_db_and_table($r,$table));      return if (! &ensure_db_and_table($r,$table));
     ##      ##
     ## Get the number of results       ## Get the number of results 
     ##      ##
     my $total_results = &Apache::lonmysql::number_of_rows($table);      my $total_results = &Apache::lonmysql::number_of_rows($table);
     if (! defined($total_results)) {      if (! defined($total_results)) {
         $r->print("A MySQL error has occurred.</form></body></html>");          $r->print("A MySQL error has occurred.</form>".
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("lonmysql was unable to determine the number".          &Apache::lonnet::logthis("lonmysql was unable to determine the number".
                                  " of rows in table ".$table);                                   " of rows in table ".$table);
         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());          &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
         return;          return;
     }      }
     my $result;      my $js =<<END;
     $result.=<<END;  <script type="text/javascript">
 <html>  
 <head>  
 <script>  
     function change_sort() {      function change_sort() {
         var newloc = "/adm/searchcat?phase=results";          var newloc = "/adm/searchcat?phase=results";
         newloc += "&persistent_db_id=$ENV{'form.persistent_db_id'}";          newloc += "&persistent_db_id=$env{'form.persistent_db_id'}";
         newloc += "&sortby=";          newloc += "&sortby=";
         newloc += document.forms.statusform.elements.sortby.value;          newloc += document.forms.statusform.elements.sortby.value;
         parent.resultsframe.location= newloc;          parent.resultsframe.location= newloc;
     }      }
 </script>  </script>
 <title>Results</title>  END
 </head>  
 $bodytag      my $start_page = &Apache::loncommon::start_page('Results',$js,
 <form name="statusform" action="" method="post">      {'no_title' => 1});
 <input type="hidden" name="Queue" value="" />      my $breadcrumbs=
           &Apache::lonhtmlcommon::breadcrumbs('Searching','Searching',
       $env{'form.catalogmode'} ne 'import');
   
       my $result = <<END;
   $start_page
   $breadcrumbs
   <form name="statusform" action="" method="post" target="_top">
   <input type="hidden" name="catalogmode" value="import" />
   <input type="hidden" name="acts" value="" />
 END  END
   
 #<h2>Sort Results</h2>  #<h2>Sort Results</h2>
 #Sort by: <select size="1" name="sortby" onchange="javascript:change_sort();">  #Sort by: <select size="1" name="sortby" onchange="javascript:change_sort();">
 #    $ENV{'form.sortby'} = 'id' if (! defined($ENV{'form.sortby'}));  #    $env{'form.sortby'} = 'id' if (! defined($env{'form.sortby'}));
 #    foreach (keys(%SortableFields)) {  #    foreach (keys(%SortableFields)) {
 #        $result.="<option name=\"$_\"";  #        $result.="<option name=\"$_\"";
 #        if ($_ eq $ENV{'form.sortby'}) {  #        if ($_ eq $env{'form.sortby'}) {
 #            $result.=" selected ";  #            $result.=" selected ";
 #        }  #        }
 #        $result.=" >$SortableFields{$_}</option>\n";  #        $result.=" >$SortableFields{$_}</option>\n";
Line 1665  END Line 2269  END
 <p>  <p>
 There are $total_results matches to your query. $revise  There are $total_results matches to your query. $revise
 </p><p>  </p><p>
 Search:$pretty_query_string  Search: $pretty_query_string
 </p>  </p>
 </form>  </form>
 </body>  
 </html>  
 END  END
     $r->print($result);      $r->print($result.&Apache::loncommon::end_page());
     return;      return;
 }  }
   
Line 1705  my @Fullindicies; Line 2307  my @Fullindicies;
 =item &create_results_table()  =item &create_results_table()
   
 Creates the table of search results by calling lonmysql.  Stores the  Creates the table of search results by calling lonmysql.  Stores the
 table id in $ENV{'form.table'}  table id in $env{'form.table'}
   
 Inputs: none.  Inputs: search area - either res or portfolio 
   
 Returns: the identifier of the table on success, undef on error.  Returns: the identifier of the table on success, undef on error.
   
Line 1716  Returns: the identifier of the table on Line 2318  Returns: the identifier of the table on
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub set_up_table_structure {  sub set_up_table_structure {
       my ($tabletype) = @_;
     my ($datatypes,$fullindicies) =       my ($datatypes,$fullindicies) = 
         &LONCAPA::lonmetadata::describe_metadata_storage();          &LONCAPA::lonmetadata::describe_metadata_storage($tabletype);
     # Copy the table description before modifying it...      # Copy the table description before modifying it...
     @Datatypes = @{$datatypes};      @Datatypes = @{$datatypes};
     unshift(@Datatypes,{name => 'id',        unshift(@Datatypes,{name => 'id',  
Line 1730  sub set_up_table_structure { Line 2333  sub set_up_table_structure {
 }  }
   
 sub create_results_table {  sub create_results_table {
     &set_up_table_structure();      my ($area) = @_;
       if ($area eq 'portfolio') {
           &set_up_table_structure('portfolio_search');
       } else {
           &set_up_table_structure('metadata');
       }
     my $table = &Apache::lonmysql::create_table      my $table = &Apache::lonmysql::create_table
         ( { columns => \@Datatypes,          ( { columns => \@Datatypes,
             FULLTEXT => [{'columns' => \@Fullindicies},],              FULLTEXT => [{'columns' => \@Fullindicies},],
         } );          } );
     if (defined($table)) {      if (defined($table)) {
         $ENV{'form.table'} = $table;          $env{'form.table'} = $table;
         return $table;          return $table;
     }       } 
     return undef; # Error...      return undef; # Error...
Line 1787  sub update_status { Line 2395  sub update_status {
     $r->rflush();      $r->rflush();
 }  }
   
   {
       my $max_time  = 300;  # seconds for the search to complete
       my $start_time = 0;
       my $last_time = 0;
   
   sub reset_timing {
       $start_time = 0;
       $last_time = 0;
   }
   
   sub time_left {
       if ($start_time == 0) {
           $start_time = time;
       }
       my $time_left = $max_time - (time - $start_time);
       $time_left = 0 if ($time_left < 0);
       return $time_left;
   }
   
 sub update_seconds {  sub update_seconds {
     my ($r,$text) = @_;      my ($r) = @_;
     $text =~ s/\'/\\\'/g;      my $time = &time_left();
     $r->print      if (($last_time-$time) > 0) {
         ("<script>document.statusform.seconds.value = ' $text'</script>\n");          $r->print("<script>".
     $r->rflush();                    "document.statusform.seconds.value = '$time'".
                     "</script>\n");
           $r->rflush();
       }
       $last_time = $time;
   }
   
 }  }
   
 ######################################################################  ######################################################################
Line 1812  Returns: html string for a 'revise searc Line 2445  Returns: html string for a 'revise searc
 ######################################################################  ######################################################################
 sub revise_button {  sub revise_button {
     my $revise_phase = 'disp_basic';      my $revise_phase = 'disp_basic';
     $revise_phase = 'disp_adv' if ($ENV{'form.searchmode'} eq 'advanced');      $revise_phase = 'disp_adv' if ($env{'form.searchmode'} eq 'advanced');
     my $newloc = '/adm/searchcat'.      my $newloc = '/adm/searchcat'.
         '?persistent_db_id='.$ENV{'form.persistent_db_id'}.          '?persistent_db_id='.$env{'form.persistent_db_id'}.
             '&cleargroupsort=1'.              '&cleargroupsort=1'.
             '&phase='.$revise_phase;              '&phase='.$revise_phase;
     my $result = qq{<input type="button" value="Revise search" name="revise"} .      my $result = qq{<input type="button" value="Revise search" name="revise"} .
Line 1837  results into MySQL. Line 2470  results into MySQL.
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub run_search {  sub run_search {
     my ($r,$query,$customquery,$customshow,$serverlist,$pretty_string) = @_;      my ($r,$query,$customquery,$customshow,$serverlist,
     my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);          $pretty_string,$area) = @_;
       my $tabletype = 'metadata';
       if ($area eq 'portfolio') {
           $tabletype = 'portfolio_search';
       }
     my $connection = $r->connection;      my $connection = $r->connection;
     #      #
     # Timing variables  
     #  
     my $starttime = time;  
     my $max_time  = 30;  # seconds for the search to complete  
     #  
     # Print run_search header      # Print run_search header
     #      #
       my $start_page = &Apache::loncommon::start_page('Search Status',undef,
       {'no_title' => 1});
       my $breadcrumbs =
    &Apache::lonhtmlcommon::breadcrumbs('Searching','Searching',
       $env{'form.catalogmode'} ne 'import');
     $r->print(<<END);      $r->print(<<END);
 <html>  $start_page
 <head><title>Search Status</title></head>  $breadcrumbs
 $bodytag  
 <form name="statusform" action="" method="post">  <form name="statusform" action="" method="post">
 <input type="hidden" name="Queue" value="" />  <input type="hidden" name="acts" value="" />
 END  END
     # Check to see if $pretty_string has more than one carriage return.      # Remove leading and trailing <br />
     # Assume \n s are following <br /> s and truncate the value.      $pretty_string =~ s:^\s*<br />::i;
     # (there is probably a better way)...      $pretty_string =~ s:(<br />)*\s*$::im;
     my @Lines = split /<br \/>/,$pretty_string;      my @Lines = split("<br />",$pretty_string);
       # I keep getting blank items at the end of the list, hence the following:
       while ($Lines[-1] =~ /^\s*$/ && @Lines) {
           pop(@Lines);
       }
     if (@Lines > 2) {      if (@Lines > 2) {
         $pretty_string = join '<br \>',(@Lines[0..2],'....<br />');          $pretty_string = join '<br />',(@Lines[0..2],'....<br />');
     }      }
     $r->print(&mt("Search").": ".$pretty_string);      $r->print(&mt("Search: [_1]",$pretty_string));
     $r->rflush();      $r->rflush();
     #      #
     # Determine the servers we need to contact.      # Determine the servers we need to contact.
Line 1874  END Line 2514  END
             @Servers_to_contact = ($serverlist);              @Servers_to_contact = ($serverlist);
         }          }
     } else {      } else {
         @Servers_to_contact = sort(keys(%Apache::lonnet::libserv));   my %all_library_servers = &Apache::lonnet::all_library();
           @Servers_to_contact = sort(keys(%all_library_servers));
     }      }
     my %Server_status;      my %Server_status;
     my $table =$ENV{'form.table'};      #
       # Check on the mysql table we will use to store results.
       my $table =$env{'form.table'};
     if (! defined($table) || $table eq '' || $table =~ /\D/ ) {      if (! defined($table) || $table eq '' || $table =~ /\D/ ) {
         $r->print("Unable to determine table id to store search results in.".          $r->print("Unable to determine table id to store search results in.".
                   "The search has been aborted.</body></html>");                    "The search has been aborted.".
     &Apache::loncommon::end_page());
         return;          return;
     }      }
     my $table_status = &Apache::lonmysql::check_table($table);      my $table_status = &Apache::lonmysql::check_table($table);
     if (! defined($table_status)) {      if (! defined($table_status)) {
         $r->print("Unable to determine status of table.</body></html>");          $r->print("Unable to determine status of table.".
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("Bogus table id of $table for ".          &Apache::lonnet::logthis("Bogus table id of $table for ".
                                  "$ENV{'user.name'} @ $ENV{'user.domain'}");                                   "$env{'user.name'} @ $env{'user.domain'}");
         &Apache::lonnet::logthis("lonmysql error = ".          &Apache::lonnet::logthis("lonmysql error = ".
                                  &Apache::lonmysql::get_error());                                   &Apache::lonmysql::get_error());
         return;          return;
Line 1899  END Line 2544  END
                                  &Apache::lonmysql::get_debug());                                   &Apache::lonmysql::get_debug());
         &Apache::lonnet::logthis('table status = "'.$table_status.'"');          &Apache::lonnet::logthis('table status = "'.$table_status.'"');
         $r->print("The table id,$table, we tried to use is invalid.".          $r->print("The table id,$table, we tried to use is invalid.".
                   "The search has been aborted.</body></html>");                    "The search has been aborted.".
     &Apache::loncommon::end_page());
         return;          return;
     }      }
     ##      ##
     ## Prepare for the big loop.      ## Prepare for the big loop.
     my $hitcountsum;      my $hitcountsum;
       my %matches;
     my $server;       my $server; 
     my $status;      my $status;
     my $revise = &revise_button();      my $revise = &revise_button();
Line 1912  END Line 2559  END
 <table>  <table>
 <tr><th>Status</th><th>Total Matches</th><th>Time Remaining</th><th></th></tr>  <tr><th>Status</th><th>Total Matches</th><th>Time Remaining</th><th></th></tr>
 <tr>  <tr>
 <td><input type="text" name="status"  value="" size="30" /></td>  <td><input type="text" name="status"  value="" size="50" /></td>
 <td><input type="text" name="count"   value="" size="10" /></td>  <td><input type="text" name="count"   value="" size="10" /></td>
 <td><input type="text" name="seconds" value="" size="8" /></td>  <td><input type="text" name="seconds" value="" size="8" /></td>
 <td>$revise</td>  <td>$revise</td>
Line 1921  END Line 2568  END
 </form>  </form>
 END  END
     $r->rflush();      $r->rflush();
     my $time_remaining = $max_time - (time - $starttime) ;      &reset_timing();
     $time_remaining = 0 if ($time_remaining <0);      &update_seconds($r);
     my $last_time = $time_remaining;      &update_status($r,&mt('contacting [_1]',$Servers_to_contact[0]));
     &update_seconds($r,$time_remaining);      while (&time_left() &&
     &update_status($r,'contacting '.$Servers_to_contact[0]);  
     while (($time_remaining > 0) &&  
            ((@Servers_to_contact) || keys(%Server_status))) {             ((@Servers_to_contact) || keys(%Server_status))) {
         $time_remaining = $max_time - (time - $starttime) ;          &update_seconds($r);
         &update_seconds($r,$time_remaining);          #
         # Send out a search request if it needs to be done.          # Send out a search request
         if (@Servers_to_contact) {          if (@Servers_to_contact) {
             # Contact one server              # Contact one server
             my $server = shift(@Servers_to_contact);              my $server = shift(@Servers_to_contact);
             &update_status($r,&mt('contacting').' '.$server);              &update_status($r,&mt('contacting [_1]',$server));
             my $reply=&Apache::lonnet::metadata_query($query,$customquery,              my $reply=&Apache::lonnet::metadata_query($query,$customquery,
                                                       $customshow,[$server]);                                                        $customshow,[$server]);
             ($server) = keys(%$reply);              ($server) = keys(%$reply);
Line 1946  END Line 2591  END
             # left to contact.                # left to contact.  
             if (scalar (keys(%Server_status))) {              if (scalar (keys(%Server_status))) {
                 &update_status($r,                  &update_status($r,
                        &mt('waiting on').' '.(join(' ',keys(%Server_status))));                         &mt('waiting on [_1]',join(' ',keys(%Server_status))));
             }              }
             sleep(1)              sleep(1)
         }          }
         #          #
         # Loop through the servers we have contacted but do not          # Loop through the servers we have contacted but do not
         # have results from yet, looking for results.          # have results from yet, looking for results.
         while (my ($server,$status) = each(%Server_status)) {          foreach my $server (keys(%Server_status)) {
             last if ($connection->aborted());              last if ($connection->aborted());
             $time_remaining = $max_time - (time - $starttime) ;              &update_seconds($r);
             $time_remaining = 0 if ($time_remaining < 0);              my $status = $Server_status{$server};
             if ($last_time - $time_remaining > 0) {  
                 $last_time = $time_remaining;  
                 &update_seconds($r,$time_remaining);  
             }  
             if ($status eq 'con_lost') {              if ($status eq 'con_lost') {
                 delete ($Server_status{$server});                  delete ($Server_status{$server});
                 next;                  next;
             }              }
             $status=~/^([\.\w]+)$/;               $status=~s|/||g;
            my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$1;             my $datafile=$r->dir_config('lonDaemons').'/tmp/'.$status;
             if (-e $datafile && ! -e "$datafile.end") {              if (-e $datafile && ! -e "$datafile.end") {
                 &update_status($r,&mt('Receiving results from').' '.$server);                  &update_status($r,&mt('Receiving results from [_1]',$server));
                 next;                  next;
             }              }
             last if ($connection->aborted());              last if ($connection->aborted());
             if (-e "$datafile.end") {              if (-e "$datafile.end") {
                 &update_status($r,&mt('Reading results from').' '.$server);                  &update_status($r,&mt('Reading results from [_1]',$server));
                 if (-z "$datafile") {                  if (-z "$datafile") {
                     delete($Server_status{$server});                      delete($Server_status{$server});
                     next;                      next;
Line 1988  END Line 2629  END
                 # Read in the whole file.                  # Read in the whole file.
                 while (my $result = <$fh>) {                  while (my $result = <$fh>) {
                     last if ($connection->aborted());                      last if ($connection->aborted());
                     # handle custom fields?  Someday we will!                      #
                       # Records are stored one per line
                     chomp($result);                      chomp($result);
                     next unless $result;                      next if (! $result);
                       #
                     # Parse the result.                      # Parse the result.
                     my %Fields = &parse_raw_result($result,$server);                      my %Fields = &parse_raw_result($result,$server,$tabletype);
                     $Fields{'hostname'} = $server;                      $Fields{'hostname'} = $server;
                       #
                       # Skip if external and we did not want that
                       next if ((! $env{'form.inclext'}) && ($Fields{'url'}=~/^\/ext\//));
                       # Skip based on copyright
                     next if (! &copyright_check(\%Fields));                      next if (! &copyright_check(\%Fields));
   
                       if ($area eq 'portfolio') {
                           next if (defined($matches{$Fields{'url'}}));
                           # Skip if inaccessible
                           next if (!&Apache::lonnet::portfolio_access($Fields{'url'}));
                           $matches{$Fields{'url'}} = 1; 
                       }
                       #
                     # Store the result in the mysql database                      # Store the result in the mysql database
                     my $result = &Apache::lonmysql::store_row($table,\%Fields);                      my $result = &Apache::lonmysql::store_row($table,\%Fields);
                     if (! defined($result)) {                      if (! defined($result)) {
                         $r->print(&Apache::lonmysql::get_error());                          $r->print(&Apache::lonmysql::get_error());
                     }                      }
                     # $r->print(&Apache::lonmysql::get_debug());                      #
                     $hitcountsum ++;                      $hitcountsum ++;
                     $time_remaining = $max_time - (time - $starttime) ;                      &update_seconds($r);
                     $time_remaining = 0 if ($time_remaining < 0);  
                     if ($last_time - $time_remaining > 0) {  
                         &update_seconds($r,$time_remaining);  
                         $last_time = $time_remaining;  
                     }  
                     if ($hitcountsum % 50 == 0) {                      if ($hitcountsum % 50 == 0) {
                         &update_count_status($r,$hitcountsum);                          &update_count_status($r,$hitcountsum);
                     }                      }
                 } # End of foreach (@results)                  }
                 $fh->close();                  $fh->close();
                 # $server is only deleted if the results file has been                   # $server is only deleted if the results file has been 
                 # found and (successfully) opened.  This may be a bad idea.                  # found and (successfully) opened.  This may be a bad idea.
Line 2021  END Line 2671  END
             &update_count_status($r,$hitcountsum);              &update_count_status($r,$hitcountsum);
         }          }
         last if ($connection->aborted());          last if ($connection->aborted());
         # Finished looping through the servers          &update_seconds($r);
         $starttime = time if (@Servers_to_contact);  
         $time_remaining = $max_time - (time - $starttime) ;  
         if ($last_time - $time_remaining > 0) {  
             $last_time = $time_remaining;  
             &update_seconds($r,$time_remaining);  
         }  
     }      }
     &update_status($r,&mt('Search Complete').$server);      &update_status($r,&mt('Search Complete [_1]',$server));
     &update_seconds($r,0);      &update_seconds($r);
     #      #
     &Apache::lonmysql::disconnect_from_db();      &Apache::lonmysql::disconnect_from_db(); # This is unneccessary
     #      #
     # We have run out of time or run out of servers to talk to and      # We have run out of time or run out of servers to talk to and
     # results to get.        # results to get, so let the client know the top frame needs to be
     $r->print("</body></html>");      # loaded from /adm/searchcat
     if ($ENV{'form.catalogmode'} ne 'groupsearch') {      $r->print(&Apache::loncommon::end_page());
   #    if ($env{'form.catalogmode'} ne 'import') {
         $r->print("<script>".          $r->print("<script>".
                       "window.location='/adm/searchcat?".                        "window.location='/adm/searchcat?".
                       "phase=sort&".                        "phase=sort&".
                       "persistent_db_id=$ENV{'form.persistent_db_id'}';".                        "persistent_db_id=$env{'form.persistent_db_id'}';".
                   "</script>");                    "</script>");
     }  #    }
     return;      return;
 }  }
   
Line 2063  Returns html for the previous and next b Line 2708  Returns html for the previous and next b
 sub prev_next_buttons {  sub prev_next_buttons {
     my ($current_min,$show,$total,$parms) = @_;      my ($current_min,$show,$total,$parms) = @_;
     return '' if ($show eq 'all'); # No links if you get them all at once.      return '' if ($show eq 'all'); # No links if you get them all at once.
     my $links;      #
     ##      # Create buttons
     ## Prev      my $buttons = '<input type="submit" name="prev" value="'.&mt('Prev').'" ';
     my $prev_min = $current_min - $show;      $buttons .= '/>';
     $prev_min = 1 if $prev_min < 1;      $buttons .= '&nbsp;'x3;
     if ($prev_min < $current_min) {      $buttons .= '<input type="submit" name="reload" '.
         $links .=           'value="'.&mt('Reload').'" />';
             qq{<a href="/adm/searchcat?$parms&start=$prev_min&show=$show">}.      $buttons .= '&nbsp;'x3;
             &mt('prev').'</a>';      $buttons .= '<input type="submit" name="next" value="'.&mt('Next').'" ';
     } else {      $buttons .= '/>';
         $links .= &mt('prev');      return $buttons;
     }  
     ##  
     ## Pages.... Someday.  
     ##  
     $links .=   
         qq{&nbsp;  
            <a href="/adm/searchcat?$parms&start=$current_min&$show=$show">}.  
                 &mt('reload').'</a>';  
     ##  
     ## Next  
     my $next_min = $current_min + $show;  
     $next_min = $current_min if ($next_min > $total);  
     if ($next_min != $current_min) {  
         $links .=   
             qq{&nbsp;  
                <a href="/adm/searchcat?$parms&start=$next_min&show=$show">}.  
                     &mt('next').'</a>';  
     } else {  
         $links .= '&nbsp;'.&mt('next');  
     }  
     return $links;  
 }  }
   
 ######################################################################  ######################################################################
Line 2111  Prints the results out for selection and Line 2735  Prints the results out for selection and
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub display_results {  sub display_results {
     my ($r,$importbutton,$closebutton,$diropendb) = @_;      my ($r,$importbutton,$closebutton,$diropendb,$area) = @_;
     my $connection = $r->connection;      my $connection = $r->connection;
     $r->print(&search_results_header($importbutton,$closebutton));      $r->print(&search_results_header($importbutton,$closebutton));
     ##      ##
     ## Set viewing function      ## Set viewing function
     ##      ##
     my $viewfunction = $Views{$ENV{'form.viewselect'}};      my $viewfunction = $Views{$env{'form.viewselect'}};
     if (!defined($viewfunction)) {      if (!defined($viewfunction)) {
         $r->print("Internal Error - Bad view selected.\n");          $r->print("Internal Error - Bad view selected.\n");
         $r->rflush();          $r->rflush();
Line 2125  sub display_results { Line 2749  sub display_results {
     }      }
     ##      ##
     ## $checkbox_num is a count of the number of checkboxes output on the       ## $checkbox_num is a count of the number of checkboxes output on the 
     ## page this is used only during catalogmode=groupsearch.      ## page this is used only during catalogmode=import.
     my $checkbox_num = 0;      my $checkbox_num = 0;
     ##      ##
     ## Get the catalog controls setup      ## Get the catalog controls setup
     ##      ##
     my $action = "/adm/searchcat?phase=results";      my $action = "/adm/searchcat?phase=results";
     ##      ##
     ## Deal with groupsearch by opening the groupsearch db file.      ## Deal with import by opening the import db file.
     if ($ENV{'form.catalogmode'} eq 'groupsearch') {      if ($env{'form.catalogmode'} eq 'import') {
         if (! tie(%groupsearch_db,'GDBM_File',$diropendb,          if (! tie(%groupsearch_db,'GDBM_File',$diropendb,
                   &GDBM_WRCREAT(),0640)) {                    &GDBM_WRCREAT(),0640)) {
             $r->print('Unable to store import results.</form></body></html>');              $r->print('Unable to store import results.</form>'.
         &Apache::loncommon::end_page());
             $r->rflush();              $r->rflush();
             return;              return;
         }           } 
     }      }
     ##      ##
     ## Prepare the table for querying      ## Prepare the table for querying
     my $table = $ENV{'form.table'};      my $table = $env{'form.table'};
     return if (! &ensure_db_and_table($r,$table));      return if (! &ensure_db_and_table($r,$table));
     ##      ##
     ## Get the number of results       ## Get the number of results 
     my $total_results = &Apache::lonmysql::number_of_rows($table);      my $total_results = &Apache::lonmysql::number_of_rows($table);
     if (! defined($total_results)) {      if (! defined($total_results)) {
         $r->print("A MySQL error has occurred.</form></body></html>");          $r->print("A MySQL error has occurred.</form>".
     &Apache::loncommon::end_page());
         &Apache::lonnet::logthis("lonmysql was unable to determine the number".          &Apache::lonnet::logthis("lonmysql was unable to determine the number".
                                  " of rows in table ".$table);                                   " of rows in table ".$table);
         &Apache::lonnet::logthis(&Apache::lonmysql::get_error());          &Apache::lonnet::logthis(&Apache::lonmysql::get_error());
Line 2157  sub display_results { Line 2783  sub display_results {
     }      }
     ##      ##
     ## Determine how many results we need to get      ## Determine how many results we need to get
     $ENV{'form.start'} = 1      if (! exists($ENV{'form.start'}));      $env{'form.start'} = 1  if (! exists($env{'form.start'}));
     $ENV{'form.show'}  = 'all'  if (! exists($ENV{'form.show'}));      $env{'form.show'}  = 20 if (! exists($env{'form.show'}));
     my $min = $ENV{'form.start'};      if (exists($env{'form.prev'})) {
           $env{'form.start'} -= $env{'form.show'};
       } elsif (exists($env{'form.next'})) {
           $env{'form.start'} += $env{'form.show'};
       }
       $env{'form.start'} = 1 if ($env{'form.start'}<1);
       $env{'form.start'} = $total_results if ($env{'form.start'}>$total_results);
       my $min = $env{'form.start'};
     my $max;      my $max;
     if ($ENV{'form.show'} eq 'all') {      if ($env{'form.show'} eq 'all') {
         $max = $total_results ;          $max = $total_results ;
     } else {      } else {
         $max = $min + $ENV{'form.show'} - 1;          $max = $min + $env{'form.show'} - 1;
         $max = $total_results if ($max > $total_results);          $max = $total_results if ($max > $total_results);
     }      }
     ##      ##
       ## Output form elements
       $r->print(&hidden_field('table').
                 &hidden_field('phase').
                 &hidden_field('persistent_db_id').
                 &hidden_field('start').
                 &hidden_field('area')
                 );
       #
       # Build sorting selector
       my @fields = 
           (
            {key=>'default' },
            {key=>'title' },
            {key =>'author' },
            {key =>'subject'},
            {key =>'url',desc=>'URL'},
            {key =>'keywords'},
            {key =>'language'},
            {key =>'creationdate'},
            {key =>'lastrevisiondate'},
            {key =>'owner'},
            {key =>'copyright'},
            {key =>'authorspace'},
            {key =>'lowestgradelevel'},
            {key =>'highestgradelevel'},
            {key =>'standards',desc=>'Standards'},
           );
       if ($area eq 'portfolio') {
           push(@fields,
          (
            {key => 'scope'},
            {key => 'keynum'},
          ));
       } else {
           push(@fields,
          (
            {key =>'count',desc=>'Number of accesses'},
            {key =>'stdno',desc=>'Students Attempting'},
            {key =>'avetries',desc=>'Average Number of Tries'},
            {key =>'difficulty',desc=>'Mean Degree of Difficulty'},
            {key =>'disc',desc=>'Mean Degree of Discrimination'},
            {key =>'clear',desc=>'Evaluation: Clear'},
            {key =>'technical',desc=>'Evaluation: Technically Correct'},
            {key =>'correct',desc=>'Evaluation: Material is Correct'},
            {key =>'helpful',desc=>'Evaluation: Material is Helpful'},
            {key =>'depth',desc=>'Evaluation: Material has Depth'},
          ));
       }
       my %fieldnames = &Apache::lonmeta::fieldnames();
       my @field_order;
       foreach my $field_data (@fields) {
           push(@field_order,$field_data->{'key'});
           if (! exists($field_data->{'desc'})) {
               $field_data->{'desc'}=$fieldnames{$field_data->{'key'}};
           } else {
               if (! defined($field_data->{'desc'})) {
                   $field_data->{'desc'} = ucfirst($field_data->{'key'});
               }
               $field_data->{'desc'} = &mt($field_data->{'desc'});
           }
       }
       my %sort_fields = map {$_->{'key'},$_->{'desc'}} @fields;
       $sort_fields{'select_form_order'} = \@field_order;
       $env{'form.sortorder'} = 'desc' if (! exists($env{'form.sortorder'}));
       if (! exists($env{'form.sortfield'})) {
           if ($area eq 'portfolio') {
               $env{'form.sortfield'} = 'owner';
           } else {
               $env{'form.sortfield'} = 'count';
           }
       }
       if (! exists($env{'form.sortorder'})) {
    if ($env{'form.sortfield'}=~/^(count|stdno|disc|clear|technical|correct|helpful)$/) {
       $env{'form.sortorder'}='desc';
    } else {
       $env{'form.sortorder'}='asc';
    }
       }
       my $sortform = &mt('Sort by [_1] [_2]',
                          &Apache::loncommon::select_form($env{'form.sortfield'},
                                                         'sortfield',
                                                         %sort_fields),
                          &Apache::loncommon::select_form($env{'form.sortorder'},
                                                         'sortorder',
                                                         (asc =>&mt('Ascending'),
                                                          desc=>&mt('Descending')
                                                          ))
                          );
       ##
     ## Output links (if necessary) for 'prev' and 'next' pages.      ## Output links (if necessary) for 'prev' and 'next' pages.
     $r->print      $r->print
         ('<center>'.          ('<table width="100%"><tr><td width="25%" align="right">'.
          &prev_next_buttons($min,$ENV{'form.show'},$total_results,           '<nobr>'.$sortform.'</nobr>'.
                             "table=".$ENV{'form.table'}.           '</td><td width="25%" align="right">'.
                             "&phase=results".           &prev_next_buttons($min,$env{'form.show'},$total_results).
                             "&persistent_db_id=".$ENV{'form.persistent_db_id'})           '</td><td align="right">'.
          ."</center>\n"           &viewoptions().'</td></tr></table>'
          );           );
     if ($total_results == 0) {      if ($total_results == 0) {
         $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="1">'.          $r->print('<meta HTTP-EQUIV="Refresh" CONTENT="2" />'.
                   '<h3>'.&mt('There are currently no results').'.</h3>'.                    '<h3>'.&mt('There are currently no results').'.</h3>'.
                   "</form></body></html>");                    "</form>".
     &Apache::loncommon::end_page());
         return;          return;
     } else {      } else {
         $r->print          $r->print('<center>'.
             ("<center>Results $min to $max out of $total_results</center>\n");                    mt('Results [_1] to [_2] out of [_3]',
                        $min,$max,$total_results).
                     "</center>\n");
     }      }
     ##      ##
     ## Get results from MySQL table      ## Get results from MySQL table
     my @Results = &Apache::lonmysql::get_rows($table,      my $sort_command  = 'id>='.$min.' AND id<='.$max;
                                               'id>='.$min.' AND id<='.$max);      my $order;
       if (exists($env{'form.sortorder'})) {
           if ($env{'form.sortorder'} eq 'asc') {
               $order = 'ASC';
           } elsif ($env{'form.sortorder'} eq 'desc') {
               $order = 'DESC';
           } else {
               $order = '';
           }
       } else {
           $order = '';
       }
       if ($env{'form.sortfield'} ne 'default' && 
           exists($sort_fields{$env{'form.sortfield'}})) {
           $sort_command = $env{'form.sortfield'}.' IS NOT NULL '.
               'ORDER BY '.$env{'form.sortfield'}.' '.$order.
               '  LIMIT '.($min-1).','.($max-$min+1);
       }
       my @Results = &Apache::lonmysql::get_rows($table,$sort_command);
     ##      ##
     ## Loop through the results and output them.      ## Loop through the results and output them.
       my $tabletype = 'metadata';
       if ($area eq 'portfolio') {
           $tabletype = 'portfolio_search';
       }
     foreach my $row (@Results) {      foreach my $row (@Results) {
         if ($connection->aborted()) {          if ($connection->aborted()) {
             &cleanup();              &cleanup();
             return;              return;
         }          }
         my %Fields = %{&parse_row(@$row)};          my %Fields = %{&parse_row($tabletype,@$row)};
         my $output="<p>\n";          my $output="<p>\n";
         if (! defined($Fields{'title'}) || $Fields{'title'} eq '') {          if (! defined($Fields{'title'}) || $Fields{'title'} eq '') {
             $Fields{'title'} = 'Untitled';              $Fields{'title'} = 'Untitled';
         }          }
         my $prefix=&catalogmode_output($Fields{'title'},$Fields{'url'},          my $prefix=&catalogmode_output($Fields{'title'},$Fields{'url'},
                                        $Fields{'id'},$checkbox_num++);                                         $Fields{'id'},$checkbox_num++);
   
         # Render the result into html          # Render the result into html
         $output.= &$viewfunction($prefix,%Fields);          $output.= &$viewfunction($prefix,%Fields);
         # Print them out as they come in.          # Print them out as they come in.
Line 2216  sub display_results { Line 2962  sub display_results {
     } else {      } else {
         $r->print          $r->print
             ('<center>'.              ('<center>'.
              &prev_next_buttons($min,$ENV{'form.show'},$total_results,               &prev_next_buttons($min,$env{'form.show'},$total_results,
                                 "table=".$ENV{'form.table'}.                                  "table=".$env{'form.table'}.
                                 "&phase=results".                                  "&phase=results".
                                 "&persistent_db_id=".                                  "&persistent_db_id=".
                                 $ENV{'form.persistent_db_id'})                                  $env{'form.persistent_db_id'})
              ."</center>\n"               ."</center>\n"
              );               );
     }      }
     $r->print("</form></body></html>");      $r->print("</form>".&Apache::loncommon::end_page());
     $r->rflush();      $r->rflush();
     untie %groupsearch_db if (tied(%groupsearch_db));      untie %groupsearch_db if (tied(%groupsearch_db));
     return;      return;
Line 2238  sub display_results { Line 2984  sub display_results {
 =item &catalogmode_output($title,$url,$fnum,$checkbox_num)  =item &catalogmode_output($title,$url,$fnum,$checkbox_num)
   
 Returns html needed for the various catalog modes.  Gets inputs from  Returns html needed for the various catalog modes.  Gets inputs from
 $ENV{'form.catalogmode'}.  Stores data in %groupsearch_db.  $env{'form.catalogmode'}.  Stores data in %groupsearch_db.
   
 =cut  =cut
   
Line 2247  $ENV{'form.catalogmode'}.  Stores data i Line 2993  $ENV{'form.catalogmode'}.  Stores data i
 sub catalogmode_output {  sub catalogmode_output {
     my $output = '';      my $output = '';
     my ($title,$url,$fnum,$checkbox_num) = @_;      my ($title,$url,$fnum,$checkbox_num) = @_;
     if ($ENV{'form.catalogmode'} eq 'interactive') {      if ($env{'form.catalogmode'} eq 'interactive') {
         $title=~ s/\'/\\\'/g;          $title=~ s/\'/\\\'/g;
         if ($ENV{'form.catalogmode'} eq 'interactive') {          if ($env{'form.catalogmode'} eq 'interactive') {
             $output.=<<END               $output.=<<END 
 <font size='-1'><INPUT TYPE="button" NAME="returnvalues" VALUE="SELECT"  <font size='-1'><INPUT TYPE="button" NAME="returnvalues" VALUE="SELECT"
 onClick="javascript:select_data('$title','$url')">  onClick="javascript:select_data('$title','$url')">
 </font>  </font>
 END  END
         }          }
     } elsif ($ENV{'form.catalogmode'} eq 'groupsearch') {      } elsif ($env{'form.catalogmode'} eq 'import') {
         $groupsearch_db{"pre_${fnum}_link"}=$url;          $groupsearch_db{"pre_${fnum}_link"}=$url;
         $groupsearch_db{"pre_${fnum}_title"}=$title;          $groupsearch_db{"pre_${fnum}_title"}=$title;
         $output.=<<END;          $output.=<<END;
Line 2282  Parse a row returned from the database. Line 3028  Parse a row returned from the database.
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
 sub parse_row {  sub parse_row {
     my @Row = @_;      my ($tabletype,@Row) = @_;
     my %Fields;      my %Fields;
     if (! scalar(@Datatypes)) {      if (! scalar(@Datatypes)) {
         &set_up_table_structure();          &set_up_table_structure($tabletype);
     }      }
     for (my $i=0;$i<=$#Row;$i++) {      for (my $i=0;$i<=$#Row;$i++) {
         $Fields{$Datatypes[$i]->{'name'}}=&Apache::lonnet::unescape($Row[$i]);          $Fields{$Datatypes[$i]->{'name'}}=&unescape($Row[$i]);
     }      }
     $Fields{'language'} =       $Fields{'language'} = 
         &Apache::loncommon::languagedescription($Fields{'language'});          &Apache::loncommon::languagedescription($Fields{'language'});
Line 2321  The 'title' field is set to "Untitled" i Line 3067  The 'title' field is set to "Untitled" i
 ###########################################################  ###########################################################
 ###########################################################  ###########################################################
 sub parse_raw_result {  sub parse_raw_result {
     my ($result,$hostname) = @_;      my ($result,$hostname,$tabletype) = @_;
     # conclude from self to others regarding fields      # conclude from self to others regarding fields
     my %Fields=&LONCAPA::lonmetadata::metadata_col_to_hash      my %Fields=&LONCAPA::lonmetadata::metadata_col_to_hash
         (map {          ($tabletype,
             &Apache::lonnet::unescape($_);           map {
         } (split(/\,/,$result)) );              &unescape($_);
            } (split(/\,/,$result)) );
     return %Fields;      return %Fields;
 }  }
   
Line 2346  sub handle_custom_fields { Line 3093  sub handle_custom_fields {
     my $customshow='';      my $customshow='';
     my $extrashow='';      my $extrashow='';
     my @customfields;      my @customfields;
     if ($ENV{'form.customshow'}) {      if ($env{'form.customshow'}) {
         $customshow=$ENV{'form.customshow'};          $customshow=$env{'form.customshow'};
         $customshow=~s/[^\w\s]//g;          $customshow=~s/[^\w\s]//g;
         my @fields=map {          my @fields=map {
             "<font color=\"#008000\">$_:</font><!-- $_ -->";              "<font color=\"#008000\">$_:</font><!-- $_ -->";
Line 2363  sub handle_custom_fields { Line 3110  sub handle_custom_fields {
         if ($result=~/^(custom\=.*)$/) { # grab all custom metadata          if ($result=~/^(custom\=.*)$/) { # grab all custom metadata
             my $tmp=$result;              my $tmp=$result;
             $tmp=~s/^custom\=//;              $tmp=~s/^custom\=//;
             my ($k,$v)=map {&Apache::lonnet::unescape($_);              my ($k,$v)=map {&unescape($_);
                         } split(/\,/,$tmp);                          } split(/\,/,$tmp);
             $customhash{$k}=$v;              $customhash{$k}=$v;
         }          }
Line 2381  sub handle_custom_fields { Line 3128  sub handle_custom_fields {
 Output the proper html headers and javascript code to deal with different   Output the proper html headers and javascript code to deal with different 
 calling modes.  calling modes.
   
 Takes most inputs directly from %ENV, except $mode.    Takes most inputs directly from %env, except $mode.  
   
 =over 4  =over 4
   
Line 2395  The following environment variables are Line 3142  The following environment variables are
   
 =item 'form.catalogmode'   =item 'form.catalogmode' 
   
 Checked for 'interactive' and 'groupsearch'.  Checked for 'interactive' and 'import'.
   
 =item 'form.mode'  =item 'form.mode'
   
Line 2421  the name of the input field to put the t Line 3168  the name of the input field to put the t
 ######################################################################  ######################################################################
 sub search_results_header {  sub search_results_header {
     my ($importbutton,$closebutton) = @_;      my ($importbutton,$closebutton) = @_;
     my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);  
     my $result = '';      my $js;
     # output beginning of search page      # output beginning of search page
     # conditional output of script functions dependent on the mode in      # conditional output of script functions dependent on the mode in
     # which the search was invoked      # which the search was invoked
     if ($ENV{'form.catalogmode'} eq 'interactive'){      if ($env{'form.catalogmode'} eq 'interactive'){
  if (! exists($ENV{'form.mode'}) || $ENV{'form.mode'} ne 'edit') {   if (! exists($env{'form.mode'}) || $env{'form.mode'} ne 'edit') {
             $result.=<<SCRIPT;              $js.=<<SCRIPT;
 <script type="text/javascript">  <script type="text/javascript">
     function select_data(title,url) {      function select_data(title,url) {
  changeTitle(title);   changeTitle(title);
Line 2447  sub search_results_header { Line 3194  sub search_results_header {
     }      }
 </script>  </script>
 SCRIPT  SCRIPT
         } elsif ($ENV{'form.mode'} eq 'edit') {          } elsif ($env{'form.mode'} eq 'edit') {
             my $form = $ENV{'form.form'};              my $form = $env{'form.form'};
             my $element = $ENV{'form.element'};              my $element = $env{'form.element'};
             my $titleelement = $ENV{'form.titleelement'};              my $titleelement = $env{'form.titleelement'};
     my $changetitle;      my $changetitle;
     if (!$titleelement) {      if (!$titleelement) {
  $changetitle='function changeTitle(val) {}';   $changetitle='function changeTitle(val) {}';
Line 2467  function changeTitle(val) { Line 3214  function changeTitle(val) {
 END  END
             }              }
   
             $result.=<<SCRIPT;              $js.=<<SCRIPT;
 <script type="text/javascript">  <script type="text/javascript">
 function select_data(title,url) {  function select_data(title,url) {
     changeURL(url);      changeURL(url);
Line 2487  function changeURL(val) { Line 3234  function changeURL(val) {
 SCRIPT  SCRIPT
         }          }
     }      }
     $result.=<<SCRIPT if $ENV{'form.catalogmode'} eq 'groupsearch';      $js.=<<SCRIPT if $env{'form.catalogmode'} eq 'import';
 <script type="text/javascript">  <script type="text/javascript">
     function queue(checkbox_num,val) {      function queue(checkbox_num,val) {
         if (document.forms.results.returnvalues.length != "undefined" &&          if (document.forms.results.returnvalues.length != "undefined" &&
             typeof(document.forms.results.returnvalues.length) == "number") {              typeof(document.forms.results.returnvalues.length) == "number") {
             if (document.forms.results.returnvalues[checkbox_num].checked) {              if (document.forms.results.returnvalues[checkbox_num].checked) {
                 parent.statusframe.document.forms.statusform.elements.Queue.value +='1a'+val+'b';                  parent.statusframe.document.forms.statusform.elements.acts.value +='1a'+val+'b';
             } else {              } else {
                 parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b';                  parent.statusframe.document.forms.statusform.elements.acts.value +='0a'+val+'b';
             }              }
         } else {          } else {
             if (document.forms.results.returnvalues.checked) {              if (document.forms.results.returnvalues.checked) {
                 parent.statusframe.document.forms.statusform.elements.Queue.value +='1a'+val+'b';                  parent.statusframe.document.forms.statusform.elements.acts.value +='1a'+val+'b';
             } else {              } else {
                 parent.statusframe.document.forms.statusform.elements.Queue.value +='0a'+val+'b';                  parent.statusframe.document.forms.statusform.elements.acts.value +='0a'+val+'b';
             }              }
         }          }
     }      }
     function select_group() {      function select_group() {
  parent.window.location=   parent.window.location=
     "/adm/groupsort?mode=$ENV{'form.mode'}&catalogmode=groupsearch&acts="+      "/adm/groupsort?mode=$env{'form.mode'}&catalogmode=import&acts="+
     parent.statusframe.document.forms.statusform.elements.Queue.value;      parent.statusframe.document.forms.statusform.elements.acts.value;
     }      }
 </script>  </script>
 SCRIPT  SCRIPT
     $result.=<<END;  
 </head>      my $start_page  = &Apache::loncommon::start_page(undef,$js,
 $bodytag       {'only_body' =>1});
 <form name="results" method="post" action="" >      my $result=<<END;
 <input type="hidden" name="Queue" value="" />  $start_page
   <form name="results" method="post" action="/adm/searchcat">
 $importbutton  $importbutton
 END  END
     return $result;      return $result;
 }  }
   
 ######################################################################  
 ######################################################################  
 sub search_status_header {  
     my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);  
     return <<ENDSTATUS;  
 <html><head><title>Search Status</title></head>  
 $bodytag  
 <h3>Search Status</h3>  
 Sending search request to LON-CAPA servers.<br />  
 ENDSTATUS  
 }  
   
 sub results_link {  sub results_link {
     my $basic_link   = "/adm/searchcat?"."&table=".$ENV{'form.table'}.      my $basic_link   = "/adm/searchcat?"."&table=".$env{'form.table'}.
         "&persistent_db_id=".$ENV{'form.persistent_db_id'};          "&persistent_db_id=".$env{'form.persistent_db_id'};
     my $results_link = $basic_link."&phase=results".      my $results_link = $basic_link."&phase=results".
         "&pause=1"."&start=1";          "&pause=1"."&start=1";
     return $results_link;      return $results_link;
Line 2546  sub results_link { Line 3282  sub results_link {
 ######################################################################  ######################################################################
 sub print_frames_interface {  sub print_frames_interface {
     my $r = shift;      my $r = shift;
     my $basic_link = "/adm/searchcat?"."&table=".$ENV{'form.table'}.      my $basic_link = "/adm/searchcat?"."&table=".$env{'form.table'}.
         "&persistent_db_id=".$ENV{'form.persistent_db_id'};          "&persistent_db_id=".$env{'form.persistent_db_id'};
     my $run_search_link = $basic_link."&phase=run_search";      my $run_search_link = $basic_link."&phase=run_search";
     my $results_link = &results_link();      my $results_link = &results_link();
     my $result = <<"ENDFRAMES";      my $js = <<JS;
 <html>  <script type="text/javascript">
 <head>  
 <script>  
 var targetwin = opener;  var targetwin = opener;
 var queue = '';  var queue = '';
 </script>  </script>
 <title>LON-CAPA Digital Library Search Results</title>  JS
 </head>  
 <frameset rows="150,*">      my $start_page =
           &Apache::loncommon::start_page('LON-CAPA Digital Library Search Results',
          $js,
          {'frameset'    => 1,
    'add_entries' => {
       'rows' => "150,*",},});
       my $end_page =
           &Apache::loncommon::end_page({'frameset' => 1});
   
       my $result = <<"ENDFRAMES";
   $start_page
     <frame name="statusframe"  src="$run_search_link">      <frame name="statusframe"  src="$run_search_link">
     <frame name="resultsframe" src="$results_link">      <frame name="resultsframe" src="$results_link">
 </frameset>  $end_page
 </html>  
 ENDFRAMES  ENDFRAMES
   
     $r->print($result);      $r->print($result);
Line 2573  ENDFRAMES Line 3316  ENDFRAMES
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
   sub has_stat_data {
       my ($values) = @_;
       if ( (defined($values->{'count'})      && $values->{'count'}      ne '') ||
            (defined($values->{'stdno'})      && $values->{'stdno'}      ne '') ||
            (defined($values->{'disc'})       && $values->{'disc'}       ne '') ||
            (defined($values->{'avetries'})   && $values->{'avetries'}   ne '') ||
            (defined($values->{'difficulty'}) && $values->{'difficulty'} ne '')) {
           return 1;
       }
       return 0;
   }
   
   sub statfields {
       return ('count','stdno','disc','avetries','difficulty');
   }
   
   sub has_eval_data {
       my ($values) = @_;
       if ( (defined($values->{'clear'})     && $values->{'clear'}     ne '') ||
            (defined($values->{'technical'}) && $values->{'technical'} ne '') ||
            (defined($values->{'correct'})   && $values->{'correct'}   ne '') ||
            (defined($values->{'helpful'})   && $values->{'helpful'}   ne '') ||
            (defined($values->{'depth'})     && $values->{'depth'}     ne '')) {
           return 1;
       }
       return 0;
   }
   
   sub evalfields { 
       return ('clear','technical','correct','helpful','depth');
   }
   
   ######################################################################
   ######################################################################
   
 =pod   =pod 
   
 =item Metadata Viewing Functions  =item Metadata Viewing Functions
Line 2594  extra custom metadata to show. Line 3372  extra custom metadata to show.
 ######################################################################  ######################################################################
 sub detailed_citation_view {  sub detailed_citation_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
     my $icon=&Apache::loncommon::icon($values{'url'});      my $result;
     my $result=<<END;      my $jumpurl=$values{'url'};
 <b>$prefix<img src="$icon" /><a href="http://$ENV{'HTTP_HOST'}$values{'url'}"       $jumpurl=~s|^/ext/|http://|;
     target='search_preview'>$values{'title'}</a></b>      $result .= '<b>'.$prefix.
 <p>          '<img src="'.&Apache::loncommon::icon($values{'url'}).'" />'.'&nbsp;'.
 <b>$values{'author'}</b>, <i>$values{'owner'}</i><br />          '<a href="'.$jumpurl.'" '.
           'target="preview">'.$values{'title'}."</a></b>\n";
 <b>Subject:       </b> $values{'subject'}<br />      $result .= "<p>\n";
 <b>Keyword(s):    </b> $values{'keywords'}<br />      $result .= '<b>'.$values{'author'}.'</b>,'.
 <b>Notes:         </b> $values{'notes'}<br />          ' <i>'.$values{'owner'}.'</i><br />';
 <b>MIME Type:     </b> $values{'mimetag'}<br />      foreach my $field 
 <b>Language:      </b> $values{'language'}<br />          (
 <b>Copyright/Distribution:</b> $values{'copyrighttag'}<br />           { name=>'url',
 </p>             translate => '<b>URL:</b>&nbsp;[_1]',
 $values{'extrashow'}             special => 'url link',},
 <p>           { name=>'subject',
 $values{'shortabstract'}             translate => '<b>Subject:</b>&nbsp;[_1]',},
 </p>           { name=>'keywords',
 <hr align='left' width='200' noshade />             translate => '<b>Keywords:</b>&nbsp;[_1]',},
 END           { name=>'notes',
              translate => '<b>Notes:</b>&nbsp;[_1]',},
            { name=>'mimetag',
              translate => '<b>MIME Type:</b>&nbsp;[_1]',},
            { name=>'standards',
              translate => '<b>Standards:</b>[_1]',},
            { name=>'copyrighttag',
              translate => '<b>Copyright/Distribution:</b>&nbsp;[_1]',},
            { name=>'count',
              format => "%d",
              translate => '<b>Access Count:</b>&nbsp;[_1]',},
            { name=>'stdno',
              format => "%d",
              translate => '<b>Number of Students:</b>&nbsp;[_1]',},
            { name=>'avetries',
              format => "%.2f",
              translate => '<b>Average Tries:</b>&nbsp;[_1]',},
            { name=>'disc',
              format => "%.2f",
              translate => '<b>Degree of Discrimination:</b>&nbsp;[_1]',},
            { name=>'difficulty',
              format => "%.2f",
              translate => '<b>Degree of Difficulty:</b>&nbsp;[_1]',},
            { name=>'clear',
              format => "%.2f",
              translate => '<b>Clear:</b>&nbsp;[_1]',},
            { name=>'depth',
              format => "%.2f",
              translate => '<b>Depth:</b>&nbsp;[_1]',},
            { name=>'helpful',
              format => "%.2f",
              translate => '<b>Helpful:</b>&nbsp;[_1]',},
            { name=>'correct',
              format => "%.2f",
              translate => '<b>Correct:</b>&nbsp;[_1]',},
            { name=>'technical',
              format => "%.2f",
              translate => '<b>Technical:</b>&nbsp;[_1]',},
            { name=>'comefrom_list',
              type => 'list',
              translate => 'Resources that lead up to this resource in maps',},
            { name=>'goto_list',
              type => 'list',
              translate => 'Resources that follow this resource in maps',},
            { name=>'sequsage_list',
              type => 'list',
              translate => 'Resources using or importing resource',},
            ) {
           next if (! exists($values{$field->{'name'}}) ||
                    $values{$field->{'name'}} eq '');
           if (exists($field->{'type'}) && $field->{'type'} eq 'list') {
               $result .= '<b>'.&mt($field->{'translate'}).'</b>';
               foreach my $item (split(',',$values{$field->{'name'}})){
                   $result .= 
     &Apache::lonhtmlcommon::crumbs(&Apache::lonnet::clutter($item),
     'preview',
     '',
     (($env{'form.catalogmode'} eq 'import')?'parent.statusframe.document.forms.statusform':''),2,0,1);
               }
           } elsif (exists($field->{'format'}) && $field->{'format'} ne ''){
               $result.= &mt($field->{'translate'},
                             sprintf($field->{'format'},
                                     $values{$field->{'name'}}))."<br />\n";
           } else {
               if ($field->{'special'} eq 'url link') {
                  if ($jumpurl=~/^http\:\/\//) {
                    $result.='<tt>'.$jumpurl.'</tt>';
                  } else {
                    $result .=
     &Apache::lonhtmlcommon::crumbs($jumpurl,
     'preview',
     '',
     (($env{'form.catalogmode'} eq 'import')?'parent.statusframe.document.forms.statusform':''),3,0,1);
                  }
               } else {
                   $result.= &mt($field->{'translate'},
                                 $values{$field->{'name'}});
               }
               $result .= "<br />\n";
           }
       }
       $result .= "</p>";
       if (exists($values{'extrashow'}) && $values{'extrashow'} ne '') {
           $result .= '<p>'.$values{'extrashow'}.'</p>';
       }
       if (exists($values{'shortabstract'}) && $values{'shortabstract'} ne '') {
           $result .= '<p>'.$values{'shortabstract'}.'</p>';
       }
       $result .= '<hr align="left" width="200" noshade />'."\n";
     return $result;      return $result;
 }  }
   
   sub detailed_citation_preview {
       my ($prefix,%values)=@_;
       return '<table><tr><td>'.
              &detailed_citation_view($prefix,%values).
              '</td><td>'.
              &Apache::lonindexer::showpreview($values{'url'}).
              '</td></tr></table><hr />';
   }
   
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 2630  END Line 3506  END
 sub summary_view {  sub summary_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
     my $icon=&Apache::loncommon::icon($values{'url'});      my $icon=&Apache::loncommon::icon($values{'url'});
     my $result=<<END;      my $result=qq{$prefix<img src="$icon" />};
 $prefix<img src="$icon" /><a href="http://$ENV{'HTTP_HOST'}$values{'url'}"       if (exists($env{'form.sortfield'}) && 
    target='search_preview'>$values{'author'}</a><br />          $env{'form.sortfield'} !~ /^(default|
 $values{'title'}<br />                                       author|
 $values{'owner'} -- $values{'lastrevisiondate'}<br />                                       url|
                                        title|
                                        owner|
                                        lastrevisiondate|
                                        copyright)$/x) {
           my $tmp = $values{$env{'form.sortfield'}};
           if (! defined($tmp)) { $tmp = 'undefined'; }
           $result .= '&nbsp;'.$tmp.'&nbsp;';
       }
       my $jumpurl=$values{'url'};
       my $link;
       if ($jumpurl=~m|^/ext/|) {
    $jumpurl=~s|^/ext/|http://|;
    $link='<br /><tt>'.$jumpurl.'</tt>';
       } else {
    $link=&Apache::lonhtmlcommon::crumbs($jumpurl,
     'preview',
     '',
     (($env{'form.catalogmode'} eq 'import')?'parent.statusframe.document.forms.statusform':''),2,0,1);
       }
       $result.=<<END;
   <a href="$jumpurl" 
      target='preview'>$values{'title'}</a>$link
   $values{'author'}, $values{'owner'} -- $values{'lastrevisiondate'}<br />
 $values{'copyrighttag'}<br />  $values{'copyrighttag'}<br />
 $values{'extrashow'}  $values{'extrashow'}
 </p>  </p>
Line 2643  END Line 3542  END
     return $result;      return $result;
 }  }
   
   sub summary_preview {
       my ($prefix,%values)=@_;
       return '<table><tr><td>'.
              &summary_view($prefix,%values).
              '</td><td>'.
              &Apache::lonindexer::showpreview($values{'url'}).
              '</td></tr></table><hr />';
   }
   
 ######################################################################  ######################################################################
 ######################################################################  ######################################################################
   
Line 2656  END Line 3564  END
 ######################################################################  ######################################################################
 sub compact_view {  sub compact_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
     my $icon=&Apache::loncommon::icon($values{'url'});      my $jumpurl=$values{'url'};
     my $result=<<END;      my $link;
 $prefix <img src="$icon" /> <a href="http://$ENV{'HTTP_HOST'}$values{'url'}"  target='search_preview'>      if ($jumpurl=~m|^/ext/|) {
 $values{'title'}</a>   $jumpurl=~s|^/ext/|http://|;
 <b>$values{'author'}</b><br />   $link='<tt>'.$jumpurl.'</tt>';
 END      } else {
           $link=&Apache::lonhtmlcommon::crumbs($jumpurl,
     'preview',
     '',
     (($env{'form.catalogmode'} eq 'import')?'parent.statusframe.document.forms.statusform':''),1,1,1).' ';
       }
       my $result = 
           $prefix.'<img src="'.&Apache::loncommon::icon($values{'url'}).'">';
       if (exists($env{'form.sortfield'}) && 
           $env{'form.sortfield'} !~ /^(default|author|url|title)$/) {
           my $tmp = $values{$env{'form.sortfield'}};
           if (! defined($tmp)) { $tmp = 'undefined'; }
           $result .= '&nbsp;'.$tmp.'&nbsp;';
       }
       $result.='&nbsp;<a href="'.$jumpurl.'" target="preview">'.
           $values{'title'}.'</a>'.('&nbsp;'x2).$link.
           '<b>'.$values{'author'}.'</b> ('.$values{'domain'}.')<br />';
     return $result;      return $result;
 }  }
   
Line 2680  END Line 3604  END
 sub fielded_format_view {  sub fielded_format_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
     my $icon=&Apache::loncommon::icon($values{'url'});      my $icon=&Apache::loncommon::icon($values{'url'});
       my %Translated = &Apache::lonmeta::fieldnames();
       my $jumpurl=$values{'url'};
       $jumpurl=~s|^/ext/|http://|;
   
     my $result=<<END;      my $result=<<END;
 $prefix <img src="$icon" />  $prefix <img src="$icon" />
 <b>URL: </b> <a href="http://$ENV{'HTTP_HOST'}$values{'url'}"   <dl>
               target='search_preview'>$values{'url'}</a>  <dt>URL:</dt>
 <br />      <dd><a href="$jumpurl" 
 <b>Title:</b> $values{'title'}<br />           target='preview'>$values{'url'}</a></dd>
 <b>Author(s):</b> $values{'author'}<br />  
 <b>Subject:</b> $values{'subject'}<br />  
 <b>Keyword(s):</b> $values{'keywords'}<br />  
 <b>Notes:</b> $values{'notes'}<br />  
 <b>MIME Type:</b> $values{'mimetag'}<br />  
 <b>Language:</b> $values{'language'}<br />  
 <b>Creation Date:</b> $values{'creationdate'}<br />  
 <b>Last Revision Date:</b> $values{'lastrevisiondate'}<br />  
 <b>Publisher/Owner:</b> $values{'owner'}<br />  
 <b>Copyright/Distribution:</b> $values{'copyrighttag'}<br />  
 <b>Repository Location:</b> $values{'hostname'}<br />  
 <b>Abstract:</b> $values{'shortabstract'}<br />  
 $values{'extrashow'}  
 </p>  
 <hr align='left' width='200' noshade />  
 END  END
       foreach my $field ('title','author','domain','subject','keywords','notes',
                          'mimetag','language','creationdate','lastrevisiondate',
                          'owner','copyrighttag','hostname','abstract') {
           $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n".
               (' 'x8).'<dd>'.$values{$field}.'</dd>'."\n";
       }
       if (&has_stat_data(\%values)) {
           foreach my $field (&statfields()) {
               $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n".
                   (' 'x8).'<dd>'.$values{$field}.'</dd>'."\n";
           }
       }
       if (&has_eval_data(\%values)) {
           foreach my $field (&evalfields()) {
               $result .= (' 'x4).'<dt>'.$Translated{$field}.'</dt>'."\n".
                   (' 'x8).'<dd>'.$values{$field}.'</dd>'."\n";
           }
       }
       $result .= "</dl>\n";
       $result .= $values{'extrashow'};
       $result .= '<hr align="left" width="200" noshade />'."\n";
     return $result;      return $result;
 }  }
   
Line 2720  END Line 3654  END
 ######################################################################  ######################################################################
 sub xml_sgml_view {  sub xml_sgml_view {
     my ($prefix,%values) = @_;      my ($prefix,%values) = @_;
     my $xml = <<END;      my $xml = '<LonCapaResource>'."\n";
 <LonCapaResource>      # The usual suspects
 <url>$values{'url'}</url>      foreach my $field ('url','title','author','subject','keywords','notes','domain') {
 <title>$values{'title'}</title>          $xml .= qq{<$field>$values{$field}</$field>}."\n";
 <author>$values{'author'}</author>      }
 <subject>$values{'subject'}</subject>      #
 <keywords>$values{'keywords'}</keywords>      $xml .= "<mimeInfo>\n";
 <notes>$values{'notes'}</notes>      foreach my $field ('mime','mimetag') {
 <mimeInfo>          $xml .= qq{<$field>$values{$field}</$field>}."\n";
 <mime>$values{'mime'}</mime>      }
 <mimetag>$values{'mimetag'}</mimetag>      $xml .= "</mimeInfo>\n";
 </mimeInfo>      #
 <languageInfo>      $xml .= "<languageInfo>\n";
 <language>$values{'language'}</language>      foreach my $field ('language','languagetag') {
 <languagetag>$values{'languagetag'}</languagetag>          $xml .= qq{<$field>$values{$field}</$field>}."\n";
 </languageInfo>      }
 <creationdate>$values{'creationdate'}</creationdate>      $xml .= "</languageInfo>\n";
 <lastrevisiondate>$values{'lastrevisiondate'}</lastrevisiondate>      #
 <owner>$values{'owner'}</owner>      foreach my $field ('creationdate','lastrevisiondate','owner') {
 <copyrightInfo>          $xml .= qq{<$field>$values{$field}</$field>}."\n";
 <copyright>$values{'copyright'}</copyright>      }
 <copyrighttag>$values{'copyrighttag'}</copyrighttag>      #
 </copyrightInfo>      $xml .= "<copyrightInfo>\n";
 <repositoryLocation>$values{'hostname'}</repositoryLocation>      foreach my $field ('copyright','copyrighttag') {
 <shortabstract>$values{'shortabstract'}</shortabstract>          $xml .= qq{<$field>$values{$field}</$field>}."\n";
 </LonCapaResource>      }
 END      $xml .= "</copyrightInfo>\n";
       $xml .= qq{<repositoryLocation>$values{'hostname'}</repositoryLocation>}.
           "\n";
       $xml .= qq{<shortabstract>$values{'shortabstract'}</shortabstract>}."\n";
       #
       if (&has_stat_data(\%values)){
           $xml .= "<problemstatistics>\n";
           foreach my $field (&statfields()) {
               $xml .= qq{<$field>$values{$field}</$field>}."\n";            
           }
           $xml .= "</problemstatistics>\n";
       }
       #
       if (&has_eval_data(\%values)) {
           $xml .= "<evaluation>\n";
           foreach my $field (&evalfields) {
               $xml .= qq{<$field>$values{$field}</$field>}."\n";            
           }
           $xml .= "</evaluation>\n";
       }    
       #
       $xml .= "</LonCapaResource>\n";
     $xml = &HTML::Entities::encode($xml,'<>&');      $xml = &HTML::Entities::encode($xml,'<>&');
     my $result=<<END;      my $result=<<END;
 $prefix  $prefix
Line 2784  sub filled { Line 3739  sub filled {
   
 =pod   =pod 
   
   =item &output_unparsed_phrase_error()
   
   =cut
   
   ######################################################################
   ######################################################################
   sub output_unparsed_phrase_error {
       my ($r,$closebutton,$parms,$hidden_fields,$field)=@_;
       my $errorstring;
       if ($field eq 'basicexp') {
           $errorstring = &mt('Unable to understand the search phrase <i>[_1]</i>.  Please modify your search.',$env{'form.basicexp'});
       } else {
           $errorstring = &mt('Unable to understand the search phrase <b>[_1]</b>:<i>[_2]</i>.',$field,$env{'form.'.$field});
       }
       my $heading = &mt('Unparsed Field');
       my $revise  = &mt('Revise search request');
       # make query information persistent to allow for subsequent revision
       my $start_page = &Apache::loncommon::start_page('Search');
       my $end_page   = &Apache::loncommon::end_page();
       $r->print(<<ENDPAGE);
   $start_page
   <form method="post" action="/adm/searchcat">
   $hidden_fields
   $closebutton
   <hr />
   <h2>$heading</h2>
   <p>
   $errorstring
   </p>
   <p>
   <a href="/adm/searchcat?$parms&persistent_db_id=$env{'form.persistent_db_id'}">$revise</a>
   </p>
   $end_page
   ENDPAGE
   }
   
   ######################################################################
   ######################################################################
   
   =pod 
   
 =item &output_blank_field_error()  =item &output_blank_field_error()
   
 Output a complete page that indicates the user has not filled in enough  Output a complete page that indicates the user has not filled in enough
Line 2801  $parms is extra information to include i Line 3797  $parms is extra information to include i
 ######################################################################  ######################################################################
 sub output_blank_field_error {  sub output_blank_field_error {
     my ($r,$closebutton,$parms,$hidden_fields)=@_;      my ($r,$closebutton,$parms,$hidden_fields)=@_;
     my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);      my $errormsg = &mt('You did not fill in enough information for the search to be started.  You need to fill in relevant fields on the search page in order for a query to be processed.');
     # make query information persistent to allow for subsequent revision      my $revise = &mt('Revise Search Request');
     $r->print(<<BEGINNING);      my $heading = &mt('Unactionable Search Queary');
 <html>      my $start_page = &Apache::loncommon::start_page('Search');
 <head>      my $end_page   = &Apache::loncommon::end_page();
 <title>The LearningOnline Network with CAPA</title>      $r->print(<<ENDPAGE);
 BEGINNING  $start_page
     $r->print(<<RESULTS);  
 </head>  
 $bodytag  
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  
 <h1>Search Catalog</h1>  
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 $hidden_fields  $hidden_fields
 <a href="/adm/searchcat?$parms&persistent_db_id=$ENV{'form.persistent_db_id'}"  
 >Revise search request</a>&nbsp;  
 $closebutton  $closebutton
 <hr />  <hr />
 <h3>Unactionable search query.</h3>  <h2>$heading</h2>
 <p>  <p>
 You did not fill in enough information for the search to be started.  $errormsg
 You need to fill in relevant fields on the search page in order   
 for a query to be processed.  
 </p>  </p>
 </body>  <p>
 </html>  <a href="/adm/searchcat?$parms&persistent_db_id=$env{'form.persistent_db_id'}">$revise</a>&nbsp;
 RESULTS  </p>
   $end_page
   ENDPAGE
       return;
 }  }
   
 ######################################################################  ######################################################################
Line 2852  Inputs: Line 3842  Inputs:
 sub output_date_error {  sub output_date_error {
     my ($r,$message,$closebutton,$hidden_fields)=@_;      my ($r,$message,$closebutton,$hidden_fields)=@_;
     # make query information persistent to allow for subsequent revision      # make query information persistent to allow for subsequent revision
     my $bodytag=&Apache::loncommon::bodytag(undef,undef,undef,1);      my $start_page = &Apache::loncommon::start_page('Search');
       my $end_page   = &Apache::loncommon::end_page();
     $r->print(<<RESULTS);      $r->print(<<RESULTS);
 <html>  $start_page
 <head>  
 <title>The LearningOnline Network with CAPA</title>  
 </head>  
 $bodytag  
 <img align='right' src='/adm/lonIcons/lonlogos.gif' />  
 <h1>Search Catalog</h1>  
 <form method="post" action="/adm/searchcat">  <form method="post" action="/adm/searchcat">
 $hidden_fields  $hidden_fields
 <input type='button' value='Revise search request'  <input type='button' value='Revise search request'
Line 2871  $closebutton Line 3856  $closebutton
 <p>  <p>
 $message  $message
 </p>  </p>
 </body>  $end_page
 </html>  
 RESULTS  RESULTS
 }  }
   
Line 2912  sub cleanup { Line 3896  sub cleanup {
     }      }
     &untiehash();      &untiehash();
     &Apache::lonmysql::disconnect_from_db();      &Apache::lonmysql::disconnect_from_db();
       return OK;
 }  }
   
 __END__  __END__

Removed from v.1.212  
changed lines
  Added in v.1.285


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