Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.344
diff -u -p -r1.344 menu.inc
--- includes/menu.inc	11 Sep 2009 15:05:42 -0000	1.344
+++ includes/menu.inc	11 Sep 2009 16:32:41 -0000
@@ -2037,8 +2037,9 @@ function _menu_navigation_links_rebuild(
           $item['plid'] = $existing_item['plid'];
         }
         else {
-          // If it moved, put it at the top level in the new menu.
-          $item['plid'] = 0;
+          // It moved to a new menu, so let menu_link_save() try to find a
+          // valid parent based on path.
+          unset($item['plid']);
         }
         $item['has_children'] = $existing_item['has_children'];
         $item['updated'] = $existing_item['updated'];
@@ -2165,7 +2166,6 @@ function _menu_delete_item($item, $force
  *   saved.
  */
 function menu_link_save(&$item) {
-
   drupal_alter('menu_link', $item);
 
   // This is the easiest way to handle the unique internal path '<front>',
@@ -2191,14 +2191,11 @@ function menu_link_save(&$item) {
     }
   }
 
-  if (isset($item['plid'])) {
-    if ($item['plid']) {
-      $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['plid']))->fetchAssoc();
-    }
-    else {
-      // Don't bother with the query - mlid can never equal zero..
-      $parent = FALSE;
-    }
+  // The re-parenting process always needs to be invoked, since there is no
+  // guarantee that {menu_links} does not contain stale data caused by a
+  // re-parenting process that went wrong in a previous rebuild.
+  if (!empty($item['plid'])) {
+    $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['plid']))->fetchAssoc();
   }
   else {
     $query = db_select('menu_links');
@@ -2207,10 +2204,9 @@ function menu_link_save(&$item) {
     if ($item['module'] == 'system') {
       $query->condition('module', 'system');
     }
-    else {
-      // If not derived from a router item, we respect the specified menu name.
-      $query->condition('menu_name', $item['menu_name']);
-    }
+    // Always respect the link's menu name. Inheritance for router items is
+    // ensured in _menu_router_build().
+    $query->condition('menu_name', $item['menu_name']);
 
     // Find the parent - it must be unique.
     $parent_path = $item['link_path'];
@@ -2225,6 +2221,7 @@ function menu_link_save(&$item) {
       }
     } while ($parent === FALSE && $parent_path);
   }
+  // If a parent link was found, derive its menu.
   if ($parent !== FALSE) {
     $item['menu_name'] = $parent['menu_name'];
   }
@@ -2676,6 +2673,15 @@ function _menu_router_build($callbacks) 
 
         $parent = $menu[$parent_path];
 
+        // Try to inherit the menu name from parent router items.
+        if (!isset($item['menu_name'])) {
+          if (!isset($parent['menu_name'])) {
+            $parent['menu_name'] = db_query("SELECT menu_name FROM {menu_links} WHERE router_path = :router_path", array(':router_path' => $parent_path))->fetchColumn();
+          }
+          if (!empty($parent['menu_name'])) {
+            $item['menu_name'] = $parent['menu_name'];
+          }
+        }
         if (!isset($item['tab_parent'])) {
           // Parent stores the parent of the path.
           $item['tab_parent'] = $parent_path;
