Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.167
diff -u -p -r1.167 bootstrap.inc
--- includes/bootstrap.inc	25 May 2007 21:01:29 -0000	1.167
+++ includes/bootstrap.inc	29 May 2007 02:26:11 -0000
@@ -912,6 +912,7 @@ function _drupal_bootstrap($phase) {
       break;
 
     case DRUPAL_BOOTSTRAP_PATH:
+      require_once './modules/filter/filter.module';
       require_once './includes/path.inc';
       // Initialize $_GET['q'] prior to loading modules and invoking hook_init().
       drupal_init_path();
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.646
diff -u -p -r1.646 common.inc
--- includes/common.inc	27 May 2007 20:31:13 -0000	1.646
+++ includes/common.inc	29 May 2007 02:26:22 -0000
@@ -191,44 +191,6 @@ function drupal_get_feeds($delimiter = "
  */
 
 /**
- * Parse an array into a valid urlencoded query string.
- *
- * @param $query
- *   The array to be processed e.g. $_GET
- * @param $exclude
- *   The array filled with keys to be excluded. Use parent[child] to exclude nested items.
- * @param $urlencode
- *   If TRUE, the keys and values are both urlencoded.
- * @param $parent
- *   Should not be passed, only used in recursive calls
- * @return
- *   urlencoded string which can be appended to/as the URL query string
- */
-function drupal_query_string_encode($query, $exclude = array(), $parent = '') {
-  $params = array();
-
-  foreach ($query as $key => $value) {
-    $key = drupal_urlencode($key);
-    if ($parent) {
-      $key = $parent .'['. $key .']';
-    }
-
-    if (in_array($key, $exclude)) {
-      continue;
-    }
-
-    if (is_array($value)) {
-      $params[] = drupal_query_string_encode($value, $exclude, $key);
-    }
-    else {
-      $params[] = $key .'='. drupal_urlencode($value);
-    }
-  }
-
-  return implode('&', $params);
-}
-
-/**
  * Prepare a destination query string for use in combination with
  * drupal_goto(). Used to direct the user back to the referring page
  * after completing a form. By default the current URL is returned.
@@ -254,69 +216,6 @@ function drupal_get_destination() {
 }
 
 /**
- * Send the user to a different Drupal page.
- *
- * This issues an on-site HTTP redirect. The function makes sure the redirected
- * URL is formatted correctly.
- *
- * Usually the redirected URL is constructed from this function's input
- * parameters. However you may override that behavior by setting a
- * <em>destination</em> in either the $_REQUEST-array (i.e. by using
- * the query string of an URI) or the $_REQUEST['edit']-array (i.e. by
- * using a hidden form field). This is used to direct the user back to
- * the proper page after completing a form. For example, after editing
- * a post on the 'admin/content/node'-page or after having logged on using the
- * 'user login'-block in a sidebar. The function drupal_get_destination()
- * can be used to help set the destination URL.
- *
- * It is advised to use drupal_goto() instead of PHP's header(), because
- * drupal_goto() will append the user's session ID to the URI when PHP is
- * compiled with "--enable-trans-sid".
- *
- * This function ends the request; use it rather than a print theme('page')
- * statement in your menu callback.
- *
- * @param $path
- *   A Drupal path or a full URL.
- * @param $query
- *   The query string component, if any.
- * @param $fragment
- *   The destination fragment identifier (named anchor).
- * @param $http_response_code
- *   Valid values for an actual "goto" as per RFC 2616 section 10.3 are:
- *   - 301 Moved Permanently (the recommended value for most redirects)
- *   - 302 Found (default in Drupal and PHP, sometimes used for spamming search
- *         engines)
- *   - 303 See Other
- *   - 304 Not Modified
- *   - 305 Use Proxy
- *   - 307 Temporary Redirect (an alternative to "503 Site Down for Maintenance")
- *   Note: Other values are defined by RFC 2616, but are rarely used and poorly
- *         supported.
- * @see drupal_get_destination()
- */
-function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) {
-  if (isset($_REQUEST['destination'])) {
-    extract(parse_url(urldecode($_REQUEST['destination'])));
-  }
-  else if (isset($_REQUEST['edit']['destination'])) {
-    extract(parse_url(urldecode($_REQUEST['edit']['destination'])));
-  }
-
-  $url = url($path, array('query' => $query, 'fragment' => $fragment, 'absolute' => TRUE));
-
-  // Before the redirect, allow modules to react to the end of the page request.
-  module_invoke_all('exit', $url);
-
-  header('Location: '. $url, TRUE, $http_response_code);
-
-  // The "Location" header sends a REDIRECT status code to the http
-  // daemon. In some cases this can go wrong, so we make sure none
-  // of the code below the drupal_goto() call gets executed when we redirect.
-  exit();
-}
-
-/**
  * Generates a site off-line message
  */
 function drupal_site_offline() {
@@ -1132,122 +1031,6 @@ function format_date($timestamp, $type =
  */
 
 /**
- * Generate a URL from a Drupal menu path. Will also pass-through existing URLs.
- *
- * @param $path
- *   The Drupal path being linked to, such as "admin/content/node", or an existing URL
- *   like "http://drupal.org/".
- * @param $options
- *   An associative array of additional options, with the following keys:
- *     'query'
- *       A query string to append to the link, or an array of query key/value
- *       properties.
- *     'fragment'
- *       A fragment identifier (or named anchor) to append to the link.
- *       Do not include the '#' character.
- *     'absolute' (default FALSE)
- *       Whether to force the output to be an absolute link (beginning with
- *       http:). Useful for links that will be displayed outside the site, such
- *       as in an RSS feed.
- *     'alias' (default FALSE)
- *       Whether the given path is an alias already.
- * @return
- *   a string containing a URL to the given path.
- *
- * When creating links in modules, consider whether l() could be a better
- * alternative than url().
- */
-function url($path = NULL, $options = array()) {
-  // Merge in defaults
-  $options += array(
-      'fragment' => '',
-      'query' => '',
-      'absolute' => FALSE,
-      'alias' => FALSE,
-    );
-
-  // May need language dependant rewriting if language.inc is present
-  if (function_exists('language_url_rewrite')) {
-    language_url_rewrite($path, $options);
-  }
-  if ($options['fragment']) {
-    $options['fragment'] = '#'. $options['fragment'];
-  }
-  if (is_array($options['query'])) {
-    $options['query'] = drupal_query_string_encode($options['query']);
-  }
-
-  // Return an external link if $path contains an allowed absolute URL.
-  // Only call the slow filter_xss_bad_protocol if $path contains a ':' before any / ? or #.
-  $colonpos = strpos($path, ':');
-  if ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path)) {
-    // Split off the fragment
-    if (strpos($path, '#') !== FALSE) {
-      list($path, $old_fragment) = explode('#', $path, 2);
-      if (isset($old_fragment) && !$options['fragment']) {
-        $options['fragment'] = '#'. $old_fragment;
-      }
-    }
-    // Append the query
-    if ($options['query']) {
-      $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . $options['query'];
-    }
-    // Reassemble
-    return $path . $options['fragment'];
-  }
-
-  global $base_url;
-  static $script;
-  static $clean_url;
-
-  if (!isset($script)) {
-    // On some web servers, such as IIS, we can't omit "index.php". So, we
-    // generate "index.php?q=foo" instead of "?q=foo" on anything that is not
-    // Apache.
-    $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === FALSE) ? 'index.php' : '';
-  }
-
-  // Cache the clean_url variable to improve performance.
-  if (!isset($clean_url)) {
-    $clean_url = (bool)variable_get('clean_url', '0');
-  }
-
-  $base = $options['absolute'] ? $base_url .'/' : base_path();
-
-  // The special path '<front>' links to the default front page.
-  if (!empty($path) && $path != '<front>') {
-    if (!$options['alias']) {
-      $path = drupal_get_path_alias($path);
-    }
-    $path = drupal_urlencode($path);
-    if (!$clean_url) {
-      if ($options['query']) {
-        return $base . $script .'?q='. $path .'&'. $options['query'] . $options['fragment'];
-      }
-      else {
-        return $base . $script .'?q='. $path . $options['fragment'];
-      }
-    }
-    else {
-      if ($options['query']) {
-        return $base . $path .'?'. $options['query'] . $options['fragment'];
-      }
-      else {
-        return $base . $path . $options['fragment'];
-      }
-    }
-  }
-  else {
-    if ($options['query']) {
-      return $base . $script .'?'. $options['query'] . $options['fragment'];
-    }
-    else {
-      return $base . $options['fragment'];
-    }
-  }
-}
-
-/**
  * Format an attribute string to insert in a tag.
  *
  * @param $attributes
@@ -1795,34 +1578,6 @@ function drupal_to_js($var) {
 }
 
 /**
- * Wrapper around urlencode() which avoids Apache quirks.
- *
- * Should be used when placing arbitrary data in an URL. Note that Drupal paths
- * are urlencoded() when passed through url() and do not require urlencoding()
- * of individual components.
- *
- * Notes:
- * - For esthetic reasons, we do not escape slashes. This also avoids a 'feature'
- *   in Apache where it 404s on any path containing '%2F'.
- * - mod_rewrite's unescapes %-encoded ampersands and hashes when clean URLs
- *   are used, which are interpreted as delimiters by PHP. These characters are
- *   double escaped so PHP will still see the encoded version.
- *
- * @param $text
- *   String to encode
- */
-function drupal_urlencode($text) {
-  if (variable_get('clean_url', '0')) {
-    return str_replace(array('%2F', '%26', '%23'),
-                       array('/', '%2526', '%2523'),
-                       urlencode($text));
-  }
-  else {
-    return str_replace('%2F', '/', urlencode($text));
-  }
-}
-
-/**
  * Ensure the private key variable used to generate tokens is set.
  *
  * @return
Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.102
diff -u -p -r1.102 module.inc
--- includes/module.inc	25 May 2007 12:46:43 -0000	1.102
+++ includes/module.inc	29 May 2007 02:26:23 -0000
@@ -345,9 +345,11 @@ function module_implements($hook, $sort 
   if (!isset($implementations[$hook])) {
     $implementations[$hook] = array();
     $list = module_list(FALSE, TRUE, $sort);
-    foreach ($list as $module) {
-      if (module_hook($module, $hook)) {
-        $implementations[$hook][] = $module;
+    if (!empty($list)) {
+      foreach ($list as $module) {
+        if (module_hook($module, $hook)) {
+          $implementations[$hook][] = $module;
+        }
       }
     }
   }
Index: includes/path.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/path.inc,v
retrieving revision 1.15
diff -u -p -r1.15 path.inc
--- includes/path.inc	26 Mar 2007 01:32:22 -0000	1.15
+++ includes/path.inc	29 May 2007 02:26:26 -0000
@@ -11,14 +11,169 @@
  */
 
 /**
+ * @name HTTP handling
+ * @{
+ * Functions to properly handle HTTP responses.
+ */
+
+/**
+ * Send the user to a different Drupal page.
+ *
+ * This issues an on-site HTTP redirect. The function makes sure the redirected
+ * URL is formatted correctly.
+ *
+ * Usually the redirected URL is constructed from this function's input
+ * parameters. However you may override that behavior by setting a
+ * <em>destination</em> in either the $_REQUEST-array (i.e. by using
+ * the query string of an URI) or the $_REQUEST['edit']-array (i.e. by
+ * using a hidden form field). This is used to direct the user back to
+ * the proper page after completing a form. For example, after editing
+ * a post on the 'admin/content/node'-page or after having logged on using the
+ * 'user login'-block in a sidebar. The function drupal_get_destination()
+ * can be used to help set the destination URL.
+ *
+ * It is advised to use drupal_goto() instead of PHP's header(), because
+ * drupal_goto() will append the user's session ID to the URI when PHP is
+ * compiled with "--enable-trans-sid".
+ *
+ * This function ends the request; use it rather than a print theme('page')
+ * statement in your menu callback.
+ *
+ * @param $path
+ *   A Drupal path or a full URL.
+ * @param $query
+ *   The query string component, if any.
+ * @param $fragment
+ *   The destination fragment identifier (named anchor).
+ * @param $http_response_code
+ *   Valid values for an actual "goto" as per RFC 2616 section 10.3 are:
+ *   - 301 Moved Permanently (the recommended value for most redirects)
+ *   - 302 Found (default in Drupal and PHP, sometimes used for spamming search
+ *         engines)
+ *   - 303 See Other
+ *   - 304 Not Modified
+ *   - 305 Use Proxy
+ *   - 307 Temporary Redirect (an alternative to "503 Site Down for Maintenance")
+ *   Note: Other values are defined by RFC 2616, but are rarely used and poorly
+ *         supported.
+ * @see drupal_get_destination()
+ */
+function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) {
+  if (isset($_REQUEST['destination'])) {
+    extract(parse_url(urldecode($_REQUEST['destination'])));
+  }
+  else if (isset($_REQUEST['edit']['destination'])) {
+    extract(parse_url(urldecode($_REQUEST['edit']['destination'])));
+  }
+
+  $url = url($path, array('query' => $query, 'fragment' => $fragment, 'absolute' => TRUE));
+
+  // Before the redirect, allow modules to react to the end of the page request.
+  module_invoke_all('exit', $url);
+
+  header('Location: '. $url, TRUE, $http_response_code);
+
+  // The "Location" header sends a REDIRECT status code to the http
+  // daemon. In some cases this can go wrong, so we make sure none
+  // of the code below the drupal_goto() call gets executed when we redirect.
+  exit();
+}
+
+/**
+ * Parse an array into a valid urlencoded query string.
+ *
+ * @param $query
+ *   The array to be processed e.g. $_GET
+ * @param $exclude
+ *   The array filled with keys to be excluded. Use parent[child] to exclude nested items.
+ * @param $urlencode
+ *   If TRUE, the keys and values are both urlencoded.
+ * @param $parent
+ *   Should not be passed, only used in recursive calls
+ * @return
+ *   urlencoded string which can be appended to/as the URL query string
+ */
+function drupal_query_string_encode($query, $exclude = array(), $parent = '') {
+  $params = array();
+
+  foreach ($query as $key => $value) {
+    $key = drupal_urlencode($key);
+    if ($parent) {
+      $key = $parent .'['. $key .']';
+    }
+
+    if (in_array($key, $exclude)) {
+      continue;
+    }
+
+    if (is_array($value)) {
+      $params[] = drupal_query_string_encode($value, $exclude, $key);
+    }
+    else {
+      $params[] = $key .'='. drupal_urlencode($value);
+    }
+  }
+
+  return implode('&', $params);
+}
+/**
+ * @} End of "HTTP handling".
+ */
+
+/**
+ * Wrapper around urlencode() which avoids Apache quirks.
+ *
+ * Should be used when placing arbitrary data in an URL. Note that Drupal paths
+ * are urlencoded() when passed through url() and do not require urlencoding()
+ * of individual components.
+ *
+ * Notes:
+ * - For esthetic reasons, we do not escape slashes. This also avoids a 'feature'
+ *   in Apache where it 404s on any path containing '%2F'.
+ * - mod_rewrite's unescapes %-encoded ampersands and hashes when clean URLs
+ *   are used, which are interpreted as delimiters by PHP. These characters are
+ *   double escaped so PHP will still see the encoded version.
+ *
+ * @param $text
+ *   String to encode
+ */
+function drupal_urlencode($text) {
+  if (variable_get('clean_url', '0')) {
+    return str_replace(array('%2F', '%26', '%23'),
+                       array('/', '%2526', '%2523'),
+                       urlencode($text));
+  }
+  else {
+    return str_replace('%2F', '/', urlencode($text));
+  }
+}
+
+/**
  * Initialize the $_GET['q'] variable to the proper normal path.
  */
 function drupal_init_path() {
   if (!empty($_GET['q'])) {
-    $_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
+    $path = drupal_get_normal_path(trim($_GET['q'], '/'));
   }
   else {
     $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
+    return;
+  }
+
+  // Wipe the temporarily stored path information.
+  drupal_lookup_path('wipe');
+
+  $active_alias = drupal_get_path_alias($path, '', FALSE);
+  if ($_GET['q'] != $active_alias) {
+    $query = $_GET;
+    // Unset the drupal path query.
+    unset($query['q']);
+
+    // Redirect to the active alias.
+    drupal_goto($path, ($query ? $query : NULL), NULL, 301);
+  }
+  else {
+    $_GET['q'] = $path;
   }
 }
 
@@ -65,7 +220,7 @@ function drupal_lookup_path($action, $pa
         return $map[$path_language][$path];
       }
       // Get the most fitting result falling back with alias without language
-      $alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s' AND language IN('%s', '') ORDER BY language DESC", $path, $path_language));
+      $alias = db_result(db_query("SELECT dst FROM {url_alias} WHERE src = '%s' AND active = 1 AND language IN('%s', '') ORDER BY language DESC", $path, $path_language));
       $map[$path_language][$path] = $alias;
       return $alias;
     }
@@ -140,6 +295,122 @@ function drupal_get_normal_path($path, $
 }
 
 /**
+ * Generate a URL from a Drupal menu path. Will also pass-through existing URLs.
+ *
+ * @param $path
+ *   The Drupal path being linked to, such as "admin/content/node", or an existing URL
+ *   like "http://drupal.org/".
+ * @param $options
+ *   An associative array of additional options, with the following keys:
+ *     'query'
+ *       A query string to append to the link, or an array of query key/value
+ *       properties.
+ *     'fragment'
+ *       A fragment identifier (or named anchor) to append to the link.
+ *       Do not include the '#' character.
+ *     'absolute' (default FALSE)
+ *       Whether to force the output to be an absolute link (beginning with
+ *       http:). Useful for links that will be displayed outside the site, such
+ *       as in an RSS feed.
+ *     'alias' (default FALSE)
+ *       Whether the given path is an alias already.
+ * @return
+ *   a string containing a URL to the given path.
+ *
+ * When creating links in modules, consider whether l() could be a better
+ * alternative than url().
+ */
+function url($path = NULL, $options = array()) {
+  // Merge in defaults
+  $options += array(
+      'fragment' => '',
+      'query' => '',
+      'absolute' => FALSE,
+      'alias' => FALSE,
+    );
+
+  // May need language dependant rewriting if language.inc is present
+  if (function_exists('language_url_rewrite')) {
+    language_url_rewrite($path, $options);
+  }
+  if ($options['fragment']) {
+    $options['fragment'] = '#'. $options['fragment'];
+  }
+  if (is_array($options['query'])) {
+    $options['query'] = drupal_query_string_encode($options['query']);
+  }
+
+  // Return an external link if $path contains an allowed absolute URL.
+  // Only call the slow filter_xss_bad_protocol if $path contains a ':' before any / ? or #.
+  $colonpos = strpos($path, ':');
+  if ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path)) {
+    // Split off the fragment
+    if (strpos($path, '#') !== FALSE) {
+      list($path, $old_fragment) = explode('#', $path, 2);
+      if (isset($old_fragment) && !$options['fragment']) {
+        $options['fragment'] = '#'. $old_fragment;
+      }
+    }
+    // Append the query
+    if ($options['query']) {
+      $path .= (strpos($path, '?') !== FALSE ? '&' : '?') . $options['query'];
+    }
+    // Reassemble
+    return $path . $options['fragment'];
+  }
+
+  global $base_url;
+  static $script;
+  static $clean_url;
+
+  if (!isset($script)) {
+    // On some web servers, such as IIS, we can't omit "index.php". So, we
+    // generate "index.php?q=foo" instead of "?q=foo" on anything that is not
+    // Apache.
+    $script = (strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === FALSE) ? 'index.php' : '';
+  }
+
+  // Cache the clean_url variable to improve performance.
+  if (!isset($clean_url)) {
+    $clean_url = (bool)variable_get('clean_url', '0');
+  }
+
+  $base = $options['absolute'] ? $base_url .'/' : base_path();
+
+  // The special path '<front>' links to the default front page.
+  if (!empty($path) && $path != '<front>') {
+    if (!$options['alias']) {
+      $path = drupal_get_path_alias($path);
+    }
+    $path = drupal_urlencode($path);
+    if (!$clean_url) {
+      if ($options['query']) {
+        return $base . $script .'?q='. $path .'&'. $options['query'] . $options['fragment'];
+      }
+      else {
+        return $base . $script .'?q='. $path . $options['fragment'];
+      }
+    }
+    else {
+      if ($options['query']) {
+        return $base . $path .'?'. $options['query'] . $options['fragment'];
+      }
+      else {
+        return $base . $path . $options['fragment'];
+      }
+    }
+  }
+  else {
+    if ($options['query']) {
+      return $base . $script .'?'. $options['query'] . $options['fragment'];
+    }
+    else {
+      return $base . $options['fragment'];
+    }
+  }
+}
+
+/**
  * Return a component of the current Drupal path.
  *
  * When viewing a page at the path "admin/content/types", for example, arg(0)
Index: modules/locale/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.module,v
retrieving revision 1.175
diff -u -p -r1.175 locale.module
--- modules/locale/locale.module	28 May 2007 06:08:42 -0000	1.175
+++ modules/locale/locale.module	29 May 2007 02:26:30 -0000
@@ -224,6 +224,7 @@ function locale_form_alter(&$form, $form
         '#title' => t('Language'),
         '#options' => array('' => t('All languages')) + locale_language_list('name'),
         '#default_value' => $form['language']['#value'],
+        '#attributes' => $form['language']['#attributes'],
         '#weight' => -10,
         '#description' => t('Path aliases added for languages take precedence over path aliases added for all languages for the same Drupal path.'),
       );
Index: modules/path/path.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/path/path.module,v
retrieving revision 1.120
diff -u -p -r1.120 path.module
--- modules/path/path.module	28 May 2007 06:08:43 -0000	1.120
+++ modules/path/path.module	29 May 2007 02:26:33 -0000
@@ -34,6 +34,17 @@ function path_help($section) {
 }
 
 /**
+ * Implementation of hook_theme().
+ */
+function path_theme() {
+  return array(
+    'path_admin_edit' => array(
+      'arguments' => array('form' => NULL),
+    ),
+  );
+}
+
+/**
  * Implementation of hook_menu().
  */
 function path_menu() {
@@ -72,30 +83,216 @@ function path_menu() {
 }
 
 /**
- * Menu callback; handles pages for creating and editing URL aliases.
+ * Menu callback; returns form for creating and editing URL aliases.
  */
-function path_admin_edit($pid = 0) {
-  if ($pid) {
-    $alias = path_load($pid);
-    drupal_set_title(check_plain($alias['dst']));
-    $output = path_form($alias);
+function path_admin_edit() {
+  $args = func_get_args();
+  $language = (isset($args[0]) && $args[0] != 'all') ? $args[0] : '';
+
+  // Unset the first language argument.
+  unset($args[0]);
+
+  $src = implode('/', $args);
+  if (!empty($src)) {
+    $aliases = path_load('', $src, $language);
   }
   else {
-    $output = path_form();
+    $aliases = array();
   }
 
-  return $output;
+
+  $active_alias = 0;
+  $form = array();
+
+  $form['alias']['#tree'] = TRUE;
+  $form['alias'][0] = array(
+     '#type' => 'textfield',
+     '#title' => t('Existing system path'),
+     '#default_value' => $src,
+     '#maxlength' => 64,
+     '#size' => 45,
+     '#required' => TRUE,
+     '#description' => t('Specify the existing path you wish to alias. For example: node/28, forum/1, taxonomy/term/1+2.'),
+     '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
+  );
+  $options[0] = '';
+
+  if (!empty($aliases)) {
+    $add_form = FALSE;
+    $attributes= array('disabled' => 'disabled');
+    // Disable system path field when editing.
+    $form['alias'][0]['#attributes'] = $attributes;
+    $count = 1;
+    foreach ($aliases as $alias) {
+      if (!empty($alias['active'])) {
+        $active_alias = $alias['pid'];
+      }
+      $form['alias'][$alias['pid']] = array(
+        '#type' => 'textfield',
+        '#title' => t('Alias @number', array('@number' => ($count++))),
+        '#default_value' => $alias['dst'],
+        '#maxlength' => 64,
+        '#size' => 45,
+        '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
+      );
+      $options[$alias['pid']] = '';
+    }
+  }
+  else {
+    $attributes = array();
+    $add_form = TRUE;
+    // Select new path as active on add alias form.
+    $active_alias = -1;
+  }
+
+  $form['alias'][-1] = array(
+     '#type' => 'textfield',
+     '#title' => t('New alias'),
+     '#maxlength' => 64,
+     '#size' => 45,
+     '#required' => $add_form,
+     '#weight' => 1,
+     '#description' => t('Specify a new alternative path by which this data can be accessed. For example: about, faq, etc.'),
+     '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
+  );
+  $options[-1] = '';
+
+  $form['active'] = array(
+    '#type' => 'radios',
+    '#options' => $options,
+    '#required' => $add_form,
+    '#default_value' => $active_alias
+  );
+
+  // This will be a hidden value unless locale module is enabled
+  $form['language'] = array(
+    '#type' => 'value',
+    '#value' => $language,
+    '#attributes' => $attributes
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save')
+  );
+
+  if (!$add_form) {
+    $form['delete'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete all')
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Theme the path creating and editing form.
+ */
+function theme_path_admin_edit($form) {
+  $header = array(t('Active'), t('Alias'));
+  $rows = array();
+  foreach (element_children($form['alias']) as $key) {
+    $rows[] = array(
+      drupal_render($form['active'][$key]),
+      drupal_render($form['alias'][$key]),
+    );
+  }
+  $output = theme('table', $header, $rows);
+  $output .= drupal_render($form);
+  return $output;
+}
+
+/**
+ * Verify that URL aliases are valid.
+ */
+function path_admin_edit_validate($form, &$form_state, $form_values) {
+  $src = !empty($form_values['alias'][0]) ? $form_values['alias'][0] : NULL;
+
+  // Language is only set if locale module is enabled, otherwise save for all languages.
+  $language = isset($form_values['language']) ? $form_values['language'] : '';
+
+  if (isset($_POST['op']) && ($_POST['op'] == t('Delete all'))) {
+    $destination = '';
+    if (isset($_REQUEST['destination'])) {
+      $destination = drupal_get_destination();
+      unset($_REQUEST['destination']);
+    }
+    drupal_goto('admin/build/path/delete/'. (!empty($language) ? $language : 'all') .'/'. $src, $destination);
+    return;
+  }
+
+  $active = !empty($form_values['active']) ? $form_values['active'] : NULL;
+  if ($active == -1 && empty($form_values['alias'][$active])) {
+    form_set_error('alias][-1', t('You can not set an empty field as an active alias.'));
+  }
+
+  if (!empty($form_values['alias'])) {
+    foreach ($form_values['alias'] as $pid => $alias) {
+      if (empty($alias) && $active == $pid) {
+        form_set_error('alias]['. $pid, t('You can not set an empty field as an active alias.'));
+      }
+      if ($alias && db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE pid != %d AND dst = '%s' AND language = '%s'", $pid, $alias, $language))) {
+        form_set_error('alias]['. $pid, t('The alias %alias is already in use in this language.', array('%alias' => $alias)));
+      }
+    }
+  }
+}
+
+/**
+ * Save URL aliases to the database.
+ */
+function path_admin_edit_submit($form, &$form_state, $form_values) {
+  $src = !empty($form_values['alias'][0]) ? $form_values['alias'][0] : NULL;
+  $new = !empty($form_values['alias'][-1]) ? $form_values['alias'][-1] : NULL;
+
+  // Language is only set if locale module is enabled, otherwise save for all languages.
+  $language = isset($form_values['language']) ? $form_values['language'] : '';
+
+  unset($form_values['alias'][0], $form_values['alias'][-1]);
+  // Unset source and new alias, preparing a list of existing aliases.
+
+  if (!empty($form_values['alias'])) {
+    foreach ($form_values['alias'] as $pid => $alias) {
+      if (!empty($alias)) {
+        path_set_alias($src, $alias, $pid, ($pid == $form_values['active']), $language);
+      }
+      else {
+        path_delete('', $pid);
+      }
+    }
+    drupal_clear_path_cache();
+  }
+
+  if (!empty($new)) {
+    path_set_alias($src, $new, NULL, ($form_values['active'] == -1), $language);
+  }
+
+  menu_rebuild();
+  drupal_set_message(t('The aliases have been saved.'));
+
+  $form_state['redirect'] = 'admin/build/path';
+  return;
 }
 
 /**
  * Menu callback; confirms deleting an URL alias
  **/
-function path_admin_delete_confirm($pid) {
-  $path = path_load($pid);
+function path_admin_delete_confirm() {
+  $output = '';
+  $args = func_get_args();
+  $language = (isset($args[0]) && $args[0] != 'all') ? $args[0] : '';
+
+  // Unset the first language argument.
+  unset($args[0]);
+
+  $src = implode('/', $args);
+
   if (user_access('administer url aliases')) {
-    $form['pid'] = array('#type' => 'value', '#value' => $pid);
+    $form['src'] = array('#type' => 'value', '#value' => $src);
+    $form['language'] = array('#type' => 'value', '#value' => $language);
     $output = confirm_form($form,
-  t('Are you sure you want to delete path alias %title?', array('%title' => $path['dst'])),
+  t('Are you sure you want to delete path aliases for %title?', array('%title' => $src)),
    isset($_GET['destination']) ? $_GET['destination'] : 'admin/build/path', t('This action cannot be undone.'),
   t('Delete'), t('Cancel') );
   }
@@ -107,24 +304,17 @@ function path_admin_delete_confirm($pid)
  **/
 function path_admin_delete_confirm_submit($form, &$form_state, $form_values) {
   if ($form_values['confirm']) {
-    path_admin_delete($form_values['pid']);
+    path_set_alias($form_values['src'], NULL, NULL, NULL, $form_values['language']);
+    drupal_set_message(t('The aliases have been deleted.'));
     $form_state['redirect'] = 'admin/build/path';
     return;
   }
 }
 
 /**
- * Post-confirmation; delete an URL alias.
- */
-function path_admin_delete($pid = 0) {
-  db_query('DELETE FROM {url_alias} WHERE pid = %d', $pid);
-  drupal_set_message(t('The alias has been deleted.'));
-}
-
-/**
  * Set an aliased path for a given Drupal path, preventing duplicates.
  */
-function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $language = '') {
+function path_set_alias($path = NULL, $alias = NULL, $pid = NULL, $active = NULL, $language = '') {
   if ($path && !$alias) {
     // Delete based on path
     db_query("DELETE FROM {url_alias} WHERE src = '%s' AND language = '%s'", $path, $language);
@@ -143,13 +333,16 @@ function path_set_alias($path = NULL, $a
     $alias_count = db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE dst = '%s' AND language = '%s'", $alias, $language));
 
     if ($alias_count == 0) {
+      if ($active) {
+        db_query("UPDATE {url_alias} SET active = 0 WHERE src = '%s' AND language = '%s'", $path, $language);
+      }
       if ($pid) {
         // Existing path changed data
-        db_query("UPDATE {url_alias} SET src = '%s', dst = '%s', language = '%s' WHERE pid = %d", $path, $alias, $language, $pid);
+        db_query("UPDATE {url_alias} SET src = '%s', dst = '%s', active = %d, language = '%s' WHERE pid = %d", $path, $alias, $active, $language, $pid);
       }
       else {
         // No such alias yet in this language
-        db_query("INSERT INTO {url_alias} (src, dst, language) VALUES ('%s', '%s', '%s')", $path, $alias, $language);
+        db_query("INSERT INTO {url_alias} (src, dst, active, language) VALUES ('%s', '%s', %d, '%s')", $path, $alias, $active, $language);
       }
     }
     // The alias exists.
@@ -160,10 +353,8 @@ function path_set_alias($path = NULL, $a
       }
       else {
         // This will delete the path that alias was originally pointing to.
-        path_set_alias(NULL, $alias, NULL, $language);
-        // This will remove the current aliases of the path.
-        path_set_alias($path, NULL, NULL, $language);
-        path_set_alias($path, $alias, NULL, $language);
+        path_set_alias(NULL, $alias, NULL, $active, $language);
+        path_set_alias($path, $alias, NULL, $active, $language);
       }
     }
     if ($alias_count == 0 || $path_count == 0) {
@@ -173,48 +364,6 @@ function path_set_alias($path = NULL, $a
 }
 
 /**
- * Return a form for editing or creating an individual URL alias.
- */
-function path_form($edit = array('src' => '', 'dst' => '', 'language' => '', 'pid' => NULL)) {
-  $form['#submit'][] = 'path_form_submit';
-  $form['#validate'][] = 'path_form_validate';
-  $form['#alias'] = $edit;
-
-  $form['src'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Existing system path'),
-    '#default_value' => $edit['src'],
-    '#maxlength' => 64,
-    '#size' => 45,
-    '#description' => t('Specify the existing path you wish to alias. For example: node/28, forum/1, taxonomy/term/1+2.'),
-    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
-  );
-  $form['dst'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Path alias'),
-    '#default_value' => $edit['dst'],
-    '#maxlength' => 64,
-    '#size' => 45,
-    '#description' => t('Specify an alternative path by which this data can be accessed. For example, type "about" when writing an about page. Use a relative path and don\'t add a trailing slash or the URL alias won\'t work.'),
-    '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=')
-  );
-  // This will be a hidden value unless locale module is enabled
-  $form['language'] = array(
-    '#type' => 'value',
-    '#value' => $edit['language']
-  );
-  if ($edit['pid']) {
-    $form['pid'] = array('#type' => 'hidden', '#value' => $edit['pid']);
-    $form['submit'] = array('#type' => 'submit', '#value' => t('Update alias'));
-  }
-  else {
-    $form['submit'] = array('#type' => 'submit', '#value' => t('Create new alias'));
-  }
-
-  return $form;
-}
-
-/**
  * Implementation of hook_nodeapi().
  *
  * Allows URL aliases for nodes to be specified at node edit time rather
@@ -232,10 +381,11 @@ function path_nodeapi(&$node, $op, $arg)
         break;
 
       case 'load':
+        $language = !empty($node->language) ? $node->language : '';
         $path = "node/$node->nid";
         // We don't use drupal_get_path_alias() to avoid custom rewrite functions.
         // We only care about exact aliases.
-        $result = db_query("SELECT dst FROM {url_alias} WHERE src = '%s'", $path);
+        $result = db_query("SELECT dst FROM {url_alias} WHERE src = '%s' AND active = 1 AND language = '%s'", $path, $language);
         if (db_num_rows($result)) {
           $node->path = db_result($result);
         }
@@ -250,13 +400,19 @@ function path_nodeapi(&$node, $op, $arg)
         break;
 
       case 'update':
-        path_set_alias("node/$node->nid", isset($node->path) ? $node->path : NULL, isset($node->pid) ? $node->pid : NULL);
+        $pid = isset($node->pid) ? $node->pid : NULL;
+        if (!empty($node->path)) {
+          path_set_alias("node/$node->nid", $node->path, $pid);
+        }
+        else if (!empty($pid)) {
+         path_delete('', $pid);
+        }
         break;
 
       case 'delete':
         $path = "node/$node->nid";
         if (drupal_get_path_alias($path) != $path) {
-          path_set_alias($path);
+          path_delete($path);
         }
         break;
     }
@@ -307,7 +463,10 @@ function path_perm() {
  * When filter key passed, perform a standard search on the given key,
  * and return the list of matching URL aliases.
  */
-function path_admin_overview($keys = NULL) {
+function path_admin_overview() {
+  $args = func_get_args();
+  $keys = implode('/', $args);
+
   // Add the filter form above the overview table.
   $output = drupal_get_form('path_admin_filter_form', $keys);
   // Enable language column if locale is enabled or if we have any alias with language
@@ -337,7 +496,8 @@ function path_admin_overview($keys = NUL
   $rows = array();
   $destination = drupal_get_destination();
   while ($data = db_fetch_object($result)) {
-    $row = array(check_plain($data->dst), check_plain($data->src), l(t('edit'), "admin/build/path/edit/$data->pid", array('query' => $destination)), l(t('delete'), "admin/build/path/delete/$data->pid", array('query' => $destination)));
+    $language = !empty($data->language) ? $data->language : 'all' ;
+    $row = array(check_plain($data->dst), check_plain($data->src), l(t('edit'), "admin/build/path/edit/$language/$data->src", array('query' => $destination)), l(t('delete'), "admin/build/path/delete/$data->pid", array('query' => $destination)));
     if ($multilanguage) {
       $row[4] = $row[3];
       $row[3] = $row[2];
@@ -360,54 +520,55 @@ function path_admin_overview($keys = NUL
 /**
  * Fetch a specific URL alias from the database.
  */
-function path_load($pid) {
-  return db_fetch_array(db_query('SELECT * FROM {url_alias} WHERE pid = %d', $pid));
-}
+function path_load($pid, $src = '', $language = '') {
+  $output = '';
 
-/**
- * Verify that a new URL alias is valid
- */
-function path_form_validate($form, &$form_state, $form_values) {
-  $src = $form_values['src'];
-  $dst = $form_values['dst'];
-  $pid = isset($form_values['pid']) ? $form_values['pid'] : 0;
-  // Language is only set if locale module is enabled, otherwise save for all languages.
-  $language = isset($form_values['language']) ? $form_values['language'] : '';
-
-  if (db_result(db_query("SELECT COUNT(dst) FROM {url_alias} WHERE pid != %d AND dst = '%s' AND language = '%s'", $pid, $dst, $language))) {
-    form_set_error('dst', t('The alias %alias is already in use in this language.', array('%alias' => $dst)));
+  if (!empty($pid)) {
+    $output = db_fetch_array(db_query('SELECT * FROM {url_alias} WHERE pid = %d', $pid));
   }
+  else if (!empty($src)) {
+    $result = db_query("SELECT * FROM {url_alias} WHERE src = '%s' AND language = '%s' ORDER BY pid", $src, $language);
+    while ($row = db_fetch_array($result)) {
+      $output[] = $row;
+    }
+  }
+
+  return $output;
 }
 
-/**
- * Save a new URL alias to the database.
- */
-function path_form_submit($form, &$form_state, $form_values) {
-  // Language is only set if locale module is enabled
-  path_set_alias($form_values['src'], $form_values['dst'], isset($form_values['pid']) ? $form_values['pid'] : 0, isset($form_values['language']) ? $form_values['language'] : '');
+function path_delete($path = '', $pid = NULL) {
+  if (!empty($path)) {
+    // Delete based on source.
+    db_query("DELETE FROM {url_alias} WHERE src = '%s'", $src);
+  }
+  else if (!empty($pid)) {
+    // Delete based on alias id.
+    db_query("DELETE FROM {url_alias} WHERE pid = %d", $pid);
+  }
 
-  drupal_set_message(t('The alias has been saved.'));
-  $form_state['redirect'] = 'admin/build/path';
   return;
 }
 
 /**
  * Return a form to filter URL aliases.
  */
-function path_admin_filter_form($keys = '') {
+function path_admin_filter_form() {
+  $args = func_get_args();
+  $keys = implode('/', $args);
+
+  $form = array();
+
   $form['#attributes'] = array('class' => 'search-form');
-  $form['basic'] = array('#type' => 'fieldset',
-    '#title' => t('Filter aliases')
-  );
-  $form['basic']['inline'] = array('#prefix' => '<div class="container-inline">', '#suffix' => '</div>');
-  $form['basic']['inline']['filter'] = array(
+  $form['inline'] = array('#prefix' => '<div class="container-inline">', '#suffix' => '</div>');
+  $form['inline']['filter'] = array(
     '#type' => 'textfield',
-    '#title' => '',
+    '#title' => t('Filter aliases'),
     '#default_value' => $keys,
     '#maxlength' => 64,
     '#size' => 25,
   );
-  $form['basic']['inline']['submit'] = array('#type' => 'submit', '#value' => t('Filter'));
+  $form['inline']['submit'] = array('#type' => 'submit', '#value' => t('Filter'));
+  $form['#submit'][] = 'path_admin_filter_form_submit';
 
   return $form;
 }
@@ -418,13 +579,24 @@ function path_admin_filter_form($keys = 
 function path_admin_filter_form_submit($form_id, $form_values) {
   return 'admin/build/path/list/'. trim($form_values['filter']);
 }
-
-/**
- * Helper function for grabbing filter keys.
- */
-function path_admin_filter_get_keys() {
-  // Extract keys as remainder of path
-  $path = explode('/', $_GET['q'], 5);
-  return count($path) == 5 ? $path[4] : '';
+
+/**
+ * Implementation of hook_user.
+ */
+function path_user($op, $edit, $user) {
+  if ($op == 'delete') {
+    $path = "user/$user->uid";
+    path_delete($path);
+  }
+}
+
+/**
+ * Implementation of hook_comment.
+ */
+function path_comment($comment, $op) {
+  if ($op == 'delete') {
+    $path = "node/$comment->nid/$comment->cid";
+    path_delete($path);
+  }
 }
 
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.118
diff -u -p -r1.118 system.install
--- modules/system/system.install	27 May 2007 20:31:13 -0000	1.118
+++ modules/system/system.install	29 May 2007 02:26:49 -0000
@@ -3306,6 +3306,22 @@ function system_update_6021() {
   return $ret;
 }
 
+function system_update_6022() {
+  $ret = array();
+
+  switch ($GLOBALS['db_type']) {
+    case 'pgsql':
+    case 'mysql':
+    case 'mysqli':
+      if (db_table_exists('url_alias')) {
+        db_add_field($ret, 'url_alias', 'active', array('type' => 'int', 'not null' => TRUE, 'default' => 0));
+      }
+      break;
+  }
+
+  return $ret;
+}
+
 /**
  * @} End of "defgroup updates-5.x-to-6.x"
  * The next series of updates should start at 7000.
Index: modules/system/system.schema
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.schema,v
retrieving revision 1.3
diff -u -p -r1.3 system.schema
--- modules/system/system.schema	27 May 2007 20:31:13 -0000	1.3
+++ modules/system/system.schema	29 May 2007 02:26:50 -0000
@@ -181,6 +181,7 @@ function system_schema() {
       'pid'      => array('type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE),
       'src'      => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
       'dst'      => array('type' => 'varchar', 'length' => 128, 'not null' => TRUE, 'default' => ''),
+      'active'    => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
       'language' => array('type' => 'varchar', 'length' => 12, 'not null' => TRUE, 'default' => '')
     ),
     'unique keys' => array('dst_language' => array('dst', 'language')),
