Index: mollom.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.admin.inc,v
retrieving revision 1.44
diff -u -p -r1.44 mollom.admin.inc
--- mollom.admin.inc	25 Oct 2010 20:34:03 -0000	1.44
+++ mollom.admin.inc	2 Nov 2010 16:05:44 -0000
@@ -12,6 +12,9 @@
 function mollom_admin_form_list() {
   _mollom_testing_mode_warning();
 
+  // Reset the cached list of protected forms.
+  mollom_form_cache(TRUE);
+
   $modes = array(
     MOLLOM_MODE_ANALYSIS => t('Text analysis'),
     MOLLOM_MODE_CAPTCHA => t('CAPTCHA'),
@@ -26,15 +29,28 @@ function mollom_admin_form_list() {
   $result = db_query('SELECT form_id FROM {mollom_form}')->fetchCol();
   foreach ($result as $form_id) {
     $mollom_form = mollom_form_load($form_id);
-    $rows[] = array(
-      $mollom_form['title'],
-      t('!protection-mode (@discard)', array(
+    $row = array();
+    $row[] = $mollom_form['title'];
+    if ($mollom_form['mode'] == MOLLOM_MODE_ANALYSIS) {
+      $row[] = t('!protection-mode (@discard)', array(
         '!protection-mode' => $modes[$mollom_form['mode']],
         '@discard' => $mollom_form['discard'] ? t('discard') : t('retain'),
-      )),
-      l(t('Configure'), 'admin/config/content/mollom/manage/' . $form_id),
-      l(t('Unprotect'), 'admin/config/content/mollom/unprotect/' . $form_id),
-    );
+      ));
+    }
+    else {
+      $row[] = $modes[$mollom_form['mode']];
+    }
+    $row[] = array('data' => array(
+      '#type' => 'link',
+      '#title' => t('Configure'),
+      '#href' => 'admin/config/content/mollom/manage/' . $form_id,
+    ));
+    $row[] = array('data' => array(
+      '#type' => 'link',
+      '#title' => t('Unprotect'),
+      '#href' => 'admin/config/content/mollom/unprotect/' . $form_id,
+    ));
+    $rows[] = $row;
   }
 
   $build['forms'] = array(
@@ -133,7 +149,6 @@ function mollom_admin_configure_form($fo
     case 'configure':
       drupal_set_title(t('Configure %form-title protection', array('%form-title' => $mollom_form['title'])), PASS_THROUGH);
 
-      // Display a list of fields for textual analysis (last step).
       $form['mollom']['form_id'] = array(
         '#type' => 'value',
         '#value' => $mollom_form['form_id'],
@@ -154,6 +169,36 @@ function mollom_admin_configure_form($fo
         '#default_value' => isset($mollom_form['mode']) ? $mollom_form['mode'] : key($modes),
       );
 
+      $all_permissions = array();
+      foreach (module_implements('permission') as $module) {
+        $module_permissions = module_invoke($module, 'permission');
+        foreach ($module_permissions as &$info) {
+          $info += array('module' => $module);
+        }
+        $all_permissions += $module_permissions;
+      }
+      // Prepend Mollom's global permission to the list.
+      array_unshift($mollom_form['bypass access'], 'bypass mollom protection');
+      $permissions = array();
+      foreach ($mollom_form['bypass access'] as $permission) {
+        // @todo D7: Array keys are used as CSS class for the link list item,
+        //   but are not sanitized: http://drupal.org/node/98696
+        $permissions[drupal_html_class($permission)] = array(
+          'title' => $all_permissions[$permission]['title'],
+          'href' => 'admin/people/permissions',
+          'fragment' => 'module-' . $all_permissions[$permission]['module'],
+          'html' => TRUE,
+        );
+      }
+      $form['mollom']['mode']['#description'] = t('The protection is omitted for users having any of the permissions: !permission-list', array(
+        '!permission-list' => theme('links', array(
+          'links' => $permissions,
+          // @todo D7: Something went entirely wrong: system.menus.css makes ANY
+          //   ul.links appear as if it would have the .inline CSS class.
+          'attributes' => array(),
+        )),
+      ));
+
       if (!empty($mollom_form['elements'])) {
         // If not re-configuring an existing protection, make it the default.
         if (!isset($mollom_form['mode'])) {
@@ -176,24 +221,6 @@ function mollom_admin_configure_form($fo
           ),
         );
 
-        $form['mollom']['discard'] = array(
-          '#type' => 'radios',
-          '#title' => t('When a post is blocked'),
-          '#default_value' => $mollom_form['discard'],
-          '#options' => array(
-            1 => t('Automatically discard'),
-            0 => t('Retain for manual moderation'),
-          ),
-          // Only possible for forms supporting moderation of unpublished posts.
-          '#access' => !empty($mollom_form['moderation callback']),
-          // Only possible for forms protected via text analysis.
-          '#states' => array(
-            'visible' => array(
-              ':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS),
-            ),
-          ),
-        );
-
         // Form elements defined by hook_mollom_form_info() use the
         // 'parent][child' syntax, which Form API also uses internally for
         // form_set_error(), and which allows us to recurse into nested fields
@@ -224,6 +251,25 @@ function mollom_admin_configure_form($fo
             ),
           ),
         );
+
+        $form['mollom']['discard'] = array(
+          '#type' => 'radios',
+          '#title' => t('When text analysis identifies spam'),
+          '#default_value' => $mollom_form['discard'],
+          '#options' => array(
+            1 => t('Automatically discard the post'),
+            0 => t('Retain the post for manual moderation'),
+          ),
+          '#required' => $mollom_form['mode'] == MOLLOM_MODE_ANALYSIS,
+          // Only possible for forms supporting moderation of unpublished posts.
+          '#access' => !empty($mollom_form['moderation callback']),
+          // Only possible for forms protected via text analysis.
+          '#states' => array(
+            'visible' => array(
+              ':input[name="mollom[mode]"]' => array('value' => (string) MOLLOM_MODE_ANALYSIS),
+            ),
+          ),
+        );
       }
 
       $form['actions']['submit'] = array(
@@ -263,6 +309,7 @@ function mollom_admin_configure_form_val
     $required = ($form_state['values']['mollom']['mode'] == MOLLOM_MODE_ANALYSIS);
     $form['mollom']['checks']['#required'] = $required;
     $form['mollom']['enabled_fields']['#required'] = $required;
+    $form['mollom']['discard']['#required'] = $required;
 
     if ($required && !array_filter($form_state['values']['mollom']['checks'])) {
       form_error($form['mollom']['checks'], t('At least one text analysis check is required.'));
Index: mollom.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.module,v
retrieving revision 1.92
diff -u -p -r1.92 mollom.module
--- mollom.module	18 Oct 2010 12:31:06 -0000	1.92
+++ mollom.module	2 Nov 2010 18:46:39 -0000
@@ -2411,7 +2411,7 @@ function contact_mollom_form_info($form_
     case 'contact_site_form':
       $form_info = array(
         'mode' => MOLLOM_MODE_ANALYSIS,
-        'bypass access' => array('administer site-wide contact form'),
+        'bypass access' => array('administer contact forms'),
         'mail ids' => array('contact_page_mail'),
         'elements' => array(
           'subject' => t('Subject'),
Index: tests/mollom.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/tests/mollom.test,v
retrieving revision 1.73
diff -u -p -r1.73 mollom.test
--- tests/mollom.test	19 Oct 2010 21:47:03 -0000	1.73
+++ tests/mollom.test	2 Nov 2010 17:32:09 -0000
@@ -1874,6 +1874,16 @@ class MollomFormConfigurationTestCase ex
     $this->assertText($form_info['user_register_form']['title']);
     $this->assertTrue(mollom_form_load('user_register_form'), t('Form configuration exists.'));
 
+    // Retrieve a list of all permissions to verify them below.
+    $all_permissions = array();
+    foreach (module_implements('permission') as $module) {
+      $module_permissions = module_invoke($module, 'permission');
+      foreach ($module_permissions as &$info) {
+        $info += array('module' => $module);
+      }
+      $all_permissions += $module_permissions;
+    }
+
     // Iterate over all unconfigured forms and protect them.
     foreach ($form_info as $form_id => $info) {
       if (!mollom_form_load($form_id)) {
@@ -1898,6 +1908,11 @@ class MollomFormConfigurationTestCase ex
           $this->assertNoText(t('Analyze text for'));
           $this->assertNoText(t('Text fields to analyze'));
         }
+        // Verify that bypass permissions are output.
+        $this->assertRaw($all_permissions['bypass mollom protection']['title']);
+        foreach ($info['bypass access'] as $permission) {
+          $this->assertRaw($all_permissions[$permission]['title']);
+        }
         $this->drupalPost(NULL, $edit, t('Save'));
         $this->assertText(t('The form protection has been added.'));
       }
