Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.86
diff -u -r1.86 menu.inc
--- includes/menu.inc	8 Oct 2005 12:38:20 -0000	1.86
+++ includes/menu.inc	12 Oct 2005 17:47:35 -0000
@@ -82,6 +82,8 @@
 define('MENU_IS_LOCAL_TASK', 0x0080);
 define('MENU_EXPANDED', 0x0100);
 define('MENU_LINKS_TO_PARENT', 0x0200);
+define('MENU_MODIFIED_BY_MODULE', 0x0400);
+define('MENU_CREATED_BY_MODULE', 0x0800);
 
 /**
  * @} End of "Menu flags".
@@ -152,6 +154,21 @@
 define('MENU_CUSTOM_MENU', MENU_IS_ROOT | MENU_VISIBLE_IN_TREE | MENU_CREATED_BY_ADMIN | MENU_MODIFIABLE_BY_ADMIN);
 
 /**
+ * Module menus are similar to custom menus but are defined by modules. Reserved for 
+ * modules that create menus automatically for the node types they support. An example
+ * would be the book.module automatically creating a menu for each book in a site.
+ * Do not return from hook_menu() implementations.
+ */
+define('MENU_MODULE_MENU', MENU_IS_ROOT | MENU_VISIBLE_IN_TREE | MENU_CREATED_BY_MODULE);
+
+/**
+ * Module items are similar to custom items but are defined by modules. Module items are
+ * children of module menus. Reserved for modules that create menus automatically for the 
+ * node types they support. Do not return from hook_menu() implementations.
+ */
+define('MENU_MODULE_ITEM', MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IN_BREADCRUMB | MENU_CREATED_BY_MODULE);
+
+/**
  * @} End of "Menu item types".
  */
 
@@ -818,7 +835,7 @@
       }
       else {
         // The path was not declared, so this is a custom item or an orphaned one.
-        if ($item->type & MENU_CREATED_BY_ADMIN) {
+        if ($item->type & MENU_CREATED_BY_ADMIN || $item->type & MENU_CREATED_BY_MODULE) {
           $_menu['items'][$item->mid] = array('path' => $item->path, 'access' => TRUE, 'callback' => '');
           if (!empty($item->path)) {
             $_menu['path index'][$item->path] = $item->mid;
@@ -827,7 +844,7 @@
       }
 
       // If the administrator has changed the item, reflect the change.
-      if ($item->type & MENU_MODIFIED_BY_ADMIN) {
+      if ($item->type & MENU_MODIFIED_BY_ADMIN || $item->type & MENU_MODIFIED_BY_MODULE) {
         $_menu['items'][$item->mid]['title'] = $item->title;
         $_menu['items'][$item->mid]['description'] = $item->description;
         $_menu['items'][$item->mid]['pid'] = $item->pid;
Index: modules/book.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/book.module,v
retrieving revision 1.323
diff -u -r1.323 book.module
--- modules/book.module	11 Oct 2005 19:44:34 -0000	1.323
+++ modules/book.module	12 Oct 2005 18:38:46 -0000
@@ -199,6 +199,7 @@
  */
 function book_insert($node) {
   db_query("INSERT INTO {book} (nid, vid, parent, weight) VALUES (%d, %d, %d, %d)", $node->nid, $node->vid, $node->parent, $node->weight);
+  book_build_menu_module_menu();
 }
 
 /**
@@ -207,9 +208,11 @@
 function book_update($node) {
   if ($node->revision) {
     db_query("INSERT INTO {book} (nid, vid, parent, weight) VALUES (%d, %d, %d, %d)", $node->nid, $node->vid, $node->parent, $node->weight);
+      book_build_menu_module_menu();
   }
   else {
     db_query("UPDATE {book} SET parent = %d, weight = %d WHERE vid = %d", $node->parent, $node->weight, $node->vid);
+      book_build_menu_module_menu();
   }
 }
 
@@ -218,6 +221,7 @@
  */
 function book_delete(&$node) {
   db_query('DELETE FROM {book} WHERE nid = %d', $node->nid);
+  book_build_menu_module_menu();
 }
 
 /**
@@ -1164,5 +1168,72 @@
     return t('The outline feature allows you to include posts in the <a href="%book">book hierarchy</a>.', array('%book' => url('book')));
   }
 }
+/**
+* Create menus for books in the menu system and update their associated blocks
+*/
+function book_build_menu_module_menu() {
+  //remember menu_module_menu block settings
+  $results = db_query('SELECT m.path, b.status, b.weight, b.region, b.custom, b.throttle, b.visibility, b.pages, b.theme FROM {menu} m INNER JOIN {blocks} b ON m.mid = b.delta WHERE m.type = %d', MENU_MODULE_MENU | MENU_MODIFIED_BY_MODULE);
+  while ($result = db_fetch_object($results)) {
+    $menu_block_settings[$result->path] = array('status' => $result->status, 'weight' => $result->weight, 'region' => $result->region, 'custom' => $result->custom, 'throttle' => $result->throttle, 'visibility' => $result->visibility, 'pages' => $result->pages, 'theme' => $result->theme);
+  }
+  //Remove existing module menus
+  db_query('DELETE FROM {menu} WHERE type = %d OR type = %d', MENU_MODULE_MENU | MENU_MODIFIED_BY_MODULE, MENU_MODULE_ITEM | MENU_MODIFIED_BY_MODULE);
+  //Get book hierarchies
+  $result = db_query(db_rewrite_sql('SELECT n.nid, n.title, b.parent, b.weight FROM {node} n INNER JOIN {book} b ON n.nid = b.nid WHERE n.status = 1 AND n.moderate = 0 ORDER BY b.parent, b.weight, n.title')); 
+  while ($node = db_fetch_object($result)) {
+    $list = $children[$node->parent] ? $children[$node->parent] : array();
+    array_push($list, $node);
+    $children[$node->parent] = $list;
+  }
 
+  //Build and execute insert of new module menu - rebuild menu system array - rehash blocks - restore block settings
+  if ($tree = book_menu_tree_recurse(0, $children, 0, 0, MENU_MODULE_MENU | MENU_MODIFIED_BY_MODULE, MENU_MODULE_ITEM | MENU_MODIFIED_BY_MODULE)) {
+    $q = rtrim($tree, ', ');
+    db_query('INSERT INTO {menu} (mid, pid, path, title, weight, type) VALUES ' . $q);
+    menu_rebuild();
+    _block_rehash();
+    //restore menu_module_menu block settings
+    if ($menu_block_settings) {
+      $result = db_query('SELECT m.path, b.delta FROM {menu} m INNER JOIN {blocks} b ON m.mid = b.delta WHERE m.type = %d', MENU_MODULE_MENU | MENU_MODIFIED_BY_MODULE);
+      while ($menu_block = db_fetch_object($result)) {
+        if (array_key_exists($menu_block->path, $menu_block_settings)) {
+          db_query("UPDATE {blocks} SET status = %d, weight = %d, region = %d, custom = '%s', throttle = %d, visibility = %d, pages = '%s', theme = '%s' WHERE delta = %d",
+                    $menu_block_settings[$menu_block->path]['status'], $menu_block_settings[$menu_block->path]['weight'], $menu_block_settings[$menu_block->path]['region'], $menu_block_settings[$menu_block->path]['custom'], $menu_block_settings[$menu_block->path]['throttle'], $menu_block_settings[$menu_block->path]['visibility'], $menu_block_settings[$menu_block->path]['pages'],  $menu_block_settings[$menu_block->path]['theme'], $menu_block->delta);
+        }
+      }
+    }
+  }
+}
 
+/**
+*  Recursively traverse books' hiearchies and return SQL insert parameters
+*/
+function book_menu_tree_recurse($pid, $children, $pmid, $mid, $menu, $item) {
+
+  if ($children[$pid]) {
+    foreach ($children[$pid] as $foo => $node) {
+      $node->mid = db_next_id('{menu}_mid');
+      $node->pmid = $pmid;
+      if ($output .= book_menu_tree_recurse($node->nid, $children, $node->mid, db_next_id('{menu}_mid'), $menu, $item)) {
+        if ($pmid==0) {
+          $output .= "($node->mid, $node->pmid, 'node/$node->nid', '". addslashes($node->title) ."', $node->weight, $menu), ";
+        }
+        else {
+          $output .= "($node->mid, $node->pmid, 'node/$node->nid', '". addslashes($node->title) ."', $node->weight, $item), ";
+        }
+      }
+      else {
+        if ($pid==0) {
+          $output .= "($node->mid, $node->pmid, 'node/$node->nid', '". addslashes($node->title) ."', $node->weight, $menu), ";
+        }
+        else {
+          $output .= "($node->mid, $node->pmid, 'node/$node->nid', '". addslashes($node->title) ."', $node->weight, $item), ";
+        }
+      }
+    }  
+  }
+    
+return $output;
+}
+?>
