Index: mollom.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/Attic/mollom.admin.inc,v
retrieving revision 1.1.2.8
diff -u -p -r1.1.2.8 mollom.admin.inc
--- mollom.admin.inc	17 Nov 2009 17:01:49 -0000	1.1.2.8
+++ mollom.admin.inc	20 Nov 2009 11:18:00 -0000
@@ -7,7 +7,220 @@
  */
 
 /**
- * Form builder; Administration settings form.
+ * Menu callback; Displays a list of forms configured for Mollom.
+ */
+function mollom_admin_form_list() {
+  $modes = array(
+    MOLLOM_MODE_DISABLED => t('No protection'),
+    MOLLOM_MODE_CAPTCHA => t('CAPTCHA only'),
+    MOLLOM_MODE_ANALYSIS => t('Text analysis and CAPTCHA backup'),
+  );
+
+  $header = array(
+    t('Form'),
+    t('Protection mode'),
+    array('data' => t('Operations'), 'colspan' => 2),
+  );
+  $rows = array();
+  $result = db_query("SELECT form_id FROM {mollom_form}");
+  while ($form_id = db_result($result)) {
+    $mollom_form = mollom_admin_form_load($form_id);
+    $rows[] = array(
+      $mollom_form['title'],
+      $modes[$mollom_form['mode']],
+      l(t('Configure'), 'admin/settings/mollom/manage/' . $form_id),
+      l(t('Unprotect'), 'admin/settings/mollom/unprotect/' . $form_id),
+    );
+  }
+
+  // Add a row to add a form.
+  if (empty($rows)) {
+    $rows[] = array(array('data' => l(t('Add form'), 'admin/settings/mollom/add'), 'colspan' => 4));
+  }
+
+  return theme('table', $header, $rows);
+}
+
+/**
+ * Helper function to return registered forms suitable for #options.
+ */
+function mollom_admin_form_options() {
+  // Retrieve all registered forms.
+  $form_info = mollom_get_form_info();
+
+  // Remove already configured form ids.
+  $result = db_query("SELECT form_id FROM {mollom_form}");
+  while ($form_id = db_result($result)) {
+    unset($form_info[$form_id]);
+  }
+
+  // Load module information.
+  $modules = module_implements('mollom_form_info');
+  $placeholders = db_placeholders($modules, 'varchar');
+  $result = db_query("SELECT name, info FROM {system} WHERE type = 'module' AND name IN ($placeholders)", $modules);
+  $modules = array();
+  while ($row = db_fetch_object($result)) {
+    $module_info = unserialize($row->info);
+    $modules[$row->name] = t($module_info['name']);
+  }
+
+  // Transform form information into an associative array suitable for #options.
+  foreach ($form_info as $form_id => $info) {
+    $form_info[$form_id] = $modules[$info['module']] . ': ' . $info['title'];
+  }
+  // Sort form options by title.
+  asort($form_info);
+
+  return $form_info;
+}
+
+/**
+ * Form builder; Configure Mollom protection for a form.
+ */
+function mollom_admin_configure_form(&$form_state, $mollom_form = NULL) {
+  // If no $mollom_form was passed, then we are adding a new form configuration.
+  if (!isset($mollom_form)) {
+    if (!isset($form_state['storage']['mollom_form'])) {
+      $form_state['storage']['step'] = 'select';
+    }
+    else {
+      $form_state['storage']['step'] = 'configure';
+      $mollom_form = $form_state['storage']['mollom_form'];
+    }
+  }
+  // Otherwise, we are editing an existing form configuration.
+  else {
+    $form_state['storage']['step'] = 'configure';
+    $form_state['storage']['mollom_form'] = $mollom_form;
+  }
+
+  $form['#tree'] = TRUE;
+
+  switch ($form_state['storage']['step']) {
+    case 'select':
+      drupal_add_js(drupal_get_path('module', 'mollom') . '/mollom.js');
+
+      $form['mollom']['form_id'] = array(
+        '#type' => 'select',
+        '#title' => t('Form'),
+        '#options' => mollom_admin_form_options(),
+        '#required' => TRUE,
+      );
+      $form['actions']['next'] = array(
+        '#type' => 'submit',
+        '#value' => t('Next'),
+        '#submit' => array('mollom_admin_configure_form_next_submit'),
+      );
+      break;
+
+    case 'configure':
+      // Display a list of fields for textual analysis (last step).
+      $form['mollom']['form_id'] = array(
+        '#type' => 'value',
+        '#value' => $mollom_form['form_id'],
+      );
+      $form['mollom']['form_title'] = array(
+        '#type' => 'item',
+        '#title' => t('Form'),
+        '#value' => $mollom_form['title'],
+      );
+      $form['mollom']['fields'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Fields to analyze'),
+        '#options' => $mollom_form['parents'],
+        '#default_value' => $mollom_form['fields'],
+        '#description' => t('If no fields are selected, the form will be protected by a CAPTCHA.'),
+      );
+      if (empty($form['mollom']['fields']['#options'])) {
+        $form['mollom']['fields']['#description'] = t('No fields are available.');
+      }
+      $form['actions']['submit'] = array(
+        '#type' => 'submit',
+        '#value' => t('Save'),
+      );
+      break;
+  }
+
+  $form['actions']['cancel'] = array(
+    '#value' => l(t('Cancel'), 'admin/settings/mollom'),
+  );
+
+  return $form;
+}
+
+/**
+ * Form submit handler for 'Next' button on Mollom form configuration form.
+ */
+function mollom_admin_configure_form_next_submit($form, &$form_state) {
+  $mollom_form = $form_state['values']['mollom'];
+
+  // Load form information into $form_state for configuration.
+  $form_state['storage']['mollom_form'] = mollom_admin_form_load($mollom_form['form_id']);
+
+  $form_state['storage']['step'] = 'configure';
+}
+
+/**
+ * Form submit handler for Mollom form configuration form.
+ */
+function mollom_admin_configure_form_submit($form, &$form_state) {
+  $mollom_form = $form_state['values']['mollom'];
+  // Merge in form information from $form_state.
+  $mollom_form += $form_state['storage']['mollom_form'];
+  // Update form information in $form_state for potential rebuilds.
+  $form_state['storage']['mollom_form'] = $mollom_form;
+
+  // Prepare selected fields for storage.
+  $mollom_form['fields'] = array_keys(array_filter($mollom_form['fields']));
+  // Determine form protection to use; use CAPTCHA-only protection if no fields
+  // were selected, otherwise text analysis.
+  $mollom_form['mode'] = (!empty($mollom_form['fields']) ? MOLLOM_MODE_ANALYSIS : MOLLOM_MODE_CAPTCHA);
+
+  $status = mollom_form_save($mollom_form);
+  if ($status === SAVED_NEW) {
+    drupal_set_message('The form protection has been added.');
+  }
+  else {
+    drupal_set_message('The form protection has been updated.');
+  }
+
+  unset($form_state['storage']);
+  $form_state['redirect'] = 'admin/settings/mollom';
+}
+
+/**
+ * Form builder; Remove Mollom protection from a form.
+ */
+function mollom_admin_unprotect_form(&$form_state, $mollom_form) {
+  $form['#tree'] = TRUE;
+  $form['form'] = array(
+    '#type' => 'item',
+    '#title' => t('Form'),
+    '#value' => $mollom_form['title'],
+  );
+  $form['mollom']['form_id'] = array(
+    '#type' => 'value',
+    '#value' => $mollom_form['form_id'],
+  );
+
+  return confirm_form($form,
+    t('Are you sure you want to unprotect this form?'),
+    'admin/settings/mollom',
+    t('Mollom will no longer protect this form from spam.')
+  );
+}
+
+/**
+ * Form submit handler for mollom_admin_unprotect_form().
+ */
+function mollom_admin_unprotect_form_submit($form, &$form_state) {
+  db_query("DELETE FROM {mollom_form} WHERE form_id = '%s'", $form_state['values']['mollom']['form_id']);
+
+  $form_state['redirect'] = 'admin/settings/mollom';
+}
+
+/**
+ * Form builder; Global Mollom settings form.
  */
 function mollom_admin_settings() {
   $keys = _mollom_access();
@@ -20,72 +233,30 @@ function mollom_admin_settings() {
       variable_del('mollom_servers');
 
       // Verify the key and output a status message.
-      _mollom_verify_key();
+      $status = _mollom_verify_key();
     }
-
-    $description = '<p>' . t("Mollom can be used to block all types of spam received on your website's protected forms. Each form can be set to one of the following options:") . '</p>';
-    $description .= '<ul><li>' . t("<strong>Text analysis and CAPTCHA backup</strong>: Mollom analyzes the data submitted on the form and presents a CAPTCHA challenge if necessary. This option is strongly recommended, as it takes full advantage of the Mollom anti-spam service to categorize your posts into ham (not spam) and spam.") . '</li>';
-    $description .= '<li>' . t("<strong>CAPTCHA only</strong>: the form's data is not sent to Mollom for analysis, and a remotely-hosted CAPTCHA challenge is always presented. This option is useful when you wish to always display a CAPTCHA or want to send less data to the Mollom network. Note, however, that forms displayed with a CAPTCHA are never cached, so always displaying a CAPTCHA challenge may reduce performance.") . '</li>';
-    $description .= '<li>' . t('<strong>No protection</strong>: Mollom is not used with this form.') . '</li></ul>';
-    $description .= '<p>';
-    $description .= t("Data is processsed and stored as explained in our <a href=\"@mollom-privacy\">Web Service Privacy Policy</a>. It is your responsibility to provide any necessary notices and obtain the appropriate consent regarding Mollom's use of your data. For more information, see <a href=\"@mollom-works\">How Mollom Works</a> and the <a href=\"@mollom-faq\">Mollom FAQ</a>.", array(
-      '@mollom-privacy' => 'http://mollom.com/service-agreement-free-subscriptions',
-      '@mollom-works' => 'http://mollom.com/how-mollom-works',
-      '@mollom-faq' => 'http://mollom.com/faq'));
-    $description .= '</p>';
-
-    $form['spam'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Spam protection settings'),
-      '#description' => $description,
-      '#collapsible' => TRUE,
-    );
-
-    $modes = array(
-      MOLLOM_MODE_DISABLED => t('No protection'),
-      MOLLOM_MODE_CAPTCHA => t('CAPTCHA only'),
-      MOLLOM_MODE_ANALYSIS => t('Text analysis and CAPTCHA backup'),
-    );
-
-    $forms = _mollom_protectable_forms();
-    foreach ($forms as $form_id => $details) {
-      $mode = _mollom_get_mode($form_id);
-      // @todo Use #tree instead.
-      $name = 'mollom_' . $form_id;
-
-      // @todo What's happening here?
-      $options = array_slice($modes, 0, $details['mode'] + 1);
-
-      $form['spam'][$name] = array(
-        '#type' => 'select',
-        '#title' => t('Protect @name', array('@name' => $details['name'])),
-        '#options' => $options,
-        '#default_value' => $mode,
-      );
-    }
-
-    $form['server'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Server settings'),
-      '#collapsible' => TRUE,
-      '#collapsed' => $keys,
-    );
-    $form['server']['mollom_fallback'] = array(
-      '#type' => 'radios',
-      '#title' => t('Fallback strategy'),
-      // Default to treating everything as inappropriate.
-      '#default_value' => variable_get('mollom_fallback', MOLLOM_FALLBACK_BLOCK),
-      '#options' => array(
-        MOLLOM_FALLBACK_BLOCK => t('Block all submissions of protected forms until the server problems are resolved'),
-        MOLLOM_FALLBACK_ACCEPT => t('Leave all forms unprotected and accept all submissions'),
-      ),
-      '#description' => t('When the Mollom servers are down or otherwise unreachable, no text analysis is performed and no CAPTCHAs are generated. If this occurs, your Drupal site will use the configured fallback strategy, and will either accept all submissions without spam checking, or block all submissions until the server or connection problems are resolved. Subscribers to <a href="@pricing">Mollom Plus</a> receive access to <a href="@sla">Mollom\'s high-availability backend infrastructure</a>, not available to free users, reducing potential downtime.', array(
-        '@pricing' => 'http://mollom.com/pricing',
-        '@sla' => 'http://mollom.com/standard-service-level-agreement',
-      )),
-    );
   }
 
+  $form['server'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Server settings'),
+    '#access' => !empty($status),
+  );
+  $form['server']['mollom_fallback'] = array(
+    '#type' => 'radios',
+    '#title' => t('Fallback strategy'),
+    // Default to treating everything as inappropriate.
+    '#default_value' => variable_get('mollom_fallback', MOLLOM_FALLBACK_BLOCK),
+    '#options' => array(
+      MOLLOM_FALLBACK_BLOCK => t('Block all submissions of protected forms until the server problems are resolved'),
+      MOLLOM_FALLBACK_ACCEPT => t('Leave all forms unprotected and accept all submissions'),
+    ),
+    '#description' => t('When the Mollom servers are down or otherwise unreachable, no text analysis is performed and no CAPTCHAs are generated. If this occurs, your Drupal site will use the configured fallback strategy, and will either accept all submissions without spam checking, or block all submissions until the server or connection problems are resolved. Subscribers to <a href="@pricing">Mollom Plus</a> receive access to <a href="@sla">Mollom\'s high-availability backend infrastructure</a>, not available to free users, reducing potential downtime.', array(
+      '@pricing' => 'http://mollom.com/pricing',
+      '@sla' => 'http://mollom.com/standard-service-level-agreement',
+    )),
+  );
+
   $form['access-keys'] = array(
     '#type' => 'fieldset',
     '#title' => t('Mollom access keys'),
@@ -95,7 +266,7 @@ function mollom_admin_settings() {
       '@mollom-manager-add' => 'http://mollom.com/site-manager/add',
       '@mollom-manager' => 'http://mollom.com/site-manager',
     )),
-    '#collapsible' => TRUE,
+    '#collapsible' => $keys,
     '#collapsed' => $keys,
   );
   $form['access-keys']['mollom_public_key'] = array(
@@ -124,12 +295,15 @@ function _mollom_verify_key() {
 
   if ($status === NETWORK_ERROR) {
     drupal_set_message(t('We tried to contact the Mollom servers but we encountered a network error. Please make sure that your web server can make outgoing HTTP requests.'), 'error');
+    return FALSE;
   }
   elseif ($status === MOLLOM_ERROR) {
     drupal_set_message(t('We contacted the Mollom servers to verify your keys: your keys do not exist or are no longer valid. Please visit the <em>Manage sites</em> page on the Mollom website again: <a href="@mollom-user">@mollom-user</a>.', array('@mollom-user' => 'http://mollom.com/user')), 'error');
+    return FALSE;
   }
   else {
     drupal_set_message(t('We contacted the Mollom servers to verify your keys: the Mollom services are operating correctly. We are now blocking spam.'));
+    return TRUE;
   }
 }
 
Index: mollom.api.php
===================================================================
RCS file: mollom.api.php
diff -N mollom.api.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mollom.api.php	20 Nov 2009 11:33:59 -0000
@@ -0,0 +1,68 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * API documentation for Mollom module.
+ */
+
+/**
+ * Return information about forms that can be protected by Mollom.
+ *
+ * Mollom invokes this hook for all modules to gather information about forms
+ * that can be protected. Only forms that have been registered via this hook are
+ * configurable in Mollom's administration interface.
+ *
+ * @return
+ *   An associative array containing information about forms that can be
+ *   protected. Each key is a $form_id whose value is an associative array:
+ *   - title: The human-readable name of the form.
+ *   - mode: (optional) The default protection mode for the form, which can be
+ *     one of:
+ *     - MOLLOM_MODE_DISABLED: No protection.
+ *     - MOLLOM_MODE_CAPTCHA: CAPTCHA-only protection.
+ *     - MOLLOM_MODE_ANALYSIS: Text analysis of submitted form values with
+ *       fallback to CAPTCHA.
+ *     If omitted, the form will not be configured upon installation of Mollom
+ *     module.
+ *   - parents: (optional) An associative array of elements in the form that can
+ *     be configured for Mollom's text analysis. The site administrator can only
+ *     select the form elements to process (and exclude certain elements) when a
+ *     form registers elements. Each key is a form API element #parents string
+ *     representation of the location of an element in the form. For example, a
+ *     key of "myelement" denotes a form element value on the top-level of
+ *     submitted form values. For nested elements, a key of "parent][child"
+ *     denotes that the value of 'child' is found below 'parent' in the
+ *     submitted form values. Each value contains the form element label. If
+ *     omitted, Mollom can only provide a CAPTCHA protection for the form.
+ */
+function hook_mollom_form_info() {
+  $forms['comment_form'] = array(
+    'title' => t('Comment form'),
+    'mode' => MOLLOM_MODE_ANALYSIS,
+    'parents' => array(
+      'subject' => t('Subject'),
+      'body' => t('Body'),
+    ),
+  );
+  $forms['user_register'] = array(
+    'title' => t('User registration form'),
+    'mode' => MOLLOM_MODE_CAPTCHA,
+  );
+
+  return $forms;
+}
+
+/**
+ * Alter registered information about forms that can be protected by Mollom.
+ *
+ * @param &$form_info
+ *   An associative array containing protectable forms. See
+ *   hook_mollom_form_info() for details.
+ */
+function hook_mollom_form_info_alter(&$form_info) {
+  if (isset($form_info['comment_form'])) {
+    $form_info['comment_form']['parents']['mymodule_field'] = t('My additional field');
+  }
+}
+
Index: mollom.form.inc
===================================================================
RCS file: mollom.form.inc
diff -N mollom.form.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ mollom.form.inc	20 Nov 2009 11:36:46 -0000
@@ -0,0 +1,121 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Implements hook_mollom_form_info() on behalf of other modules.
+ */
+
+/**
+ * Implements hook_mollom_form_info().
+ */
+function comment_mollom_form_info() {
+  $forms['comment_form'] = array(
+    'title' => t('Comment form'),
+    'mode' => MOLLOM_MODE_ANALYSIS,
+    'parents' => array(
+      'subject' => t('Subject'),
+      'body' => t('Body'),
+    ),
+  );
+
+  return $forms;
+}
+
+/**
+ * Implements hook_mollom_form_info().
+ */
+function contact_mollom_form_info() {
+  $forms['contact_mail_page'] = array(
+    'title' => t('Site-wide contact form'),
+    'mode' => MOLLOM_MODE_ANALYSIS,
+    'parents' => array(
+      'subject' => t('Subject'),
+      'message' => t('Message'),
+    ),
+  );
+  $forms['contact_mail_user'] = array(
+    'title' => t('User contact form'),
+    'mode' => MOLLOM_MODE_ANALYSIS,
+    'parents' => array(
+      'subject' => t('Subject'),
+      'message' => t('Message'),
+    ),
+  );
+
+  return $forms;
+}
+
+/**
+ * Implements hook_mollom_form_info().
+ */
+function node_mollom_form_info() {
+  $types = node_get_types('types');
+  $forms = array();
+  foreach ($types as $type) {
+    $forms[$type->type . '_node_form'] = array(
+      'title' => t('@name form', array('@name' => $type->name)),
+      'mode' => MOLLOM_MODE_ANALYSIS,
+    );
+    $parents = array();
+    // @see node_content_form()
+    if ($type->has_title) {
+      $parents['title'] = check_plain($type->title_label);
+    }
+    if ($type->has_body) {
+      $parents['body'] = check_plain($type->body_label);
+      // @todo How do we get invisible & dependent 'format' support in here?
+      // $parents['format'] = t('Input format'),
+    }
+    // Add CCK fields by default.
+    if (module_exists('content')) {
+      $content_info = content_types($type->type);
+      foreach ($content_info['fields'] as $field_name => $field) {
+        // We only consider text fields for text analysis.
+        if ($field['type'] == 'text') {
+          $parents[$field_name] = check_plain(t($field['widget']['label']));
+        }
+      }
+    }
+    $forms[$type->type . '_node_form']['parents'] = $parents;
+  }
+
+  return $forms;
+}
+
+/**
+ * Implements hook_mollom_form_info().
+ */
+function user_mollom_form_info() {
+  $forms['user_register'] = array(
+    'title' => t('User registration form'),
+    'mode' => MOLLOM_MODE_CAPTCHA,
+  );
+  $forms['user_pass'] = array(
+    'title' => t('User password request form'),
+    'mode' => MOLLOM_MODE_CAPTCHA,
+  );
+
+  return $forms;
+}
+
+/**
+ * Implements hook_mollom_form_info().
+ *
+ * @todo Move this into Webform module.
+ */
+function webform_mollom_form_info() {
+  // @todo
+  $webforms = db_query("SELECT n.nid, n.title FROM {node} n WHERE n.type = 'webform' AND n.status = 1");
+  while ($webform = db_fetch_object($webforms)) {
+    $forms['webform_client_form_'. $webform->nid] = array(
+      'title' => $webform->title,
+      'mode' => MOLLOM_MODE_ANALYSIS,
+      'parents' => array(
+      ),
+    );
+  }
+
+  return $forms;
+}
+
Index: mollom.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.install,v
retrieving revision 1.2.2.11
diff -u -p -r1.2.2.11 mollom.install
--- mollom.install	17 Nov 2009 17:01:49 -0000	1.2.2.11
+++ mollom.install	20 Nov 2009 00:20:55 -0000
@@ -53,6 +53,33 @@ function mollom_schema() {
     'primary key' => array('did'),
   );
 
+  $schema['mollom_form'] = array(
+    // @todo Add description.
+    'description' => '',
+    'fields' => array(
+      'form_id' => array(
+        'description' => 'The $form_id of the form being protected.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'mode' => array(
+        'description' => 'The configured protection mode to use for the form.',
+        'type' => 'int',
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'fields' => array(
+        'type' => 'text',
+        'serialize' => TRUE,
+      ),
+      // @todo 'module' required for maintenance.
+    ),
+    'primary key' => array('form_id'),
+  );
+
   $schema['cache_mollom'] = drupal_get_schema_unprocessed('system', 'cache');
   $schema['cache_mollom']['description'] = 'Cache table for the Mollom module to store information for forms it protects.';
 
@@ -64,6 +91,19 @@ function mollom_schema() {
  */
 function mollom_install() {
   drupal_install_schema('mollom');
+
+  // Install default form configuration for enabled, supported modules.
+  foreach (module_list() as $module) {
+    drupal_load('module', $module);
+  }
+  $form_info = mollom_get_form_info();
+  foreach ($form_info as $form_id => $info) {
+    if (!empty($info['mode'])) {
+      $info['form_id'] = $form_id;
+      $info['fields'] = array_keys($info['parents']);
+      mollom_form_save($info);
+    }
+  }
 }
 
 /**
@@ -97,10 +137,11 @@ function mollom_update_2() {
  * Upgrade form protection storage.
  */
 function mollom_update_3() {
-  // Load the Drupal module so that _mollom_protectable_forms() is available.
+  // Load the module, so mollom_get_form_info() is available.
   drupal_load('module', 'mollom');
 
-  foreach (_mollom_protectable_forms() as $form_id => $details) {
+  // @todo FIXME
+  foreach (mollom_get_form_info() as $form_id => $details) {
     $name = 'mollom_' . $form_id;
     $mode = variable_get($name, NULL);
     if ($mode && $details['mode'] == MOLLOM_MODE_ANALYSIS) {
@@ -120,3 +161,54 @@ function mollom_update_4() {
   return $ret;
 }
 
+/**
+ * Add the {mollom_form} table.
+ */
+function mollom_update_6105() {
+  $ret = array();
+  $schema = array(
+    'fields' => array(
+      'form_id' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'mode' => array(
+        'description' => 'The configured protection mode to use for the form.',
+        'type' => 'int',
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'fields' => array(
+        'type' => 'text',
+        'serialize' => TRUE,
+      ),
+      // @todo 'module' required for maintenance.
+    ),
+    'primary key' => array('form_id'),
+  );
+  db_create_table($ret, 'mollom_form', $schema);
+
+  // Migrate form configuration for enabled, supported modules.
+  foreach (module_list() as $module) {
+    drupal_load('module', $module);
+  }
+  $form_info = mollom_get_form_info();
+  $result = db_query("SELECT name, value FROM {variable} WHERE name LIKE 'mollom_%%' AND name NOT IN ('mollom_servers', 'mollom_fallback', 'mollom_public_key', 'mollom_private_key')");
+  while ($row = db_fetch_object($result)) {
+    $form_id = substr($row->name, 7);
+    $mode = unserialize($row->value);
+    if (!empty($mode) && isset($form_info[$form_id])) {
+      $info = $form_info[$form_id];
+      $info['form_id'] = $form_id;
+      $info['mode'] = $mode;
+      $info['fields'] = array_keys($info['parents']);
+      mollom_form_save($info);
+    }
+    variable_del($row->name);
+  }
+  return $ret;
+}
+
Index: mollom.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.js,v
retrieving revision 1.2.2.7
diff -u -p -r1.2.2.7 mollom.js
--- mollom.js	17 Nov 2009 17:01:49 -0000	1.2.2.7
+++ mollom.js	19 Nov 2009 20:20:45 -0000
@@ -3,7 +3,7 @@
 /**
  * Attach click event handlers for CAPTCHA links.
  */
-Drupal.behaviors.mollom = function(context) {
+Drupal.behaviors.mollomCaptcha = function(context) {
   $('a.mollom-audio-captcha', context).click(getAudioCaptcha);
   $('a.mollom-image-captcha', context).click(getImageCaptcha);
 }
@@ -45,3 +45,17 @@ function getImageCaptcha() {
    });
    return false;
 }
+
+/**
+ * Toggle display of custom form ID element depending on select list value.
+ */
+Drupal.behaviors.mollomSettingsFormID = function() {
+  $('#edit-mollom-form-id').change(function() {
+    if ($(this).val() == 'form_id_custom') {
+      $('#edit-mollom-form-id-custom-wrapper').show();
+    }
+    else {
+      $('#edit-mollom-form-id-custom-wrapper').hide();
+    }
+  }).change();
+}
Index: mollom.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.module,v
retrieving revision 1.2.2.101
diff -u -p -r1.2.2.101 mollom.module
--- mollom.module	17 Nov 2009 23:39:49 -0000	1.2.2.101
+++ mollom.module	20 Nov 2009 11:20:55 -0000
@@ -91,12 +91,34 @@ define('MOLLOM_REDIRECT', 1200);
  */
 function mollom_help($path, $arg) {
   if ($path == 'admin/settings/mollom') {
-    return t("Allowing users to react, participate and contribute while still keeping your site's content under control can be a huge challenge. Mollom is a web service that helps you identify content quality and, more importantly, helps you stop spam. When content moderation becomes easier, you have more time and energy to interact with your web community. More information about Mollom is available on the <a href=\"@mollom-website\">Mollom website</a> or in the <a href=\"@mollom-faq\">Mollom FAQ</a>.",
+    return t('All listed forms below are protected by Mollom. You can <a href="@add-form-url">add a form</a> to protect, configure already protected forms, or remove the protection.', array(
+      '@add-form-url' => url('admin/settings/mollom/add'),
+    ));
+  }
+  if ($path == 'admin/help#mollom') {
+    $output = '<p>';
+    $output = t("Allowing users to react, participate and contribute while still keeping your site's content under control can be a huge challenge. Mollom is a web service that helps you identify content quality and, more importantly, helps you stop spam. When content moderation becomes easier, you have more time and energy to interact with your web community. More information about Mollom is available on the <a href=\"@mollom-website\">Mollom website</a> or in the <a href=\"@mollom-faq\">Mollom FAQ</a>.",
       array(
         '@mollom-website' => 'http://mollom.com',
         '@mollom-faq' => 'http://mollom.com/faq',
       )
     );
+    $output .= '</p><p>';
+    $output .= t("Mollom can be used to block all types of spam received on your website's protected forms. Each form can be set to one of the following options:");
+    $output .= '</p><ul><li>';
+    $output .= t("<strong>Text analysis and CAPTCHA backup</strong>: Mollom analyzes the data submitted on the form and presents a CAPTCHA challenge if necessary. This option is strongly recommended, as it takes full advantage of the Mollom anti-spam service to categorize your posts into ham (not spam) and spam.");
+    $output .= '</li><li>';
+    $output .= t("<strong>CAPTCHA only</strong>: the form's data is not sent to Mollom for analysis, and a remotely-hosted CAPTCHA challenge is always presented. This option is useful when you wish to always display a CAPTCHA or want to send less data to the Mollom network. Note, however, that forms displayed with a CAPTCHA are never cached, so always displaying a CAPTCHA challenge may reduce performance.");
+    $output .= '</li><li>';
+    $output .= t('<strong>No protection</strong>: Mollom is not used with this form.');
+    $output .= '</li></ul><p>';
+    $output .= t("Data is processsed and stored as explained in our <a href=\"@mollom-privacy\">Web Service Privacy Policy</a>. It is your responsibility to provide any necessary notices and obtain the appropriate consent regarding Mollom's use of your data. For more information, see <a href=\"@mollom-works\">How Mollom Works</a> and the <a href=\"@mollom-faq\">Mollom FAQ</a>.", array(
+      '@mollom-privacy' => 'http://mollom.com/service-agreement-free-subscriptions',
+      '@mollom-works' => 'http://mollom.com/how-mollom-works',
+      '@mollom-faq' => 'http://mollom.com/faq')
+    );
+    $output .= '</p>';
+    return $output;
   }
 }
 
@@ -155,16 +177,54 @@ function mollom_menu() {
     'file' => 'mollom.pages.inc',
     'type' => MENU_CALLBACK,
   );
+
   $items['admin/settings/mollom'] = array(
     'title' => 'Mollom',
     'description' => 'Mollom is a web service that helps you manage your community.',
+    'page callback' => 'mollom_admin_form_list',
+    'access arguments' => array('administer mollom'),
+    'file' => 'mollom.admin.inc',
+  );
+  $items['admin/settings/mollom/list'] = array(
+    'title' => 'List',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/settings/mollom/add'] = array(
+    'title' => 'Add form',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mollom_admin_configure_form'),
+    'access arguments' => array('administer mollom'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'mollom.admin.inc',
+  );
+  $items['admin/settings/mollom/manage/%mollom_admin_form'] = array(
+    'title' => 'Configure',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mollom_admin_configure_form', 4),
+    'access arguments' => array('administer mollom'),
+    'file' => 'mollom.admin.inc',
+  );
+  $items['admin/settings/mollom/unprotect/%mollom_admin_form'] = array(
+    'title' => 'Unprotect form',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('mollom_admin_unprotect_form', 4),
+    'access arguments' => array('administer mollom'),
+    'type' => MENU_CALLBACK,
+    'file' => 'mollom.admin.inc',
+  );
+  $items['admin/settings/mollom/settings'] = array(
+    'title' => 'Settings',
+    'description' => 'Configure Mollom keys and global settings.',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('mollom_admin_settings'),
     'access arguments' => array('administer mollom'),
+    'type' => MENU_LOCAL_TASK,
     'file' => 'mollom.admin.inc',
   );
+
   $items['admin/reports/mollom'] = array(
-    'title' => 'Mollom',
+    'title' => 'Mollom statistics',
     'description' => 'Reports and usage statistics for the Mollom module.',
     'page callback' => 'mollom_reports_page',
     'access callback' => '_mollom_access',
@@ -305,11 +365,11 @@ function mollom_comment($comment, $op) {
  * This function intercepts all forms in Drupal and Mollom-enables them if
  * necessary.
  */
-function mollom_form_alter(&$form, $form_state, $form_id) {
+function mollom_form_alter(&$form, &$form_state, $form_id) {
   // Site administrators don't have their content checked with Mollom.
   if (!user_access('post with no checking')) {
-    // Retrieve the mode of protection required for this form.
-    if ($mode = _mollom_get_mode($form_id)) {
+    // Retrieve the protection mode for this form.
+    if ($mollom_form = mollom_form_load($form_id)) {
       // Compute the weight of the CAPTCHA so we can position it in the form.
       $weight = 99999;
       foreach (element_children($form) as $key) {
@@ -332,7 +392,8 @@ function mollom_form_alter(&$form, $form
       // Add Mollom form protection widget.
       $form['mollom'] = array(
         '#type' => 'mollom',
-        '#mode' => $mode,
+        '#mode' => $mollom_form['mode'],
+        '#fields' => $mollom_form['fields'],
         '#weight' => $weight,
       );
       // Add a submit handler that will clean the Mollom state as soon as the
@@ -468,61 +529,154 @@ function mollom_data_node_form($form_sta
  *   - MOLLOM_MODE_DISABLED: None.
  *   - MOLLOM_MODE_CAPTCHA: CAPTCHA only.
  *   - MOLLOM_MODE_ANALYSIS: Text analysis with CAPTCHA fallback.
- *
- * @todo Store form ids in a single variable.
  */
 function _mollom_get_mode($form_id) {
-  $mode = variable_get('mollom_' . $form_id, NULL);
-  if (!isset($mode)) {
-    $forms = _mollom_protectable_forms();
-    return isset($forms[$form_id]['mode']) ? $forms[$form_id]['mode'] : MOLLOM_MODE_DISABLED;
+  $mollom_form = mollom_form_load($form_id);
+  return isset($mollom_form['mode']) ? $mollom_form['mode'] : MOLLOM_MODE_DISABLED;
+}
+
+/**
+ * Returns information about protectable forms registered via hook_mollom_form_info().
+ *
+ * @param $form_id
+ *   (optional) The form id to return information for. If omitted, information
+ *   for all registered forms is returned.
+ */
+function mollom_get_form_info($form_id = NULL) {
+  static $form_info;
+
+  if (!isset($form_info)) {
+    module_load_include('inc', 'mollom', 'mollom.form');
+    $form_info = array();
+    foreach (module_implements('mollom_form_info') as $module) {
+      $function = $module . '_mollom_form_info';
+      $module_forms = $function();
+      foreach ($module_forms as $id => $info) {
+        // Ensure basic properties for all forms.
+        $module_forms[$id] += array(
+          'module' => $module,
+          'form_id' => $id,
+          'title' => $id,
+          'parents' => array(),
+        );
+      }
+      $form_info = array_merge_recursive($form_info, $module_forms);
+    }
+
+    // Allow modules to alter the default form information.
+    drupal_alter('mollom_form_info', $form_info);
   }
-  return $mode;
+
+  if (isset($form_id)) {
+    return isset($form_info[$form_id]) ? $form_info[$form_id] : array();
+  }
+  return $form_info;
 }
 
 /**
- * Returns a list of forms that can be protected with Mollom.
+ * Menu argument loader; Loads Mollom configuration for a given form id.
  */
-function _mollom_protectable_forms() {
-  static $forms = NULL;
+function mollom_form_load($form_id) {
+  $mollom_form = db_fetch_array(db_query_range("SELECT * FROM {mollom_form} WHERE form_id = '%s'", $form_id, 0, 1));
+  if ($mollom_form) {
+    $mollom_form['fields'] = unserialize($mollom_form['fields']);
+  }
+  return $mollom_form;
+}
 
-  if (!isset($forms)) {
-    if (module_exists('comment')) {
-      $forms['comment_form'] = array(
-        'name' => 'comment form',
-        'mode' => MOLLOM_MODE_ANALYSIS,
-      );
-    }
-    if (module_exists('contact')) {
-      $forms['contact_mail_page'] = array(
-        'name' => 'site-wide contact form',
-        'mode' => MOLLOM_MODE_ANALYSIS,
-      );
+/**
+ * Loads Mollom information and configuration for a given form id.
+ *
+ * This needs to live in mollom.module or the menu system won't recognize it.
+ */
+function mollom_admin_form_load($form_id) {
+  // Load form configuration.
+  $mollom_form = mollom_form_load($form_id);
+  if (!$mollom_form) {
+    $mollom_form = array();
+  }
 
-      $forms['contact_mail_user'] = array(
-        'name' => 'per-user contact forms',
-        'mode' => MOLLOM_MODE_ANALYSIS,
-      );
+  // Attach form registry information.
+  $mollom_form += mollom_get_form_info($form_id);
+
+  // Ensure default values for administrative configuration.
+  $mollom_form += array(
+    'form_id' => $form_id,
+    'title' => $form_id,
+    'parents' => array(),
+    'fields' => array(),
+  );
+
+  return $mollom_form;
+}
+
+/**
+ * Saves a Mollom form configuration.
+ */
+function mollom_form_save(&$mollom_form) {
+  $exists = db_result(db_query_range("SELECT 1 FROM {mollom_form} WHERE form_id = '%s'", $mollom_form['form_id'], 0, 1));
+  if ($exists) {
+    $status = drupal_write_record('mollom_form', $mollom_form, 'form_id');
+  }
+  else {
+    $status = drupal_write_record('mollom_form', $mollom_form);
+  }
+  // Allow modules to react on saved form configurations.
+  if (isset($status) && $status) {
+    if ($status === SAVED_NEW) {
+      module_invoke_all('mollom_form_insert', $mollom_form);
     }
-    $forms['user_register'] = array(
-      'name' => 'user registration form',
-      'mode' => MOLLOM_MODE_CAPTCHA,
-    );
-    $forms['user_pass'] = array(
-      'name' => 'user password request form',
-      'mode' => MOLLOM_MODE_CAPTCHA,
-    );
-    // Add all node forms.
-    $types = node_get_types('names');
-    foreach ($types as $type => $name) {
-      $forms[$type . '_node_form'] = array(
-        'name' => drupal_strtolower($name) . ' form',
-        'mode' => MOLLOM_MODE_ANALYSIS,
-      );
+    elseif ($status === SAVED_UPDATED) {
+      module_invoke_all('mollom_form_update', $mollom_form);
     }
   }
+  return $status;
+}
 
-  return $forms;
+/**
+ * Given an array of values and an array of fields, extract data for use.
+ *
+ * @param $values
+ *   An array of data, usually $form_state['values'].
+ * @param $fields
+ *   An array of strings representing fields to extract. Nested fields are in
+ *   the form of 'parent[child]'.
+ */
+function mollom_form_get_values($values, $fields) {
+  global $user;
+
+  $field_data = array();
+  foreach ($fields as $field) {
+    // Nested field values use 'parent][child', so we need to recurse.
+    $parents = explode('][', $field);
+    $field_value = $values;
+    foreach ($parents as $key) {
+      $field_value = isset($field_value[$key]) ? $field_value[$key] : NULL;
+    }
+    // Only save values that are not empty.
+    if (isset($field_value) && strlen($field_value)) {
+      $field_data[$field] = $field_value;
+    }
+  }
+
+  $data = array();
+  // Add the data from the fields.
+  // @todo Allow hook_mollom_form_info() to specify a form element mapping.
+  $data['post_title'] = isset($values['title']) ? $values['title'] : (isset($values['subject']) ? $values['subject'] : NULL);
+  $data['post_body'] = !empty($fields_data) ? implode("\n", $fields_data) : NULL;
+
+  // Add common data.
+  $data['author_name'] = isset($values['name']) ? $values['name'] : (isset($user->name) ? $user->name : NULL);
+  $data['author_mail'] = isset($values['mail']) ? $values['mail'] : (isset($user->mail) ? $user->mail : NULL);
+  $data['author_url'] = isset($values['homepage']) ? $values['homepage'] : NULL;
+  $data['author_openid'] = $user->uid ? _mollom_get_openid($user) : NULL;
+  $data['author_id'] = $user->uid ? $user->uid : NULL;
+  // @todo For any reason, the previous data collector functions used the
+  //   content's internal system id (i.e. nid, cid, etc.) instead of the IP
+  //   address...?
+  $data['author_ip'] = ip_address();
+
+  return $data;
 }
 
 /**
@@ -637,6 +791,7 @@ function mollom_expand_element($element,
       '#require_captcha' => $element['#mode'] == MOLLOM_MODE_CAPTCHA,
       '#passed_captcha' => FALSE,
       '#user_session_id' => session_id(),
+      '#fields' => $element['#fields'],
     );
   }
 
@@ -726,6 +881,7 @@ function mollom_validate_analysis(&$moll
   $data = array();
 
   $form_id = $form_state['values']['form_id'];
+  $data = mollom_form_get_values($form_state['values'], $mollom_state['#fields']);
 
   $pos = strpos($form_id, '_node_form');
   if ($pos !== FALSE) {
@@ -970,11 +1126,12 @@ function mollom($method, $data = array()
 /**
  * Helper function to debug the form API workflow.
  *
- * Uncomment the function body to activate.
+ * Comment the return to enable.
  */
 function _mollom_debug($message) {
-  // print $message .'<br />';
-  // error_log($message);
+  return;
+  print $message .'<br />';
+  error_log($message);
 }
 
 /**
Index: tests/mollom.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/tests/Attic/mollom.test,v
retrieving revision 1.1.2.19
diff -u -p -r1.1.2.19 mollom.test
--- tests/mollom.test	23 Oct 2009 00:35:22 -0000	1.1.2.19
+++ tests/mollom.test	20 Nov 2009 00:16:40 -0000
@@ -273,7 +273,7 @@ class MollomAccessTestCase extends Mollo
   function testKeyPairs() {
     // Check that a success message is shown.
     $this->drupalLogin($this->admin_user);
-    $this->drupalGet('admin/settings/mollom');
+    $this->drupalGet('admin/settings/mollom/settings');
     $this->assertText(t('We contacted the Mollom servers to verify your keys: the Mollom services are operating correctly. We are now blocking spam.'));
 
     // Set up invalid test keys and check that an error message is shown.
@@ -281,10 +281,10 @@ class MollomAccessTestCase extends Mollo
       'mollom_public_key' => 'invalid-public-key',
       'mollom_private_key' => 'invalid-private-key',
     );
-    $this->drupalPost('admin/settings/mollom', $edit, t('Save configuration'));
+    $this->drupalPost(NULL, $edit, t('Save configuration'));
     $this->assertText(t('The configuration options have been saved.'));
 
-    $this->drupalGet('admin/settings/mollom');
+    $this->drupalGet('admin/settings/mollom/settings');
     $this->assertRaw(t('"messages error"'), t('The Mollom settings page reports that the Mollom keys are invalid.'));
   }
 
@@ -302,8 +302,8 @@ class MollomAccessTestCase extends Mollo
     $this->assertResponse(200);
 
     // Check access for a user that has everything except the 'administer
-    // site configuration' permission. This user should not have access
-    // to the Mollom settings page.
+    // mollom' permission. This user should not have access to the Mollom
+    // settings page.
     $this->web_user = $this->drupalCreateUser(array_diff(module_invoke_all('perm'), array('administer mollom')));
     $this->drupalLogin($this->web_user);
     $this->drupalGet('admin/settings/mollom');
@@ -324,7 +324,9 @@ class MollomFallbackTestCase extends Mol
     parent::setUp('mollom');
     $this->setUpMollom();
     // Enable Mollom for the request password form.
-    variable_set('mollom_user_pass', MOLLOM_MODE_CAPTCHA);
+    $form_info = mollom_get_form_info('user_pass');
+    $form_info['fields'] = array_keys($form_info['parents']);
+    mollom_form_save($form_info);
   }
 
   /**
@@ -334,7 +336,7 @@ class MollomFallbackTestCase extends Mol
   function testFallbackMechanismBlock() {
     // Set the fallback strategy to 'blocking mode'.
     $this->drupalLogin($this->admin_user);
-    $this->drupalPost('admin/settings/mollom', array('mollom_fallback' => MOLLOM_FALLBACK_BLOCK), t('Save configuration'));
+    $this->drupalPost('admin/settings/mollom/settings', array('mollom_fallback' => MOLLOM_FALLBACK_BLOCK), t('Save configuration'));
     $this->assertText('The configuration options have been saved.');
     $this->drupalLogout();
 
@@ -356,7 +358,7 @@ class MollomFallbackTestCase extends Mol
   function testFallbackMechanismAccept() {
     // Set the fallback strategy to 'accept mode'.
     $this->drupalLogin($this->admin_user);
-    $this->drupalPost('admin/settings/mollom', array('mollom_fallback' => MOLLOM_FALLBACK_ACCEPT), t('Save configuration'));
+    $this->drupalPost('admin/settings/mollom/settings', array('mollom_fallback' => MOLLOM_FALLBACK_ACCEPT), t('Save configuration'));
     $this->assertText('The configuration options have been saved.');
     $this->drupalLogout();
 
@@ -466,7 +468,9 @@ class MollomUserFormsTestCase extends Mo
    */
   function testProtectRequestPassword() {
     // We first enable Mollom for the request password form.
-    variable_set('mollom_user_pass', MOLLOM_MODE_CAPTCHA);
+    $form_info = mollom_get_form_info('user_pass');
+    $form_info['fields'] = array_keys($form_info['parents']);
+    mollom_form_save($form_info);
 
     // Create a new user.
     $this->web_user = $this->drupalCreateUser();
@@ -487,7 +491,9 @@ class MollomUserFormsTestCase extends Mo
    */
   function testProtectRegisterUser() {
     // We first enable Mollom for the user registration form.
-    variable_set('mollom_user_register', MOLLOM_MODE_CAPTCHA);
+    $form_info = mollom_get_form_info('user_register');
+    $form_info['fields'] = array_keys($form_info['parents']);
+    mollom_form_save($form_info);
 
     // Validate that the user registration form has a CAPTCHA text field.
     $this->drupalGet('user/register');
@@ -523,7 +529,7 @@ class MollomCommentFormTestCase extends 
   }
 
   function setUp() {
-    parent::setUp('mollom', 'comment');
+    parent::setUp('comment', 'mollom');
     $this->setUpMollom();
     $this->web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'post comments without approval', 'create story content'));
     $this->node = $this->drupalCreateNode(array('type' => 'story', 'uid' => $this->web_user->uid));
@@ -536,7 +542,12 @@ class MollomCommentFormTestCase extends 
    */
   function testUnprotectedCommentForm() {
     // Disable Mollom for comments.
-    variable_set('mollom_comment_form', MOLLOM_MODE_DISABLED);
+    $mollom_form = array(
+      'form_id' => 'comment_form',
+      'mode' => MOLLOM_MODE_DISABLED,
+      'fields' => array(),
+    );
+    mollom_form_save($mollom_form);
 
     // Request the comment reply form. There should be no CAPTCHA.
     $this->drupalGet('comment/reply/'. $this->node->nid);
@@ -548,7 +559,7 @@ class MollomCommentFormTestCase extends 
 
     // Save the comment and make sure it appears.
     $this->drupalPost(NULL, array(), t('Save'));
-    $this->assertRaw('<p>spam</p>', t('A comment that is known to be ham appears on the screen after it is submitted.'));
+    $this->assertRaw('<p>spam</p>', t('A comment that is known to be spam appears on the screen after it is submitted.'));
   }
 
   /**
@@ -556,7 +567,12 @@ class MollomCommentFormTestCase extends 
    */
   function testCaptchaProtectedCommentForm() {
     // Enable Mollom CAPTCHA protection for comments.
-    variable_set('mollom_comment_form', MOLLOM_MODE_CAPTCHA);
+    $mollom_form = array(
+      'form_id' => 'comment_form',
+      'mode' => MOLLOM_MODE_CAPTCHA,
+      'fields' => array(),
+    );
+    mollom_form_save($mollom_form);
 
     // Request the comment reply form. There should be a CAPTCHA form.
     $this->drupalGet('comment/reply/'. $this->node->nid);
@@ -584,7 +600,9 @@ class MollomCommentFormTestCase extends 
    */
   function testTextAnalysisProtectedCommentForm() {
     // Enable Mollom text-classification for comments.
-    variable_set('mollom_comment_form', MOLLOM_MODE_ANALYSIS);
+    $form_info = mollom_get_form_info('comment_form');
+    $form_info['fields'] = array_keys($form_info['parents']);
+    mollom_form_save($form_info);
 
     // Request the comment reply form.  Initially, there should be no CAPTCHA.
     $this->drupalGet('comment/reply/'. $this->node->nid);
@@ -670,7 +688,7 @@ class MollomContactFormTestCase extends 
   }
 
   function setUp() {
-    parent::setUp('mollom', 'contact');
+    parent::setUp('contact', 'mollom');
     $this->setUpMollom();
     $this->web_user = $this->drupalCreateUser(array('access site-wide contact form', 'access user profiles'));
     $this->drupalLogin($this->web_user);
@@ -683,7 +701,9 @@ class MollomContactFormTestCase extends 
    */
   function testProtectContactUserForm() {
     // Enable Mollom for the contact form.
-    variable_set('mollom_contact_mail_user', MOLLOM_MODE_ANALYSIS);
+    $form_info = mollom_get_form_info('contact_mail_user');
+    $form_info['fields'] = array_keys($form_info['parents']);
+    mollom_form_save($form_info);
 
     $url = 'user/' . $this->admin_user->uid . '/contact';
     $button = t('Send e-mail');
@@ -709,7 +729,9 @@ class MollomContactFormTestCase extends 
    */
   function testProtectContactSiteForm() {
     // Enable Mollom for the contact form.
-    variable_set('mollom_contact_mail_page', MOLLOM_MODE_ANALYSIS);
+    $form_info = mollom_get_form_info('contact_mail_page');
+    $form_info['fields'] = array_keys($form_info['parents']);
+    mollom_form_save($form_info);
 
     // Add some fields to the contact form so that it is active.
     db_query("INSERT INTO {contact} (category, recipients, reply) VALUES ('%s', '%s', '%s')", 'test category', $this->web_user->mail, 'test auto-reply');
