Index: index.php
===================================================================
RCS file: /cvs/drupal/drupal/index.php,v
retrieving revision 1.78
diff -u -F^function -r1.78 index.php
--- index.php	15 Apr 2004 20:49:39 -0000	1.78
+++ index.php	19 Apr 2004 21:23:14 -0000
@@ -7,11 +7,15 @@
 
 fix_gpc_magic();
 
-if (menu_active_handler_exists()) {
-  menu_execute_active_handler();
-}
-else {
-  drupal_not_found();
+$status = menu_execute_active_handler();
+switch ($status) {
+  case MENU_FOUND:
+    break;
+  case MENU_DENIED:
+    drupal_access_denied();
+    break;
+  default:
+    drupal_not_found();
 }
 
 drupal_page_footer();
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.338
diff -u -F^function -r1.338 common.inc
--- includes/common.inc	15 Apr 2004 14:07:08 -0000	1.338
+++ includes/common.inc	19 Apr 2004 21:23:14 -0000
@@ -80,7 +80,6 @@ function drupal_get_breadcrumb() {
 
   if (!isset($breadcrumb)) {
     $breadcrumb = menu_get_active_breadcrumb();
-    array_pop($breadcrumb);
   }
 
   return $breadcrumb;
@@ -253,24 +252,40 @@ function drupal_goto($url = NULL, $query
  * Generates a 404 error if the request can not be handled.
  */
 function drupal_not_found() {
-  header("HTTP/1.0 404 Not Found");
-  watchdog("httpd", "404 error: '". check_query($_GET["q"]) ."' not found");
+  header('HTTP/1.0 404 Not Found');
+  watchdog('httpd', '404 error: "'. check_query($_GET['q']) .'" not found');
 
   $path = drupal_get_normal_path(variable_get('site_404', ''));
-
+  $status = MENU_FALLTHROUGH;
   if ($path) {
     menu_set_active_item($path);
+    $status = menu_execute_active_handler();
   }
 
-  if ($path && menu_active_handler_exists()) {
-    menu_execute_active_handler();
-  }
-  else {
+  if ($status != MENU_FOUND) {
     print theme('page', '', t('Page not found'));
   }
 }
 
 /**
+ * Generates a 403 error if the request is not allowed.
+ */
+function drupal_access_denied() {
+  header('HTTP/1.0 403 Forbidden');
+
+  $path = drupal_get_normal_path(variable_get('site_403', ''));
+  $status = MENU_FALLTHROUGH;
+  if ($path) {
+    menu_set_active_item($path);
+    $status = menu_execute_active_handler();
+  }
+
+  if ($status != MENU_FOUND) {
+    print theme('page', message_access(), t('Access denied'));
+  }
+}
+
+/**
  * Flexible and powerful HTTP client implementation. Allows to GET, POST, PUT
  * or any other HTTP requests. Handles redirects.
  *
Index: includes/file.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/file.inc,v
retrieving revision 1.11
diff -u -F^function -r1.11 file.inc
--- includes/file.inc	24 Mar 2004 18:58:36 -0000	1.11
+++ includes/file.inc	19 Apr 2004 21:23:14 -0000
@@ -323,7 +323,7 @@ function file_download() {
     foreach ($list as $module) {
       $headers = module_invoke($module, 'file_download', $file);
       if ($headers === -1) {
-        print theme('page', message_access());
+        drupal_access_denied();
       }
       elseif (is_array($headers)) {
         file_transfer($file, $headers);
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.38
diff -u -F^function -r1.38 menu.inc
--- includes/menu.inc	15 Apr 2004 20:49:40 -0000	1.38
+++ includes/menu.inc	19 Apr 2004 21:23:14 -0000
@@ -15,6 +15,10 @@
 define('MENU_LOCKED', 2);
 define('MENU_CUSTOM', 3);
 
+define('MENU_FALLTHROUGH', 0);
+define('MENU_DENIED', 1);
+define('MENU_FOUND', 2);
+
 /** @} */
 
 /**
@@ -23,7 +27,10 @@
  * @ingroup menu
  * @param $path Location then menu item refers to.
  * @param $title The title of the menu item to show in the rendered menu.
- * @param $callback The function to call when this is the active menu item.
+ * @param $callback
+ * - string - The function to call when this is the active menu item.
+ * - MENU_FALLTHROUGH - Use the callback defined by the menu item's parent.
+ * - MENU_DENIED - Deny access to this menu item by this user.
  * @param $weight Heavier menu items sink down the menu.
  * @param $visibility
  * - MENU_SHOW - Show the menu item (default).
@@ -31,11 +38,9 @@
  * - MENU_HIDE_NOCHILD - Hide the menu item when it has no children.
  * @param $status
  * - MENU_NORMAL - The menu item can be moved (default).
- * - MENU_MODIFIED - The administrator has moved or otherwise changed the menu item.
  * - MENU_LOCKED - The administrator may not modify the item.
- * - MENU_CUSTOM - The menu item was created by the administrator.
  */
-function menu($path, $title, $callback = NULL, $weight = 0, $visibility = MENU_SHOW, $status = MENU_NORMAL) {
+function menu($path, $title, $callback = MENU_FALLTHROUGH, $weight = 0, $visibility = MENU_SHOW, $status = MENU_NORMAL) {
   global $_menu;
 
   // add the menu to the flat list of menu items:
@@ -90,7 +95,13 @@ function menu_get_trail($path) {
 
   $trail = array();
 
-  $mid = menu_get_active_item();
+  // Find the ID of the given path.
+  while ($path && !$menu['path index'][$path]) {
+    $path = substr($path, 0, strrpos($path, '/'));
+  }
+  $mid = $menu['path index'][$path];
+  
+  // Follow the parents up the chain to get the trail.
   while ($mid && $menu['items'][$mid]) {
     array_unshift($trail, $mid);
     $mid = $menu['items'][$mid]['pid'];
@@ -171,9 +182,13 @@ function menu_get_active_breadcrumb() {
   $links[] = l(t('Home'), '');
 
   $trail = menu_get_trail($_GET['q']);
+  
+  // The last item in the trail is the page title; don't display it here.
+  array_pop($trail);
+  
   foreach ($trail as $mid) {
-    // Don't show menu items without valid link targets.
-    if ($menu['items'][$mid]['path'] != '') {
+    // Don't show hidden menu items or items without valid link targets.
+    if (isset($menu['visible'][$mid]) && $menu['items'][$mid]['path'] != '') {
       $links[] = _menu_render_item($mid);
     }
   }
@@ -188,20 +203,26 @@ function menu_execute_active_handler() {
   $menu = menu_get_menu();
 
   $path = $_GET['q'];
-  while ($path && (!$menu['path index'][$path] || !$menu['items'][$menu['path index'][$path]]['callback'])) {
+  while ($path && (!$menu['path index'][$path] || $menu['items'][$menu['path index'][$path]]['callback'] === MENU_FALLTHROUGH)) {
     $path = substr($path, 0, strrpos($path, '/'));
   }
   $mid = $menu['path index'][$path];
-
-  if ($menu['items'][$mid]['callback']) {
+  if ($menu['items'][$mid]['callback'] === MENU_DENIED) {
+    return MENU_DENIED;
+  }
+  
+  if (is_string($menu['items'][$mid]['callback'])) {
     $arg = substr($_GET['q'], strlen($menu['items'][$mid]['path']) + 1);
     if (isset($arg)) {
-      return call_user_func_array($menu['items'][$mid]['callback'], explode('/', $arg));
+      call_user_func_array($menu['items'][$mid]['callback'], explode('/', $arg));
     }
     else {
-      return call_user_func($menu['items'][$mid]['callback']);
+      call_user_func($menu['items'][$mid]['callback']);
     }
+    return MENU_FOUND;
   }
+  
+  return MENU_FALLTHROUGH;
 }
 
 /**
@@ -211,11 +232,18 @@ function menu_active_handler_exists() {
   $menu = menu_get_menu();
 
   $path = $_GET['q'];
-  while ($path && (!$menu['path index'][$path] || !$menu['items'][$menu['path index'][$path]]['callback'])) {
+  while ($path && (!$menu['path index'][$path] || $menu['items'][$menu['path index'][$path]]['callback'] === MENU_FALLTHROUGH)) {
     $path = substr($path, 0, strrpos($path, '/'));
   }
   $mid = $menu['path index'][$path];
 
+  if ($menu['items'][$mid]['callback'] === MENU_FALLTHROUGH) {
+    return FALSE;
+  }
+  if ($menu['items'][$mid]['callback'] === MENU_DENIED) {
+    return FALSE;
+  }
+  
   return function_exists($menu['items'][$mid]['callback']);
 }
 
@@ -298,7 +326,7 @@ function menu_build() {
     while ($item = db_fetch_object($result)) {
       // First, add any custom items added by the administrator.
       if ($item->status == MENU_CUSTOM) {
-        $_menu['items'][$item->mid] = array('pid' => $item->pid, 'path' => $item->path, 'title' => $item->title, 'callback' => NULL, 'weight' => $item->weight, 'visibility' => MENU_SHOW, 'status' => MENU_CUSTOM);
+        $_menu['items'][$item->mid] = array('pid' => $item->pid, 'path' => $item->path, 'title' => $item->title, 'callback' => MENU_FALLTHROUGH, 'weight' => $item->weight, 'visibility' => MENU_SHOW, 'status' => MENU_CUSTOM);
         $_menu['path index'][$item->path] = $item->mid;
       }
       // Don't display non-custom menu items if no module declared them.
@@ -371,9 +399,12 @@ function menu_build_visible_tree($pid = 
         $children = array_merge($children, menu_build_visible_tree($mid));
       }
     }
-    if (($parent['visibility'] == MENU_SHOW) ||
-        ($parent['visibility'] == MENU_HIDE_NOCHILD && count($children) > 1)) {
+    if ((($parent['visibility'] == MENU_SHOW) ||
+        ($parent['visibility'] == MENU_HIDE_NOCHILD && count($children) > 1)) && $parent['callback'] !== MENU_DENIED) {
       $_menu['visible'][$pid] = array('title' => $parent['title'], 'path' => $parent['path'], 'children' => $children);
+      foreach ($children as $mid) {
+        $_menu['visible'][$mid]['pid'] = $pid;
+      }
       return array($pid);
     }
     else {
Index: modules/admin.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/admin.module,v
retrieving revision 1.43
diff -u -F^function -r1.43 admin.module
--- modules/admin.module	15 Feb 2004 20:09:46 -0000	1.43
+++ modules/admin.module	19 Apr 2004 21:23:14 -0000
@@ -12,9 +12,12 @@ function admin_help($section) {
   }
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function admin_link($type) {
-  if ($type == "system" && user_access("access administration pages")) {
-    menu("admin", t("administer"), "admin_admin", 9);
+  if ($type == 'system') {
+    menu('admin', t('administer'), user_access('access administration pages') ? 'admin_admin' : MENU_DENIED, 9);
   }
 }
 
Index: modules/aggregator.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/aggregator.module,v
retrieving revision 1.168
diff -u -F^function -r1.168 aggregator.module
--- modules/aggregator.module	15 Apr 2004 14:07:08 -0000	1.168
+++ modules/aggregator.module	19 Apr 2004 21:23:15 -0000
@@ -85,27 +85,28 @@ function aggregator_perm() {
   return array('administer news feeds', 'access news feeds');
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function aggregator_link($type) {
   if ($type == 'page' && user_access('access news feeds')) {
     return array(l(t('news feeds'), 'aggregator', array('title' => t('Read the latest news from syndicated web sites.'))));
   }
 
   if ($type == 'system') {
-    if (user_access('administer news feeds')) {
-      menu('admin/syndication', t('syndication'), 'aggregator_help_page', 5);
-      menu('admin/syndication/news', t('RSS/RDF'), 'aggregator_admin');
-      menu('admin/syndication/news/add/feed', t('new feed'), 'aggregator_admin', 2);
-      menu('admin/syndication/news/add/bundle', t('new bundle'), 'aggregator_admin', 3);
-      menu('admin/syndication/news/tag', t('tag items'), 'aggregator_admin', 4);
-      menu('admin/syndication/news/help', t('help'), 'aggregator_help_page', 9);
-    }
-
-    if (user_access('access news feeds')) {
-      menu('aggregator', t('news aggregator'), 'aggregator_page', 5);
-      menu('aggregator/feeds', t('news by source'), 'aggregator_page');
-      menu('aggregator/bundles', t('news by topic'), 'aggregator_page');
-      menu('aggregator/sources', t('news sources'), 'aggregator_page');
-    }
+    $access = user_access('administer news feeds');
+    menu('admin/syndication', t('syndication'), $access ? 'aggregator_help_page' : MENU_DENIED, 5);
+    menu('admin/syndication/news', t('RSS/RDF'), $access ? 'aggregator_admin' : MENU_DENIED);
+    menu('admin/syndication/news/add/feed', t('new feed'), $access ? 'aggregator_admin' : MENU_DENIED, 2);
+    menu('admin/syndication/news/add/bundle', t('new bundle'), $access ? 'aggregator_admin' : MENU_DENIED, 3);
+    menu('admin/syndication/news/tag', t('tag items'), $access ? 'aggregator_admin' : MENU_DENIED, 4);
+    menu('admin/syndication/news/help', t('help'), $access ? 'aggregator_help_page' : MENU_DENIED, 9);
+
+    $access = user_access('access news feeds');
+    menu('aggregator', t('news aggregator'), $access ? 'aggregator_page' : MENU_DENIED, 5);
+    menu('aggregator/feeds', t('news by source'), $access ? 'aggregator_page' : MENU_DENIED);
+    menu('aggregator/bundles', t('news by topic'), $access ? 'aggregator_page' : MENU_DENIED);
+    menu('aggregator/sources', t('news sources'), $access ? 'aggregator_page' : MENU_DENIED);
   }
 }
 
Index: modules/archive.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/archive.module,v
retrieving revision 1.51
diff -u -F^function -r1.51 archive.module
--- modules/archive.module	5 Mar 2004 20:57:05 -0000	1.51
+++ modules/archive.module	19 Apr 2004 21:23:15 -0000
@@ -182,18 +182,18 @@ function archive_block($op = "list", $de
   }
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function archive_link($type) {
-
   $links = array();
 
-  if ($type == "page" && user_access("access content")) {
-    $links[] = l(t("archives"), "archive", array("title" => t("Read the older content in our archive.")));
+  if ($type == 'page' && user_access('access content')) {
+    $links[] = l(t('archives'), 'archive', array('title' => t('Read the older content in our archive.')));
   }
 
-  if ($type == "system") {
-    if (user_access("access content")) {
-      menu("archive", t("archives"), "archive_page", 0, MENU_HIDE);
-    }
+  if ($type == 'system') {
+    menu('archive', t('archives'), user_access('access content') ? 'archive_page' : MENU_DENIED, 0, MENU_HIDE);
   }
 
   return $links;
Index: modules/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block.module,v
retrieving revision 1.110
diff -u -F^function -r1.110 block.module
--- modules/block.module	29 Mar 2004 18:56:21 -0000	1.110
+++ modules/block.module	19 Apr 2004 21:23:15 -0000
@@ -61,13 +61,15 @@ function block_perm() {
   return array("administer blocks");
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function block_link($type) {
-  if ($type == "system" && user_access("administer blocks")) {
-
-    menu("admin/system/block", t("blocks"), "block_admin", 3);
-    menu("admin/system/block/add", t("new block"), "block_admin", 2);
-    menu("admin/system/block/preview", t("preview placement"), "block_admin", 3);
-    menu("admin/system/block/help", t("help"), "block_help_page", 9);
+  if ($type == 'system') {
+    menu('admin/system/block', t('blocks'), user_access('administer blocks') ? 'block_admin' : MENU_DENIED, 3);
+    menu('admin/system/block/add', t('new block'), user_access('administer blocks') ? 'block_admin' : MENU_DENIED, 2);
+    menu('admin/system/block/preview', t('preview placement'), user_access('administer blocks') ? 'block_admin' : MENU_DENIED, 3);
+    menu('admin/system/block/help', t('help'), user_access('administer blocks') ? 'block_help_page' : MENU_DENIED, 9);
   }
 }
 
Index: modules/blog.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/blog.module,v
retrieving revision 1.171
diff -u -F^function -r1.171 blog.module
--- modules/blog.module	15 Apr 2004 20:49:41 -0000	1.171
+++ modules/blog.module	19 Apr 2004 21:23:15 -0000
@@ -211,31 +211,30 @@ function blog_view($node, $main = 0, $pa
   return theme("node", $node, $main, $page);
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function blog_link($type, $node = 0, $main) {
   global $user;
 
   $links = array();
 
-  if ($type == "system") {
-    if (user_access("maintain personal blog")) {
-      menu("node/add/blog", t("blog entry"), "node_page", 0);
-      menu("blog/". $user->uid, t("my blog"), "blog_page", 1, MENU_SHOW, MENU_LOCKED);
-    }
-    if (user_access("access content")) {
-      menu("blog", t("blogs"), "blog_page", 0, MENU_HIDE);
-    }
+  if ($type == 'system') {
+    menu('node/add/blog', t('blog entry'), user_access('maintain personal blog') ? 'node_page' : MENU_DENIED, 0);
+    menu('blog/'. $user->uid, t('my blog'), user_access('maintain personal blog') ? 'blog_page' : MENU_DENIED, 1, MENU_SHOW, MENU_LOCKED);
+    menu('blog', t('blogs'), user_access('access content') ? 'blog_page' : MENU_DENIED, 0, MENU_HIDE);
   }
 
-  if ($type == "page" && user_access("access content")) {
-    $links[] = l(t("blogs"), "blog", array("title" => t("Read the latest blog entries.")));
+  if ($type == 'page' && user_access('access content')) {
+    $links[] = l(t('blogs'), 'blog', array('title' => t('Read the latest blog entries.')));
   }
 
-  if ($type == "node" && $node->type == "blog") {
-    if (blog_access("update", $node)) {
-      $links[] = l(t("edit this blog entry"), "node/edit/$node->nid", array("title" => t("Edit this blog entry.")));
+  if ($type == 'node' && $node->type == 'blog') {
+    if (blog_access('update', $node)) {
+      $links[] = l(t('edit this blog entry'), "node/edit/$node->nid", array('title' => t('Edit this blog entry.')));
     }
     elseif (arg(0) != 'blog' && arg(1) != $node->uid) {
-      $links[] = l(t("%username's blog", array("%username" => $node->name)), "blog/$node->uid", array("title" => t("Read %username's latest blog entries.", array("%username" => $node->name))));
+      $links[] = l(t("%username's blog", array('%username' => $node->name)), "blog/$node->uid", array('title' => t("Read %username's latest blog entries.", array('%username' => $node->name))));
     }
   }
 
Index: modules/book.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/book.module,v
retrieving revision 1.217
diff -u -F^function -r1.217 book.module
--- modules/book.module	20 Mar 2004 13:29:06 -0000	1.217
+++ modules/book.module	19 Apr 2004 21:23:15 -0000
@@ -47,40 +47,38 @@ function book_access($op, $node) {
   }
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function book_link($type, $node = 0, $main = 0) {
 
   $links = array();
 
-  if ($type == "page" && user_access("access content")) {
-    $links[] = l(t("books"), "book", array("title" => t("Read and contribute to the collaborative books.")));
+  if ($type == 'page' && user_access('access content')) {
+    $links[] = l(t('books'), 'book', array('title' => t('Read and contribute to the collaborative books.')));
   }
 
-  if ($type == "node" && $node->type == "book") {
-    if (book_access("update", $node)) {
-      $links[] = l(t("edit this page"), "node/edit/$node->nid", array("title" => t("Suggest an update for this book page.")));
+  if ($type == 'node' && $node->type == 'book') {
+    if (book_access('update', $node)) {
+      $links[] = l(t('edit this page'), "node/edit/$node->nid", array('title' => t('Suggest an update for this book page.')));
     }
     if (!$main) {
-      $links[] = l(t("printer-friendly version"), "book/print/$node->nid", array("title" => t("Show a printer-friendly version of this book page and its sub-pages.")));
+      $links[] = l(t('printer-friendly version'), "book/print/$node->nid", array('title' => t('Show a printer-friendly version of this book page and its sub-pages.')));
     }
   }
 
-  if ($type == "system") {
-    if (user_access("maintain books")) {
-      menu("node/add/book", t("book page"), "node_page", 0);
-    }
-    if (user_access("administer nodes")) {
-      menu("admin/node/book", t("books"), "book_admin", 4);
-      menu("admin/node/book/orphan", t("orphan pages"), "book_admin_orphan", 8);
-      menu("admin/node/book/help", t("help"), "book_help_page", 9);
+  if ($type == 'system') {
+    menu('node/add/book', t('book page'), user_access('maintain books') ? 'node_page' : MENU_DENIED, 0);
 
-      $result = db_query("SELECT n.nid, n.title FROM {node} n INNER JOIN {book} b ON n.nid = b.nid WHERE b.parent = 0 ORDER BY b.weight, n.title");
-      while ($book = db_fetch_object($result)) {
-        menu("admin/node/book/$book->nid", t("'%title' book", array("%title" => $book->title)), "book_admin");
-      }
-    }
-    if (user_access("access content")) {
-      menu("book", t("books"), "book_page", 0, MENU_HIDE);
+    menu('admin/node/book', t('books'), user_access('administer nodes') ? 'book_admin' : MENU_DENIED, 4);
+    menu('admin/node/book/orphan', t('orphan pages'), user_access('administer nodes') ? 'book_admin_orphan' : MENU_DENIED, 8);
+    menu('admin/node/book/help', t('help'), user_access('administer nodes') ? 'book_help_page' : MENU_DENIED, 9);
+
+    $result = db_query("SELECT n.nid, n.title FROM {node} n INNER JOIN {book} b ON n.nid = b.nid WHERE b.parent = 0 ORDER BY b.weight, n.title");
+    while ($book = db_fetch_object($result)) {
+      menu("admin/node/book/$book->nid", t('"%title" book', array('%title' => $book->title)), user_access('administer nodes') ? 'book_admin' : MENU_DENIED);
     }
+    menu('book', t('books'), user_access('access content') ? 'book_page' : MENU_DENIED, 0, MENU_HIDE);
   }
 
   return $links;
@@ -677,7 +675,7 @@ function book_page() {
     }
   }
   else {
-    print theme("page", message_access());
+    drupal_access_denied();
   }
 }
 
Index: modules/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment.module,v
retrieving revision 1.234
diff -u -F^function -r1.234 comment.module
--- modules/comment.module	18 Apr 2004 15:17:10 -0000	1.234
+++ modules/comment.module	19 Apr 2004 21:23:16 -0000
@@ -716,10 +716,13 @@ function comment_perm() {
   return array("access comments", "post comments", "administer comments", "moderate comments", "post comments without approval", "administer moderation");
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function comment_link($type, $node = 0, $main = 0) {
   $links = array();
 
-  if ($type == "node" && $node->comment) {
+  if ($type == 'node' && $node->comment) {
 
     if ($main) {
 
@@ -727,24 +730,24 @@ function comment_link($type, $node = 0, 
       ** Main page: display the number of comments that have been posted.
       */
 
-      if (user_access("access comments")) {
+      if (user_access('access comments')) {
         $all = comment_num_all($node->nid);
         $new = comment_num_new($node->nid);
 
         if ($all) {
-          $links[] = l(format_plural($all, "1 comment", "%count comments"), "node/view/$node->nid", array("title" => t("Jump to the first comment of this posting.")), NULL, "comment");
+          $links[] = l(format_plural($all, '1 comment', '%count comments'), "node/view/$node->nid", array('title' => t('Jump to the first comment of this posting.')), NULL, 'comment');
 
           if ($new) {
-            $links[] = l(format_plural($new, "1 new comment", "%count new comments"), "node/view/$node->nid", array("title" => t("Jump to the first new comment of this posting.")), NULL, "new");
+            $links[] = l(format_plural($new, '1 new comment', '%count new comments'), "node/view/$node->nid", array('title' => t('Jump to the first new comment of this posting.')), NULL, 'new');
           }
         }
         else {
           if ($node->comment == 2) {
-            if (user_access("post comments")) {
-              $links[] = l(t("add new comment"), "comment/reply/$node->nid", array("title" => t("Add a new comment to this page.")));
+            if (user_access('post comments')) {
+              $links[] = l(t('add new comment'), "comment/reply/$node->nid", array('title' => t('Add a new comment to this page.')));
             }
             else {
-              $links[] = theme("comment_post_forbidden");
+              $links[] = theme('comment_post_forbidden');
             }
           }
         }
@@ -757,44 +760,42 @@ function comment_link($type, $node = 0, 
       */
 
       if ($node->comment == 2) {
-        if (user_access("post comments")) {
-          $links[] = l(t("add new comment"), "comment/reply/$node->nid", array("title" => t("Share your thoughts and opinions related to this posting.")), NULL, "comment");
+        if (user_access('post comments')) {
+          $links[] = l(t('add new comment'), "comment/reply/$node->nid", array('title' => t('Share your thoughts and opinions related to this posting.')), NULL, 'comment');
         }
         else {
-          $links[] = theme("comment_post_forbidden");
+          $links[] = theme('comment_post_forbidden');
         }
       }
     }
   }
 
-  if ($type == "comment") {
+  if ($type == 'comment') {
     $links = comment_links($node, $main);
   }
 
-  if ($type == "system") {
-    if (user_access("administer comments")) {
-
-      menu("admin/comment", t("comments"), "comment_admin", 1);
-      menu("admin/comment/comments", t("overview"), "comment_admin", 2);
-      menu("admin/comment/comments/0", t("new/updated"), "comment_admin", 1);
-      menu("admin/comment/comments/1", t("approval queue"), "comment_admin", 2);
-      menu("admin/comment/help", t("help"), "comment_help_page", 9);
-      menu("admin/comment/edit", t("edit comment"), "comment_admin", 0, MENU_HIDE, MENU_LOCKED);
-      menu("admin/comment/delete", t("delete comment"), "comment_admin", 0, MENU_HIDE, MENU_LOCKED);
-      if (module_exist('search')) {
-        menu("admin/comment/search", t("search"), "comment_admin", 8);
-      }
+  if ($type == 'system') {
+    $access = user_access('administer comments');
+    menu('admin/comment', t('comments'), $access ? 'comment_admin' : MENU_DENIED, 1);
+    menu('admin/comment/comments', t('overview'), $access ? 'comment_admin' : MENU_DENIED, 2);
+    menu('admin/comment/comments/0', t('new/updated'), $access ? 'comment_admin' : MENU_DENIED, 1);
+    menu('admin/comment/comments/1', t('approval queue'), $access ? 'comment_admin' : MENU_DENIED, 2);
+    menu('admin/comment/help', t('help'), $access ? 'comment_help_page' : MENU_DENIED, 9);
+    menu('admin/comment/edit', t('edit comment'), $access ? 'comment_admin' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/comment/delete', t('delete comment'), $access ? 'comment_admin' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    if (module_exist('search')) {
+      menu('admin/comment/search', t('search'), $access ? 'comment_admin' : MENU_DENIED, 8);
+    }
+
+    // comment settings:
+    $access = user_access('administer comments') && user_access('administer moderation');
+    menu('admin/comment/moderation', t('moderation'), $access ? 'comment_admin' : MENU_DENIED, 3);
+    menu('admin/comment/moderation/votes', t('votes'), $access ? 'comment_admin' : MENU_DENIED);
+    menu('admin/comment/moderation/matrix', t('matrix'), $access ? 'comment_admin' : MENU_DENIED);
+    menu('admin/comment/moderation/filters', t('thresholds'), $access ? 'comment_admin' : MENU_DENIED);
+    menu('admin/comment/moderation/roles', t('initial scores'), $access ? 'comment_admin' : MENU_DENIED, 6);
 
-      // comment settings:
-      if (user_access("administer moderation")) {
-        menu("admin/comment/moderation", t("moderation"), "comment_admin", 3);
-        menu("admin/comment/moderation/votes", t("votes"), "comment_admin");
-        menu("admin/comment/moderation/matrix", t("matrix"), "comment_admin");
-        menu("admin/comment/moderation/filters", t("thresholds"), "comment_admin");
-        menu("admin/comment/moderation/roles", t("initial scores"), "comment_admin", 6);
-      }
-    }
-    menu("comment", t("comments"), "comment_page", 0, MENU_HIDE, MENU_LOCKED);
+    menu('comment', t('comments'), 'comment_page', 0, MENU_HIDE, MENU_LOCKED);
   }
 
   return $links;
Index: modules/drupal.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/drupal.module,v
retrieving revision 1.75
diff -u -F^function -r1.75 drupal.module
--- modules/drupal.module	11 Mar 2004 20:33:58 -0000	1.75
+++ modules/drupal.module	19 Apr 2004 21:23:16 -0000
@@ -160,9 +160,12 @@ function drupal_auth($username, $passwor
   return $login;
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function drupal_link($type) {
-  if ($type == "system") {
-    menu("drupal", t("Drupal"), "drupal_page", 0, MENU_HIDE);
+  if ($type == 'system') {
+    menu('drupal', t('Drupal'), 'drupal_page', 0, MENU_HIDE);
   }
 }
 
Index: modules/filter.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter.module,v
retrieving revision 1.12
diff -u -F^function -r1.12 filter.module
--- modules/filter.module	15 Apr 2004 20:49:41 -0000	1.12
+++ modules/filter.module	19 Apr 2004 21:23:16 -0000
@@ -41,13 +41,14 @@ function filter_help($section = "admin/h
   }
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function filter_link($type) {
-  if ($type == "system") {
-    if (user_access("administer site configuration")) {
-      menu("admin/system/filters", t("filters"), "filter_admin", 5);
-      menu("admin/system/filters/order", t("ordering"), "filter_admin", 5);
-    }
-    menu("filter/tips", t("compose tips"), "filter_tips_long", 0, MENU_HIDE);
+  if ($type == 'system') {
+    menu('admin/system/filters', t('filters'), user_access('administer site configuration') ? 'filter_admin' : MENU_DENIED, 5);
+    menu('admin/system/filters/order', t('ordering'), user_access('administer site configuration') ? 'filter_admin' : MENU_DENIED, 5);
+    menu('filter/tips', t('compose tips'), 'filter_tips_long', 0, MENU_HIDE);
   }
 }
 
Index: modules/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum.module,v
retrieving revision 1.173
diff -u -F^function -r1.173 forum.module
--- modules/forum.module	20 Mar 2004 13:23:33 -0000	1.173
+++ modules/forum.module	19 Apr 2004 21:23:16 -0000
@@ -119,6 +119,9 @@ function forum_block($op = 'list', $delt
   return $blocks;
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function forum_link($type, $node = 0, $main = 0) {
   global $user;
 
@@ -129,12 +132,8 @@ function forum_link($type, $node = 0, $m
   }
 
   if ($type == 'system') {
-    if (user_access('create forum topics')) {
-      menu('node/add/forum', t('forum topic'), 'node_page');
-    }
-    if (user_access('access content')) {
-      menu('forum', t('forums'), 'forum_page', 0, MENU_HIDE);
-    }
+    menu('node/add/forum', t('forum topic'), user_access('create forum topics') ? 'node_page' : MENU_DENIED);
+    menu('forum', t('forums'), user_access('access content') ? 'forum_page' : MENU_DENIED, 0, MENU_HIDE);
   }
 
   if (!$main && $type == 'node' && $node->type == 'forum') {
Index: modules/help.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/help.module,v
retrieving revision 1.30
diff -u -F^function -r1.30 help.module
--- modules/help.module	23 Jan 2004 18:42:43 -0000	1.30
+++ modules/help.module	19 Apr 2004 21:23:16 -0000
@@ -1,10 +1,13 @@
 <?php
 // $Id: help.module,v 1.30 2004/01/23 18:42:43 dries Exp $
 
+/**
+ * Implementation of hook_link().
+ */
 function help_link($type) {
-  if ($type == "system" && user_access("access administration pages")) {
-    menu("admin/help/glossary", t("glossary"), "help_glossary", 8);
-    menu("admin/help", t("help"), "help_help_page", 9);
+  if ($type == 'system') {
+    menu('admin/help/glossary', t('glossary'), user_access('access administration pages') ? 'help_glossary' : MENU_DENIED, 8);
+    menu('admin/help', t('help'), user_access('access administration pages') ? 'help_help_page' : MENU_DENIED, 9);
   }
 }
 
Index: modules/locale.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale.module,v
retrieving revision 1.98
diff -u -F^function -r1.98 locale.module
--- modules/locale.module	15 Apr 2004 20:49:41 -0000	1.98
+++ modules/locale.module	19 Apr 2004 21:23:16 -0000
@@ -51,23 +51,24 @@ function locale_perm() {
   return array('administer locales');
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function locale_link($type) {
   global $languages;
 
-  if ($type == "system") {
-    if (user_access('administer locales')) {
+  if ($type == 'system') {
+    $access = user_access('administer locales');
+    menu('admin/locale', t('localization'), $access ? 'locale_admin' : MENU_DENIED, 5);
+    menu('admin/locale/search', t('search string'), $access ? 'locale_admin' : MENU_DENIED, 8);
+    menu('admin/locale/help', t('help'), $access ? 'locale_help_page' : MENU_DENIED, 9);
+    menu('admin/locale/edit', t('edit string'), $access ? 'locale_admin' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/locale/delete', t('delete string'), $access ? 'locale_admin' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
 
-      menu("admin/locale", t("localization"), "locale_admin", 5);
-      menu("admin/locale/search", t("search string"), "locale_admin", 8);
-      menu("admin/locale/help", t("help"), "locale_help_page", 9);
-      menu("admin/locale/edit", t("edit string"), "locale_admin", 0, MENU_HIDE, MENU_LOCKED);
-      menu("admin/locale/delete", t("delete string"), "locale_admin", 0, MENU_HIDE, MENU_LOCKED);
-
-      foreach ($languages as $key => $value) {
-        menu("admin/locale/$key", "$value", "locale_admin");
-        menu("admin/locale/$key/translated", t("translated strings"), "locale_admin");
-        menu("admin/locale/$key/untranslated", t("untranslated strings"), "locale_admin");
-      }
+    foreach ($languages as $key => $value) {
+      menu("admin/locale/$key", "$value", $access ? 'locale_admin' : MENU_DENIED);
+      menu("admin/locale/$key/translated", t('translated strings'), $access ? 'locale_admin' : MENU_DENIED);
+      menu("admin/locale/$key/untranslated", t('untranslated strings'), $access ? 'locale_admin' : MENU_DENIED);
     }
   }
 }
Index: modules/menu.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu.module,v
retrieving revision 1.1
diff -u -F^function -r1.1 menu.module
--- modules/menu.module	15 Apr 2004 20:49:41 -0000	1.1
+++ modules/menu.module	19 Apr 2004 21:23:16 -0000
@@ -5,15 +5,15 @@
  * Implementation of hook_link().
  */
 function menu_link($type, $node = 0, $main) {
-  if ($type == 'system' && user_access('administer menu')) {
-    menu('admin/menu', t('menus'), 'menu_overview', 0, MENU_SHOW);
-    menu('admin/menu/reset', t('reset all menus'), 'menu_reset', 0, MENU_SHOW);
-    menu('admin/menu/menu/add', t('add menu'), 'menu_add_menu', 0, MENU_SHOW);
-    menu('admin/menu/item/add', t('add menu item'), 'menu_edit_item', 0, MENU_SHOW);
-    menu('admin/menu/item/edit', t('edit menu item'), 'menu_edit_item', 0, MENU_HIDE, MENU_LOCKED);
-    menu('admin/menu/item/reset', t('reset menu item'), 'menu_reset_item', 0, MENU_HIDE, MENU_LOCKED);
-    menu('admin/menu/item/disable', t('disable menu item'), 'menu_disable_item', 0, MENU_HIDE, MENU_LOCKED);
-    menu('admin/menu/item/delete', t('delete menu item'), 'menu_delete_item', 0, MENU_HIDE, MENU_LOCKED);
+  if ($type == 'system') {
+    menu('admin/menu', t('menus'), user_access('administer menu') ? 'menu_overview' : MENU_DENIED, 0, MENU_SHOW);
+    menu('admin/menu/reset', t('reset all menus'), user_access('administer menu') ? 'menu_reset' : MENU_DENIED, 0, MENU_SHOW);
+    menu('admin/menu/menu/add', t('add menu'), user_access('administer menu') ? 'menu_add_menu' : MENU_DENIED, 0, MENU_SHOW);
+    menu('admin/menu/item/add', t('add menu item'), user_access('administer menu') ? 'menu_edit_item' : MENU_DENIED, 0, MENU_SHOW);
+    menu('admin/menu/item/edit', t('edit menu item'), user_access('administer menu') ? 'menu_edit_item' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/menu/item/reset', t('reset menu item'), user_access('administer menu') ? 'menu_reset_item' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/menu/item/disable', t('disable menu item'), user_access('administer menu') ? 'menu_disable_item' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/menu/item/delete', t('delete menu item'), user_access('administer menu') ? 'menu_delete_item' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
   }
 }
 
Index: modules/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node.module,v
retrieving revision 1.347
diff -u -F^function -r1.347 node.module
--- modules/node.module	15 Apr 2004 20:49:41 -0000	1.347
+++ modules/node.module	19 Apr 2004 21:23:16 -0000
@@ -589,6 +589,9 @@ function node_comment_mode($nid) {
   return $comment_mode[$nid];
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function node_link($type, $node = 0, $main = 0) {
 
   $links = array();
@@ -614,19 +617,15 @@ function node_link($type, $node = 0, $ma
   if ($type == 'system') {
     menu('node/add', t('create content'), 'node_page', 1, MENU_HIDE_NOCHILD);
 
-    if (user_access('administer nodes')) {
-      menu('admin/node', t('content'), 'node_admin');
-      menu('admin/node/help', t('help'), 'node_help_page', 9);
-      menu('admin/node/edit', t('edit post'), 'node_admin', 0, MENU_HIDE, MENU_LOCKED);
-      menu('admin/node/settings', t('settings'), 'node_admin', 8);
-      if (module_exist('search')) {
-        menu('admin/node/search', t('search'), 'node_admin', 8);
-      }
+    menu('admin/node', t('content'), user_access('administer nodes') ? 'node_admin' : MENU_DENIED);
+    menu('admin/node/help', t('help'), user_access('administer nodes') ? 'node_help_page' : MENU_DENIED, 9);
+    menu('admin/node/edit', t('edit post'), user_access('administer nodes') ? 'node_admin' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/node/settings', t('settings'), user_access('administer nodes') ? 'node_admin' : MENU_DENIED, 8);
+    if (module_exist('search')) {
+      menu('admin/node/search', t('search'), user_access('administer nodes') ? 'node_admin' : MENU_DENIED, 8);
     }
 
-    if (user_access('access content')) {
-      menu('node', t('content'), 'node_page', 0, MENU_HIDE);
-    }
+    menu('node', t('content'), user_access('access content') ? 'node_page' : MENU_DENIED, 0, MENU_HIDE);
   }
 
   return $links;
@@ -1274,7 +1273,6 @@ function node_add($type) {
     }
     $output = node_form($node);
     drupal_set_title(t('Submit %name', array('%name' => node_invoke($node, 'node_name'))));
-    drupal_set_breadcrumb(array(l(t('Home'), NULL), l(t('create content'), 'node/add')));
   }
   else {
 
@@ -1292,7 +1290,6 @@ function node_add($type) {
     }
 
     $output = t('Choose the appropriate item from the list:') ."<ul>$output</ul>";
-    drupal_set_breadcrumb(array(l(t('Home'), NULL)));
   }
 
   return $output;
Index: modules/page.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/page.module,v
retrieving revision 1.111
diff -u -F^function -r1.111 page.module
--- modules/page.module	10 Mar 2004 09:32:46 -0000	1.111
+++ modules/page.module	19 Apr 2004 21:23:16 -0000
@@ -94,21 +94,19 @@ function page_load($node) {
 }
 
 /**
- * Define internal Drupal links.
+ * Implementation of hook_link().
  */
 function page_link($type, $node = 0, $main) {
 
   $links = array();
 
   if ($type == 'system') {
-    if (page_access('create', $node)) {
-      menu("node/add/page", t("page"), "node_page", 0);
-    }
+    menu('node/add/page', t('page'), page_access('create', $node) ? 'node_page' : MENU_DENIED, 0);
   }
 
   if ($type == 'node' && $node->type == 'page') {
     /* Don't display a redundant edit link if they are node administrators */
-    if (page_access("update", $node) && !user_access('administer nodes')) {
+    if (page_access('update', $node) && !user_access('administer nodes')) {
       $links[] = l(t('edit this page'), "node/edit/$node->nid");
     }
   }
Index: modules/path.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/path.module,v
retrieving revision 1.29
diff -u -F^function -r1.29 path.module
--- modules/path.module	20 Mar 2004 13:29:06 -0000	1.29
+++ modules/path.module	19 Apr 2004 21:23:16 -0000
@@ -143,11 +143,14 @@ function conf_url_rewrite(\$path, \$mode
   return $output;
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function path_link($type, $node = NULL) {
-  if ($type == "system" && user_access("administer url aliases")) {
-    menu("admin/path", t("url aliasing"), "path_admin", 4);
-    menu("admin/path/add", t("new alias"), "path_admin");
-    menu("admin/path/help", t("help"), "path_admin", 9);
+  if ($type == 'system') {
+    menu('admin/path', t('url aliasing'), user_access('administer url aliases') ? 'path_admin' : MENU_DENIED, 4);
+    menu('admin/path/add', t('new alias'), user_access('administer url aliases') ? 'path_admin' : MENU_DENIED);
+    menu('admin/path/help', t('help'), user_access('administer url aliases') ? 'path_admin' : MENU_DENIED, 9);
   }
 }
 
Index: modules/poll.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/poll.module,v
retrieving revision 1.132
diff -u -F^function -r1.132 poll.module
--- modules/poll.module	14 Apr 2004 14:02:36 -0000	1.132
+++ modules/poll.module	19 Apr 2004 21:23:16 -0000
@@ -163,16 +163,15 @@ function poll_insert($node) {
   }
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function poll_link($type, $node = 0, $main) {
   $links = array();
 
   if ($type == 'system') {
-    if (user_access("create polls")) {
-      menu('node/add/poll', t('poll'), 'node_page', 0);
-    }
-    if (user_access('access content')) {
-      menu('poll', t('polls'), 'poll_page', 0, MENU_HIDE);
-    }
+    menu('node/add/poll', t('poll'), user_access('create polls') ? 'node_page' : MENU_DENIED, 0);
+    menu('poll', t('polls'), user_access('access content') ? 'poll_page' : MENU_DENIED, 0, MENU_HIDE);
   }
   else if ($type == 'page' && user_access('access content')) {
     $links[] = l(t('polls'), 'poll', array('title' => t('View the list of polls on this site.')));
Index: modules/profile.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/profile.module,v
retrieving revision 1.52
diff -u -F^function -r1.52 profile.module
--- modules/profile.module	15 Apr 2004 20:49:41 -0000	1.52
+++ modules/profile.module	19 Apr 2004 21:23:16 -0000
@@ -14,16 +14,17 @@ function profile_help($section) {
 
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function profile_link($type) {
   if ($type == 'system') {
     menu('profile', t('browse'), 'profile_browse', 0, MENU_HIDE);
 
-    if (user_access('administer users')) {
-      menu('admin/system/modules/profile', t('profile'), 'profile_admin_overview');
-      menu('admin/system/modules/profile/add', NULL, 'profile_admin_add', 0, MENU_HIDE, MENU_LOCKED);
-      menu('admin/system/modules/profile/edit', NULL, 'profile_admin_edit', 0, MENU_HIDE, MENU_LOCKED);
-      menu('admin/system/modules/profile/delete', NULL, 'profile_admin_delete', 0, MENU_HIDE, MENU_LOCKED);
-    }
+    menu('admin/system/modules/profile', t('profile'), user_access('administer users') ? 'profile_admin_overview' : MENU_DENIED);
+    menu('admin/system/modules/profile/add', NULL, user_access('administer users') ? 'profile_admin_add' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/system/modules/profile/edit', NULL, user_access('administer users') ? 'profile_admin_edit' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    menu('admin/system/modules/profile/delete', NULL, user_access('administer users') ? 'profile_admin_delete' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
   }
 }
 
Index: modules/queue.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/queue.module,v
retrieving revision 1.106
diff -u -F^function -r1.106 queue.module
--- modules/queue.module	15 Feb 2004 20:09:46 -0000	1.106
+++ modules/queue.module	19 Apr 2004 21:23:17 -0000
@@ -31,13 +31,14 @@ function queue_perm() {
   return array("access submission queue");
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function queue_link($type) {
   $links = array();
 
-  if ($type == "system") {
-    if (user_access("access submission queue")) {
-      menu("queue", t("submission queue"), "queue_page", 1);
-    }
+  if ($type == 'system') {
+    menu('queue', t('submission queue'), user_access('access submission queue') ? 'queue_page' : MENU_DENIED, 1);
   }
 
   return $links;
Index: modules/search.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/search.module,v
retrieving revision 1.75
diff -u -F^function -r1.75 search.module
--- modules/search.module	13 Apr 2004 21:33:27 -0000	1.75
+++ modules/search.module	19 Apr 2004 21:23:17 -0000
@@ -30,20 +30,17 @@ function search_perm() {
 }
 
 /**
- * Return an array of links to be displayed
- *
- * @param $type The type of page requesting the link
- *
+ * Implementation of hook_link().
  */
 function search_link($type) {
   $links = array();
 
-  if ($type == "page" && user_access("search content")) {
-    $links[] = l(t("search"), "search", array("title" => t("Search for older content.")));
+  if ($type == 'page' && user_access('search content')) {
+    $links[] = l(t('search'), 'search', array('title' => t('Search for older content.')));
   }
 
-  if ($type == "system" && user_access("search content")) {
-    menu("search", t("search"), "search_page", 0, MENU_HIDE);
+  if ($type == 'system') {
+    menu('search', t('search'), user_access('search content') ? 'search_page' : MENU_DENIED, 0, MENU_HIDE);
   }
 
   return $links;
@@ -360,7 +357,7 @@ function search_view($keys) {
     print theme("page", $output, t("Search"));
   }
   else {
-    print theme("page", message_access());
+    drupal_access_denied();
   }
 
 }
Index: modules/statistics.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/statistics.module,v
retrieving revision 1.143
diff -u -F^function -r1.143 statistics.module
--- modules/statistics.module	18 Apr 2004 12:51:55 -0000	1.143
+++ modules/statistics.module	19 Apr 2004 21:23:17 -0000
@@ -119,46 +119,44 @@ function statistics_perm() {
   return array("administer statistics module", "administer statistics", "access statistics");
 }
 
-/* Link hook, defines module's links */
+/**
+ * Implementation of hook_link().
+ */
 function statistics_link($type, $node = 0, $main = 0) {
   global $id;
 
   $links = array();
 
-  if ($type == "node" && user_access("access statistics") && variable_get("statistics_display_counter", 0)) {
+  if ($type == 'node' && user_access('access statistics') && variable_get('statistics_display_counter', 0)) {
     $statistics = statistics_get($node->nid);
     if ($statistics) {
-      if (user_access("administer statistics")) {
-        $links[] = l(format_plural($statistics["totalcount"], "1 read", "%count reads"), "admin/logs/access/node/$node->nid");
+      if (user_access('administer statistics')) {
+        $links[] = l(format_plural($statistics['totalcount'], '1 read', '%count reads'), "admin/logs/access/node/$node->nid");
       }
       else {
-        $links[] = format_plural($statistics["totalcount"], "1 read", "%count reads");
+        $links[] = format_plural($statistics['totalcount'], '1 read', '%count reads');
       }
     }
   }
 
-  if ($type == "page" && user_access("access content")) {
-    $userlink = variable_get("statistics_userpage_link", "");
+  if ($type == 'page' && user_access('access content')) {
+    $userlink = variable_get('statistics_userpage_link', '');
     if ($userlink) {
-      $links[] = l(t($userlink), "statistics", array("title" => t("View this site's most popular content.")));
+      $links[] = l(t($userlink), 'statistics', array('title' => t("View this site's most popular content.")));
     }
   }
 
-  if ($type == "system") {
-    if ((user_access("administer statistics module") || (user_access("administer statistics")))) {
-      menu("admin/logs/topnodes", t("top nodes"), "statistics_admin", 1);
-      menu("admin/logs/referrer", t("referrer"), "statistics_admin", 2);
-      menu("admin/logs/referrer/internal", t("internal referrers only"), "statistics_admin");
-      menu("admin/logs/referrer/external", t("external referrers only"), "statistics_admin");
-      menu("admin/logs/access", t("access"), "statistics_admin", 3);
-      menu("admin/logs/access/node", t("track node"), "statistics_admin", 0, MENU_HIDE);
-      menu("admin/logs/access/user", t("track user"), "statistics_admin", 0, MENU_HIDE);
-      menu("admin/logs/access/host", t("track host"), "statistics_admin", 0, MENU_HIDE);
-    }
+  if ($type == 'system') {
+    $access = user_access('administer statistics module') || user_access('administer statistics');
 
-    if (user_access("access content")) {
-      menu("statistics", t("view most popular content"), "statistics_page", 0, MENU_HIDE);
-    }
+    menu('admin/logs/topnodes', t('top nodes'), $access ? 'statistics_admin' : MENU_DENIED, 1);
+    menu('admin/logs/referrer', t('referrer'), $access ? 'statistics_admin' : MENU_DENIED, 2);
+    menu('admin/logs/referrer/internal', t('internal referrers only'), $access ? 'statistics_admin' : MENU_DENIED);
+    menu('admin/logs/referrer/external', t('external referrers only'), $access ? 'statistics_admin' : MENU_DENIED);
+    menu('admin/logs/access', t('access'), $access ? 'statistics_admin' : MENU_DENIED, 3);
+    menu('admin/logs/access/node', t('track node'), $access ? 'statistics_admin' : MENU_DENIED, 0, MENU_HIDE);
+    menu('admin/logs/access/user', t('track user'), $access ? 'statistics_admin' : MENU_DENIED, 0, MENU_HIDE);
+    menu('admin/logs/access/host', t('track host'), $access ? 'statistics_admin' : MENU_DENIED, 0, MENU_HIDE);
   }
 
   return $links;
Index: modules/story.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/story.module,v
retrieving revision 1.145
diff -u -F^function -r1.145 story.module
--- modules/story.module	15 Mar 2004 19:39:33 -0000	1.145
+++ modules/story.module	19 Apr 2004 21:23:17 -0000
@@ -82,20 +82,18 @@ function story_access($op, $node) {
 }
 
 /**
- * Define internal Drupal links.
+ * Implementation of hook_link().
  */
 function story_link($type, $node = 0, $main) {
   $links = array();
 
-  if ($type == "system") {
-    if (story_access('create', $node)) {
-      menu("node/add/story", t("story"), "node_page", 0);
-    }
+  if ($type == 'system') {
+    menu('node/add/story', t('story'), story_access('create', $node) ? 'node_page' : MENU_DENIED, 0);
   }
 
   if ($type == 'node' && $node->type == 'story') {
     /* Don't display a redundant edit link if they are node administrators */
-    if (story_access("update", $node) && !user_access('administer nodes')) {
+    if (story_access('update', $node) && !user_access('administer nodes')) {
       $links[] = l(t('edit this story'), "node/edit/$node->nid");
     }
   }
Index: modules/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system.module,v
retrieving revision 1.134
diff -u -F^function -r1.134 system.module
--- modules/system.module	21 Mar 2004 14:28:15 -0000	1.134
+++ modules/system.module	19 Apr 2004 21:23:17 -0000
@@ -45,34 +45,36 @@ function system_perm() {
   return array("administer site configuration", "access administration pages", "bypass input data check", "create php content");
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function system_link($type) {
-  if ($type == "system") {
-    menu("system/files", t("file download"), "file_download", 0, MENU_HIDE);
-    if (user_access("administer site configuration")) {
-
-      menu("admin/system", t("configuration"), "system_admin", 3);
-      menu("admin/system/themes", t("themes"), "system_admin", 2);
-
-      foreach (list_themes() as $theme) {
-        // TODO: reenable 'forced refresh' once we move the menu_build() later in the request. it added overhead with no benefit
-        // NOTE: refresh the list because some themes might have been enabled/disabled.
-        include_once "$theme->filename";
-        $function = $theme->name ."_settings";
-        if (function_exists($function)) {
-          menu("admin/system/themes/$theme->name", $theme->name, "system_admin");
-        }
+  if ($type == 'system') {
+    menu('system/files', t('file download'), 'file_download', 0, MENU_HIDE, MENU_LOCKED);
+    $access = user_access('administer site configuration');
+
+    menu('admin/system', t('configuration'), $access ? 'system_admin' : MENU_DENIED, 3);
+    menu('admin/system/themes', t('themes'), $access ? 'system_admin' : MENU_DENIED, 2);
+
+    foreach (list_themes() as $theme) {
+      // TODO: reenable 'forced refresh' once we move the menu_build() later in the request. it added overhead with no benefit
+      // NOTE: refresh the list because some themes might have been enabled/disabled.
+      include_once "$theme->filename";
+      $function = $theme->name .'_settings';
+      if (function_exists($function)) {
+        menu("admin/system/themes/$theme->name", $theme->name, $access ? 'system_admin' : MENU_DENIED);
       }
+    }
 
-      menu("admin/system/modules", t("modules"), "system_admin", 3);
-      foreach (module_list() as $name) {
-        // TODO: reenable 'forced refresh' once we move the menu_build() later in the request.  it added overhead with no benefit
-        // NOTE: refresh the list because some modules might have been enabled/disabled.
-        if (module_hook($name, "settings")) {
-          menu("admin/system/modules/$name", t($name), "system_admin");
-        }
+    menu('admin/system/modules', t('modules'), $access ? 'system_admin' : MENU_DENIED, 3);
+    foreach (module_list() as $name) {
+      // TODO: reenable 'forced refresh' once we move the menu_build() later in the request.  it added overhead with no benefit
+      // NOTE: refresh the list because some modules might have been enabled/disabled.
+      if (module_hook($name, 'settings')) {
+        menu("admin/system/modules/$name", t($name), $access ? 'system_admin' : MENU_DENIED);
       }
-      menu("admin/system/help", t("help"), "system_help_page", 9);
     }
+    menu('admin/system/help', t('help'), $access ? 'system_help_page' : MENU_DENIED, 9);
   }
 }
 
@@ -114,6 +116,7 @@ function system_view_general() {
   $group .= form_textarea(t("Footer message"), "site_footer", variable_get("site_footer", ""), 70, 5, t("This text will be displayed at the bottom of each page.  Useful for adding a copyright notice to your pages."));
   $group .= form_textfield(t("Anonymous user"), "anonymous", variable_get("anonymous", "Anonymous"), 70, 70, t("The name used to indicate anonymous users."));
   $group .= form_textfield(t("Default front page"), "site_frontpage", variable_get("site_frontpage", "node"), 70, 70, t("The home page displays content from this relative URL.  If you are not using clean URLs, specify the part after '?q='.  If unsure, specify 'node'."));
+  $group .= form_textfield(t("Default 403 (access denied) page"), "site_403", variable_get("site_403", ""), 70, 70, t("This page is displayed when the requested document is denied to the current user.  If you are not using clean URLs, specify the part after '?q='.  If unsure, specify nothing."));
   $group .= form_textfield(t("Default 404 (not found) page"), "site_404", variable_get("site_404", ""), 70, 70, t("This page is displayed when no other content matches the requested document.  If you are not using clean URLs, specify the part after '?q='.  If unsure, specify nothing."));
   $group .= form_radios(t("Clean URLs"), "clean_url", variable_get("clean_url", 0), array(t("Disabled"), t("Enabled")), t("Enable or disable clean URLs.  If enabled, you'll need <code>ModRewrite</code> support.  See also the <code>.htaccess</code> file in Drupal's top-level directory."));
 
Index: modules/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy.module,v
retrieving revision 1.110
diff -u -F^function -r1.110 taxonomy.module
--- modules/taxonomy.module	18 Apr 2004 14:03:33 -0000	1.110
+++ modules/taxonomy.module	19 Apr 2004 21:23:17 -0000
@@ -21,18 +21,26 @@ function taxonomy_perm() {
   return array("administer taxonomy");
 }
 
+/**
+ * Implementation of hook_link().
+ *
+ * This hook is extended with $type = 'taxonomy terms' to allow themes to
+ * print lists of terms associated with a node. Themes can print taxonomy
+ * links with:
+ *
+ * if (module_exist('taxonomy')) {
+ *   $this->links(taxonomy_link('taxonomy terms', $node));
+ * }
+ */
 function taxonomy_link($type, $node = NULL) {
-  if ($type == "system") {
-    if (user_access("administer taxonomy")) {
-      menu("admin/taxonomy", t("categories"), "taxonomy_admin", 3);
-      menu("admin/taxonomy/add/vocabulary", t("create new vocabulary"), "taxonomy_admin");
-      menu("admin/taxonomy/help", t("help"), "taxonomy_admin", 9);
-    }
-    if (user_access("access content")) {
-      menu("taxonomy", t("taxonomy"), "taxonomy_page", 0, MENU_HIDE, MENU_LOCKED);
-    }
+  if ($type == 'system') {
+      menu('admin/taxonomy', t('categories'), user_access('administer taxonomy') ? 'taxonomy_admin' : MENU_DENIED, 3);
+      menu('admin/taxonomy/add/vocabulary', t('create new vocabulary'), user_access('administer taxonomy') ? 'taxonomy_admin' : MENU_DENIED);
+      menu('admin/taxonomy/help', t('help'), user_access('administer taxonomy') ? 'taxonomy_admin' : MENU_DENIED, 9);
+
+      menu('taxonomy', t('taxonomy'), user_access('access content') ? 'taxonomy_page' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
   }
-  else if ($type == "taxonomy terms" && $node != NULL) {
+  else if ($type == 'taxonomy terms' && $node != NULL) {
     $links = array();
     if ($node->taxonomy) {
       foreach ($node->taxonomy as $tid) {
@@ -41,15 +49,6 @@ function taxonomy_link($type, $node = NU
       }
     }
     else {
-
-    /*
-    ** Themes can print taxonomy links with:
-    **
-    ** if (module_exist("taxonomy")) {
-    **   $this->links(taxonomy_link("taxonomy terms", $node));
-    ** }
-    */
-
       $links = array();
       foreach (taxonomy_node_get_terms($node->nid) as $term) {
         $links[] = l($term->name, "taxonomy/page/or/$term->tid");
Index: modules/title.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/title.module,v
retrieving revision 1.30
diff -u -F^function -r1.30 title.module
--- modules/title.module	15 Apr 2004 20:49:41 -0000	1.30
+++ modules/title.module	19 Apr 2004 21:23:17 -0000
@@ -13,11 +13,12 @@ function title_help($section) {
   return $output;
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function title_link($type) {
-  if ($type == "system") {
-    if (user_access("access content")) {
-      menu("title", t("search"), "title_page", 0, MENU_HIDE, MENU_LOCKED);
-    }
+  if ($type == 'system') {
+    menu('title', t('search'), user_access('access content') ? 'title_page' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
   }
 }
 
Index: modules/tracker.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/tracker.module,v
retrieving revision 1.82
diff -u -F^function -r1.82 tracker.module
--- modules/tracker.module	1 Apr 2004 18:57:41 -0000	1.82
+++ modules/tracker.module	19 Apr 2004 21:23:17 -0000
@@ -10,9 +10,12 @@ function tracker_help($section = 'admin/
   }
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function tracker_link($type) {
-  if ($type == 'system' && user_access('access content')) {
-    menu('tracker', t('recent posts'), 'tracker_page', 1);
+  if ($type == 'system') {
+    menu('tracker', t('recent posts'), user_access('access content') ? 'tracker_page' : MENU_DENIED, 1);
   }
 }
 
Index: modules/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user.module,v
retrieving revision 1.314
diff -u -F^function -r1.314 user.module
--- modules/user.module	15 Apr 2004 20:49:41 -0000	1.314
+++ modules/user.module	19 Apr 2004 21:23:18 -0000
@@ -529,34 +529,36 @@ function theme_user_list($items, $title 
   return theme("item_list", $items, $title);
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function user_link($type) {
   global $user;
 
-  if ($type == "system") {
-    if ($user->uid) {
-      menu('user', t("my account"), "user_page", 8);
-      menu("user/edit", t("edit account"), "user_page", 0);
-      menu("logout", t("log out"), "user_logout", 10);
-    }
-    else {
-      menu("user/login", t("log in"), "user_page", 0, MENU_HIDE);
-    }
-    menu("user/password", t("e-mail new password"), "user_page", 0, MENU_HIDE);
-    menu("user/register", t("create new account"), "user_page", 0, MENU_HIDE);
-
-    if (user_access("administer users")) {
-      menu("admin/user", t("accounts"), "user_admin", 2);
-      menu("admin/user/create", t("new user"), "user_admin", 1);
-      menu("admin/user/access", t("access rules"), "user_admin", 3);
-      menu("admin/user/access/mail", t("e-mail rules"), "user_admin");
-      menu("admin/user/access/user", t("name rules"), "user_admin");
-      menu("admin/user/role", t("roles"), "user_admin", 4);
-      menu("admin/user/permission", t("permissions"), "user_admin", 5);
-      menu("admin/user/help", t("help"), "user_help_page", 9);
-      menu("admin/user/edit", t("edit user account"), "user_admin", 0, MENU_HIDE, MENU_LOCKED);
-      if (module_exist('search')) {
-        menu("admin/user/search", t("search"), "user_admin", 8);
-      }
+  if ($type == 'system') {
+    $access = $user->uid;
+    menu('user', t('my account'), $access ? 'user_page' : MENU_DENIED, 8);
+    menu('user/edit', t('edit account'), $access ? 'user_page' : MENU_DENIED, 0);
+    menu('logout', t('log out'), $access ? 'user_logout' : MENU_DENIED, 10);
+    
+    if (!$user->uid) {
+      menu('user/login', t('log in'), 'user_page', 0, MENU_HIDE);
+      menu('user/password', t('e-mail new password'), 'user_page', 0, MENU_HIDE);
+      menu('user/register', t('create new account'), 'user_page', 0, MENU_HIDE);
+    }
+
+    $access = user_access('administer users');
+    menu('admin/user', t('accounts'), $access ? 'user_admin' : MENU_DENIED, 2);
+    menu('admin/user/create', t('new user'), $access ? 'user_admin' : MENU_DENIED, 1);
+    menu('admin/user/access', t('access rules'), $access ? 'user_admin' : MENU_DENIED, 3);
+    menu('admin/user/access/mail', t('e-mail rules'), $access ? 'user_admin' : MENU_DENIED);
+    menu('admin/user/access/user', t('name rules'), $access ? 'user_admin' : MENU_DENIED);
+    menu('admin/user/role', t('roles'), $access ? 'user_admin' : MENU_DENIED, 4);
+    menu('admin/user/permission', t('permissions'), $access ? 'user_admin' : MENU_DENIED, 5);
+    menu('admin/user/help', t('help'), $access ? 'user_help_page' : MENU_DENIED, 9);
+    menu('admin/user/edit', t('edit user account'), $access ? 'user_admin' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+    if (module_exist('search')) {
+      menu('admin/user/search', t('search'), $access ? 'user_admin' : MENU_DENIED, 8);
     }
   }
 }
@@ -1172,7 +1174,7 @@ function user_page() {
         print theme('page', $output, t("Create new account"));
       }
       else {
-        print theme('page', message_access());
+        drupal_access_denied();
       }
       break;
     case t("Log in"):
Index: modules/watchdog.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/watchdog.module,v
retrieving revision 1.97
diff -u -F^function -r1.97 watchdog.module
--- modules/watchdog.module	18 Apr 2004 12:51:55 -0000	1.97
+++ modules/watchdog.module	19 Apr 2004 21:23:18 -0000
@@ -49,14 +49,16 @@ function watchdog_perm() {
   return array("administer watchdog");
 }
 
+/**
+ * Implementation of hook_link().
+ */
 function watchdog_link($type) {
-  if ($type == "system") {
-    if (user_access("administer watchdog")) {
-      menu("admin/logs", t("logs"), "watchdog_admin", 7);
-      menu("admin/logs/view", t("view details"), "watchdog_admin", 0, MENU_HIDE, MENU_LOCKED);
-      foreach (_watchdog_get_message_types() as $type) {
-        menu("admin/logs/$type", t($type), "watchdog_admin");
-      }
+  if ($type == 'system') {
+    menu('admin/logs', t('logs'), user_access('administer watchdog') ? 'watchdog_admin' : MENU_DENIED, 7);
+    menu('admin/logs/view', t('view details'), user_access('administer watchdog') ? 'watchdog_admin' : MENU_DENIED, 0, MENU_HIDE, MENU_LOCKED);
+
+    foreach (_watchdog_get_message_types() as $type) {
+      menu("admin/logs/$type", t($type), user_access('administer watchdog') ? 'watchdog_admin' : MENU_DENIED);
     }
   }
 }
