diff -urpN includes/menu.inc includes/menu.inc
--- includes/menu.inc	2008-11-10 20:32:51.000000000 +0200
+++ includes/menu.inc	2008-11-11 11:03:27.000000000 +0200
@@ -486,22 +486,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;
     }
   }
 }
@@ -2040,7 +2051,7 @@ function menu_link_save(&$item) {
     if ($existing_item && $menu_name != $existing_item['menu_name']) {
       menu_cache_clear($existing_item['menu_name']);
     }
-  
+
     _menu_clear_page_cache();
   }
   return $item['mlid'];
@@ -2276,6 +2287,31 @@ function _menu_router_build($callbacks) 
   // matching. Calculate fitness, and fill some default values.
   $menu = array();
   foreach ($callbacks as $path => $item) {
+    /******************************************************/
+    // Temoprary, 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,
+        )
+      );
+      unset($item['access callback']);
+      unset($item['access arguments']);
+      unset($item['page callback']);
+      unset($item['page arguments']);
+    }
+
+    /******************************************************/
+
     $load_functions = array();
     $to_arg_functions = array();
     $fit = 0;
@@ -2286,6 +2322,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;
@@ -2359,7 +2405,6 @@ function _menu_router_build($callbacks) 
   }
   // Delete the existing router since we have some data to replace it.
   db_query('DELETE FROM {menu_router}');
-  // Apply inheritance rules.
   foreach ($menu as $path => $v) {
     $item = &$menu[$path];
     if (!$item['_tab']) {
@@ -2371,6 +2416,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,67 +2426,114 @@ 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;
+      }
+    }
+    $keyd_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'])) {
+      foreach ($item['callbacks'] as $key => $v) {
+        switch ($item['callbacks'][$key]['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($item['callbacks'][$key]['callback'])) {
+              if (is_bool($item['callbacks'][$key]['callback'])) {
+                $item['callbacks'][$key]['callback'] = intval($item['callbacks'][$key]['callback']);
+              }
+            }
+            elseif ($item['type'] == MENU_DEFAULT_LOCAL_TASK && isset($parent['callbacks'][$key]['callback'])) {
+              // Set to parent access callback.
+              $item['callbacks'][$key]['callback'] = $parent['callbacks'][$key]['callback'];
+            }
+            elseif (isset($item['callbacks'][$key]['arguments'])) {
+              // Default callback.
+              $item['callbacks'][$key]['callback'] = 'user_access';
+            }
+
+            if (!isset($item['callbacks'][$key]['arguments']) && isset($parent['callbacks'][$key]['arguments'])) {
+              // Set to parent access arguments.
+              $item['callbacks'][$key]['arguments'] = unserialize($parent['callbacks'][$key]['arguments']);
+            }
+
+            if (!isset($item['callbacks'][$key]['arguments'])) {
+              // Populate with an empty array in order not to get
+              // exceptions when unserialize in _menu_check_access().
+              $item['callbacks'][$key]['arguments'] = array();
+            }
+
+            // Serialize the access arguments as they will later be menu_serialize().
+            $item['callbacks'][$key]['arguments'] = serialize($item['callbacks'][$key]['arguments']);
+
+            // Accumlate all 'access' type callbacks.
+            $keyd_callbacks['access'][] = $item['callbacks'][$key];
+            break;
+
+            case 'page':
+              // Set parent inheritance for page callbacks.
+              if (!isset($item['callbacks'][$key]['callback']) && isset($parent['callbacks'][$key]['callback'])) {
+                $item['callbacks'][$key]['callback'] = $parent['callbacks'][$key]['callback'];
+                if (!isset($item['callbacks'][$key]['arguments']) && isset($parent['callbacks'][$key]['arguments'])) {
+                  $item['callbacks'][$key]['arguments'] = $parent['callbacks'][$key]['arguments'];
+                }
+
+                if (!isset($item['file']) && isset($parent['file'])) {
+                  $item['file'] = $parent['file'];
+                }
+                if (!isset($item['file path']) && isset($parent['file path'])) {
+                  $item['file path'] = $parent['file path'];
+                }
+              }
+              // Accumlate all 'page' type callbacks.
+              $keyd_callbacks['page'][] = $item['callbacks'][$key];
+              break;
           }
         }
       }
-    }
-    if (!isset($item['access callback']) && isset($item['access arguments'])) {
-      // Default callback.
-      $item['access callback'] = 'user_access';
-    }
-    if (!isset($item['access callback']) || empty($item['page callback'])) {
-      $item['access callback'] = 0;
-    }
-    if (is_bool($item['access callback'])) {
-      $item['access callback'] = intval($item['access callback']);
-    }
+      if (empty($keyd_callbacks['access']) || empty($keyd_callbacks['page'])) {
+        $keyd_callbacks['access']['0']['callback'] = 0;
+      }
+      if (!isset($item['callbacks'][$key]['callback'])) {
+        $keyd_callbacks['page']['0']['callback'] = '';
+      }
 
-    $item += array(
-      'access arguments' => array(),
-      'access callback' => '',
-      'page arguments' => array(),
-      'page callback' => '',
-      'block callback' => '',
-      'title arguments' => array(),
-      'title callback' => 't',
-      'description' => '',
-      'position' => '',
-      'tab_parent' => '',
-      'tab_root' => $path,
-      'path' => $path,
-    );
+      if (!isset($item['callbacks'][$key]['arguments'])) {
+        $keyd_callbacks['page']['0']['arguments'] = array();
+      }
+
+      $item += array(
+        'page arguments' => array(),
+        'page callback' => '',
+        'block callback' => '',
+        'title arguments' => array(),
+        'title callback' => 't',
+        'description' => '',
+        'position' => '',
+        'tab_parent' => '',
+        'tab_root' => $path,
+        'path' => $path,
+      );
+      $title_arguments = $item['title arguments'] ? serialize($item['title arguments']) : '';
 
-    $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,
-      number_parts, tab_parent, tab_root,
-      title, title_callback, title_arguments,
-      type, block_callback, description, position, weight)
-      VALUES ('%s', '%s', '%s', '%s',
-      '%s', '%s', '%s', %d,
-      %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'],
-      $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']);
+      db_query("INSERT INTO {menu_router}
+        (path, load_functions, to_arg_functions, access_callback,
+        access_arguments, page_callback, page_arguments, fit,
+        number_parts, tab_parent, tab_root,
+        title, title_callback, title_arguments,
+        type, block_callback, description, position, weight)
+        VALUES ('%s', '%s', '%s', '%s',
+        '%s', '%s', '%s', %d,
+        %d, '%s', '%s',
+        '%s', '%s', '%s',
+        %d, '%s', '%s', '%s', %d)",
+        $path, $item['load_functions'], $item['to_arg_functions'], '-1',
+        serialize($keyd_callbacks['access']), $keyd_callbacks['page']['0']['callback'], serialize($keyd_callbacks['page']['0']['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']);
   }
   // Sort the masks so they are in order of descending fit, and store them.
   $masks = array_keys($masks);
