Index: modules/search/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.module,v
retrieving revision 1.344
diff -u -r1.344 search.module
--- modules/search/search.module	11 Apr 2010 18:54:11 -0000	1.344
+++ modules/search/search.module	15 Apr 2010 21:20:38 -0000
@@ -246,9 +246,13 @@
   );
   drupal_static_reset('search_get_info');
   $search_hooks = search_get_info();
+  $default_module = _search_get_active_type();
   foreach(variable_get('search_active_modules', array('node', 'user')) as $module) {
     if (isset($search_hooks[$module])) {
-      $items['search/' . $search_hooks[$module]['path'] . '/%menu_tail'] = array(
+      $path = 'search/' . $search_hooks[$module]['path'];
+      // Set up path as a local task for search/module_path.
+      // These are the active tabs when you go to path 'search'.
+      $items[$path] = array(
         'title' => $search_hooks[$module]['title'],
         'page callback' => 'search_view',
         'page arguments' => array($module),
@@ -256,7 +260,29 @@
         'access arguments' => array($module),
         'type' => MENU_LOCAL_TASK,
         'file' => 'search.pages.inc',
+        'tab_parent' => 'search',
+        'tab_root' => 'search',
       );
+
+      // Make sure the default module is weighted low.
+      if ($module == $default_module) {
+        $items[$path]['weight'] = -10;
+      }
+
+      // Now also make a group of tasks at search/module_path/keywords, with
+      // search/default_module/% as the common 'root' of the tasks, but no
+      // default local task. Note that although the path here ends in
+      // %menu_tail, that gets translated into just % by the time the menu
+      // system is building the tabs, so we set tab_root using just %.
+      $items[$path . '/%menu_tail'] = $items[$path];
+      $items[$path . '/%menu_tail']['tab_root'] = 'search/' . $default_module . '/%';
+
+      // For the default module, set to the default local task, but only
+      // for the no-keywords path. If you set it for the with-keywords path,
+      // you end up with infinite recursion in menu_local_tasks().
+      if ($module == $default_module) {
+        $items[$path]['type'] = MENU_DEFAULT_LOCAL_TASK;
+      }
     }
   }
   return $items;
@@ -892,6 +918,11 @@
   // Add CSS
   drupal_add_css(drupal_get_path('module', 'search') . '/search.css', array('preprocess' => FALSE));
 
+  $type = _search_get_active_type($type);
+  if (!$type) {
+    form_set_error(NULL, t('All searching modules are disabled.'), 'error');
+    return $form;
+  }
   if (!$action) {
     $action = 'search/' . $type;
   }
@@ -921,6 +952,45 @@
 }
 
 /**
+ * Returns an active search type, using the supplied type if possible.
+ *
+ * @param $type
+ *   Type of search to try to use.
+ *
+ * @return
+ *   $type if that search module is currently active. If it is not currently
+ *   active, 'node' if that is an active search type. If neither $type nor
+ *   'node' works, the first active search module is chosen. FALSE is returned
+ *   if there are no active search modules.
+ */
+function _search_get_active_type($type = NULL) {
+  $search_hooks = search_get_info();
+  $types = array();
+  foreach (variable_get('search_active_modules', array('node', 'user')) as $module) {
+    if (isset($search_hooks[$module])) {
+      $types[] = $module;
+    }
+  }
+
+  if (!count($types)) {
+    return FALSE;
+  }
+
+  // Try to use supplied type.
+  if (isset($type) && in_array($type, $types)) {
+    return $type;
+  }
+
+  // Try to use 'node'.
+  if (in_array('node', $types)) {
+    return 'node';
+  }
+
+  // Just use the first active search type.
+  return $types[0];
+}
+
+/**
  * Form builder; Output a search form for the search block's search box.
  *
  * @ingroup forms
@@ -954,7 +1024,8 @@
   }
 
   $form_id = $form['form_id']['#value'];
-  $form_state['redirect'] = 'search/node/' . trim($form_state['values'][$form_id]);
+  $type = _search_get_active_type('node');
+  $form_state['redirect'] = 'search/' . $type . '/' . trim($form_state['values'][$form_id]);
 }
 
 /**
@@ -988,6 +1059,7 @@
  * Perform a standard search on the given keys, and return the formatted results.
  */
 function search_data($keys = NULL, $type = 'node') {
+  $type = _search_get_active_type($type);
 
   if (isset($keys)) {
     if (module_hook($type, 'search_execute')) {
Index: modules/search/search.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.pages.inc,v
retrieving revision 1.18
diff -u -r1.18 search.pages.inc
--- modules/search/search.pages.inc	13 Apr 2010 15:23:03 -0000	1.18
+++ modules/search/search.pages.inc	15 Apr 2010 21:20:38 -0000
@@ -9,16 +9,15 @@
 /**
  * Menu callback; presents the search form and/or search results.
  */
-function search_view($type = 'node') {
+function search_view($type = NULL) {
   // Search form submits with POST but redirects to GET. This way we can keep
   // the search query URL clean as a whistle:
   // search/type/keyword+keyword
   if (!isset($_POST['form_id'])) {
-    if ($type == '') {
-      // Note: search/node can not be a default tab because it would take on the
-      // path of its parent (search). It would prevent remembering keywords when
-      // switching tabs. This is why we drupal_goto to it from the parent instead.
-      drupal_goto('search/node');
+    $activetype = _search_get_active_type($type);
+    if (!$activetype) {
+      drupal_set_message(t('No search modules are currently enabled.'), 'error');
+      return '';
     }
 
     $keys = search_get_keys();
@@ -131,10 +130,9 @@
   $keys = $form_state['values']['processed_keys'];
   if ($keys == '') {
     form_set_error('keys', t('Please enter some keywords.'));
-    // Fall through to the drupal_goto() call.
+    // Fall through to the redirect.
   }
 
-  $type = $form_state['values']['module'] ? $form_state['values']['module'] : 'node';
   $form_state['redirect'] = $form_state['action'] . '/' . $keys;
   return;
 }
