Index: mollom.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.admin.inc,v
retrieving revision 1.1.2.33
diff -u -p -r1.1.2.33 mollom.admin.inc
--- mollom.admin.inc	11 Aug 2010 00:47:10 -0000	1.1.2.33
+++ mollom.admin.inc	30 Aug 2010 18:11:55 -0000
@@ -138,6 +138,24 @@ function mollom_admin_configure_form(&$f
         ),
         '#default_value' => $mollom_form['mode'],
       );
+      // The negated form widget and value handling looks a bit weird, but users
+      // can rather relate to more common "unpublish" and "moderation" terms,
+      // and by default, Mollom should operate correctly and therefore also
+      // reject spam posts, so this setting should stay optional and disabled by
+      // default. The internally stored value for 'reject' is technically smart,
+      // since a value of 1 means to reject spam posts, and 0 means to unpublish
+      // posts; the value therefore represents "rejection" and a "publishing
+      // status" at the same time.
+      // @todo Is this checkbox limited to spam? (what about profanity?)
+      $form['mollom']['reject'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Unpublish spam posts instead of rejecting'),
+        '#default_value' => !$mollom_form['reject'],
+      );
+      if (!isset($mollom_form['mapping']['post_status'])) {
+        $form['mollom']['reject']['#disabled'] = TRUE;
+        $form['mollom']['reject']['#description'] = t('This form does not support moderation of unpublished posts.');
+      }
 
       if (!empty($mollom_form['elements'])) {
         // Add the text analysis protection mode as first, suggested option.
@@ -236,10 +254,9 @@ function mollom_admin_configure_form_sub
   $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['reject'] = !$mollom_form['reject'];
   $enabled_fields = array();
   foreach (array_keys(array_filter($mollom_form['enabled_fields'])) as $field) {
     $enabled_fields[] = rawurldecode($field);
Index: mollom.api.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.api.php,v
retrieving revision 1.1.2.6
diff -u -p -r1.1.2.6 mollom.api.php
--- mollom.api.php	18 Aug 2010 00:43:27 -0000	1.1.2.6
+++ mollom.api.php	31 Aug 2010 10:54:02 -0000
@@ -153,6 +153,8 @@
  *         'entity' => 'im',
  *         // Optional: User permission list to skip Mollom's protection for.
  *         'bypass access' => array('administer instant messages'),
+ *         // @todo
+ *         'reject callback' => 'im_mollom_reject',
  *         // Optional: To allow textual analysis of the form values, the form
  *         // elements needs to be registered individually. The keys are the
  *         // field keys in $form_state['values']. Sub-keys are noted using "]["
@@ -275,6 +277,10 @@ function hook_mollom_form_list() {
  *     current user to determine whether to protect the form with Mollom or do
  *     not validate submitted form values. If the current user has at least one
  *     of the listed permissions, the form will not be protected.
+ *   - reject callback: (optional) A function name to invoke when a form
+ *     submission would normally be rejected. This allows modules to put such
+ *     posts into a moderation queue (i.e., accept but not publish them) by
+ *     altering the $form or $form_state information being passed by reference.
  *   - mail ids: (optional) An array of mail IDs that will be sent as a result
  *     of this form being submitted. When these mails are sent, a 'report to
  *     Mollom' link will be included at the bottom of the mail body. Be sure to
Index: mollom.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.install,v
retrieving revision 1.2.2.31
diff -u -p -r1.2.2.31 mollom.install
--- mollom.install	6 Apr 2010 22:17:51 -0000	1.2.2.31
+++ mollom.install	30 Aug 2010 18:11:55 -0000
@@ -118,6 +118,13 @@ function mollom_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
+      'reject' => array(
+        'description' => 'Whether to reject (1) or unpublish (0) spam submissions.',
+        'type' => 'int',
+        'size' => 'tiny',
+        'not null' => TRUE,
+        'default' => 1,
+      ),
       'enabled_fields' => array(
         'description' => 'A list of form elements configured for textual analysis.',
         'type' => 'text',
@@ -382,3 +389,19 @@ function mollom_update_6112() {
   }
   return $ret;
 }
+
+/**
+ * Add {mollom_form}.reject column to form configuration.
+ */
+function mollom_update_6113() {
+  $ret = array();
+  if (!db_column_exists('mollom_form', 'reject')) {
+    db_add_field($ret, 'mollom_form', 'reject', array(
+      'type' => 'int',
+      'size' => 'tiny',
+      'not null' => TRUE,
+      'default' => 1,
+    ));
+  }
+  return $ret;
+}
Index: mollom.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.module,v
retrieving revision 1.2.2.156
diff -u -p -r1.2.2.156 mollom.module
--- mollom.module	7 Aug 2010 02:49:44 -0000	1.2.2.156
+++ mollom.module	31 Aug 2010 10:53:22 -0000
@@ -400,7 +400,6 @@ function mollom_data_load($entity, $id) 
  * - session: The session ID returned by the Mollom server.
  * - quality: A quality rating assigned to the content to tell whether or not
  *   it's spam.
- * - reputation: The reputation of the author.
  * - languages: An array containing language codes the content might be
  *   written in.
  *
@@ -418,7 +417,7 @@ function mollom_data_load($entity, $id) 
  */
 function mollom_data_save($entity, $id) {
   // Nothing to do, if we do not have a valid Mollom response.
-  if (!isset($GLOBALS['mollom_response']['session_id'])) {
+  if (empty($GLOBALS['mollom_response']['session_id'])) {
     return FALSE;
   }
   $data = $GLOBALS['mollom_response'];
@@ -632,6 +631,7 @@ function mollom_form_alter(&$form, &$for
       // Add Mollom form validation handlers.
       $form['#validate'][] = 'mollom_validate_analysis';
       $form['#validate'][] = 'mollom_validate_captcha';
+      $form['#validate'][] = 'mollom_validate_status';
 
       // Add a submit handler to remove form state storage.
       $form['#submit'][] = 'mollom_form_submit';
@@ -779,6 +779,7 @@ function mollom_form_info($form_id, $mod
     'entity' => NULL,
     'title' => $form_id,
     'mode' => NULL,
+    'reject' => FALSE,
     'bypass access' => array(),
     'elements' => array(),
     'mapping' => array(),
@@ -1226,18 +1227,15 @@ function mollom_process_mollom($element,
   // Setup initial Mollom session and form information.
   if (empty($form_state['mollom'])) {
     $form_state['mollom'] = array(
-      'form_id' => $element['#mollom_form']['form_id'],
       'require_analysis' => $element['#mollom_form']['mode'] == MOLLOM_MODE_ANALYSIS,
       'require_captcha' => $element['#mollom_form']['mode'] == MOLLOM_MODE_CAPTCHA,
       'passed_captcha' => FALSE,
-      'entity' => $element['#mollom_form']['entity'],
-      'enabled_fields' => $element['#mollom_form']['enabled_fields'],
-      'mapping' => $element['#mollom_form']['mapping'],
       'response' => array(
         'session_id' => '',
       ),
     );
   }
+  $form_state['mollom'] += $element['#mollom_form'];
 
   // Add the Mollom session element.
   $element['session_id'] = array(
@@ -1265,6 +1263,12 @@ function mollom_process_mollom($element,
   // $form_state['mollom'] will be carried over to the element for rendering.
   $element['#mollom'] = &$form_state['mollom'];
 
+  // Make Mollom form and session information available to entirely different
+  // functions.
+  // @todo Rename 'mollom_form' into 'mollom', and remove 'mollom_response'.
+  $GLOBALS['mollom_response'] = &$form_state['mollom']['response'];
+  $GLOBALS['mollom_form'] = &$form_state['mollom'];
+
   return $element;
 }
 
@@ -1343,9 +1347,6 @@ function mollom_validate_analysis(&$form
   }
   // Store the response returned by Mollom.
   $form_state['mollom']['response'] = $result;
-  // @todo Only used for Contact module and mail integration in general.
-  $GLOBALS['mollom_response'] = $form_state['mollom']['response'];
-  $GLOBALS['mollom_form'] = $form['mollom']['#mollom_form'];
 
   switch ($result['spam']) {
     case MOLLOM_ANALYSIS_HAM:
@@ -1353,13 +1354,20 @@ function mollom_validate_analysis(&$form
       break;
 
     case MOLLOM_ANALYSIS_SPAM:
-      form_set_error('mollom', t('Your submission has triggered the spam filter and will not be accepted.'));
+      // By default, the submission is rejected, unless the form was configured
+      // to unpublish spam posts, which requires a valid 'reject callback'.
+      // @see mollom_validate_status()
+      if (!isset($form_state['mollom']['reject callback']) || !function_exists($form_state['mollom']['reject callback'])) {
+        form_set_error('mollom', t('Your submission has triggered the spam filter and will not be accepted.'));
+      }
+      else {
+        $form_state['mollom']['reject'] = TRUE;
+      }
       watchdog('mollom', 'Spam: <pre>@message</pre>Result: <pre>@result</pre>', array('@message' => print_r($data, TRUE), '@result' => print_r($result, TRUE)));
       break;
 
-    default:
-      // Fall back to a CAPTCHA.
-      form_set_error('mollom', t("To complete this form, please complete the word verification below."));
+    case MOLLOM_ANALYSIS_UNSURE:
+      form_set_error('mollom][captcha', t('To complete this form, please complete the word verification below.'));
       watchdog('mollom', 'Unsure: <pre>@message</pre>Result: <pre>@result</pre>', array('@message' => print_r($data, TRUE), '@result' => print_r($result, TRUE)));
 
       $form_state['mollom']['require_captcha'] = TRUE;
@@ -1378,11 +1386,10 @@ function mollom_validate_captcha(&$form,
   // When re-validating a form that already passed a CAPTCHA in a previous
   // request, we need to re-populate our global variable for mollom_data_save().
   if ($form_state['mollom']['passed_captcha']) {
-    $GLOBALS['mollom_response'] = $form_state['mollom']['response'];
     return;
   }
 
-  // Bail out if no value was provided.
+  // Nothing to validate if there is no value.
   if (empty($form_state['values']['mollom']['captcha'])) {
     form_set_error('mollom][captcha', t('The word verification field is required.'));
     return;
@@ -1400,9 +1407,7 @@ function mollom_validate_captcha(&$form,
     'author_id' => isset($data['author_id']) ? $data['author_id'] : NULL,
   ));
   // Store the response for #submit handlers.
-  $form_state['mollom']['response']['spam'] = (int) $result;
-  $GLOBALS['mollom_response'] = $form_state['mollom']['response'];
-  $GLOBALS['mollom_form'] = $form['mollom']['#mollom_form'];
+  $form_state['mollom']['response']['captcha'] = $result;
 
   // Explictly check for TRUE, since mollom.checkCaptcha() can also return an
   // error message (e.g. expired or invalid session_id).
@@ -1418,6 +1423,20 @@ function mollom_validate_captcha(&$form,
 }
 
 /**
+ * Form validation handler to perform post-validation tasks.
+ *
+ * Required, since our individual form validation handlers may not be re-run
+ * after positive validation. Thus, any changes applied to form values may not
+ * persist across multiple submission attempts/form rebuilds.
+ */
+function mollom_validate_status(&$form, &$form_state) {
+  if (!$form_state['mollom']['reject']) {
+    $function = $form_state['mollom']['reject callback'];
+    $function($form, $form_state);
+  }
+}
+
+/**
  * Form element #pre_render callback for CAPTCHA element.
  *
  * Conditionally alters the #type of the CAPTCHA form element into a 'hidden'
@@ -1902,6 +1921,7 @@ function node_mollom_form_info($form_id)
     'bypass access' => array('administer nodes', 'edit any ' . $type->type . ' content'),
     'entity' => 'node',
     'bundle' => $type->type,
+    'reject callback' => 'node_mollom_reject',
     'elements' => array(),
     'mapping' => array(
       'post_id' => 'nid',
@@ -1944,6 +1964,13 @@ function mollom_nodeapi($node, $op) {
 }
 
 /**
+ * Mollom reject callback.
+ */
+function node_mollom_reject(&$form, &$form_state) {
+  $form_state['values']['status'] = 0;
+}
+
+/**
  * Implements hook_form_FORMID_alter().
  *
  * Hook into the mass comment administration page and add some operations to
@@ -2004,6 +2031,7 @@ function comment_mollom_form_info($form_
     'mode' => MOLLOM_MODE_ANALYSIS,
     'bypass access' => array('administer comments'),
     'entity' => 'comment',
+    'reject callback' => 'comment_mollom_reject',
     'elements' => array(
       'subject' => t('Subject'),
       'comment' => t('Comment'),
@@ -2081,6 +2109,13 @@ function mollom_comment($comment, $op) {
 }
 
 /**
+ * Mollom reject callback.
+ */
+function comment_mollom_reject(&$form, &$form_state) {
+  $form_state['values']['status'] = COMMENT_NOT_PUBLISHED;
+}
+
+/**
  * Implements hook_form_FORMID_alter().
  *
  * Hook into the mass comment administration page and add some operations to
@@ -2146,6 +2181,7 @@ function user_mollom_form_info($form_id)
         'title' => t('User registration form'),
         'mode' => MOLLOM_MODE_CAPTCHA,
         'bypass access' => array('administer users'),
+        'reject callback' => 'user_mollom_reject',
         'entity' => 'user',
         'mapping' => array(
           'post_id' => 'uid',
@@ -2160,6 +2196,7 @@ function user_mollom_form_info($form_id)
         'title' => t('User password request form'),
         'mode' => MOLLOM_MODE_CAPTCHA,
         'bypass access' => array('administer users'),
+        'reject callback' => 'user_mollom_reject',
         'entity' => 'user',
         'mapping' => array(
           'post_id' => 'uid',
@@ -2173,6 +2210,13 @@ function user_mollom_form_info($form_id)
 }
 
 /**
+ * Mollom reject callback.
+ */
+function user_mollom_reject(&$form, &$form_state) {
+  $form_state['values']['status'] = 0;
+}
+
+/**
  * @} End of "name mollom_user".
  */
 
