Index: modules/filter/filter.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.install,v
retrieving revision 1.9
diff -u -r1.9 filter.install
--- modules/filter/filter.install	14 Apr 2008 17:48:37 -0000	1.9
+++ modules/filter/filter.install	2 May 2008 00:53:18 -0000
@@ -64,13 +64,6 @@
         'default' => '',
         'description' => t('Name of the input format (Filtered HTML).'),
       ),
-      'roles' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => t('A comma-separated string of roles; references {role}.rid.'), // This is bad since you can't use joins, nor index.
-      ),
       'cache' => array(
         'type' => 'int',
         'not null' => TRUE,
@@ -99,6 +92,11 @@
 }
 
 /**
+ * @defgroup updates-6.x-to-7.x Filter updates from 6.x to 7.x
+ * @{
+ */
+
+/**
  * Add a weight column to the filter formats table.
  */
 function filter_update_7000() {
@@ -122,3 +120,34 @@
   }
   return $ret;
 }
+
+/**
+ * Move filter format access to the user permissions handler.
+ */
+function filter_update_7002() {
+  $ret = array();
+  // Get list of roles to work with.
+  $result = db_query("SELECT rid FROM {role}");
+  while ($role = db_result($result)) {
+    $roles[$role] = $role;
+  }
+  
+  // Move role data from filter_formats to user permissions.
+  $result = db_query("SELECT name, roles FROM {filter_formats}");
+  while ($format = db_fetch_object($result)) {
+    $format_roles = explode(',', $format->roles);
+    foreach ($format_roles as $format_role) {
+      if (in_array($format_role, $roles)) {
+        $ret[] = update_sql("UPDATE {permission} SET perm = CONCAT(perm, ', use " . db_escape_string(check_plain($format->name)) . "') WHERE rid = " . $format_role);
+      }
+    }
+  }
+  // Finally, drop the roles field from filter_formats.
+  db_drop_field($ret, 'filter_formats', 'roles');
+  return $ret;
+}
+
+/**
+ * @} End of "defgroup updates-6.x-to-7.x"
+ * The next series of updates should start at 8000.
+ */
Index: modules/filter/filter.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.admin.inc,v
retrieving revision 1.11
diff -u -r1.11 filter.admin.inc
--- modules/filter/filter.admin.inc	14 Apr 2008 17:48:37 -0000	1.11
+++ modules/filter/filter.admin.inc	2 May 2008 00:53:18 -0000
@@ -21,13 +21,7 @@
 
   $form = array('#tree' => TRUE);
   foreach ($formats as $id => $format) {
-    $roles = array();
-    foreach (user_roles() as $rid => $name) {
-      // Prepare a roles array with roles that may access the filter.
-      if (strstr($format->roles, ",$rid,")) {
-        $roles[] = $name;
-      }
-    }
+    $roles = user_roles(FALSE, 'use ' . check_plain($format->name));
     $default = ($id == variable_get('filter_default_format', 1));
     $options[$id] = '';
     $form[$id]['name'] = array('#value' => $format->name);
@@ -95,7 +89,7 @@
 function filter_admin_format_page($format = NULL) {
   if (!isset($format->name)) {
     drupal_set_title(t("Add input format"));
-    $format = (object)array('name' => '', 'roles' => '', 'format' => '');
+    $format = (object)array('name' => '', 'format' => '');
   }
   return drupal_get_form('filter_admin_format_form', $format);
 }
@@ -108,9 +102,7 @@
  * @see filter_admin_format_form_submit()
  */
 function filter_admin_format_form(&$form_state, $format) {
-  $default = ($format->format == variable_get('filter_default_format', 1));
-  if ($default) {
-    $help = t('All roles for the default format must be enabled and cannot be changed.');
+  if ($format->format == variable_get('filter_default_format', 1)) {
     $form['default_format'] = array('#type' => 'hidden', '#value' => 1);
   }
 
@@ -121,23 +113,6 @@
     '#required' => TRUE,
   );
 
-  // Add a row of checkboxes for form group.
-  $form['roles'] = array('#type' => 'fieldset',
-    '#title' => t('Roles'),
-    '#description' => $default ? $help : t('Choose which roles may use this filter format. Note that roles with the "administer filters" permission can always use all the filter formats.'),
-    '#tree' => TRUE,
-  );
-
-  foreach (user_roles() as $rid => $name) {
-    $checked = strstr($format->roles, ",$rid,");
-    $form['roles'][$rid] = array('#type' => 'checkbox',
-      '#title' => $name,
-      '#default_value' => ($default || $checked),
-    );
-    if ($default) {
-      $form['roles'][$rid]['#disabled'] = TRUE;
-    }
-  }
   // Table with filters
   $all = filter_list_all();
   $enabled = filter_list_format($format->format);
@@ -156,6 +131,7 @@
   }
   if (!empty($format->format)) {
     $form['format'] = array('#type' => 'hidden', '#value' => $format->format);
+    $form['previous_name'] = array('#type' => 'hidden', '#value' => $format->name);
 
     // Composition tips (guidelines)
     $tips = _filter_tips($format->format, FALSE);
@@ -195,7 +171,7 @@
   $name = trim($form_state['values']['name']);
   $cache = TRUE;
 
-  // Add a new filter format.
+  // Add a new input format.
   if (!$format) {
     $new = TRUE;
     db_query("INSERT INTO {filter_formats} (name) VALUES ('%s')", $name);
@@ -203,6 +179,8 @@
     drupal_set_message(t('Added input format %format.', array('%format' => $name)));
   }
   else {
+    // Update the name of affected permission.
+    user_rename_permission('use '. check_plain($form_state['values']['previous_name']), 'use '. check_plain($name));
     drupal_set_message(t('The input format settings have been updated.'));
   }
 
@@ -219,25 +197,7 @@
     }
   }
 
-  // We store the roles as a string for ease of use.
-  // We should always set all roles to TRUE when saving a default role.
-  // We use leading and trailing comma's to allow easy substring matching.
-  $roles = array();
-  if (isset($form_state['values']['roles'])) {
-    foreach ($form_state['values']['roles'] as $id => $checked) {
-      if ($checked) {
-        $roles[] = $id;
-      }
-    }
-  }
-  if (!empty($form_state['values']['default_format'])) {
-    $roles = ',' . implode(',', array_keys(user_roles())) . ',';
-  }
-  else {
-    $roles = ',' . implode(',', $roles) . ',';
-  }
-
-  db_query("UPDATE {filter_formats} SET cache = %d, name='%s', roles = '%s' WHERE format = %d", $cache, $name, $roles, $format);
+  db_query("UPDATE {filter_formats} SET cache = %d, name='%s' WHERE format = %d", $cache, $name, $format);
 
   cache_clear_all($format . ':', 'cache_filter', TRUE);
 
@@ -256,14 +216,14 @@
  * @ingroup forms
  * @see filter_admin_delete_submit()
  */
-function filter_admin_delete() {
-  $format = arg(4);
+function filter_admin_delete($form_state, $format) {
   $format = db_fetch_object(db_query('SELECT * FROM {filter_formats} WHERE format = %d', $format));
 
   if ($format) {
     if ($format->format != variable_get('filter_default_format', 1)) {
       $form['format'] = array('#type' => 'hidden', '#value' => $format->format);
       $form['name'] = array('#type' => 'hidden', '#value' => $format->name);
+      $form['destination'] = array('#type' => 'hidden', '#value' => 'admin/settings/filters');
 
       return confirm_form($form, t('Are you sure you want to delete the input format %format?', array('%format' => $format->name)), 'admin/settings/filters', t('If you have any content left in this input format, it will be switched to the default input format. This action cannot be undone.'), t('Delete'), t('Cancel'));
     }
Index: modules/filter/filter.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/filter/filter.module,v
retrieving revision 1.210
diff -u -r1.210 filter.module
--- modules/filter/filter.module	23 Apr 2008 20:01:50 -0000	1.210
+++ modules/filter/filter.module	2 May 2008 00:53:19 -0000
@@ -154,9 +154,20 @@
  * Implementation of hook_perm().
  */
 function filter_perm() {
-  return array(
+  $default_format = variable_get('filter_default_format', 1);
+  $perms = array(
     'administer filters' => t('Manage input formats and filters, and select which roles may use them. %warning', array('%warning' => t('Warning: Give to trusted roles only; this permission has security implications.'))),
   );
+
+  // Generate permissions for each input format.
+  $result = db_query('SELECT * FROM {filter_formats} ORDER BY weight');
+  while ($format = db_fetch_object($result)) {
+    $perms['use '. check_plain($format->name)] = t('Use %input_format in forms when entering or editing content.', array('%input_format' => $format->name));
+    if ($format->format == $default_format) {
+      $perms['use '. check_plain($format->name)] .= ' ' . theme('placeholder', t('The default input format must be available to all users'));
+    }
+  }
+  return $perms;
 }
 
 /**
@@ -289,35 +300,45 @@
 }
 
 /**
- * Retrieve a list of input formats.
+ * Implementation of hook_form_alter().
+ */
+function filter_form_alter(&$form, &$form_state, $form_id) {
+  if ($form_id == 'user_admin_perm') {
+    // Disable the checkboxes for the default format permissions.
+    $default_format = filter_formats(variable_get('filter_default_format', 1));
+    foreach (user_roles() as $rid => $role) {
+      $form['checkboxes'][$rid]['use ' . check_plain($default_format->name)] = array(
+        '#type' => 'checkbox',
+        '#value' => 1,
+        '#disabled' => TRUE,
+      );
+    }
+  }
+}
+
+/**
+ * Retrieve a list of input formats the current user can use.
+ *
+ * @param $index
+ *   Optional format identifier. If provided, only this format object will be
+ *   returned. Otherwise all format objects in an array keyed by format ID.
  */
 function filter_formats($index = NULL) {
-  global $user;
   static $formats;
 
   // Administrators can always use all input formats.
-  $all = user_access('administer filters');
+  $access_all = user_access('administer filters');
+  $default_format = variable_get('filter_default_format', 1);
 
   if (!isset($formats)) {
     $formats = array();
-
-    $query = 'SELECT * FROM {filter_formats}';
-
-    // Build query for selecting the format(s) based on the user's roles.
-    $args = array();
-    if (!$all) {
-      $where = array();
-      foreach ($user->roles as $rid => $role) {
-        $where[] = "roles LIKE '%%,%d,%%'";
-        $args[] = $rid;
-      }
-      $query .= ' WHERE ' . implode(' OR ', $where) . ' OR format = %d';
-      $args[] = variable_get('filter_default_format', 1);
-    }
-
-    $result = db_query($query . ' ORDER by weight', $args);
+    $result = db_query('SELECT * FROM {filter_formats} ORDER BY weight');
     while ($format = db_fetch_object($result)) {
-      $formats[$format->format] = $format;
+      if ($access_all || ($format->format == $default_format) || user_access('use '. check_plain($format->name))) {
+        // Always add the default input format, otherwise add the format if
+        // the user has access to it.
+        $formats[$format->format] = $format;
+      }
     }
   }
   if (isset($index)) {
Index: modules/user/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.module,v
retrieving revision 1.904
diff -u -r1.904 user.module
--- modules/user/user.module	23 Apr 2008 20:01:56 -0000	1.904
+++ modules/user/user.module	2 May 2008 00:53:21 -0000
@@ -1635,6 +1635,69 @@
 }
 
 /**
+ * Retreive a list of permissions for a role.
+ *
+ * @param $rid
+ *   Optional. The role whose permissions are to be retreived.
+ * @param $reset
+ *   Reset the internal cache of user permissions.
+ * @return
+ *   An associative array of all the permissions for a role.
+ */
+function user_permissions($rid = NULL, $reset = FALSE) {
+  static $permissions = array();
+
+  if (empty($permissions[$rid]) || $reset) {
+    $all_permissions = module_invoke_all('perm');
+    $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
+    while ($role = db_fetch_object($result)) {
+      // Set all permissions to false by default.
+      foreach ($all_permissions as $permission => $description) {
+        $permissions[$role->rid][$permission] = FALSE;
+      }
+      // Specify the allowed permission as true.
+      foreach (explode(', ', $role->perm) as $permission) {
+        $permissions[$role->rid][$permission] = TRUE;
+      }
+    }
+  }
+
+  return is_numeric($rid) ? $permissions[$rid] : $permissions;
+}
+
+/**
+ * Rename a permission.
+ * 
+ * @param $old_perm
+ *   The current name of the permissions to renamed. May be a single string
+ *   permission or an array of permissions.
+ * @param $new_perm
+ *   The new name of the permissions. May be a single string permission or an
+ *   array of permissions. The type for $old_perm and $new_perm must match.
+ */
+function user_rename_permission($old_perm, $new_perm) {
+  // Convert parameters to arrays if they're not already.
+  if (!is_array($old_perm) && !is_array($new_perm)) {
+    $old_perm = array($old_perm);
+    $new_perm = array($new_perm);
+  }
+
+  $result = db_query('SELECT * FROM {permission}');
+  while ($permission = db_fetch_object($result)) {
+    // Create an associative array for easy mapping.
+    $permissions = drupal_map_assoc(explode(', ', $permission->perm));
+    foreach ($old_perm as $index => $name) {
+      // Give the permission the new name.
+      if (isset($permissions[$name]) && isset($new_perm[$index])) {
+        $permissions[$name] = $new_perm[$index];
+      }
+    }
+    $permission->perm = implode(', ', $permissions);
+    db_query("UPDATE {permission} SET perm = '%s' WHERE pid = %d", $permission->perm, $permission->pid);
+  }
+}
+
+/**
  * Implementation of hook_user_operations().
  */
 function user_user_operations($form_state = array()) {
Index: modules/user/user.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/user/user.admin.inc,v
retrieving revision 1.21
diff -u -r1.21 user.admin.inc
--- modules/user/user.admin.inc	14 Apr 2008 17:48:43 -0000	1.21
+++ modules/user/user.admin.inc	2 May 2008 00:53:20 -0000
@@ -493,20 +493,8 @@
  * @see theme_user_admin_perm()
  */
 function user_admin_perm($form_state, $rid = NULL) {
-  if (is_numeric($rid)) {
-    $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid WHERE r.rid = %d', $rid);
-  }
-  else {
-    $result = db_query('SELECT r.rid, p.perm FROM {role} r LEFT JOIN {permission} p ON r.rid = p.rid ORDER BY name');
-  }
-
-  // Compile role array:
-  // Add a comma at the end so when searching for a permission, we can
-  // always search for "$perm," to make sure we do not confuse
-  // permissions that are substrings of each other.
-  while ($role = db_fetch_object($result)) {
-    $role_permissions[$role->rid] = $role->perm . ',';
-  }
+  // Retrieve role permissions.
+  $role_permissions = user_permissions();
 
   // Retrieve role names for columns.
   $role_names = user_roles();
@@ -537,7 +525,7 @@
         );
         foreach ($role_names as $rid => $name) {
           // Builds arrays for checked boxes for each role
-          if (strpos($role_permissions[$rid], $perm . ',') !== FALSE) {
+          if ($role_permissions[$rid][$perm]) {
             $status[$rid][] = $perm;
           }
         }
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.250
diff -u -r1.250 system.install
--- modules/system/system.install	16 Apr 2008 11:35:52 -0000	1.250
+++ modules/system/system.install	2 May 2008 00:53:20 -0000
@@ -369,8 +369,8 @@
   db_query("INSERT INTO {role} (name) VALUES ('%s')", 'anonymous user');
   db_query("INSERT INTO {role} (name) VALUES ('%s')", 'authenticated user');
 
-  db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 1, 'access content', 0);
-  db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 2, 'access comments, access content, post comments, post comments without approval', 0);
+  db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 1, 'access content, use Filtered HTML', 0);
+  db_query("INSERT INTO {permission} (rid, perm, tid) VALUES (%d, '%s', %d)", 2, 'access comments, access content, post comments, post comments without approval, use Filtered HTML', 0);
 
   db_query("INSERT INTO {variable} (name, value) VALUES ('%s', '%s')", 'theme_default', 's:7:"garland";');
   db_query("UPDATE {system} SET status = %d WHERE type = '%s' AND name = '%s'", 1, 'theme', 'garland');
@@ -381,8 +381,8 @@
   db_query("INSERT INTO {node_access} (nid, gid, realm, grant_view, grant_update, grant_delete) VALUES (%d, %d, '%s', %d, %d, %d)", 0, 0, 'all', 1, 0, 0);
 
   // Add input formats.
-  db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('%s', '%s', %d)", 'Filtered HTML', ',1,2,', 1);
-  db_query("INSERT INTO {filter_formats} (name, roles, cache) VALUES ('%s', '%s', %d)", 'Full HTML', '', 1);
+  db_query("INSERT INTO {filter_formats} (name, cache) VALUES ('%s', %d)", 'Filtered HTML', 1);
+  db_query("INSERT INTO {filter_formats} (name, cache) VALUES ('%s', %d)", 'Full HTML', 1);
 
   // Enable filters for each input format.
 
