? files
? menu_update_25.patch
? menu_update_26.patch
? sites/default/settings.php
Index: includes/install.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/install.inc,v
retrieving revision 1.43
diff -u -p -r1.43 install.inc
--- includes/install.inc	22 Aug 2007 08:36:34 -0000	1.43
+++ includes/install.inc	28 Aug 2007 15:25:22 -0000
@@ -354,6 +354,32 @@ function drupal_install_modules($module_
 function drupal_uninstall_module($module) {
   module_load_install($module);
   module_invoke($module, 'uninstall');
+  
+  // Remove menu links for paths declared by this module.
+  drupal_load('module', $module);
+  $paths = module_invoke($module, 'menu');
+  if (!empty($paths)) {
+    $paths = array_keys($paths);
+    // Clean out the names of load functions.
+    foreach($paths as $index => $path) {
+      $parts = explode('/', $path, MENU_MAX_PARTS);
+      foreach ($parts as $k => $part) {
+        if (preg_match('/^%[a-z_]*$/', $part)) {
+          $parts[$k] = '%';
+        }
+      }
+      $paths[$index] = implode('/', $parts);
+    }
+    $placeholders = implode(', ', array_fill(0, count($paths), "'%s'"));
+    
+    $result = db_query('SELECT * FROM {menu_links} WHERE router_path IN ('. $placeholders .') AND external = 0 ORDER BY depth DESC', $paths);
+    // Remove all such items. Starting from those with the greatest depth will
+    // minimize the amount of re-parenting done by menu_link_delete().
+    while ($item = db_fetch_array($result)) {
+      _menu_delete_item($item, TRUE);
+    }
+  }
+
   drupal_set_installed_schema_version($module, SCHEMA_UNINSTALLED);
 }
 
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.201
diff -u -p -r1.201 menu.inc
--- includes/menu.inc	25 Aug 2007 10:29:18 -0000	1.201
+++ includes/menu.inc	28 Aug 2007 15:25:23 -0000
@@ -363,10 +363,10 @@ function _menu_load_objects($item, &$map
 function _menu_check_access(&$item, $map) {
   // Determine access callback, which will decide whether or not the current
   // user has access to this path.
-  $callback = trim($item['access_callback']);
+  $callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']);
   // Check for a TRUE or FALSE value.
   if (is_numeric($callback)) {
-    $item['access'] = $callback;
+    $item['access'] = (bool)$callback;
   }
   else {
     $arguments = menu_unserialize($item['access_arguments'], $map);
@@ -1457,13 +1457,12 @@ function _menu_navigation_links_rebuild(
       }
     }
   }
-  $placeholders = implode(', ', array_fill(0, count($menu), "'%s'"));
-  // Find any items where their router path does not exist any more.
-  $result = db_query('SELECT * FROM {menu_links} WHERE router_path NOT IN ('. $placeholders .') AND external = 0 ORDER BY depth DESC', array_keys($menu));
-  // Remove all such items. Starting from those with the greatest depth will
-  // minimize the amount of re-parenting done by menu_link_delete().
+  $result = db_query("SELECT ml.link_path, ml.mlid, ml.router_path FROM {menu_links} ml WHERE ml.updated = 1");
   while ($item = db_fetch_array($result)) {
-    _menu_delete_item($item, TRUE);
+    $router_path = _menu_find_router_path($menu, $item['link_path']);
+    if (!empty($router_path) && $router_path != $item['router_path']) {
+      db_query("UPDATE {menu_links} SET router_path = '%s' WHERE mlid = %d", $router_path, $item['mlid']);
+    }
   }
 }
 
@@ -1548,6 +1547,7 @@ function menu_link_save(&$item) {
     'options' => array(),
     'module' => 'menu',
     'customized' => 0,
+    'updated' => 0,
   );
   $menu_name = $item['menu_name'];
   $existing_item = FALSE;
@@ -1580,15 +1580,17 @@ function menu_link_save(&$item) {
        menu_name, plid, link_path,
       hidden, external, has_children,
       expanded, weight,
-      module, link_title, options, customized) VALUES (
+      module, link_title, options,
+      customized, updated) VALUES (
       '%s', %d, '%s',
       %d, %d, %d,
       %d, %d,
-      '%s', '%s', '%s', %d)",
+      '%s', '%s', '%s', %d, %d)",
       $item['menu_name'], $item['plid'], $item['link_path'],
       $item['hidden'], $item['_external'], $item['has_children'],
       $item['expanded'], $item['weight'],
-      $item['module'],  $item['link_title'], serialize($item['options']), $item['customized']);
+      $item['module'],  $item['link_title'], serialize($item['options']),
+      $item['customized'], $item['updated']);
     $item['mlid'] = db_last_insert_id('menu_links', 'mlid');
   }
 
@@ -1618,23 +1620,14 @@ function menu_link_save(&$item) {
     _menu_link_move_children($item, $existing_item);
   }
   // Find the callback.
-  if (empty($item['router_path']) || !$existing_item || ($existing_item['link_path'] != $item['link_path'])) {
+  if (!isset($_SESSION['system_update_6021']) && (empty($item['router_path'])  || !$existing_item || ($existing_item['link_path'] != $item['link_path']))) {
     if ($item['_external']) {
       $item['router_path'] = '';
     }
     else {
       // Find the router path which will serve this path.
       $item['parts'] = explode('/', $item['link_path'], MENU_MAX_PARTS);
-      $item['router_path'] = $item['link_path'];
-      if (!isset($menu[$item['router_path']])) {
-        list($ancestors) = menu_get_ancestors($item['parts']);
-        while ($ancestors && (empty($menu[$item['router_path']]))) {
-          $item['router_path'] = array_shift($ancestors);
-        }
-      }
-      if (empty($item['router_path'])) {
-        return FALSE;
-      }
+      $item['router_path'] = _menu_find_router_path($menu, $item['link_path']);
     }
   }
   db_query("UPDATE {menu_links} SET menu_name = '%s', plid = %d, link_path = '%s',
@@ -1663,6 +1656,21 @@ function menu_link_save(&$item) {
   return $item['mlid'];
 }
 
+function _menu_find_router_path($menu, $link_path) {
+  // Find the router path which will serve this path.
+  $parts = explode('/', $link_path, MENU_MAX_PARTS);
+  $router_path = $link_path;
+  if (!isset($menu[$router_path])) {
+    list($ancestors) = menu_get_ancestors($parts);
+    $ancestors[] = '';
+    while ($ancestors && (empty($menu[$router_path]))) {
+      $router_path = array_shift($ancestors);
+    }
+  }
+  return $router_path;
+}
+
+
 /**
  * Find the depth of an item's children relative to its depth.
  *
Index: modules/menu/menu.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v
retrieving revision 1.140
diff -u -p -r1.140 menu.module
--- modules/menu/menu.module	28 Aug 2007 13:16:36 -0000	1.140
+++ modules/menu/menu.module	28 Aug 2007 15:25:24 -0000
@@ -130,15 +130,17 @@ function menu_menu() {
 function menu_enable() {
   menu_rebuild();
   $result = db_query("SELECT * FROM {menu_custom}");
-  $link['module'] = 'menu';
-  $link['plid'] = db_result(db_query("SELECT mlid FROM {menu_links} WHERE link_path = '%s' AND module = '%s'", 'admin/build/menu', 'system'));
+  $link = db_fetch_array(db_query("SELECT mlid AS plid, menu_name from {menu_links} WHERE link_path = 'admin/build/menu' AND module = 'system'"));
   $link['router_path'] = 'admin/build/menu-customize/%';
-
+  $link['module'] = 'menu';
+  $result = db_query("SELECT * FROM {menu_custom}");
   while ($menu = db_fetch_array($result)) {
     $link['mlid'] = 0;
     $link['link_title'] = $menu['title'];
     $link['link_path'] = 'admin/build/menu-customize/'. $menu['menu_name'];
-    menu_link_save($link);
+    if (!db_result(db_query("SELECT mlid FROM {menu_links} WHERE link_path = '%s' AND plid = %d", $link['link_path'], $link['plid']))) {
+      menu_link_save($link);
+    }
   }
   menu_cache_clear_all();
 }
@@ -460,6 +462,7 @@ function menu_edit_menu(&$form_state, $t
     $form['menu_name'] = array(
       '#type' => 'textfield',
       '#title' => t('Menu name'),
+      '#maxsize' => 27,
       '#description' => t('The machine-readable name of this menu. This text will be used for constructing the URL of the <em>menu overview</em> page for this menu. This name may consist of only of lowercase letters, numbers, and hyphens, and must be unique.'),
       '#required' => TRUE,
     );
@@ -559,6 +562,9 @@ function menu_edit_menu_validate($form, 
   if (preg_match('/[^a-z0-9-]/', $item['menu_name'])) {
     form_set_error('menu_name', t('Menu name may consist only of lowercase letters, numbers, and hyphens.'));
   }
+  if (strlen($item['menu_name']) > 27) {
+    form_set_error('menu_name', t('Menu name can not be longer than 27 characters.'));
+  }
   if ($form['#insert']) {
     // We will add 'menu-' to the menu name to help avoid name-space conflicts.
     $item['menu_name'] = 'menu-'. $item['menu_name'];
Index: modules/menu/menu.schema
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.schema,v
retrieving revision 1.3
diff -u -p -r1.3 menu.schema
--- modules/menu/menu.schema	27 May 2007 20:31:13 -0000	1.3
+++ modules/menu/menu.schema	28 Aug 2007 15:25:24 -0000
@@ -4,7 +4,7 @@
 function menu_schema() {
   $schema['menu_custom'] = array(
     'fields' => array(
-      'menu_name'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'menu_name'   => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
       'title'       => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
       'description' => array('type' => 'text', 'not null' => FALSE),
     ),
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.5
diff -u -p -r1.5 system.admin.inc
--- modules/system/system.admin.inc	26 Aug 2007 16:41:02 -0000	1.5
+++ modules/system/system.admin.inc	28 Aug 2007 15:25:25 -0000
@@ -123,7 +123,7 @@ function system_settings_overview() {
 
 /**
  * Form builder; This function allows selection of the theme to show in administration sections.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  */
@@ -156,7 +156,7 @@ function system_admin_theme_settings() {
 
 /**
  * Menu callback; displays a listing of all themes.
- * 
+ *
  * @ingroup forms
  * @see system_themes_form_submt().
  */
@@ -280,7 +280,7 @@ function system_themes_form_submit($form
 
 /**
  * Form builder; display theme configuration for entire site and individual themes.
- * 
+ *
  * @ingroup forms
  * @see system_theme_settings_submit().
  */
@@ -675,7 +675,7 @@ function system_modules_disable($form, $
  *   elements: the list of dependencies and the list of status
  *   form field values from the previous screen.
  * @ingroup forms
- * @see 
+ * @see
  */
 function system_modules_confirm_form($modules, $storage) {
   $form = array();
@@ -989,7 +989,7 @@ function system_modules_uninstall_submit
 
 /**
  * Form builder; The general site information form.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  */
@@ -1047,7 +1047,7 @@ function system_site_information_setting
 
 /**
  * Form builder; Configure error reporting settings.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  */
@@ -1094,7 +1094,7 @@ function system_logging_overview() {
 
 /**
  * Form builder; Configure site performance settings.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  */
@@ -1197,7 +1197,7 @@ function system_performance_settings() {
 
 /**
  * Form builder; Configure the site file handling.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  */
@@ -1234,7 +1234,7 @@ function system_file_system_settings() {
 
 /**
  * Form builder; Configure site image toolkit usage.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  */
@@ -1259,7 +1259,7 @@ function system_image_toolkit_settings()
 
 /**
  * Form builder; Configure how the site handles RSS feeds.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  */
@@ -1285,7 +1285,7 @@ function system_rss_feeds_settings() {
 
 /**
  * Form builder; Configure the site date and time settings.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  * @see system_date_time_settings().
@@ -1455,7 +1455,7 @@ function system_date_time_lookup() {
 
 /**
  * Form builder; Configure the site's maintenance status.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  */
@@ -1481,7 +1481,7 @@ function system_site_maintenance_setting
 
 /**
  * Form builder; Configure Clean URL settings.
- * 
+ *
  * @ingroup forms
  * @see system_settings_form().
  */
@@ -1781,7 +1781,7 @@ function theme_system_admin_by_module($m
 
 /**
  * Theme status report
- * 
+ *
  * @ingroup themeable
  */
 function theme_status_report(&$requirements) {
@@ -1816,7 +1816,7 @@ function theme_status_report(&$requireme
 
 /**
  * Theme call back for the modules form.
- * 
+ *
  * @ingroup themeable
  */
 function theme_system_modules($form) {
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.141
diff -u -p -r1.141 system.install
--- modules/system/system.install	28 Aug 2007 11:42:56 -0000	1.141
+++ modules/system/system.install	28 Aug 2007 15:25:27 -0000
@@ -3262,6 +3262,9 @@ function system_update_6019() {
   return $ret;
 }
 
+/**
+ * Create the tables for the new menu system.
+ */
 function system_update_6020() {
   $ret = array();
 
@@ -3297,7 +3300,7 @@ function system_update_6020() {
 
   $schema['menu_links'] = array(
     'fields' => array(
-      'menu_name'    => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''),
+      'menu_name'    => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
       'mlid'         => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
       'plid'         => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'link_path'    => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
@@ -3321,6 +3324,7 @@ function system_update_6020() {
       'p7'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'p8'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'p9'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'updated'      => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
     ),
     'indexes' => array(
       'path_menu'              => array(array('link_path', 128), 'menu_name'),
@@ -3337,11 +3341,195 @@ function system_update_6020() {
   return $ret;
 }
 
+/**
+ * Migrate the menu items from the old menu ystem to the new menu_links table.
+ */
 function system_update_6021() {
-  $ret = array();
-  // TODO - menu module updates. These need to happen before we do the menu_rebuild
+  $ret = array('#finished' => 0);
+  // Multi-part update
+  if (!isset($_SESSION['system_update_6021'])) {
+    switch ($GLOBALS['db_type']) {
+      case 'mysql':
+      case 'mysqli':
+        update_sql('ALTER TABLE {menu} ADD converted tinyint unsigned default 0 NOT NULL');
+        break;
+      case 'pgsql':
+        db_add_column($ret, 'menu', 'converted', 'smallint', array('default' => 0, 'not null' => TRUE));
+        break;
+    }
+    $_SESSION['system_update_6021_max'] = db_result(db_query('SELECT COUNT(*) FROM {menu}'));
+    $_SESSION['menu_menu_map'] = array(1 => 'navigation');
+    // 0 => FALSE is for new menus, 1 => FALSE is for the navigation.
+    $_SESSION['menu_item_map'] = array(0 => FALSE, 1 => FALSE);
+    if ($secondary = variable_get('menu_secondary_menu', 0)) {
+      $_SESSION['menu_menu_map'][$secondary] = 'secondary-links';
+      $_SESSION['menu_item_map'][$secondary] = FALSE;
+    }
+    if ($primary = variable_get('menu_primary_menu', 0)) {
+      $_SESSION['menu_menu_map'][$primary] = 'primary-links';
+      $_SESSION['menu_item_map'][$primary] = FALSE;
+      if ($primary == $secondary) {
+        variable_set('menu_secondary_links_source', 'primary-links');
+      }
+    }
+    $table = array(
+      'fields' => array(
+        'menu_name'   => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
+        'title'       => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+        'description' => array('type' => 'text', 'not null' => FALSE),
+      ),
+      'primary key' => array('menu_name'),
+    );
+    db_create_table($ret, 'menu_custom', $table);
+    $menus = array(
+      'navigation' => array(
+        'menu_name' => 'navigation',
+        'title' => 'Navigation',
+        'description' => 'The navigation menu is provided by Drupal and is the main interactive menu for any site. It is usually the only menu that contains personalized links for authenticated users, and is often not even visible to anonymous users.',
+      ),
+      'primary-links' => array(
+        'menu_name' => 'primary-links',
+        'title' => 'Primary links',
+        'description' => 'Primary links are often used at the theme layer to show the major sections of a site. A typical representation for primary links would be tabs along the top.',
+      ),
+      'secondary-links' => array(
+        'menu_name' => 'secondary-links',
+        'title' => 'Secondary links',
+        'description' => 'Secondary links are often used for pages like legal notices, contact details, and other secondary navigation items that play a lesser role than primary links',
+      ),
+    );
+    // Save user-defined titles.
+    foreach (array($primary, $secondary) as $mid) {
+      if ($item = db_fetch_array(db_query('SELECT * FROM {menu} WHERE mid = %d', $mid))) {
+        $menus[$_SESSION['menu_menu_map'][$mid]]['title']  = $item['title'];
+      }
+    }
+    foreach ($menus as $menu) {
+      db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", $menu);
+    }
+    menu_rebuild();
+    $_SESSION['system_update_6021'] = 0;
+    // force page reload.
+    return $ret;
+  }
 
-  menu_rebuild();
+  $limit = 50;
+  while ($limit-- && ($item = db_fetch_array(db_query_range('SELECT * FROM {menu} WHERE converted = 0', 0, 1)))) {
+    // If it's not a menu...
+    if ($item['pid']) {
+      // Let's climb up until we find an item with a converted parent.
+      $item_original = $item;
+      while ($item && !isset($_SESSION['menu_item_map'][$item['pid']])) {
+        $item = db_fetch_array(db_query('SELECT * FROM {menu} WHERE mid = %d', $item['pid']));
+      }
+      // This can only occur if the menu entry is a leftover in the menu table.
+      // These do not appear in Drupal 5 anyways, so we skip them.
+      if (!$item) {
+        db_query('UPDATE {menu} SET converted = %d WHERE mid  = %d', 1, $item_original['mid']);
+        $_SESSION['system_update_6021']++;
+        continue;
+      }
+    }
+    // We need to recheck because item might have changed.
+    if ($item['pid']) {
+      // Fill the new fields.
+      $item['link_title'] = $item['title'];
+      $item['link_path'] = drupal_get_normal_path($item['path']);
+      // We know the parent is already set. If it's not FALSE then it's an item.
+      if ($_SESSION['menu_item_map'][$item['pid']]) {
+        // The new menu system parent link id.
+        $item['plid'] = $_SESSION['menu_item_map'][$item['pid']]['mlid'];
+        // The new menu system menu name.
+        $item['menu_name'] = $_SESSION['menu_item_map'][$item['pid']]['menu_name'];
+      }
+      else {
+        // This a top level element.
+        $item['plid'] = 0;
+        // The menu name is stored among the menus.
+        $item['menu_name'] = $_SESSION['menu_menu_map'][$item['pid']];
+      }
+      // Is the element visible in the menu block?
+      $item['hidden'] = !($item['type'] & MENU_VISIBLE_IN_TREE);
+      // Is it a custom(ized) element?
+      if ($item['type'] & (MENU_CREATED_BY_ADMIN | MENU_MODIFIED_BY_ADMIN)) {
+        $item['customized'] = TRUE;
+      }
+      // Items created via the menu module need to be assigned to it.
+      if ($item['type'] & MENU_CREATED_BY_ADMIN) {
+        $item['module'] = 'menu';
+      }
+      else {
+        $item['module'] = 'system';
+      }
+      $item['updated'] = TRUE;
+      // Save the link.
+      if ($existing_item = db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} WHERE link_path = '%s' AND plid = '%s' AND link_title = '%s' AND menu_name = '%s'", $item['link_path'], $item['plid'], $item['link_title'], $item['menu_name']))) {
+        $_SESSION['menu_item_map'][$item['mid']] = $existing_item;
+      }
+      else {
+        $item['router_path'] = '';
+        menu_link_save($item);
+        $_SESSION['menu_item_map'][$item['mid']] = array('mlid' => $item['mlid'], 'menu_name' => $item['menu_name']);
+      }
+
+    }
+    elseif (!isset($_SESSION['menu_menu_map'][$item['mid']])) {
+      $item['menu_name'] = 'menu-'. preg_replace('/[^a-zA-Z0-9]/' , '-', strtolower($item['title']));
+      $item['menu_name'] = substr($item['menu_name'], 0, 20);
+      $original_menu_name = $item['menu_name'];
+      $i = 0;
+      while (db_result(db_query("SELECT menu_name FROM {menu_custom} WHERE menu_name = '%s'", $item['menu_name']))) {
+        $item['menu_name'] = $original_menu_name . ($i++);
+      }
+      if ($item['path']) {
+        // Another bunch of bogus entries. Apparently, these are leftovers
+        // from Drupal 4.7 .
+        $_SESSION['menu_bogus_menus'][] = $item['menu_name'];
+      }
+      else {
+        // Add this menu to the list of custom menus.
+        db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '')", $item['menu_name'], $item['title']);
+      }
+      $_SESSION['menu_menu_map'][$item['mid']] = $item['menu_name'];
+      $_SESSION['menu_item_map'][$item['mid']] = FALSE;
+    }
+    db_query('UPDATE {menu} SET converted = %d WHERE mid  = %d', 1, $item['mid']);
+    $_SESSION['system_update_6021']++;
+  }
+
+  if ($_SESSION['system_update_6021'] >= $_SESSION['system_update_6021_max']) {
+    $result = db_query('SELECT * FROM {menu_links} WHERE updated = 1 AND has_children = 0 AND customized = 0 ORDER BY depth DESC');
+    // Remove all items that are not customized.
+    while ($item = db_fetch_array($result)) {
+      _menu_delete_item($item, TRUE);
+    }
+    if (!empty($_SESSION['menu_bogus_menus'])) {
+      // Remove entries in bogus menus. This is secure because we deleted
+      // every non-alpanumeric character from the menu name.
+      $ret[] = update_sql("DELETE FROM {menu_links} WHERE menu_name IN ('". implode("', '", $_SESSION['menu_bogus_menus']) ."')");
+    }
+    // Update menu OTF preferences.
+    $mid = variable_get('menu_parent_items', 0);
+    $menu_name = $mid ? $_SESSION['menu_menu_map'][$mid] : 'navigation';
+    variable_set('menu_default_node_menu', $menu_name);
+    // Skip the navigation menu - it is handled by the user module.
+    unset($_SESSION['menu_menu_map'][1]);
+    // Update the deltas for all menu module blocks.
+    foreach ($_SESSION['menu_menu_map'] as $mid => $menu_name) {
+      // This is again secure because we deleted every non-alpanumeric
+      // character from the menu name.
+      $ret[] = update_sql("UPDATE {blocks} SET delta = '". $menu_name ."' WHERE module  = 'menu' AND delta = '". $mid ."'");
+      $ret[] = update_sql("UPDATE {blocks_roles} SET delta = '". $menu_name ."' WHERE module  = 'menu' AND delta = '". $mid ."'");
+    }
+    $ret[] = array('success' => TRUE, 'query' => t('Relocated @num existing items to the new menu system.', array('@num' => $_SESSION['system_update_6021'])));
+    unset($_SESSION['system_update_6021'], $_SESSION['system_update_6021_max'], $_SESSION['menu_menu_map'], $_SESSION['menu_item_map'], $_SESSION['menu_bogus_menus']);
+    // Create the menu overview links - also calls menu_rebuild().
+    menu_enable();
+    $ret['#finished'] = 1;
+  }
+  else {
+    $ret['#finished'] = $_SESSION['system_update_6021'] / $_SESSION['system_update_6021_max'];
+  }
   return $ret;
 }
 
@@ -3538,7 +3726,7 @@ function system_update_6028() {
   return $ret;
 }
 
-/*
+/**
  * Enable the dblog module on sites that upgrade, since otherwise
  * watchdog logging will stop unexpectedly.
  */
Index: modules/system/system.schema
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.schema,v
retrieving revision 1.9
diff -u -p -r1.9 system.schema
--- modules/system/system.schema	11 Aug 2007 14:06:15 -0000	1.9
+++ modules/system/system.schema	28 Aug 2007 15:25:27 -0000
@@ -99,7 +99,7 @@ function system_schema() {
 
   $schema['menu_links'] = array(
     'fields' => array(
-      'menu_name'    => array('type' => 'varchar', 'length' => 64, 'not null' => TRUE, 'default' => ''),
+      'menu_name'    => array('type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => ''),
       'mlid'         => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
       'plid'         => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'link_path'    => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
@@ -123,6 +123,7 @@ function system_schema() {
       'p7'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'p8'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'p9'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'updated'      => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
     ),
     'indexes' => array(
       'path_menu'              => array(array('link_path', 128), 'menu_name'),
