Index: modules/menu/menu.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v
retrieving revision 1.116
diff -u -p -r1.116 menu.module
--- modules/menu/menu.module	6 Jun 2007 06:18:47 -0000	1.116
+++ modules/menu/menu.module	9 Jun 2007 02:31:47 -0000
@@ -187,7 +187,7 @@ function _menu_overview_tree($tree) {
         $operations[] = array('data' => l(t('delete'), 'admin/build/menu/item/delete/'. $item['mlid']));
       }
       // Set the reset column.
-      else if ($item['module'] == 'system') {
+      else if ($item['module'] == 'system' && $item['customized']) {
         $operations[] = array('data' => l(t('reset'), 'admin/build/menu/item/reset/'. $item['mlid']));
       }
       else {
@@ -242,23 +242,27 @@ function menu_edit_item(&$form_state, $t
   }
   else {
     // This is an add form.
-    // The mlid argument (if set) will be the default pid to use.
+    // The $id argument is the menu_name
     $item = array('mlid' => 0, 'plid' => 0, 'menu_name' => $id, 'weight' => 0, 'link_title' => '', 'link_path' => '', 'options' => array(), 'module' => 'menu', 'expanded' => 0, 'hidden' => 0, 'has_children' => 0);
   }
-  foreach (array('link_path', 'mlid', 'module', 'hidden', 'menu_name', 'has_children') as $key) {
-    $form[$key] = array('#type' => 'value', '#value' => $item[$key]);
+  foreach ($item as $key => $value) {
+    $form[$key] = array('#type' => 'value', '#value' => $value);
   }
+  // Any item created or edited via this interface is considered "customized".
+  $form['customized'] = array('#type' => 'value', '#value' => 1);
 
   $form['link_title'] = array('#type' => 'textfield',
-    '#title' => t('Title'),
+    '#title' => t('Menu link title'),
     '#default_value' => $item['link_title'],
-    '#description' => t('The name of the menu item.'),
+    '#description' => t('The link text corresponding to this item that should appear in the menu.'),
     '#required' => TRUE,
   );
   $form['description'] = array(
     '#type' => 'textarea',
     '#title' => t('Description'),
     '#default_value' => isset($item['options']['attributes']['title']) ? $item['options']['attributes']['title'] : '',
+    '#rows' => 1,
+    '#description' => t('The description displayed when hovering over a menu item.'),
   );
   if ($item['module'] == 'menu') {
     $form['link_path'] = array(
@@ -286,7 +290,7 @@ function menu_edit_item(&$form_state, $t
   );
 
   // Generate a list of possible parents (not including this item or descendants).
-  $options = menu_parent_options($item['mlid'], $item['menu_name']);
+  $options = menu_parent_options($item['menu_name'], $item);
   $form['plid'] = array(
     '#type' => 'select',
     '#title' => t('Parent item'),
@@ -319,6 +323,7 @@ function menu_edit_item_validate($form, 
  * Process menu and menu item add/edit form submissions.
  */
 function menu_edit_item_submit($form, &$form_state) {
+  $form_state['values']['options']['attributes']['title'] = $form_state['values']['description'];
   menu_link_save($form_state['values']);
   $form_state['redirect'] = 'admin/build/menu/'. $form_state['values']['menu_name'];
 }
@@ -327,59 +332,36 @@ function menu_edit_item_submit($form, &$
  * Return a list of menu items that are valid possible parents for the
  * given menu item. The list excludes the given item and its children.
  *
- * @param $mlid
- *   The menu item id for which to generate a list of parents.
- *   If $mlid == 0 then the complete tree is returned.
  * @param $menu_name
  *   The name of the menu.
- * @param $plid
- *   The menu link item id of the menu item at which to start the tree.
- *   If $pid > 0 then this item will be included in the tree.
- * @param $depth
- *   The current depth in the tree - used when recursing to indent the tree.
+ * @param $item
+ *   The menu item for which to generate a list of parents.
+ *   If $item['mlid'] == 0 or NULL then the complete tree is returned.
  * @return
- *   An array of menu titles keyed on the mlid.
+ *   An array of menu link titles keyed on the mlid.
  */
-function menu_parent_options($mlid, $menu_name, $plid = 0, $depth = 0) {
+function menu_parent_options($menu_name, $item) {
+
+  $tree = menu_tree_all_data($item['menu_name'], NULL, TRUE);
   $options = array(0 => t('Root'));
-  // Exclude $mlid and its children from the list unless $mlid is 0.
-  if ($mlid && $mlid == $plid) {
-    return $options;
-  }
+  _menu_parents_recurse($tree, '--', $options, $item['mlid']);
+
+  return $options;
+}
 
-  $sql = "SELECT * FROM {menu_links} ml LEFT JOIN {menu_router} mr ON ml.router_path = mr.path WHERE menu_name = '%s' AND hidden >= 0";
-  $params = array($menu_name);
-  if ($mlid && ($item = menu_link_load($mlid))) {
-    $parents = array();
-    for ($i = 1; $i <= 6; $i++) {
-      $key = "p$i";
-      $value = $item[$key];
-      if ($value) {
-        $parents[]= "$key != %d";
-        $params[] = $value;
+function _menu_parents_recurse($tree, $indent, &$options, $exclude) {
+  foreach ($tree as $data) {
+    if ($data['link']['mlid'] != $exclude) {
+      $title = $indent .' '. truncate_utf8($data['link']['title'], 30, TRUE, FALSE);
+      if ($data['link']['hidden']) {
+        $title .= ' ('. t('disabled') .')';
       }
-      else {
-        break;
+      $options[$data['link']['mlid']] = $title;
+      if ($data['below'] && $data['link']['depth'] < MENU_MAX_DEPTH - 1) {
+         _menu_parents_recurse($data['below'], $indent .'--', $options, $exclude);
       }
     }
-    $sql .= ' AND (' . implode(' OR ', $parents) .')';
-  }
-
-  $sql .= ' ORDER BY p1, p2, p3, p4, p5';
-  $result = db_query($sql, $params);
-
-  while ($item = db_fetch_array($result)) {
-    _menu_link_translate($item);
-    if (!$item['access']) {
-      continue;
-    }
-    $title = str_repeat('--', $item['depth']) .' '. $item['link_title'];
-    if ($item['hidden']) {
-      $title .= ' ('. t('disabled') .')';
-    }
-    $options[$item['mlid']] = $title;
   }
-  return $options;
 }
 
 /**
@@ -485,6 +467,7 @@ function menu_item_delete_form_submit($f
 function menu_reset_item(&$form_state, $mlid) {
   if (isset($mlid) && $item = db_fetch_array(db_query('SELECT router_path, link_title FROM {menu_links} WHERE mlid = %d', $mlid))) {
     $form['#router_path'] = $item['router_path'];
+    $form['mlid'] = array('#type' => 'value', '#value' => $mlid);
     return confirm_form($form, t('Are you sure you want to reset the item %item to its default values?', array('%item' => $item['link_title'])), 'admin/build/menu', t('Any customizations will be lost. This action cannot be undone.'), t('Reset'));
   }
   else {
@@ -497,6 +480,7 @@ function menu_reset_item(&$form_state, $
  */
 function menu_reset_item_submit($form, &$form_state) {
   $new_item = db_fetch_array(db_query("SELECT * FROM {menu_router} WHERE path = '%s'", $form['#router_path']));
+  $new_item['mlid'] = $form_state['values']['mlid'];
   menu_link_save(_menu_link_build($new_item));
   drupal_set_message(t('The menu item was reset to its default settings.'));
   $form_state['redirect'] = 'admin/build/menu/navigation';
@@ -527,7 +511,7 @@ function menu_block($op = 'list', $delta
 /**
  * Implementation of hook_nodeapi().
  */
-function menu_nodeapi($node, $op) {
+function menu_nodeapi(&$node, $op) {
   if (user_access('administer menu') && isset($node->menu)) {
     $item = $node->menu;
     switch ($op) {
@@ -536,16 +520,34 @@ function menu_nodeapi($node, $op) {
         // Deliberate no break.
       case 'insert':
       case 'update':
-        if ($item['delete']) {
-          _menu_delete_item($item);
+        if (!empty($item['delete'])) {
+          menu_link_delete($item['mlid']);
         }
-        else {
+        elseif (trim($item['link_title'])) {
+          $item['link_title'] = trim($item['link_title']);
           $item['link_path'] = "node/$node->nid";
+          if (!$item['customized']) {
+            $item['options']['attributes']['title'] = trim($node->title);
+          }
           menu_link_save($item);
         }
         break;
     }
   }
+  elseif ($op == 'prepare') {
+    if (empty($node->menu)) {
+      $menu_name = variable_get('menu_parent_items', 'navigation');
+      $item = array();
+      if (isset($node->nid)) {
+        $mlid = db_result(db_query("SELECT mlid FROM {menu_links} WHERE link_path = 'node/%d' AND menu_name = '%s' ORDER BY mlid ASC", $node->nid, $menu_name));
+        if ($mlid) {
+          $item = menu_link_load($mlid);
+        }
+      }
+      // Set default values
+      $node->menu = $item + array('mlid' => 0, 'plid' => 0, 'menu_name' => $menu_name, 'weight' => 0, 'link_title' => '', 'options' => array(), 'module' => 'menu', 'expanded' => 0, 'hidden' => 0, 'has_children' => 0);
+    }
+  }
 }
 
 /**
@@ -554,34 +556,57 @@ function menu_nodeapi($node, $op) {
  */
 function menu_form_alter(&$form, $form_state, $form_id) {
   if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
+
     $form['menu'] = array(
       '#type' => 'fieldset',
-      '#title' => t('Menu settings'),
+      '#title' => t('Menu settings for this post'),
       '#access' => user_access('administer menu'),
       '#collapsible' => TRUE,
       '#collapsed' => FALSE,
       '#tree' => TRUE,
-      '#weight' => 30,
+      '#weight' => -2,
     );
-    $form_state = array();
-    if ($mlid = db_result(db_query("SELECT mlid FROM {menu_links} WHERE link_path = 'node/%d' AND menu_name = '%s'", $form['nid']['#value'], variable_get('menu_parent_items', 'navigation')))) {
-      $menu_form = drupal_retrieve_form('menu_edit_item', $form_state, 'edit', $mlid);
-      $menu_form['delete'] = array(
+    $item = $form['#node']->menu;
+
+    if ($item['mlid']) {
+      // There is an existing link
+      $form['menu']['delete'] = array(
         '#type' => 'checkbox',
-        '#title' => t('Check to delete this menu item.'),
+        '#title' => t('Check to remove this item from the menu.'),
       );
     }
-    else {
-      $menu_form = drupal_retrieve_form('menu_edit_item', $form_state, 'add', variable_get('menu_parent_items', 'navigation'));
-      unset($menu_form['link_path']);
-      $menu_form['link_title']['#required'] = FALSE;
+    if (!$item['link_title']) {
       $form['menu']['#collapsed'] = TRUE;
     }
-    unset($menu_form['submit']);
-    $form['menu'] += $menu_form;
+
+    foreach ($item as $key => $value) {
+      $form['menu'][$key] = array('#type' => 'value', '#value' => $value);
+    }
+
+    $form['menu']['link_title'] = array('#type' => 'textfield',
+      '#title' => t('Menu link title'),
+      '#default_value' => $item['link_title'],
+      '#description' => t('The link text corresponding to this item that should appear in the menu.'),
+      '#required' => FALSE,
+    );
+    // Generate a list of possible parents (not including this item or descendants).
+    $options = menu_parent_options($item['menu_name'], $item);
+    $form['menu']['plid'] = array(
+      '#type' => 'select',
+      '#title' => t('Parent item'),
+      '#default_value' => $item['plid'],
+      '#options' => $options,
+    );
+    $form['menu']['weight'] = array(
+      '#type' => 'weight',
+      '#title' => t('Weight'),
+      '#default_value' => $item['weight'],
+      '#description' => t('Optional. In the menu, the heavier items will sink and the lighter items will be positioned nearer the top.'),
+    );
   }
 }
 
+
 function menu_get_menus($all = FALSE) {
   $sql = 'SELECT * FROM {menu_custom}'. ($all ? '' : " WHERE menu_name NOT IN ('navigation', 'primary-links', 'secondary-links')") . ' ORDER BY title';
   $result = db_query($sql);
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.121
diff -u -p -r1.121 system.install
--- modules/system/system.install	7 Jun 2007 03:44:13 -0000	1.121
+++ modules/system/system.install	9 Jun 2007 02:31:47 -0000
@@ -3288,24 +3288,161 @@ function system_update_6019() {
 function system_update_6020() {
   $ret = array();
 
-  $schema['menu_router'] = drupal_get_schema_unprocessed('system', 'menu_router');
-  $schema['menu_links'] = drupal_get_schema_unprocessed('system', 'menu_links');
+  $schema['menu_router'] = array(
+    'fields' => array(
+      'path'             => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'load_functions'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'to_arg_functions' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'access_callback'  => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'access_arguments' => array('type' => 'text', 'not null' => FALSE),
+      'page_callback'    => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'page_arguments'   => array('type' => 'text', 'not null' => FALSE),
+      'fit'              => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'number_parts'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
+      'tab_parent'       => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'tab_root'         => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'title'            => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'title_callback'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'title_arguments'  => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'type'             => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'block_callback'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'description'      => array('type' => 'text', 'not null' => TRUE),
+      'position'         => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'weight'           => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'file'             => array('type' => 'text', 'size' => 'medium')
+    ),
+    'indexes' => array(
+      'fit'        => array('fit'),
+      'tab_parent' => array('tab_parent')
+    ),
+    'primary key' => array('path'),
+  );
+
+  $schema['menu_links'] = array(
+    'fields' => array(
+      'menu_name'    => array('type' => 'varchar', 'length' => 64, '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' => ''),
+      'router_path'  => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'hidden'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
+      'external'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
+      'has_children' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
+      'expanded'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
+      'weight'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
+      'depth'        => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
+      'customized'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
+      'p1'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'p2'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'p3'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'p4'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'p5'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'p6'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+      'module'       => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => 'system'),
+      'link_title'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'options'      => array('type' => 'text', 'not null' => FALSE)
+    ),
+    'indexes' => array(
+      'expanded_children' => array('expanded', 'has_children'),
+      'menu_name_path' => array('menu_name', 'link_path'),
+      'plid'=> array('plid'),
+      'parents' => array('p1', 'p2', 'p3', 'p4', 'p5'),
+      'router_path' => array('router_path'),
+    ),
+    'primary key' => array('mlid'),
+  );
+
   _drupal_initialize_schema('system', $schema);
   $ret = array();
   foreach ($schema as $table) {
     db_create_table($ret, $table);
   }
+
   return $ret;
 }
 
 function system_update_6021() {
   $ret = array();
-  // TODO - menu module updates. These need to happen before we do the menu_rebuild
+  // We should die a horrible death here if this query fails.
+  $menu = unserialize(db_result(db_query("SELECT data FROM {cache_menu} WHERE cid LIKE '1:%%'")));
+  $new_menu = menu_router_build(TRUE);
+  if ($menu && module_exists('menu')) {
+    $items = $menu['items'];
+    drupal_install_schema('menu');
+    $menu_names = array();
+    $system_menus = array(
+      1 => 'navigation',
+      variable_get('menu_primary_menu', 2) => 'primary-links',
+      variable_get('menu_secondary_menu', 0) => 'secondary-links',
+    );
+    // These are the root menus.
+    foreach ($items[0]['children'] as $mid) {
+      $item = $items[$mid];
+      if (isset($system_menus[$mid])) {
+        $menu_name = $system_menus[$mid];
+      }
+      else {
+        $title = $item['title'];
+        $menu_name = preg_replace('[^a-z0-9]', '-', $title);
+        if (isset($menu_names[$menu_name])) {
+          $counter = 0;
+          while (isset($menu_names[$menu_name . ++$counter]));
+          $menu_name = $menu_name . $counter;
+        }
+        $description = db_result(db_query('SELECT description FROM {menu} WHERE mid = %d', $mid));
+        db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('%s', '%s', '%s')", $menu_name, $title, $description);
+      }
+      $menu_names[$menu_name] = $mid;
+      if (isset($item['children'])) {
+        foreach ($item['children'] as $child_mid) {
+          _system_update_6021($items, $menu_name, $child_mid);
+        }
+      }
+      menu_cache_clear($menu_name);
+    }
+    array_flip($menu_names);
+    $menu_parent_items = variable_get('menu_parent_items', NULL);
+    if (isset($menu_parent_items)) {
+      if ($menu_parent_items) {
+        variable_set('menu_parent_items', $menu_names[$menu_parent_items]);
+      }
+      else {
+        drupal_set_message(t('The menu name for on-the-fly creation of menu links has been set the navigation'), 'warning');
+        variable_set('menu_parent_items', 'navigation');
+      }
+    }
+  }
+  _menu_navigation_links_rebuild($new_menu);
 
-  menu_rebuild();
   return $ret;
 }
 
+function _system_update_6021($items, $menu_name, $mid) {
+  static $map;
+  $item = $items[$mid];
+  if ($item['type'] & MENU_VISIBLE_IN_BREADCRUMB) {
+    $item = _menu_link_build($item);
+    $item['menu_name'] = $menu_name;
+    $item['plid'] = isset($map[$item['pid']]) ? $map[$item['pid']] : 0;
+    if ($mid > 0) {
+      $item['description'] = db_result(db_query('SELECT description FROM {menu} WHERE mid = %d', $mid));
+      if ($item['type'] & MENU_CREATED_BY_ADMIN) {
+        $item['module'] = 'menu';
+      }
+      elseif ($item['type'] & MENU_MODIFIED_BY_ADMIN) {
+        $item['customized'] = TRUE;
+      }
+    }
+    $item['expanded'] = (bool)($item['type'] & 0x0100);
+    $map[$mid] = menu_link_save($item);
+  }
+  if (isset($item['children'])) {
+    foreach ($item['children'] as $child_mid) {
+      _system_update_6021($items, $menu_name, $child_mid);
+    }
+  }
+}
+
 /**
  * Update files tables to associate files to a uid by default instead of a nid.
  * Rename file_revisions to upload since it should only be used by the upload
Index: modules/system/system.schema
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.schema,v
retrieving revision 1.5
diff -u -p -r1.5 system.schema
--- modules/system/system.schema	5 Jun 2007 09:33:57 -0000	1.5
+++ modules/system/system.schema	9 Jun 2007 02:31:47 -0000
@@ -110,6 +110,7 @@ function system_schema() {
       'expanded'     => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
       'weight'       => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'depth'        => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
+      'customized'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'small'),
       'p1'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'p2'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
       'p3'           => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.177
diff -u -p -r1.177 menu.inc
--- includes/menu.inc	6 Jun 2007 06:26:15 -0000	1.177
+++ includes/menu.inc	9 Jun 2007 02:31:48 -0000
@@ -279,7 +279,7 @@ function menu_get_item($path = NULL) {
     list($ancestors, $placeholders) = menu_get_ancestors($parts);
 
     if ($router_item = db_fetch_array(db_query_range('SELECT * FROM {menu_router} WHERE path IN ('. implode (',', $placeholders) .') ORDER BY fit DESC', $ancestors, 0, 1))) {
-//var_dump($router_item);
+
       $map = _menu_translate($router_item, $original_map);
       if ($map === FALSE) {
         $router_items[$path] = FALSE;
@@ -633,7 +633,7 @@ function menu_tree_all_data($menu_name =
         $where .= ' AND ml.hidden = 0';
       }
       else {
-        $where .= ' AND ml.hidden > 0';
+        $where .= ' AND ml.hidden >= 0';
       }
       array_unshift($args, $menu_name);
       list(, $tree[$cid]) = _menu_tree_data(db_query("
@@ -1217,7 +1217,7 @@ function _menu_navigation_links_rebuild(
   foreach ($menu as $path => $item) {
     $item = _menu_link_build($item);
     // We add nonexisting items.
-    if ($item['_visible'] && !db_result(db_query("SELECT COUNT(*) FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $item['menu_name'], $item['link_path']))) {
+    if ($item['_visible']) {
       $menu_links[$path] = $item;
       $sort[$path] = $item['_number_parts'];
     }
@@ -1227,7 +1227,13 @@ function _menu_navigation_links_rebuild(
     array_multisort($sort, SORT_NUMERIC, $menu_links);
 
     foreach ($menu_links as $item) {
-      menu_link_save($item);
+      $existing_item = db_fetch_array(db_query("SELECT mlid, customized FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s' AND module = 'system'", $item['menu_name'], $item['link_path']));
+      if ($existing_item) {
+        $item['mlid'] = $existing_item['mlid'];
+      }
+      if (!$existing_item || !$existing_item['customized']) {
+        menu_link_save($item);
+      }
     }
   }
   $placeholders = implode(', ', array_fill(0, count($menu), "'%s'"));
@@ -1289,8 +1295,7 @@ function _menu_delete_item($item) {
  *     weight      default is 0
  *     expanded    whether the item is expanded.
  *     options     An array of options, @see l for more.
- *     mlid        If it's an existing item, this comes from the database.
- *                 Never set by hand.
+ *     mlid        Set to an existing value, or 0 or NULL to insert a new link.
  *     plid        The mlid of the parent.
  *     router_path The path of the relevant router item.
  */
@@ -1310,19 +1315,13 @@ function menu_link_save(&$item) {
     'expanded' => 0,
     'options' => array(),
     'module' => 'menu',
+    'customized' => 0,
   );
   $menu_name = $item['menu_name'];
   $existing_item = FALSE;
   if (isset($item['mlid'])) {
     $existing_item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE mlid = %d", $item['mlid']));
   }
-  else {
-    $existing_item = db_fetch_array(db_query("SELECT * FROM {menu_links} WHERE menu_name = '%s' AND link_path = '%s'", $menu_name, $item['link_path']));
-  }
-
-  if ($existing_item) {
-    $item['mlid'] = $existing_item['mlid'];
-  }
 
   // Find the parent - it must be in the same menu.
   if (isset($item['plid'])) {
@@ -1349,15 +1348,15 @@ function menu_link_save(&$item) {
        menu_name, plid, link_path,
       hidden, external, has_children,
       expanded, weight,
-      module, link_title, options) VALUES (
+      module, link_title, options, customized) VALUES (
       '%s', %d, '%s',
       %d, %d, %d,
       %d, %d,
-      '%s', '%s', '%s')",
+      '%s', '%s', '%s', %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['module'],  $item['link_title'], serialize($item['options']), $item['customized']);
     $item['mlid'] = db_last_insert_id('menu_links', 'mlid');
   }
 
@@ -1408,12 +1407,12 @@ function menu_link_save(&$item) {
     router_path = '%s', hidden = %d, external = %d, has_children = %d,
     expanded = %d, weight = %d,  depth = %d,
     p1 = %d, p2 = %d, p3 = %d, p4 = %d, p5 = %d, p6 = %d,
-    module = '%s', link_title = '%s', options = '%s' WHERE mlid = %d",
+    module = '%s', link_title = '%s', options = '%s', customized = %d WHERE mlid = %d",
     $item['menu_name'], $item['plid'], $item['link_path'],
     $item['router_path'], $item['hidden'], $item['_external'], $item['has_children'],
     $item['expanded'], $item['weight'],  $item['depth'],
     $item['p1'], $item['p2'], $item['p3'], $item['p4'], $item['p5'], $item['p6'],
-    $item['module'],  $item['link_title'], serialize($item['options']), $item['mlid']);
+    $item['module'],  $item['link_title'], serialize($item['options']), $item['customized'], $item['mlid']);
   // Check the has_children status of the parent.
   if ($item['plid']) {
     $parent_has_children = (bool)db_result(db_query("SELECT COUNT(*) FROM {menu_links} WHERE plid = %d AND hidden = 0", $item['plid']));
