Index: mollom.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.admin.inc,v
retrieving revision 1.7
diff -u -p -r1.7 mollom.admin.inc
--- mollom.admin.inc	14 Jan 2010 18:42:50 -0000	1.7
+++ mollom.admin.inc	29 Jan 2010 17:00:46 -0000
@@ -270,19 +270,18 @@ function mollom_admin_unprotect_form_sub
  * Form builder; Global Mollom settings form.
  */
 function mollom_admin_settings($form, &$form_state) {
-  $keys = _mollom_access();
-
-  if ($keys) {
-    if (!$_POST) {
-      // When a user visits the Mollom administration page, automatically
-      // clear the server list.  This causes the client to fetch a fresh
-      // server list from the server.
-      // @todo Add a timeout interval. Also consider hook_enable() together with
-      //   hook_cron().
-      variable_del('mollom_servers');
-
-      // Verify the key and output a status message.
-      _mollom_verify_key();
+  // When a user visits the Mollom administration page, automatically verify the
+  // keys and output any error messages.
+  if (empty($form_state['input'])) {
+    $status = _mollom_status(TRUE);
+    if ($status === TRUE) {
+      // Everything is in order.
+    }
+    elseif ($status['keys valid'] === 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');
+    }
+    elseif ($status['keys valid'] === 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');
     }
   }
 
@@ -307,7 +306,7 @@ function mollom_admin_settings($form, &$
   $form['access-keys'] = array(
     '#type' => 'fieldset',
     '#title' => t('Mollom access keys'),
-    '#description' => t('In order to use Mollom, you need both a public and private key. To obtain your keys, simply <a href="@mollom-register">create a user account on mollom.com</a>, <a href="@mollom-login">login to mollom.com</a>, and <a href="@mollom-manager-add">create a subscription</a> for your site.  Once you created a subscription, your private and public access keys will be available from the <a href="@mollom-manager">site manager on mollom.com</a>. Copy-paste them in the form below, and you are ready to go.', array(
+    '#description' => t('To use Mollom, you need a public and private key. To obtain your keys, <a href="@mollom-login">register and login on mollom.com</a>, and <a href="@mollom-manager-add">create a subscription</a> for your site. Once you created a subscription, copy your private and public access keys from the <a href="@mollom-manager">site manager</a> into the form fields below, and you are ready to go.', array(
       '@mollom-register' => 'http://mollom.com/user/register',
       '@mollom-login' => 'http://mollom.com/user',
       '@mollom-manager-add' => 'http://mollom.com/site-manager/add',
@@ -331,26 +330,6 @@ function mollom_admin_settings($form, &$
 }
 
 /**
- * Verifies the Mollom key by contacting Mollom servers.
- */
-function _mollom_verify_key() {
-  $status = mollom('mollom.verifyKey');
-
-  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;
-  }
-}
-
-/**
  * Form submit handler to mass-report and unpublish or delete comments.
  */
 function mollom_comment_admin_overview_submit($form, &$form_state) {
Index: mollom.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.inc,v
retrieving revision 1.3
diff -u -p -r1.3 mollom.inc
--- mollom.inc	21 Dec 2009 20:24:22 -0000	1.3
+++ mollom.inc	29 Jan 2010 17:01:11 -0000
@@ -25,10 +25,19 @@
  *
  * Make sure your server's time is synchronized with the world clocks,
  * and that you don't share your private key with anyone else.
+ *
+ * @param $public_key
+ *   (optional) The public key to use for authentication. Only used internally.
+ * @param $private_key
+ *   (optional) The private key to use for authentication. Only used internally.
  */
-function _mollom_authentication() {
-  $public_key = variable_get('mollom_public_key', '');
-  $private_key = variable_get('mollom_private_key', '');
+function _mollom_authentication($public_key = NULL, $private_key = NULL) {
+  if (!isset($public_key)) {
+    $public_key = variable_get('mollom_public_key', '');
+  }
+  if (!isset($private_key)) {
+    $private_key = variable_get('mollom_private_key', '');
+  }
 
   // Generate a timestamp according to the dateTime format (http://www.w3.org/TR/xmlschema-2/#dateTime):
   $time = gmdate("Y-m-d\TH:i:s.\\0\\0\\0O", REQUEST_TIME);
@@ -71,6 +80,6 @@ function _mollom_retrieve_server_list() 
     }
   }
 
-  return array();
+  return xmlrpc_errno();
 }
 
Index: mollom.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.install,v
retrieving revision 1.6
diff -u -p -r1.6 mollom.install
--- mollom.install	18 Jan 2010 22:46:38 -0000	1.6
+++ mollom.install	29 Jan 2010 17:01:35 -0000
@@ -7,6 +7,41 @@
  */
 
 /**
+ * Implements hook_requirements().
+ */
+function mollom_requirements($phase = 'runtime') {
+  $requirements = array();
+  if ($phase == 'runtime') {
+    $status = _mollom_status(TRUE);
+    // Immediately return if everything is in order.
+    if ($status === TRUE) {
+      return $requirements;
+    }
+    // If not, something is wrong; prepare the requirements entry and set
+    // defaults for any yet unknown edge-cases.
+    $requirements['mollom'] = array(
+      'title' => 'Mollom API keys',
+      'value' => '',
+      'severity' => REQUIREMENT_ERROR,
+    );
+    // Missing API keys.
+    if (!$status['keys']) {
+      $requirements['mollom']['value'] = t('Not configured');
+      $requirements['mollom']['description'] = t('Mollom API keys are not <a href="@settings-url">configured</a> yet.', array('@settings-url' => url('admin/settings/mollom/settings')));
+    }
+    elseif ($status['keys valid'] === NETWORK_ERROR) {
+      $requirements['mollom']['value'] = t('Network error');
+      $requirements['mollom']['description'] = t('The Mollom servers could not be contacted. Please make sure that your web server can make outgoing HTTP requests.');
+    }
+    elseif ($status['keys valid'] === MOLLOM_ERROR) {
+      $requirements['mollom']['value'] = t('Invalid');
+      $requirements['mollom']['description'] = t('The <a href="@settings-url">configured</a> Mollom API keys are invalid.', array('@settings-url' => url('admin/settings/mollom/settings')));
+    }
+  }
+  return $requirements;
+}
+
+/**
  * Implements hook_schema().
  */
 function mollom_schema() {
Index: mollom.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.module,v
retrieving revision 1.15
diff -u -p -r1.15 mollom.module
--- mollom.module	18 Jan 2010 22:35:58 -0000	1.15
+++ mollom.module	29 Jan 2010 17:07:18 -0000
@@ -371,7 +371,7 @@ function mollom_data_delete($entity, $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')) {
+  if (!user_access('post with no checking') && _mollom_status() === TRUE) {
     // Retrieve configuration for this form.
     if ($mollom_form = mollom_form_load($form_id)) {
       // Determine whether to bypass validation for the current user.
@@ -714,6 +714,51 @@ function _mollom_get_openid($account) {
 }
 
 /**
+ * Returns the (last known) status of the configured Mollom API keys.
+ *
+ * @param $reset
+ *   (optional) Boolean whether to reset the stored state and re-check.
+ *   Defaults to FALSE.
+ *
+ * @return
+ *   TRUE if the module is considered operable, or an associative array
+ *   describing the current status of the module:
+ *   - keys: Boolean whether Mollom API keys have been configured.
+ *   - keys valid: TRUE if Mollom API keys are valid, or the error code as
+ *     returned by Mollom servers.
+ *   - servers: Boolean whether there is a non-empty list of Mollom servers.
+ *
+ * @see mollom_requirements()
+ */
+function _mollom_status($reset = FALSE) {
+  // Load stored status.
+  $status = variable_get('mollom_status', array(
+    'keys valid' => FALSE,
+  ));
+
+  // Both API keys are required.
+  $public_key = variable_get('mollom_public_key', '');
+  $private_key = variable_get('mollom_private_key', '');
+  $status['keys'] = (!empty($public_key) && !empty($private_key));
+
+  // If we have keys and are asked to reset, check whether keys are valid.
+  if ($status['keys'] && $reset) {
+    $status['keys valid'] = mollom('mollom.verifyKey');
+    variable_set('mollom_status', $status);
+  }
+
+  if ($status['keys valid'] === TRUE) {
+    return TRUE;
+  }
+
+  // In case of an error, also indicate whether we have a non-empty server list.
+  $servers = variable_get('mollom_servers', array());
+  $status['servers'] = !empty($servers);
+
+  return $status;
+}
+
+/**
  * Helper function to log and optionally output an error message when Mollom servers are unavailable.
  */
 function _mollom_fallback() {
@@ -1127,11 +1172,20 @@ function mollom($method, $data = array()
   $refresh = FALSE;
 
   // Retrieve the list of Mollom servers from the database.
-  $servers = variable_get('mollom_servers', NULL);
+  $servers = variable_get('mollom_servers', array());
 
-  if ($servers == NULL) {
+  if (empty($servers)) {
     // Retrieve a new list of servers.
     $servers = _mollom_retrieve_server_list();
+    // If API keys are invalid, a XML-RPC error code is returned.
+    if (!is_array($servers)) {
+      return $servers;
+    }
+
+    $messages[] = array(
+      'text' => 'Refreshed servers: %servers',
+      'arguments' => array('%servers' => implode(', ', $servers)),
+    );
 
     // Store the list of servers in the database.
     variable_set('mollom_servers', $servers);
@@ -1145,13 +1199,20 @@ function mollom($method, $data = array()
       $result = xmlrpc($server . '/' . MOLLOM_API_VERSION, $method, $data + _mollom_authentication());
 
       if ($result === FALSE && ($error = xmlrpc_error())) {
-        if ($error->code == MOLLOM_REFRESH) {
+        if ($error->code === MOLLOM_REFRESH) {
           // Avoid endless loops.
           if (!$refresh) {
             $refresh = TRUE;
 
             // Retrieve a new list of valid Mollom servers.
             $servers = _mollom_retrieve_server_list();
+            // If API keys are invalid, the XML-RPC error code is returned.
+            // To reach this, we must have had a server list (and therefore
+            // valid keys) before, so we do not immediately return (like above),
+            // but instead trigger the fallback mode.
+            if (!is_array($servers)) {
+              break;
+            }
 
             // Reset the list of servers to restart from the first server.
             reset($servers);
@@ -1165,7 +1226,7 @@ function mollom($method, $data = array()
             );
           }
         }
-        elseif ($error->code == MOLLOM_REDIRECT) {
+        elseif ($error->code === MOLLOM_REDIRECT) {
           // Try the next server in the list.
           $next = next($servers);
 
@@ -1187,7 +1248,7 @@ function mollom($method, $data = array()
           );
 
           // Instantly return upon a 'real' error.
-          if ($error->code == MOLLOM_ERROR) {
+          if ($error->code === MOLLOM_ERROR) {
             _mollom_watchdog($messages, WATCHDOG_ERROR);
             return MOLLOM_ERROR;
           }
@@ -1203,7 +1264,17 @@ function mollom($method, $data = array()
   }
 
   // If none of the servers worked, activate the fallback mechanism.
-  _mollom_fallback();
+  // @todo mollom() can be invoked outside of form processing. _mollom_fallback()
+  //   unconditionally invokes form_set_error(), which always displays the
+  //   fallback error message. Ideally, we would pass a $verbose argument to
+  //   _mollom_fallback(), but for that, we'd have to know here already.
+  //   Consequently, mollom() would need that $verbose argument. In the end, we
+  //   likely want to either embed the fallback handling into form processing,
+  //   or introduce a new helper function that is invoked instead of mollom()
+  //   during form processing.
+  if ($method != 'mollom.verifyKey') {
+    _mollom_fallback();
+  }
 
   // If everything failed, we reset the server list to force Mollom to request
   // a new list.
@@ -1263,7 +1334,7 @@ function mollom_get_statistics($refresh 
 
   // Only fetch if $refresh is TRUE, the cache is empty, or the cache is expired.
   if ($refresh || !$cache || REQUEST_TIME >= $cache->expire) {
-    if (_mollom_access()) {
+    if (_mollom_status() === TRUE) {
       $statistics = drupal_map_assoc(array(
         'total_days',
         'total_accepted',
@@ -1402,7 +1473,7 @@ function mollom_form_node_admin_content_
  */
 function mollom_node_view($node, $build_mode) {
   // Only show the links if the module is configured.
-  if (_mollom_access() && user_access('administer nodes') && mollom_get_mode($node->type . '_node_form')) {
+  if (_mollom_status() === TRUE && user_access('administer nodes') && mollom_get_mode($node->type . '_node_form')) {
     $node->content['links']['mollom'] = array(
       '#theme' => 'links',
       '#links' => array(
@@ -1503,7 +1574,7 @@ function mollom_form_comment_admin_overv
  */
 function mollom_comment_view($comment, $build_mode) {
   // Only show the links if the module is configured.
-  if (_mollom_access() && user_access('administer comments') && mollom_get_mode('comment_form')) {
+  if (_mollom_status() === TRUE && user_access('administer comments') && mollom_get_mode('comment_form')) {
     $comment->content['links']['mollom'] = array(
       '#theme' => 'links',
       '#links' => array(
Index: tests/mollom.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/tests/mollom.test,v
retrieving revision 1.9
diff -u -p -r1.9 mollom.test
--- tests/mollom.test	14 Jan 2010 18:42:50 -0000	1.9
+++ tests/mollom.test	29 Jan 2010 17:55:55 -0000
@@ -83,27 +83,33 @@ class MollomWebTestCase extends DrupalWe
     $this->resetSessionID();
     $this->messages = array();
 
-    // Call parent::setUp() allowing Mollom test cases to pass further modules.
-    $modules = func_get_args();
-    $modules[] = 'mollom';
-    $modules[] = 'dblog';
-    call_user_func_array(array($this, 'parent::setUp'), $modules);
-
-    $this->admin_user = $this->drupalCreateUser(array(
-      'administer mollom',
-      'access administration pages',
-      'administer content types',
-      'administer comments',
-      'administer permissions',
-    ));
-    $this->setKeys();
-    $this->assertValidKeys();
+    // If not explicitly disabled by a test, setup with Mollom and default admin
+    // user.
+    if (empty($this->disableDefaultSetup)) {
+      // Call parent::setUp() allowing Mollom test cases to pass further modules.
+      $modules = func_get_args();
+      $modules[] = 'mollom';
+      $modules[] = 'dblog';
+      call_user_func_array(array($this, 'parent::setUp'), $modules);
+
+      $this->admin_user = $this->drupalCreateUser(array(
+        'administer mollom',
+        'access administration pages',
+        'administer content types',
+        'administer comments',
+        'administer permissions',
+      ));
+    }
+    else {
+      $modules = func_get_args();
+      $modules[] = 'dblog';
+      call_user_func_array(array($this, 'parent::setUp'), $modules);
+    }
 
-    // @todo Remove this when comment body is required again.
-    $instance = field_info_instance('comment', 'comment_body', 'comment_node_article');
-    if (empty($instance['required'])) {
-      $instance['required'] = TRUE;
-      field_update_instance($instance);
+    // If not explicitly disabled by a test, setup and validate testing keys.
+    if (empty($this->disableDefaultSetup)) {
+      $this->setKeys();
+      $this->assertValidKeys();
     }
   }
 
@@ -244,11 +250,9 @@ class MollomWebTestCase extends DrupalWe
    * keys are valid.
    */
   protected function assertValidKeys() {
-    // Call the mollom.verifyKey function directly and check that the key
-    // is valid.
-    $key_is_valid = mollom('mollom.verifyKey');
+    $status = _mollom_status(TRUE);
     $this->assertMollomWatchdogMessages();
-    $this->assertIdentical($key_is_valid, TRUE, t('The Mollom servers can be contacted and the key pair specified in the mollom.test file is found to be valid.'));
+    $this->assertIdentical($status, TRUE, t('Mollom servers can be contacted and testing API keys are valid.'));
   }
 
   /**
@@ -582,6 +586,102 @@ class MollomWebTestCase extends DrupalWe
 }
 
 /**
+ * Tests module installation and global status handling.
+ */
+class MollomStatusTestCase extends MollomWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Status handling',
+      'description' => 'Tests module installation and global status handling.',
+      'group' => 'Mollom',
+    );
+  }
+
+  function setUp() {
+    // Re-initialize stored session_id and watchdog messages.
+    $this->resetSessionID();
+    $this->messages = array();
+
+    $this->disableDefaultSetup = TRUE;
+    parent::setUp('comment');
+
+    $this->admin_user = $this->drupalCreateUser(array(
+      'access administration pages',
+      'administer site configuration',
+      'administer modules',
+      'administer permissions',
+    ));
+    $this->web_user = $this->drupalCreateUser();
+  }
+
+  /**
+   * Tests status handling after installation.
+   */
+  function testStatusInstallation() {
+    // Ensure there is no requirements error by default.
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin/reports/status');
+    $this->clickLink('run cron manually');
+    $this->drupalGet('admin');
+    $this->assertNoLink('status report');
+
+    // Install the module.
+    $this->drupalPost('admin/modules', array('modules[Other][mollom][enable]' => TRUE), t('Save configuration'));
+
+    // Verify that forms can be submitted without valid module configuration.
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $this->drupalLogin($this->web_user);
+    $this->drupalGet('comment/reply/' . $node->nid);
+    $edit = array(
+      'comment_body[und][0][value]' => $this->randomName(),
+    );
+    $this->drupalPost(NULL, $edit, t('Preview'));
+    $this->drupalPost(NULL, array(), t('Save'));
+    $this->assertText(t('Your comment has been posted.'));
+
+    // Verify requirements error about missing API keys.
+    $this->drupalLogin($this->admin_user);
+    $this->drupalGet('admin');
+    $this->clickLink('status report');
+    // @todo Should a user without Mollom administration access see a
+    //   requirement error containing a link to the settings page?
+    $this->assertRaw(t('Mollom API keys are not <a href="@settings-url">configured</a> yet.', array('@settings-url' => url('admin/settings/mollom/settings'))), t('Requirements error found.'));
+
+    // Grant access to Mollom settings.
+    $edit = array(
+      DRUPAL_AUTHENTICATED_RID . '[administer mollom]' => TRUE,
+    );
+    $this->drupalPost('admin/config/people/permissions', $edit, t('Save permissions'));
+
+    // Configure invalid keys.
+    $edit = array(
+      'mollom_public_key' => 'foo',
+      'mollom_private_key' => 'bar',
+    );
+    $this->drupalPost('admin/config/content/mollom/settings', $edit, t('Save configuration'), array('watchdog' => FALSE));
+    $this->assertText(t('The configuration options have been saved.'));
+    $this->assertNoText($this->fallback_message, t('Fallback message not found.'));
+    $this->assertNoText(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.'), t('Network error message not found.'));
+    $this->assertRaw(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')), t('Invalid keys error message found.'));
+
+    // Verify requirements error about invalid API keys.
+    $this->drupalGet('admin', array('watchdog' => FALSE));
+    $this->assertLink('status report');
+    $this->drupalGet('admin/reports/status', array('watchdog' => FALSE));
+    $this->assertRaw(t('The <a href="@settings-url">configured</a> Mollom API keys are invalid.', array('@settings-url' => url('admin/settings/mollom/settings'))), t('Requirements error found.'));
+
+    // Replace server list with unreachable servers.
+    variable_set('mollom_servers', array('http://fake-host'));
+
+    // Verify requirements error about network error.
+    // Go directly to the status report, since the server list will be reset.
+    $this->drupalGet('admin/reports/status', array('watchdog' => FALSE));
+    $this->assertText(t('The Mollom servers could not be contacted. Please make sure that your web server can make outgoing HTTP requests.'), t('Requirements error found.'));
+    $this->assertNoText($this->fallback_message, t('Fallback message not found.'));
+  }
+}
+
+/**
  * Tests low-level XML-RPC communication with Mollom servers.
  */
 class MollomResponseTestCase extends MollomWebTestCase {
@@ -642,14 +742,13 @@ class MollomAccessTestCase extends Mollo
   }
 
   /**
-   * Configure both a valid and an invalid key pair and make sure both
-   * success and failure are reported on the Mollom settings page.
+   * Configure an invalid key pair and ensure error message.
    */
   function testKeyPairs() {
-    // Check that a success message is shown.
+    // No error message or watchdog messages should be thrown with default
+    // testing keys.
     $this->drupalLogin($this->admin_user);
     $this->drupalGet('admin/config/content/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.
     $edit = array(
@@ -658,7 +757,7 @@ class MollomAccessTestCase extends Mollo
     );
     $this->drupalPost(NULL, $edit, t('Save configuration'), array('watchdog' => FALSE));
     $this->assertText(t('The configuration options have been saved.'));
-    $this->assertRaw(t('"messages error"'), t('The Mollom settings page reports that the Mollom keys are invalid.'));
+    $this->assertRaw(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')), t('Invalid keys error message appears.'));
   }
 
   /**
Index: tests/mollom_test.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/tests/mollom_test.module,v
retrieving revision 1.3
diff -u -p -r1.3 mollom_test.module
--- tests/mollom_test.module	21 Dec 2009 20:24:22 -0000	1.3
+++ tests/mollom_test.module	29 Jan 2010 16:59:06 -0000
@@ -13,6 +13,7 @@ function mollom_test_xmlrpc() {
   return array(
     // $data contains a variable amount of properties, so we cannot specify a
     // signature.
+    'mollom.verifyKey' => 'mollom_test_verify_key',
     'mollom.checkContent' => 'mollom_test_check_content',
     'mollom.getImageCaptcha' => 'mollom_test_get_captcha',
     'mollom.checkCaptcha' => 'mollom_test_check_captcha',
@@ -20,6 +21,25 @@ function mollom_test_xmlrpc() {
 }
 
 /**
+ * XML-RPC callback for mollom.verifyKey to validate API keys.
+ */
+function mollom_test_verify_key($data) {
+  $storage = variable_get(__FUNCTION__, array());
+  $storage[] = $data;
+  variable_set(__FUNCTION__, $storage);
+
+  module_load_include('inc', 'mollom');
+  module_load_include('php', 'simpletest', 'drupal_web_test_case');
+  module_load_include('test', 'mollom', 'tests/mollom');
+  $expected = _mollom_authentication(MOLLOM_TEST_PUBLIC_KEY, MOLLOM_TEST_PRIVATE_KEY);
+
+  if ($data['public_key'] === $expected['public_key'] && $data['hash'] === $expected['hash']) {
+    return TRUE;
+  }
+  xmlrpc_error(MOLLOM_ERROR);
+}
+
+/**
  * XML-RPC callback for mollom.checkContent to perform textual analysis.
  *
  * @todo Add support for 'redirect' and 'refresh' values.
@@ -34,6 +54,9 @@ function mollom_test_check_content($data
   $spam = FALSE;
   $ham = FALSE;
   foreach (array('post_title', 'post_body') as $key) {
+    if (!isset($data[$key])) {
+      continue;
+    }
     // 'spam' always has precedence.
     if (strpos($data[$key], 'spam') !== FALSE) {
       $spam = TRUE;
