Index: tac_lite.module
===================================================================
--- tac_lite.module	(revision 1171)
+++ tac_lite.module	(working copy)
@@ -49,21 +49,29 @@
 					 'title' => t('Access control by taxonomy'),
                      'callback' => 'drupal_get_form',
 					 'callback arguments' => 'tac_lite_admin_settings',
-					 'type' => MENU_NORMAL_ITEM,
+					 'type' => MENU_LOCAL_TASK,
 					 'weight' => 1, // after 'roles' tab
 					 'access' => $admin_access);
 	$items[] = array('path' => 'admin/user/access/tac_lite/settings',
 					 'title' => t('Settings'),
 					 'type' => MENU_DEFAULT_LOCAL_TASK,
 					 'weight' => -1,
+					 'access' => $admin_access,
 					 );
-	$items[] = array('path' => 'admin/user/access/tac_lite/roles',
-					 'title' => t('Role based privileges'),
-                     'callback' => 'drupal_get_form',
-					 'callback arguments' => 'tac_lite_admin_settings_defaults', 
-					 'type' => MENU_LOCAL_TASK,
-					 'access' => $admin_access);					 
   }
+  else {
+    if (arg(0) == 'admin' && arg(1) == 'user' && arg(2) == 'access' && arg(3) == 'tac_lite') {
+      $schemes = variable_get('tac_lite_schemes', 1);
+      for ($i = 1; $i <= $schemes; $i++) {
+        $items[] = array('path' => 'admin/user/access/tac_lite/scheme/' . $i,
+                         'title' => t('Scheme !num', array('!num' => $i)),
+                         'callback' => 'tac_lite_admin_settings_scheme',
+                         'callback arguments' => $i,
+                         'type' => MENU_LOCAL_TASK,
+                         'access' => $admin_access);
+      }
+    }
+  }
   
   return $items;
 }
@@ -87,12 +95,26 @@
     
     $form['tac_lite_categories'] = 
       array('#type' => 'select',
-            '#title' => 'Vocabularies',
+            '#title' => t('Vocabularies'),
             '#default_value' => variable_get('tac_lite_categories', null),
             '#options' => $options,
             '#description' => t('Select one or more vocabularies to control privacy.  Do not select free tagging vocabularies, they are not supported.'),
-            '#multiple' => true,
+            '#multiple' => TRUE,
+            '#required' => TRUE,
       );
+    $scheme_options = array();
+    // Currently only view, edit, delete permissions possible, so 7
+    // permutations will be more than enough.
+    for ($i = 1; $i < 8; $i++)
+      $scheme_options[$i] = $i;
+    $form['tac_lite_schemes'] =
+      array('#type' => 'select',
+            '#title' => t('Schemes'),
+            '#description' => t('Each scheme allows for a different set of permissions.  For example, use scheme 1 for read-only permission; scheme 2 for read and update; scheme 3 for delete; etc.  Additional schemes increase the size of your node_access table, so use no more than you need.'),
+            '#default_value' => variable_get('tac_lite_schemes', 1),
+            '#options' => $scheme_options,
+            '#required' => TRUE,
+      );
     
     $ret = system_settings_form($form);
     // Special handling is required when this form is submitted.
@@ -113,19 +135,73 @@
   drupal_set_message(t('The content access permissions have been rebuilt.'));
 }
 
+
+function tac_lite_admin_settings_scheme($i) {
+  return drupal_get_form('tac_lite_admin_scheme_form', $i);
+}
+
 /**
+ * helper function
+ */
+function _tac_lite_config($scheme) {
+  // different defaults for scheme 1
+  if ($scheme === 1)
+    $config = variable_get('tac_lite_config_scheme_' . $scheme, 
+                           array('name' => t('read'), 
+                                 'perms' => array('grant_view')));
+  else
+    $config = variable_get('tac_lite_config_scheme_' . $scheme, 
+                           array('name' => NULL, 'perms' => array()));
+  // For backward compatability, use naming convention for scheme 1
+  if ($scheme == 1)
+    $config['realm'] = 'tac_lite';
+  else
+    $config['realm'] = 'tac_lite_scheme_' . $scheme;
+
+  return $config;
+}
+
+/**
  * Returns the form for role-based privileges.
  */
-function tac_lite_admin_settings_defaults() {
+function tac_lite_admin_scheme_form($i) {
   $vids = variable_get('tac_lite_categories', null);
   $roles = user_roles();
 
   if (count($vids)) {
-	$all_defaults = variable_get('tac_lite_default_grants', array());
-	$form['tac_lite_default_grants'] = 
+    $config = _tac_lite_config($i);
+      
+    $form['tac_lite_config_scheme_' . $i] =
+      array('#tree' => TRUE);
+    $form['tac_lite_config_scheme_' . $i]['name'] =
+      array('#type' => 'textfield',
+            '#title' => t('Scheme name'),
+            '#description' => t('A human-readable name for administrators to see.  For example, \'read\' or \'read and write\'.'),
+            '#default_value' => $config['name'],
+            '#required' => TRUE,
+      );
+    // Currently, only view, update and delete are supported by node_access
+    $options = array('grant_view' => 'view',
+                     'grant_update' => 'update',
+                     'grant_delete' => 'delete');
+    $form['tac_lite_config_scheme_' . $i]['perms'] =
+      array('#type' => 'select',
+            '#title' => t('Permissions'),
+            '#multiple' => TRUE,
+            '#options' => $options,
+            '#default_value' => $config['perms'],
+            '#description' => t('Select which permissions are granted by this scheme.'),
+      );
+
+    $form['helptext'] = array('#type' => 'markup',
+                              '#value' => t('You may grant these permissions by role, below.  To grant permission to an individual user, visit the tac_lite tab on the user edit page.'));
+
+
+	$all_defaults = variable_get('tac_lite_grants_scheme_' . $i, array());
+	$form['tac_lite_grants_scheme_' . $i] = 
 	  array('#tree' => true);
 	foreach ($roles as $rid => $role_name) {
-	  $form['tac_lite_default_grants'][$rid] =
+	  $form['tac_lite_grants_scheme_' . $i][$rid] =
 		array('#type' => 'fieldset',
 			  '#tree' => true,
 			  '#title' => t('Access for %role', array('%role' => $role_name)),
@@ -134,7 +210,7 @@
 	  $defaults = $all_defaults[$rid];
 	  foreach ($vids as $vid) {
 		$v = taxonomy_get_vocabulary($vid);
-		$form['tac_lite_default_grants'][$rid][$vid] = 
+		$form['tac_lite_grants_scheme_' . $i][$rid][$vid] = 
 		  _taxonomy_term_select($v->name,
 								null, // name no longer used in new form api
 								$defaults[$vid],
@@ -144,13 +220,12 @@
 								'<'.t('none').'>');
 	  }
 	}
-	$output .= '<p>'.t('For each role below, select the terms which members of the role are allowed to view.')."</p>\n";
-	$output .= '<p>'.t('You may grant individual users additional access to specific terms.  See the tac_lite tab when editing user accounts.')."</p>\n";
+    
 	return system_settings_form($form);
   }
   else {
     return (array('body' => array('#type' => 'markup',
-                                  '#value' => t('First select vocabularies on the tac_lite settings page.'))));
+                                  '#value' => t('First select vocabularies on the <a href=!url>settings page</a>.', array('!url' => url('admin/user/access/tac_lite'))))));
   }
 }
 /**
@@ -168,7 +243,7 @@
   switch ($op) {
   case 'categories':
 	return array(array('name' => 'tac_lite',
-					   'title' => 'tac_lite access',
+					   'title' => 'Access control (tac_lite)',
 					   ),
 				 );
 	break;
@@ -177,26 +252,38 @@
 	if ($category == 'tac_lite') {
 	  $vids = variable_get('tac_lite_categories', null);
 	  if (count($vids)) {
-		foreach ($vids as $vid) {
-		  $v = taxonomy_get_vocabulary($vid);
-		  $form['tac_lite']['tac_lite'][$vid] = 
-			 _taxonomy_term_select($v->name,
-								   null, // name no longer used in new form api
-								   $account->tac_lite[$vid],
-								   $vid,
-								   '',
-								   true,
-								   '<'.t('none').'>');
-		}
-	  }
-	  $form['tac_lite'][0] = 
-		array('#type' => 'markup',
-			  '#value' => '<p>'.t('You may grant this user view access to any of the terms below.  These grants are in addition to !grant_per_role_link.',
-								  array('!grant_per_role_link' => l(t('access granted to the user by virtue of his/her roles'), 'admin/user/access/tac_lite/roles'))) . "</p>\n",
-			  '#weight' => -1);
-	  $form['tac_lite']['tac_lite']['#tree'] = true;
-	  return $form;
-	}
+        for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) {
+          $config = _tac_lite_config($i);
+          if ($config['name']) {
+            $form['tac_lite'][$config['realm']] =
+              array('#type' => 'fieldset',
+                    '#title'=> $config['name'],
+                    '#description' => t('This scheme includes permissions %perms',
+                                        array('%perms' => implode(' and ', $config['perms']))),
+                    '#tree' => TRUE,
+              );
+            foreach ($vids as $vid) {
+              $v = taxonomy_get_vocabulary($vid);
+              $form['tac_lite'][$config['realm']][$vid] = 
+                _taxonomy_term_select($v->name,
+                                      null, // name no longer used in new form api
+                                      $account->tac_lite[$vid],
+                                      $vid,
+                                      '',
+                                      true,
+                                      '<'.t('none').'>');
+            }
+          }
+        }
+        $form['tac_lite'][0] = 
+          array('#type' => 'markup',
+                '#value' => '<p>' . t('You may grant this user access based on the schemes and terms below.  These permissions are in addition to <a href="!url">role based grants on scheme settings pages</a>.',
+                                      array('!url' => url('admin/user/access/tac_lite/scheme/1'))) . "</p>\n",
+                '#weight' => -1);
+
+        return $form;
+      }
+    }
 	break;
   case 'validate':
 	//print_r($edit);
@@ -204,9 +291,13 @@
 	break;
   }
 }
+
 /**
  * Implementation of hook_node_access_records
  * 
+ * We are given a node and we return records for the node_access table.  In
+ * our case, we inpect the node's taxonomy and grant permissions based on the
+ * terms.
  */
 function tac_lite_node_access_records($node) {
   // all terms from all vocabs
@@ -233,11 +324,17 @@
     // if we're here, the node has terms associated with it which restrict
 	// access to the node.
     $grants = array();
-    foreach ($tids as $tid) {
-      $grants[] = array('realm' => 'tac_lite',
-                        'gid' => $tid, // use term id as grant id
-                        'grant_view' => TRUE);
-	}
+    for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) {
+      $config = _tac_lite_config($i);
+      foreach ($tids as $tid) {
+        $grant = array('realm' => $config['realm'],
+                       'gid' => $tid, // use term id as grant id
+        );
+        foreach($config['perms'] as $perm)
+          $grant[$perm] = TRUE;
+        $grants[] = $grant;
+      }
+    }
     return $grants;
   }
 }
@@ -296,38 +393,36 @@
 }
 
 /**
- * Return the term ids of terms this user is allowed to access
+ * Return the term ids of terms this user is allowed to access.
  * 
  * Users are granted access to terms either because of who they are,
  * or because of the roles they have.
  */
-function _tac_lite_user_tids(&$account) {
-  $grants = array();
-  if (count($account->tac_lite)) {
-	// $account->tac_lite is array.  Keys are vids, values are array of tids within that vocabulary, to which the user has access
-	foreach ($account->tac_lite as $tids) {
+function _tac_lite_user_tids(&$account, $scheme) {
+  // grant id 0 is reserved for nodes which were not given a grant id when they were created.  By adding 0 to the grant id, we let the user view those nodes.
+  $grants = array(0);
+  $config = _tac_lite_config($scheme);
+  if (count($account->$config['realm'])) {
+	// $account->$config['realm'] is array.  Keys are vids, values are array of tids within that vocabulary, to which the user has access
+	foreach ($account->$config['realm'] as $tids) {
 	  if (count($tids)) {
 		$grants = array_merge($grants, $tids);
       }
 	}
   }
-
+  
   // add per-role grants in addition to per-user grants
-  $defaults = variable_get('tac_lite_default_grants', array());
+  $defaults = variable_get('tac_lite_grants_scheme_' . $scheme, array());
   foreach ($account->roles as $rid => $role_name) {
-	if (count($defaults[$rid])) {
-	  foreach ($defaults[$rid] as $tids) {
-		if (count($tids)) {
+    if (count($defaults[$rid])) {
+      foreach ($defaults[$rid] as $tids) {
+        if (count($tids)) {
           $grants = array_merge($grants, $tids);
         }
 	  }
 	}
   }
 
-  // grant id 0 is reserved for nodes which were not given a grant id when they were created.  By adding 0 to the grant id, we let the user view those nodes.
-  // TODO: make this behavior configurable, to play nicely with other node_access modules which may be installed
-  $grants[] = 0;
-
   // Because of some flakyness in the form API and the form we insert under
   // user settings, we may have a bogus entry with vid set
   // to ''.  Here we make sure not to return that.
@@ -338,15 +433,20 @@
 
 /**
  * Implementation of hook_node_grants
+ * 
+ * Returns any grants which may give the user permission to perform the
+ * requested op.
  */
 function tac_lite_node_grants(&$account, &$op) {
-  // tac_lite deals only with 'view' permission.
-  // if there is a clean way to add support for other ops, I'm open to it.  However users who need that should currently use the Taxonomy Access Control module.
-  if ($op == 'view') {
-    $grants = _tac_lite_user_tids($account);
-    
-    return array('tac_lite' => $grants);
+  $grants = array();
+  for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) {
+    $config = _tac_lite_config($i);
+    if (in_array('grant_' . $op, $config['perms'])) {
+      $grants[$config['realm']] = _tac_lite_user_tids($account, $i);
+    }
   }
+  if (count($grants))
+    $grants;
 }
 
 function tac_lite_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
@@ -361,8 +461,13 @@
   $vids = variable_get('tac_lite_categories', array(0));
 
   // the terms this user is allowed to see
-  $tids = _tac_lite_user_tids($user);
-
+  $tids = array();
+  for ($i = 1; $i <= variable_get('tac_lite_schemes', 1); $i++) {
+    $config = _tac_lite_config($i);
+    if (in_array('grant_view', $config['perms'])) {
+      $tids = array_merge($tids, _tac_lite_user_tids($user, $i));
+    }
+  }
   switch ($primary_field) {
   case 'tid':
 	// prevent users from seeing terms they do not have permission to read.
Index: tac_lite.install
===================================================================
--- tac_lite.install	(revision 1171)
+++ tac_lite.install	(working copy)
@@ -34,4 +34,14 @@
   return $ret;
 }
 
+/**
+ * Introducing schemes.  Rename tac_lite_default_grants to tac_lite_grants_scheme_1.
+ */
+function tac_lite_update_3() {
+  $ret = array();
+  $ret[] = update_sql("UPDATE {variable} SET name='tac_lite_grants_scheme_1' WHERE name='tac_lite_default_grants'");
+  return $ret;
+}
+
+
 ?>
\ No newline at end of file
