=== modified file 'includes/menu.inc'
--- includes/menu.inc	2007-02-14 16:43:38 +0000
+++ includes/menu.inc	2007-03-01 01:49:27 +0000
@@ -350,7 +350,7 @@ function menu_execute_active_handler() {
  *   with objects loaded where appropriate and the third is the path ready for
  *   printing.
  */
-function _menu_translate($item, $map, $operation = MENU_HANDLE_REQUEST) {
+function _menu_translate($item, $map, $operation = MENU_HANDLE_REQUEST, $access_check = TRUE) {
   $path = '';
 
   // Check if there are dynamic arguments in the path that need to be calculated.
@@ -376,7 +376,7 @@ function _menu_translate($item, $map, $o
         }
       }
       // We now have a real path regardless of operation, map it.
-      if ($load_function) {
+      if ($access_check && $load_function) {
         $return = $load_function(isset($path_map[$index]) ? $path_map[$index] : '');
         // If callback returned an error or there is no callback, trigger 404.
         if ($return === FALSE) {
@@ -393,7 +393,9 @@ function _menu_translate($item, $map, $o
   else {
     $path = $item->path;
   }
-
+  if (!$access_check) {
+    return array(TRUE, $map, $path);
+  }
   // Determine access callback, which will decide whether or not the current user has
   // access to this path.
   $callback = $item->access_callback;
@@ -415,33 +417,88 @@ function _menu_translate($item, $map, $o
  * Returns a rendered menu tree.
  */
 function menu_tree() {
+  global $user;
   if ($item = menu_get_item()) {
-    list(, $menu) = _menu_tree(db_query('SELECT * FROM {menu} WHERE pid IN ('. $item->parents .') AND visible = 1 ORDER BY vancode'));
+    if ($user->uid == 1) {
+      $result = db_query('SELECT *, 1 AS rid FROM {menu} WHERE pid IN ('. $item->parents .') AND visible = 1 ORDER BY mleft');
+    }
+    else {
+      $rids = array_keys($user->roles);
+      // rid 0 means that the item needs dynamic permissions.
+      $rids[] = 0;
+      $rids_string = implode(',', $rids);
+      // As only visible items have entires in menu_roles, there is no need for
+      // visible = 1 checking.
+      $result = db_query('SELECT m.*, MAX(rid) AS rid FROM {menu} m INNER JOIN {menu_roles_cache} mr ON m.mid = mr.mid WHERE mr.page_mid = %d AND mr.rid IN (%s) GROUP BY m.mid ORDER BY mleft', $item->mid, $rids_string);
+      if (!db_num_rows($result)) {
+        $menu_empty = variable_get('menu_empty', array());
+        $load_cache = FALSE;
+        foreach ($rids as $rid) {
+          $load_cache = $load_cache || empty($menu_empty[$item->mid][$rid]);
+        }
+        if ($load_cache) {
+          db_query('
+            INSERT INTO {menu_roles_cache} (page_mid, mid, rid)
+            SELECT %d, children.mid, mr.rid
+            FROM {menu} children
+            INNER JOIN {menu_roles} mr ON children.mid = mr.mid
+            WHERE NOT EXISTS
+              (SELECT 1 FROM {menu} parent
+              INNER JOIN {menu_roles} mr ON parent.mid = mr.mid
+              WHERE parent.mleft < children.mleft AND children.mright < parent.mright
+              LIMIT 1)
+              OR pid IN ('. $item->parents .')
+            ORDER BY mleft', $item->mid);
+        }
+        $result = db_query('SELECT m.*, MAX(rid) AS rid FROM {menu} m INNER JOIN {menu_roles_cache} mr ON m.mid = mr.mid WHERE mr.page_mid = %d AND mr.rid IN (%s) GROUP BY m.mid ORDER BY mleft', $item->mid, $rids_string);
+        if (!db_num_rows($result)) {
+          foreach ($rids as $rid) {
+            $menu_empty[$item->mid][$rid] = TRUE;
+          }
+          variable_set('menu_empty', $menu_empty);
+        }
+      }
+    }
+    list(, $menu) = _menu_tree($result);
     return $menu;
   }
 }
 
-function _menu_tree($result = NULL, $depth = 0, $link = array('link' => '', 'has_children' => FALSE)) {
-  static $original_map;
+function _menu_tree($result = NULL, $link = array('link' => '', 'has_children' => FALSE), $parents = '0,') {
+  static $map, $old_parents = '0';
   $remnant = array('link' => '', 'has_children' => FALSE);
   $tree = '';
-  $map = arg(NULL);
+  if (!isset($map)) {
+    $map = arg(NULL);
+  }
   while ($item = db_fetch_object($result)) {
-    list($access, , $path) = _menu_translate($item, $map, MENU_RENDER_LINK);
-    if (!$access) {
-      continue;
+    if (!$item->rid || $item->to_arg_functions) {
+      // If rid is not 0, access check already happened, so we skip that.
+      list($access, , $path) = _menu_translate($item, $map, MENU_RENDER_LINK, !$item->rid);
+      if (!$access) {
+        continue;
+      }
+    }
+    else {
+      $path = $item->path;
     }
     $menu_link = array('link' => l($item->title, $path), 'has_children' => $item->has_children);
-    if ($item->depth > $depth) {
-      list($remnant, $menu) = _menu_tree($result, $item->depth, $menu_link);
+    $preserved_old_parents = $old_parents .',';
+    $old_parents = $item->parents;
+    // It's a child if the current parent is a continuation of the
+    // previous parent.
+    if (strpos($item->parents, $preserved_old_parents) === 0) {
+      list($remnant, $menu) = _menu_tree($result, $menu_link, $preserved_old_parents);
       $tree .= theme('menu_tree', $link, $menu);
       $link = $remnant;
       $remnant = array('link' => '', 'has_children' => FALSE);
     }
-    elseif ($item->depth == $depth) {
+    // We are on the same level if the parents begins with parents of the parent.
+    elseif (strpos($item->parents, $parents) === 0) {
       $tree .= theme('menu_link', $link);
       $link = $menu_link;
     }
+    // it's the end of a submenu
     else {
       $remnant = $menu_link;
       break;
@@ -506,8 +563,18 @@ function menu_get_active_help() {
  * Populate the database representation of the menu.
  */
 function menu_rebuild() {
-  $next = array();
+  // TODO: split menu and menu links storage.
+  $permissions = array();
+  $result = db_query('SELECT * FROM {permission}');
+  while ($permission_role = db_fetch_object($result)) {
+    foreach(explode(', ', $permission_role->perm) as $permission) {
+      $permissions[$permission][] = $permission_role->rid;
+    }
+  }
   db_query('DELETE FROM {menu}');
+  db_query('DELETE FROM {menu_roles}');
+  db_query('DELETE FROM {menu_roles_cache}');
+  variable_set('menu_empty', array());
   $menu = module_invoke_all('menu');
   foreach (module_implements('menu_alter') as $module) {
     $function = $module .'_menu_alter';
@@ -532,7 +599,6 @@ function menu_rebuild() {
         if (empty($matches[1])) {
           $match = TRUE;
           $load_functions[$k] = NULL;
-          $to_arg_functions[$k] = NULL;
         }
         else {
           if (function_exists($matches[1] .'_to_arg')) {
@@ -571,6 +637,7 @@ function menu_rebuild() {
       '_parts' => $parts,
       '_fit' => $fit,
       '_mid' => $mid++,
+      '_children' => array(),
     );
     $item += array(
       '_visible' => (bool)($item['type'] & MENU_VISIBLE_IN_TREE),
@@ -583,37 +650,33 @@ function menu_rebuild() {
     else {
       $new_path = $path;
     }
+    $menu_path_map[$path] = $new_path;
     $menu[$new_path] = $item;
   }
-  // Second pass: find visible parents and prepare for sorting.
+  $menu_path_map[''] = '';
+  // Second pass: prepare for sorting and find parents.
   foreach ($menu as $path => $item) {
     $item = &$menu[$path];
     $number_parts = $item['_number_parts'];
-    $parents = array($item['_mid']);
-    if ($item['_visible'] && isset($item['parent'])) {
-      $parent_parts = explode('/', $item['parent'], 6);
+    if (isset($item['parent'])) {
+      $parent_parts = explode('/', $menu_path_map[$item['parent']], 6);
       $slashes = count($parent_parts) - 1;
     }
     else {
       $parent_parts = $item['_parts'];
-      $slashes = $number_parts -1;
+      $slashes = $number_parts - 1;
     }
     $depth = 1;
+    $parents = array($item['_mid']);
     for ($i = $slashes; $i; $i--) {
       $parent_path = implode('/', array_slice($parent_parts, 0, $i));
-      // We need to calculate depth to be able to sort. depth needs visibility.
-      if (isset($menu[$parent_path])) {
-        $parent = &$menu[$parent_path];
-        if ($item['_visible'] && $parent['_visible']) {
-          $parent['_has_children'] = 1;
-          $depth++;
-          $parents[] = $parent['_mid'];
-          if (!isset($item['_pid'])) {
-            $item['_pid'] = $parent['_mid'];
-            $item['_visible_parent_path'] = $parent_path;
-          }
+      if (isset($menu[$parent_path]) && $menu[$parent_path]['_visible']) {
+        $parent = $menu[$parent_path];
+        $parents[] = $parent['_mid'];
+        $depth++;
+        if (!isset($item['_pid'])) {
+          $item['_pid'] = $parent['_mid'];
         }
-        unset($parent);
       }
     }
     $parents[] = 0;
@@ -621,15 +684,37 @@ function menu_rebuild() {
     // Store variables and set defaults.
     $item += array(
       '_pid' => 0,
-      '_depth' => $item['_visible'] ? $depth : $number_parts,
+      '_depth' => $depth,
       '_parents' => $parents,
       '_has_children' => 0,
+      '_parent_parts' => $parent_parts,
+      '_slashes' => $slashes,
     );
-    $sort[$path] = $item['_depth'] . sprintf('%05d', $item['weight']) . $item['title'];
+    $sort[$path] = ($item['_visible'] ? $depth : $number_parts) . sprintf('%05d', $item['weight']) . $item['title'];
     unset($item);
   }
   array_multisort($sort, $menu);
-  // Third pass: calculate ancestors, vancode and store into the database.
+  // We are now sorted, so let's build the tree.
+  $children = array();
+  foreach ($menu as $path => $item) {
+    if ($item['_visible']) {
+      $slashes = $item['_slashes'];
+      $parent_parts = $item['_parent_parts'];
+      for ($i = $slashes; $i; $i--) {
+        $parent_path = implode('/', array_slice($parent_parts, 0, $i));
+        if (isset($menu[$parent_path]) && $menu[$parent_path]['_visible']) {
+          $menu[$parent_path]['_children'][] = $path;
+        }
+      }
+    }
+  }
+  // Calculate the nested set values.
+  foreach ($menu as $path => $item) {
+    if ($item['_visible'] && !$item['_pid']) {
+      _menu_renumber($menu, $path);
+    }
+  }
+  // Apply inheritance rules.
   foreach ($menu as $path => $item) {
     $item = &$menu[$path];
     for ($i = $item['_number_parts'] - 1; $i; $i--) {
@@ -650,28 +735,17 @@ function menu_rebuild() {
       }
     }
     if (!isset($item['access callback'])) {
-      $menu[$path]['access callback'] = isset($item['access arguments']) ? 'user_access' : 0;
+      $item['access callback'] = isset($item['access arguments']) ? 'user_access' : 0;
     }
     if (is_bool($item['access callback'])) {
       $item['access callback'] = intval($item['access callback']);
     }
-    if ($item['_visible']) {
-      $prefix = isset($item['_visible_parent_path']) ? $menu[$item['_visible_parent_path']]['_prefix'] : '';
-      if (!isset($next[$prefix])) {
-        $next[$prefix] = 0;
-      }
-      $vancode = $prefix . int2vancode($next[$prefix]++);
-      $menu[$path]['_prefix'] = $vancode .'.';
-    }
-    else {
-      $vancode = '';
-    }
     if ($item['_tab']) {
       if (!isset($item['parent'])) {
         $item['parent'] = implode('/', array_slice($item['_parts'], 0, $item['_number_parts'] - 1));
       }
       else {
-        $item['_depth'] = $item['parent'] ? $menu[$item['parent']]['_depth'] + 1 : 1;
+        $item['_depth'] = $item['parent'] ? $menu[$menu_path_map[$item['parent']]]['_depth'] + 1 : 1;
       }
     }
     else {
@@ -679,32 +753,57 @@ function menu_rebuild() {
       // stored in parents, parent stores the tab parent.
       $item['parent'] = $path;
     }
-    $insert_item = $item + array(
+    $insert_item = $item;
+    unset($item);
+    $item = $insert_item + array(
       'access arguments' => array(),
       'access callback' => '',
       'page arguments' => array(),
       'page callback' => '',
+      '_mleft' => 0,
+      '_mright' => 0,
     );
     db_query("INSERT INTO {menu} (
       mid, pid, path, load_functions, to_arg_functions,
       access_callback, access_arguments, page_callback, page_arguments, fit,
-      number_parts, vancode, visible, parents, depth, has_children, tab, title, parent, type)
-      VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s')",
-      $insert_item['_mid'], $insert_item['_pid'], $path,
-      $insert_item['load_functions'], $insert_item['to_arg_functions'],
-      $insert_item['access callback'], serialize($insert_item['access arguments']),
-      $insert_item['page callback'], serialize($insert_item['page arguments']),
-      $insert_item['_fit'], $insert_item['_number_parts'], $vancode .'+',
-      $insert_item['_visible'], $insert_item['_parents'], $insert_item['_depth'],
-      $insert_item['_has_children'], $item['_tab'], $insert_item['title'],
-      $insert_item['parent'], $insert_item['type']);
-    unset($item);
+      number_parts, visible, parents, depth, has_children, tab, title, parent,
+      type, mleft, mright)
+      VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d,
+      '%s', %d, %d, %d, '%s', '%s', '%s', %d, %d)",
+      $item['_mid'], $item['_pid'], $path, $item['load_functions'],
+      $item['to_arg_functions'], $item['access callback'],
+      serialize($item['access arguments']), $item['page callback'],
+      serialize($item['page arguments']), $item['_fit'],
+      $item['_number_parts'], $item['_visible'], $item['_parents'],
+      $item['_depth'], !empty($item['_children']), $item['_tab'],
+      $item['title'], $item['parent'], $item['type'], $item['_mleft'],
+      $item['_mright']);
+    if ($item['_visible']) {
+      if (($item['access callback'] == 'user_access' && count($item['access arguments'] == 1)) || isset($item['permission'])) {
+        $permission = isset($item['permission']) ? $item['permission'] : $item['access arguments'][0];
+        if (isset($permissions[$permission])) {
+          foreach ($permissions[$permission] as $rid) {
+            db_query('INSERT INTO {menu_roles} (mid, rid) VALUES (%d, %d)', $item['_mid'], $rid);
+          }
+        }
+      }
+      else {
+        // The item needs dynamic access handling.
+        db_query('INSERT INTO {menu_roles} (mid, rid) VALUES (%d, %d)', $item['_mid'], 0);
+      }
+    }
   }
 }
 
-function menu_map($arg, $function, $index, $default = FALSE) {
-  $arg[$index] = is_numeric($arg[$index]) ? $function($arg[$index]) : $default;
-  return $arg[$index] ? $arg : FALSE;
+function _menu_renumber(&$menu, $path) {
+  static $counter = 1;
+  if (!isset($menu[$path]['_mleft'])) {
+    $menu[$path]['_mleft'] = $counter++;
+    foreach ($menu[$path]['_children'] as $child_path) {
+      _menu_renumber($menu, $child_path);
+    }
+    $menu[$path]['_mright'] = $counter++;
+  }
 }
 
 // Placeholders.
@@ -741,7 +840,7 @@ function menu_local_tasks($level = 0) {
         continue;
       }
       // This loads all the tabs.
-      $result = db_query("SELECT * FROM {menu} WHERE parent = '%s' AND tab = 1 ORDER BY vancode", $parent);
+      $result = db_query("SELECT * FROM {menu} WHERE parent = '%s' AND tab = 1 ORDER BY mleft", $parent);
       $tabs_current = '';
       while ($item = db_fetch_object($result)) {
         // This call changes the path from for example user/% to user/123 and

=== modified file 'modules/comment/comment.module'
--- modules/comment/comment.module	2007-02-15 11:40:17 +0000
+++ modules/comment/comment.module	2007-02-27 05:56:27 +0000
@@ -198,6 +198,7 @@ function comment_menu() {
   $items['comment/reply/%node'] = array(
     'title' => t('Reply to comment'),
     'page callback' => 'comment_reply',
+    'page arguments' => array(2),
     'access callback' => 'node_access',
     'access arguments' => array('view', 2),
     'type' => MENU_CALLBACK,
@@ -614,8 +615,8 @@ function comment_edit($cid) {
  * The node or comment that is being replied to must appear above the comment
  * form to provide the user context while authoring the comment.
  *
- * @param $nid
- *   Every comment belongs to a node. This is that node's id.
+ * @param $node
+ *   Every comment belongs to a node. This is that node.
  * @param $pid
  *   Some comments are replies to other comments. In those cases, $pid is the parent
  *   comment's cid.
@@ -623,12 +624,9 @@ function comment_edit($cid) {
  * @return $output
  *   The rendered parent node or comment plus the new comment form.
  */
-function comment_reply($nid, $pid = NULL) {
-  // Load the parent node.
-  $node = node_load($nid);
-
+function comment_reply($node, $pid = NULL) {
   // Set the breadcrumb trail.
-  menu_set_location(array(array('path' => "node/$nid", 'title' => $node->title), array('path' => "comment/reply/$nid")));
+  menu_set_location(array(array('path' => "node/$node->nid", 'title' => $node->title), array('path' => "comment/reply/$node->nid")));
 
   $op = isset($_POST['op']) ? $_POST['op'] : '';
 
@@ -638,11 +636,11 @@ function comment_reply($nid, $pid = NULL
     // The user is previewing a comment prior to submitting it.
     if ($op == t('Preview comment')) {
       if (user_access('post comments')) {
-        $output .= comment_form_box(array('pid' => $pid, 'nid' => $nid), NULL);
+        $output .= comment_form_box(array('pid' => $pid, 'nid' => $node->nid), NULL);
       }
       else {
         drupal_set_message(t('You are not authorized to post comments.'), 'error');
-        drupal_goto("node/$nid");
+        drupal_goto("node/$node->nid");
       }
     }
     else {
@@ -652,10 +650,10 @@ function comment_reply($nid, $pid = NULL
         if ($comment = db_fetch_object(db_query('SELECT c.*, u.uid, u.name AS registered_name, u.picture, u.data FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.cid = %d AND c.status = %d', $pid, COMMENT_PUBLISHED))) {
           // If that comment exists, make sure that the current comment and the parent comment both
           // belong to the same parent node.
-          if ($comment->nid != $nid) {
+          if ($comment->nid != $node->nid) {
             // Attempting to reply to a comment not belonging to the current nid.
             drupal_set_message(t('The comment you are replying to does not exist.'), 'error');
-            drupal_goto("node/$nid");
+            drupal_goto("node/$node->nid");
           }
           // Display the parent comment
           $comment = drupal_unpack($comment);
@@ -664,7 +662,7 @@ function comment_reply($nid, $pid = NULL
         }
         else {
           drupal_set_message(t('The comment you are replying to does not exist.'), 'error');
-          drupal_goto("node/$nid");
+          drupal_goto("node/$node->nid");
         }
       }
       // This is the case where the comment is in response to a node. Display the node.
@@ -673,22 +671,22 @@ function comment_reply($nid, $pid = NULL
       }
 
       // Should we show the reply box?
-      if (node_comment_mode($nid) != COMMENT_NODE_READ_WRITE) {
+      if (node_comment_mode($node->nid) != COMMENT_NODE_READ_WRITE) {
         drupal_set_message(t("This discussion is closed: you can't post new comments."), 'error');
-        drupal_goto("node/$nid");
+        drupal_goto("node/$node->nid");
       }
       else if (user_access('post comments')) {
-        $output .= comment_form_box(array('pid' => $pid, 'nid' => $nid), t('Reply'));
+        $output .= comment_form_box(array('pid' => $pid, 'nid' => $node->nid), t('Reply'));
       }
       else {
         drupal_set_message(t('You are not authorized to post comments.'), 'error');
-        drupal_goto("node/$nid");
+        drupal_goto("node/$node->nid");
       }
     }
   }
   else {
     drupal_set_message(t('You are not authorized to view comments.'), 'error');
-    drupal_goto("node/$nid");
+    drupal_goto("node/$node->nid");
   }
 
   return $output;

=== modified file 'modules/system/system.install'
--- modules/system/system.install	2007-02-12 17:47:07 +0000
+++ modules/system/system.install	2007-02-26 23:22:57 +0000
@@ -327,8 +327,8 @@ function system_install() {
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
       db_query("CREATE TABLE {menu} (
-        mid int NOT NULL default '0',
-        pid int NOT NULL default '0',
+        mid int NOT NULL default 0,
+        pid int NOT NULL default 0,
         path varchar(255) NOT NULL default '',
         load_functions varchar(255) NOT NULL default '',
         to_arg_functions varchar(255) NOT NULL default '',
@@ -336,25 +336,41 @@ function system_install() {
         access_arguments text,
         page_callback varchar(255) NOT NULL default '',
         page_arguments text,
-        fit int NOT NULL default '0',
-        number_parts int NOT NULL default '0',
-        vancode varchar(255) NOT NULL default '',
-        visible int NOT NULL default '0',
+        fit int NOT NULL default 0,
+        number_parts int NOT NULL default 0,
+        mleft int NOT NULL default 0,
+        mright int NOT NULL default 0,
+        visible int NOT NULL default 0,
         parents varchar(255) NOT NULL default '',
-        depth int NOT NULL default '0',
-        has_children int NOT NULL default '0',
+        depth int NOT NULL default 0,
+        has_children int NOT NULL default 0,
         tab int NOT NULL default 0,
         title varchar(255) NOT NULL default '',
         parent varchar(255) NOT NULL default '',
         type int NOT NULL default 0,
         PRIMARY KEY  (path),
-        KEY vancode (vancode),
         KEY fit (fit),
         KEY visible (visible),
         KEY pid (pid),
         KEY parent (parent)
       ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");
 
+      db_query("CREATE TABLE {menu_roles} (
+        mid int NOT NULL default 0,
+        rid int NOT NULL default 0,
+        KEY mid (mid),
+        KEY rid (rid)
+      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");    
+
+      db_query("CREATE TABLE {menu_roles_cache} (
+        page_mid int NOT NULL default 0,
+        mid int NOT NULL default 0,
+        rid int NOT NULL default 0,
+        KEY page_mid (page_mid),
+        KEY mid (mid),
+        KEY rid (rid)
+      ) /*!40100 DEFAULT CHARACTER SET UTF8 */ ");    
+
       db_query("CREATE TABLE {node} (
         nid int unsigned NOT NULL auto_increment,
         vid int unsigned NOT NULL default '0',
@@ -801,8 +817,8 @@ function system_install() {
       )");
 
       db_query("CREATE TABLE {menu} (
-        mid int NOT NULL default '0',
-        pid int NOT NULL default '0',
+        mid int NOT NULL default 0,
+        pid int NOT NULL default 0,
         path varchar(255) NOT NULL default '',
         load_functions varchar(255) NOT NULL default '',
         to_arg_functions varchar(255) NOT NULL default '',
@@ -810,13 +826,14 @@ function system_install() {
         access_arguments text,
         page_callback varchar(255) NOT NULL default '',
         page_arguments text,
-        fit int NOT NULL default '0',
-        number_parts int NOT NULL default '0',
-        vancode varchar(255) NOT NULL default '',
-        visible int NOT NULL default '0',
+        fit int NOT NULL default 0,
+        number_parts int NOT NULL default 0,
+        mleft int NOT NULL default 0,
+        mright int NOT NULL default 0,
+        visible int NOT NULL default 0,
         parents varchar(255) NOT NULL default '',
-        depth int NOT NULL default '0',
-        has_children int NOT NULL default '0',
+        depth int NOT NULL default 0,
+        has_children int NOT NULL default 0,
         tab int NOT NULL default 0,
         title varchar(255) NOT NULL default '',
         parent varchar(255) NOT NULL default '',
@@ -824,12 +841,29 @@ function system_install() {
         PRIMARY KEY (path)
       )");
 
-      db_query("CREATE INDEX {menu}_vancode_idx ON {menu} (vancode)");
       db_query("CREATE INDEX {menu}_fit_idx ON {menu} (fit)");
       db_query("CREATE INDEX {menu}_visible_idx ON {menu} (visible)");
       db_query("CREATE INDEX {menu}_parent_idx ON {menu} (parent)");
       db_query("CREATE INDEX {menu}_pid_idx ON {menu} (parent)");
 
+      db_query("CREATE TABLE {menu_roles} (
+        mid int NOT NULL default 0,
+        rid int NOT NULL default 0
+      )");
+
+      db_query("CREATE INDEX {menu_roles}_mid_idx ON {menu_roles} (mid)");
+      db_query("CREATE INDEX {menu_roles}_rid_idx ON {menu_roles} (rid)");
+
+      db_query("CREATE TABLE {menu_roles_cache} (
+        page_mid int NOT NULL default 0,
+        mid int NOT NULL default 0,
+        rid int NOT NULL default 0
+      )");
+
+      db_query("CREATE INDEX {menu_roles_cache}_page_mid_idx ON {menu_roles_cache} (page_mid)");
+      db_query("CREATE INDEX {menu_roles_cache}_mid_idx ON {menu_roles_cache} (mid)");
+      db_query("CREATE INDEX {menu_roles_cache}_rid_idx ON {menu_roles_cache} (rid)");
+
       db_query("CREATE TABLE {node} (
         nid serial CHECK (nid >= 0),
         vid int_unsigned NOT NULL default '0',

=== modified file 'modules/user/user.module'
--- modules/user/user.module	2007-02-15 11:40:17 +0000
+++ modules/user/user.module	2007-02-21 22:21:27 +0000
@@ -735,6 +735,7 @@ function user_menu() {
     'page callback' => 'drupal_get_form',
     'page arguments' => array('user_login'),
     'access callback' => 'user_is_anonymous',
+    'type' => MENU_CALLBACK,
   );
 
   $items['user/login'] = array(

