<?php
/**
*
* @package ppkBB3cker
* @version $Id: announce.php 1.000 2009-04-06 10:40:00 PPK $
* @copyright (c) 2008, 2009 PPK, Based On skytracker, torrenttrader
* http://ppkbb3cker.rx22.ru, http://protoneutron.narod.ru
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
*/

define('IN_PHPBB', true);

$phpbb_root_path = (defined('PHPBB_ROOT_PATH')) ? PHPBB_ROOT_PATH : './../';
$phpEx = substr(strrchr(__FILE__, '.'), 1);
$tcachedir=$phpbb_root_path.'cache/';
$tincludedir=$phpbb_root_path.'tracker/tinc/';

require($phpbb_root_path . 'config.'.$phpEx);

if($dbms!='mysql')
{
	err('Only mysql supported');
}

$c=@mysql_connect($dbhost, $dbuser, $dbpasswd);
if(!$c)
{
	err('Error connecting database: '.mysql_error());
}

$s=@mysql_select_db($dbname, $c);
if(!$s)
{
	err('Error selecting database: '.mysql_error());
}

$dt = time();
$gmq_gpc = get_magic_quotes_gpc() ? 1 : 0;

$agent=@$_SERVER['HTTP_USER_AGENT'];
if (ereg("^(Mozilla|Opera|Links|Lynks)\\/", $agent))
{
	err("Invalid User Agent");
}
$agent = $gmq_gpc ? $agent : mysql_real_escape_string($agent);

$port = intval(@$_GET['port']);
if (!$port || $port > 65535)
{
	err("invalid port");
}

$uploaded = preg_replace('/[^0-9]/', '', @$_GET['uploaded']);
!$uploaded ? $uploaded=0 : '';

$downloaded =  preg_replace('/[^0-9]/', '', @$_GET['downloaded']);
!$downloaded ? $downloaded=0 : '';

$left = preg_replace('/[^0-9]/', '', @$_GET['left']);
!$left ? $left=0 : '';

$compact=intval(@$_GET['compact']);

$no_peer_id = intval(@$_GET['no_peer_id']);

$event=@$_GET['event'];
$event = ($event=='stopped' || $event=='completed' || $event=='started') ? $event : '';

$peer_id=$gmq_gpc ? stripslashes(@$_GET['peer_id']) : @$_GET['peer_id'];
$l_peer_id=strlen($peer_id);
if ($l_peer_id != 20)
{
	err("invalid peer_id: $peer_id ($l_peer_id)");
}
$peer_id = mysql_real_escape_string(base64_encode($peer_id));

$ip = $_SERVER['REMOTE_ADDR'];
$ip = $gmq_gpc ? $ip : mysql_real_escape_string($ip);
if (!validip($ip))
{
	err('Invalid OR Reserved IP');
}

$passkey = $gmq_gpc ? @$_GET['passkey'] : mysql_real_escape_string(@$_GET['passkey']);
if (!$passkey)
{
	err('PASSKEY NOT DEFINED');
}

$info_hash=@$_GET['?info_hash'] && @!$_GET['info_hash'] ? $_GET['?info_hash'] : @$_GET['info_hash'];
$gmq_gpc ? $info_hash=stripslashes($info_hash) : '';
$l_info_hash=strlen($info_hash);
if ($l_info_hash == 20)
{
	$info_hash=bin2hex($info_hash);
}
else if($l_info_hash != 40)
{
	err("invalid info_hash: $info_hash ($l_info_hash)");
}
$info_hash = mysql_real_escape_string($info_hash);

$seeder = ($left == 0) ? 'yes' : 'no';

define('USER_GROUP_TABLE',			$table_prefix . 'user_group');
define('ACL_GROUPS_TABLE',			$table_prefix . 'acl_groups');
define('ACL_USERS_TABLE',			$table_prefix . 'acl_users');
define('ACL_ROLES_DATA_TABLE',		$table_prefix . 'acl_roles_data');
define('USERS_TABLE',				$table_prefix . 'users');
define('TRACKER_TORRENTS_TABLE',			$table_prefix . 'tracker_torrents');
define('TRACKER_RESTRICTS_TABLE',			$table_prefix . 'tracker_restricts');
define('TRACKER_PEERS_TABLE',			$table_prefix . 'tracker_peers');
define('TRACKER_SNATCHED_TABLE',			$table_prefix . 'tracker_snatched');
define('TRACKER_CONFIG_TABLE',			$table_prefix . 'tracker_config');
define('FORUMS_TABLE',				$table_prefix . 'forums');
define('POSTS_TABLE',				$table_prefix . 'posts');
define('ATTACHMENTS_TABLE',			$table_prefix . 'attachments');
define('ACL_OPTIONS_TABLE',			$table_prefix . 'acl_options');
define('EXTENSIONS_TABLE',			$table_prefix . 'extensions');
define('EXTENSION_GROUPS_TABLE',	$table_prefix . 'extension_groups');
define('BANLIST_TABLE',				$table_prefix . 'banlist');

define('ANONYMOUS', 1);
define('USER_NORMAL', 0);
define('USER_FOUNDER', 3);

define('ACL_NEVER', 0);
define('ACL_YES', 1);
define('ACL_NO', -1);

my_sql_query("SET NAMES 'utf8'");

$cache_config=t_getcache('config');
if(!$cache_config)
{
	include($tincludedir.'tcache.'.$phpEx);
}
else
{
	foreach($cache_config as $k => $v)
	{
		$$k=$v;
	}
}
if($ppkbb_tctracker_disabled)
{
	err('Sorry, Tracker disabled');
}
if (!$allow_attachments)
{
	err('ATTACHMENT FUNCTIONALITY DISABLED');
}

$sql="SELECT tt.id, tt.seeders, tt.leechers, tt.times_completed, tt.added, tt.free, tt.size, tt.upload, tt.forb, tt.last_cleanup, tt.req_ratio, tt.req_upload, u.user_id, u.user_uploaded, u.user_downloaded, u.user_permissions, u.user_bonus, u.user_type FROM ".TRACKER_TORRENTS_TABLE." tt LEFT JOIN " . USERS_TABLE . " u ON u.user_passkey = '$passkey' WHERE tt.info_hash='$info_hash' AND u.user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ") LIMIT 1";

$result = my_sql_query($sql);
$user = mysql_fetch_array($result);
mysql_free_result($result);

$torrentid = $user['id'];
$numpeers=$user['seeders']+$user['leechers'];
$userid = $user['user_id'];

if (!$torrentid)
{
	err("Torrent not found on this tracker - hash = $info_hash ($l_info_hash)");
}

if ($user['forb'])
{
	err("Forbidden Torrent");
}

if(!$userid)
{
	err('NOT FOUND USER WITH THIS PASSKEY');
}
else
{
	if($ppkbb_tccheck_ban)
	{
		include($tincludedir.'tban.'.$phpEx);
	}
}

$updateset = array();

$ppkbb_tcclean_place=explode(' ', trim($ppkbb_tcclean_place));
if(@$ppkbb_tcclean_place[0] && $dt - $user['last_cleanup'] > $ppkbb_tccleanup_interval)
{
	my_sql_query('DELETE FROM '. TRACKER_PEERS_TABLE ." WHERE torrent='$torrentid' AND $dt - last_action > '{$ppkbb_tcdead_time}'");
	//if(mysql_affected_rows())
	//{
		$result=my_sql_query("SELECT SUM(IF(seeder='yes', 1, 0)) seeder, SUM(IF(seeder='no', 1, 0)) leecher FROM ". TRACKER_PEERS_TABLE ." WHERE torrent='$torrentid'");
		$t_seedleech=mysql_fetch_row($result);
		mysql_free_result($result);
		$t_seeders=intval($t_seedleech[0]);
		$t_leechers=intval($t_seedleech[1]);
	//}
	$updateset[]="last_cleanup='$dt'";
}

$selfwhere = "tp.torrent = '$torrentid' AND tp.peer_id='$peer_id'";

$sql="SELECT a.attach_id, a.in_message, a.extension, p.post_id, f.forum_id, f.forum_status, f.forum_password, f.forumas, tp.seeder, tp.last_action, tp.id, tp.uploaded, tp.downloaded, IF(tp.userid = '$userid', tp.rights, 0) rights
	FROM ".ATTACHMENTS_TABLE." a LEFT JOIN ".POSTS_TABLE." p ON p.post_id=a.post_msg_id LEFT JOIN ".FORUMS_TABLE." f ON f.forum_id=p.forum_id LEFT JOIN ". TRACKER_PEERS_TABLE ." tp ON $selfwhere
	WHERE a.attach_id = '$torrentid' LIMIT 1";

$result = my_sql_query($sql);
$attachment = mysql_fetch_array($result);
mysql_free_result($result);

if (!$attachment['attach_id'] || !$attachment['post_id'] || !$attachment['forum_id'])
{
	err('ERROR, NO ATTACHMENT OR POST OR FORUM');
}

if ($attachment['forum_status']==1)
{
	err('SORRY, FORUM LOCKED');
}

if (!$attachment['in_message'])
{
	$forum_astracker=$attachment['forumas']==1 ? 1 : 0;
	$forum_id=$attachment['forum_id'];

	if(!$forum_astracker)
	{
		err('THIS TORRENT NOT IN A TRACKER');
	}
}
else
{
	err('TRACKER FUNCTIONS DISABLED IN PM');
}

// disallowed?
if ($ppkbb_tccheck_fext)
{
	include($tincludedir.'tattach.'.$phpEx);
}
else
{
	if($attachment['extension']!='torrent')
	{
		err('Not .torrent extension');
	}
}

$limit = '';
$rsize = intval($ppkbb_tcmaxpeers_limit);
if(!$ppkbb_tcmaxpeers_rewrite)
{
	foreach(array('numwant', 'num want', 'num_want') as $k)
	{
		if (isset($_GET[$k]))
		{
			$rsize = intval($_GET[$k]);
			break;
		}
	}
}
if ($rsize && $numpeers && $numpeers > $rsize)
{
	$limit = "ORDER BY RAND() LIMIT $rsize";
}
if(!$ppkbb_tcignore_connectable)
{
	$limit="AND tp.connectable = 'yes' ".$limit;
}
$sql="SELECT tp.ip, tp.port".(!$no_peer_id ? ', tp.peer_id' : '')." FROM ". TRACKER_PEERS_TABLE ." tp WHERE tp.torrent = '$torrentid'".($attachment['id'] ? " AND tp.id!='{$attachment['id']}'" : '')." $limit";
$result = my_sql_query($sql);

$plist='';
$resp = "d8:completei{$user['seeders']}e10:downloadedi{$user['times_completed']}e10:incompletei{$user['leechers']}e";
$resp .= benc_str('interval') . 'i' . $ppkbb_tcannounce_interval . 'e'
	. benc_str('min interval') . 'i' . $ppkbb_tcminannounce_interval . 'e'
	. benc_str('peers') . ($compact ? '' : 'l');
while ($row = mysql_fetch_array($result))
{
	if($compact)
	{
		$peer_ip = explode('.', $row['ip']);
		$plist .= pack("C*", $peer_ip[0], $peer_ip[1], $peer_ip[2], $peer_ip[3]). pack("n*", (int) $row['port']);
	}
	else
	{
		$row['peer_id'] = str_pad(base64_decode(stripslashes($row['peer_id'])), 20);
		$resp .= "d" .
			benc_str('ip') . benc_str($row['ip']) .
			(!$no_peer_id ? benc_str('peer id') . benc_str($row['peer_id']) : '') .
			benc_str('port') . "i" . $row['port'] . "ee";
	}
}
mysql_free_result($result);
$resp .= ($compact ? benc_str($plist) : '') . 'ee';

$updateuser=array();
$updatesnatch=array();
$updatepeers=array();

$updatesnatch[]="to_go='$left'";
$updatepeers[]="to_go='$left'";

@$attachment['rights']!='' ? $rights=explode(' ', $attachment['rights']) : '';
if(@$attachment['rights']=='' || $forum_id!=@$rights[1] || $dt - @$rights[0] > $ppkbb_tcrights_tcache)
{
	include($tincludedir.'trights.'.$phpEx);
}
else
{
	array_shift($rights);
	array_shift($rights);
}

if ($rights[0])
{
	if ($attachment['forum_password'])
	{
		err('ACCESS FORBIDDEN, PASSWORD PROTECTED');
	}
}
else
{
	err('SORRY AUTH VIEW ATTACH');
}

if(!$rights[1] || !$rights[11])
{
	err("You can't use tracker, reason: ".(!$rights[11] ? '11' : '1'));
}

if($attachment['id'])
{
	$sql="DELETE FROM ".TRACKER_PEERS_TABLE." WHERE torrent='$torrentid' AND id!='{$attachment['id']}' AND userid='$userid'";
}
else
{
	$sql="DELETE FROM ".TRACKER_PEERS_TABLE." WHERE torrent='$torrentid' AND userid='$userid'";
}
$result=my_sql_query($sql);

if(($seeder=='yes' && $ppkbb_tcmax_seed && !$rights[7]) || ($seeder=='no' && ($ppkbb_tcmax_leech && !$rights[8]) || ($ppkbb_tcmaxleech_restr && !$rights[2])))
{
	include($tincludedir.'tmaxsl.'.$phpEx);
}
if(!$rights[13] && ($ppkbb_tcmaxip_pertorr || $ppkbb_tcmaxip_pertr))
{
	include($tincludedir.'tmaxip.'.$phpEx);
}
if (!$attachment['id'])
{
	include($tincludedir.'tanotself1.'.$phpEx);
}
else
{
	include($tincludedir.'taself1.'.$phpEx);
}

if ($event == "stopped")
{
	if($attachment['id'])
	{
		include($tincludedir.'taselfstopped.'.$phpEx);
	}
}
else
{
	if ($event == "completed")
	{
		$updatesnatch[] = "finished  = 'yes'";
		$updatesnatch[] = "completedat = '$dt'";

		$updateset[] = "times_completed = times_completed + 1";
	}

	if ($attachment['id'])
	{
		include($tincludedir.'taself2.'.$phpEx);
	}
	else
	{
		include($tincludedir.'tanotself2.'.$phpEx);
	}
}

if(!isset($t_updated) && isset($t_seeders))
{
	$updateset[]="seeders='$t_seeders'";
	$updateset[]="leechers='$t_leechers'";
}

if (sizeof($updateset))
{
	my_sql_query("UPDATE ". TRACKER_TORRENTS_TABLE ." SET " . implode(", ", $updateset) . " WHERE id = '$torrentid'");
}

benc_resp_raw($resp);

mysql_close();

exit();

//############################################################

function my_sql_query($query)
{
	global $startsqlcount, $c;

	$startsqlcount+=1;

	return mysql_query($query);
}

function t_getcache($t)
{
	global $tcachedir, $phpEx;

	$cache_data=array();
	@include($tcachedir.'data_ppkBB3cker_'.$t.'.'.$phpEx);

	return $cache_data;
}

function validip($ip)
{
	if (!empty($ip) && ip2long($ip)!=-1)
	{
		$reserved_ips = array (
				//array('0.0.0.0','2.255.255.255'),
				//array('10.0.0.0','10.255.255.255'),
				//array('127.0.0.0','127.255.255.255'),
				//array('169.254.0.0','169.254.255.255'),
				//array('172.16.0.0','172.31.255.255'),
				//array('192.0.2.0','192.0.2.255'),
				//array('192.168.0.0','192.168.255.255'),
				array('255.255.255.0','255.255.255.255')
		);

		foreach ($reserved_ips as $r)
		{
				$min = ip2long($r[0]);
				$max = ip2long($r[1]);
				if ((ip2long($ip) >= $min) && (ip2long($ip) <= $max)) return false;
		}
		return true;
	}
	else
	{
		return false;
	}
}

function err($msg)
{
	benc_resp(array("failure reason" => array('type' => "string", 'value' => $msg)));
	exit();
}

function warn($msg)
{
	benc_resp(array("warning message" => array('type' => "string", 'value' => $msg)));
	exit();
}

function benc($obj)
{
	if (!is_array($obj) || !isset($obj['type']) || !isset($obj['value']))
	{
		return;
	}
	$c = $obj['value'];
	switch ($obj['type'])
	{
		case "string":
			return benc_str($c);
		case "integer":
			return benc_int($c);
		case "list":
			return benc_list($c);
		case "dictionary":
			return benc_dict($c);
		default:
			return;
	}
}

function benc_str($s)
{
	return strlen($s) . ":$s";
}

function benc_int($i)
{
	return "i" . $i . "e";
}

function benc_list($a)
{
	$s = "l";
	foreach ($a as $e)
	{
		$s .= benc($e);
	}
	$s .= "e";
	return $s;
}

function benc_dict($d)
{
	$s = "d";
	$keys = array_keys($d);
	sort($keys);
	foreach ($keys as $k)
	{
		$v = $d[$k];
		$s .= benc_str($k);
		$s .= benc($v);
	}
	$s .= "e";
	return $s;
}

function benc_resp($d)
{
	benc_resp_raw(benc(array('type' => "dictionary", 'value' => $d)));
}

function benc_resp_raw($x)
{

	header("Content-Type: text/plain");
	header("Pragma: no-cache");

	if (@$_SERVER['HTTP_ACCEPT_ENCODING'] == 'gzip')
	{
		header("Content-Encoding: gzip");
		echo gzencode($x, 9, FORCE_GZIP);
	}
	else
	{
		print($x);
	}

}


function portblacklisted($port)
{
	// direct connect
	if ($port >= 411 && $port <= 413) return true;

	// bittorrent (AZUREUS)
	// if ($port >= 6881 && $port <= 6889) return true;

	// kazaa
	if ($port == 1214) return true;

	// gnutella
	if ($port >= 6346 && $port <= 6347) return true;

	// emule
	if ($port == 4662) return true;

	// winmx
	if ($port == 6699) return true;

	return false;
}
?>
