'. t('The gotcha module adds a field to the contact form which is hidden by the CSS. Spam bots will see the field and may fill it in, thus tipping us off to a spam bot.') .'
';
case 'admin/logs/gotcha':
return ''. t('This is a list of all the Contact messages that have been logged. You are currently logging %logged messages. Settings for this list can be found on the Contact Form settings page.',
array('%logged' => variable_get('gotcha_log_email', 0) ? 'all' : 'only suspect',
'@link' => url('admin/build/contact/settings'),
)) .'
';
}
}
/**
* Implementation of hook_menu().
* The only menu items for this module is to list the emails that were intercepted.
* It will be under the admin >> logs section of the Administer menu.
*/
function gotcha_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/logs/gotcha',
'title' => t('Gotcha list'),
'description' => t('Show emails intercepted by the Gotcha module.'),
'callback' => 'gotcha_list',
'access' => user_access('access administration pages'),
);
}
else {
drupal_add_css(drupal_get_path('module', 'gotcha') .'/gotcha.css');
$items[] = array(
'path' => 'gotcha/view',
'title' => t('Gotcha view'),
'description' => t('Show an individual intercepted by the Gotcha module.'),
'callback' => 'gotcha_view',
'access' => user_access('access administration pages'),
'type' => MENU_CALLBACK,
);
}
return $items;
}
/**
* Implementation of hook_enable.
* This function logs a message saying the module is enabled and gives the user id.
*/
function gotcha_enable() {
global $user;
watchdog('Gotcha', t('Gotcha module enabled by ') . theme('username', $user), WATCHDOG_NOTICE, NULL);
$go_away = db_result(db_query("SELECT nid FROM {node} WHERE title='Gotcha: Go Away!' LIMIT 1"));
if ($go_away) {
// The page is already present.
}
else {
// Define the default "Go Away" message page.
// http://drupal.org/node/183635, I'm setting the status to "published."
$go_page = array(
'status' => 0,
'sticky' => 0,
'promote' => 1,
'comment' => 0,
'uid' => $user->uid,
'type' => 'page',
'title' => 'Gotcha: Go Away!',
'body' => 'SPAM ALERT!
This message was flagged as probable spam. It will not be sent.
Your identifying information has been logged and will be reported.
Get a life!
Do something productive and leave me alone!
',
'format' => 2, /* Full HTML */
);
$go_away_page = (object)$go_page;
$go_away_node = node_save($go_away_page);
// Now we have to get the new page's nid.
$go_away = db_result(db_query("SELECT nid FROM {node} WHERE title='Gotcha: Go Away!' LIMIT 1"));
}
variable_set('gotcha_goaway_page', 'node/'. $go_away);
drupal_set_message(t('Gotcha "Go Away" page set to !goaway. The settings can be adjusted here.', array('!goaway' => $go_away, '@settings' => url('admin/build/contact/settings'))), 'notice');
}
/**
* Implementation of hook_disable.
* This function logs a message saying the module is disabled and gives the user id.
*/
function gotcha_disable() {
global $user;
watchdog('Gotcha', t('Gotcha module disabled by ') . theme('username', $user), WATCHDOG_NOTICE, NULL);
}
// *****************************
// ***** *****
// ***** "Working" Section *****
// ***** *****
// *****************************
/**
* Implementation of hook_form_alter.
* This function:
* 1) Adds a field to the top of the contact form and sets it to use a CSS style that makes it hidden.
* It then intercepts the submit button to check the field and bypass sending the message if it looks like a spam bot.
* 2) Adds a field to the Contact settings form to enable email logging.
*/
function gotcha_form_alter($form_id, &$form) {
switch ($form_id) {
case 'contact_mail_page':
case 'contact_mail_user':
// We'll call our hidden field "Subject" so it sounds enticing.
// We provide a message for browsers that don't hide the field.
gotcha_api_gotcha_fields($form_id, $form);
// set it up to catch the "send email" (submit) button.
$form['#submit'] = array('gotcha_contact_submit' => array());
break;
case 'contact_admin_settings':
$form['gotcha'] = array('#type' => 'fieldset',
'#title' => t('Gotcha module settings'),
'#weight' => -5,
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['gotcha']['gotcha_log_email'] = array(
'#type' => 'checkbox',
'#title' => t('Log all email'),
'#default_value' => variable_get('gotcha_log_email', false),
'#description' => t('If this box is checked, all site-wide Contact email will be logged in the Gotcha table. If it is not checked, only suspect emails will be logged.', array('!log' => url('admin/logs/gotcha'))),
);
$form['gotcha']['gotcha_goaway_page'] = array(
'#type' => 'textfield',
'#title' => t('"Go Away" page'),
'#default_value' => variable_get('gotcha_goaway_page', 'node'),
'#description' => t('This is the path to the page to be displayed when the message has been identified as spam. That message should be tactful, but forceful. Set this field to "node" to disable the message.'),
'#size' => 30,
);
$form['gotcha']['log'] = array('#type' => 'fieldset',
'#title' => t('Log display settings'),
'#weight' => 1,
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['gotcha']['log']['gotcha_max_body'] = array(
'#type' => 'textfield',
'#title' => t('Maximum body'),
'#default_value' => variable_get('gotcha_max_body', 100),
'#description' => t("The maximum size of the message's body to show in the logging list."),
'#size' => 7,
'#maxlength' => 5,
);
$form['gotcha']['log']['gotcha_rows_per_page'] = array(
'#type' => 'textfield',
'#title' => t('Rows per Page'),
'#default_value' => variable_get('gotcha_rows_per_page', 20),
'#description' => t("The number of rows to show per page in the logging list."),
'#size' => 7,
'#maxlength' => 5,
);
$form['gotcha']['log']['gotcha_show_site'] = array(
'#type' => 'checkbox',
'#title' => t('Show Site Name'),
'#default_value' => variable_get('gotcha_show_site', FALSE),
'#description' => t("If set, the site's name will show in the logging list. This is useful in a multisite environment with a shared 'Gotcha' log."),
);
break;
}
}
/**
* This is the intercept form_submit function.
* Here we check the field and bypass sending the message if it looks like a spam bot.
* Just in case, we'll log the message and the info.
**/
function gotcha_contact_submit($form_id, $form_values) {
global $user;
$LOG_ALL = variable_get('gotcha_log_email', false);
// Get the entered information.
$site_name = variable_get('site_name', 'Drupal');
switch ($form_id) {
case 'contact_mail_page':
$type = 'site';
$contact = db_fetch_object(db_query("SELECT * FROM {contact} WHERE cid = %d", $form_values['cid']));
$recipients = $contact->recipients;
// Apply filter?
$sendername = check_plain($form_values['name']);
$sendermail = $form_values['mail'];
break;
case 'contact_mail_user':
$type = 'user';
$account = user_load(array('uid' => arg(1), 'status' => 1));
// Prepare all fields:
$recipients = $account->mail;
// $from = $user->mail;
$sendername = $user->name;
$sendermail = $user->mail;
// Format the subject:
// $subject = '['. variable_get('site_name', 'Drupal') .'] '. $form_values['subject'];
// Prepare the body:
// $body = implode("\n\n", $message);
break;
} // End switch.
$subject = check_plain($form_values['subject']);
$body = $form_values['message'];
if (!gotcha_api_gotcha_check(1, 1, $subject, $recipients, $body, $sendername, $sendermail, $site_name, $type)) {
// Looks okay, so send it on to Contact.
contact_mail_page_submit($form_id, $form_values);
}
}
/*
* Provide Gotcha form field(s).
*/
function gotcha_api_gotcha_fields($form_id, &$form) {
// We'll call our hidden field "Subject" so it sounds enticing.
// We provide a message for browsers that don't hide the field.
$form['Private_Message'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#weight' => -5, /* Place it high on the form. */
'#prefix' => '',
'#suffix' => '
',
'#description' => t('This field is for computer-generated email only and should not be visible. If you can see it, please ignore it.'),
);
}
/*
* Here we check the form field(s) for spam.
*
* Input:
* $log: 1 / 0: yes / no logging a spam attempt message and the info.
* $goto: 1 / 0: yes / no goto goaway page at a a spam attempt
* The names of the following fields are based on those in the contact form ==> e-mail
* $subject: subject of the e-mail
* $recipients: recipients of the e-mail
* $body: body of the e-mail: all formfields not mentioned elsewhere in the input fields, separated by "\n"
* $sendername: name of the sender of the e-mail
* $sendermail: e-mail address of the sender of the e-mail
* $site_name: the result of variable_get('site_name', 'Drupal');
* $type: your formtype name in 4 characters (e.g. user or mail).
* Returns: $suspect: 0=no spam, 1=spam_content_filter reports spam, 2=Private Message contains data
*/
function gotcha_api_gotcha_check($log, $goto, $subject, $recipients, $body, $sendername, $sendermail, $site_name, $type) {
drupal_set_message("in gotcha_api_check\n");
// Get the session information.
$userip = $_SERVER['REMOTE_ADDR'];
$datestamp = str_replace(' ', 'T', date('Y-m-d H:i:s')); // ISO format without zone.
// If there's anything in our hidden field, it is most likely the result of a spam bot.
$suspect = !empty($form_values['Private_Message']) ? 2 : 0;
drupal_set_message("suspect=$suspect\n");
// Check with Spam module if it's not a bot.
if (module_exists('spam') && !$suspect) {
$probability = spam_content_filter('contact', $datestamp, $subject, $body, 'gotcha_spam_contact');
if ($probability >= variable_get('spam_threshold', 80)) { $suspect = true; }
}
drupal_set_message("probability=$probability\n");
// Log all the data.
if ($log) {
drupal_set_message("in log\n");
if ($LOG_ALL || $suspect) {
// Write the data to our database table. (We allow datesent to default.)
drupal_set_message("in query write\n");
db_query("INSERT INTO {gotcha} (datestamp, suspect, recipients, subject, body, sendername, sendermail, userip, sitename, type) VALUES ('%s', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')", $datestamp, $suspect, $recipients, $subject, $body, $sendername, $sendermail, $userip, $site_name, $type);
}
if ($suspect) {
drupal_set_message("in if suspect\n");
watchdog('gotcha_api', t("Suspect contact attempt intercepted from IP address !ip, probability=!prob", array('!ip' => $userip, '!prob' => $spam)),
WATCHDOG-WARNING, l(t('View log'), 'admin/logs/gotcha_api'));
}
}
if ($suspect && $goto) {
// Finish by redirecting to the "go away" page or page_not_found.
$dest = variable_get('gotcha_goaway_page', variable_get('site_404', 'node'));
drupal_set_message("naar drupal goto $dest\n");
drupal_goto($dest);
}
return $suspect;
}
/*
* Implementation of Spam module call for delete contact processing.
*/
function spam_delete_contact($id) {
watchdog(t('Contact spam is to be deleted; id=!id', array('!id' => $id)), WATCHDOG_WARNING);
// $delete = "DELETE FROM {gotcha} WHERE datestamp='%s' LIMIT 1";
return;
}
/*
* Implementation of Spam module call for further processing.
* Check the table and increase the probability that it's spam by 10 points for every time we've flagged them before.
*/
function gotcha_spam_contact($source, $id, $header, $body, $probability, $old, $action) {
$userip = $_SERVER['REMOTE_ADDR'];
$bad_guy = 0;
// Ignore local test site ip address.
if ($userip != '127.0.0.1') {
$result = db_query("SELECT * FROM {gotcha} WHERE userip='%s'", $userip);
while ($hit = db_fetch_array($result)) {
// Should we do something special if the sender had one marked "not spam" and sent?
if ($hit['suspect'] > 0 && $hit['suspect'] < 5) { $bad_guy += 10; }
}
}
if ($bad_guy) {
spam_log(SPAM_LOG, t('spam_contact_filter: @prob% added for previous spam from @source "%header"', array('@prob' => $bad_guy, '@source' => $userip, '%header' => $header)), $source, $id);
}
return $probability + $bad_guy;
}
/**
* This is the menu callback function to view entries in the log.
**/
function gotcha_view($mid=NULL) {
if (is_null($mid)) {
drupal_set_message('A message ID is required.', 'warning');
return;
}
$output = "\n". t('View Message Number !num', array('!num' => $mid)) .'
';
$msg = db_fetch_array(db_query('SELECT * FROM {gotcha} WHERE mid=%d LIMIT 1', $mid));
// Compose the body. Note, we don't need an explanation if it's not suspect, because it was sent originally.
if ($msg['suspect']) {
$body = gotcha_explain($msg);
}
else { $body = null; }
$body .= ''. wordwrap($msg['body'], 75, '
') .'
';
$rows[] = array(array('data' => t('To'), 'header' => TRUE), $msg['recipients']);
$rows[] = array(array('data' => t('From'), 'header' => TRUE), $msg['sendername']);
$rows[] = array(array('data' => t('Subject'), 'header' => TRUE), $msg['subject']);
$rows[] = array(array('data' => $body, 'colspan' => '2'));
$output .= theme('table', array(), $rows, array('border' => '2'));
// Now add a link back to the list.
$output .= '
'. l('Back to the log', 'admin/logs/gotcha') .'
';
echo theme('page', $output, TRUE);
}
/**
* Helper function to build explanation text on message.
**/
function gotcha_explain($msg) {
$sitename = variable_get('site_name', 'Drupal');
switch ($msg['type']) {
case 'site':
$message = t("!name sent a message using the contact form at !site.",
array('!name' => $msg['sendername'],
'!site' => $sitename,
)
);
$message .= ' '. t("It was inadvertantly intercepted as potential spam on !date.", array('!date' => substr($msg['datestamp'], 0, 10)));
break;
case 'user':
$message = ''. t("!name (!senderemail) has sent you a message via your contact form at !site.",
array('!name' => $msg['sendername'],
'!senderemail' => $msg['senderemail'] ? $msg['senderemail'] : variable_get('site_mail', '?'),
'!site' => $sitename,
)
);
$message .= ' '. t("It was inadvertantly intercepted as potential spam on !date.", array('!date' => substr($msg['datestamp'], 0, 10)));
$message .= ' '. t("If you don't want to receive such e-mails, you may change your settings.") .'
';
$message .= ''. t('Message:') .'
';
break;
}
return wordwrap($message);
}
/**
* This is the menu callback function to send a message that was not spam.
**/
function gotcha_send($mid=NULL) {
if (is_null($mid)) {
drupal_set_message('A message ID is required.', 'warning');
return;
}
$msg = db_fetch_array(db_query('SELECT * FROM {gotcha} WHERE mid=%d LIMIT 1', $mid));
$title = $msg['subject'];
// Compose the body. Note, we don't need an explanation if it's not suspect, because it was sent originally.
if ($msg['suspect']) {
$body = gotcha_explain($msg) . "\n\n";
}
else { $body = null; }
$body .= ''. wordwrap($msg['body'], 75, '
') .'
';
// Send the e-mail to the recipients:
drupal_mail('contact-page-mail', $msg['recipients'], $title, $body, $msg['sendername']);
$x = str_replace(' ', 'T', date('Y-m-d H:i:s'));
$mark_sent = db_query("UPDATE {gotcha} SET suspect=5, datesent='%s' WHERE mid=%d LIMIT 1", $x, $mid);
drupal_set_message("Okay, I sent '$title' (#$mid)", 'notice');
drupal_goto('admin/logs/gotcha');
}
/**
* This is the menu callback function to delete entries in the log.
**/
function gotcha_delete($mid=NULL) {
if (is_null($mid)) {
drupal_set_message('A message ID is required.', 'warning');
return;
}
$delsql = db_query('DELETE FROM {gotcha} WHERE mid=%d LIMIT 1', $mid);
drupal_set_message("Okay, I deleted row #$mid", 'notice');
// Now go back to the list.
drupal_goto('admin/logs/gotcha');
}
/**
* This is the menu callback function to list the emails that have been intercepted.
**/
function gotcha_list($op=NULL, $mid=NULL) {
if ($op == 'delete') { gotcha_delete($mid); }
if ($op == 'view') { gotcha_view($mid); }
if ($op == 'send') { $output .= gotcha_send($mid); }
$show_site = variable_get('gotcha_show_site', FALSE);
$how_many = variable_get('gotcha_rows_per_page', 20);
$max_body_len = variable_get('gotcha_max_body', 100);
$suspect_type = array(0 => t('No'), 1 => t('Yes'), 2 => t('Bot'), 5 => t('Sent'));
$sql = "SELECT * FROM {gotcha} g ORDER BY g.datestamp DESC";
$result = pager_query($sql, $how_many);
$rows = array();
while ($msg = db_fetch_array($result)) {
// We'll limit the body length.
$body = check_plain($msg['body']);
if (strlen($body) > $max_body_len) {
$body = substr($body, 0, $max_body_len) .'...';
}
$op_links = array();
$op_links[] = l(t('view'), 'gotcha/view/'. $msg['mid']);
$op_links[] = l(t('delete'), 'admin/logs/gotcha/delete/'. $msg['mid']);
if ($msg['suspect'] > 0 && $msg['suspect'] < 5) {
$op_links[] = l(t('send'), 'admin/logs/gotcha/send/'. $msg['mid']);
}
$row_data = array($msg['datestamp'],
array('data' => $suspect_type[$msg['suspect']], 'align' => 'center'),
$msg['userip'],
$msg['recipients'] .'
('. $msg['type'] .')',
check_plain($msg['subject']),
$body,
array('data' => $msg['sendername'] .'
'. $msg['sendermail'], 'align' => 'center'),
// These lines removed because they were no value.
// array('data' => $msg['servername'] .'
'. $msg['serveraddr'], 'align' => 'center'),
// $msg['referer'],
array('data' => implode('
', $op_links), 'align' => 'center'),
);
if ($show_site) { $row_data[0] .= '
'. t($msg['sitename']); }
$rows[] = $row_data;
}
// All ready to show the table if there were any entries in the log.
if (count($rows)) {
$header = array(t('Date/Time'),
t('Suspect'),
t('User IP'),
t('To'),
t('Subject'),
t('Body'),
t('Sender Name') .'
'. t('Sender Email'),
// These lines removed because they were no value.
// t('Server Name') .'
'. t('Server Address'),
// t('Referer'),
t('Action'),
);
if ($show_site) { $header[0] .= '
'. t('Site Name'); }
$output .= ''.
theme('table', $header, $rows) .
theme('pager', NULL, $how_many)
."
";
return $output;
}
else { return ''. t('No emails found in the log.') .'
'; }
}
/* Implementation of hook_spam
* This function sets the tab name for the settings intro page.
*/
function gotcha_spam($name, $arg1, $arg2, $arg3) {
// Do stuff based on the hook type (name).
switch ($name) {
case 'tab_description':
$tabs = array();
$tabs['Gotcha'] = t('Capture Contact form spam. This is not yet a real add-on to Spam. The settings are at Contact Form settings page', array('@link' => url('admin/build/contact/settings')));
return $tabs;
case "filter_settings":
$form['spam_filter_contact'] = array(
'#type' => 'checkbox',
'#title' => t('Filter Contact form'),
'#return_value' => 1,
'#weight' => -1,
'#default_value' => variable_get('spam_filter_contact', 1),
'#description' => t('Enable this option to filter Contact emails before they are sent, determining whether or not they are spam.'),
);
$hook['group'] = $form;
return $hook;
default:
return array();
}
}