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 12 Aug 2010 16:54:16 -0000 @@ -138,6 +138,28 @@ function mollom_admin_configure_form(&$f ), '#default_value' => $mollom_form['mode'], ); + // @todo Ideally, instead of a checkbox, we'd allow to define the + // "treshold level" (returned 'quality'?), until which posts identified + // as spam would be accepted (but unpublished), allowing site admins to + // configure an individually suitable treshold. But that would require + // to get a 'quality' also for CAPTCHAs. + // 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. + $form['mollom']['reject'] = array( + '#type' => 'checkbox', + '#title' => t('Unpublish spam posts instead of rejecting'), + '#default_value' => (int) !$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. Index: mollom.api.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/mollom/mollom.api.php,v retrieving revision 1.1.2.5 diff -u -p -r1.1.2.5 mollom.api.php --- mollom.api.php 5 Aug 2010 02:22:45 -0000 1.1.2.5 +++ mollom.api.php 12 Aug 2010 16:55:50 -0000 @@ -172,6 +172,8 @@ * // find the message id of the created, edited, or deleted message * // in $form_state['values']['im']['id']. * 'post_id' => 'im][id', + * // @todo + * 'post_status' => 'status', * // Required if the form or entity contains a title-alike field: * 'post_title' => 'im][subject', * // Optional: If our instant message form was accessible for @@ -723,6 +725,7 @@ function hook_mollom_form_list() { * The following mappings are possible: * - post_id: The form element value that denotes the ID of the content * stored in the database. + * - post_status: @todo * - post_title: The form element value that should be used as title. * - post_body: Mollom automatically assigns this property based on all * elements that have been selected for textual analysis in Mollom's 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 12 Aug 2010 16:06:11 -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 12 Aug 2010 17:41:30 -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' => 1, 'bypass access' => array(), 'elements' => array(), 'mapping' => array(), @@ -949,6 +950,10 @@ function mollom_form_get_values($form_va if (!empty($mapping['post_id'])) { $data['post_id'] = $mapping['post_id']; } + // Post status; not sent to Mollom. + if (!empty($mapping['post_status'])) { + $data['post_status'] = $mapping['post_status']; + } // Post title. if (!empty($mapping['post_title'])) { $data['post_title'] = $mapping['post_title']; @@ -1226,18 +1231,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 +1267,12 @@ function mollom_process_mollom($element, // $form_state['mollom'] will be carried over to the element for rendering. $element['#mollom'] = &$form_state['mollom']; + // Another trick to 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; } @@ -1322,10 +1330,8 @@ function mollom_validate_analysis(&$form // Perform textual analysis. $data = mollom_form_get_values($form_state['values'], $form_state['mollom']['enabled_fields'], $form_state['mollom']['mapping']); - // Remove 'post_id' property; only used by mollom_form_submit(). - if (isset($data['post_id'])) { - unset($data['post_id']); - } + // Remove non-XML-RPC properties. + unset($data['post_id'], $data['post_status']); if (!empty($form_state['mollom']['response']['session_id'])) { $data['session_id'] = $form_state['mollom']['response']['session_id']; } @@ -1343,9 +1349,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,16 +1356,25 @@ 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.')); + $reject = ($form_state['mollom']['reject'] == 1); + if ($reject) { + form_set_error('mollom', t('Your submission has triggered the spam filter and will not be accepted.')); + } + else { + } watchdog('mollom', 'Spam:
@message
Result:
@result
', 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.")); - watchdog('mollom', 'Unsure:
@message
Result:
@result
', array('@message' => print_r($data, TRUE), '@result' => print_r($result, TRUE))); + // Fall through to a CAPTCHA, when not rejecting a spam post. + if ($reject) { + break; + } + case MOLLOM_ANALYSIS_UNSURE: $form_state['mollom']['require_captcha'] = TRUE; + form_set_error('mollom][captcha', t("To complete this form, please complete the word verification below.")); + if ($result['spam'] = MOLLOM_ANALYSIS_UNSURE) { + watchdog('mollom', 'Unsure:
@message
Result:
@result
', array('@message' => print_r($data, TRUE), '@result' => print_r($result, TRUE))); + } break; } } @@ -1378,11 +1390,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 +1411,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 +1427,28 @@ function mollom_validate_captcha(&$form, } /** + * Form validation handler to perform post-validation tasks. + * + * Required, since we do not re-run text analysis after requiring a CAPTCHA. + * Therefore, when not rejecting a spam post and forcing an unpublished status, + * but showing a CAPTCHA afterwards, does no longer invoke the actions performed + * in mollom_validate_analysis() after checking the content. + */ +function mollom_validate_status(&$form, &$form_state) { + if (isset($form_state['mollom']['response']['spam']) && $form_state['mollom']['response']['spam'] == MOLLOM_ANALYSIS_SPAM && $form_state['mollom']['reject'] != 1) { + // When not rejecting, there must be a 'post_status' form value mapping. + $parents = explode('][', $form_state['mollom']['mapping']['post_status']); + $status = 0; + // Comment module is the only abnormal thing we make a hard-coded + // exception for, and really only just because it's insane. + if ($form_state['values']['form_id'] == 'comment_form') { + $status = COMMENT_NOT_PUBLISHED; + } + form_set_value(array('#parents' => $parents), $status, $form_state); + } +} + +/** * Form element #pre_render callback for CAPTCHA element. * * Conditionally alters the #type of the CAPTCHA form element into a 'hidden' @@ -1905,6 +1936,7 @@ function node_mollom_form_info($form_id) 'elements' => array(), 'mapping' => array( 'post_id' => 'nid', + 'post_status' => 'status', 'author_name' => 'name', ), ); @@ -2010,6 +2042,7 @@ function comment_mollom_form_info($form_ ), 'mapping' => array( 'post_id' => 'cid', + 'post_status' => 'status', 'post_title' => 'subject', // In D6, comment_form() dynamically uses different form elements for // anonymous users, authenticated users, and comment administrators. @@ -2149,6 +2182,7 @@ function user_mollom_form_info($form_id) 'entity' => 'user', 'mapping' => array( 'post_id' => 'uid', + 'post_status' => 'status', 'author_name' => 'name', 'author_mail' => 'mail', ), @@ -2163,6 +2197,7 @@ function user_mollom_form_info($form_id) 'entity' => 'user', 'mapping' => array( 'post_id' => 'uid', + 'post_status' => 'status', 'author_name' => 'name', // The 'name' form element accepts either a username or mail address. 'author_mail' => 'name',