Index: mollom.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.admin.inc,v
retrieving revision 1.48
diff -u -p -r1.48 mollom.admin.inc
--- mollom.admin.inc	7 Nov 2010 18:55:32 -0000	1.48
+++ mollom.admin.inc	10 Feb 2011 18:50:07 -0000
@@ -16,13 +16,14 @@ function mollom_admin_form_list() {
   mollom_form_cache(TRUE);
 
   $modes = array(
-    MOLLOM_MODE_ANALYSIS => t('Text analysis'),
-    MOLLOM_MODE_CAPTCHA => t('CAPTCHA'),
+    'spam' => t('Spam'),
+    'captcha' => t('CAPTCHA'),
+    'profanity' => t('Profanity'),
   );
 
   $header = array(
     t('Form'),
-    t('Protection mode'),
+    t('Checks'),
     array('data' => t('Operations'), 'colspan' => 2),
   );
   $result = db_query('SELECT form_id FROM {mollom_form}')->fetchCol();
@@ -49,14 +50,15 @@ function mollom_admin_form_list() {
   foreach ($forms as $form_id => $mollom_form) {
     $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']],
+    $checks = array_intersect_key($modes, array_flip($mollom_form['checks']));
+    if (isset($checks['spam'])) {
+      $row[] = t('!checks (@discard)', array(
+        '!checks' => implode(', ', $checks),
         '@discard' => $mollom_form['discard'] ? t('discard') : t('retain'),
       ));
     }
     else {
-      $row[] = $modes[$mollom_form['mode']];
+      $row[] = implode(', ', $checks);
     }
     $row[] = array('data' => array(
       '#type' => 'link',
@@ -178,19 +180,28 @@ function mollom_admin_configure_form($fo
       );
 
       $modes = array();
-      // Textual analysis, if any elements are available.
-      if (!empty($mollom_form['elements'])) {
-        $modes[MOLLOM_MODE_ANALYSIS] = t('Text analysis');
-      }
-      // CAPTCHA-only, always available.
-      $modes[MOLLOM_MODE_CAPTCHA] = t('CAPTCHA');
-
-      $form['mollom']['mode'] = array(
-        '#type' => 'radios',
-        '#title' => t('Protection mode'),
-        '#options' => $modes,
-        '#default_value' => isset($mollom_form['mode']) ? $mollom_form['mode'] : key($modes),
+      // Text analysis is only possible if there any elements to analyze.
+      $modes[MOLLOM_MODE_ANALYSIS] = !empty($mollom_form['elements']);
+      // CAPTCHA is always possible.
+      $modes[MOLLOM_MODE_CAPTCHA] = TRUE;
+
+      // Textual analysis filters.
+      $form['mollom']['checks'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Checks'),
+        '#default_value' => $mollom_form['checks'],
+        '#required' => TRUE,
       );
+      if ($modes[MOLLOM_MODE_ANALYSIS]) {
+        $form['mollom']['checks']['#options']['spam'] = t('Spam');
+      }
+      $form['mollom']['checks']['#options']['captcha'] = t('CAPTCHA');
+      $form['mollom']['checks']['captcha']['#description'] = t('Mollom CAPTCHAs are <a href="@help-url">intelligent</a>. When also checking for <em>Spam</em>, a CAPTCHA will only appear if Mollom is unsure.', array(
+        '@help-url' => url('admin/help/mollom'),
+      ));
+      if ($modes[MOLLOM_MODE_ANALYSIS]) {
+        $form['mollom']['checks']['#options']['profanity'] = t('Profanity');
+      }
 
       $all_permissions = array();
       foreach (module_implements('permission') as $module) {
@@ -214,87 +225,99 @@ function mollom_admin_configure_form($fo
           'html' => TRUE,
         );
       }
-      $form['mollom']['mode']['#description'] = t('The protection is omitted for users having any of the permissions: !permission-list', array(
+      $form['mollom']['checks']['#description'] = t('All checks are 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'])) {
-          $form['mollom']['mode']['#default_value'] = MOLLOM_MODE_ANALYSIS;
-        }
-
-        // Textual analysis filters.
-        $form['mollom']['checks'] = array(
-          '#type' => 'checkboxes',
-          '#title' => t('Analyze text for'),
-          '#options' => array(
-            'spam' => t('Spam'),
-            'profanity' => t('Profanity'),
-          ),
-          '#default_value' => $mollom_form['checks'],
-          '#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
-        // during processing of submitted form values. However, since we are using
-        // those keys also as internal values to configure the fields to use for
-        // textual analysis, we need to encode them. Otherwise, a nested field key
-        // would result in the following checkbox attribute:
-        //   '#name' => 'mollom[enabled_fields][parent][child]'
-        // This would lead to a form validation error, because it is a valid key.
-        // By encoding them, we prevent this from happening:
-        //   '#name' => 'mollom[enabled_fields][parent%5D%5Bchild]'
-        $elements = array();
-        foreach ($mollom_form['elements'] as $key => $value) {
-          $elements[rawurlencode($key)] = $value;
-        }
-        $enabled_fields = array();
-        foreach ($mollom_form['enabled_fields'] as $value) {
-          $enabled_fields[] = rawurlencode($value);
-        }
-        $form['mollom']['enabled_fields'] = array(
-          '#type' => 'checkboxes',
-          '#title' => t('Text fields to analyze'),
-          '#options' => $elements,
-          '#default_value' => $enabled_fields,
-          '#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
+      // during processing of submitted form values. However, since we are using
+      // those keys also as internal values to configure the fields to use for
+      // textual analysis, we need to encode them. Otherwise, a nested field key
+      // would result in the following checkbox attribute:
+      //   '#name' => 'mollom[enabled_fields][parent][child]'
+      // This would lead to a form validation error, because it is a valid key.
+      // By encoding them, we prevent this from happening:
+      //   '#name' => 'mollom[enabled_fields][parent%5D%5Bchild]'
+      $elements = array();
+      foreach ($mollom_form['elements'] as $key => $value) {
+        $elements[rawurlencode($key)] = $value;
+      }
+      $enabled_fields = array();
+      foreach ($mollom_form['enabled_fields'] as $value) {
+        $enabled_fields[] = rawurlencode($value);
+      }
+      $form['mollom']['enabled_fields'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Text fields to analyze'),
+        '#options' => $elements,
+        '#default_value' => $enabled_fields,
+        '#access' => $modes[MOLLOM_MODE_ANALYSIS],
+        // @todo Requires OR support for #states http://drupal.org/node/735528,
+        //   or native OR selector support http://drupal.org/node/1057748.
+        '#states' => array(
+          'visible' => array(
+            ':input[name="mollom[checks][spam]"], :input[name="mollom[checks][profanity]"]' => array('checked' => TRUE),
           ),
-        );
+        ),
+      );
 
-        $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'),
+      $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' => $modes[MOLLOM_MODE_ANALYSIS] && !empty($mollom_form['moderation callback']),
+        // Only possible for forms protected via text analysis.
+        '#states' => array(
+          'visible' => array(
+            ':input[name="mollom[checks][spam]"], :input[name="mollom[checks][profanity]"]' => array('checked' => TRUE),
           ),
-          '#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['mollom']['rate_limit'] = array(
+        '#type' => 'select',
+        '#title' => t('Minimum interval between posts of same author'),
+        '#options' => drupal_map_assoc(array(0, 5, 10, 15, 20, 30, 40, 50, 60, 90, 120, 150, 180), 'format_interval'),
+        '#empty_value' => '',
+        '#empty_option' => t('- Default -'),
+        '#default_value' => isset($mollom_form['rate_limit']) ? $mollom_form['rate_limit'] : NULL,
+        /*
+        '#attached' => array(
+          'library' => array(array('system', 'ui.slider')),
+          'js' => array(array(
+            'data' => 'jQuery(function( jQuery("#edit-mollom-rate-limit").slider(); ));',
+            'type' => 'inline',
+            'scope' => 'footer',
+          )),
+        ),
+        */
+      );
+      $form['mollom']['strictness'] = array(
+        '#type' => 'radios',
+        '#title' => t('Strictness'),
+        '#options' => array(
+          'low' => t('Relaxed'),
+          'medium' => t('Normal'),
+          'high' => t('Strict'),
+        ),
+        '#default_value' => $mollom_form['strictness'],
+        '#access' => $modes[MOLLOM_MODE_ANALYSIS],
+        // Only possible for forms protected via text analysis.
+        '#states' => array(
+          'visible' => array(
+            ':input[name="mollom[checks][spam]"], :input[name="mollom[checks][profanity]"]' => array('checked' => TRUE),
           ),
-        );
-      }
+        ),
+      );
 
       $form['actions']['submit'] = array(
         '#type' => 'submit',
@@ -328,16 +351,13 @@ function mollom_admin_configure_form_val
   // 'checks' and 'enabled_fields', as their labels do not work with the default
   // #required form error message.
   if ($form_state['storage']['step'] == 'configure') {
-    // Make field checkboxes required, if protection mode is textual analysis.
+    // Make field checkboxes required, if protection involves text analysis.
     // @see http://drupal.org/node/875722
-    $required = ($form_state['values']['mollom']['mode'] == MOLLOM_MODE_ANALYSIS);
-    $form['mollom']['checks']['#required'] = $required;
+    $checks = array_filter($form_state['values']['mollom']['checks']);
+    $required = (bool) array_diff_key($checks, array('captcha' => 0));
     $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.'));
-    }
     if ($required && !array_filter($form_state['values']['mollom']['enabled_fields'])) {
       form_error($form['mollom']['enabled_fields'], t('At least one field is required for text analysis.'));
     }
@@ -352,8 +372,15 @@ function mollom_admin_configure_form_sub
   // Merge in form information from $form_state.
   $mollom_form += $form_state['storage']['mollom_form'];
 
+  // Set protection mode to text analysis, in case more than CAPTCHA is enabled
+  // for 'checks'.
+  $checks = array_filter($form_state['values']['mollom']['checks']);
+  $mollom_form['mode'] = MOLLOM_MODE_CAPTCHA;
+  if (array_diff_key($checks, array('captcha' => 0))) {
+    $mollom_form['mode'] = MOLLOM_MODE_ANALYSIS;
+  }
   // Only store a list of enabled textual analysis checks.
-  $mollom_form['checks'] = array_keys(array_filter($mollom_form['checks']));
+  $mollom_form['checks'] = array_keys($checks);
   // Prepare selected fields for storage.
   $enabled_fields = array();
   foreach (array_keys(array_filter($mollom_form['enabled_fields'])) as $field) {
@@ -361,6 +388,10 @@ function mollom_admin_configure_form_sub
   }
   $mollom_form['enabled_fields'] = $enabled_fields;
 
+  if ($mollom_form['rate_limit'] === '') {
+    $mollom_form['rate_limit'] = NULL;
+  }
+
   $status = mollom_form_save($mollom_form);
   if ($status === SAVED_NEW) {
     drupal_set_message(t('The form protection has been added.'));
Index: mollom.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.install,v
retrieving revision 1.34
diff -u -p -r1.34 mollom.install
--- mollom.install	16 Dec 2010 14:50:04 -0000	1.34
+++ mollom.install	10 Feb 2011 18:03:28 -0000
@@ -194,6 +194,18 @@ function mollom_schema() {
         'not null' => FALSE,
         'serialize' => TRUE,
       ),
+      'rate_limit' => array(
+        'description' => 'Rate limit for form submissions.',
+        'type' => 'int',
+        'not null' => FALSE,
+      ),
+      'strictness' => array(
+        'description' => 'Strictness of Mollom checks.',
+        'type' => 'varchar',
+        'length' => 8,
+        'not null' => TRUE,
+        'default' => 'medium',
+      ),
       'module' => array(
         'description' => 'Module name owning the form.',
         'type' => 'varchar',
@@ -791,3 +803,26 @@ function mollom_update_7009() {
     ));
   }
 }
+
+/**
+ * Add {mollom_form}.rate_limit and {mollom_form}.strictness columns.
+ */
+function mollom_update_7010() {
+  if (!db_field_exists('mollom_form', 'rate_limit')) {
+    db_add_field('mollom_form', 'rate_limit', array(
+      'description' => 'Rate limit for form submissions.',
+      'type' => 'int',
+      'not null' => FALSE,
+    ));
+  }
+  if (!db_field_exists('mollom_form', 'strictness')) {
+    db_add_field('mollom_form', 'strictness', array(
+      'description' => 'Strictness of Mollom checks.',
+      'type' => 'varchar',
+      'length' => 8,
+      'not null' => TRUE,
+      'default' => 'medium',
+    ));
+  }
+  // @todo Update 'checks' column; add 'captcha' to all 'spam' checks.
+}
Index: mollom.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.module,v
retrieving revision 1.104
diff -u -p -r1.104 mollom.module
--- mollom.module	5 Feb 2011 01:07:06 -0000	1.104
+++ mollom.module	10 Feb 2011 18:03:28 -0000
@@ -851,6 +851,8 @@ function mollom_form_new($form_id = NULL
     'mode' => NULL,
     'checks' => array(),
     'enabled_fields' => array(),
+    'rate_limit' => NULL,
+    'strictness' => 'medium',
   );
   // Enable all fields for textual analysis by default.
   if (!empty($mollom_form['elements'])) {
@@ -1437,7 +1439,17 @@ function mollom_validate_analysis(&$form
     unset($data['post_id']);
   }
   $data['session_id'] = $form_state['mollom']['response']['session_id'];
-  $data['checks'] = implode(',', $form_state['mollom']['checks']);
+
+  $checks = drupal_map_assoc($form_state['mollom']['checks']);
+  $data['unsure'] = isset($checks['captcha']) ? 'yes' : 'no';
+  unset($checks['captcha']);
+  $data['checks'] = implode(',', $checks);
+
+  if (isset($form_state['mollom']['rate_limit'])) {
+    $data['rate_limit'] = $form_state['mollom']['rate_limit'];
+  }
+  $data['strictness'] = $form_state['mollom']['strictness'];
+
   $result = mollom('mollom.checkContent', $data);
   // Use all available data properties for log messages below.
   $data += $all_data;
@@ -1585,6 +1597,9 @@ function mollom_validate_captcha(&$form,
     'captcha_result' => $form_state['values']['mollom']['captcha'],
     'author_ip' => $all_data['author_ip'],
   );
+  if (isset($form_state['mollom']['rate_limit'])) {
+    $data['rate_limit'] = $form_state['mollom']['rate_limit'];
+  }
   if (isset($all_data['author_id'])) {
     $data['author_id'] = $all_data['author_id'];
   }
