diff -urp book_page_access/book_page_access.install book_page_access_new/book_page_access.install
--- book_page_access/book_page_access.install	2009-12-17 08:39:24.000000000 +0000
+++ book_page_access_new/book_page_access.install	2010-05-24 23:14:35.000000000 +0100
@@ -27,6 +27,7 @@ function book_page_access_schema() {
       ),
     'primary key' => array('nid', 'rid'),
   );
+  
   return $schema;
 }
 
@@ -39,9 +40,40 @@ function book_page_access_install() {
 }
 
 /**
+ * Create new table to handle assigning roles to users.
+ */
+function book_page_access_update_6001() {
+  
+  $ret = array();
+
+  $schema['book_page_user_access'] = array(
+    'description' => t('The base table for delegation of nodes to users.'),
+    'fields' => array(
+      'nid' => array(
+        'description' => t('The {node}.nid of the book page.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE),
+      'uid' => array(
+        'description' => t('The {users}.uid the book page was delegated to.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0),
+      ),
+    'primary key' => array('nid', 'uid'),
+  );
+  db_create_table($ret, 'book_page_user_access', $schema['book_page_user_access']);
+  
+  return $ret;
+  
+}  
+
+
+/**
  * Implementation of hook_uninstall().
  */
 function book_page_access_uninstall() {
   // Drop my tables.
   drupal_uninstall_schema('book_page_access');
-}
+}
\ No newline at end of file
diff -urp book_page_access/book_page_access.module book_page_access_new/book_page_access.module
--- book_page_access/book_page_access.module	2009-12-30 14:19:43.000000000 +0000
+++ book_page_access_new/book_page_access.module	2010-05-25 00:07:52.000000000 +0100
@@ -12,6 +12,30 @@
 define('BOOK_PAGE_ACCESS_GRANT_PRIORITY', 0);
 
 /**
+ * Implementation of hook_perm().
+ */
+function book_page_access_perm() {
+  $perms = array('delegate book page access to roles',
+                 'delegate book page access to users');
+  return $perms;
+}
+
+/**
+ * Implementation of hook_menu().
+ * Menu item for user autocomplete
+ */
+function book_page_access_menu() {
+  $items['book_page_access/autocomplete'] = array(
+    'title' => 'Book page access autocomplete',
+    'page callback' => 'book_page_access_autocomplete',
+    'access arguments' => array('access user profiles'),
+    'type' => MENU_CALLBACK,
+  );
+
+  return $items;
+}
+
+/**
  * Implementation of hook_form_alter().
  */
 function book_page_access_form_alter(&$form, $form_state, $form_id) {
@@ -20,7 +44,8 @@ function book_page_access_form_alter(&$f
     // Add elements to the node form
     $node = $form['#node'];
 
-    if (user_access('administer book outlines')) {
+    if (book_page_access_can_delegate()) {
+      
       $form['book_page_access'] = array(
         '#type' => 'fieldset',
         '#title' => t('Delegate book page'),
@@ -28,26 +53,48 @@ function book_page_access_form_alter(&$f
         '#collapsible' => TRUE,
         '#collapsed' => TRUE,
       );
+     
+      // Generate role checkboxes
+      if (user_access('delegate book page access to roles') ) {
+        $rids = user_roles();
+ 
+        //we don't want it to include anonymous users
+        unset($rids[1]);
+
+        //prepare default_values
+        $default_values = array();
+        $results = db_query("SELECT rid FROM {book_page_access} WHERE nid = %d", $form['#node']->nid);
+        while ($role = db_fetch_object($results)) {
+          $default_values[] = $role->rid;
+        }
 
-      $rids = user_roles();
-
-      //we don't want it to include anonymous users
-      unset($rids[1]);
-
-      //prepare default_values
-      $default_values = array();
-      $results = db_query("SELECT rid FROM {book_page_access} WHERE nid = %d", $form['#node']->nid);
-      while ($role = db_fetch_object($results)) {
-        $default_values[] = $role->rid;
-      }
-
-      $form['book_page_access']['book_page_access'] = array(
-        '#type' => 'checkboxes',
-        '#title' => t('Delegate book page to roles'),
-        '#options' => $rids,
-        '#default_value' => $default_values,
-      );
-
+        $form['book_page_access']['book_page_access'] = array(
+          '#type' => 'checkboxes',
+          '#title' => t('Delegate book page to roles'),
+          '#options' => $rids,
+          '#default_value' => $default_values,
+        );
+      }
+      
+      // Generate autocomplete list of users
+      if (user_access('delegate book page access to users') ) {
+        
+        $names = array();
+        $query = db_query('SELECT u.name from {users} u JOIN {book_page_user_access} b on u.uid = b.uid WHERE b.nid = %d', $node->nid); 
+        while ($user = db_fetch_object($query)) {
+          $names[] = $user->name;
+        }    
+        $name_list = implode(',', $names);
+     
+        $form['book_page_access']['book_page_user_access'] = array(
+          '#type' => 'textfield',
+          '#title' => t('Delegate book page to individual users'),
+          '#maxlength' => 1024,
+          '#autocomplete_path' => 'book_page_access/autocomplete',
+          '#default_value' => $name_list ? $name_list : '',
+          '#description' => 'Enter comma seperated list of users (case-sensitive) - there is an autocomplete to help you locate the users',
+        );
+      }
       $form['#validate'][] = 'book_page_access_validate';
       $form['buttons']['submit']['#submit'][] = 'book_page_access_submit';
     }
@@ -60,21 +107,26 @@ function book_page_access_form_alter(&$f
 function book_page_access_validate($form, &$form_state) {
   global $user;
 
-  if (!user_access('administer book outlines')) {
+  if (!book_page_access_can_delegate()) {
 
-    $roles = book_page_access_permissions_tree($form['#node']->nid);
+    // first check individual users
+    $users = book_page_access_user_permissions_tree($form['#node']->nid);
 
-    $authorized = FALSE;
+    if (!in_array($user->uid, $users)) {
+      // now check the roles
+      $roles = book_page_access_permissions_tree($form['#node']->nid);
 
-    foreach ($user->roles as $rid => $role_name) {
-      if (in_array($rid, $roles)) {
-        $authorized = TRUE;
-        break;
-      }
-    }
+      $authorized = FALSE;
 
-    if (!$authorized) {
-      form_set_error('book_page_access', t('You may not insert this book page here.'));
+      foreach ($user->roles as $rid => $role_name) {
+        if (in_array($rid, $roles)) {
+          $authorized = TRUE;
+          break;
+        }
+      }
+      if (!$authorized) {
+        form_set_error('book_page_access', t('Error: You may not insert this book page here.'));
+      }
     }
   }
 }
@@ -83,49 +135,96 @@ function book_page_access_validate($form
  * Submit data
  */
 function book_page_access_submit($form, &$form_state) {
-  $roles_in_form = $form_state['values']['book_page_access'];
-  $roles_to_add = '';
+  
   $nid = $form_state['nid'];
-  $needs_rebuild = FALSE;
-
-  $existing = db_query('SELECT * from {book_page_access} WHERE nid = %d', $nid);
-  if (db_fetch_array($existing)) {
-    db_query("DELETE from {book_page_access} WHERE nid = %d", $nid);
-    $needs_rebuild = TRUE;
-  }
-
-  foreach ($roles_in_form as $role => $value) {
-    $needs_rebuild = TRUE;
-    if ($value) {
-      db_query("INSERT INTO {book_page_access} (nid, rid) VALUES (%d, %d)", $nid, $role);
+  
+  // Handle roles first
+  if (user_access('delegate book page access to roles') ) {
+
+    $roles_in_form = $form_state['values']['book_page_access'];
+    $roles_needs_rebuild = FALSE;
+
+    $existing = db_query('SELECT * from {book_page_access} WHERE nid = %d', $nid);
+    if (db_fetch_array($existing)) {
+      db_query("DELETE from {book_page_access} WHERE nid = %d", $nid);
+      $roles_needs_rebuild = TRUE;
+    }
+
+    foreach ($roles_in_form as $role => $value) {
+      $roles_needs_rebuild = TRUE;
+      if ($value) {
+        db_query("INSERT INTO {book_page_access} (nid, rid) VALUES (%d, %d)", $nid, $role);
+      }
+    }
+  }  
+  
+  // Now handle users 
+  if (user_access('delegate book page access to users') ) {
+    drupal_set_message($form_state['values']['book_page_user_access']);
+    $user_names = explode(',', $form_state['values']['book_page_user_access']);
+    $users_needs_rebuild = FALSE;
+
+    $existing = db_query('SELECT * from {book_page_user_access} WHERE nid = %d', $nid);
+    if (db_fetch_array($existing)) {
+      db_query("DELETE from {book_page_user_access} WHERE nid = %d", $nid);
+      $users_needs_rebuild = TRUE;
+    }
+
+    foreach ($user_names as $name) {     
+      $users_needs_rebuild = TRUE;        
+      $uid = db_result(db_query("SELECT uid from {users} WHERE name='%s'", $name));
+      db_query("INSERT INTO {book_page_user_access} (nid, uid) VALUES (%d, %d)", $nid, $uid); 
     }
   }
-  if ($needs_rebuild && is_array($form_state['values']['book'])) {
+  
+  if (($roles_needs_rebuild || $users_needs_rebuild) && is_array($form_state['values']['book'])) {
     book_page_access_access_rebuild($form_state['values']['book']['bid']);
-  }
+  } 
 }
 
-
 /**
- * Implementation of hook_node_grants().
+ * Implementation of hook_node_grants();
  */
 function book_page_access_node_grants($account, $op) {
+	global $user;
+	
   if ($op == 'view') {
     $grants['book_page_access_view'] = array(1);
   }
   if ($op == 'update' || $op == 'delete') {
-    if (user_access('administer book outlines', $account)) {
+     
+   if (book_page_access_can_delegate()) {
       $grants['book_page_access_admin'] = array(1);
     }
-    else {
+    else {   
       $grants['book_page_access'] = array_keys($account->roles);
+      $grants['book_page_access_user'] = array($account->uid);  
     }
   }
-
   return $grants;
 }
 
 /**
+ * Check that the user has authority to delegate pages to either roles or users;
+ */
+function book_page_access_can_delegate() {
+  
+    // This hook will allow you to limit delegation powers  
+    // to certain sections of the site e.g a domain
+    $pageaccesshook = TRUE;
+    foreach (module_implements('bookpageaccess') as $name) {
+       $function = $name .'_bookpageaccess';
+       $result = $function($comment, $op);
+       if (!$result) {
+         $pageaccesshook = FALSE;
+       }
+    }
+    
+    return user_access('administer book outlines', $account) ||
+        ((user_access('delegate book page access to roles') || user_access('delegate book page access to users')) && $pageaccesshook);  
+}  
+
+/**
  * Implementation of hook_node_access_records().
  *
  * Returns a list of grant records for the passed in book node object. If we
@@ -137,6 +236,7 @@ function book_page_access_node_access_re
     $nid = $node->book['nid'];
 
     $roles = book_page_access_permissions_tree($node->nid);
+    $users = book_page_access_user_permissions_tree($node->nid);
 
     $grants[] = array(
       'realm'        => 'book_page_access_view',
@@ -161,6 +261,19 @@ function book_page_access_node_access_re
       }
     }
 
+    if (count($users)) {
+      foreach ($users as $uid) {
+        $grants[] = array(
+          'realm'        => 'book_page_access_user',
+          'gid'          => $uid,
+          'grant_view'   => TRUE,
+          'grant_update' => TRUE,
+          'grant_delete' => TRUE,
+          'priority'     => BOOK_PAGE_ACCESS_GRANT_PRIORITY,
+        );
+      }
+    }    
+
     $grants[] = array(
       'realm'        => 'book_page_access_admin',
       'gid'          => 1,
@@ -198,6 +311,24 @@ function book_page_access_permissions_tr
   }
 }
 
+function book_page_access_user_permissions_tree($nid) {
+
+  $users = array();
+
+  while ($nid) {
+    // find the assigned users for this node
+    $result = db_query("SELECT uid FROM {book_page_user_access} WHERE nid = %d", $nid);
+    while ($user = db_fetch_object($result)) {
+      $users[] = $user->uid;
+    }
+
+    //get book parent
+    $nid = db_result(db_query('SELECT b.nid from {book} b INNER JOIN {menu_links} ml ON b.mlid = ml.plid WHERE ml.link_path = \'node/%d\'', $nid)); 
+  }
+
+  return $users;
+}
+
 /**
  * Implementation of hook_enable().
  */
@@ -350,3 +481,26 @@ function book_page_access_block($op = 'l
 
 } // function book_page_access_block
 
+/**
+ * Helper function for multiple user autocompletion
+ */
+function book_page_access_autocomplete($string = '') {
+  // The user enters a comma-separated list of users. We only autocomplete the last user.
+  $array = explode(',' , $string);
+
+  // Fetch last user
+  $last_string = trim(array_pop($array));
+  $matches = array();
+  if ($last_string != '') {
+    $result = db_query_range("SELECT name FROM {users} WHERE name LIKE '%%%s%%'", $last_string, 0, 10);
+
+    $prefix = count($array) ? implode(', ', $array) .', ' : '';
+    while ($user = db_fetch_object($result)) {
+      $n = $user->name;
+      $matches[$prefix . $n] = check_plain($user->name);
+    }
+  }
+
+  drupal_json($matches);
+}
+
