<?php
###############################################################################
# Whois.php
#
# @author Anil Kumar <akumar@codepunch.com>
# @link   https://codepunch.com
#
############################################################################### 

namespace 	CodePunch\LU;
use 		CodePunch\Base\Util as UTIL;
use			CodePunch\Base\Text as TEXT;

###############################################################################

class Whois  {
	
	private $lookupManager = null;
	
	###########################################################################
	
	public function __construct($lum=null) {
		$this->lookupManager = $lum;
	}
	
	###########################################################################
	
	public function Whois(&$ludata) 
	{
		$lookupcount = 0;
		$did = $ludata['sid'];
		$db = $this->lookupManager->getAuthentication()->getDatabase();
		$domain = $db->getDomainName($did);
		$ludata['api_profile'] = $db->findOneOf($db->getDomainTableName(), "sid", $did, "api_profile");
		if($domain !== false) {
			$server = $ludata['server'];
			if($server != "" && $server != "unknown") {
				if($this->lookupManager->isConnectionsAllowedToServer($server)) {
					$whoisdata = $this->whoislookup($domain, $server);
					$lookupcount++;
					$this->lookupManager->setLastConnectForServer($server);
					$parser = new \CodePunch\LU\WhoisParser($db, $whoisdata, $server);
					$dataarray = $parser->postProcess($domain);
					if(is_array($dataarray))
						$this->lookupManager->resetDomainData($domain);
					$dataarray['sid'] = $did;
					$this->lookupManager->updateDomainTable(\CodePunch\LU\LookupManager::DOMAIN_RECORDS, $dataarray);
					
					if((isset($dataarray['secondary_whois_server']) && $dataarray['secondary_whois_server'] != "") || ($ludata['api_profile'] != "" && $ludata['api_profile'] !== false)) {
						$status = false;
						$ludata['lutype'] = \CodePunch\LU\LookupManager::AUTH_DOMAIN_RECORDS;
						$lookupcount += $this->SecondaryWhois($ludata);
					}
					else
						$ludata['status'] = \CodePunch\LU\LookupManager::LUQ_COMPLETE;
					return $lookupcount;
				}
			}
			else {
				$logger = new \CodePunch\Base\CPLogger();
				$logger->error(TEXT::get("luq_whoissetup_error") . " [$domain]");
				$dataarray['primary_whois_checked_at'] = date("Y-m-d H:i:s");
				$dataarray['domain'] = $domain;
				$dataarray['registry_whois'] = "Error: " . TEXT::get("luq_whoissetup_error") . " [$domain]";
				$this->lookupManager->updateDomainTable(\CodePunch\LU\LookupManager::DOMAIN_RECORDS, $dataarray);
				$ludata['status'] = \CodePunch\LU\LookupManager::LUQ_UNSUPPORTED;
			}
		}
		else {
			$logger = new \CodePunch\Base\CPLogger();
			$logger->error(TEXT::get("luq_missingdomain"));
			$ludata['status'] = \CodePunch\LU\LookupManager::LUQ_UNSUPPORTED;
		}
		return $lookupcount;
	}
	
	###############################################################################
	// Will lookup the registrar whois server

	public function SecondaryWhois(&$ludata)
	{
		$did = $ludata['sid'];
		$db = $this->lookupManager->getAuthentication()->getDatabase();
		$domain = $db->getDomainName($did);
		if($domain !== false) {
			$secondary_whois_server = $db->findOneOf($db->getDomainTableName(), "sid", $did, "secondary_whois_server");
			if(isset($ludata['api_profile'])) {
				if($ludata['api_profile'] !== false && $ludata['api_profile'] != "") {
					$whois02 = $this->lookupManager->getWhoisFromRegistrar($domain, $ludata['api_profile']);
					if($whois02 !== false) {
						$parser = new \CodePunch\LU\WhoisParser($db, $whois02, $secondary_whois_server);
						$data_array02 = $parser->processRegistrarData($domain);
						if(is_array($data_array02))
						{
							if(function_exists("sedf_after_registrar_whois_check"))
								sedf_after_registrar_whois_check($domain, $secondary_whois_server, $whois02, $data_array02, $spit_out);
							$data_array02['sid'] = $did;
							$this->lookupManager->updateDomainTable(\CodePunch\LU\LookupManager::AUTH_DOMAIN_RECORDS, $data_array02);
							$ludata['status'] = \CodePunch\LU\LookupManager::LUQ_COMPLETE;
							return 1;
						}
					}
				}
			}
			$secondary_whois_server = $db->findOneOf($db->getDomainTableName(), "sid", $did, "secondary_whois_server");
			if($secondary_whois_server !== false && $secondary_whois_server != "") {
				if($this->lookupManager->isConnectionsAllowedToServer($secondary_whois_server)) {
					$whois02 = $this->whoislookup($domain, $secondary_whois_server);
					$this->lookupManager->setLastConnectForServer($secondary_whois_server);
					if($whois02 == "")
						$whois02 = "Whois returned an empty result!";
					$parser = new \CodePunch\LU\WhoisParser($db, $whois02, $secondary_whois_server);
					$data_array02 = $parser->processRegistrarData($domain);
					if(is_array($data_array02))
					{
						if(function_exists("sedf_after_registrar_whois_check"))
							sedf_after_registrar_whois_check($domain, $secondary_whois_server, $whois02, $data_array02, $spit_out);
						$data_array02['sid'] = $did;
						$this->lookupManager->updateDomainTable(\CodePunch\LU\LookupManager::AUTH_DOMAIN_RECORDS, $data_array02);
						$ludata['status'] = \CodePunch\LU\LookupManager::LUQ_COMPLETE;
						return 1;
					}
					else
					{
						$wlines = explode("\n", $whois02);
						$rwdata = implode("<br>", $wlines);
						$rwdata = UTIL::toUTF8($rwdata);
						$data_array02['registrar_whois']  = $rwdata;
						$this->lookupManager->updateDomainTable(\CodePunch\LU\LookupManager::AUTH_DOMAIN_RECORDS, $data_array02);
						$ludata['status'] = \CodePunch\LU\LookupManager::LUQ_COMPLETE;
						return 1;
					}
				}
				else {
					// Busy, The LU will get queued again. 
				}
			}
			else {
				// Nothing can be done without a whois server.
				// Mark as complete.
				$logger = new \CodePunch\Base\CPLogger();
				$logger->error(TEXT::get("luq_no_registrar_whois_server_error") . " [$domain]");
				$ludata['status'] = \CodePunch\LU\LookupManager::LUQ_COMPLETE;
			}
		}
		return 0;
	}
	
	###############################################################################
	
	public function whoisThroughProxy($domain, $server, $proxy) 
	{
		$turl = str_replace("{D}", $domain, $proxy);
		$turl = str_replace("{S}", $server, $turl);
		
		// Handle URL of the form json:whois:http://......
		$jskey = "";
		$tp = strpos($turl, "json:");
		if($tp !== false && $tp == 0)
		{
			$tp1 = strpos($turl, ":http");
			if($tp1 !== false)
			{
				$jskey = substr($turl, $tp+5, $tp1-5);
				$turl = substr($turl, $tp1+1);
			}
		}
		
		$data = file_get_contents($turl);
		if($data === false)
			$data = "Error - unable to connect to $turl";
		else if($jskey != "")
		{
			$jdata = json_decode($data);
			if(isset($jdata[$jskey]))
				$data = $jdata[$jskey];
		}
		return strip_tags($data);
	}
	
	###############################################################################

	public function whoislookup($domain, $server)
	{
		$db = $this->lookupManager->getAuthentication()->getDatabase();
		$server = str_replace('/', '', strtolower($server));  // Remove any unwanted / in whois server
		$domain = UTIL::idn_convert($domain);
		$sinfo = $db->getWhoisServerInfo($server);
		if($sinfo !== false)
		{
			$proxy = trim($sinfo['proxy']);
			if($proxy != "") 
				return $this->whoisThroughProxy($domain, $server, $proxy);
		}
		else {
			$sinfo = [];
			$sinfo['query'] = "";
			$sinfo['port'] = 43;
			$sinfo['bannedtext'] = "";
		}
		
		$query = $this->createWhoisQuery($sinfo['query'], $domain);	
		$m_connectiontimeout = 10;
		$m_sockettimeout = 30;
		$port = $sinfo['port'] > 0 ? $sinfo['port'] : 43;
		$bannedtext = $sinfo['bannedtext'];
		if($bannedtext == "") {
			$bannedtext =  "You have exceeded your access quota. Please try again later|You have been banned for abuse";
			$bannedtext .= "|IP Address Has Reached Rate Limit|Query limit exceeded, please try again later|maximum number of requests per second exceeded";
		}
		
		$data = "";
		if($query != '' && $server != '' ) 
		{
			//$output = UTIL::Whois($query, $server, $port, $m_connectiontimeout);
			$output = $this->Socks5Whois($query, $server, $port, $m_connectiontimeout);
			if($output['status'] === false) {
				$extramsg = "";
				if($output['errno'] == 13)
					$extramsg = "Please <b>check if SELinux is enabled</b>. ";
				$extramsg .= "You may want to see the trouble shooting page at https://learn.domainpunch.com/wmdsed/install/troubleshooting/";
				$data = "Error - unable to connect to $server.\n\n" . $output['error'] . "\n\n$extramsg";
			}
			else {
				$data = $output['data'];
			}
		}
		
		if(strlen($data) > 0 && strlen($bannedtext) > 0) {
			$parts = array_filter(explode("|", $bannedtext));
			foreach($parts as $part) {
				if(stristr($data, $part) !== false) {
					$this->lookupManager->blockWhoisServer($server);
					break;
				}
			}
		}
		
		return $data;
	}
	
	###############################################################################
	
	public function Socks5Whois($query, $server, $whois_port=43, $timeout=10) {
		$whoisdata = false;
		$ext_proxy = $this->lookupManager->getProxy('whois');
		if($ext_proxy && $ext_proxy['type'] == 'socks5') {
			$options = [
				'host' => $ext_proxy['url'],
				'port' => intval($ext_proxy['port']),
				'connect_timeout' => 5.0
			];
			if(strlen($ext_proxy['user'])) {
				$options['auth'] = ['username' => $ext_proxy['user'], 'password' => $ext_proxy['password']];
			}
			$client = new \PhpSocks\Client($options);
			try {
				$cs = 'tcp://' . $server . ':' . $whois_port;
				$stream = $client->connect($cs);
				$stream->write($query . "\r\n");
				$whoisdata = $stream->readAll();
				$stream->close();
				return array('status'=>true, 'data'=>$whoisdata);
			} 
			catch (\PhpSocks\Exception\PhpSocksException $e) {
				echo($e->getMessage());
				return array('status'=>false, 'errno'=>0, 'error'=>$e->getMessage());
			}
		}
		else
			return UTIL::Whois($query, $server, $whois_port, $timeout);
	}
	
	###############################################################################

	private function createWhoisQuery($prefix, $domain)
	{
		$query = $domain;
		$prefix = empty($prefix) ? "" : trim($prefix);
		if($prefix != "")
		{
			$query = $prefix;
			if(strstr($query, "{D}"))
				$query = str_replace("{D}", $domain, $query);
			else if(strstr($query, "{d}"))
			{
				$pos = mb_strrpos($domain, ".");
				if($pos !== false)
				{
					$nameonly = mb_substr($domain, 0, $pos);
				$query = str_replace("{d}", $nameonly, $query);
				}
				else
					$query .= " " . $domain;
			}
			else
				$query .= " " . $domain;
		}
		return $query;
	}

	###############################################################################
	
	public static function hasWhoisPort($server, $timeout=20)
	{
		$hip = gethostbyname($server);
		if($hip != $server) {
			$fp = @fsockopen($hip, 43, $errno, $errstr, $timeout);
			if( $fp ) {
				@fclose($fp);
				return true;
			}
		}
		return false;
	}
}

###############################################################################
