--- /home/mike/Documents/sunweb/role_delegation/role_delegation.module	2009-03-02 20:39:31.000000000 -0500
+++ ./role_delegation.module	2009-03-23 15:20:12.000000000 -0400
@@ -50,7 +50,8 @@
       $profile_access &= $account->status || user_access('administer users');
 
       // Determine access to role assignment page.
-      if (!$delegation_access = user_access('administer access control')) {
+      $delegation_access = FALSE;
+      if (!user_access('administer users') && !$delegation_access = user_access('administer access control')) {
         $perms = role_delegation_perm();
         foreach ($perms as $perm) {
           if (user_access($perm)) {
@@ -81,11 +82,11 @@
   $form['roles'] = array(
     '#type' => 'fieldset',
     '#title' => t('Roles'),
-    '#description' => t('The user receives the combined permissions of the authenticated user role, and all roles selected here.'),
     '#tree' => TRUE,
   );
   // Provide a separate checkbox for each role but hide those the user has no authority over.
   $roles = _role_delegation_roles();
+  $roles_preserve = array('authenticated user');
   foreach ($roles as $rid => $role) {
     if (!(user_access('assign all roles') || user_access(_role_delegation_make_perm($role)) || user_access('administer access control'))) {
       // Hide roles the user can't assign.
@@ -93,6 +94,9 @@
         '#type' => 'value',
         '#value' => isset($account->roles[$rid]),
       );
+      if (isset($account->roles[$rid])) {
+        $roles_preserve[] = $role;
+      }
     }
     else {
       $form['roles'][$rid] = array(
@@ -102,6 +106,7 @@
       );
     }
   }
+  $form['roles']['#description'] = t('The user receives the combined permissions of the %roles role(s), and all roles selected here. ', array('%roles' => implode(', ', $roles_preserve)));
   $form['account'] = array(
     '#type' => 'value',
     '#value' => $account,
@@ -152,4 +157,69 @@
   // Allow alphanumerics, space, hyphen, underscore.
   $role = preg_replace('/[^a-zA-Z0-9 \\-_]/', '', $role);
   return "assign $role role";
+}
+
+/**
+ * Implementation of hook_form_alter()
+ */
+function role_delegation_form_alter($form_id, &$form) {
+  // only show for user forms when roles can't already be assigned
+  if ($form_id != 'user_register' && $form_id != 'user_edit') {
+    return;
+  }
+  if (user_access('administer access control')) {
+    return;
+  }
+  // split up roles based on whether they are assignable or not
+  $current_roles = (is_numeric(arg(1)) && $user = user_load(array('uid' => arg(1)))) ? $user->roles : array();
+  $rids_default = array();
+  $rids_preserve = array(DRUPAL_AUTHENTICATED_RID => DRUPAL_AUTHENTICATED_RID);
+  $roles_preserve = array('authenticated user');
+  $roles_options = array();
+  $roles = _role_delegation_roles();
+  foreach ($roles as $rid => $role) {
+    if (user_access('assign all roles') || user_access(_role_delegation_make_perm($role))) {
+      if (array_key_exists($rid, $current_roles)) {
+        $rids_default[] = $rid;
+      }
+      $roles_options[$rid] = $role;
+    } else {
+      if (array_key_exists($rid, $current_roles)) {
+        $rids_preserve[$rid] = $rid;
+        $roles_preserve[] = $role;
+      }
+    }
+  }
+  // set up form items
+  $preserve_item = array(
+    '#type' => 'value',
+    '#value' => $rids_preserve,
+  );
+  $assign_item = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Roles'),
+    '#description' => t('The user receives the combined permissions of the %roles role(s), and all roles selected here. ', array('%roles' => implode(', ', $roles_preserve))),
+    '#options' => $roles_options,
+    '#default_value' => $rids_default,
+  );
+  if (isset($form['account'])) {
+    $form['account']['roles_preserve'] = $preserve_item;
+    $form['account']['roles_assign'] = $assign_item;
+  } else {
+    $form['roles_preserve'] = $preserve_item;
+    $form['roles_assign'] = $assign_item;
+  }
+}
+
+/**
+ * Implementation of hook_user()
+ */
+function role_delegation_user($op, &$edit, &$account, $category = NULL) {
+  if ($op != 'insert' && $op != 'submit') {
+    return;
+  }
+  if (!isset($edit['roles_assign'])) {
+    return;
+  }
+  $edit['roles'] = $edit['roles_preserve'] + array_filter($edit['roles_assign']);
 }
\ No newline at end of file
