=== modified file 'includes/menu.inc'
--- includes/menu.inc	2009-02-09 16:27:35 +0000
+++ includes/menu.inc	2009-02-23 01:12:44 +0000
@@ -350,14 +350,15 @@ function menu_set_item($path, $router_it
  *   filled in based on the database values and the objects loaded.
  */
 function menu_get_item($path = NULL, $router_item = NULL) {
-  static $router_items;
+  static $router_items, $in_call;
   if (!isset($path)) {
     $path = $_GET['q'];
   }
   if (isset($router_item)) {
     $router_items[$path] = $router_item;
   }
-  if (!isset($router_items[$path])) {
+  if (!isset($router_items[$path]) && !$in_call) {
+    $in_call = TRUE;
     $original_map = arg(NULL, $path);
     $parts = array_slice($original_map, 0, MENU_MAX_PARTS);
     $ancestors = menu_get_ancestors($parts);
@@ -379,8 +380,9 @@ function menu_get_item($path = NULL, $ro
       }
     }
     $router_items[$path] = $router_item;
+    $in_call = FALSE;
   }
-  return $router_items[$path];
+  return isset($router_items[$path]) ? $router_items[$path] : FALSE;
 }
 
 /**
@@ -536,9 +538,12 @@ function _menu_check_access(&$item, $map
 function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
   $callback = $item['title_callback'];
   $item['localized_options'] = $item['options'];
-  // If we are not doing link translation or if the title matches the
-  // link title of its router item, localize it.
-  if (!$link_translate || (!empty($item['title']) && ($item['title'] == $item['link_title']))) {
+  // If we are translating a router item, then we need to use the title
+  // callback. If we are translating a link title and its title is the same
+  // as its router item then we can use the title information from the router
+  // item. If its title is not the same as  the corresponding router item
+  // then we use the link title without change.
+  if (!$link_translate || ($item['title'] == $item['link_title'])) {
     // t() is a special case. Since it is used very close to all the time,
     // we handle it directly instead of using indirect, slower methods.
     if ($callback == 't') {
@@ -684,6 +689,7 @@ function menu_tail_to_arg($arg, $map, $i
  *   to $item['localized_options'] by _menu_item_localize().
  */
 function _menu_link_translate(&$item) {
+  global $menu_admin;
   $item['options'] = unserialize($item['options']);
   if ($item['external']) {
     $item['access'] = 1;
@@ -699,8 +705,16 @@ function _menu_link_translate(&$item) {
 
     // Note - skip callbacks without real values for their arguments.
     if (strpos($item['href'], '%') !== FALSE) {
-      $item['access'] = FALSE;
-      return FALSE;
+      if ($menu_admin) {
+        $item['access'] = TRUE;
+        $item['title'] = $item['link_title'];
+        $item['_no_link'] = TRUE;
+        return $map;
+      }
+      else {
+        $item['access'] = FALSE;
+        return FALSE;
+      }
     }
     // menu_tree_check_access() may set this ahead of time for links to nodes.
     if (!isset($item['access'])) {
@@ -751,7 +765,7 @@ function _menu_link_translate(&$item) {
  *   For node/%node, the position of %node is 1, but for comment/reply/%node,
  *   it's 2. Defaults to 1.
  * @param $path
- *   See menu_get_item() for more on this. Defaults to the current path.
+ *   @see menu_get_item() for more on this. Defaults to the current path.
  */
 function menu_get_object($type = 'node', $position = 1, $path = NULL) {
   $router_item = menu_get_item($path);
@@ -1736,7 +1750,8 @@ function menu_get_active_title() {
  *   A menu link, with $item['access'] filled and link translated for
  *   rendering.
  */
-function menu_link_load($mlid) {
+function menu_link_load($mlid, $is_menu_admin = FALSE) {
+  global $menu_admin;
   if (is_numeric($mlid)) {
     $query = db_select('menu_links', 'ml');
     $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
@@ -1744,7 +1759,9 @@ function menu_link_load($mlid) {
     $query->fields('m');
     $query->condition('ml.mlid', $mlid);
     if ($item = $query->execute()->fetchAssoc()) {
+      $menu_admin = $is_menu_admin;
       _menu_link_translate($item);
+      $menu_admin = FALSE;
       return $item;
     }
   }
@@ -2681,15 +2698,11 @@ function menu_valid_path($form_item) {
   if ($path == '<front>' || menu_path_is_external($path)) {
     $item = array('access' => TRUE);
   }
-  elseif (preg_match('/\/\%/', $path)) {
-    // Path is dynamic (ie 'user/%'), so check directly against menu_router table.
-    if ($item = db_query("SELECT * FROM {menu_router} where path = :path", array(':path' => $path))->fetchAssoc()) {
-      $item['link_path']  = $form_item['link_path'];
-      $item['link_title'] = $form_item['link_title'];
-      $item['external']   = FALSE;
-      $item['options'] = '';
-      _menu_link_translate($item);
-    }
+  // Path is dynamic (ie 'user/%'), so check directly against menu_router
+  // table. In the hope that on some page these will be accessible, we let
+  // them in.
+  elseif (preg_match('|/%|', $path) && ($item = db_fetch_array(db_query("SELECT * FROM {menu_router} where path = '%s' ", $path)))) {
+    $item['access'] = TRUE;
   }
   else {
     $item = menu_get_item($path);

=== modified file 'modules/aggregator/aggregator.module'
--- modules/aggregator/aggregator.module	2009-01-26 14:08:40 +0000
+++ modules/aggregator/aggregator.module	2009-02-23 00:18:25 +0000
@@ -553,6 +553,18 @@ function aggregator_refresh($feed) {
 }
 
 /**
+ * Change arguments of dynamic menu links.
+ */
+function aggregator_feed_to_arg($arg, $map, $index) {
+  // For dynamic links, we check whether we are on an aggregator feed page,
+  // and change the argument to the actual fid.
+  if ($arg == '%' && ($feed = menu_get_object('aggregator_feed', $index))) {
+    $arg = $feed->fid;
+  }
+  return $arg;
+}
+
+/**
  * Load an aggregator feed.
  *
  * @param $fid
@@ -570,6 +582,19 @@ function aggregator_feed_load($fid) {
 }
 
 /**
+ * Change arguments of dynamic menu links.
+ */
+function aggregator_category_to_arg($arg, $map, $index) {
+  // For dynamic links, we check whether we are on an aggregator feed page,
+  // and change the argument to the actual fid.
+  if ($arg == '%' && ($category = menu_get_object('aggregator_category', $index))) {
+    $arg = $category['cid'];
+  }
+  return $arg;
+}
+
+
+/**
  * Load an aggregator category.
  *
  * @param $cid

=== modified file 'modules/contact/contact.module'
--- modules/contact/contact.module	2008-10-09 15:15:49 +0000
+++ modules/contact/contact.module	2009-02-22 18:14:03 +0000
@@ -128,6 +128,18 @@ function _contact_user_tab_access($accou
 }
 
 /**
+ * Change arguments of dynamic menu links.
+ */
+function contact_to_arg($arg, $map, $index) {
+  // For dynamic links, we check if we are administering the site-wide contact
+  // form, change the argument to the current contact category id.
+  if ($arg == '%' && ($contact = menu_get_object('contact', $index))) {
+    $arg = $contact['cid'];
+  }
+  return $arg;
+}
+
+/**
  * Load the data for a single contact category.
  */
 function contact_load($cid) {

=== modified file 'modules/filter/filter.module'
--- modules/filter/filter.module	2009-01-21 16:58:41 +0000
+++ modules/filter/filter.module	2009-02-22 19:34:20 +0000
@@ -130,6 +130,18 @@ function filter_menu() {
   return $items;
 }
 
+/**
+ * Change arguments of dynamic menu links.
+ */
+function filter_format_to_arg($arg, $map, $index) {
+  // For dynamic links, we check if we are administering a filter format,
+  // change the argument to the current filter format id.
+  if ($arg == '%' && ($filter_format = menu_get_object('filter_format', $index))) {
+    $arg = $filter_format->fid;
+  }
+  return $arg;
+}
+
 function filter_format_load($arg) {
   return filter_formats($arg);
 }

=== modified file 'modules/forum/forum.module'
--- modules/forum/forum.module	2009-02-18 15:19:54 +0000
+++ modules/forum/forum.module	2009-02-23 00:21:41 +0000
@@ -65,6 +65,18 @@ function forum_theme() {
 }
 
 /**
+ * Change arguments of dynamic menu links.
+ */
+function forum_term_to_arg($arg, $map, $index) {
+  // For dynamic links, we check if we are administering a forum term, change
+  // the argument to the current forum term id.
+  if ($arg == '%' && ($forum_term = menu_get_object('forum_term', $index))) {
+    $arg = $forum_term->tid;
+  }
+  return $arg;
+}
+
+/**
  * Fetch a forum term.
  *
  * @param $tid

=== modified file 'modules/menu/menu.admin.inc'
--- modules/menu/menu.admin.inc	2009-02-03 18:55:29 +0000
+++ modules/menu/menu.admin.inc	2009-02-22 03:50:51 +0000
@@ -62,14 +62,17 @@ function menu_overview_form(&$form_state
 function _menu_overview_tree_form($tree) {
   static $form = array('#tree' => TRUE);
   foreach ($tree as $data) {
-    $title = '';
     $item = $data['link'];
     // Don't show callbacks; these have $item['hidden'] < 0.
     if ($item && $item['hidden'] >= 0) {
       $mlid = 'mlid:' . $item['mlid'];
       $form[$mlid]['#item'] = $item;
       $form[$mlid]['#attributes'] = $item['hidden'] ? array('class' => 'menu-disabled') : array('class' => 'menu-enabled');
-      $form[$mlid]['title']['#markup'] = l($item['title'], $item['href'], $item['localized_options']) . ($item['hidden'] ? ' (' . t('disabled') . ')' : '');
+      $title = empty($item['_no_link']) ? l($item['title'], $item['href'], $item['options']) : t('@title (dynamic)', array('@title' => $item['title']));
+      $form[$mlid]['title']['#markup'] = $title;
+      if ($item['hidden']) {
+        $form[$mlid]['title']['#markup'] .= ' ('. t('disabled') .')';
+      }
       $form[$mlid]['hidden'] = array(
         '#type' => 'checkbox',
         '#default_value' => !$item['hidden'],
@@ -375,7 +378,10 @@ function menu_edit_item_submit($form, &$
 
   $item['options']['attributes']['title'] = $item['description'];
   list($item['menu_name'], $item['plid']) = explode(':', $item['parent']);
-  if (!menu_link_save($item)) {
+  if (menu_link_save($item)) {
+    drupal_set_message(t('Your item was saved'));
+  }
+  else {
     drupal_set_message(t('There was an error saving the menu link.'), 'error');
   }
   $form_state['redirect'] = 'admin/build/menu-customize/' . $item['menu_name'];

=== modified file 'modules/menu/menu.module'
--- modules/menu/menu.module	2009-01-31 16:56:00 +0000
+++ modules/menu/menu.module	2009-02-22 19:35:45 +0000
@@ -115,6 +115,7 @@ function menu_menu() {
     'title' => 'Edit menu item',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('menu_edit_item', 'edit', 4, NULL),
+    'load arguments' => array(TRUE),
     'access arguments' => array('administer menu'),
     'type' => MENU_CALLBACK,
   );
@@ -122,6 +123,7 @@ function menu_menu() {
     'title' => 'Reset menu item',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('menu_reset_item_confirm', 4),
+    'load arguments' => array(TRUE),
     'access arguments' => array('administer menu'),
     'type' => MENU_CALLBACK,
   );
@@ -129,6 +131,7 @@ function menu_menu() {
     'title' => 'Delete menu item',
     'page callback' => 'menu_item_delete_page',
     'page arguments' => array(4),
+    'load arguments' => array(TRUE),
     'access arguments' => array('administer menu'),
     'type' => MENU_CALLBACK,
   );
@@ -179,6 +182,18 @@ function menu_overview_title($menu) {
 }
 
 /**
+ * Change arguments of dynamic menu links.
+ */
+function menu_to_arg($arg, $map, $index) {
+  // For dynamic links, we check if we are administering a custom menu, change
+  // the argument to the current menu name.
+  if ($arg == '%' && ($menu = menu_get_object('menu', $index))) {
+    $arg = $menu['menu_name'];
+  }
+  return $arg;
+}
+
+/**
  * Load the data for a single custom menu.
  */
 function menu_load($menu_name) {

=== modified file 'modules/menu/menu.test'
--- modules/menu/menu.test	2008-11-29 09:33:50 +0000
+++ modules/menu/menu.test	2009-02-22 17:50:36 +0000
@@ -18,7 +18,7 @@ class MenuTestCase extends DrupalWebTest
   function setUp() {
     parent::setUp('menu');
     // Create users.
-    $this->big_user = $this->drupalCreateUser(array('access administration pages', 'administer blocks', 'administer menu', 'create article content'));
+    $this->big_user = $this->drupalCreateUser(array('access administration pages', 'administer blocks', 'administer menu', 'create article content', 'edit own article content'));
     $this->std_user = $this->drupalCreateUser(array());
   }
 
@@ -143,6 +143,18 @@ class MenuTestCase extends DrupalWebTest
     // Add menu items.
     $item1 = $this->addMenuItem(0, 'node/' . $node1->nid, $menu_name);
     $item2 = $this->addMenuItem($item1['mlid'], 'node/' . $node2->nid, $menu_name);
+    $dynamic_item = $this->addMenuItem(0, 'node/%/edit');
+    $title = $dynamic_item['link_title'];
+    $this->assertText(t('@title (dynamic)', array('@title' => $title)), t('Dynamic text found'));
+    $this->assertNoRaw('href="node/%/edit"', t('Dynamic item is not a link'));
+    $this->drupalGet("node/$node1->nid");
+    file_put_contents('/tmp/log.htm', $this->content);
+    $urls = $this->xpath('//a[text()="' . $title . '"]');
+    $this->assertTrue($urls, t('link found'));
+    $this->assertTrue(strpos($urls[0]['href'], "node/$node1->nid/edit") !== FALSE, t('Dynamic link points to the correct url'));
+    $this->drupalGet("");
+    $urls = $this->xpath('//a[text()="' . $title . '"]');
+    $this->assertFalse($urls, t('link not found'));
 
     // Verify menu items.
     $this->verifyMenuItem($item1, $node1);

=== modified file 'modules/node/node.module'
--- modules/node/node.module	2009-02-18 15:19:54 +0000
+++ modules/node/node.module	2009-02-23 00:47:53 +0000
@@ -1675,6 +1675,18 @@ function _node_add_access() {
 }
 
 /**
+ * Change arguments of dynamic menu links.
+ */
+function node_to_arg($arg, $map, $index) {
+  // For dynamic links, we check whether we are on a node page, and change the
+  // argument to the actual nid.
+  if ($arg == '%' && ($node = menu_get_object('node', $index))) {
+    $arg = $node->nid;
+  }
+  return $arg;
+}
+
+/**
  * Implementation of hook_menu().
  */
 function node_menu() {
@@ -1946,7 +1958,7 @@ function node_feed($nids = FALSE, $chann
         $item->body = $content;
         unset($item->teaser);
       }
-    
+
       // Allow modules to modify the fully-built node.
       node_invoke_nodeapi($item, 'alter', $teaser, FALSE);
     }

=== modified file 'modules/taxonomy/taxonomy.module'
--- modules/taxonomy/taxonomy.module	2009-02-11 03:53:36 +0000
+++ modules/taxonomy/taxonomy.module	2009-02-22 19:36:01 +0000
@@ -70,7 +70,7 @@ function taxonomy_nodeapi_view($node) {
       }
     }
   }
-  
+
   $node->content['links']['terms'] = array(
     '#type' => 'node_links',
     '#value' => $links,
@@ -320,7 +320,7 @@ function taxonomy_term_save($term) {
     $status = drupal_write_record('taxonomy_term_data', $term);
     module_invoke_all('taxonomy_term_update', $term);
   }
-  
+
   $or = db_or()->condition('tid1', $term->tid)->condition('tid2', $term->tid);
   db_delete('taxonomy_term_relation')->condition($or)->execute();
 
@@ -968,6 +968,18 @@ function taxonomy_get_term_by_name($name
 }
 
 /**
+ * Change arguments of dynamic menu links.
+ */
+function taxonomy_vocabulary_to_arg($arg, $map, $index) {
+  // For dynamic links, we check if we are administering a vocabulary and
+  // change the argument to the current menu name.
+  if ($taxonomy_vocabulary = menu_get_object('taxonomy_vocabulary', $index)) {
+    $arg = $taxonomy_vocabulary->vid;
+  }
+  return $arg;
+}
+
+/**
  * Return the vocabulary object matching a vocabulary ID.
  *
  * @param $vid

=== modified file 'modules/user/user.module'
--- modules/user/user.module	2009-02-19 12:09:30 +0000
+++ modules/user/user.module	2009-02-23 01:13:51 +0000
@@ -1137,6 +1137,10 @@ function user_load_self($arg) {
   return $arg;
 }
 
+function user_category_to_arg($arg) {
+  return user_uid_optional_to_arg($arg);
+}
+
 /**
  * Implementation of hook_menu().
  */

