Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.310
diff -u -p -r1.310 bootstrap.inc
--- includes/bootstrap.inc	16 Oct 2009 02:04:42 -0000	1.310
+++ includes/bootstrap.inc	16 Oct 2009 03:55:13 -0000
@@ -127,15 +127,10 @@ define('DRUPAL_BOOTSTRAP_PAGE_HEADER', 5
 define('DRUPAL_BOOTSTRAP_LANGUAGE', 6);
 
 /**
- * Eighth bootstrap phase: set $_GET['q'] to Drupal path of request.
- */
-define('DRUPAL_BOOTSTRAP_PATH', 7);
-
-/**
  * Final bootstrap phase: Drupal is fully loaded; validate and fix
  * input data.
  */
-define('DRUPAL_BOOTSTRAP_FULL', 8);
+define('DRUPAL_BOOTSTRAP_FULL', 7);
 
 /**
  * Role ID for anonymous users; should match what's in the "role" table.
@@ -1382,7 +1377,7 @@ function drupal_anonymous_user($session 
  *   function called from drupal_bootstrap (recursion).
  * @return
  *   The most recently completed phase.
- *   
+ *
  */
 function drupal_bootstrap($phase = NULL, $new_phase = TRUE) {
   $final_phase = &drupal_static(__FUNCTION__ . '_final_phase');
@@ -1399,7 +1394,6 @@ function drupal_bootstrap($phase = NULL,
     DRUPAL_BOOTSTRAP_SESSION,
     DRUPAL_BOOTSTRAP_PAGE_HEADER,
     DRUPAL_BOOTSTRAP_LANGUAGE,
-    DRUPAL_BOOTSTRAP_PATH,
     DRUPAL_BOOTSTRAP_FULL,
   ));
   $completed_phase = &drupal_static(__FUNCTION__ . '_completed_phase', -1);
@@ -1535,12 +1529,6 @@ function _drupal_bootstrap($phase) {
       drupal_language_initialize();
       break;
 
-    case DRUPAL_BOOTSTRAP_PATH:
-      require_once DRUPAL_ROOT . '/includes/path.inc';
-      // Initialize $_GET['q'] prior to loading modules and invoking hook_init().
-      drupal_path_initialize();
-      break;
-
     case DRUPAL_BOOTSTRAP_FULL:
       require_once DRUPAL_ROOT . '/includes/common.inc';
       _drupal_bootstrap_full();
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1021
diff -u -p -r1.1021 common.inc
--- includes/common.inc	15 Oct 2009 21:19:30 -0000	1.1021
+++ includes/common.inc	16 Oct 2009 03:55:14 -0000
@@ -2357,6 +2357,7 @@ function url($path = NULL, array $option
     'https' => FALSE,
     'prefix' => ''
   );
+
   if (!isset($options['external'])) {
     // Return an external link if $path contains an allowed absolute URL.
     // Only call the slow filter_xss_bad_protocol if $path contains a ':' before
@@ -2365,10 +2366,12 @@ function url($path = NULL, array $option
     $options['external'] = ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path));
   }
 
-  // May need language dependent rewriting if language.inc is present.
-  if (function_exists('language_url_rewrite')) {
-    language_url_rewrite($path, $options);
-  }
+  // Preserve the original path before altering or aliasing.
+  $original_path = $path;
+
+  // Allow other modules to alter the outbound URL and options.
+  drupal_alter('url_outbound', $path, $options);
+
   if ($options['fragment']) {
     $options['fragment'] = '#' . $options['fragment'];
   }
@@ -2417,21 +2420,16 @@ function url($path = NULL, array $option
     }
   }
 
-  // Preserve the original path before aliasing.
-  $original_path = $path;
-
   // The special path '<front>' links to the default front page.
   if ($path == '<front>') {
     $path = '';
   }
   elseif (!empty($path) && !$options['alias']) {
     $language = isset($options['language']) && isset($options['language']->language) ? $options['language']->language : '';
-    $path = drupal_get_path_alias($path, $language);
-  }
-
-  if (function_exists('custom_url_rewrite_outbound')) {
-    // Modules may alter outbound links by reference.
-    custom_url_rewrite_outbound($path, $options, $original_path);
+    $alias = drupal_get_path_alias($original_path, $language);
+    if ($alias != $original_path) {
+      $path = $alias;
+    }
   }
 
   $base = $options['absolute'] ? $options['base_url'] . '/' : base_path();
@@ -2595,7 +2593,7 @@ function l($text, $path, array $options 
  *
  * In order for page callbacks to be reusable in different delivery formats,
  * they should not issue any "print" or "echo" statements, but instead just
- * return content. 
+ * return content.
  *
  * @param $page_callback_result
  *   The result of a page callback. Can be one of:
@@ -2608,7 +2606,7 @@ function l($text, $path, array $options 
  *   to be appropriate for the page request as determined by the calling
  *   function (e.g., menu_execute_active_handler()). If not given, it is
  *   determined from the menu router information of the current page. In either
- *   case, modules have a final chance to alter which function is called. 
+ *   case, modules have a final chance to alter which function is called.
  *
  * @see menu_execute_active_handler()
  * @see hook_menu()
@@ -2655,7 +2653,7 @@ function drupal_deliver_html_page($page_
   // Menu status constants are integers; page content is a string or array.
   if (is_int($page_callback_result)) {
     // @todo: Break these up into separate functions?
-    switch ($page_callback_result) {   
+    switch ($page_callback_result) {
       case MENU_NOT_FOUND:
         // Print a 404 page.
         drupal_add_http_header('404 Not Found');
@@ -2719,7 +2717,7 @@ function drupal_deliver_html_page($page_
         drupal_add_http_header('503 Service unavailable');
         drupal_set_title(t('Site under maintenance'));
         print theme('maintenance_page', array('content' => filter_xss_admin(variable_get('maintenance_mode_message',
-          t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))))));    
+          t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))))));
         break;
     }
   }
@@ -4154,6 +4152,7 @@ function _drupal_bootstrap_full() {
     return;
   }
   $called = 1;
+  require_once DRUPAL_ROOT . '/includes/path.inc';
   require_once DRUPAL_ROOT . '/includes/theme.inc';
   require_once DRUPAL_ROOT . '/includes/pager.inc';
   require_once DRUPAL_ROOT . '/includes/menu.inc';
@@ -4187,6 +4186,8 @@ function _drupal_bootstrap_full() {
     ini_set('log_errors', 1);
     ini_set('error_log', file_directory_path() . '/error.log');
   }
+  // Initialize $_GET['q'] prior to invoking hook_init().
+  drupal_path_initialize();
   // Set a custom theme for the current page, if there is one. We need to run
   // this before invoking hook_init(), since any modules which initialize the
   // theme system will prevent a custom theme from being correctly set later.
@@ -6018,4 +6019,3 @@ function drupal_get_updaters() {
   }
   return $updaters;
 }
-
Index: includes/language.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/language.inc,v
retrieving revision 1.21
diff -u -p -r1.21 language.inc
--- includes/language.inc	16 Oct 2009 02:04:42 -0000	1.21
+++ includes/language.inc	16 Oct 2009 03:55:14 -0000
@@ -325,47 +325,6 @@ function language_from_default() {
 }
 
 /**
- * Rewrite URLs allowing modules to hook in.
- *
- * @param $path
- *   The path to rewrite.
- * @param $options
- *   An associative array of additional options as in url().
- */
-function language_url_rewrite(&$path, &$options) {
-  // Only modify relative (insite) URLs.
-  if (!$options['external']) {
-    static $callbacks;
-
-    if (!isset($callbacks)) {
-      $callbacks = array();
-
-      foreach (language_types_configurable() as $type) {
-        // Get url rewriter callbacks only from enabled language providers.
-        $negotiation = variable_get("language_negotiation_$type", array());
-
-        foreach ($negotiation as $id => $provider) {
-          if (isset($provider['file'])) {
-            require_once DRUPAL_ROOT . '/' . $provider['file'];
-          }
-
-          // Avoid duplicate callback entries.
-          if (isset($provider['callbacks']['url_rewrite'])) {
-            $callbacks[$provider['callbacks']['url_rewrite']] = NULL;
-          }
-        }
-      }
-
-      $callbacks = array_keys($callbacks);
-    }
-
-    foreach ($callbacks as $callback) {
-      $callback($path, $options);
-    }
-  }
-}
-
-/**
  * Split the given path into prefix and actual path.
  *
  * Parse the given path and return the language object identified by the
Index: includes/path.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/path.inc,v
retrieving revision 1.45
diff -u -p -r1.45 path.inc
--- includes/path.inc	15 Oct 2009 17:53:34 -0000	1.45
+++ includes/path.inc	16 Oct 2009 03:55:14 -0000
@@ -6,8 +6,8 @@
  * Functions to handle paths in Drupal, including path aliasing.
  *
  * These functions are not loaded for cached pages, but modules that need
- * to use them in hook_init() or hook exit() can make them available, by
- * executing "drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH);".
+ * to use them in hook_boot() or hook exit() can make them available, by
+ * executing "drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);".
  */
 
 /**
@@ -205,13 +205,23 @@ function drupal_get_path_alias($path = N
  */
 function drupal_get_normal_path($path, $path_language = '') {
   $result = $path;
+
+  // Lookup the path alias first.
   if ($source = drupal_lookup_path('source', $path, $path_language)) {
     $result = $source;
   }
-  if (function_exists('custom_url_rewrite_inbound')) {
-    // Modules may alter the inbound request path by reference.
-    custom_url_rewrite_inbound($result, $path, $path_language);
+
+  // Allow other modules to alter the inbound URL. We cannot use drupal_alter()
+  // here because we need to run hook_url_inbound_alter() in the reverse order
+  // of hook_url_outbound_alter().
+  $result_copy = $result;
+  foreach (array_reverse(module_implements('url_inbound_alter')) as $module) {
+    $function = $module . '_url_inbound_alter';
+    $function($result, $result_copy, $path_language);
   }
+
+  drupal_alter('url_inbound', $result, $result_copy, $path_language);
+
   return $result;
 }
 
@@ -347,7 +357,7 @@ function drupal_match_path($path, $patte
  * This function is not available in hook_boot() so use $_GET['q'] instead.
  * However, be careful when doing that because in the case of Example #3
  * $_GET['q'] will contain "path/alias". If "node/306" is needed, calling
- * drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH) makes this function available.
+ * drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL) makes this function available.
  *
  * @return
  *   The current Drupal URL path.
Index: modules/forum/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v
retrieving revision 1.524
diff -u -p -r1.524 forum.module
--- modules/forum/forum.module	15 Oct 2009 12:44:36 -0000	1.524
+++ modules/forum/forum.module	16 Oct 2009 03:55:15 -0000
@@ -115,12 +115,6 @@ function forum_menu() {
     'parent' => 'admin/structure/forum',
     'file' => 'forum.admin.inc',
   );
-  $items['admin/structure/forum/edit/%taxonomy_term'] = array(
-    'page callback' => 'forum_form_main',
-    'access arguments' => array('administer forums'),
-    'type' => MENU_CALLBACK,
-    'file' => 'forum.admin.inc',
-  );
   $items['admin/structure/forum/edit/container/%taxonomy_term'] = array(
     'title' => 'Edit container',
     'page callback' => 'forum_form_main',
@@ -610,7 +604,7 @@ function forum_block_view_pre_render($el
  */
 function forum_form($node, $form_state) {
   $type = node_type_get_type($node);
-  
+
   if (!empty($node->nid)) {
     $forum_terms = $node->taxonomy_forums;
     // If editing, give option to leave shadows
@@ -626,10 +620,15 @@ function forum_form($node, $form_state) 
 }
 
 /**
- * Implement hook_term_path().
+ * Implement hook_url_outbound_alter().
  */
-function forum_term_path($term) {
-  return 'forum/' . $term->tid;
+function forum_url_outbound_alter(&$path, &$options) {
+  if (preg_match('!^taxonomy/term/(\d+)!', $path, $matches)) {
+    $term = taxonomy_term_load($matches[1]);
+    if ($term && $term->vocabulary_machine_name == 'forums') {
+      $path = 'forum/' . $matches[1];
+    }
+  }
 }
 
 /**
Index: modules/forum/forum.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.test,v
retrieving revision 1.34
diff -u -p -r1.34 forum.test
--- modules/forum/forum.test	11 Oct 2009 03:07:18 -0000	1.34
+++ modules/forum/forum.test	16 Oct 2009 03:55:15 -0000
@@ -204,7 +204,7 @@ class ForumTestCase extends DrupalWebTes
   function deleteForum($tid) {
     // Delete the forum.
     $this->drupalPost('admin/structure/forum/edit/forum/' . $tid, array(), t('Delete'));
-    $this->drupalPost(NULL, NULL, t('Delete'));
+    $this->drupalPost(NULL, array(), t('Delete'));
 
     // Assert that the forum no longer exists.
     $this->drupalGet('forum/' . $tid);
Index: modules/locale/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v
retrieving revision 1.264
diff -u -p -r1.264 locale.module
--- modules/locale/locale.module	16 Oct 2009 02:04:42 -0000	1.264
+++ modules/locale/locale.module	16 Oct 2009 03:55:15 -0000
@@ -1067,3 +1067,40 @@ function locale_date_format_reset_form_s
   $form_state['redirect'] = 'admin/config/regional/date-time/locale';
 }
 
+/**
+ * Implement hook_url_outbound_alter().
+ *
+ * Rewrite outbound URLs with language based prefixes.
+ */
+function locale_url_outbound_alter(&$path, &$options) {
+  // Only modify relative (insite) URLs.
+  if (!$options['external']) {
+    static $callbacks;
+
+    if (!isset($callbacks)) {
+      $callbacks = array();
+
+      foreach (language_types_configurable() as $type) {
+        // Get url rewriter callbacks only from enabled language providers.
+        $negotiation = variable_get("language_negotiation_$type", array());
+
+        foreach ($negotiation as $id => $provider) {
+          if (isset($provider['file'])) {
+            require_once DRUPAL_ROOT . '/' . $provider['file'];
+          }
+
+          // Avoid duplicate callback entries.
+          if (isset($provider['callbacks']['url_rewrite'])) {
+            $callbacks[$provider['callbacks']['url_rewrite']] = NULL;
+          }
+        }
+      }
+
+      $callbacks = array_keys($callbacks);
+    }
+
+    foreach ($callbacks as $callback) {
+      $callback($path, $options);
+    }
+  }
+}
Index: modules/path/path.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.admin.inc,v
retrieving revision 1.34
diff -u -p -r1.34 path.admin.inc
--- modules/path/path.admin.inc	15 Oct 2009 17:53:34 -0000	1.34
+++ modules/path/path.admin.inc	16 Oct 2009 03:55:15 -0000
@@ -104,7 +104,7 @@ function path_admin_form($form, &$form_s
     '#default_value' => $path['source'],
     '#maxlength' => 255,
     '#size' => 45,
-    '#description' => t('Specify the existing path you wish to alias. For example: node/28, forum/1, taxonomy/term/1+2.'),
+    '#description' => t('Specify the existing path you wish to alias. For example: node/28, forum/1, taxonomy/term/1.'),
     '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
     '#required' => TRUE,
   );
@@ -149,7 +149,8 @@ function path_admin_form($form, &$form_s
  * Verify that a URL alias is valid
  */
 function path_admin_form_validate($form, &$form_state) {
-  $source = $form_state['values']['source'];
+  $source = &$form_state['values']['source'];
+  $source = drupal_get_normal_path($source);
   $alias = $form_state['values']['alias'];
   $pid = isset($form_state['values']['pid']) ? $form_state['values']['pid'] : 0;
   // Language is only set if locale module is enabled, otherwise save for all languages.
Index: modules/simpletest/tests/path.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/path.test,v
retrieving revision 1.1
diff -u -p -r1.1 path.test
--- modules/simpletest/tests/path.test	11 Sep 2009 02:19:02 -0000	1.1
+++ modules/simpletest/tests/path.test	16 Oct 2009 03:55:15 -0000
@@ -126,3 +126,111 @@ class DrupalMatchPathTestCase extends Dr
     );
   }
 }
+
+/**
+ * Tests hook_url_alter functions.
+ */
+class UrlAlterFunctionalTest extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => t('URL altering'),
+      'description' => t('Tests hook_url_inbound_alter() and hook_url_outbound_alter().'),
+      'group' => t('Path API'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('path', 'forum', 'url_alter_test');
+  }
+
+  /**
+   * Test that URL altering works and that it occurs in the correct order.
+   */
+  function testUrlAlter() {
+    $account = $this->drupalCreateUser(array('administer url aliases'));
+    $this->drupalLogin($account);
+
+    $uid = $account->uid;
+    $name = $account->name;
+
+    // Test single alter paths first.
+    $this->assertUrlInboundAlter("user/$name", "user/$uid");
+    $this->assertUrlOutboundAlter("user/$uid", "user/$name");
+
+    // Make sure a path with an alias always uses the alias.
+    path_save(array('source' => "user/$uid/test1", 'alias' => 'alias/test1'));
+    $this->assertUrlInboundAlter('alias/test1', "user/$uid/test1");
+    $this->assertUrlOutboundAlter("user/$uid/test1", 'alias/test1');
+
+    // Make sure aliases are saved with the normal path.
+    $edit = array('source' => "user/$name/edit", 'alias' => 'alias/test2');
+    $this->drupalPost('admin/config/search/path/add', $edit, t('Create new alias'));
+    $this->assertText(t('The alias has been saved.'));
+
+    // Test that a path always uses its alias.
+    $this->assertUrlInboundAlter('alias/test2', "user/$uid/edit");
+    $this->assertUrlOutboundAlter("user/$uid/edit", 'alias/test2');
+
+    // Test a non-existant user is not altered.
+    $uid++;
+    $this->assertUrlInboundAlter("user/$uid", "user/$uid");
+    $this->assertUrlOutboundAlter("user/$uid", "user/$uid");
+
+    // Test that 'forum' is altered to 'community' correctly.
+    $this->assertUrlInboundAlter('community', 'forum');
+    $this->assertUrlOutboundAlter('forum', 'community');
+
+    // Add a forum to test url altering.
+    $forum_vid = db_query("SELECT vid FROM {taxonomy_vocabulary} WHERE module = 'forum'")->fetchField();
+    $tid = db_insert('taxonomy_term_data')
+      ->fields(array(
+        'name' => $this->randomName(),
+        'vid' => $forum_vid,
+      ))
+      ->execute();
+
+    // Test that a existing forum URL is altered.
+    $this->assertUrlInboundAlter("community/$tid", "forum/$tid");
+    $this->assertUrlOutboundAlter("taxonomy/term/$tid", "community/$tid");
+
+    // Test that a non-existant forum URL is not altered.
+    $tid++;
+    $this->assertUrlInboundAlter("taxonomy/term/$tid", "taxonomy/term/$tid");
+    $this->assertUrlOutboundAlter("taxonomy/term/$tid", "taxonomy/term/$tid");
+  }
+
+  /**
+   * Assert that an outbound path is altered to an expected value.
+   *
+   * @param $original
+   *   A string with the original path that is run through url().
+   * @param $final
+   *   A string with the expected result after url().
+   * @return
+   *   TRUE if $original was correctly altered to $final, FALSE otherwise.
+   */
+  protected function assertUrlOutboundAlter($original, $final) {
+    // Test outbound altering.
+    $result = url($original);
+    $base_path = base_path() . (variable_get('clean_url', '0') ? '' : '?q=');
+    $result = substr($result, strlen($base_path));
+    $this->assertIdentical($result, $final, t('Altered outbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result)));
+  }
+
+  /**
+   * Assert that a inbound path is altered to an expected value.
+   *
+   * @param $original
+   *   A string with the aliased or un-normal path that is run through
+   *   drupal_get_normal_path().
+   * @param $final
+   *   A string with the expected result after url().
+   * @return
+   *   TRUE if $original was correctly altered to $final, FALSE otherwise.
+   */
+  protected function assertUrlInboundAlter($original, $final) {
+    // Test inbound altering.
+    $result = drupal_get_normal_path($original);
+    $this->assertIdentical($result, $final, t('Altered inbound URL %origianl, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result)));
+  }
+}
Index: modules/simpletest/tests/url_alter_test.info
===================================================================
RCS file: modules/simpletest/tests/url_alter_test.info
diff -N modules/simpletest/tests/url_alter_test.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/url_alter_test.info	16 Oct 2009 03:55:15 -0000
@@ -0,0 +1,9 @@
+; $Id$
+name = Url_alter tests
+description = A support modules for url_alter hook testing.
+core = 7.x
+package = Testing
+version = VERSION
+files[] = url_alter_test.module
+files[] = url_alter_test.install
+hidden = TRUE
Index: modules/simpletest/tests/url_alter_test.install
===================================================================
RCS file: modules/simpletest/tests/url_alter_test.install
diff -N modules/simpletest/tests/url_alter_test.install
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/url_alter_test.install	16 Oct 2009 03:55:15 -0000
@@ -0,0 +1,13 @@
+<?php
+// $Id$
+
+/**
+ * Impelement hook_install().
+ */
+function url_alter_test_install() {
+  // Set the weight of this module to one higher than forum.module.
+  db_update('system')
+    ->fields(array('weight' => 2))
+    ->condition('name', 'url_alter_test')
+    ->execute();
+}
Index: modules/simpletest/tests/url_alter_test.module
===================================================================
RCS file: modules/simpletest/tests/url_alter_test.module
diff -N modules/simpletest/tests/url_alter_test.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/url_alter_test.module	16 Oct 2009 03:55:15 -0000
@@ -0,0 +1,43 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Module to help test hook_url_inbound_alter() and hook_url_outbound_alter().
+ */
+
+/**
+ * Implement hook_url_inbound_alter().
+ */
+function url_alter_test_url_inbound_alter(&$path, $original_path, $path_language) {
+  // Rewrite user/username to user/uid.
+  if (preg_match('!^user/([^/]+)(/.*)?!', $path, $matches)) {
+    if ($account = user_load_by_name($matches[1])) {
+      $matches += array(2 => '');
+      $path = 'user/' . $account->uid . $matches[2];
+    }
+  }
+
+  // Rewrite community/ to forum/.
+  if ($path == 'community' || strpos($path, 'community/') === 0) {
+    $path = 'forum' . substr($path, 9);
+  }
+}
+
+/**
+ * Implement hook_url_outbound_alter().
+ */
+function url_alter_test_url_outbound_alter(&$path, &$options) {
+  // Rewrite user/uid to user/username.
+  if (preg_match('!^user/([0-9]+)(/.*)?!', $path, $matches)) {
+    if ($account = user_load($matches[1])) {
+      $matches += array(2 => '');
+      $path = 'user/' . $account->name . $matches[2];
+    }
+  }
+
+  // Rewrite forum/ to community/.
+  if ($path == 'forum' || strpos($path, 'forum/') === 0) {
+    $path = 'community' . substr($path, 5);
+  }
+}
Index: modules/statistics/statistics.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/statistics/statistics.module,v
retrieving revision 1.320
diff -u -p -r1.320 statistics.module
--- modules/statistics/statistics.module	5 Sep 2009 13:49:28 -0000	1.320
+++ modules/statistics/statistics.module	16 Oct 2009 03:55:15 -0000
@@ -45,7 +45,7 @@ function statistics_help($path, $arg) {
 function statistics_exit() {
   global $user;
 
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_PATH);
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 
   if (variable_get('statistics_count_content_views', 0)) {
     // We are counting content views.
Index: modules/system/system.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v
retrieving revision 1.91
diff -u -p -r1.91 system.api.php
--- modules/system/system.api.php	16 Oct 2009 03:01:54 -0000	1.91
+++ modules/system/system.api.php	16 Oct 2009 03:55:16 -0000
@@ -2316,7 +2316,7 @@ function hook_drupal_goto_alter(&$path, 
  *   the Drupal installation process that occurs after the installation profile
  *   is selected.
  * @param $install_state
- *   An array of information about the current installation state. 
+ *   An array of information about the current installation state.
  */
 function hook_install_tasks_alter(&$tasks, $install_state) {
   // Replace the "Choose language" installation task provided by Drupal core
@@ -2491,7 +2491,7 @@ function hook_date_format_types() {
  * module can define additional types that can be used when displaying dates. A
  * date type is a key which can be passed to format_date() to return a date in
  * the configured displayed format. A date format is a string defining the date
- * and time elements to use. For example, a date type could be 
+ * and time elements to use. For example, a date type could be
  * 'mymodule_extra_long', while a date format is like 'Y-m-d'.
  *
  * New date types must first be declared using hook_date_format_types(). It is
@@ -2519,7 +2519,7 @@ function hook_date_format_types() {
  *     'short', 'mymodule_extra_long'. It must first be declared in
  *     hook_date_format_types() unless extending a type provided by another
  *     module.
- *   - 'format': a string defining the date and time elements to use. It 
+ *   - 'format': a string defining the date and time elements to use. It
  *     can contain any of the formatting options described at
  *     http://php.net/manual/en/function.date.php
  *   - 'locales': (optional) an array of 2 and 5 character language codes, for
@@ -2637,5 +2637,77 @@ function hook_page_delivery_callback_alt
 }
 
 /**
+ * Alters inbound URL requests.
+ *
+ * @param $path
+ *   The path being constructed, which, if a path alias, has been resolved to a
+ *   Drupal path by the database, and which also may have been altered by other
+ *   modules before this one.
+ * @param $original_path
+ *   The original path, before being checked for path aliases or altered by the
+ *   modules.
+ * @param $path_language
+ *   The language of the path.
+ *
+ * @see drupal_get_normal_path()
+ */
+function hook_url_inbound_alter(&$path, $original_path, $path_language) {
+  // Change all node/[title]/edit paths to node/[nid]/edit.
+  if (preg_match('|^node(/.*)/edit|', $path, $matches)) {
+    $nodes = node_load_multiple(array(), array('title' => $matches[1]));
+    if (count($nodes) === 1) {
+      $node = array_shift($nodes);
+      $path = "node/$node->nid/edit";
+    }
+  }
+
+  // Create the path user/me/edit, which allows a user to edit their account.
+  if (preg_match('|^user/me/edit(/.*)?|', $path, $matches)) {
+    global $user;
+    $path = 'user/' . $user->uid . '/edit' . $matches[1];
+  }
+}
+
+/**
+ * Alters outbound URLs.
+ *
+ * @param $path
+ *   The outbound path to alter, not adjusted for path aliases yet. It won't be
+ *   adjusted for path aliases until all modules are finished altering it, thus
+ *   being consistent with hook_url_alter_inbound(), which adjusts for all path
+ *   aliases before allowing modules to alter it. This may have been altered by
+ *   other modules before this one.
+ * @param $options
+ *   A set of URL options for the URL so elements such as a fragment or a query
+ *   string can be added to the URL.
+ *
+ * @see url()
+ */
+function hook_url_outbound_alter(&$path, &$options) {
+  // Use an external RSS feed rather than the Drupal one.
+  if ($path == 'rss.xml') {
+    $path = 'http://example.com/rss.xml';
+    $options['external'] = TRUE;
+  }
+
+  // Instead of pointing to user/[uid]/edit, point to user/me/edit.
+  if (preg_match('|^user/([0-9]*)/edit(/.*)?|', $path, $matches)) {
+    global $user;
+    if ($user->uid == $matches[1]) {
+      $path = 'user/me/edit' . $matches[2];
+    }
+  }
+
+  // Change node/[nid]/edit paths to node/[title]/edit.
+  if (preg_match('|^node([0-9]*)/edit|', $path, $matches)) {
+    $node = node_load($matches[1]);
+    $nodes = node_load_multiple(array(), array('title' => $node->title));
+    if (count($nodes) === 1) {
+      $path = "node/$node->title/edit";
+    }
+  }
+}
+
+/**
  * @} End of "addtogroup hooks".
  */
Index: modules/taxonomy/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v
retrieving revision 1.523
diff -u -p -r1.523 taxonomy.module
--- modules/taxonomy/taxonomy.module	16 Oct 2009 03:21:23 -0000	1.523
+++ modules/taxonomy/taxonomy.module	16 Oct 2009 03:55:16 -0000
@@ -158,23 +158,6 @@ function taxonomy_theme() {
 }
 
 /**
- * For vocabularies not maintained by taxonomy.module, give the maintaining
- * module a chance to provide a path for terms in that vocabulary.
- *
- * @param $term
- *   A term object.
- * @return
- *   An internal Drupal path.
- */
-function taxonomy_term_path($term) {
-  $vocabulary = taxonomy_vocabulary_load($term->vid);
-  if ($vocabulary->module != 'taxonomy' && $path = module_invoke($vocabulary->module, 'term_path', $term)) {
-    return $path;
-  }
-  return 'taxonomy/term/' . $term->tid;
-}
-
-/**
  * Implement hook_menu().
  */
 function taxonomy_menu() {
@@ -1093,7 +1076,7 @@ function taxonomy_field_formatter_info()
  */
 function theme_field_formatter_taxonomy_term_link($variables) {
   $term = $variables['element']['#item']['taxonomy_term'];
-  return l($term->name, taxonomy_term_path($term));
+  return l($term->name, 'taxonomy/term/' . $term->tid, array('term' => $term));
 }
 
 /**
@@ -1494,4 +1477,3 @@ function taxonomy_taxonomy_term_delete($
 /**
  * @} End of "defgroup taxonomy indexing"
  */
-
Index: modules/taxonomy/taxonomy.pages.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.pages.inc,v
retrieving revision 1.40
diff -u -p -r1.40 taxonomy.pages.inc
--- modules/taxonomy/taxonomy.pages.inc	16 Oct 2009 03:21:23 -0000	1.40
+++ modules/taxonomy/taxonomy.pages.inc	16 Oct 2009 03:55:16 -0000
@@ -22,7 +22,7 @@ function taxonomy_term_page($term) {
   $breadcrumb = array();
   while ($parents = taxonomy_get_parents($current->tid)) {
     $current = array_shift($parents);
-    $breadcrumb[] = l($current->name, taxonomy_term_path($current));
+    $breadcrumb[] = l($current->name, 'taxonomy/term/' . $current->tid);
   }
   $breadcrumb[] = l(t('Home'), NULL);
   $breadcrumb = array_reverse($breadcrumb);
Index: modules/taxonomy/taxonomy.tokens.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.tokens.inc,v
retrieving revision 1.2
diff -u -p -r1.2 taxonomy.tokens.inc
--- modules/taxonomy/taxonomy.tokens.inc	18 Sep 2009 00:04:23 -0000	1.2
+++ modules/taxonomy/taxonomy.tokens.inc	16 Oct 2009 03:55:16 -0000
@@ -119,7 +119,7 @@ function taxonomy_tokens($type, $tokens,
           break;
 
         case 'url':
-          $replacements[$original] = url(taxonomy_term_path($term), array('absolute' => TRUE));
+          $replacements[$original] = url('taxonomy/term/' . $term, array('absolute' => TRUE));
           break;
 
         case 'node-count':
