View source
<?php
define('ANTISPAM_DRUPAL_VERSION', '7');
define('ANTISPAM_MODULE_VERSION', '1.0');
define('ANTISPAM_MODULE_HOMEURL', 'http://www.drupal.org/project/antispam');
define('ANTISPAM_MODULE_USERAGENT', 'Drupal/' . ANTISPAM_DRUPAL_VERSION . ' | antispam.module/' . ANTISPAM_MODULE_VERSION);
define('AKISMET_API_HOST', 'rest.akismet.com');
define('TYPEPAD_API_HOST', 'api.antispam.typepad.com');
define('DEFENSIO_API_HOST', 'api.defensio.com');
define('ANTISPAM_API_PORT', 80);
define('AKISMET_API_VERSION', '1.1');
define('DEFENSIO_API_VERSION', '1.2');
define('ANTISPAM_API_USERAGENT', 'Drupal/' . ANTISPAM_DRUPAL_VERSION . ' | antispam.module/' . ANTISPAM_MODULE_VERSION);
define('ANTISPAM_API_RESULT_ERROR', -1);
define('ANTISPAM_API_RESULT_SUCCESS', 0);
define('ANTISPAM_API_RESULT_IS_SPAM', 1);
define('ANTISPAM_API_RESULT_IS_HAM', 2);
define('AKISMET_SERVICE', 0);
define('TYPEPAD_SERVICE', 1);
define('DEFENSIO_SERVICE', 2);
define('ANTISPAM_COUNT_ALL', 0);
define('ANTISPAM_COUNT_SPAM_DETECTED', 1);
define('ANTISPAM_COUNT_HAM_DETECTED', 2);
define('ANTISPAM_COUNT_FALSE_NEGATIVE', 3);
define('ANTISPAM_COUNT_FALSE_POSITIVE', 4);
function antispam_help($path, $arg) {
switch ($path) {
case 'admin/help#antispam':
$output = t('<p>In order to use the AntiSpam, you need a API key for the selected antispam service. If you don\'t have one already, you can get it by simply signing up for a free account at the following sites.</p>
<ul>
<li><a href="!wordpress">wordpress.com</a> for <a href="!akismet">Akismet</a> service
<li><a href="!typepad">typepad.com</a> for TypePad AntiSpam service
<li><a href="!defensio">defensio.com</a> for Defensio service
</ul>
<p>The <em>antispam module</em> may automatically check for spam posted in content (nodes and/or comments) by any user, except node or comment administrators respectively. It is also possible, from the <a href="!permission">Permission</a> panel, to grant <em>%no-check-perm</em> permission to <em>user roles</em> of your choice.</p>
<p>Content marked as <em>spam</em> is still saved into database so it can be reviewed by content administrators. There is <a href="!antispam-settings">an option</a> that allows you to specify how long this information will be kept in the database. <em>Spam</em> older than a specified age will be automatically removed. Requires crontab.</p>
<p>Automatic spam detection can be enabled or disabled by content type and/or comments. In addition to this, the antispam service makes it easy for <em>content administrators</em> to manually <em>publish</em>/<em>unpublish</em> content and <em>mark</em>/<em>unmark</em> content as spam, from links available at the bottom of content.</p>
<p></p>', array(
'!wordpress' => url('http://wordpress.com'),
'!akismet' => url('http://akismet.com'),
'!typepad' => url('http://antispam.typepad.com'),
'!defensio' => url('http://defensio.com'),
'!antispam-settings' => url('admin/settings/antispam'),
'!permission' => url('admin/user/permissions'),
'%no-check-perm' => t('post with no antispam checking'),
));
return $output;
case 'admin/help/antispam':
case 'admin/settings/antispam':
$output = t('<p>The <a href="!antispam-module-home">AntiSpam module</a> for <a href="!drupal">Drupal</a> allows you to use either one of the <a href="!akismet">Akismet</a>, <a href="!typepad">TypePad AntiSpam</a> or <a href="!defensio">Defensio</a> service to protect your site from being spammed.</p>', array(
'!antispam-module-home' => url(ANTISPAM_MODULE_HOMEURL),
'!drupal' => url('http://drupal.org'),
'!akismet' => url('http://akismet.com'),
'!typepad' => url('http://antispam.typepad.com'),
'!defensio' => url('http://defensio.com'),
));
$output .= t('<p>AntiSpam has caught <strong>@count spam</strong> for you since %since.</p>', array(
'@count' => antispam_get_total_counter(ANTISPAM_COUNT_SPAM_DETECTED),
'%since' => antispam_get_counting_since(),
));
return $output;
case 'admin/content/antispam/nodes/unpublished':
$output = t('Below is the list of <strong>unpublished nodes</strong> awaiting for moderation.');
$output .= ' ' . t('Click on the titles to see the content of the nodes or the author\'s name to view the author\'s user information. You may also wish to click on the headers to order the nodes upon your needs.');
break;
case 'admin/content/antispam/nodes/published':
$output = t('Below is the list of <strong>published nodes</strong>.');
$output .= ' ' . t('Click on the titles to see the content of the nodes or the author\'s name to view the author\'s user information. You may also wish to click on the headers to order the nodes upon your needs.');
break;
case 'admin/content/antispam/nodes':
$output = t('Below is the list of <strong>nodes marked as spam</strong> awaiting for moderation.');
$output .= ' ' . t('Click on the titles to see the content of the nodes or the author\'s name to view the author\'s user information. You may also wish to click on the headers to order the nodes upon your needs.');
break;
case 'admin/content/antispam/comments/unpublished':
$output = t('Below is the list of <strong>unpublished comments</strong> awaiting for moderation.');
$output .= ' ' . t('Click on the subjects to see the comments or the author\'s name to view the author\'s user information. You may also wish to click on the headers to order the comments upon your needs.');
break;
case 'admin/content/antispam/comments/published':
$output = t('Below is the list of <strong>published comments</strong>.');
$output .= ' ' . t('Click on the subjects to see the comments or the author\'s name to view the author\'s user information. You may also wish to click on the headers to order the comments upon your needs.');
break;
case 'admin/content/antispam/comments':
$output = t('Below is the list of <strong>comments marked as spam</strong> awaiting for moderation.');
$output .= ' ' . t('Click on the subjects to see the comments or the author\'s name to view the author\'s user information. You may also wish to click on the headers to order the comments upon your needs.');
break;
}
if (arg(0) == 'admin' && arg(1) == 'content ' && arg(2) == 'antispam' && !isset($_POST) && !empty($output)) {
$output .= '<br />' . t('<strong>Note:</strong> To interact fully with the antispam service, you really should try putting data back into the system as well as just taking it out. If it is at all possible, please use the submit <em>ham</em> operation rather than simply publishing content that was identified as spam (false positives). This is necessary in order to let the antispam service learn from its mistakes. Thank you.');
}
}
function antispam_requirements($phase) {
$t = get_t();
$provider = antispam_get_service_provider();
if ($phase == 'runtime') {
if ($provider == AKISMET_SERVICE) {
if (variable_get('antispam_wpapikey', '') == '') {
$requirements['antispam_key'] = array(
'title' => t('Akismet API key'),
'value' => t('Not present'),
'description' => t("Akismet spam protection service requires a <a href='!wpapikey'>WordPress.com API key</a> to function. Obtain a key by signing up for a free account at <a href='!wordpress-com'>WordPress.com</a>, then enter the key on the <a href='!antispam-settings'>AntiSpam settings page</a>.", array(
'!wpapikey' => url('http://wordpress.com/api-keys/'),
'!wordpress-com' => url('http://wordpress.com'),
'!antispam-settings' => url('admin/settings/antispam'),
)),
'severity' => REQUIREMENT_ERROR,
);
return $requirements;
}
}
else {
if ($provider == TYPEPAD_SERVICE) {
if (variable_get('antispam_tpapikey', '') == '') {
$requirements['antispam_key'] = array(
'title' => t('TypePad AntiSpam API key'),
'value' => t('Not present'),
'description' => t("TypePad AntiSpam service requires a <a href='!tpapikey'>TypePad.com AntiSpam API key</a> to function. Obtain a key by signing up for a free account at <a href='!typepad-com'>Typepad.com</a>. Once you get a free account, visit the <a href='!tpapikey'>TypePad AntiSpam Service</a> and get your free TypePad AntiSpam API Key there, then enter the key on the <a href='!antispam-settings'>AntiSpam settings page</a>.", array(
'!tpapikey' => url('http://antispam.typepad.com/info/get-api-key.html'),
'!typepad-com' => url('http://typepad.com/connect/register'),
'!antispam-settings' => url('admin/settings/antispam'),
)),
'severity' => REQUIREMENT_ERROR,
);
return $requirements;
}
}
else {
if ($provider == DEFENSIO_SERVICE) {
if (variable_get('antispam_deapikey', '') == '') {
$requirements['antispam_key'] = array(
'title' => t('Defensio AntiSpam API key'),
'value' => t('Not present'),
'#description' => t("Defensio spam protection service requires a <a href='!defensio-com'>Defensio API key</a> to function. Obtain a key by signing up for a free account at <a href='!defensio-key'>Defensio.com</a> and get your free Defensio API key there, then enter the key on the <a href='!antispam-settings'>AntiSpam settings page</a>.", array(
'!defensio-com' => url('http://defensio.com/'),
'!defensio-key' => url('http://defensio.com/signup/'),
'!antispam-settings' => url('admin/settings/antispam'),
)),
'severity' => REQUIREMENT_ERROR,
);
return $requirements;
}
}
}
}
}
}
function antispam_perm() {
$perms = array(
'administer antispam settings',
);
foreach (node_get_types('names') as $type => $name) {
$perms[] = 'moderate spam in nodes of type ' . $name;
}
$perms[] = 'moderate spam in comments';
$perms[] = 'post with no antispam checking';
return $perms;
}
function antispam_cron() {
module_load_include('inc', 'antispam', 'antispam.cron');
module_load_include('inc', 'comment', 'comment.admin');
antispam_cron_shutdown();
}
function antispam_get_service_provider() {
return variable_get('antispam_service_provider', 0);
}
function antispam_get_provider_name($provider, $with_link = FALSE) {
switch ($provider) {
case AKISMET_SERVICE:
return $with_link ? t('<a href="http://akismet.com">Akismet</a>') : t('Akismet');
case TYPEPAD_SERVICE:
return $with_link ? t('<a href="http://antispam.typepad.com">TypePad AntiSpam</a>') : t('TypePad AntiSpam');
case DEFENSIO_SERVICE:
return $with_link ? t('<a href="http://defensio.com">Defensio</a>') : t('Defensio');
default:
return '';
}
}
function antispam_get_api_host($provider) {
switch ($provider) {
case AKISMET_SERVICE:
$api_host = AKISMET_API_HOST;
break;
case TYPEPAD_SERVICE:
$api_host = TYPEPAD_API_HOST;
break;
case DEFENSIO_SERVICE:
$api_host = DEFENSIO_API_HOST;
break;
}
return $api_host;
}
function antispam_get_api_key($provider) {
switch ($provider) {
case AKISMET_SERVICE:
$api_key = variable_get('antispam_wpapikey', '');
break;
case TYPEPAD_SERVICE:
$api_key = variable_get('antispam_tpapikey', '');
break;
case DEFENSIO_SERVICE:
$api_key = variable_get('antispam_deapikey', '');
break;
}
return $api_key;
}
function antispam_get_max_counter($counter_type = '') {
$rec = db_fetch_object(db_query("SELECT MAX(spam_detected) AS max_spam, MAX(ham_detected) AS max_ham, MAX(false_negative) AS max_fnegative, MAX(false_positive) AS max_fpositive FROM {antispam_counter}"));
if ($rec->max_spam == '') {
$rec->max_spam = 0;
}
if ($rec->max_ham == '') {
$rec->max_ham = 0;
}
if ($rec->max_fnegative == '') {
$rec->max_fnegative = 0;
}
if ($rec->max_fpositive == '') {
$rec->max_fpositive = 0;
}
if (empty($counter_type)) {
return array(
'max_spam' => $rec->max_spam,
'max_ham' => $rec->max_ham,
'max_fnegative' => $rec->max_fnegative,
'max_fpositive' => $rec->max_fpositive,
);
}
switch ($counter_type) {
case ANTISPAM_COUNT_ALL:
return $rec->max_spam + $rec->max_ham;
case ANTISPAM_COUNT_SPAM_DETECTED:
return $rec->max_spam;
case ANTISPAM_COUNT_HAM_DETECTED:
return $rec->max_ham;
case ANTISPAM_COUNT_FALSE_NEGATIVE:
return $rec->max_fnegative;
case ANTISPAM_COUNT_FALSE_POSITIVE:
return $rec->max_fpositive;
default:
return 0;
}
}
function antispam_get_total_counter($counter_type = '') {
$rec = db_fetch_object(db_query("SELECT SUM(spam_detected) AS total_spam, SUM(ham_detected) AS total_ham, SUM(false_negative) AS total_fnegative, SUM(false_positive) AS total_fpositive FROM {antispam_counter}"));
if ($rec->total_spam == '') {
$rec->total_spam = 0;
}
if ($rec->total_ham == '') {
$rec->total_ham = 0;
}
if ($rec->total_fnegative == '') {
$rec->total_fnegative = 0;
}
if ($rec->total_fpositive == '') {
$rec->total_fpositive = 0;
}
if (empty($counter_type)) {
return array(
'total_spam' => $rec->total_spam,
'total_ham' => $rec->total_ham,
'total_fnegative' => $rec->total_fnegative,
'total_fpositive' => $rec->total_fpositive,
);
}
switch ($counter_type) {
case ANTISPAM_COUNT_ALL:
return $rec->total_spam + $rec->total_ham;
case ANTISPAM_COUNT_SPAM_DETECTED:
return $rec->total_spam;
case ANTISPAM_COUNT_HAM_DETECTED:
return $rec->total_ham;
case ANTISPAM_COUNT_FALSE_NEGATIVE:
return $rec->total_fnegative;
case ANTISPAM_COUNT_FALSE_POSITIVE:
return $rec->total_fpositive;
default:
return 0;
}
}
function antispam_get_counter($counter_type) {
$rec = db_fetch_object(db_query("SELECT * FROM {antispam_counter} WHERE date = '%s'", date('Y-m-d 00:00:00')));
if (!$rec) {
return 0;
}
switch ($counter_type) {
case ANTISPAM_COUNT_ALL:
return $rec->spam_detected + $rec->ham_detected;
case ANTISPAM_COUNT_SPAM_DETECTED:
return $rec->spam_detected;
case ANTISPAM_COUNT_HAM_DETECTED:
return $rec->ham_detected;
case ANTISPAM_COUNT_FALSE_NEGATIVE:
return $rec->false_negative;
case ANTISPAM_COUNT_FALSE_POSITIVE:
return $rec->false_positive;
default:
return 0;
}
}
function antispam_set_counter($counter_type, $count) {
switch ($counter_type) {
case ANTISPAM_COUNT_ALL:
return;
case ANTISPAM_COUNT_SPAM_DETECTED:
$field = 'spam_detected';
break;
case ANTISPAM_COUNT_HAM_DETECTED:
$field = 'ham_detected';
break;
case ANTISPAM_COUNT_FALSE_NEGATIVE:
$field = 'false_negative';
break;
case ANTISPAM_COUNT_FALSE_POSITIVE:
$field = 'false_positive';
break;
default:
return;
}
db_query("UPDATE {antispam_counter} SET %s = %d WHERE date = '%s'", $field, $count, date('Y-m-d 00:00:00'));
if (!db_affected_rows()) {
$provider = antispam_get_service_provider();
db_query("INSERT INTO {antispam_counter} (date, provider, %s) VALUES ('%s', %d, %d)", $field, date('Y-m-d 00:00:00'), $provider, $count);
}
}
function antispam_increase_counter($counter_type) {
antispam_set_counter($counter_type, antispam_get_counter($counter_type) + 1);
}
function _antispam_moderator_types_count($types = array()) {
if (empty($types)) {
$types = antispam_get_moderator_types();
}
return count($types);
}
function _antispam_is_moderator($moderator_types = array(), $type = '') {
global $user;
if ($user->uid == 1) {
return TRUE;
}
if (empty($moderator_types)) {
$moderator_types = antispam_get_moderator_types();
}
if (_antispam_moderator_types_count($moderator_types) > 0 && (empty($type) || isset($moderator_types[$type]))) {
return TRUE;
}
else {
return FALSE;
}
}
function _antispam_is_node_moderator($moderator_types = array()) {
global $user;
if ($user->uid == 1) {
return TRUE;
}
if (empty($moderator_types)) {
$moderator_types = antispam_get_moderator_types();
}
if (_antispam_is_moderator($moderator_types) && (!_antispam_is_moderator($moderator_types, $type = 'comments') || _antispam_moderator_types_count($moderator_types) > 1)) {
return TRUE;
}
else {
return FALSE;
}
}
function _antispam_is_moderator_type($type, $types = array()) {
if (empty($types)) {
$types = antispam_get_moderator_types();
}
if (_antispam_moderator_types_count($types) > 0 && isset($types[$type])) {
return TRUE;
}
else {
return FALSE;
}
}
function antispam_menu() {
$items = array();
$items['admin/settings/antispam'] = array(
'title' => t('AntiSpam'),
'description' => t('Use the anti-spam service to protect your site from spam.'),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'antispam_settings',
),
'access arguments' => array(
'administer antispam settings',
),
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam'] = array(
'title' => t('AntiSpam moderation queue'),
'description' => t('Manage the AntiSpam spam queue, appropving or deleting content in need of moderation.'),
'page callback' => 'antispam_callback_queue',
'access callback' => '_antispam_is_moderator',
'access arguments' => array(
$moderator_types,
),
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/overview'] = array(
'title' => t('Overview'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => 0,
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/nodes'] = array(
'title' => t('Nodes'),
'page callback' => 'antispam_callback_queue',
'page arguments' => array(
'nodes',
),
'access callback' => '_antispam_is_node_moderator',
'access arguments' => array(
$moderator_types,
),
'type' => MENU_LOCAL_TASK,
'weight' => 1,
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/nodes/spam'] = array(
'title' => t('Spam'),
'page callback' => 'antispam_callback_queue',
'page arguments' => array(
'nodes',
),
'access callback' => '_antispam_is_node_moderator',
'access arguments' => array(
$moderator_types,
),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => 0,
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/nodes/unpublished'] = array(
'title' => t('Unpublished nodes'),
'page callback' => 'antispam_callback_queue',
'page arguments' => array(
'nodes',
'unpublished',
),
'access callback' => '_antispam_is_node_moderator',
'access arguments' => array(
$moderator_types,
),
'type' => MENU_LOCAL_TASK,
'weight' => 1,
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/nodes/published'] = array(
'title' => t('Published nodes'),
'page callback' => 'antispam_callback_queue',
'page arguments' => array(
'nodes',
'published',
),
'access callback' => '_antispam_is_node_moderator',
'access arguments' => array(
$moderator_types,
),
'type' => MENU_LOCAL_TASK,
'weight' => 2,
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/comments'] = array(
'title' => t('Comments'),
'page callback' => 'antispam_callback_queue',
'page arguments' => array(
'comments',
),
'access callback' => '_antispam_is_moderator',
'access arguments' => array(
$moderator_types,
'comments',
),
'type' => MENU_LOCAL_TASK,
'weight' => 2,
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/comments/spam'] = array(
'title' => t('Spam'),
'page callback' => 'antispam_callback_queue',
'page arguments' => array(
'comments',
),
'access callback' => '_antispam_is_moderator',
'access arguments' => array(
$moderator_types,
'comments',
),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => 0,
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/comments/unpublished'] = array(
'title' => t('Unpublished comments'),
'page callback' => 'antispam_callback_queue',
'page arguments' => array(
'comments',
'unpublished',
),
'access callback' => '_antispam_is_moderator',
'access arguments' => array(
$moderator_types,
'comments',
),
'type' => MENU_LOCAL_TASK,
'weight' => 1,
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/comments/published'] = array(
'title' => t('Published comments'),
'page callback' => 'antispam_callback_queue',
'page arguments' => array(
'comments',
'published',
),
'access callback' => '_antispam_is_moderator',
'access arguments' => array(
$moderator_types,
'comments',
),
'type' => MENU_LOCAL_TASK,
'weight' => 2,
'file' => 'antispam.admin.inc',
);
$items['admin/content/antispam/statistics'] = array(
'title' => t('Statistics'),
'page callback' => 'antispam_callback_queue',
'page arguments' => array(
'statistics',
),
'access callback' => '_antispam_is_moderator',
'access arguments' => array(
$moderator_types,
),
'type' => MENU_LOCAL_TASK,
'weight' => 3,
'file' => 'antispam.admin.inc',
);
$item = array(
'title' => 'switch content status',
'page callback' => 'antispam_page',
'page arguments' => array(
0,
1,
2,
3,
),
'load arguments' => array(
'%map',
'%index',
),
'access callback' => 'antispam_access_callback',
'access arguments' => array(
0,
1,
2,
3,
),
);
foreach (array(
'publish',
'unpublish',
'submit-spam',
'submit-ham',
) as $op) {
$items['antispam/%antispam/%/' . $op] = $item;
}
return $items;
}
function antispam_load($arg, &$map, $index) {
module_load_include('inc', 'comment', 'comment.admin');
if (!is_numeric($map[2])) {
return FALSE;
}
$content_type = $map[1];
if ($content_type == 'node') {
if (!($map[2] = node_load($map[2]))) {
return FALSE;
}
}
if ($content_type == 'comment' && module_exists('comment')) {
if (!($map[2] = _comment_load($map[2]))) {
return FALSE;
}
}
$op = $map[3];
if ($op == 'publish' || $op == 'unpublish') {
$map[0] = 'antispam_callback_set_published_status';
}
else {
if ($op == 'submit-spam' || $op == 'submit-ham') {
$map[0] = 'antispam_callback_set_spam_status';
}
}
return $map[$index];
}
function antispam_access_callback($callback, $content_type, $object, $op) {
if ($content_type == 'node' && !node_access('update', $object)) {
return FALSE;
}
if (function_exists($callback && !antispam_is_spam_moderator(antispam_content_get_moderator_type($content_type, $object)))) {
return FALSE;
}
return TRUE;
}
function antispam_page($callback, $content_type, $object, $op) {
if (function_exists($callback)) {
return $callback($content_type, $object, $op);
}
drupal_not_found();
}
function antispam_link($type, $content = 0, $main = 0) {
$links = array();
if ($type == 'node' && antispam_is_spam_moderator($content->type)) {
if (variable_get('antispam_node_publish_links', 0)) {
if ($content->status) {
$links['antispam_node_unpublish'] = array(
'title' => t('Unpublish'),
'href' => 'antispam/node/' . $content->nid . '/unpublish',
);
}
else {
$links['antispam_node_publish'] = array(
'title' => t('Publish'),
'href' => 'antispam/node/' . $content->nid . '/publish',
);
}
}
if (variable_get('antispam_node_spam_links', 0)) {
if (antispam_content_is_spam('node', $content->nid)) {
$links['antispam_node_ham'] = array(
'title' => variable_get('antispam_connection_enabled', 1) ? t('Submit ham') : t('Mark as ham'),
'href' => 'antispam/node/' . $content->nid . '/submit-ham',
);
}
else {
$links['antispam_node_spam'] = array(
'title' => variable_get('antispam_connection_enabled', 1) ? t('Submit spam') : t('Mark as spam'),
'href' => 'antispam/node/' . $content->nid . '/submit-spam',
);
}
}
}
else {
if ($type == 'comment' && antispam_is_spam_moderator('comments')) {
if (variable_get('antispam_comment_publish_links', 1)) {
if ($content->status == COMMENT_PUBLISHED) {
$links['antispam_comment_unpublish'] = array(
'title' => t('Unpublish'),
'href' => 'antispam/comment/' . $content->cid . '/unpublish',
);
}
else {
if ($content->status == COMMENT_NOT_PUBLISHED) {
$links['antispam_comment_publish'] = array(
'title' => t('Publish'),
'href' => 'antispam/comment/' . $content->cid . '/publish',
);
}
}
}
if (variable_get('antispam_comment_spam_links', 1)) {
if (antispam_content_is_spam('comment', $content->cid)) {
$links['antispam_comment_ham'] = array(
'title' => variable_get('antispam_connection_enabled', 1) ? t('Submit ham') : t('Mark as ham'),
'href' => 'antispam/comment/' . $content->cid . '/submit-ham',
);
}
else {
$links['antispam_comment_spam'] = array(
'title' => variable_get('antispam_connection_enabled', 1) ? t('Submit spam') : t('Mark as spam'),
'href' => 'antispam/comment/' . $content->cid . '/submit-spam',
);
}
}
}
}
return $links;
}
function antispam_callback_set_published_status($content_type, $object, $op) {
if ($content_type == 'node') {
$content = antispam_content_load($content_type, $object->nid);
$is_published = $content->status ? TRUE : FALSE;
}
else {
$content = antispam_content_load($content_type, $object->cid);
$is_published = $content->status == COMMENT_PUBLISHED ? TRUE : FALSE;
}
if ($op == 'publish' && !$is_published) {
antispam_content_publish_operation($content_type, $content, 'publish');
}
else {
if ($op == 'unpublish' && $is_published) {
antispam_content_publish_operation($content_type, $content, 'unpublish');
}
}
if ($content_type == 'node') {
drupal_goto('node/' . $content->nid);
}
else {
drupal_goto('node/' . $content->nid, NULL, 'comment-' . $content->cid);
}
}
function antispam_callback_set_spam_status($content_type, $object, $op) {
if ($content_type == 'node') {
$is_spam = antispam_content_is_spam($content_type, $object->nid);
$content = antispam_content_load($content_type, $object->nid);
$is_published = $content->status ? TRUE : FALSE;
}
else {
$is_spam = antispam_content_is_spam($content_type, $object->cid);
$content = antispam_content_load($content_type, $object->cid);
$is_published = $content->status == COMMENT_PUBLISHED ? TRUE : FALSE;
}
if ($op == 'submit-spam') {
if (!$is_spam) {
antispam_content_spam_operation($content_type, $content, 'submit-spam');
antispam_increase_counter(ANTISPAM_COUNT_FALSE_NEGATIVE);
}
if ($is_published) {
antispam_content_publish_operation($content_type, $content, 'unpublish');
}
}
else {
if ($op == 'submit-ham') {
if ($is_spam) {
antispam_content_spam_operation($content_type, $content, 'submit-ham');
antispam_increase_counter(ANTISPAM_COUNT_FALSE_POSITIVE);
}
if (!$is_published) {
antispam_content_publish_operation($content_type, $content, 'publish');
}
}
}
if ($content_type == 'node') {
drupal_goto('node/' . $content->nid);
}
else {
drupal_goto('node/' . $content->nid, NULL, 'comment-' . $content->cid);
}
}
function antispam_nodeapi(&$node, $op, $teaser, $page) {
switch ($op) {
case 'insert':
case 'update':
if (!variable_get('antispam_connection_enabled', 1)) {
antispam_notify_moderators('node', $node, $node->status ? TRUE : FALSE, FALSE);
break;
}
if (antispam_is_spam_moderator($node->type) || user_access('post with no antispam checking')) {
antispam_notify_moderators('node', $node, $node->status ? TRUE : FALSE, FALSE);
break;
}
$check_nodetypes = variable_get('antispam_check_nodetypes', array());
if (!is_array($check_nodetypes) || !isset($check_nodetypes[$node->type]) || !$check_nodetypes[$node->type]) {
antispam_notify_moderators('node', $node, $node->status ? TRUE : FALSE, FALSE);
break;
}
$api_result = antispam_api_cmd_comment_check('node', $node);
if ($api_result[0] == ANTISPAM_API_RESULT_IS_HAM) {
antispam_notify_moderators('node', $node, $node->status ? TRUE : FALSE, FALSE);
antispam_increase_counter(ANTISPAM_COUNT_HAM_DETECTED);
}
else {
if ($api_result[0] == ANTISPAM_API_RESULT_IS_SPAM) {
$node->signature = $api_result[1];
$node->spaminess = $api_result[2];
antispam_content_spam_operation('node', $node, 'submit-spam', FALSE);
antispam_increase_counter(ANTISPAM_COUNT_SPAM_DETECTED);
antispam_notify_moderators('node', $node, FALSE, TRUE);
}
else {
antispam_notify_moderators('node', $node, FALSE, FALSE);
}
if ($node->status) {
antispam_content_publish_operation('node', $node, 'unpublish', FALSE);
}
$content_type_name = node_get_types('name', $node);
drupal_set_message(t('Your %content-type-name has been queued for moderation by site administrators and will be published after approval.', array(
'%content-type-name' => $content_type_name,
)));
if ($api_result[0] == ANTISPAM_API_RESULT_ERROR) {
watchdog('content', 'AntiSpam service seems to be down, %content-type-name queued for manual approval: %title', array(
'%content-type-name' => $content_type_name,
'%title' => $node->title,
), WATCHDOG_WARNING, l(t('view'), 'node/' . $node->nid));
}
else {
watchdog('content', 'Spam detected by AntiSpam in %content-type-name: %title', array(
'%content-type-name' => $content_type_name,
'%title' => $node->title,
), WATCHDOG_WARNING, l(t('view'), 'node/' . $node->nid));
if (($seconds = variable_get('antispam_antispambot_delay', 60)) > 0) {
sleep($seconds);
}
}
}
break;
case 'delete':
db_query('DELETE FROM {antispam_spam_marks} WHERE content_type = \'node\' AND content_id = %d', $node->nid);
break;
case 'load':
$rec = db_fetch_object(db_query('SELECT signature, spaminess FROM {antispam_spam_marks} WHERE content_type = \'node\' AND content_id = %d', $node->nid));
if ($rec) {
return $rec;
}
else {
return array(
'signature' => '',
'spaminess' => 1,
);
}
break;
}
}
function antispam_comment(&$comment, $op) {
switch ($op) {
case 'insert':
case 'update':
if (!variable_get('antispam_check_comments', 0) || antispam_is_spam_moderator('comments') || !variable_get('antispam_connection_enabled', 1)) {
antispam_notify_moderators('comment', $comment, $comment->status == COMMENT_PUBLISHED ? TRUE : FALSE, FALSE);
}
break;
case 'delete':
db_query('DELETE FROM {antispam_spam_marks} WHERE content_type = \'comment\' AND content_id = %d', $comment->cid);
break;
case 'view':
$rec = db_fetch_object(db_query('SELECT signature, spaminess FROM {antispam_spam_marks} WHERE content_type = \'comment\' AND content_id = %d', $comment->cid));
if ($rec) {
return $rec;
}
else {
return array(
'signature' => '',
'spaminess' => 1,
);
}
break;
}
}
function antispam_form_alter(&$form, $form_state, $form_id) {
if ($form_id == 'comment_form' && variable_get('antispam_check_comments', 1)) {
if (!antispam_is_spam_moderator('comments')) {
if (variable_get('antispam_connection_enabled', 1)) {
$form['#submit'][] = '_antispam_comment_form_submit';
}
if (antispam_is_anti_spambot_enabled()) {
$form['#validate'][] = '_antispam_comment_form_validate';
}
}
}
else {
if (isset($form['type']) && $form['type']['#value'] . '_node_form' == $form_id) {
if (!antispam_is_spam_moderator('comments')) {
$check_nodetypes = variable_get('antispam_check_nodetypes', array());
$node_type = $form['type']['#value'];
if (is_array($check_nodetypes) && isset($check_nodetypes[$node_type]) && $check_nodetypes[$node_type]) {
if (antispam_is_anti_spambot_enabled()) {
$form['#validate'][] = '_antispam_node_form_validate';
}
}
}
}
}
}
function _antispam_node_form_validate($form, &$form_state) {
if (form_get_errors()) {
return;
}
global $user;
$antispambot_rules = antispam_get_anti_spambot_rules();
$sql_where = array();
$sql_args = array();
if ($antispambot_rules['ip']) {
$sql_where[] = 's.hostname = \'%s\'';
$sql_args[] = ip_address();
}
if ($antispambot_rules['body'] && !empty($form_state['values']['body'])) {
$sql_where[] = 'r.body = \'%s\'';
$sql_args[] = $form_state['values']['body'];
}
if ($antispambot_rules['mail'] && !empty($user->mail)) {
$sql_where[] = 's.mail = \'%s\'';
$sql_args[] = $user->mail;
}
if (count($sql_where) > 0) {
if ($antispambot_rules['body'] || $antispambot_rules['mail']) {
$sql_stmt = 'SELECT 1 FROM {node} n INNER JOIN {node_revisions} r ON r.nid = n.nid INNER JOIN {antispam_spam_marks} s ON s.content_type = \'node\' AND s.content_id = n.nid WHERE (%cond)';
}
else {
$sql_stmt = 'SELECT 1 FROM {antispam_spam_marks} s WHERE s.content_type = \'node\' AND (%cond)';
}
$sql_stmt = str_replace('%cond', implode(' OR ', $sql_where), $sql_stmt);
if (db_result(db_query($sql_stmt, $sql_args, 0, 1))) {
antispam_anti_spambot_action(array(
t('SQL') => _antispam_translate_query($sql_stmt, $sql_args),
t('E-mail') => isset($user->mail) ? $user->mail : '',
t('Body') => $form_state['values']['body'],
));
}
}
}
function _antispam_comment_form_validate($form, &$form_state) {
if (form_get_errors()) {
return;
}
$antispambot_rules = antispam_get_anti_spambot_rules();
$sql_where = array();
$sql_args = array();
if ($antispambot_rules['ip']) {
$sql_where[] = 's.hostname = \'%s\'';
$sql_args[] = ip_address();
}
if ($antispambot_rules['body'] && !empty($form_state['values']['comment'])) {
$sql_where[] = 'c.comment = \'%s\'';
$sql_args[] = $form_state['values']['comment'];
}
if ($antispambot_rules['mail'] && !empty($form_state['values']['mail'])) {
$sql_where[] = 's.mail = \'%s\'';
$sql_args[] = ${$form_state}['values']['mail'];
}
if (count($sql_where) > 0) {
if ($antispambot_rules['body'] || $antispambot_rules['mail']) {
$sql_stmt = 'SELECT 1 FROM {comments} c INNER JOIN {antispam_spam_marks} s ON s.content_type = \'comment\' AND s.content_id = c.cid WHERE (%cond)';
}
else {
$sql_stmt = 'SELECT 1 FROM {antispam_spam_marks} s WHERE s.content_type = \'comment\' AND (%cond)';
}
$sql_stmt = str_replace('%cond', implode(' OR ', $sql_where), $sql_stmt);
if (db_result(db_query($sql_stmt, $sql_args, 0, 1))) {
antispam_anti_spambot_action(array(
t('SQL') => _antispam_translate_query($sql_stmt, $sql_args),
t('E-mail') => $form_state['values']['mail'],
t('Comment') => $form_state['values']['comment'],
));
}
}
}
function _antispam_comment_form_submit($form, &$form_state, $original_submit_callback = NULL) {
$goto = NULL;
if (isset($form_state['values']['cid'])) {
$cid = $form_state['values']['cid'];
}
else {
$goto = $form_state['redirect'];
if (is_array($goto) && isset($goto[2]) && preg_match('#^comment-([0-9]+)$#', $goto[2], $match)) {
$cid = $match[1];
$goto[2] = NULL;
}
}
if (antispam_is_spam_moderator('comments') || user_access('post with no antispam checking')) {
antispam_notify_moderators('comment', $comment, $comment->status == COMMENT_PUBLISHED ? TRUE : FALSE, FALSE);
return $goto;
}
if ($cid) {
$comment = antispam_content_load('comment', $cid);
if ($comment) {
$api_result = antispam_api_cmd_comment_check('comment', $comment);
if ($api_result[0] == ANTISPAM_API_RESULT_IS_HAM) {
antispam_notify_moderators('comment', $comment, $comment->status == COMMENT_PUBLISHED ? TRUE : FALSE, FALSE);
antispam_increase_counter(ANTISPAM_COUNT_HAM_DETECTED);
}
else {
if ($api_result[0] == ANTISPAM_API_RESULT_IS_SPAM) {
$comment->signature = $api_result[1];
$comment->spaminess = $api_result[2];
antispam_content_spam_operation('comment', $comment, 'submit-spam', FALSE);
antispam_increase_counter(ANTISPAM_COUNT_SPAM_DETECTED);
antispam_notify_moderators('comment', $comment, FALSE, TRUE);
}
else {
antispam_notify_moderators('comment', $comment, FALSE, FALSE);
}
if ($comment->status == COMMENT_PUBLISHED) {
antispam_content_publish_operation('comment', $comment, 'unpublish', FALSE);
}
drupal_set_message(t('Your comment has been queued for moderation by site administrators and will be published after approval.'));
$form_state['redirect'] = $goto;
if ($api_result[0] == ANTISPAM_API_RESULT_ERROR) {
watchdog('content', 'AntiSpam service seems to be down, comment queued for manual approval: %subject', array(
'%subject' => $comment->subject,
), WATCHDOG_WARNING, l(t('view'), 'node/' . $comment->nid, array(
'fragment' => 'comment-' . $comment->cid,
)));
}
else {
watchdog('content', 'Spam detected by AntiSpam in comment: %subject', array(
'%subject' => $comment->subject,
), WATCHDOG_WARNING, l(t('view'), 'node/' . $comment->nid, array(
'fragment' => 'comment-' . $comment->cid,
)));
if (($seconds = variable_get('antispam_antispambot_delay', 60)) > 0) {
sleep($seconds);
}
}
}
}
}
return $goto;
}
function antispam_get_anti_spambot_rules() {
static $antispambot_rules = FALSE;
if (!$antispambot_rules) {
$antispambot_rules = array();
$options = variable_get('antispam_antispambot_rules', array());
if (is_array($options)) {
foreach ($options as $key => $value) {
if (is_string($key)) {
$antispambot_rules[$key] = $key === $value ? TRUE : FALSE;
}
}
}
}
return $antispambot_rules;
}
function antispam_is_anti_spambot_enabled() {
$antispambot_rules = antispam_get_anti_spambot_rules();
return count($antispambot_rules) > 0 ? TRUE : FALSE;
}
function antispam_anti_spambot_action($debug_info) {
$antispambot_action = variable_get('antispam_antispambot_action', '503');
if (($seconds = variable_get('antispam_antispambot_delay', 60)) > 0) {
sleep($seconds);
}
if ($antispambot_action == 'none') {
return;
}
$items = array();
foreach ($debug_info as $label => $value) {
$items[] = '<strong>' . check_plain($label) . '</strong>: ' . check_plain($value);
}
if ($antispambot_action == '403d') {
drupal_access_denied();
$message = t('Spambot detected (action: 403 Forbidden).');
}
else {
if ($antispambot_action == '403') {
@header('HTTP/1.0 403 Forbidden');
print t('Access denied');
$message = t('Spambot detected (action: 403 Forbidden).');
}
else {
@header('HTTP/1.0 503 Service unavailable');
print t('Service unavailable');
$message = t('Spambot detected (action: 503 Service unavailable).');
}
}
watchdog('antispam', '%message<p>Additional information:</p>%items', array(
'%message' => $message,
'%items' => theme('item_list', $items),
));
module_invoke_all('exit');
exit;
}
function _antispam_translate_query($query) {
$args = func_get_args();
array_shift($args);
$query = db_prefix_tables($query);
if (isset($args[0]) && is_array($args[0])) {
$args = $args[0];
}
_db_query_callback($args, TRUE);
$query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query);
return $query;
}
function antispam_content_is_spam($content_type, $content_id) {
return db_result(db_query('SELECT 1 FROM {antispam_spam_marks} WHERE content_type = \'%s\' AND content_id = %d', $content_type, $content_id));
}
function antispam_content_get_moderator_type($content_type, $content_id) {
if ($content_type == 'node') {
$moderator_type = db_result(db_query('SELECT type FROM {node} WHERE nid = %d', $content_id));
if (!$moderator_type) {
$moderator_type = '';
}
}
else {
if ($content_type == 'comment') {
$moderator_type = db_result(db_query('SELECT 1 FROM {comments} WHERE cid = %d', $content_id)) ? 'comments' : '';
}
else {
$moderator_type = '';
}
}
return $moderator_type;
}
function antispam_get_moderator_types($account = NULL) {
global $user;
static $node_types = FALSE;
static $moderator_types = array();
if (is_null($account)) {
$account = $user;
}
if ($node_types === FALSE) {
$node_types = node_get_types('names');
}
if (!isset($moderator_types[$account->uid])) {
if (user_access('administer nodes', $account)) {
foreach ($node_types as $type => $name) {
$moderator_types[$account->uid][$type] = $name;
}
}
else {
foreach ($node_types as $type => $name) {
if (user_access('moderate spam in nodes of type ' . $node_types[$type], $account)) {
$moderator_types[$account->uid][$type] = $name;
}
}
}
if (user_access('administer comments', $account) || user_access('moderate spam in comments', $account)) {
$moderator_types[$account->uid]['comments'] = t('comments');
}
}
return $moderator_types[$account->uid];
}
function antispam_is_spam_moderator($moderator_type = NULL, $account = NULL) {
global $user;
if (is_null($account)) {
$account = $user;
}
$moderator_types = antispam_get_moderator_types($account);
if (is_null($moderator_type)) {
return count($moderator_types) > 0 ? TRUE : FALSE;
}
return isset($moderator_types[$moderator_type]);
}
function antispam_notify_moderators($content_type, $content, $is_published, $is_spam) {
global $user, $base_url;
if (!variable_get('antispam_email_enabled', 0)) {
return;
}
$content = (object) $content;
if ($content_type == 'comment') {
$moderator_permission = 'moderate spam in comments';
$administer_permission = 'administer comments';
}
else {
$moderator_types = antispam_get_moderator_types($account);
$moderator_permission = 'moderate spam in nodes of type ' . $moderator_types[$content->type];
$administer_permission = 'administer nodes';
}
$sql = 'SELECT u.uid, u.name, u.mail, m.email_for' . ' FROM {permission} p' . ' INNER JOIN {users_roles} r ON r.rid = p.rid' . ' INNER JOIN {users} u ON u.uid = r.uid OR u.uid = 1' . ' LEFT JOIN {antispam_moderator} m ON m.uid = u.uid' . ' WHERE p.perm LIKE \'%%%s%%\'' . ' OR p.perm LIKE \'%%%s%%\'';
$result = db_query($sql, $moderator_permission, $administer_permission);
$moderators = array();
while ($u = db_fetch_object($result)) {
if ($u->uid != $user->uid) {
$moderators[$u->uid] = array(
'name' => $u->name,
'email_to' => $u->mail,
'email_for' => !is_null($u->email_for) ? $u->email_for : 'approval',
);
}
}
$sql = 'SELECT u.uid, u.name, u.mail, m.email_for' . ' FROM {users} u' . ' LEFT JOIN {antispam_moderator} m ON m.uid = u.uid' . ' WHERE u.uid = 1';
$result = db_query($sql, $moderator_permission, $administer_permission);
if ($u = db_fetch_object($result)) {
if ($u->uid != $user->uid) {
$moderators[$u->uid] = array(
'name' => $u->name,
'email_to' => $u->mail,
'email_for' => !is_null($u->email_for) ? $u->email_for : 'approval',
);
}
}
$unique_emails = array();
foreach ($moderators as $uid => $moderator) {
if ($moderator['email_for'] == 'all' || $moderator['email_for'] == 'approval' && !$is_published) {
if (!isset($unique_emails[$moderator['email_to']])) {
$unique_emails[$moderator['email_to']] = $uid;
}
}
}
if (count($unique_emails) <= 0) {
return;
}
$site_name = variable_get('site_name', t('Drupal'));
if ($content_type == 'comment') {
if (!($node = antispam_content_load('node', $content->nid))) {
watchdog('antispam', 'An error has ocurred while trying to notify moderators about a comment. The associated node could not be loaded.', array(), WATCHDOG_NOTICE, l(t('view'), 'node/' . $content->nid, array(
'fragment' => 'comment-' . $content->cid,
)));
return;
}
$message_args = array(
'@title-label' => t('Subject'),
'@content-title' => $content->subject,
'@content-type' => t('comment'),
'!content-link' => url('node/' . $content->nid, array(
'fragment' => 'comment-' . $content->cid,
'absolute' => TRUE,
)),
);
}
else {
$message_args = array(
'@title-label' => t('Title'),
'@content-title' => $content->title,
'@content-type' => $moderator_types[$content->type],
'!content-link' => url('node/' . $content->nid, array(
'absolute' => TRUE,
)),
);
}
$message_args['@content-status'] = ($is_published ? t('published') : t('not published')) . ($is_spam ? ' (' . t('marked as spam') . ')' : '');
$message_args['@site-name'] = $site_name;
$message_args['!site-link'] = $base_url . base_path();
$message_args['@type'] = $moderator_types[$content->type];
$message_title = t('[@site-name] moderator notification - Posted @content-type \'@content-title\'', $message_args);
$message_body = t(<<<EOT
Hello @user-name,
You can use the following information to review this @content-type:
@title-label: @content-title
URL: !content-link
Status: @content-status
Please, do not reply to this e-mail. It is an automated notification you are receiving because you are a moderator at @site-name. If you no longer wish to receive such notifications, you can change your moderator settings in your user profile.
Thank you
!site-link
EOT
, $message_args);
watchdog('antispam', 'Trying to notify the following recipients: %emails', array(
'%emails' => implode(', ', array_keys($unique_emails)),
));
foreach ($unique_emails as $email_to => $uid) {
$message = array(
'id' => 'antispam_moderator_notification',
'to' => $email_to,
'subject' => $message_title,
'body' => str_replace('@user-name', check_plain($moderators[$uid]['name']), $message_body),
'headers' => array(),
);
$ret = drupal_mail_send($message);
if ($ret == FALSE) {
watchdog('antispam', 'Failed to send a moderator notification email to: %emails', array(
'%emails' => implode(', ', array_keys($unique_emails)),
));
}
}
}
function antispam_user($op, &$edit, &$account, $category = NULL) {
$moderator_email_for_options = array(
'all' => t('All new (or updated) content'),
'approval' => t('Only content needing approval'),
'never' => t('Never'),
);
switch ($op) {
case 'form':
if ($category == 'account' && variable_get('antispam_email_enabled', 1)) {
$moderator_types = antispam_get_moderator_types($account);
$moderator_types_count = count($moderator_types);
if ($moderator_types_count > 0) {
$form = array();
$form['antispam_moderator'] = array(
'#type' => 'fieldset',
'#title' => t('AntiSpam moderator settings'),
'#weight' => 5,
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#description' => t('You are currently moderator for the following content types: %types.', array(
'%types' => implode(', ', $moderator_types),
)),
);
$form['antispam_moderator']['antispam_moderator_email_for'] = array(
'#type' => 'radios',
'#title' => t('Send me e-mails for'),
'#options' => $moderator_email_for_options,
'#default_value' => isset($moderator_email_for_options[$edit['antispam_moderator_email_for']]) ? $edit['antispam_moderator_email_for'] : 'approval',
);
return $form;
}
}
break;
case 'load':
$moderator_types = antispam_get_moderator_types($account);
$moderator_types_count = count($moderator_types);
if ($moderator_types_count > 0) {
$moderator_data = db_fetch_object(db_query('SELECT * FROM {antispam_moderator} WHERE uid = %d', $account->uid));
$account->antispam_moderator_email_for = isset($moderator_data->email_for) && isset($moderator_email_for_options[$moderator_data->email_for]) ? $moderator_data->email_for : 'approval';
}
break;
case 'insert':
case 'update':
$moderator_types = antispam_get_moderator_types($account);
$moderator_types_count = count($moderator_types);
if ($moderator_types_count > 0 && isset($edit['antispam_moderator_email_for'])) {
if (!isset($moderator_email_for_options[$edit['antispam_moderator_email_for']])) {
$edit['antispam_moderator_email_for'] = 'approval';
}
db_query('UPDATE {antispam_moderator} SET email_for = \'%s\' WHERE uid = %d', $edit['antispam_moderator_email_for'], $account->uid);
if (!db_affected_rows()) {
db_query('INSERT INTO {antispam_moderator} (uid, email_for) VALUES (%d, \'%s\')', $account->uid, $edit['antispam_moderator_email_for']);
}
$edit['antispam_moderator_email_for'] = NULL;
break;
}
case 'delete':
db_query('DELETE FROM {antispam_moderator} WHERE uid = %d', $account->uid);
break;
}
}
function antispam_get_counting_since() {
$since = variable_get('antispam_counter_since', array(
'day' => date('j'),
'month' => date('n'),
'year' => date('Y'),
));
$format = variable_get('antispam_counter_date_format', 'F j, Y');
$replace = array(
'd' => sprintf('%02d', $since['day']),
'j' => $since['day'],
'm' => sprintf('%02d', $since['month']),
'M' => format_date(gmmktime(0, 0, 0, $since['month'], 2, 1970), 'custom', 'M', 0),
'F' => format_date(gmmktime(0, 0, 0, $since['month'], 2, 1970), 'custom', 'F', 0),
'Y' => $since['year'],
);
return strtr($format, $replace);
}
function antispam_block($op = 'list', $delta = 0, $edit = array()) {
static $block_fields = FALSE;
if (!$block_fields) {
$block_fields = array(
'type' => array(
'#type' => 'radios',
'#title' => t('Display counter as'),
'#options' => array(
'image' => t('Image'),
'text' => t('Text'),
),
'#default_value' => 'image',
),
'sitename' => array(
'#type' => 'radios',
'#title' => t('Show site name'),
'#options' => array(
'1' => t('Enabled'),
'0' => t('Disabled'),
),
'#default_value' => '1',
),
'newwin' => array(
'#type' => 'radios',
'#title' => t('Open AntiSpam link in new window'),
'#options' => array(
'1' => t('Enabled'),
'0' => t('Disabled'),
),
'#default_value' => '1',
),
);
}
switch ($op) {
case 'list':
$blocks_counter = variable_get('antispam_blocks_counter', 1);
$blocks = array();
for ($i = 0; $i < $blocks_counter; $i++) {
$blocks[] = array(
'info' => t('AntiSpam spam counter (block: @count)', array(
'@count' => $i + 1,
)),
);
}
return $blocks;
case 'configure':
if ($delta < 0 || $delta >= variable_get('antispam_blocks_counter', 1)) {
drupal_set_message(t('Oops! You are requesting a non-existing block, changes will not be saved.'), 'error');
break;
}
$form = array();
$form['description'] = array(
'#type' => 'markup',
'#value' => '<div class="description"><p>' . t('These options allow to customize the look of this <em>antispam spam counter</em> block.') . '</p></div>',
);
$block_settings = variable_get('antispam_blocks_' . $delta, FALSE);
foreach ($block_fields as $field_key => $field_info) {
$field_name = 'antispam_blocks_' . $delta . '_' . $field_key;
$form[$field_name] = array();
foreach ($field_info as $key => $value) {
$form[$field_name][$key] = $value;
}
if ($block_settings && isset($block_settings[$field_key])) {
$form[$field_name]['#default_value'] = $block_settings[$field_key];
}
}
return $form;
case 'save':
if ($delta < 0 || $delta >= variable_get('antispam_blocks_counter', 1)) {
drupal_set_message(t('Oops! You have requested a non-existing block, changes were not saved.'), 'error');
break;
}
$block_settings = array();
foreach ($block_fields as $field_key => $field_info) {
$field_name = 'antispam_blocks_' . $delta . '_' . $field_key;
$block_settings[$field_key] = $edit[$field_name];
}
variable_set('antispam_blocks_' . $delta, $block_settings);
break;
case 'view':
if ($delta >= 0 && $delta < variable_get('antispam_blocks_counter', 1)) {
$block_settings = variable_get('antispam_blocks_' . $delta, FALSE);
if (!$block_settings) {
$block_settings = array();
}
$block_args = array(
'content' => '',
'counter' => antispam_get_total_counter(ANTISPAM_COUNT_SPAM_DETECTED),
'since' => antispam_get_counting_since(),
'text' => '',
'image' => '',
'block' => array(
'delta' => $delta,
),
);
foreach ($block_fields as $field_key => $field_info) {
if (!isset($block_settings[$field_key])) {
$block_settings[$field_key] = $field_info['#default_value'];
}
$block_args['block'][$field_key] = $block_settings[$field_key];
}
$target = $block_settings['newwin'] ? ' target="_blank"' : '';
$sitename = $block_settings['sitename'] ? variable_get('site_name', 'drupal') : t('This site');
$block_args['text'] = array(
'plain' => t('@site_name is proudly protected by AntiSpam, !spams caught since @since.', array(
'@site_name' => $sitename,
'!spams' => format_plural($block_args['counter'], '1 spam', '@count spams'),
'@since' => $block_args['since'],
)),
'html' => t('@site_name is proudly protected by <a href="!antispam"@target>AntiSpam</a>, %spams caught since @since', array(
'@site_name' => $sitename,
'!antispam' => url('http://drupal.org/project/antispam'),
'@target' => $target,
'%spams' => format_plural($block_args['counter'], '1 spam', '@count spams'),
'@since' => $block_args['since'],
)),
);
$title_text = $block_args['text']['plain'];
$image_url = base_path() . drupal_get_path('module', 'antispam') . '/antispam.png';
$block_args['image'] = '<img src="' . $image_url . '" title="' . $title_text . '" alt="' . $title_text . '" />';
if ($block_settings['type'] == 'image') {
$block_args['content'] = '<a href="http://drupal.org/project/antispam" title="' . $title_text . '"' . $target . '>' . $block_args['image'] . '</a>';
}
else {
$block_args['content'] = $block_args['text']['html'];
}
$block = array();
$block['subject'] = t('AntiSpam spam counter');
$block['content'] = theme('antispam_counter_block', $block_args);
return $block;
}
break;
}
}
function antispam_theme() {
return array(
'antispam_counter_block' => array(
'arguments' => array(
'args' => array(
'content',
'counter',
'since',
'text' => array(
'plain' => array(
'short',
'long',
),
'html' => array(
'short',
'long',
),
),
'image',
'block',
),
),
),
'antispam_moderation_form' => array(
'arguments' => array(
'form' => NULL,
),
'file' => 'antispam.admin.inc',
),
);
}
function theme_antispam_counter_block($args) {
return $args['content'];
}
function antispam_content_load($content_type, $content_id) {
if ($content_type == 'node') {
$content = node_load($content_id);
if (empty($content->nid)) {
$content = FALSE;
}
}
else {
if ($content_type == 'comment') {
$content = db_fetch_object(db_query(db_rewrite_sql('SELECT c.*, u.name AS registered_name FROM {comments} c INNER JOIN {users} u ON u.uid = c.uid WHERE c.cid = %d', 'c'), $content_id));
if (empty($content->cid)) {
$content = FALSE;
}
else {
$rec = db_fetch_object(db_query('SELECT signature, spaminess FROM {antispam_spam_marks} WHERE content_type = \'comment\' AND content_id = %d', $content->cid));
if ($rec) {
$content->signature = $rec->signature;
$content->spaminess = $rec->spaminess;
}
else {
$content->signature = '';
$content->spaminess = '';
}
if ($content->uid == 0) {
$content->name = variable_get('anonymous', t('Anonymous'));
}
else {
if ($content->uid) {
$content->name = $content->registered_name;
}
}
}
}
else {
$content = FALSE;
}
}
return $content;
}
function antispam_content_delete($content_type, $content_id) {
module_load_include('inc', 'comment', 'comment.admin');
if ($content_type == 'node') {
$node = antispam_content_load($content_type, $content_id);
if ($node) {
db_query('DELETE FROM {node} WHERE nid = %d', $node->nid);
db_query('DELETE FROM {node_revisions} WHERE nid = %d', $node->nid);
node_invoke($node, 'delete');
node_invoke_nodeapi($node, 'delete');
if (function_exists('search_wipe')) {
search_wipe($node->nid, 'node');
}
watchdog('content', '%type: deleted @title.', array(
'%type' => t($node->type),
'@title' => $node->title,
));
return TRUE;
}
}
else {
if ($content_type == 'comment') {
$comment = antispam_content_load($content_type, $content_id);
if ($comment) {
_comment_delete_thread($comment);
_comment_update_node_statistics($comment->cid);
return TRUE;
}
}
}
return FALSE;
}
function antispam_clear_cache() {
static $already_done = FALSE;
if (!$already_done) {
cache_clear_all();
$already_done = TRUE;
}
}
function antispam_content_spam_operation($content_type, $content, $op, $log_action = TRUE) {
if ($content_type == 'node') {
global $user;
$content_id = $content->nid;
$content_title = $content->title;
$content_link = l(t('view'), 'node/' . $content->nid);
$user_mail = isset($user->mail) ? $user->mail : '';
}
else {
$content_id = $content->cid;
$content_title = $content->subject;
$content_link = l(t('view'), 'node/' . $content->nid, array(
'fragment' => 'comment-' . $content->cid,
));
$user_mail = $content->mail;
}
if ($op == 'submit-spam') {
if (variable_get('antispam_connection_enabled', 1)) {
if (antispam_get_service_provider() == DEFENSIO_SERVICE) {
if ($content->signature == '') {
$api_result = antispam_api_cmd_comment_check($content_type, $content);
$content->signature = $api_result[1];
$content->spaminess = $api_result[2];
}
}
antispam_api_cmd_submit_spam($content_type, $content);
$action = $content_type == 'node' ? t('Content submitted as spam') : t('Comment submitted as spam');
}
else {
$action = $content_type == 'node' ? t('Content marked as spam') : t('Comment marked as spam');
}
$hostname = !empty($content->hostname) ? $content->hostname : ip_address();
db_query('INSERT INTO {antispam_spam_marks} (content_type, content_id, spam_created, hostname, mail, signature, spaminess) VALUES (\'%s\', %d, %d, \'%s\', \'%s\', \'%s\', %f)', $content_type, $content_id, time(), $hostname, $user_mail, $content->signature, $content->spaminess);
}
else {
if (variable_get('antispam_connection_enabled', 1)) {
if (antispam_get_service_provider() == DEFENSIO_SERVICE) {
if ($content->signature == '') {
$api_result = antispam_api_cmd_comment_check($content_type, $content);
$content->signature = $api_result[1];
$content->spaminess = $api_result[2];
}
}
antispam_api_cmd_submit_ham($content_type, $content);
$action = $content_type == 'node' ? t('Content submitted as ham') : t('Comment submitted as ham');
}
else {
$action = $content_type == 'node' ? t('Content marked as ham') : t('Comment marked as ham');
}
db_query('DELETE FROM {antispam_spam_marks} WHERE content_type = \'%s\' AND content_id = %d', $content_type, $content_id);
}
if ($log_action) {
watchdog('content', '@action: @title', array(
'@action' => $action,
'@title' => $content_title,
), WATCHDOG_NOTICE, $content_link);
}
antispam_clear_cache();
}
function antispam_content_publish_operation($content_type, $content, $op, $log_action = TRUE) {
module_load_include('inc', 'comment', 'comment.admin');
if ($content_type == 'node') {
db_query('UPDATE {node} SET status = %d WHERE nid = %d', $op == 'publish' ? 1 : 0, $content->nid);
if ($log_action) {
$action = $op == 'publish' ? t('Content published') : t('Content unpublished');
watchdog('content', '@action: @title', array(
'@action' => $action,
'@title' => $content->title,
), WATCHDOG_NOTICE, l(t('view'), 'node/' . $content->nid));
}
}
else {
static $comment_operations = FALSE;
if (!$comment_operations) {
$comment_operations = comment_operations();
}
$query = $comment_operations[$op][1];
db_query($query, $content->cid);
_comment_update_node_statistics($content->nid);
comment_invoke_comment($content, $op);
if ($log_action) {
$action = $op == 'publish' ? t('Comment published') : t('Comment unpublished');
watchdog('content', '@action: %subject', array(
'@action' => $action,
'%subject' => $content->subject,
), WATCHDOG_NOTICE, l(t('view'), 'node/' . $content->nid, array(
'fragment' => 'comment-' . $content->cid,
)));
}
}
antispam_clear_cache();
}
function antispam_prepare_comment_data($content_type, $content, $provider) {
global $user, $base_url;
if ($provider == DEFENSIO_SERVICE) {
if ($content->signature != '') {
$comment_data = array(
'signature' => $content->signature,
);
}
else {
$comment_data = array(
'user-ip' => !empty($content->hostname) ? $content->hostname : ip_address(),
'user-agent' => $_SERVER['HTTP_USER_AGENT'],
'referrer' => $_SERVER['HTTP_REFERER'],
'comment-author' => $content->name,
);
if ($content_type == 'comment') {
$comment_data['permalink'] = url('node/' . $content->nid, array(
'fragment' => 'comment-' . $content->cid,
));
$comment_data['comment-author-email'] = $content->mail;
$comment_data['comment-author-url'] = $content->homepage;
$comment_data['comment-content'] = $content->comment;
$node_created = db_result(db_query('SELECT created FROM {node} WHERE nid = %d', $content->nid));
$comment_data['article-date'] = date("Y/m/d", $node_created);
$comment_data['comment-type'] = 'comment';
}
else {
if ($content_type == 'node') {
$comment_data['permalink'] = url('node/' . $content->nid);
$comment_data['comment-author_email'] = isset($user->mail) ? $user->mail : '';
$comment_data['comment-author_url'] = '';
$comment_data['comment-content'] = $content->body;
$comment_data['article-date'] = date("Y/m/d");
$comment_data['comment-type'] = 'other';
}
else {
$comment_data['permalink'] = '';
$comment_data['comment-author_email'] = isset($user->mail) ? $user->mail : isset($content->mail) ? $content->mail : '';
$comment_data['comment-author_url'] = isset($content->homepage) ? $content->homepage : '';
$comment_data['comment-content'] = $content->body;
$comment_data['article-date'] = date("Y/m/d");
$comment_data['comment-type'] = 'other';
}
}
if ($user->uid > 0) {
$comment_data['user-logged-in'] = TRUE;
}
if ($user->uid == 1) {
$comment_data['trusted-user'] = TRUE;
}
if ($user->uid == 0 || empty($comment_data['comment-author'])) {
$comment_data['comment-author'] = variable_get('anonymous', t('Anonymous'));
}
}
}
else {
$comment_data = array(
'user_ip' => !empty($content->hostname) ? $content->hostname : ip_address(),
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'referrer' => $_SERVER['HTTP_REFERER'],
'comment_type' => '',
'comment_author' => $content->name,
);
if ($content_type == 'comment') {
$comment_data['permalink'] = url('node/' . $content->nid, array(
'fragment' => 'comment-' . $content->cid,
));
$comment_data['comment_author_email'] = $content->mail;
$comment_data['comment_author_url'] = $content->homepage;
$comment_data['comment_content'] = $content->comment;
}
else {
if ($content_type == 'node') {
$comment_data['permalink'] = url('node/' . $content->nid);
$comment_data['comment_author_email'] = isset($user->mail) ? $user->mail : '';
$comment_data['comment_author_url'] = '';
$comment_data['comment_content'] = $content->body;
}
else {
$comment_data['permalink'] = '';
$comment_data['comment-author_email'] = isset($user->mail) ? $user->mail : isset($content->mail) ? $content->mail : '';
$comment_data['comment-author_url'] = isset($content->homepage) ? $content->homepage : '';
$comment_data['comment_content'] = $content->body;
}
}
}
return $comment_data;
}
function _antispam_parse_yaml_response($response, $field = '') {
$lines = explode("\n", $response);
foreach ($lines as $line) {
$line = trim($line);
if ($line != '' && $line != "defensio-result:") {
$line = preg_replace("/(.*): \"?([^\"]*)\"?/", "\$1|\$2", $line);
list($key, $data) = explode('|', $line);
$array[$key] = $data;
}
}
if ($field != '') {
return $array[$field];
}
else {
return $array;
}
}
function antispam_api_cmd_verify_key($key) {
global $base_url;
if (empty($key)) {
return ANTISPAM_API_RESULT_ERROR;
}
$provider = antispam_get_service_provider();
$api_host = antispam_get_api_host($provider);
if ($provider == DEFENSIO_SERVICE) {
$request = 'owner-url=' . $base_url . base_path();
$response = _antispam_api_http_post($request, $api_host, '/blog/' . DEFENSIO_API_VERSION . '/validate-key/' . $key . '.yaml');
if (!isset($response[1])) {
return ANTISPAM_API_RESULT_ERROR;
}
return _antispam_parse_yaml_response($response[1], 'status') == 'success' ? ANTISPAM_API_RESULT_SUCCESS : ANTISPAM_API_RESULT_ERROR;
}
else {
$request = 'key=' . $key . '&blog=' . $base_url . base_path();
$response = _antispam_api_http_post($request, $api_host, '/' . AKISMET_API_VERSION . '/verify-key');
if (!isset($response[1])) {
return ANTISPAM_API_RESULT_ERROR;
}
return 'valid' == $response[1] ? ANTISPAM_API_RESULT_SUCCESS : ANTISPAM_API_RESULT_ERROR;
}
}
function antispam_api_cmd_spam_check($body, $name = NULL, $mail = NULL, $homepage = NULL) {
$provider = antispam_get_service_provider();
$api_host = antispam_get_api_host($provider);
$api_key = antispam_get_api_key($provider);
if (empty($api_key)) {
return array(
ANTISPAM_API_RESULT_ERROR,
);
}
$content = array(
'body' => $body,
'name' => $name,
'mail' => $mail,
'homepage' => $homepage,
);
$api_result = antispam_api_cmd_comment_check('other', $content);
if ($api_result[0] == ANTISPAM_API_RESULT_IS_HAM) {
return 0;
}
else {
if ($api_result[0] == ANTISPAM_API_RESULT_IS_SPAM) {
return 1;
}
else {
return -1;
}
}
}
function antispam_api_cmd_comment_check($content_type, $content) {
if (!variable_get('antispam_connection_enabled', 1)) {
return array(
ANTISPAM_API_RESULT_ERROR,
);
}
$provider = antispam_get_service_provider();
$comment_data = antispam_prepare_comment_data($content_type, $content, $provider);
$api_host = antispam_get_api_host($provider);
$api_key = antispam_get_api_key($provider);
if (empty($api_key)) {
return array(
ANTISPAM_API_RESULT_ERROR,
);
}
if ($provider == DEFENSIO_SERVICE) {
$comment_data = array_merge(_antispam_api_prepare_request_data(), $comment_data);
$query_string = _antispam_api_build_query_string($comment_data);
$response = _antispam_api_http_post($query_string, $api_host, '/app/' . DEFENSIO_API_VERSION . '/audit-comment/' . $api_key . '.yaml');
if (!isset($response[1])) {
return ANTISPAM_API_RESULT_ERROR;
}
$res_array = _antispam_parse_yaml_response($response[1]);
$result = array();
if (isset($res_array['spam'])) {
$result[0] = $res_array['spam'] == 'true' ? ANTISPAM_API_RESULT_IS_SPAM : ANTISPAM_API_RESULT_IS_HAM;
if (isset($res_array['signature'])) {
$result[1] = $res_array['signature'];
}
if (isset($res_array['spaminess'])) {
$result[2] = $res_array['spaminess'];
}
return $result;
}
else {
return array(
ANTISPAM_API_RESULT_ERROR,
);
}
}
else {
$comment_data = array_merge(_antispam_api_prepare_request_data(), $comment_data);
$query_string = _antispam_api_build_query_string($comment_data);
$host = $api_key . '.' . $api_host;
$response = _antispam_api_http_post($query_string, $host, '/' . AKISMET_API_VERSION . '/comment-check');
if (!isset($response[1])) {
return ANTISPAM_API_RESULT_ERROR;
}
return 'true' == $response[1] ? array(
ANTISPAM_API_RESULT_IS_SPAM,
) : array(
ANTISPAM_API_RESULT_IS_HAM,
);
}
}
function antispam_api_cmd_submit_spam($content_type, $content) {
if (!variable_get('antispam_connection_enabled', 1)) {
return ANTISPAM_API_RESULT_ERROR;
}
$provider = antispam_get_service_provider();
$comment_data = antispam_prepare_comment_data($content_type, $content, $provider);
$api_host = antispam_get_api_host($provider);
$api_key = antispam_get_api_key($provider);
if (empty($api_key)) {
return ANTISPAM_API_RESULT_ERROR;
}
if ($provider == DEFENSIO_SERVICE) {
$query_string = _antispam_api_build_query_string($comment_data);
$response = _antispam_api_http_post($query_string, $api_host, '/blog/' . DEFENSIO_API_VERSION . '/report-false-negatives/' . $api_key . '.yaml');
if (!isset($response[1])) {
return ANTISPAM_API_RESULT_ERROR;
}
return _antispam_parse_yaml_response($response[1], 'status') == 'success' ? ANTISPAM_API_RESULT_SUCCESS : ANTISPAM_API_RESULT_ERROR;
}
else {
$query_string = _antispam_api_build_query_string($comment_data);
$host = $api_key . '.' . $api_host;
$response = _antispam_api_http_post($query_string, $host, '/' . AKISMET_API_VERSION . '/submit-spam');
return isset($response[1]) ? ANTISPAM_API_RESULT_SUCCESS : ANTISPAM_API_RESULT_ERROR;
}
}
function antispam_api_cmd_submit_ham($content_type, $content) {
if (!variable_get('antispam_connection_enabled', 1)) {
return ANTISPAM_API_RESULT_ERROR;
}
$provider = antispam_get_service_provider();
$comment_data = antispam_prepare_comment_data($content_type, $content, $provider);
$api_host = antispam_get_api_host($provider);
$api_key = antispam_get_api_key($provider);
if (empty($api_key)) {
return ANTISPAM_API_RESULT_ERROR;
}
if ($provider == DEFENSIO_SERVICE) {
$query_string = _antispam_api_build_query_string($comment_data);
$response = _antispam_api_http_post($query_string, $api_host, '/blog/' . DEFENSIO_API_VERSION . '/report-false-positives/' . $api_key . '.yaml');
if (!isset($response[1])) {
return ANTISPAM_API_RESULT_ERROR;
}
return _antispam_parse_yaml_response($response[1], 'status') == 'success' ? ANTISPAM_API_RESULT_SUCCESS : ANTISPAM_API_RESULT_ERROR;
}
else {
$query_string = _antispam_api_build_query_string($comment_data);
$host = $api_key . '.' . $api_host;
$response = _antispam_api_http_post($query_string, $host, '/' . AKISMET_API_VERSION . '/submit-ham');
return isset($response[1]) ? ANTISPAM_API_RESULT_SUCCESS : ANTISPAM_API_RESULT_ERROR;
}
}
function _antispam_api_prepare_request_data() {
static $safe_to_send = array(
'CONTENT_LENGTH',
'CONTENT_TYPE',
'HTTP_ACCEPT',
'HTTP_ACCEPT_CHARSET',
'HTTP_ACCEPT_ENCODING',
'HTTP_ACCEPT_LANGUAGE',
'HTTP_REFERER',
'HTTP_USER_AGENT',
'REMOTE_ADDR',
'REMOTE_PORT',
'SCRIPT_URI',
'SCRIPT_URL',
'SERVER_ADDR',
'SERVER_NAME',
'REQUEST_METHOD',
'REQUEST_URI',
'SCRIPT_NAME',
);
static $server_data;
if (!$server_data) {
$server_data = array();
foreach ($_SERVER as $key => $value) {
if (in_array($key, $safe_to_send)) {
$server_data[$key] = $value;
}
}
}
return $server_data;
}
function _antispam_api_build_query_string($array) {
global $base_url;
if (antispam_get_service_provider() == DEFENSIO_SERVICE) {
$string = 'owner-url=' . $base_url . base_path();
}
else {
$string = 'blog=' . $base_url . base_path();
}
foreach ($array as $key => $value) {
$string .= '&' . $key . '=' . urlencode(stripslashes($value));
}
return $string;
}
function _antispam_api_http_post($request, $host, $path) {
$fsock_timeout = (int) variable_get('antispam_connection_timeout', 10);
$http_request = "POST {$path} HTTP/1.0\r\n" . "Host: {$host}\r\n" . "Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n" . 'Content-Length: ' . strlen($request) . "\r\n" . 'User-Agent: ' . ANTISPAM_API_USERAGENT . "\r\n" . "\r\n" . $request;
$response = '';
if (false !== ($fs = @fsockopen($host, ANTISPAM_API_PORT, $errno, $errstr, $fsock_timeout))) {
fwrite($fs, $http_request);
while (!feof($fs)) {
$response .= fgets($fs, 1160);
}
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
}
return $response;
}