Index: mollom.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.admin.inc,v
retrieving revision 1.1.2.34
diff -u -p -r1.1.2.34 mollom.admin.inc
--- mollom.admin.inc	3 Sep 2010 18:53:51 -0000	1.1.2.34
+++ mollom.admin.inc	5 Sep 2010 21:57:24 -0000
@@ -140,6 +140,22 @@ function mollom_admin_configure_form(&$f
       );
 
       if (!empty($mollom_form['elements'])) {
+        // By default, Mollom module rejects all posts that did not successfully
+        // pass mollom.checkContent. Instead of rejecting posts, site admins
+        // can optionally configure that posts shall be unpublished instead, so
+        // they can go through manual moderation. The negated form widget may
+        // look odd, but users can rather relate to more common terms like
+        // "unpublish" or "moderation". Furthermore, by default, Mollom should
+        // reject bad posts, so this setting should stay optional and disabled
+        // by default.
+        $form['mollom']['reject'] = array(
+          '#type' => 'checkbox',
+          '#title' => t('Unpublish bad posts for manual moderation instead of rejecting them'),
+          '#default_value' => !$mollom_form['reject'],
+          // Only possible for forms supporting moderation of unpublished posts.
+          '#access' => !empty($mollom_form['reject callback']),
+        );
+
         // Add the text analysis protection mode as first, suggested option.
         $form['mollom']['mode']['#options'] = array(
           MOLLOM_MODE_ANALYSIS => t('Text analysis and CAPTCHA backup'),
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	5 Sep 2010 21:57:25 -0000
@@ -153,6 +153,9 @@
  *         'entity' => 'im',
  *         // Optional: User permission list to skip Mollom's protection for.
  *         'bypass access' => array('administer instant messages'),
+ *         // Optional: Function to invoke to unpublish a bad form submission
+ *         // instead of rejecting it.
+ *         '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 "]["
@@ -208,6 +211,16 @@
  * Additionally, the "post_id" data property always needs to be mapped to a form
  * element that holds the entity id.
  *
+ * When registering a 'reject callback', then the registered function needs to
+ * be available when the form is validated, and it is responsible for changing
+ * the submitted form values in a way that results in an unpublished post ending
+ * up in a moderation queue:
+ * @code
+ * function im_mollom_reject(&$form, &$form_state) {
+ *   $form_state['values']['status'] = 0;
+ * }
+ * @endcode
+ *
  * @see mollom_node
  * @see mollom_comment
  * @see mollom_user
@@ -275,6 +288,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	5 Sep 2010 21:57:25 -0000
@@ -118,6 +118,13 @@ function mollom_schema() {
         'not null' => TRUE,
         'default' => 0,
       ),
+      'reject' => array(
+        'description' => 'Whether to reject (1) or unpublish (0) bad form 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.157
diff -u -p -r1.2.2.157 mollom.module
--- mollom.module	3 Sep 2010 18:53:51 -0000	1.2.2.157
+++ mollom.module	5 Sep 2010 21:58:48 -0000
@@ -631,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_post';
 
       // Add a submit handler to remove form state storage.
       $form['#submit'][] = 'mollom_form_submit';
@@ -778,6 +779,7 @@ function mollom_form_info($form_id, $mod
     'entity' => NULL,
     'title' => $form_id,
     'mode' => NULL,
+    'reject' => TRUE,
     'bypass access' => array(),
     'elements' => array(),
     'mapping' => array(),
@@ -1235,6 +1237,13 @@ function mollom_process_mollom($element,
   }
   $form_state['mollom'] += $element['#mollom_form'];
 
+  // By default, bad form submissions are rejected, unless the form was
+  // configured to unpublish bad posts. 'reject' may only be FALSE, if there is
+  // a valid 'reject callback'. Otherwise, it must be TRUE.
+  if (empty($form_state['mollom']['reject callback']) || !function_exists($form_state['mollom']['reject callback'])) {
+    $form_state['mollom']['reject'] = TRUE;
+  }
+
   // Add the Mollom session element.
   $element['session_id'] = array(
     '#type' => 'hidden',
@@ -1265,6 +1274,10 @@ function mollom_process_mollom($element,
   // functions.
   $GLOBALS['mollom'] = &$form_state['mollom'];
 
+  // Make Mollom form and session information available to entirely different
+  // functions.
+  $GLOBALS['mollom'] = &$form_state['mollom'];
+
   return $element;
 }
 
@@ -1352,7 +1365,9 @@ function mollom_validate_analysis(&$form
 
     case MOLLOM_ANALYSIS_SPAM:
       $form_state['mollom']['require_captcha'] = FALSE;
-      form_set_error('mollom', t('Your submission has triggered the spam filter and will not be accepted.'));
+      if ($form_state['mollom']['reject']) {
+        form_set_error('mollom', t('Your submission has triggered the spam filter and will not be accepted.'));
+      }
       watchdog('mollom', 'Spam: <pre>@message</pre>Result: <pre>@result</pre>', array('@message' => print_r($data, TRUE), '@result' => print_r($result, TRUE)));
       break;
 
@@ -1412,6 +1427,26 @@ function mollom_validate_captcha(&$form,
 }
 
 /**
+ * Form validation handler to perform post-validation tasks.
+ *
+ * Since our individual form validation handlers are not re-run after positive
+ * validation, any changes applied to form values will not persist across
+ * multiple form submission attempts and rebuilds.
+ */
+function mollom_validate_post(&$form, &$form_state) {
+  // Unpublish a post instead of rejecting it. If 'reject' is not TRUE, then
+  // the 'reject callback' is responsible for altering $form_state in a way that
+  // the post ends up unpublished in a moderation queue. Most callbacks will
+  // only want to set a value in $form_state. Technically, modules do not need
+  // to implement a 'reject callback' to achieve this, they may simply add a
+  // custom form validation handler (or use an existing one).
+  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'
@@ -1896,6 +1931,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',
@@ -1938,6 +1974,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
@@ -1998,6 +2041,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'),
@@ -2075,6 +2119,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
@@ -2140,6 +2191,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',
@@ -2154,6 +2206,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',
@@ -2167,6 +2220,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".
  */
 
