--- biblio/biblio.admin.inc.orig	2008-11-19 11:53:04.000000000 +0100
+++ biblio/biblio.admin.inc	2008-11-19 11:53:35.000000000 +0100
@@ -228,6 +228,26 @@
   // Add profile page settings... this is done in a fucntion so it can be reused elsewhere
   _biblio_get_user_profile_form($form);
   //
+  $form['search'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Search'),
+  );
+  $form['search']['biblio_search'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable a search box on the biblio page.'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_search', 0),
+    '#description' => t('Shows a search box on the biblio page that returns drupal search results in the biblio style.')
+  );
+  $form['search']['biblio_index'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Re-/Index a biblio node when creating or updating.'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_index', 0),
+    '#description' => t('A biblio node must be indexed for the drupal search to know its content. You need to check this option if you want to search for a biblio node that you just created or updated. Otherwise you must wait for the cron job to reindex nodes.')
+  );
   $form['sort'] = array(
     '#type' => 'fieldset',
     '#collapsible' => TRUE,
--- biblio/biblio.css.orig	2008-11-19 11:53:04.000000000 +0100
+++ biblio/biblio.css	2008-11-19 11:53:35.000000000 +0100
@@ -1,4 +1,24 @@
 /** Node admin filter **/
+.biblio-search, .biblio-inline div {  
+  display: inline;
+}
+
+.biblio-inline { 
+  margin-bottom: 10px;
+}
+
+.biblio-search input {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+.biblio-fieldset {
+  margin-top: -1em;
+  border: none;
+  margin-bottom: 0px;
+  padding: 0px 0px 5px 0px;
+  display: inline;
+}
 #biblio-filter ul {
   padding:                    1px;
   margin:                     1px;
--- biblio/biblio.install.orig	2008-11-19 11:53:04.000000000 +0100
+++ biblio/biblio.install	2008-11-19 11:53:35.000000000 +0100
@@ -61,6 +61,8 @@
   variable_del('biblio_rowsperblock');
   variable_del('biblio_show_profile');
   variable_del('biblio_show_profile_tab');
+  variable_del('biblio_search');
+  variable_del('biblio_index');
   variable_del('biblio_sort');
   variable_del('biblio_sort_tabs');
   variable_del('biblio_style');
--- biblio/biblio.module.orig	2008-11-19 11:53:04.000000000 +0100
+++ biblio/biblio.module	2008-11-19 11:53:35.000000000 +0100
@@ -569,7 +569,8 @@
   drupal_goto($base, $options);
 }
 function biblio_nodeapi(& $node, $op, $teaser, $page) {
-  switch ($op) {
+  if ($node->type == 'biblio') {
+    switch ($op) {
     case 'delete revision' :
       db_query('DELETE FROM {biblio} WHERE vid = %d', $node->vid);
       db_query('DELETE FROM {biblio_contributor} WHERE nid = %d AND vid = %d', array($node->nid, $node->vid));
@@ -585,6 +586,23 @@
            }
            break;
       */
+    case 'insert':
+      if (variable_get('biblio_index',0)) {
+        _node_index_node($node); 
+        search_update_totals();
+      }
+      break;
+    case 'update':
+      if (variable_get('biblio_index',0)) {
+        // _node_index_node performs a node_load without resetting the node_load cache,
+        // so it would index the old version. We reset the cache here.
+        // Don't assign node_load to $node because node_load resets e.g. the menus mlid etc.
+        $mynode = node_load($node->nid, NULL, TRUE);
+        _node_index_node($mynode);
+        search_update_totals();
+      }
+      break;  
+    }
   }
 }
 function biblio_node_form_submit(& $node) {
--- biblio/biblio.pages.inc.orig	2008-09-24 04:38:26.000000000 +0200
+++ biblio/biblio.pages.inc	2008-11-19 11:53:43.000000000 +0100
@@ -24,6 +24,47 @@
 function biblio_db_search() {
 
   $arg_list = func_get_args();
+  // Drupal search? It returns an array of search results. We store the nids
+  // of the result nodes and make them a "where n.nid in {..}" filter.
+  // After installing the filter, we can go on as usual.
+
+  // When called manually, search takes one parameter, i.e. 
+  // biblio_db_search('search', 'bla blu')
+  $search = array_search('search', $arg_list);
+  if ($search !== FALSE) {
+    $keys = $arg_list[$search+1];
+  }
+  else {
+    $keys = _get_biblio_search_filter();
+  }
+
+  if ($keys) {
+    // Only search in biblio nodes. If we use a SESSION filter and have a list of 
+    // nids stored there, don't re-search. List is reset when submitting a new search.
+    if ($search !== FALSE || !_get_biblio_search_filter('nodelist')) {
+      if ($result = node_search('search',$keys.' type:biblio')) {
+        $node_list = '';
+        foreach ($result as $res) {
+          $node_list .= $res['node']->nid.",";
+        }
+      }
+      else {
+        // No node search result. Make sure we find nothing, too. Node -1 does not exist.
+        $node_list = '-1';
+      }
+      // Store as SESSION filter or argument list.
+      // When called as function argument it takes only one parameter, i.e.
+      // biblio_db_search('search', 'bla blu') and we must insert the node
+      // list inbetween.
+      if ($search !== FALSE) {
+	array_splice($arg_list,$search+1,0,$node_list);
+      }
+      else {
+	$_SESSION['biblio_filter'] = array(array('search',rtrim($node_list,','),$keys));
+      }
+    }
+  }
+ 
   $inline = in_array('inline', $arg_list);
   $inline = in_array('profile',$arg_list)?'profile':$inline;
   $query_info = biblio_build_query($arg_list);
@@ -250,6 +291,18 @@
               $sortby = "ORDER BY b.biblio_year %s, SUBSTRING(n.title,1,1) ASC, b.biblio_type ASC ";
           } //end switch
           break;
+        case 'search':
+         $term = explode("?",array_shift($arg_list));
+         // Search filter has a third component, the keywords, here useless. Drop it.
+         array_shift($arg_list);
+         $result_nids = split(',', $term[0]);
+         $where[] = "n.nid in (".db_placeholders($result_nids).")";
+         foreach ($result_nids as $result_nid) {
+           $terms[] = db_escape_string($result_nid);
+           array_push($args, $type, $result_nid);
+         }
+         $operator = NULL;
+         break;
         default:
           $fields = biblio_get_db_fields();
           $term = explode("?",array_shift($arg_list));
@@ -309,6 +362,10 @@
     $pub_type["$option->tid"] = $option->name;
   }
   if (!$inline) {
+    // Search box. Has same permissions as the filter tab.
+    if (variable_get('biblio_search',0) && user_access('show filter tab')) {
+      $content .= drupal_get_form('biblio_search_form');
+    }
     // Add some links to the top of the page to change the sorting/ordering...
     $order = ($attrib['order'] == "desc" || $attrib['order'] == "DESC")?"asc":"desc";
     if ( biblio_access('export')) {
@@ -355,12 +412,16 @@
     $session = &$_SESSION['biblio_filter'];
     // if there are any filters in place, print them at the top of the list
     if (count($args)) {
-      $content .= '<div class="biblio-current-filters"><b>'.t('Filters').': </b>';
       $i = 0;
       while ($args) {
         $type = $args[0];
         array_shift($args);
         $value = db_escape_string($args[0]);
+	if ($type == 'search') {
+	  $search_content = '<em>'._get_biblio_search_filter().'</em>';
+	  array_shift($args);
+	  continue;
+	}
         if ($type == 'term_id') {
           $term = taxonomy_get_term($value);
           $value = $term->name;
@@ -374,8 +435,19 @@
         if ($type == 'type') $value = $pub_type["$value"];
         array_shift($args);
         $params = array('%a' =>  $type , '%b' =>  $value );
-        $content .= ($i++ ? t('<em> and</em> <strong>%a</strong> is <strong>%b</strong>', $params) : t('<strong>%a</strong> is <strong>%b</strong>', $params)) ;
+        $filtercontent .= ($i++ ? t('<em> and</em> <strong>%a</strong> is <strong>%b</strong>', $params) : t('<strong>%a</strong> is <strong>%b</strong>', $params)) ;
       }
+      if ($search_content) {
+	$content .= '<div class="biblio-current-filters"><b>'.t('Search results for ').'</b>';
+	$content .= $search_content;
+	if ($filtercontent) {
+	  $content .= '<br><b>'.t('Filters').': </b>';
+	}
+      }
+      else {
+	$content .= '<div class="biblio-current-filters"><b>'.t('Filters').': </b>';
+      }
+      $content .= $filtercontent;
        $link_options = array();
        if (isset($_GET['sort'])) {
             $link_options['query']  .= "sort=" . $_GET['sort'];
@@ -385,7 +457,11 @@
      	$link_options['query']   .= "order=" . $_GET['order'];
   	   }
 
-      $content .= '&nbsp;&nbsp;'.l('['.t('Clear All Filters').']',"$base/filter/clear", $link_options);
+      if ($search_content) {
+        $content .= '&nbsp;&nbsp;'.l('['.t('Reset Search').']',"$base/filter/clear", $link_options);
+      } else {
+        $content .= '&nbsp;&nbsp;'.l('['.t('Clear All Filters').']',"$base/filter/clear", $link_options);
+      }
       $content .= '</div>';
     }
   }
@@ -465,6 +541,98 @@
   if ($inline === "profile")  return $content;
 
 }
+
+
+/**
+ * Add a search field on the main biblio page.
+ */
+function biblio_search_form(&$form_state) {
+ $form = array(
+    '#attributes' => array('class' => 'biblio-search'),
+  );
+  $form['module'] = array('#type' => 'value', '#value' => $type);
+
+  // Uncomment to collapse the search box.
+  //$form['basic'] = array(
+  //  '#attributes' => array('class' => 'biblio-fieldset'),
+  //  '#type' => 'fieldset',
+  //  '#collapsible' => TRUE,
+  //  '#collapsed' => TRUE,
+  //  '#title' => t('Quick Search'),
+  //  '#description' => '',
+  //  );
+
+  $form['basic']['inline'] = array('#prefix' => '<div class="biblio-inline">', '#suffix' => '</div>');
+  $form['basic']['inline']['keys'] = array(
+    '#type' => 'textfield',
+    '#title' => '',
+    '#default_value' => '',
+    '#size' => 25,
+    '#maxlength' => 255,
+  );
+  $form['basic']['inline']['submit'] = array('#type' => 'submit', '#value' => t('Biblio search'));
+  return $form;
+}
+
+/**
+ * We must validate the keyword length before calling node_search. Otherwise
+ * we would store a keyword of e.g. length 1, but do_search would complain about
+ * it later and resend us to the input form. But since the keyword was stored already
+ * we could never again display the page without errors
+ */
+function biblio_search_form_validate($form, &$form_state) {
+  // Empty searchbox finds everything.
+  $keys = $form_state['values']['keys'];
+  if ($keys != '')  {
+    $query = search_parse_query($form_state['values']['keys']);
+    if ($query[2] == '') {
+      form_set_error('keys', t('You must include at least one positive keyword with @count characters or more.', array('@count' => variable_get('minimum_word_size', 3))));
+    }
+  }
+}
+
+
+/**
+ * When we submit a search, we revoke all current filters since search
+ * and filtering are considered two different concepts things* conceptually.
+ *
+ * But we store the results as a filter (which is just a list of node ids that
+ * matched the search request) so that we can reorder or export the search
+ * results like with any other filter.  The filter has three components:
+ * ('search',<list of node ids>,<search keywords>).
+ * The second component, the filter value, is empty when submitting keywords.
+ * In biblio_db_search we fill the second component with the list of nids
+ * matching our keywords, as returned by node_search.  We store the keywords
+ * only for showing them in "Search results for <keywords>".
+ */
+function biblio_search_form_submit($form, &$form_state) {
+  $keys = $form_state['values']['keys'];
+  if ($keys != '')  {
+    $_SESSION['biblio_filter'] = array(array('search','',$keys));
+    $base =  variable_get('biblio_base', 'biblio');
+    $form_state['redirect'] = $base;
+  }
+  else {
+    // No keywords. Remove former search keys if any. Leaves other filters intact.
+    if (_get_biblio_search_filter()){
+      $_SESSION['biblio_filter'] = array();
+    }
+  }
+}
+
+function _get_biblio_search_filter($arg = 'keys') {
+  if (variable_get('biblio_search',0) &&
+      is_array($_SESSION['biblio_filter']) &&
+      is_array($_SESSION['biblio_filter'][0]) &&
+      in_array('search',$_SESSION['biblio_filter'][0])) {
+    switch ($arg) {
+    case 'keys': return $_SESSION['biblio_filter'][0][2]; break;
+    case 'nodelist': return $_SESSION['biblio_filter'][0][1]; break;
+    }
+  }
+}
+
+
 function _get_biblio_filters() {
 
   $fields = " b.biblio_year, t.name , t.tid ";
@@ -513,7 +681,8 @@
 }
 
 function biblio_form_filter() {
-  $session = &$_SESSION['biblio_filter'];
+  // No longer use &$_SESSION so that we can alter $session in case of the search filter.
+  $session = $_SESSION['biblio_filter'];
   $session = is_array($session) ? $session : array();
   $filters = _get_biblio_filters();
 
@@ -524,6 +693,11 @@
   );
   foreach ($session as $filter) {
     list($type, $value) = $filter;
+    // Don't show the search filter. Reset $session because of the $count(session) below.
+    if ($type == 'search') {
+      $session = array ();
+      break;
+    }
     if ($type == 'category') {
       // Load term name from DB rather than search and parse options array.
       $value = module_invoke('taxonomy', 'get_term', $value);
@@ -548,7 +722,7 @@
 
   $form['filters']['filter'] = array('#type' => 'radios', '#options' => $names, '#default_value' => 'aid');
   $form['filters']['buttons']['submit'] = array('#type' => 'submit', '#value' => (count($session) ? t('Refine') : t('Filter')));
-  if (count($session)) {
+  if (count($session) && $type != 'search') {
     $form['filters']['buttons']['undo'] = array('#type' => 'submit', '#value' => t('Undo'));
     $form['filters']['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset'));
   }
@@ -557,6 +731,10 @@
 }
 
 function biblio_form_filter_submit($form, &$form_state) {
+  // If the search filter was set, remove it now.
+  if(_get_biblio_search_filter()){
+    $_SESSION['biblio_filter'] = array ();
+  }
   $op = $form_state['values']['op'];
   $filters = _get_biblio_filters();
   switch ($op) {
