diff -urp includes/menu.inc includes/menu.inc
--- includes/menu.inc	2008-11-13 15:15:18.000000000 +0200
+++ includes/menu.inc	2008-11-13 22:39:10.000000000 +0200
@@ -485,22 +485,33 @@ function _menu_load_objects(&$item, &$ma
  *   $item['access'] becomes TRUE if the item is accessible, FALSE otherwise.
  */
 function _menu_check_access(&$item, $map) {
-  // Determine access callback, which will decide whether or not the current
-  // user has access to this path.
-  $callback = empty($item['access_callback']) ? 0 : trim($item['access_callback']);
-  // Check for a TRUE or FALSE value.
-  if (is_numeric($callback)) {
-    $item['access'] = (bool)$callback;
-  }
-  else {
-    $arguments = menu_unserialize($item['access_arguments'], $map);
-    // As call_user_func_array is quite slow and user_access is a very common
-    // callback, it is worth making a special case for it.
-    if ($callback == 'user_access') {
-      $item['access'] = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]);
+  $callbacks = array();
+  foreach (unserialize($item['access_arguments']) as $callback) {
+    $callbacks[] = array(
+      'callback' => empty($callback['callback']) ? 0 : trim($callback['callback']),
+       'arguments' => $callback['arguments'],
+     );
+   }
+  foreach ($callbacks as $callback) {
+    // Check for a TRUE or FALSE value.
+    if (is_numeric($callback['callback'])) {
+      $item['access'] =  (bool)$callback['callback'];
     }
     else {
-      $item['access'] = call_user_func_array($callback, $arguments);
+      $arguments = menu_unserialize($callback['arguments'], $map);
+      // As call_user_func_array is quite slow and user_access is a very common
+      // callback, it is worth making a special case for it.
+      if ($callback['callback'] == 'user_access') {
+        $item['access'] = count($arguments) == 1 ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]);
+      }
+      else {
+        $item['access'] = call_user_func_array($callback['callback'], $arguments);
+      }
+    }
+    // If menu has multiple access and one access is FALSE then deny access
+    // and stop checking other access callbacks.
+    if ($item['access'] == FALSE) {
+      break;
     }
   }
 }
@@ -2276,6 +2287,40 @@ function _menu_router_build($callbacks) 
   // matching. Calculate fitness, and fill some default values.
   $menu = array();
   foreach ($callbacks as $path => $item) {
+    /******************************************************/
+    // Temporary, just until core's hook_menu() are updated.
+    if (empty($item['callbacks'])) {
+      $item['callbacks'] = array(
+        array(
+          'type' => 'access',
+          'callback' => isset($item['access callback']) ? $item['access callback'] : NULL,
+          'arguments' => isset($item['access arguments']) ? $item['access arguments'] : NULL,
+        ),
+        array(
+          'type' => 'page',
+          'callback' => isset($item['page callback']) ? $item['page callback'] : NULL,
+          'arguments' => isset($item['page arguments']) ? $item['page arguments'] : NULL,
+        ),
+        array(
+          'type' => 'title',
+          'callback' => isset($item['title callback']) ? $item['title callback'] : NULL,
+          'arguments' => isset($item['title arguments']) ? $item['title arguments'] : NULL,
+        ),
+        array(
+          'type' => 'block',
+          'callback' => isset($item['block callback']) ? $item['block callback'] : NULL,
+        ),
+      );
+      unset($item['access callback']);
+      unset($item['access arguments']);
+      unset($item['page callback']);
+      unset($item['page arguments']);
+      unset($item['title callback']);
+      unset($item['title arguments']);
+      unset($item['block callback']);
+    }
+    /******************************************************/
+
     $load_functions = array();
     $to_arg_functions = array();
     $fit = 0;
@@ -2286,6 +2331,16 @@ function _menu_router_build($callbacks) 
     // We store the highest index of parts here to save some work in the fit
     // calculation loop.
     $slashes = $number_parts - 1;
+    // Get the load callback if exists.
+    $load_callback_key = -1;
+    if (!empty($item['callbacks'])) {
+      foreach ($item['callbacks'] as $key => $arguments) {
+        if (!empty($arguments['type']) && $arguments['type'] == 'load') {
+          $load_callback_key = $key;
+          break;
+        }
+      }
+    }
     // Extract load and to_arg functions.
     foreach ($parts as $k => $part) {
       $match = FALSE;
@@ -2371,6 +2426,7 @@ function _menu_router_build($callbacks) 
       $parent_path = implode('/', array_slice($item['_parts'], 0, $i));
       if (isset($menu[$parent_path])) {
 
+        // Get the parent item if inheritance rules should be applied.
         $parent = $menu[$parent_path];
 
         if (!isset($item['tab_parent'])) {
@@ -2380,43 +2436,106 @@ function _menu_router_build($callbacks) 
         if (!isset($item['tab_root']) && !$parent['_tab']) {
           $item['tab_root'] = $parent_path;
         }
-        // If an access callback is not found for a default local task we use
-        // the callback from the parent, since we expect them to be identical.
-        // In all other cases, the access parameters must be specified.
-        if (($item['type'] == MENU_DEFAULT_LOCAL_TASK) && !isset($item['access callback']) && isset($parent['access callback'])) {
-          $item['access callback'] = $parent['access callback'];
-          if (!isset($item['access arguments']) && isset($parent['access arguments'])) {
-            $item['access arguments'] = $parent['access arguments'];
-          }
-        }
-        // Same for page callbacks.
-        if (!isset($item['page callback']) && isset($parent['page callback'])) {
-          $item['page callback'] = $parent['page callback'];
-          if (!isset($item['page arguments']) && isset($parent['page arguments'])) {
-            $item['page arguments'] = $parent['page arguments'];
-          }
-        }
+        break;
       }
     }
-    if (!isset($item['access callback']) && isset($item['access arguments'])) {
-      // Default callback.
-      $item['access callback'] = 'user_access';
+    // This array will hold the callbacks grouped by type
+    // (e.g. access, page, etc').
+    $item['group_callbacks'] = array();
+    // Process the callbacks' keys that holds all the load, access and page
+    // callbacks and arguments. Load key was already processed.
+    if (!empty($item['callbacks'])) {
+      // Pass by reference as we might change the callback itself.
+      foreach ($item['callbacks'] as &$callback) {
+        switch ($callback['type']) {
+          case 'access':
+            // If an access callback is not found for a default local task we use
+            // the callback from the parent, since we expect them to be identical.
+            // In all other cases, the access parameters must be specified.
+            if (isset($callback['callback'])) {
+              if (is_bool($callback['callback'])) {
+                $callback['callback'] = intval($callback['callback']);
+              }
+            }
+            elseif ($item['type'] == MENU_DEFAULT_LOCAL_TASK && !empty($parent)) {
+              // Set to parent access callback.
+              foreach ($parent['callbacks'] as $parent_callback) {
+                if ($parent_callback['type'] == 'access') {
+                  $callback['callback'] = isset($parent_callback['callback']) ? $parent_callback['callback'] : '';
+                  // If also the arguments are missing set the parent's
+                  // arguments.
+                  $callback['arguments'] = isset($callback['arguments']) ? $callback['arguments'] : $parent_callback['arguments'];
+                }
+              }
+            }
+            elseif (isset($callback['arguments'])) {
+              // Default callback.
+              $callback['callback'] = 'user_access';
+            }
+            // Serialize the access arguments as they will later
+            // be menu_serialize().dpm($callback['arguments']);
+            if (is_array($callback['arguments'])) {
+              $callback['arguments'] = serialize($callback['arguments']);
+            }
+            // Group all 'access' type callbacks.
+            $item['group_callbacks']['access'][] = array(
+              'callback' => $callback['callback'],
+              'arguments' => $callback['arguments'],
+            );
+            break;
+
+          case 'page':
+            // Set parent inheritance for page callbacks.
+            if (!isset($callback['callback'])) {
+              if (!empty($parent)) {
+                foreach ($parent['callbacks'] as $parent_callback) {
+                  if ($parent_callback['type'] == 'page') {
+                    $callback['callback'] = isset($parent_callback['callback']) ? $parent_callback['callback'] : '';
+                    $callback['arguments'] = isset($callback['arguments']) ? $callback['arguments'] : $parent_callback['arguments'];
+
+                  }
+                }
+              }
+            }
+            // Group 'page' type callback.
+            $item['group_callbacks']['page'] = array(
+              'callback' => isset($callback['callback']) ? $callback['callback'] : '',
+              'arguments' => isset($callback['arguments']) ? $callback['arguments'] : array(),
+            );
+            break;
+
+          case 'block':
+            // Group 'block' type.
+            $item['group_callbacks']['block'] = array(
+              'callback' => isset($callback['callback']) ? $callback['callback'] : '',
+            );
+            break;
+
+          case 'title':
+            // Group 'title' type.
+            $item['group_callbacks']['title'] = array(
+              'callback' => isset($callback['callback']) ? $callback['callback'] : 't',
+              'arguments' => isset($callback['arguments']) ? serialize($callback['arguments']) : '',
+            );
+            break;
+        }
+      }
     }
-    if (!isset($item['access callback']) || empty($item['page callback'])) {
-      $item['access callback'] = 0;
+
+    // Make sure there are atleast a single default value assigned to
+    // access callback.
+    if (empty($item['group_callbacks']['access']) || empty($item['group_callbacks']['page'])) {
+      $item['group_callbacks']['access'][0]['callback'] = 0;
+    }
+    // Set parent inheritance for file and filepath.
+    if (!isset($item['file']) && isset($parent['file'])) {
+      $item['file'] = $parent['file'];
     }
-    if (is_bool($item['access callback'])) {
-      $item['access callback'] = intval($item['access callback']);
+    if (!isset($item['file path']) && isset($parent['file path'])) {
+      $item['file path'] = $parent['file path'];
     }
 
     $item += array(
-      'access arguments' => array(),
-      'access callback' => '',
-      'page arguments' => array(),
-      'page callback' => '',
-      'block callback' => '',
-      'title arguments' => array(),
-      'title callback' => 't',
       'description' => '',
       'position' => '',
       'tab_parent' => '',
@@ -2424,7 +2543,6 @@ function _menu_router_build($callbacks) 
       'path' => $path,
     );
 
-    $title_arguments = $item['title arguments'] ? serialize($item['title arguments']) : '';
     db_query("INSERT INTO {menu_router}
       (path, load_functions, to_arg_functions, access_callback,
       access_arguments, page_callback, page_arguments, fit,
@@ -2436,11 +2554,11 @@ function _menu_router_build($callbacks) 
       %d, '%s', '%s',
       '%s', '%s', '%s',
       %d, '%s', '%s', '%s', %d)",
-      $path, $item['load_functions'], $item['to_arg_functions'], $item['access callback'],
-      serialize($item['access arguments']), $item['page callback'], serialize($item['page arguments']), $item['_fit'],
+      $path, $item['load_functions'], $item['to_arg_functions'], '',
+      serialize($item['group_callbacks']['access']), $item['group_callbacks']['page']['callback'], serialize($item['group_callbacks']['page']['arguments']), $item['_fit'],
       $item['_number_parts'], $item['tab_parent'], $item['tab_root'],
-      $item['title'], $item['title callback'], $title_arguments,
-      $item['type'], $item['block callback'], $item['description'], $item['position'], $item['weight']);
+      $item['title'], $item['group_callbacks']['title']['callback'], $item['group_callbacks']['title']['arguments'],
+      $item['type'], $item['group_callbacks']['block']['callback'], $item['description'], $item['position'], $item['weight']);
   }
   // Sort the masks so they are in order of descending fit, and store them.
   $masks = array_keys($masks);
