### Eclipse Workspace Patch 1.0
#P simple_access-6
Index: simple_access.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/simple_access/simple_access.info,v
retrieving revision 1.3
diff -u -r1.3 simple_access.info
--- simple_access.info	18 Jun 2007 22:53:58 -0000	1.3
+++ simple_access.info	21 Mar 2008 23:54:35 -0000
@@ -1,3 +1,4 @@
-; $Id: simple_access.info,v 1.3 2007/06/18 22:53:58 dww Exp $
+; $Id$
 name = Simple Access
-description = "Provides simple hide/view access for nodes."
+description = Provides simple hide/view access for nodes.
+core = 6.x
Index: simple_access.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/simple_access/simple_access.install,v
retrieving revision 1.3
diff -u -r1.3 simple_access.install
--- simple_access.install	10 Mar 2007 04:46:13 -0000	1.3
+++ simple_access.install	21 Mar 2008 23:54:35 -0000
@@ -1,66 +1,115 @@
 <?php
-// $Id: simple_access.install,v 1.3 2007/03/10 04:46:13 gordon Exp $
+// $Id$
 
 /**
  * Implementation of hook_install()
  */
 function simple_access_install() {
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      db_query("CREATE TABLE {simple_access_groups} (
-        gid int(10) NOT NULL default '0',
-        name varchar(50) NOT NULL default '',
-        weight int(3) NOT NULL default '0'
-      ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      db_query("CREATE TABLE {simple_access_roles} (
-        gid int(10) NOT NULL default '0',
-        rid int(10) NOT NULL default '0'
-      ) TYPE=MyISAM /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      break;
-    case 'pgsql':
-      db_query("CREATE TABLE {simple_access_groups} (
-        gid serial NOT NULL,
-        name varchar(50) NOT NULL default '',
-        weight integer NOT NULL default '0'
-      );");
-      db_query("CREATE TABLE {simple_access_roles} (
-        gid integer NOT NULL default '0',
-        rid integer NOT NULL default '0'
-      );");
-      break;
-  }
-  drupal_set_message(t('simple access has created the required tables.'));
+  drupal_install_schema('simple_access');
 }
 
-/** 
+/**
  * Implementation of hook_uninstall()
  */
 function simple_access_uninstall() {
-  db_query('DROP TABLE {simple_access_groups}');
-  db_query('DROP TABLE {simple_access_roles}');
+  drupal_uninstall_schema('simple_access');
   variable_del('sa_display');
   variable_del('sa_showgroups');
-  drupal_set_message(t('simple access has been uninstalled'));
 }
 
-/**
- * Implementation of hook_enable
- */ 
-function simple_access_enable() {
-  drupal_set_message(t('To fully activate simple_access you also need to !rebuild_permissions.', array('!rebuild_permissions' => l(t('rebuild permissions'), 'admin/content/node-settings'))));
-}
 
 /**
- * Implementation of hook_disable()
+ * Schema definition for simple_access
  */
-function simple_access_disable() {
-  drupal_set_message(t('To fully disable simple_access you also need to !rebuild_permissions.', array('!rebuild_permissions' => l(t('rebuild permissions'), 'admin/content/node-settings'))));
-}
+function simple_access_schema() {
+  $schema['simple_access_roles'] = array(
+    'description' => t('Simple access roles.'),
+    'fields' => array(
+      'gid' => array(
+        'description' => t('Simple access roles - gid.'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'rid' => array(
+        'description' => t('Simple access roles - rid.'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+  );
 
-/**
- * Updates
- */
-function simple_access_update_1() {
-  return _system_update_utf8(array('simple_access_groups', 'simple_access_roles'));
+  $schema['simple_access_groups'] = array(
+    'description' => t('Simple access groups.'),
+    'fields' => array(
+      'gid' => array(
+        'description' => t('Simple access groups - gid.'),
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE
+    ),
+      'name' => array(
+        'description' => t('Simple access groups - name.'),
+        'type' => 'varchar',
+        'length' => '50',
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'weight' => array(
+        'description' => t('Simple access groups - weight.'),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('gid'),
+  );
+
+  $schema['simple_access_node'] = array(
+    'description' => t('Simple access node.'),
+    'fields' => array(
+      'nid' => array(
+        'description' => t('Simple access node - nid.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'gid' => array(
+        'description' => t('Simple access node - gid.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'view' => array(
+        'description' => t('Simple access node - view.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'update' => array(
+        'description' => t('Simple access node - update.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'delete' => array(
+        'description' => t('Simple access node - delete.'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('nid', 'gid'),
+  );
+
+  return $schema;
 }
Index: simple_access.css
===================================================================
RCS file: simple_access.css
diff -N simple_access.css
--- simple_access.css	6 Jan 2006 01:35:34 -0000	1.1
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,6 +0,0 @@
-.sa-inline {
-  float: left;
-}
-.sa-after {
-  clear: both;
-}
Index: simple_access.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/simple_access/simple_access.module,v
retrieving revision 1.25
diff -u -r1.25 simple_access.module
--- simple_access.module	10 Mar 2007 04:46:13 -0000	1.25
+++ simple_access.module	21 Mar 2008 23:54:35 -0000
@@ -1,6 +1,5 @@
 <?php
-// $Id: simple_access.module,v 1.25 2007/03/10 04:46:13 gordon Exp $
-
+// $Id$
 
 /**
  * @file
@@ -12,184 +11,200 @@
  * Database definition:
  * @code
  * @endcode
- *
  */
 
 /**
  * Implementation of hook_menu().
  */
-function simple_access_menu($may_cache) {
-  $access = user_access('manage simple access');
-  if ($may_cache) {
-    $items[] = array(
-      'path' => 'admin/user/simple_access',
-      'title' => t('Simple Access'),
-      'access' => $access,
-      'callback' => 'simple_access_page_overview',
-      'type' => MENU_NORMAL_ITEM,
-      'description' => t('Manage groups of users for node-specific access control.'),
-    );
-    $items[] = array(
-      'path' => 'admin/user/simple_access/list',
-      'title' => t('List'),
-      'access' => $access,
-      'type' => MENU_DEFAULT_LOCAL_TASK,
-      'weight' => -8,
-    );
-    $items[] = array(
-      'path' => 'admin/user/simple_access/add',
-      'title' => t('Add Group'),
-      'callback' => 'drupal_get_form',
-      'callback arguments' => array('simple_access_group_form'),
-      'access' => $access,
-      'type' => MENU_LOCAL_TASK,
-      'weight' => -6,
-    );
-    $items[] = array(
-      'path' => 'admin/user/simple_access/edit',
-      'title' => t('Edit Group'),
-      'callback' => 'drupal_get_form',
-      'callback arguments' => array('simple_access_group_form'),
-      'access' => $access,
-      'type' => MENU_CALLBACK,
-    );
-    $items[] = array(
-      'path' => 'admin/user/simple_access/delete',
-      'title' => t('Delete Group'),
-      'callback' => 'drupal_get_form',
-      'callback arguments' => array('simple_access_delete_group_confirm'),
-      'access' => $access,
-      'type' => MENU_CALLBACK,
-    );
-    $items[] = array(
-      'path' => 'admin/settings/simple_access',
-      'title' => t('Simple Access'),
-      'callback' => 'drupal_get_form',
-      'callback arguments' => array('simple_access_settings_page'),
-      'access' => $access,
-      'type' => MENU_NORMAL_ITEM,
-      'description' => t('Configure which kinds of access (view, edit, delete) users with permission to use Simple Access can define for each node.'),
-    );
+function simple_access_menu() {
+
+  $items = array();
+
+  $items['admin/user/simple_access'] = array(
+    'title' => 'Simple access',
+    'description' => 'List, edit, or add access groups.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('simple_access_admin_list_groups'),
+    'access arguments' => array('manage simple access'),
+    'file' => 'simple_access.admin.inc',
+  );
+
+  $items['admin/user/simple_access/edit/%'] = array(
+    'title' => 'Edit access group',
+    'page arguments' => array('simple_access_add_edit_group', 4),
+    'type' => MENU_CALLBACK,
+    'file' => 'simple_access.admin.inc',
+  );
+
+  $items['admin/user/simple_access/add'] = array(
+    'title' => 'Add access group',
+    'page arguments' => array('simple_access_add_edit_group', NULL),
+    'type' => MENU_CALLBACK,
+    'file' => 'simple_access.admin.inc',
+  );
+
+  $items['admin/user/simple_access/delete/%'] = array(
+    'title' => t('Delete group'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('simple_access_delete_group_confirm', 4),
+    'type' => MENU_CALLBACK,
+    'file' => 'simple_access.admin.inc',
+  );
+
+  $items['admin/settings/simple_access'] = array(
+    'title' => t('Simple access'),
+    'description' => t('Configure which kinds of access (view, edit, delete) users with permission to use simple access can define for each node.'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('simple_access_settings_page'),
+    'access arguments' => array('manage simple access'),
+    'type' => MENU_NORMAL_ITEM,
+    'file' => 'simple_access.admin.inc',
+  );
+
+  $items['admin/content/simple_access'] = array(
+    'title' => t('Simple access'),
+    'description' => t('View node access which has been set up via simple access.'),
+    'access arguments' => array('administer nodes'),
+    'page callback' => 'simple_access_nodes',
+    'type' => MENU_NORMAL_ITEM,
+    'file' => 'simple_access.admin.inc',
+  );
+
+  $items['admin/content/simple_access/view'] = array(
+    'title' => t('View access'),
+    'page callback' => 'simple_access_nodes',
+    'page arguments' => array('view'),
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -5,
+    'file' => 'simple_access.admin.inc',
+  );
+
+  $items['admin/content/simple_access/edit'] = array(
+    'title' => t('Edit access'),
+    'page callback' => 'simple_access_nodes',
+    'page arguments' => array('edit'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => -4,
+    'file' => 'simple_access.admin.inc',
+  );
+
+  $items['admin/content/simple_access/delete'] = array(
+    'title' => t('Delete access'),
+    'page callback' => 'simple_access_nodes',
+    'page arguments' => array('delete'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => -3,
+    'file' => 'simple_access.admin.inc',
+  );
 
-    $items[] = array(
-      'path' => 'admin/content/simple_access',
-      'title' => t('Simple Access'),
-      'access' => user_access('administer nodes'),
-      'callback' => 'simple_access_nodes',
-      'type' => MENU_NORMAL_ITEM,
-      'description' => t('View node access which has been set up via Simple Access.'),
-    );
-    $items[] = array(
-      'path' => 'admin/content/simple_access/view',
-      'title' => t('View'),
-      'callback' => 'simple_access_nodes',
-      'access' => user_access('administer nodes'),
-      'type' => MENU_DEFAULT_LOCAL_TASK,
-      'weight' => -5,
-    );
-    $items[] = array(
-      'path' => 'admin/content/simple_access/edit',
-      'title' => t('Edit Access'),
-      'callback' => 'simple_access_nodes',
-      'access' => user_access('administer nodes'),
-      'type' => MENU_CALLBACK,
-      'weight' => -4,
-    );
-    $items[] = array(
-      'path' => 'admin/content/simple_access/delete',
-      'title' => t('Delete Access'),
-      'callback' => 'simple_access_nodes',
-      'access' => user_access('administer nodes'),
-      'type' => MENU_CALLBACK,
-      'weight' => -3,
-    );
-  }
   return $items;
 }
 
+
 /**
  * Implementation of hook_perm().
  */
 function simple_access_perm() {
-  return array('manage simple access', 'assign access to nodes');
+  return array(
+    'manage simple access',
+    'assign access to nodes',
+  );
 }
 
+
 /**
- * Implementation of hook_node_access_records
+ * Use hook_nodeapi to retrieve and update simple_access data as required
  */
-function simple_access_node_access_records($node)
-{
-  $records = array();
+function simple_access_nodeapi(&$node, $op, $arg = 0) {
+  switch ($op) {
+    case 'prepare':
+      if (!isset($node->simple_access)) {
+        $node->simple_access = array();
+      }
+      break;
+
+    case 'load':
+      $extra = array();
+      $result = db_query('SELECT na.gid, na.view, na.update, na.delete FROM {simple_access_node} na WHERE na.nid = %d', $node->nid);
+      while($grant = db_fetch_array($result)) {
+        $extra[$grant['gid']] = $grant;
+      }
+      $node->simple_access = $extra;
+      break;
 
-  if ($node->simple_access) {
-    // loop through simple_access arrays from page submission
-    // $type is either 'view', 'update', or 'delete'
-
-    foreach((array)$node->simple_access as $type => $array) {
-      // loop through each checkbox of the group
-      foreach((array)$array['checks'] as $gid => $checked) {
-        // make an array of all grants for node
-        if($checked){
-          $sa_grants[$gid][$type] = true;
-          if ($type == 'view') {
-            // if we've gotten here, then one of
-            // the view boxes is checked so...
-            $views = TRUE;
+    case 'update':
+    case 'insert':
+      db_query('DELETE FROM {simple_access_node} WHERE nid = %d', $node->nid);
+      if (isset($node->simple_access)) {
+        foreach ($node->simple_access as $gid => $access) {
+          if ($access['view'] || $access['update'] || $access['delete']) {
+            db_query("INSERT INTO {simple_access_node} (`nid`, `gid`, `view`, `update`, `delete`) VALUES (%d, %d, %d, %d, %d)", $node->nid, $gid, $access['view'], $access['update'], $access['delete']);
           }
         }
       }
-    }
-    // Because the UI is organized by access rather than GID, we need to
-    // reorganize the array by realm/GID
-    if ($sa_grants) {
-      foreach($sa_grants as $gid => $access) {
-        $records[] = array(
-          'realm' => 'simple_access',
-          'gid' => $gid,
-          'grant_view' => $access['view'],
-          'grant_update' => $access['update'],
-          'grant_delete' => $access['delete'],
-          'priority' => 1,
-        );
-      }
+      break;
+
+    case 'delete':
+      db_query('DELETE FROM {simple_access_node} WHERE nid = %d', $node->nid);
+      break;
+  }
+}
+
+
+/**
+ * Implementation of hook_node_access_records
+ */
+function simple_access_node_access_records($node) {
+
+  $records = array();
+
+  // Loop through simple_access arrays from page submission
+  // Create one entry per gid as required
+  foreach((array)$node->simple_access as $gid => $access) {
+    if ($access['view'] || $access['update'] || $access['delete']) {
+      $records[] = array(
+        'realm' => 'simple_access',
+        'gid' => $gid,
+        'grant_view' => $access['view'],
+        'grant_update' => $access['update'],
+        'grant_delete' => $access['delete'],
+      );
     }
   }
-  // if there are new view recrods set
-  if (!$views) {
+
+  // If access restrictions have been set, assign a simple_access_author gid
+  if (!empty($records) && $node->uid) {
     $records[] = array(
-      'realm' => 'simple_access',
-      'gid' => 0,
-      'grant_view' => 1,
-      'grant_update' => 0,
-      'grant_update' => 0,
-      'priority' => 1,
+      'realm' => 'simple_access_author',
+      'gid' => $node->uid,
+      'grant_view' => TRUE,
+      'grant_update' => TRUE,
+      'grant_delete' => TRUE,
     );
   }
-  $records[] = array(
-    'realm' => 'simple_access_author',
-    'gid' => $node->uid,
-    'grant_view' => user_access('access content'),
-    'grant_update' => user_access('access content'),
-    'grant_delete' => user_access('access content'),
-    'priority' => 0,
-  );
+
   return $records;
 }
 
+
 /**
  * Implementation of hook_node_grants().
- *
- *  @TODO implement to correcly return groups in all cases.
  */
 function simple_access_node_grants($account, $op) {
-  $gids = simple_access_groups_from_roles( array_keys($account->roles));
+
+  $gids = simple_access_groups_from_roles(array_keys($account->roles));
   $grants['simple_access'] = $gids;
   $grants['simple_access_author'] = array($account->uid);
   return $grants;
+
 }
 
-function simple_access_form_alter($form_id, &$form){
-  // if this is a node form...
+
+/**
+ * Add simple_access options to the node input form
+ */
+function simple_access_form_alter(&$form, $form_state, $form_id){
+  // If this is a node form then add the simple_access fields to it
   if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id) {
     if ($simple_access_form = simple_access_form($form['#node'])) {
       $form = array_merge($form, $simple_access_form);
@@ -197,387 +212,208 @@
   }
 }
 
+
+/**
+ * Generate the form elements for the node input form
+ */
 function simple_access_form($node){
-  if (user_access('assign access to nodes') || user_access('administer nodes')){
-    //include the css
-    drupal_add_css(drupal_get_path('module', 'simple_access') .'/simple_access.css');
-    // set up the outer fieldset
-    $form['simple_access'] = array(
-      '#title' => t('Access'),
-      '#type' => 'fieldset',
-      '#collapsible' => true,
-      '#collapsed' => true,
-      '#tree' => true,
-      '#weight' => 5
-    );
 
-    if (!isset($node->simple_access)) {
-      // Load the grants from the database.
-      $result = db_query('SELECT na.gid, na.grant_view, na.grant_update, na.grant_delete FROM {node_access} na WHERE na.nid = %d AND na.realm = \'simple_access\'', $node->nid);
-      while($grant = db_fetch_object($result)) {
-        if ($grant->gid > 0) {
-          if ($grant->grant_view) {
-            $views[$grant->gid] = $grant->gid;
-          }
-          if ($grant->grant_update) {
-            $updates[$grant->gid] = $grant->gid;
-          }
-          if ($grant->grant_delete) {
-            $deletes[$grant->gid] = $grant->gid;
-          }
-        }
-      }
-      $node->simple_access = array(
-        'views' => $views,
-        'updates' => $updates,
-        'deletes' => $deletes
-      );
-    }
+  $user_groups = array_filter($node->simple_access, '_simple_access_filter_access');
 
-    // See what form elements we should include. If not configured,
-    // only enable the 'view' elements by default.
-    $variable = variable_get('sa_display', array('view' => 1));
-    $count = count($variable) ? count($variable) : 1;
-    $percent = 90/$count;
-
-    // Get the array of checkbox options to use for each form element.  
-    // If the "Show groups even when user is not a member" setting is
-    // enabled, or if the current user has 'administer nodes', let
-    // them choose from any of the SA groups.
-    $options = simple_access_group_select(user_access('administer nodes') || variable_get('sa_showgroups', 0));
-
-    // This is the only stuff that changes for each
-    // so we put it all in one place for easy editing
-    $loop = array(
-      'view' => array(
-        'title' => t('Only viewable by'),
-        'description' => '<span style="font-size:xx-small">'. t('All unchecked = viewable by all.') .'</span>',
-        'default' => $views,
-      ),
-      'update' => array(
-        'title' => t('Additionally editable by'),
-        'description' => '<span style="font-size:xx-small">'. t('All unchecked = normal behavior<br />(author and admins can edit).') .'</span>',
-        'default' => $updates,
-      ),
-      'delete' => array(
-        'title' => t('Additionally deletable by'),
-        'description' => '<span style="font-size:xx-small">'. t('All unchecked = normal behavior<br />(author and admins can delete).') .'</span>',
-        'default' => $deletes,
-      ),
-    );
-    foreach($loop as $key => $vals) {
-      if ($variable[$key]) {
-        $form['simple_access'][$key] = array(
-          '#type' => 'fieldset',
-          '#title' => $vals['title'],
-          '#description' => $vals['description'],
-          '#attributes' => array('class' => 'sa-inline', 'style' => "width:$percent%"),
-        );
-        if ($options) {
-          $form['simple_access'][$key]['checks'] = array(
-            '#type' => 'checkboxes',
-            '#title' => '',
-            '#default_value' => $vals['default'],
-            '#options' => $options
-          );
-        }
-        else {
-          $form['simple_access'][$key][] = array(
-            '#type' => 'markup',
-            '#value' => t('No <a href="!url">access groups</a> have been defined', array('!url' => url('admin/user/simple_access')))
-          );
-        }
-      }
-    }
-    // stick in a div to keep the floats working right
-    $form['simple_access'][] = array(
-      '#type' => 'markup',
-      '#value' => '<div class="sa-after"></div>'
+  // set up the outer fieldset
+  $form['simple_access'] = array(
+    '#title' => t('Access'),
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => empty($user_groups),
+    '#tree' => TRUE,
+    '#weight' => 5,
+    '#access' => user_access('assign access to nodes') || user_access('administer nodes'),
+    '#theme' => 'simple_access_form',
+  );
+
+  // See what form elements we should include. If not configured,
+  // only enable the 'view' elements by default.
+  $variable = variable_get('sa_display', array('view' => 1));
+
+  // Get the array of checkbox options to use for each form element.
+  // If the "Show groups even when user is not a member" setting is
+  // enabled, or if the current user has 'administer nodes', let
+  // them choose from any of the SA groups.
+  $groups = simple_access_group_select();
+
+  foreach ($groups as $gid => $group) {
+    $access = $group->access || user_access('administer nodes');
+    $form['simple_access'][$gid] = array(
+      '#access' => $access,
+    );
+    $form['simple_access'][$gid]['name'] = array(
+      '#value' => $group->name,
+      '#access' => $access,
+    );
+    $form['simple_access'][$gid]['view'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => $node->simple_access[$gid]['view'],
+      '#access' => $access && $variable['view'],
+    );
+    $form['simple_access'][$gid]['update'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => $node->simple_access[$gid]['update'],
+      '#access' => $access && $variable['update'],
+    );
+    $form['simple_access'][$gid]['delete'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => $node->simple_access[$gid]['delete'],
+      '#access' => $access && $variable['delete'],
     );
-    return $form;
   }
+  return $form;
 }
 
-function simple_access_delete_group_confirm() {
-  $gid = arg(4);
-  $form['gid'] = array(
-    '#type' => 'hidden',
-    '#value' => $gid
-  );
-  return confirm_form($form,
-    t('Are you sure you want to delete this group?'),
-    'admin/user/simple_access',
-    t('This action cannot be undone.'), t('Delete'), t('Cancel')
-  );
-}
-
-function simple_access_delete_group_confirm_submit($form_id, $form_values) {
-  simple_access_delete_group($form_values['gid']);
-  return 'admin/user/simple_access';
-}
 
-function simple_access_page_overview() {
-  if (count($rg = simple_access_get_groups())) {
-    drupal_set_title(t('Access Groups'));
-    $header = array(t('Group'), t('Roles'), t('Operations'));
-    $roles = user_roles();
-    foreach ($rg as $g) {
-      $gid = $g['gid'];
-      $rows[$gid]['group'] = $g['name'];
-      $r = array();
-      foreach($g['roles'] as $rid) {
-        $r[] = $roles[$rid];
-      }
-      $rows[$gid]['roles'] = "<span style='font-size:xx-small'>".implode(', ', $r)."</span>";
-      $rows[$gid]['ops'] = l('edit', 'admin/user/simple_access/edit/'.$gid). '&nbsp;'. l('delete', 'admin/user/simple_access/delete/'.$gid);
+/**
+ * Theme simple_access table for the node editing form
+ */
+function theme_simple_access_form($form) {
+  $variable = variable_get('sa_display', array('view' => 1));
+  $head = array(t('Access Group'));
+  if ($variable['view']) {
+    $head[] = t('View');
+  }
+  if ($variable['update']) {
+    $head[] = t('Edit');
+  }
+  if ($variable['delete']) {
+    $head[] = t('Delete');
+  }
+
+  foreach (element_children($form) as $gid) {
+    $row = array(
+      array('data' => drupal_render($form[$gid]['name'])),
+    );
+    if ($variable['view']) {
+      $row[] = array(
+        'data' => drupal_render($form[$gid]['view']),
+      );
     }
-    $output .= theme('table', $header, $rows, array('style'=>'width:100%'));
-    $output .= '<br />'.l(t('add another access group'), 'admin/user/simple_access/add');
-    return $output;
-  }
-  else {
-    drupal_set_message(t('You have not yet defined any access groups.'));
-    drupal_goto('admin/user/simple_access/add');
+    if ($variable['update']) {
+      $row[] = array(
+        'data' => drupal_render($form[$gid]['update']),
+      );
+    }
+    if ($variable['delete']) {
+      $row[] = array(
+        'data' => drupal_render($form[$gid]['delete']),
+      );
+    }
+
+    $rows[] = $row;
   }
-}
 
-function simple_access_settings_page() {
-  drupal_set_title(t('Simple Access Settings'));
-  $options = array(
-    'view' => t('<strong>View</strong>: Displays viewability selections at top of node form. Selected access groups will be the only users who can view the node. All unselected = normal node behavior (viewable by all).<br />'),
-    'update' => t('<strong>Edit</strong>: Displays editability selections at top of node form. Users who are part of selected access groups will be able to edit this node. All unselected = "normal" node behavior (only author and admins may edit).<br />'),
-    'delete' => t('<strong>Delete</strong>: Displays deleteability selections at top of node form. Users who are part of selected access groups will be able to delete this node. All unselected = "normal" node behavior (only author and admins may delete).<br />')
-  );
-  $form['sa_display'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Display'),
-    '#default_value' => variable_get('sa_display', array('view')),
-    '#options' => $options,
-    '#description' => t('Which options should appear on node add/edit pages for administrators? Select at least one.'),
-    '#required' => TRUE
-  );
-   $form['sa_showgroups'] = array(
-    '#type' => 'checkbox',
-    '#title' => 'Show groups even when user is not a member.',
-    '#default_value' => variable_get('sa_showgroups',0),
-    '#description' => 'This is useful when you want to have a user be able to make content viewable by themselves and a higher privileged group (e.g. students sharing work with faculty)',
-    );
-  return system_settings_form($form);
-}
+  $output.= theme('table', $head, $rows);
 
-function simple_access_deactivate_confirm_submit($form_id, $form_values) {
-  simple_access_initialize(FALSE);
-  return 'admin/access/simple_access/setup';
-}
-
-function simple_access_group_form($gid = NULL) {
-  if ($gid) {
-    drupal_set_title(t('Edit Access Group'));
-    $group = db_fetch_object(db_query('SELECT name, weight FROM {simple_access_groups} WHERE gid = %d', $gid));
-    $name = $group->name;
-    $weight = $group->weight;
-    $roles = simple_access_get_roles($gid);
-    $form['gid'] = array(
-      '#type' => 'hidden',
-      '#value' => $gid,
-    );
-  }
-  else {
-    drupal_set_title(t('Create Access Group'));
-    $weight = 0;
-  }
-  $form['name'] = array(
-    '#type' => 'textfield',
-    '#title' => t('Name'),
-    '#default_value' => $name,
-    '#size' => 40,
-    '#maxlength' => 80,
-    '#description' => t('The name for the access group as it will appear on the content editing form.'),
-    '#attributes' => $attributes = NULL,
-    '#required' => TRUE,
-  );
-  $form['roles'] = array(
-    '#type' => 'checkboxes',
-    '#title' => t('Roles'),
-    '#default_value' => $roles,
-    '#options' => user_roles(),
-    '#description' => t('Roles that can view'),
-  );
-  $form['weight'] = array(
-    '#type' => 'weight',
-    '#title' => 'Weight',
-    '#default_value' => $weight,
-    '#delta' => 10,
-    '#description' => t('When setting permissions, heavier names will sink and lighter names will be positioned nearer the top.'),
-  );
-  $form[] = array(
-    '#type' => 'submit',
-    '#value' => t('Submit'),
-  );
-  return $form;
+  return $output;
 }
 
-function simple_access_group_form_submit($form_id, $form_values) {
-  simple_access_save_group($form_values);
-  return 'admin/user/simple_access';
-}
-
-function simple_access_get_roles($gid) {
-  $roles = array();
-  $sql = db_query('SELECT rid FROM {simple_access_roles} WHERE gid = %d', $gid);
-  while ($row = db_fetch_object($sql)) {
-    $roles[] = $row->rid;
-  }
-  return $roles;
-}
-
-function simple_access_get_groups() {
-  $groups = array();
-  $sql = db_query('SELECT gid, name FROM {simple_access_groups} ORDER BY weight, name');
-  while ($g = db_fetch_object($sql)) {
-    $groups[$g->gid]['name'] = $g->name;
-    $groups[$g->gid]['gid'] = $g->gid;
-    $groups[$g->gid]['roles'] = simple_access_get_roles($g->gid);
-  }
-  return $groups;
+
+/**
+ * Filter the access records for the corrent user
+ */
+function _simple_access_filter_access($a) {
+  $groups = simple_access_group_select();
+  return isset($groups[$a['gid']]->access) && $groups[$a['gid']]->access;
 }
 
-function simple_access_group_select($all = FALSE) {
-  $groups = array();
-  if ($all){
-    // return all of the groups (for node administrators)
+
+/**
+ * Return a list of groups of which the user is a member
+ */
+function simple_access_group_select() {
+  static $groups;
+
+  if (empty($groups)) {
+    global $user;
+    $default_access = user_access('administer nodes');
+
+    $groups = array();
     $result = db_query('SELECT gid, name FROM {simple_access_groups} ORDER BY weight, name');
-  }
-  else {
+    while ($group = db_fetch_object($result)) {
+      $groups[$group->gid] = $group;
+      $groups[$group->gid]->access = $default_access;
+
+    }
+
+    if (!$default_access) {
     // return just groups for which user is a member
-    global $user;
-    $roles = array_keys($user->roles);
-    $result = db_query('SELECT DISTINCT g.gid, g.name FROM {simple_access_groups} g INNER JOIN {simple_access_roles} r ON g.gid = r.gid WHERE r.rid IN (%s) ORDER BY weight, name', implode(',', $roles));
-  }
-  while ($g = db_fetch_object($result)) {
-    $groups[$g->gid] = $g->name;
+      $roles = array_keys($user->roles);
+      $result = db_query('SELECT DISTINCT g.gid FROM {simple_access_groups} g INNER JOIN {simple_access_roles} r ON g.gid = r.gid WHERE r.rid IN ('. db_placeholders($roles) .') ORDER BY weight, name', $roles);
+      while ($group = db_fetch_object($result)) {
+        $groups[$group->gid]->access = TRUE;
+      }
+    }
   }
   return $groups;
 }
 
+
 /**
-  * Get a list of group/grant ids based on a list of user roles
-  * $roles should be a linear list a role ids
-  */
+ * Get a list of group/grant ids based on a list of user roles
+ * $roles should be a linear list a role ids
+ */
 function simple_access_groups_from_roles($roles) {
   // there probably should be some 'static' stuff going on here
-  // always return gid 0 just to be safe. 
+  // always return gid 0 just to be safe.
   $gids = array(0);
-  $result = db_query("SELECT gid FROM {simple_access_roles} WHERE rid IN (%s)", implode(",", $roles));
+  $result = db_query('SELECT gid FROM {simple_access_roles} WHERE rid IN ('.db_placeholders($roles).')', $roles);
   while ($g = db_fetch_object($result)) {
     $gids[] = $g->gid;
   }
   return $gids;
 }
 
-/**
-  * Save group of roles into the database
-  * $roles is an associative array of roles where the keys are role ids
-  * $name is the name of the group
-  * $gid is the group id
-  *
-  */
-
-function simple_access_save_group($edit) {
-  if (!$edit['gid']) {
-    $edit['gid'] = db_next_id('{simple_access_groups}_gid');
-  }
-  db_query('DELETE FROM {simple_access_roles} WHERE gid = %d', $edit['gid']);
-  db_query('DELETE FROM {simple_access_groups} WHERE gid = %d', $edit['gid']);
-  $success = db_query("INSERT INTO {simple_access_groups} (gid, name, weight) VALUES (%d, '%s', %d)", $edit['gid'], $edit['name'], $edit['weight']);
-  if (is_array($edit['roles'])) {
-    foreach($edit['roles'] as $key => $value) {
-      if ($value) {
-        $success = $success && db_query('INSERT INTO {simple_access_roles} (rid, gid) VALUES (%d, %d)', $key, $edit['gid']);
-      }
-    }
-  }
-  if (!$success) {
-    drupal_set_message(t('There was a problem saving to the database.'));
-  }
-  return $success;
-}
-
-function simple_access_delete_group($gid) {
-  db_query('DELETE FROM {simple_access_roles} WHERE gid = %d', $gid);
-  db_query('DELETE FROM {simple_access_groups} WHERE gid = %d', $gid);
-}
 
-function simple_access_initialize($initialize = TRUE) {
-  if ($initialize) {
-    // delete universal view grant
-    db_query("DELETE FROM {node_access} WHERE nid = 0 AND realm = 'all'");
-    // set all nodes to viewable
-    db_query("INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) SELECT nid, 0, 'simple_access', 1, 0, 0 FROM {node}");
-    variable_set('simple_access_active', TRUE);
-    drupal_set_message(t('The database has been configured and simple_access module is ready for use.'));
-  }
-  else {
-    // delete all simple_access stuff
-    db_query("DELETE FROM {node_access} WHERE realm = 'simple_access'");
-    // re-enable universal view grant
-    db_query("INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (0, 0, 'all', 1, 0, 0)");
-    variable_set('simple_access_active', FALSE);
-    drupal_set_message(t('The database has been re-configured. You should now visit %modules to disable the simple_access module itself.', array('%modules' => l('the modules page', 'admin/build/modules'))));
-  }
+/**
+ * Implementation of hook_theme
+ */
+function simple_access_theme() {
+  return array(
+    'simple_access_nodes' => array(
+      'arguments' => array(
+        'task' => NULL,
+      ),
+      'file' => 'simple_access.admin.inc',
+    ),
+    'simple_access_admin_new_group' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'simple_access.admin.inc',
+    ),
+   'simple_access_admin_list_groups' => array(
+      'arguments' => array('form' => NULL),
+      'file' => 'simple_access.admin.inc',
+    ),
+    'simple_access_form' => array(
+      'arguments' => array('form' => NULL),
+    ),
+  );
 }
 
 
 /**
-  * List hidden, editable, and deletable nodes
-  *
-  */
-function simple_access_nodes() {
-  switch(arg(3)) {
-    case 'edit':
-      drupal_set_title(t('Items With Edit Access Set'));
-      $output = '<div>'.t('These nodes have been set as "additionally editable by" certain Simple Access <a href="!url">groups</a>. ', array('!url' => url('admin/user/simple_access'))).'</div><br />';
-      $sql = "SELECT DISTINCT n.title, na.nid FROM {node} n INNER JOIN {node_access} na ON n.nid = na.nid WHERE na.realm='simple_access' AND na.gid > 0 AND na.grant_update = 1";
-      break;
-    case 'delete':
-      drupal_set_title(t('Items With Delete Access Set'));
-      $output = '<div>'.t('These nodes have been set as "additionally deletable by" certain Simple Access <a href="!url">groups</a>. ', array('!url' => url('admin/user/simple_access'))).'</div><br />';
-      $sql = "SELECT DISTINCT n.title, na.nid FROM {node} n INNER JOIN {node_access} na ON n.nid = na.nid WHERE na.realm='simple_access' AND na.gid > 0 AND na.grant_delete = 1";
-      break;
-    case 'view':
-    default:
-      drupal_set_title(t('Items With View Access Set'));
-      $output = '<div>'.t('These nodes have been set as "only viewable by" certain Simple Access <a href="!url">groups</a>.', array('!url' => url('admin/user/simple_access'))).'</div><br />';
-      $sql = "SELECT DISTINCT n.title, na.nid FROM {node} n INNER JOIN {node_access} na ON n.nid = na.nid WHERE na.realm='simple_access' AND na.gid > 0 AND na.grant_view = 1";
-      break;
-  }
-  $header = array(
-    array('data' => t('ID'), 'field' => 'n.nid', 'sort' => 'desc'),
-    array('data' => t('Title'), 'field' => 'n.title'),
-    array('data' => '&nbsp;')
-  );
-  $sql .= tablesort_sql($header);
-  $result = pager_query($sql, 50);
-  $groups_info = simple_access_get_groups();
-  while ($r = db_fetch_object($result)) {
-    $groups = array();
-    $rs2 = db_query('SELECT na.gid, na.grant_view, na.grant_update, na.grant_delete FROM {node_access} na WHERE na.nid = %d AND na.realm = \'simple_access\'', $r->nid);
-    while ($r2 = db_fetch_object($rs2)) {
-      $groups[] = $groups_info[$r2->gid]['name'];
-    }
-    $rows[$r->nid]['nid'] = array('data' => $r->nid, 'style' => 'vertical-align:top');
-    $info = '<div>'.$r->title.'</div><div style="font-size:xx-small">'.implode(', ', $groups).'</div>';
-    $rows[$r->nid]['title'] = array('data' => $info, 'style' => 'vertical-align:top');
-    $rows[$r->nid]['ops'] = array('data' => l(t('view'), 'node/'.$r->nid).' '.l(t('edit'), 'node/'.$r->nid.'/edit', array(), drupal_get_destination()), 'style' => 'vertical-align:top');
-  }
-  if ($rows) {
-    $output .= theme('table', $header, $rows, array('style' => 'width:100%'));
-    $output .= theme('pager', array(), 50);
-  }
-  else {
-    $output .= '<div>'.t('No nodes match this criteria.').'</div>';
-  }
-  return $output;
-}
-
+ * Implementation of hook_help().
+ */
+function simple_access_help($path, $arg) {
+ switch ($path) {
+   case 'admin/content/simple_access':
+     return '<p>'. t('These nodes have been set as only viewable by certain simple access <a href="@url">groups</a>.', array('@url' => url('admin/user/simple_access'))) .'</p>';
+   case 'admin/content/simple_access/edit':
+     return '<p>'. t('These nodes have been set as additionally editable by certain simple access <a href="@url">groups</a>.', array('@url' => url('admin/user/simple_access'))) .'</p>';
+   case 'admin/content/simple_access/delete':
+     return '<p>'. t('These nodes have been set as additionally deletable by certain simple access <a href="@url">groups</a>.', array('@url' => url('admin/user/simple_access'))) .'</p>';
+   case 'admin/user/simple_access':
+     return '<p>'. t('Simple access uses access groups to control who can view, edit and delete nodes. The table below shows the groups that have been defined, and which <a href="@roles">roles</a> are members of each group (note - a role can be a member of more than one group). When setting access permissions on a node you choose the groups you want to limit the node to and then only users who have a role that is in one the selected access groups can access it.', array('@roles' => url('admin/user/roles'))) .'</p>';
+   case 'admin/user/simple_access/add':
+   case 'admin/user/simple_access/edit/%':
+     return '<p>'. t('Set the name for this access group, and assign which <a href="@roles">roles</a> are members of the group.', array('@roles' => url('admin/user/roles'))) .'</p>';
 
+ }
+}
Index: simple_access.admin.inc
===================================================================
RCS file: simple_access.admin.inc
diff -N simple_access.admin.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ simple_access.admin.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,402 @@
+<?php
+// $Id$
+
+/**
+ * List hidden, editable, and deletable nodes
+ */
+function simple_access_nodes($task = 'view') {
+  return theme('simple_access_nodes', $task);
+}
+
+
+/**
+ * Theme a page showing nodes with simple_access view, edit or delete privileges assigned
+ */
+function theme_simple_access_nodes($task) {
+
+  // Set page title
+  drupal_set_title(t('Items with '. $task .' access set'));
+
+  // Array to help build sql string
+  $task_sql = array(
+    'view' => 'grant_view = 1',
+    'edit' => 'grant_update = 1',
+    'delete' => 'grant_delete = 1',
+  );
+
+  // Retrieve list of simple_access groups
+  $groups_info = simple_access_get_groups();
+
+  // Construct a table to hold results
+  $header = array(
+    array('data' => t('Node'), 'field' => 'n.nid', 'sort' => 'desc'),
+    array('data' => t('Title'), 'field' => 'n.title'),
+    array('data' => t('Operations'), 'colspan' => 2),
+  );
+
+  // Select all nodes that have the appropriate simple_access grant
+  $sql = "SELECT DISTINCT n.title, n.nid FROM {node} n INNER JOIN {node_access} na ON n.nid = na.nid WHERE na.realm = 'simple_access' AND na.gid > 0 AND na." . $task_sql[$task];
+  $sql .= tablesort_sql($header);
+  $nodes = pager_query($sql, 50);
+
+  // Retrieve results and populate rows
+  $rows = array();
+
+  // Iterate through the nodes
+  while ($node = db_fetch_object($nodes)) {
+    $node_groups = array();
+
+    // Retrieve simple_access groups that are active for this node in this mode
+    $groups = db_query("SELECT gid FROM {node_access} WHERE nid = %d AND realm = 'simple_access' AND gid > 0 AND ".$task_sql[$task], $node->nid);
+    while ($group = db_fetch_object($groups)) {
+      $node_groups[] = $groups_info[$group->gid]['name'];
+    }
+
+    // Generate a row in the table
+    $rows[] = array(
+      array('data' => $node->nid, 'style' => 'vertical-align:top'),
+      array('data' => $node->title . '<div style="font-size:xx-small">' . implode(', ', $node_groups) . '</div>', 'style' => 'vertical-align:top'),
+      array('data' => l(t('view'), 'node/'.$node->nid), 'style' => 'vertical-align:top'),
+      array('data' => l(t('edit'), 'node/'.$node->nid.'/edit', array('query' => drupal_get_destination())), 'style' => 'vertical-align:top'),
+    );
+
+  }
+
+  // If no rows found nothing matched so show a message instead
+  if (!$rows) {
+    $rows[] = array(array('data' => '<em>'. t('No nodes match this criteria.') .'</em>', 'colspan' => 4));
+  }
+
+  // Output table and pager
+  $output .= theme('table', $header, $rows);
+  $output .= theme('pager', array(), 50);
+
+  // Return output
+  return $output;
+}
+
+
+/**
+ * Retrieve simple_access groups from the database, and return an array of results
+ * Key is group id, values are group name and an array of roles who are members of the group
+ */
+function simple_access_get_groups() {
+  $groups = array();
+  $sql = db_query('SELECT gid, name FROM {simple_access_groups} ORDER BY weight, name');
+  while ($g = db_fetch_object($sql)) {
+    $groups[$g->gid]['name'] = $g->name;
+    $groups[$g->gid]['roles'] = simple_access_get_roles($g->gid);
+  }
+  return $groups;
+}
+
+/**
+ * Return an array of role ids that are members of the group specified by the supplied parameter gid
+ */
+function simple_access_get_roles($gid) {
+  $roles = array();
+  $sql = db_query('SELECT rid FROM {simple_access_roles} WHERE gid = %d', $gid);
+  while ($row = db_fetch_object($sql)) {
+    $roles[] = $row->rid;
+  }
+  return $roles;
+}
+
+
+/**
+ * Return a confirmation form asking for confirmation to delete the role specifed by gid
+ */
+function simple_access_delete_group_confirm($form_state, $gid) {
+
+  $group_name = db_result(db_query('SELECT name FROM {simple_access_groups} WHERE gid = %d', $gid));
+
+  $form['gid'] = array(
+    '#type' => 'hidden',
+    '#value' => $gid
+  );
+
+  return confirm_form(
+    $form,
+    t('Are you sure you want to delete the group %group_name?', array('%group_name' => $group_name)),
+    'admin/user/simple_access/edit/'.$gid,
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+
+/**
+ * Submit handler for simple_access_delete_group_confirm - delete the requested group
+ */
+function simple_access_delete_group_confirm_submit($form, &$form_state) {
+
+  // Get gid from the form
+  $gid = $form_state['values']['gid'];
+
+  // Delete all entries for this group from simple access tables
+  db_query('DELETE FROM {simple_access_roles} WHERE gid = %d', $gid);
+  db_query('DELETE FROM {simple_access_groups} WHERE gid = %d', $gid);
+  db_query('DELETE FROM {simple_access_node} WHERE gid = %d', $gid);
+
+  // Remind user that group deletion requires access rebuild following group deletion
+  node_access_needs_rebuild(TRUE);
+
+  // Send user back to the group administration form as this is where they started
+  $form_state['redirect'] = 'admin/user/simple_access';
+  return;
+}
+
+
+/**
+ * Return the settings page for simple access
+ */
+function simple_access_settings_page() {
+
+  $options = array(
+    'view' => t('<strong>View</strong>: Displays viewability selections at top of node form. Selected access groups will be the only users who can view the node. All unselected = normal node behavior (viewable by all).<br />'),
+    'update' => t('<strong>Edit</strong>: Displays editability selections at top of node form. Users who are part of selected access groups will be able to edit this node. All unselected = "normal" node behavior (only author and admins may edit).<br />'),
+    'delete' => t('<strong>Delete</strong>: Displays deleteability selections at top of node form. Users who are part of selected access groups will be able to delete this node. All unselected = "normal" node behavior (only author and admins may delete).<br />')
+  );
+
+  $form['sa_display'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Display'),
+    '#default_value' => variable_get('sa_display', array('view')),
+    '#options' => $options,
+    '#description' => t('Which options should appear on node add/edit pages for administrators? Select at least one.'),
+    '#required' => TRUE
+  );
+
+  $form['sa_showgroups'] = array(
+    '#type' => 'checkbox',
+    '#title' => 'Show groups even when user is not a member.',
+    '#default_value' => variable_get('sa_showgroups',0),
+    '#description' => t('This is useful when you want to have a user be able to make content viewable by themselves and a higher privileged group (e.g. students sharing work with faculty)'),
+    );
+
+  return system_settings_form($form);
+}
+
+
+/**
+ * Validate handler for simple_access_add_edit_group
+ */
+function simple_access_add_edit_group_validate($form, &$form_state) {
+
+  // Check that a group name was assigned
+  if ($form_state['values']['name']) {
+
+    // If saving an existing group check the name was not changed to something that already exists
+    if ($form_state['values']['gid']) {
+      if (db_result(db_query("SELECT COUNT(*) FROM {simple_access_groups} WHERE name = '%s' AND gid != %d", $form_state['values']['name'], $form_state['values']['gid']))) {
+        form_set_error('name', t('The group name %name already exists. Please choose another group name.', array('%name' => $form_state['values']['name'])));
+      }
+    }
+    // If adding a new group check the name does not already exist
+    else {
+      if (db_result(db_query("SELECT COUNT(*) FROM {simple_access_groups} WHERE name = '%s'", $form_state['values']['name']))) {
+        form_set_error('name', t('The group name %name already exists. Please choose another group name.', array('%name' => $form_state['values']['name'])));
+      }
+    }
+  }
+  else {
+    // Get here if no group name was given
+    form_set_error('name', t('You must specify a valid group name.'));
+  }
+}
+
+
+/**
+ * Submit handler for simple_access_add_edit_group
+ */
+function simple_access_add_edit_group_submit($form, &$form_state) {
+
+  // If saving an existing group update the name and weight, and prepare {simple_access_roles} to receive new data
+  if ($form_state['values']['gid']) {
+    db_query("UPDATE {simple_access_groups} SET name = '%s', weight = %d WHERE gid = %d", $form_state['values']['name'], $form_state['values']['weight'], $form_state['values']['gid']);
+    db_query('DELETE FROM {simple_access_roles} WHERE gid = %d', $form_state['values']['gid']);
+  }
+
+  // If creating a new group put it in to {simple_access_groups} and get the gid of the new group
+  else {
+    db_query("INSERT INTO {simple_access_groups} (name) VALUES ('%s')", $form_state['values']['name']);
+    $form_state['values']['gid'] = db_last_insert_id('simple_access', 'simple_access_groups');
+  }
+
+  // Put new roles in the database
+  foreach($form_state['values']['roles'] as $key => $value) {
+    if ($value) {
+      db_query('INSERT INTO {simple_access_roles} (rid, gid) VALUES (%d, %d)', $key, $form_state['values']['gid']);
+    }
+  }
+
+  // Display message and redirect to list view
+  drupal_set_message(t('The group has been saved.'));
+  $form_state['redirect'] = 'admin/user/simple_access';
+
+  return;
+}
+
+
+/**
+ *  Submit handler for simple_access_add_edit_group delete button
+ *  Redirect to delete handler if delete is clicked
+ */
+function simple_access_delete_group_submit($form, &$form_state) {
+  $form_state['redirect'] = array('admin/user/simple_access/delete/'.$form_state['values']['gid']);
+}
+
+
+/**
+ * Return a simple form that contains an action button to create a new access group
+ * This form is themed by its themer to include a table of existing groups
+ */
+function simple_access_admin_list_groups($form_state) {
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add group'),
+  );
+
+  return $form;
+}
+
+
+/**
+ * Redirect user to the form to add a role when the list form is submitted
+ */
+function simple_access_admin_list_groups_submit($form, &$form_state) {
+  $form_state['redirect'] = 'admin/user/simple_access/add';
+}
+
+
+/**
+ * Themer to go with simple_access_admin_list_groups
+ *
+ * This renders a table showing current groups to go above the submit button to create a new group
+ */
+function theme_simple_access_admin_list_groups($form) {
+
+  // Define a table to hold results
+  $header = array(
+    t('Group'),
+    t('Roles'),
+    t('Operations'),
+  );
+
+  // If there are groups defined by simple_access
+  if (count($groups = simple_access_get_groups())) {
+
+    // Get a list of available user roles
+    $roles = user_roles();
+
+    // Iterate through the groups
+    foreach ($groups as $gid => $group) {
+
+      // Define an array to hold results
+      $group_roles = array();
+
+      // Iterate through the roles in this group
+      foreach($group['roles'] as $rid) {
+
+        // If this role exists in the available user roles (this screens out deleted roles)
+        if ($roles[$rid]) {
+
+          // Add this role to the list for this group
+          $group_roles[] = $roles[$rid];
+        }
+      }
+
+      // Create a row in the table for this result
+      $rows[] = array(
+        $group['name'],
+        "<span style='font-size:xx-small'>".implode(', ', $group_roles)."</span>",
+        l(t('edit'), 'admin/user/simple_access/edit/'.$gid),
+      );
+    }
+  }
+  else {
+
+    // If no rows exist format a special row and set a helpful message
+    $rows[] = array(array('data' => '<em>'. t('There are currently no access groups defined.') .'</em>', 'colspan' => 3));
+    drupal_set_message(t('Add an access group to begin using simple access.'), 'warning');
+
+  }
+
+  // Add the form to create a new group to the bottom of the table
+  $rows[] = array(array('data' => drupal_render($form['submit']), 'colspan' => 3));
+
+  // Generate output
+  $output .= drupal_render($form);
+  $output .= theme('table', $header, $rows);
+
+  return $output;
+}
+
+
+/**
+ * Multi purpose form function - either the add group or edit group page, depending if $gid is set
+ */
+function simple_access_add_edit_group($form_state, $gid) {
+
+  $roles = array();
+
+  if ($gid) {
+    $group = db_fetch_object(db_query('SELECT name, weight FROM {simple_access_groups} WHERE gid = %d', $gid));
+    $roles = simple_access_get_roles($gid);
+
+    $form['gid'] = array(
+      '#type' => 'value',
+      '#value' => $gid,
+    );
+  }
+
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Name'),
+    '#default_value' => $group->name,
+    '#size' => 40,
+    '#maxlength' => 80,
+    '#description' => t('The name for the access group as it will appear on the content editing form.'),
+    '#required' => TRUE,
+  );
+
+  $form['roles'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Members'),
+    '#default_value' => $roles,
+    '#options' => user_roles(),
+    '#description' => t('Roles that are members of this group.'),
+  );
+
+  $form['weight'] = array(
+    '#type' => 'weight',
+    '#title' => 'Weight',
+    '#default_value' => $group->weight ? $group->weight : 0,
+    '#description' => t('When setting permissions, heavier names will sink and lighter names will be positioned nearer the top.'),
+  );
+
+  $form['actions'] = array('#prefix' => '<div class="confirmation container-inline">', '#suffix' => '</div>');
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save group'),
+  );
+
+  // Delete button is only applicable if editing an existing group - no context for a new group!
+  if ($gid) {
+    $form['actions']['delete'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete group'),
+      '#validate' => array(),
+      '#submit' => array('simple_access_delete_group_submit'),
+    );
+  }
+
+  $form['actions']['cancel'] = array(
+    '#value' => l(t('Cancel'), 'admin/user/simple_access'),
+  );
+
+  // Return the form
+  return $form;
+}
