<?php
/**
 * "Report Spammer" v1.2 MyBB plugin
 * 
 * Use various web sites and services to gather information of spamming activity by the user currently edited in Mod CP.
 * Offer the option of reporting the scumbag to StopForumSpam.com.
 * 
 * Copyright 2011 Dan Dascalescu, http://dandascalescu.com
 *
 * Website: https://github.com/dandv/Report-Spammer-MyBB-plugin
 *
 * NOTE: This plugin does not support localization on purpose. For the rationale of this decision, please carefully read
 * http://wiki.dandascalescu.com/essays/english-universal-language
 * Patches that implement localization will only be accepted if acceptable refutation of the essay linked above is provided.
 *
 * License: GPL3. However, redistribution of modifications that include localization is prohibited.
 */

// Disallow direct access to this file for security reasons
if(!defined('IN_MYBB'))
{
	die('Direct initialization of this file is not allowed.<br /><br />Please make sure IN_MYBB is defined.');
}

$plugins->add_hook('modcp_editprofile_end', 'report_spammer_display');
$plugins->add_hook('xmlhttp', 'report_spammer_ajax');

function report_spammer_info()
{
	return array(
		'name'			=> 'Report Spammer',
		'description'	=> 'Show how likely that a given user is a spammer, and allows reporting them to <a href="http://stopforumspam.com">StopForumSpam.com</a>.',
		'website'		=> 'https://github.com/dandv/Report-Spammer-MyBB-plugin',
		'author'		=> 'Dan Dascalescu',
		'authorsite'	=> 'http://dandascalescu.com',
		'version'		=> '1.0',
		'guid' 			=> '0b53630a641f43baeea8bee1428c585a',
		'compatibility' => '16*'
	);
}

/**
 *   Called whenever a plugin is installed by clicking the "Install" button in the plugin manager.
 */
function report_spammer_install()
{
	global $db;
	report_spammer_uninstall();

	// add settings
	$result = $db->simple_select('settinggroups', 'MAX(disporder) AS max_disporder');
	$max_disporder = $db->fetch_field($result, 'max_disporder');

	$settings_group = array(
		'gid'			=> 'NULL',
		'name'			=> 'report_spammer',
		'title'			=> 'Report Spammer',
		'description'	=> 'Settings for the Report Spammer plugin',
		'disporder'		=> $max_disporder + 1,
		'isdefault'		=> '0'
	);
	$db->insert_query('settinggroups', $settings_group);
	$gid = (int) $db->insert_id();

	$db->insert_query('settings', array(
		'sid'			=> 'NULL',
		'name'			=> 'report_spammer_StopForumSpam_key',
		'title'			=> 'StopForumSpam.com key',
		'description'	=> 'To report spammers, StopForumSpam.com requires an API key. Get one <a href="http://www.stopforumspam.com/signup">here</a>.',
		'optionscode'	=> 'text',
		'value'			=> '',
		'disporder'		=> '1',
		'gid'			=> $gid
	));

	// Create a new global template for displaying the Report Spammer information.
	// Other plugins do this in _activate(), but if the user customized the template, when they deactivate the plugin, the customizations will be lost.
	$template_content ='
		<br />
		<style>
		.spammer_yes, .report_spammer_error {
			font-weight: bold;
			color: red;
		}
		.spammer_no, .report_spammer_success {
			font-weight: bold;
			color: green;
		}
		.spammer_unknown {
		}
		</style>
		<fieldset class="trow2">
			<legend><strong>Report Spammer options</strong></legend>
			<table cellspacing="0" cellpadding="{$theme[\'tablespace\']}">
				<tr>
					<td>Username known for spamming:</td>
					<td class="{$username_spammer_class}">{$username_spammer_message}</td>
				</tr>
				<tr>
					<td>Email known for spamming:</td>
					<td class="{$email_spammer_class}">{$email_spammer_message}</td>
				</tr>
				{$ip_addresses_spammer}
			</table>
			<input type="button" id="report_spammer_button" value="{$report_spammer_button_text}" />
			<br/>
			<div id="report_spammer_status" />
		</fieldset>
		<script type="text/javascript">
			var report_spammer_username={$username};
			var report_spammer_email={$email};
			var report_spammer_ip_addresses = {$ip_addresses};
		</script>
		<script type="text/javascript" src="{$mybb->settings[\'bburl\']}/jscripts/report_spammer.js"></script>
';
	$db->insert_query('templates', array(
		'title' => 'report_spammer_display',
		'template' => $db->escape_string($template_content),
		'sid' => '-1',
		'version' => '1603',
		'dateline' => TIME_NOW
	));

	rebuild_settings();
}
/**
 *   Called on the plugin management page to establish if a plugin is already installed or not.
 *   Returns boolean.
 */
function report_spammer_is_installed()
{
	global $db;
	$query = $db->simple_select('settinggroups', 'name', 'name="report_spammer"');
	return $query->num_rows > 0;
}

/**
 *    Remove ALL traces of the plugin from the installation (templates, settings etc).
 */
function report_spammer_uninstall()
{
	global $db;
	// delete templates
	$db->delete_query('templates', 'title LIKE "report_spammer%"');
	// delete the settings
	$query = $db->simple_select('settinggroups', 'gid', 'name = "report_spammer"');
	if ($gid = $db->fetch_field($query, 'gid'))
	{
		$db->delete_query('settings', 'gid = ' . $gid);
		$db->delete_query('settinggroups', 'gid = ' . $gid);
	}

	rebuild_settings();
}


// Make the plugin "visible" by adding and changing templates
function report_spammer_activate()
{
	report_spammer_deactivate();
	
	require_once MYBB_ROOT . 'inc/adminfunctions_templates.php';
	// add an indication that there are some Report Spammer options in the 'Edit this user is Mod CP' page
	find_replace_templatesets('member_profile_modoptions', '#(lang->edit_in_mcp}</a>)#i', '$1 (+ <i>Report Spammer</i> options)');
	
	find_replace_templatesets('modcp_editprofile', '#(lang->moderation}.*?</tr>\s*</table>\s*</fieldset>)#si', '$1' . "\n" . '{$report_spammer}');
}

function report_spammer_deactivate()
{
	require_once MYBB_ROOT . 'inc/adminfunctions_templates.php';
	find_replace_templatesets('modcp_editprofile', '#\s{\$report_spammer}#i', '', 0);
	find_replace_templatesets('member_profile_modoptions', '# \(\+ <i>Report Spammer</i> options\)#', '', 0);
}

// After over 100 lines of boilerplate code, we get to do interesting stuff
function report_spammer_display()
{
	// TODO: delayed loading of external HTTP requests
	global $templates, $user, $session;  // imports
	global $mybb, $theme;      // imports used in eval'ing the template
	global $report_spammer;    // exports
	// variables used by the report_spammer_display template
	$username_spammer_message = 'No';
	$username_spammer_class = 'spammer_unknown';
	$email_spammer_message = 'No';
	$email_spammer_class = 'spammer_unknown';
	$ip_addresses_spammer = '';  // not worth creating a template, nothing to customize here
	$report_spammer_button_text = 'Report spammer';  // changed to 'Confirm spammer report' if spammer has already been reported

	$ipaddresses = array();
	$ipaddresses[] = array(
		title => 'Registration IP',
		ip => $user['regip']
	);
	if($user['lastip'] != $user['regip'])
	{
		$ipaddresses[] = array(
			title => 'Last IP',
			ip => $user['lastip']
		);
	}
	// TODO: we only get the lastip and regip, but the user might have used more IPs, which we could find in their posting history
/*	$ipaddresses[] = array(
		title => 'IP used to post <a href="' . get_post_link($post['pid']) . '">{$post['subject']}</a>',
		ip => $post['ipaddress']
	);
*/
	
	$ch = curl_init();
	## curl_setopt_array doesn't work in some configurations (see http://community.mybb.com/thread-100846-post-735575.html#pid735575)
	curl_setopt($ch, CURLOPT_HEADER, false);
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);  // follow redirects
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);  // return a string, don't output it directly

	// see http://stopforumspam.com/usage
	curl_setopt($ch, CURLOPT_URL, 'http://www.stopforumspam.com/api?email=' . urlencode($user['email']) . '&username=' . urlencode($user['username']) . '&f=serial');
	$output = curl_exec($ch);
	$stopforumspam_info = unserialize($output);  // it's fine, this is not an eval
	if($stopforumspam_info['success'])
	{
		if($stopforumspam_info['username']['appears'])
		{
			$report_spammer_button_text = 'Confirm spammer report';
			$username_spammer_class = 'spammer_yes';
			$username_spammer_message = "Yes, reported {$stopforumspam_info['username']['frequency']} time(s)";
		}
		if($stopforumspam_info['email']['appears'])
		{
			$report_spammer_button_text = 'Confirm spammer report';
			$email_spammer_class = 'spammer_yes';
			$email_spammer_message = "Yes, reported {$stopforumspam_info['email']['frequency']} time(s)";
		}
	}
	$ip_addresses_var = array();
    // TODO: we could reduce the number of queries to StopForumSpam by batching them, but SFS supports only 15 items max per query
	foreach($ipaddresses as $ipaddress)
	{
		$ip_addresses_var[] = $ipaddress['ip'];
		$ip_addresses_spammer .= "
			<tbody>
				<tr>
					<td>{$ipaddress['title']}:</b></td><td>{$ipaddress['ip']}</td>
				</tr>";
		// fetch a URL into a string
		curl_setopt($ch, CURLOPT_URL, 'http://whatismyipaddress.com/ip/' . $ipaddress['ip']);
		$output = curl_exec($ch);
		preg_match('#Hostname:.*?<td>(.*?)</td>.*?ISP:.*?<td>(.*?)</td>.*?Organization:.*?<td>(.*?)</td>#', $output, $matches);
		$hostname = preg_replace('/(server)/i',  '<span class="spammer_yes">$1</span>', $matches[1]);
		$isp = preg_replace('/(server)/i',  '<span class="spammer_yes">$1</span>', $matches[2]);
		$organization = preg_replace('/(server)/i',  '<span class="spammer_yes">$1</span>', $matches[3]);
		$ip_addresses_spammer .= "
				<tr>
					<td>Hostname:</td><td>{$hostname}</td>
				</tr>
				<tr>
					<td>ISP:</td><td>{$isp}</td>
				</tr>
				<tr>
					<td>Organization</td><td>{$organization}</td>
				</tr>";		
		curl_setopt($ch, CURLOPT_URL, 'http://www.stopforumspam.com/api?ip=' . $ipaddress['ip'] . '&f=serial');
		$output = curl_exec($ch);
		$stopforumspam_info = unserialize($output);  // it's fine, this is not an eval
		if($stopforumspam_info['ip']['appears'])
		{
			$report_spammer_button_text = 'Confirm spammer report';
			$ip_addresses_spammer .= "
				<tr>
					<td>IP reported as spamming?</td><td class='spammer_yes'>Yes, {$stopforumspam_info['ip']['frequency']} time(s)</td>
				</tr>";
		}

		$ip_addresses_spammer .= "
			</tbody>";
	}

	curl_close($ch);

	$username = "'".$user['username']."'";
	$email = "'".$user['email']."'";
	$ip_addresses = "'".json_encode(array_values($ip_addresses_var))."'";
	eval("\$report_spammer = \"".$templates->get('report_spammer_display')."\";");
}


// called for all AJAX actions, e.g. validate username availability, CAPTCHA...
function report_spammer_ajax()
{
	global $mybb;
    // ... so we must only act on what pertains to our plugin
	if($mybb->input['action'] == 'report_spammer_do' && $mybb->input['ajax'] == 1)
	{
		if (empty($mybb->settings['report_spammer_StopForumSpam_key']))
		{
			echo json_encode(array(
				status => 'error',
				status_text => 'Please configure the StopForumSpam.com key in the <a href="' . $mybb->settings['bburl'] . '/admin/index.php?module=config-settings">plugin settings</a>.' 
			));
			exit;
		}

		if(!verify_post_check($mybb->input['my_post_key'], true))
		{
			echo json_encode(array(
				status => 'error',
				status_text => 'Authorization code mismatch' 
			));
			exit;
		}

		// http://stopforumspam.com/usage doesn't support adding multiple spammer IPs per query
		$ch = curl_init('http://www.stopforumspam.com/add.php');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  // don't output result, but return in a string
		curl_setopt($ch, CURLOPT_POST, true);
		$ipaddresses = json_decode($mybb->input['ipaddresses']);
		$ips_reported = 0;
		$stop_forum_spam_output = '';

		// report each IP
		foreach($ipaddresses as $ipaddress) {
			curl_setopt($ch, CURLOPT_POSTFIELDS, array(
				'username' => $mybb->input['username'],
				'email' => $mybb->input['email'],
				'ip_addr' => $ipaddress,
				'api_key' => $mybb->settings['report_spammer_StopForumSpam_key']
			));
			$stop_forum_spam_output .= curl_exec($ch);
			$info = curl_getinfo($ch);
			$ips_reported += ($info['http_code'] >= 200 && $info['http_code'] < 300);  // the return value is documented to be only 200 for success, but theoretically, any 2xx means success
		}

		curl_close($ch);

		if($ips_reported == 0)
		{
			echo json_encode(array(
				'status' => 'error',
				'status_text' => "Reporting spammer failed: $stop_forum_spam_output",
			));
		}
		else
		{
			$adjectives = array('annoying', 'braindead', 'dimwit', 'dopey', 'insensate', 'moronic', 'retarded', 'silly', 'stupid', 'witless');
			$random = array_rand($adjectives);
			$adjective = $adjectives[$random]; 

			echo json_encode(array(
				'status' => 'success',  // or partial success
				'status_text' => "Reported this $adjective spammer and $ips_reported of their " . count($ipaddresses) . " IP address(es).",
			));
		}
		exit;
	}
}

?>