Index: contentsearch.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/coresearches/contentsearch.info,v
retrieving revision 1.1
diff -u -p -r1.1 contentsearch.info
--- contentsearch.info	13 Dec 2007 12:21:36 -0000	1.1
+++ contentsearch.info	11 Jul 2008 21:17:20 -0000
@@ -2,5 +2,6 @@
 name = Content search
 description = Adds a tab to the search page for finding content.
 package = Search
-dependencies = search
+dependencies[] = search
 version = VERSION
+core = 6.x
Index: contentsearch.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/coresearches/contentsearch.module,v
retrieving revision 1.1.2.3
diff -u -p -r1.1.2.3 contentsearch.module
--- contentsearch.module	7 Jul 2008 12:00:54 -0000	1.1.2.3
+++ contentsearch.module	11 Jul 2008 21:17:20 -0000
@@ -1,13 +1,19 @@
 <?php
-// $Id: contentsearch.module,v 1.1.2.3 2008/07/07 12:00:54 robertDouglass Exp $   
+// $Id$
 
-function contentsearch_menu($maycache) {
+/**
+ * @file
+ * Content search
+ *
+ */
+function contentsearch_menu() {
   $items = array();
   if ($maycache) {
-    $items[] = array('path' => 'admin/content/search', 'title' => t('Search content'),
-      'description' => t('Search content by keyword.'),
-      'callback' => 'contentsearch_admin_search',
-      'access' => user_access('administer nodes'),
+    $items['admin/content/search'] = array(
+      'title' => 'Search content',
+      'description' => 'Search content by keyword.',
+      'page callback' => 'contentsearch_admin_search',
+      'access arguments' => array('administer nodes'),
       'type' => MENU_NORMAL_ITEM);
   }
   return $items;
@@ -16,72 +22,64 @@ function contentsearch_menu($maycache) {
 function contentsearch_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
   switch ($op) {
     case 'delete':
-	  // Remove this node from the search index if needed.
+      // Remove this node from the search index if needed.
       search_wipe($node->nid, 'node');
-      break;
-  } 
+    break;
+  }
 }
 
 /**
  * Implementation of hook_update_index().
  */
 function contentsearch_update_index() {
-  global $last_change, $last_nid;
-
-  register_shutdown_function('contentsearch_update_shutdown');
-
-  $last = variable_get('contentsearch_cron_last', 0);
-  $last_nid = variable_get('contentsearch_cron_last_nid', 0);
   $limit = (int)variable_get('search_cron_limit', 100);
 
   // Store the maximum possible comments per thread (used for ranking by reply count)
   variable_set('contentsearch_cron_comments_scale', 1.0 / max(1, db_result(db_query('SELECT MAX(comment_count) FROM {node_comment_statistics}'))));
   variable_set('contentsearch_cron_views_scale', 1.0 / max(1, db_result(db_query('SELECT MAX(totalcount) FROM {node_counter}'))));
 
-  $result = db_query_range('SELECT GREATEST(IF(c.last_comment_timestamp IS NULL, 0, c.last_comment_timestamp), n.changed) as last_change, n.nid FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE n.status = 1 AND ((GREATEST(n.changed, c.last_comment_timestamp) = %d AND n.nid > %d) OR (n.changed > %d OR c.last_comment_timestamp > %d)) ORDER BY GREATEST(n.changed, c.last_comment_timestamp) ASC, n.nid ASC', $last, $last_nid, $last, $last, $last, 0, $limit);
+  $result = db_query_range("SELECT n.nid FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE d.sid IS NULL OR d.reindex <> 0 ORDER BY d.reindex ASC, n.nid ASC", 0, $limit);
 
   while ($node = db_fetch_object($result)) {
-    $last_change = $node->last_change;
-    $last_nid = $node->nid;
-    $node = node_load($node->nid);
-
-    // Build the node body.
-    $node = node_build_content($node, FALSE, FALSE);
-    $node->body = drupal_render($node->content);
-
-    $text = '<h1>'. check_plain($node->title) .'</h1>'. $node->body;
-
-    // Fetch extra data normally not visible
-    $extra = node_invoke_nodeapi($node, 'update index');
-    foreach ($extra as $t) {
-      $text .= $t;
-    }
-
-    // Update index
-    search_index($node->nid, 'node', $text);
+    _contentsearch_index_node($node);
   }
 }
 
-
 /**
- * shutdown function to make sure we always mark the last node processed.
+ * Index a single node.
+ *
+ * @param $node
+ *   The node to index.
  */
-function contentsearch_update_shutdown() {
-  global $last_change, $last_nid;
+function _contentsearch_index_node($node) {
+  $node = node_load($node->nid);
+
+  // save the changed time of the most recent indexed node, for the search results half-life calculation
+  variable_set('contentsearch_cron_last', $node->changed);
 
-  if ($last_change && $last_nid) {
-    variable_set('contentsearch_cron_last', $last_change);
-    variable_set('contentsearch_cron_last_nid', $last_nid);
+  // Build the node body.
+  $node->build_mode = NODE_BUILD_SEARCH_INDEX;
+  $node = node_build_content($node, FALSE, FALSE);
+  $node->body = drupal_render($node->content);
+
+  $text = '<h1>'. check_plain($node->title) .'</h1>'. $node->body;
+
+  // Fetch extra data normally not visible
+  $extra = node_invoke_nodeapi($node, 'update index');
+  foreach ($extra as $t) {
+    $text .= $t;
   }
-}
 
+  // Update index
+  search_index($node->nid, 'node', $text);
+}
 
 /**
  * Implementation of hook_form_alter().
  */
-function contentsearch_form_alter($form_id, &$form) {
+function contentsearch_form_alter(&$form, &$form_state, $form_id) {
   // Advanced node search form
-  if ($form_id == 'search_form' && arg(1) == 'node' && user_access('use advanced search')) {
+  if ($form_id == 'search_form' && $form['module']['#value'] == 'node' && user_access('use advanced search')) {
     // Keyword boxes:
     $form['advanced'] = array(
       '#type' => 'fieldset',
@@ -142,44 +140,44 @@ function contentsearch_form_alter($form_
       '#suffix' => '</div>',
     );
 
-    $form['#validate']['contentsearch_search_validate'] = array();
+    $form['#validate'][] = 'contentsearch_search_validate';
   }
 }
 
 /**
  * Form API callback for the search form. Registered in node_form_alter().
  */
-function contentsearch_search_validate($form_id, $form_values, $form) {
+function contentsearch_search_validate($form, &$form_state) {
   // Initialise using any existing basic search keywords.
-  $keys = $form_values['processed_keys'];
+  $keys = $form_state['values']['processed_keys'];
 
   // Insert extra restrictions into the search keywords string.
-  if (isset($form_values['type']) && is_array($form_values['type'])) {
+  if (isset($form_state['values']['type']) && is_array($form_state['values']['type'])) {
     // Retrieve selected types - Forms API sets the value of unselected checkboxes to 0.
-    $form_values['type'] = array_filter($form_values['type']);
-    if (count($form_values['type'])) {
-      $keys = search_query_insert($keys, 'type', implode(',', array_keys($form_values['type'])));
+    $form_state['values']['type'] = array_filter($form_state['values']['type']);
+    if (count($form_state['values']['type'])) {
+      $keys = search_query_insert($keys, 'type', implode(',', array_keys($form_state['values']['type'])));
     }
   }
 
-  if (isset($form_values['category']) && is_array($form_values['category'])) {
-    $keys = search_query_insert($keys, 'category', implode(',', $form_values['category']));
+  if (isset($form_state['values']['category']) && is_array($form_state['values']['category'])) {
+    $keys = search_query_insert($keys, 'category', implode(',', $form_state['values']['category']));
   }
-  if ($form_values['or'] != '') {
-    if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' '. $form_values['or'], $matches)) {
+  if ($form_state['values']['or'] != '') {
+    if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' '. $form_state['values']['or'], $matches)) {
       $keys .= ' '. implode(' OR ', $matches[1]);
     }
   }
-  if ($form_values['negative'] != '') {
-    if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' '. $form_values['negative'], $matches)) {
+  if ($form_state['values']['negative'] != '') {
+    if (preg_match_all('/ ("[^"]+"|[^" ]+)/i', ' '. $form_state['values']['negative'], $matches)) {
       $keys .= ' -'. implode(' -', $matches[1]);
     }
   }
-  if ($form_values['phrase'] != '') {
-    $keys .= ' "'. str_replace('"', ' ', $form_values['phrase']) .'"';
+  if ($form_state['values']['phrase'] != '') {
+    $keys .= ' "'. str_replace('"', ' ', $form_state['values']['phrase']) .'"';
   }
   if (!empty($keys)) {
-    form_set_value($form['basic']['inline']['processed_keys'], trim($keys));
+    form_set_value($form['basic']['inline']['processed_keys'], trim($keys), $form_state);
   }
 }
 
@@ -193,23 +191,25 @@ function contentsearch_search($op = 'sea
       return t('Content');
 
     case 'reset':
-      variable_del('contentsearch_cron_last');
-      variable_del('contentsearch_cron_last_nid');
+      db_query("UPDATE {search_dataset} SET reindex = %d WHERE type = 'node'", time());
       return;
 
     case 'status':
-      $last = variable_get('contentsearch_cron_last', 0);
-      $last_nid = variable_get('contentsearch_cron_last_nid', 0);
       $total = db_result(db_query('SELECT COUNT(*) FROM {node} WHERE status = 1'));
-      $remaining = db_result(db_query('SELECT COUNT(*) FROM {node} n LEFT JOIN {node_comment_statistics} c ON n.nid = c.nid WHERE n.status = 1 AND ((GREATEST(n.created, n.changed, c.last_comment_timestamp) = %d AND n.nid > %d ) OR (n.created > %d OR n.changed > %d OR c.last_comment_timestamp > %d))', $last, $last_nid, $last, $last, $last));
+      $remaining = db_result(db_query("SELECT COUNT(*) FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE n.status = 1 AND (d.sid IS NULL OR d.reindex <> 0)"));
       return array('remaining' => $remaining, 'total' => $total);
 
     case 'admin':
       $form = array();
       // Output form for defining rank factor weights.
-      $form['content_ranking'] = array('#type' => 'fieldset', '#title' => t('Content ranking'));
+      $form['content_ranking'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Content ranking'),
+      );
       $form['content_ranking']['#theme'] = 'node_search_admin';
-      $form['content_ranking']['info'] = array('#value' => '<em>'. t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') .'</em>');
+      $form['content_ranking']['info'] = array(
+        '#value' => '<em>'. t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property isignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') .'</em>'
+      );
 
       $ranking = array('node_rank_relevance' => t('Keyword relevance'),
                        'node_rank_recent' => t('Recently posted'));
@@ -223,7 +223,12 @@ function contentsearch_search($op = 'sea
       // Note: reversed to reflect that higher number = higher ranking.
       $options = drupal_map_assoc(range(0, 10));
       foreach ($ranking as $var => $title) {
-        $form['content_ranking']['factors'][$var] = array('#title' => $title, '#type' => 'select', '#options' => $options, '#default_value' => variable_get($var, 5));
+        $form['content_ranking']['factors'][$var] = array(
+          '#title' => $title,
+          '#type' => 'select',
+          '#options' => $options,
+          '#default_value' => variable_get($var, 5),
+        );
       }
       return $form;
 
@@ -250,7 +255,7 @@ function contentsearch_search($op = 'sea
           $arguments1[] = $c;
         }
         $conditions1 .= ' AND ('. implode(' OR ', $categories) .')';
-        $join1 .= ' INNER JOIN {term_node} tn ON n.nid = tn.nid';
+        $join1 .= ' INNER JOIN {term_node} tn ON n.vid = tn.vid';
         $keys = search_query_insert($keys, 'category');
       }
 
@@ -270,17 +275,18 @@ function contentsearch_search($op = 'sea
       }
       if ($weight = (int)variable_get('node_rank_recent', 5)) {
         // Exponential decay with half-life of 6 months, starting at last indexed node
-        $ranking[] = '%d * POW(2, (GREATEST(n.created, n.changed, c.last_comment_timestamp) - %d) * 6.43e-8)';
+        $ranking[] = '%d * POW(2, (GREATEST(MAX(n.created), MAX(n.changed), MAX(c.last_comment_time
+stamp)) - %d) * 6.43e-8)';
         $arguments2[] = $weight;
-        $arguments2[] = (int)variable_get('node_cron_last', 0);
-        $join2 .= ' INNER JOIN {node} n ON n.nid = i.sid LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
+        $arguments2[] = (int)variable_get('contentsearch_cron_last', 0);
+        $join2 .= ' LEFT JOIN {node_comment_statistics} c ON c.nid = i.sid';
         $stats_join = TRUE;
         $total += $weight;
       }
       if (module_exists('comment') && $weight = (int)variable_get('node_rank_comments', 5)) {
         // Inverse law that maps the highest reply count on the site to 1 and 0 to 0.
         $scale = variable_get('node_cron_comments_scale', 0.0);
-        $ranking[] = '%d * (2.0 - 2.0 / (1.0 + c.comment_count * %f))';
+        $ranking[] = '%d * (2.0 - 2.0 / (1.0 + MAX(c.comment_count) * %f))';
         $arguments2[] = $weight;
         $arguments2[] = $scale;
         if (!$stats_join) {
@@ -292,14 +298,23 @@ function contentsearch_search($op = 'sea
           $weight = (int)variable_get('node_rank_views', 5)) {
         // Inverse law that maps the highest view count on the site to 1 and 0 to 0.
         $scale = variable_get('node_cron_views_scale', 0.0);
-        $ranking[] = '%d * (2.0 - 2.0 / (1.0 + nc.totalcount * %f))';
+        $ranking[] = '%d * (2.0 - 2.0 / (1.0 + MAX(nc.totalcount) * %f))';
         $arguments2[] = $weight;
         $arguments2[] = $scale;
         $join2 .= ' LEFT JOIN {node_counter} nc ON nc.nid = i.sid';
         $total += $weight;
       }
-      $select2 = (count($ranking) ? implode(' + ', $ranking) : 'i.relevance') .' AS score';
-
+      // When all search factors are disabled (ie they have a weight of zero), 
+      // the default score is based only on keyword relevance and there is no need to 
+      // adjust the score of each item. 
+      if ($total == 0) {
+        $select2 = 'i.relevance AS score';
+        $total = 1;
+      }
+      else {
+        $select2 = implode(' + ', $ranking) . ' AS score';
+      }
+      
       // Do search
       $find = do_search($keys, 'node', 'INNER JOIN {node} n ON n.nid = i.sid '. $join1 .' INNER JOIN {users} u ON n.uid = u.uid', $conditions1 . (empty($where1) ? '' : ' AND '. $where1), $arguments1, $select2, $join2, $arguments2);
 
@@ -308,6 +323,7 @@ function contentsearch_search($op = 'sea
       foreach ($find as $item) {
         // Build the node body.
         $node = node_load($item->sid);
+        $node->build_mode = NODE_BUILD_SEARCH_RESULT;
         $node = node_build_content($node, FALSE, FALSE);
         $node->body = drupal_render($node->content);
 
@@ -317,24 +333,37 @@ function contentsearch_search($op = 'sea
         $node->body .= module_invoke('taxonomy', 'nodeapi', $node, 'update index');
 
         $extra = node_invoke_nodeapi($node, 'search result');
-        $results[] = array('link' => url('node/'. $item->sid, NULL, NULL, TRUE),
-                           'type' => node_get_types('name', $node),
-                           'title' => $node->title,
-                           'user' => theme('username', $node),
-                           'date' => $node->changed,
-                           'node' => $node,
-                           'extra' => $extra,
-                           'score' => $item->score / $total,
-                           'snippet' => search_excerpt($keys, $node->body));
+        $results[] = array(
+          'link' => url('node/'. $item->sid, array('absolute' => TRUE)),
+          'type' => check_plain(node_get_types('name', $node)),
+          'title' => $node->title,
+          'user' => theme('username', $node),
+          'date' => $node->changed,
+          'node' => $node,
+          'extra' => $extra,
+          'score' => $item->score / $total,
+          'snippet' => search_excerpt($keys, $node->body),
+        );
       }
       return $results;
   }
 }
 
+
 function contentsearch_admin_search() {
   return drupal_get_form('search_form', url('admin/content/search'), $_POST['keys'], 'node') . search_data($_POST['keys'], 'node');
-}                               
+}
 
+/**
+ * Implementation of hook_theme().
+ */
+function contentsearch_theme() {
+  return array(
+    'contentsearch_search_admin' => array(
+      'arguments' => array('form' => NULL),
+    ),
+  );
+}
 
 function theme_contentsearch_search_admin($form) {
   $output = drupal_render($form['info']);
Index: usersearch.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/coresearches/usersearch.info,v
retrieving revision 1.1
diff -u -p -r1.1 usersearch.info
--- usersearch.info	13 Dec 2007 12:21:36 -0000	1.1
+++ usersearch.info	11 Jul 2008 21:17:20 -0000
@@ -2,5 +2,6 @@
 name = User search
 description = Adds a tab to the search page for finding users.
 package = Search
-dependencies = search
+dependencies[] = search
 version = VERSION
+core = 6.x
Index: usersearch.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/coresearches/usersearch.install,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 usersearch.install
--- usersearch.install	7 Jul 2008 12:00:54 -0000	1.1.2.1
+++ usersearch.install	11 Jul 2008 21:17:20 -0000
@@ -1,5 +1,4 @@
 <?php
-// $Id: usersearch.install,v 1.1.2.1 2008/07/07 12:00:54 robertDouglass Exp $   
 
 function usersearch_install() {
   db_query("UPDATE {system} SET weight = 5 WHERE name = 'usersearch'");
Index: usersearch.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/coresearches/usersearch.module,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 usersearch.module
--- usersearch.module	7 Jul 2008 12:00:54 -0000	1.1.2.1
+++ usersearch.module	11 Jul 2008 21:17:20 -0000
@@ -1,13 +1,18 @@
 <?php
-// $Id: usersearch.module,v 1.1.2.1 2008/07/07 12:00:54 robertDouglass Exp $
-             
+// $Id$
+
+/**
+ * @file
+ * User search
+ */
+
 /**
  * Implementation of hook_search().
  */
-function user_search($op = 'search', $keys = NULL) {
+function usersearch_search($op = 'search', $keys = NULL, $skip_access_check = FALSE) {
   switch ($op) {
     case 'name':
-      if (user_access('access user profiles')) {
+      if ($skip_access_check || user_access('access user profiles')) {
         return t('Users');
       }
     case 'search':
@@ -15,9 +20,18 @@ function user_search($op = 'search', $ke
         $find = array();
         // Replace wildcards with MySQL/PostgreSQL wildcards.
         $keys = preg_replace('!\*+!', '%', $keys);
-        $result = pager_query("SELECT name, uid FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
-        while ($account = db_fetch_object($result)) {
-          $find[] = array('title' => $account->name, 'link' => url('user/'. $account->uid, NULL, NULL, TRUE));
+        if (user_access('administer users')) {
+          // Administrators can also search in the otherwise private email field.
+          $result = pager_query("SELECT name, uid, mail FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%') OR LOWER(mail) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys, $keys);
+          while ($account = db_fetch_object($result)) {
+            $find[] = array('title' => $account->name .' ('. $account->mail .')', 'link' => url('user/'. $account->uid, array('absolute' => TRUE)));
+          }
+        }
+        else {
+          $result = pager_query("SELECT name, uid FROM {users} WHERE LOWER(name) LIKE LOWER('%%%s%%')", 15, 0, NULL, $keys);
+          while ($account = db_fetch_object($result)) {
+            $find[] = array('title' => $account->name, 'link' => url('user/'. $account->uid, array('absolute' => TRUE)));
+          }
         }
         return $find;
       }
