#!/usr/local/psa/admin/bin/php
<?php

define('APP_PATH', dirname(__FILE__));
define('DEBUG', 0); // allow to dump sql logs to output
define('PRE_TRANSFER_SCRIPT_VERSION', '11.0.9.11'); //script version
define('PLESK_VERSION', '11.0.9'); // latest Plesk version
define('DUMP_FILENAME', 'panel_pre_transfer.dump');   
if (!defined('PHP_EOL')) {
    define('PHP_EOL', "\n", true);
}

$phpType = php_sapi_name();
if (substr($phpType, 0, 3) == 'cgi') {
    //:INFO: set max execution time 1hr
    @set_time_limit(3600);
}

@date_default_timezone_set(@date_default_timezone_get());


class GetOpt
{
    var $_argv = null;
    var $_argc = null;
	var $_adminDbPasswd = null;
	var $_host = null;
	var $_login = null;
    var $_port = null;
    var $_dump = null;
    var $_source_adminDbPasswd = null;
    
    function GetOpt()
    {
        $this->_argv = $_SERVER['argv'];
        $this->_argc = $_SERVER['argc'];
        
        if (in_array('--source', $this->_argv) && (in_array('--dump', $this->_argv))) {
        	Log::error('--source and --dump options can not be used thogether');
    		return $this->_helpUsage();
    	}
    		
        if (Util::isWindows()) {
        	if (!in_array('--source', $this->_argv)) {
        		if (!in_array('--dump', $this->_argv)) {
	        		return $this->_helpUsageWindows();
	        	}	
        	}
        	
        	if (in_array('--source', $this->_argv)) {
        		if ($this->_argc < 2) {
        			Log::error('Too few arguments for --source');
	        		return $this->_helpUsageWindows();
	        	}	
        	}
        	
        	if (in_array('--dump', $this->_argv)) {
        		if ($this->_argc < 3) {
        			Log::error('Too few arguments for --dump');
	        		return $this->_helpUsageWindows();
	        	}	
        	}
        } else {
        	if (in_array('--source', $this->_argv)) { 
        		if ($this->_argc < 2) {
        			Log::error('Too few arguments for --source');
        			return $this->_helpUsageLinux();
        		}
        	} else if (in_array('--dump', $this->_argv)) { 
        		if ($this->_argc < 3) {
        			Log::error('Too few arguments for --dump');
        			return $this->_helpUsageLinux();
        		}
        	} else {
        		if ($this->_argc < 7) {
        			Log::error('Too few arguments.');
        			return $this->_helpUsageLinux();
        		}
        		for ($i = 1; $i < $this->_argc; ++$i) {
					$arg = $this->_argv[$i];
					if ($arg == '-s')
						$this->_host = $this->_argv[++$i];
					else if ($arg == '-l')
						$this->_login = $this->_argv[++$i];
					else if ($arg == '-P')
						$this->_port = $this->_argv[++$i];
					else {
						Log::error('Not enough arguments');
						return $this->_helpUsageLinux();
					}
        		}
        	}
        }
        
        // common options
		$this->_adminDbPasswd = $this->_argv[1];
		
		for ($i = 1; $i < $this->_argc; ++$i) {
			$arg = $this->_argv[$i];
			if ($arg == '--dump') {
				$this->_dump = $this->_argv[++$i];
				if (empty($this->_dump)) {
					Log::error('--dump is empty');
					return $this->_helpUsage();
				}
			}
        }
    }
    
    function isSource()
    {
    	
    	if (in_array('--source', $this->_argv)) {
    		return true;
    	} else {
    		return false;
    	}
    }	
    
    function getDbPasswd()
    {
    	if (Util::isWindows()) {
    		$this->_adminDbPasswd = get_admin_password();
		} else {
			$this->_adminDbPasswd = file_get_contents('/etc/psa/.psa.shadow');
    	}
    	
    	return $this->_adminDbPasswd;
    }
    
    function _helpUsage()
    {
    	if (Util::isWindows()) {
    		echo PHP_EOL . "Usage: {$this->_argv[0]} [--source | --dump file]" . PHP_EOL;
    	} else {
        	echo PHP_EOL . "Usage: {$this->_argv[0]} [--source] [--dump file] | <-s host> <-l login> <-P port>" . PHP_EOL;
    	}
        exit(1);
    }
    
    function _helpUsageWindows()
    {
    	
    	echo PHP_EOL . "Usage: {$this->_argv[0]} <plesk_db_admin_password> [--source | --dump file]" . PHP_EOL;
    	exit(1);
    }
    
    function _helpUsageLinux()
    {
    	echo PHP_EOL . "Usage: {$this->_argv[0]} <plesk_db_admin_password> <-s host> <-l login> <-P port> <-p source_plesk_db_admin_password>" . PHP_EOL;
        exit(1);
    }
}

class PleskOS
{
	function isSuse103()
	{
		return PleskOS::_detectOS('suse', '10.3');
	}

	function isUbuntu804()
	{
		return PleskOS::_detectOS('ubuntu', '8.04');
	}

	function isDebLike()
	{
		if (PleskOS::_detectOS('ubuntu', '.*')
				|| PleskOS::_detectOS('debian', '.*')
		) {
			return true;
		}
		return false;
	}

	function isSuseLike()
	{
		if (PleskOS::_detectOS('suse', '.*')) {
			return true;
		}
		return false;
	}

	function isRedHatLike()
	{
		return (PleskOS::isRedHat() || PleskOS::isCentOS() || PleskOS::isCloudLinux());
	}


	function isRedHat()
	{
		if (PleskOS::_detectOS('red hat', '.*')) {
			return true;
		}
		return false;
	}

	function isCentOS()
	{
		if (PleskOS::_detectOS('centos', '.*')) {
			return true;
		}
		return false;
	}

	function isCloudLinux()
	{
		return PleskOS::_detectOS('CloudLinux', '.*');
	}

	function isWindows2003()
	{
		if (!Util::isWindows()) {
			return false;
		}
		 
		$version = Util::regQuery('\Microsoft\Windows NT\CurrentVersion', '/v CurrentVersion', true);
		if (version_compare($version, '5.0', '>=') && version_compare($version, '6.0', '<')) {
			return true;
		}
	}

	function isWindows2008()
	{
		if (!Util::isWindows()) {
			return false;
		}

		$version = Util::regQuery('\Microsoft\Windows NT\CurrentVersion', '/v CurrentVersion', true);
		if (version_compare($version, '6.0', '>=') && version_compare($version, '6.1', '<=')) {
			return true;
		}
	}

	function _detectOS($name, $version)
	{
		$output = PleskOS::catEtcIssue();
		// This is wrong in a general case! There might be additional text between name and version.
		if (!preg_match("/{$name}[\s]+$version/i", $output)) {
			return false;
		}
		return true;
	}
	 
	function catEtcIssue()
	{
		$cmd = 'cat /etc/issue';
		$output = Util::exec($cmd, $code);

		return $output;
	}

	function detectSystem()
	{
		Log::step('Detect system configuration');

		Log::info('OS: ' . (Util::isLinux() ? PleskOS::catEtcIssue() : 'Windows'));
		Log::info('Arch: ' . Util::getArch());
	}
}

class Log
{
    function Log()
    {
        $this->_logFile = APP_PATH . '/panel_pre_transfer_checker.log';
        @unlink($this->_logFile);
    }
    
    function _getInstance()
    {
        static $_instance = null;
        if (is_null($_instance)) {
            $_instance = new Log();
        }
        return $_instance;
    }
    
    function fatal($msg)
    {
        $log = Log::_getInstance();
        $log->_log($msg, 'FATAL_ERROR');
    }
    
    function error($msg)
    {
        $log = Log::_getInstance();
        $log->_log($msg, 'ERROR');
    }
    
    function warning($msg)
    {
        $log = Log::_getInstance();
        $log->_log($msg, 'WARNING');
    }
    
    function emergency($msg)
    {
    	$log = Log::_getInstance();
    	$log->_log($msg, 'EMERGENCY');
    }
    
    function step($msg, $useNumber=false)
    {
        static $step = 1;
        
        if ($useNumber) {
            $msg = "==> STEP " . $step . ": {$msg}";
            $step++;
        } else {
            $msg = "==> {$msg}";
        }
        
        $log = Log::_getInstance();
        $log->_log($msg, 'INFO', PHP_EOL);
    }
    
    function resultOk()
    {
        $msg = 'Result: OK';
        Log::info($msg);
    }
    
    function resultWarning()
    {
        $msg = 'Result: Warning';
        Log::info($msg);
    }
    
    function resultError()
    {
        $msg = 'Result: Error';
        Log::info($msg);
    }
    
    function info($msg)
    {
        $log = Log::_getInstance();
        $log->_log($msg, 'INFO');
    }
    
    function dumpStatistics()
    {
        global $errors, $warnings;
        
        $str = 'Found errors: ' . $errors 
            . '; Found Warnings: ' . $warnings
        ;
        echo PHP_EOL . $str . PHP_EOL . PHP_EOL;
    }
    
    function _log($msg, $type, $newLine='')
    {
        global $errors, $warnings, $emergency;

		// TODO modern PHP (from 5.3) issues warning:
		//  PHP Warning:  date(): It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting 
		//  or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most 
		//  likely misspelled the timezone identifier. We selected 'America/New_York' for 'EDT/-4.0/DST' instead in 
		//  panel_preupgrade_checker.php on line 1282
    	if (getenv('AUTOINSTALLER_VERSION')) {
            $log = $newLine . "{$type}: {$msg}" . PHP_EOL;
    	} else {
            $date = date('Y-m-d h:i:s');
            $log = $newLine . "[{$date}][{$type}] {$msg}" . PHP_EOL;
        }
		if ($type == 'EMERGENCY') {
			$emergency++;
			fwrite(STDERR, $log);
		} elseif ($type == 'ERROR' || $type == 'FATAL_ERROR') {
            $errors++;
            fwrite(STDERR, $log);
        } elseif ($type == 'WARNING') {
            $warnings++;
            fwrite(STDERR, $log);
        } elseif ($type == 'INFO') {
            //:INFO: Dump to output and write log to the file
            echo $log;
        }
        
        Log::write($this->_logFile, $log);
        
        //:INFO: Terminate the process if have the fatal error
        if ($type == 'FATAL_ERROR' || $type == 'EMERGENCY' ) {
            exit(1);
        }
    }
    
    function write($file, $content, $mode='a+')
    {
        $fp = fopen($file, $mode);
        fwrite($fp, $content);
        fclose($fp);
    }
}

class PleskDb
{
    var $_db = null;
    
    function PleskDb($dbParams)
    {
        switch($dbParams['db_type']) {
            case 'mysql':
                $this->_db = new DbMysql(
                    $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port']
                );
                break;
                
            case 'jet':
                $this->_db = new DbJet($dbParams['db']);
                break;
                
            case 'mssql':
                $this->_db = new DbMsSql(
                    $dbParams['host'], $dbParams['login'], $dbParams['passwd'], $dbParams['db'], $dbParams['port']
                );
                break;

            default:
                Log::fatal("{$dbParams['db_type']} is not implemented yet");
                break;
        }
    }
    
    function getInstance()
    {
        global $options;
        static $_instance = array();
        
        $dbParams['db_type']= Util::getPleskDbType();
        $dbParams['db']     = Util::getPleskDbName();
        $dbParams['port']   = Util::getPleskDbPort();
        $dbParams['login']  = Util::getPleskDbLogin();
        $dbParams['passwd'] = $options->getDbPasswd();
        $dbParams['host']   = Util::getPleskDbHost();
        
        $dbId = md5(implode("\n", $dbParams));

		$_instance[$dbId] = new PleskDb($dbParams);
        
        return $_instance[$dbId];
    }
    
    function fetchOne($sql)
    {
        if (DEBUG) {
            Log::info($sql);
        }
        return $this->_db->fetchOne($sql);
    }
    
    function fetchRow($sql)
    {
    	if (DEBUG) {
            Log::info($sql);
        }
        $res = $this->fetchAll($sql);
        if (is_array($res) && isset($res[0])) {
            return $res[0];
        }
        return array();
    }
    
    function fetchCol($sql)
    {
    	if (DEBUG) {
            Log::info($sql);
        }
        return $this->_db->fetchCol($sql);
    }
    
    
    function fetchAll($sql)
    {
        if (DEBUG) {
            Log::info($sql);
        }
        return $this->_db->fetchAll($sql);
    }
}

class DbMysql
{
    var $_dbHandler = null;
    
    function DbMysql($host, $user, $passwd, $database, $port)
    {
        if ( extension_loaded('mysql') ) {
            $this->_dbHandler = @mysql_connect("{$host}:{$port}", $user, $passwd);
            if (!is_resource($this->_dbHandler)) {
                $mysqlError = mysql_error();
                if (stristr($mysqlError, 'access denied for user')) {
                    $errMsg = 'Given <password> is incorrect. ' . $mysqlError;
                } else {
                    $errMsg = 'Unable to connect to MySQL. Check that MySQL service is running. Last error: ' . $mysqlError . PHP_EOL;
                }
                $this->_logError($errMsg);
            }
            @mysql_select_db($database, $this->_dbHandler);
        } else if ( extension_loaded('mysqli') ) {

            $this->_dbHandler = @mysqli_connect($host, $user, $passwd, $database, $port);
            if (!$this->_dbHandler) {
                $mysqlError = mysqli_connect_error();
                if (stristr($mysqlError, 'access denied for user')) {
                    $errMsg = 'Given <password> is incorrect. ' . $mysqlError;
                } else {
                    $errMsg = 'Unable to connect database. The reason of problem: ' . $mysqlError . PHP_EOL;
                }
                $this->_logError($errMsg);
            }
        } else {
            Log::fatal("No MySQL extension is available");
        }
    }
    
    function fetchAll($sql)
    {
        if ( extension_loaded('mysql') ) {
            $res = mysql_query($sql, $this->_dbHandler);
            if (!is_resource($res)) {
                $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler));
            }
            $rowset = array();
            while ($row = mysql_fetch_assoc($res)) {
                $rowset[] = $row;
            }
            return $rowset;
        } else if ( extension_loaded('mysqli') ) {
            $res = $this->_dbHandler->query($sql);
            if ($res === false) {
                $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler));
            }
            $rowset = array();
            while ($row = mysqli_fetch_assoc($res)) {
                $rowset[] = $row;
            }
            return $rowset;
        } else {
            Log::fatal("No MySQL extension is available");
        }
    }
    
    function fetchCol($sql)
    {
        if ( extension_loaded('mysql') ) {
            $res = mysql_query($sql, $this->_dbHandler);
            if (!is_resource($res)) {
                $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler));
            }
            $rowset = array();
            while ($row = mysql_fetch_array($res, MYSQL_BOTH)) {
                $rowset[] = $row[0];
            }
            return $rowset;
        } else if ( extension_loaded('mysqli') ) {
            $res = $this->_dbHandler->query($sql);
            if ($res === false) {
                $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler));
            }
            $rowset = array();
            while ($row = mysqli_fetch_array($res, MYSQL_BOTH)) {
                $rowset[] = $row[0];
            }
            return $rowset;
        } else {
            Log::fatal("No MySQL extension is available");
        }
    }
    
    function fetchOne($sql)
    {
        if ( extension_loaded('mysql') ) {
            $res = mysql_query($sql, $this->_dbHandler);
            if (!is_resource($res)) {
                $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler));
            }
            $row = mysql_fetch_row($res);
            return $row[0];
        } else if ( extension_loaded('mysqli') ) {
            $res = $this->_dbHandler->query($sql);
            if ($res === false) {
                $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler));
            }
            $row = mysqli_fetch_row($res);
            return $row[0];
        } else {
            Log::fatal("No MySQL extension is available");
        }
    }    
    
    function query($sql)
    {
        if ( extension_loaded('mysql') ) {
            $res = mysql_query($sql, $this->_dbHandler);
            if ($res === false ) {
                $this->_logError('Unable to execute query. Error: ' . mysql_error($this->_dbHandler) );
            }
            return $res;
        } else if ( extension_loaded('mysqli') ) {
            $res = $this->_dbHandler->query($sql);
            if ($res === false ) {
                $this->_logError('Unable to execute query. Error: ' . mysqli_error($this->_dbHandler) );
            }
            return $res;
        } else {
            Log::fatal("No MySQL extension is available");
        }
    }    
    
    function _logError($message)
    {
        $message = "[MYSQL ERROR] $message";
        Log::fatal($message);
    }
}

class DbClientMysql extends DbMysql
{
    var $errors = array();

    function _logError($message)
    {
        $message = "[MYSQL ERROR] $message";
        Log::warning($message);
        $this->errors[] = $message;
    }

    function hasErrors() {
        return count($this->errors) > 0;
    }
}

class DbJet
{
    var $_dbHandler = null;
    
    function DbJet($dbPath)
    {
        $dsn = "Provider='Microsoft.Jet.OLEDB.4.0';Data Source={$dbPath}";
        $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8);
        if (!$this->_dbHandler) {
            $this->_logError('Unable to init ADODB.Connection');
        }
        
        $this->_dbHandler->open($dsn);
    }
    
    function fetchAll($sql)
    {
        $result_id = $this->_dbHandler->execute($sql);
        if (!$result_id) {
            $this->_logError('Unable to execute sql query ' . $sql);
        }
		if ($result_id->BOF && !$result_id->EOF) {
            $result_id->MoveFirst();
		}
		if ($result_id->EOF) {
		    return array();
		}
		
		$rowset = array();
		while(!$result_id->EOF) {
    		$row = array();
    		for ($i=0;$i<$result_id->Fields->count;$i++) {
                $field = $result_id->Fields($i);
                $row[$field->Name] = (string)$field->value;
    		}
    		$result_id->MoveNext();
    		$rowset[] = $row;
		}
		return $rowset;
    }
    
    function fetchCol($sql)
    {
        $result_id = $this->_dbHandler->execute($sql);
        if (!$result_id) {
            $this->_logError('Unable to execute sql query ' . $sql);
        }
		if ($result_id->BOF && !$result_id->EOF) {
            $result_id->MoveFirst();
		}
		if ($result_id->EOF) {
		    return array();
		}
		
		$rowset = array();
		while(!$result_id->EOF) {
            $field = $result_id->Fields(0);
            $rowset[] = (string)$field->value;
    		$result_id->MoveNext();
		}
		return $rowset;
    }
    
    function fetchOne($sql)
    {
        $result_id = $this->_dbHandler->execute($sql);
        if (!$result_id) {
            $this->_logError('Unable to execute sql query ' . $sql);
        }
		if ($result_id->BOF && !$result_id->EOF) {
            $result_id->MoveFirst();
		}
		if ($result_id->EOF) {
		    //Log::fatal('Unable to find row');
		    return null;
		}
        $field = $result_id->Fields(0);
        $result = $field->value;
        
        return (string)$result;
    }
    
    function _logError($message)
    {
        $message = "[JET ERROR] $message";
        Log::fatal($message);
    }
}

class DbMsSql extends DbJet
{
    function DbMsSql($host, $user, $passwd, $database, $port)
    {
        $dsn = "Provider=SQLOLEDB.1;Initial Catalog={$database};Data Source={$host}";
        $this->_dbHandler = new COM("ADODB.Connection", NULL, CP_UTF8);
        if (!$this->_dbHandler) {
            $this->_logError('Unable to init ADODB.Connection');
        }
        $this->_dbHandler->open($dsn, $user, $passwd);
    }
    
    function _logError($message)
    {
        $message = "[MSSQL ERROR] $message";
        Log::fatal($message);
    }
}

class PleskVersion
{
    function is8x()
    {
        $version = PleskVersion::getVersion();
        return version_compare($version, '8.0.0', '>=') && version_compare($version, '9.0.0', '<');
    }

    function is9x()
    {
        $version = PleskVersion::getVersion();
        return version_compare($version, '9.0.0', '>=') && version_compare($version, '10.0.0', '<');
    }
    
    function is9x_or_above()
    {
    	$version = PleskVersion::getVersion();
    	return version_compare($version, '9.0.0', '>=');
    }

    function is10x()
    {
        $version = PleskVersion::getVersion();
        return version_compare($version, '10.0.0', '>=') && version_compare($version, '11.0.0', '<');
    }
    
    function is11x()
    {
        $version = PleskVersion::getVersion();
        return version_compare($version, '11.0.0', '>=') && version_compare($version, '12.0.0', '<');
    }
    
    function is10_0()
    {
    	$version = PleskVersion::getVersion();
    	return version_compare($version, '10.0.0', '>=') && version_compare($version, '10.1.0', '<');
    }
    
    function is10x_or_above()
    {
    	$version = PleskVersion::getVersion();
    	return version_compare($version, '10.0.0', '>=');
    }
    
    function is10_1_or_below()
    {
    	$version = PleskVersion::getVersion();
    	return version_compare($version, '10.1.1', '<=');
    }
    
    function is10_2_or_above()
    {
    	$version = PleskVersion::getVersion();
    	return version_compare($version, '10.2.0', '>=');
    }
    
    function is10_3_or_above()
    {
    	$version = PleskVersion::getVersion();
    	return version_compare($version, '10.3.0', '>=');
    }
    
    function is10_4()
    {
    	$version = PleskVersion::getVersion();
    	return version_compare($version, '10.4.0', '>=') && version_compare($version, '10.5.0', '<');
    }
    
    function is10_4_or_above()
    {
    	$version = PleskVersion::getVersion();
    	return version_compare($version, '10.4.0', '>=');
    }
    
    function is11_0_or_above()
    {
    	$version = PleskVersion::getVersion();
    	return version_compare($version, '11.0.0', '>=');
    }
    
    function getVersion()
    {
        $version = PleskVersion::getVersionAndBuild();
        if (!preg_match('/([0-9]+[.][0-9]+[.][0-9])/', $version, $macthes)) {
            Log::fatal("Incorrect Plesk version format. Current version: {$version}");
        }
        return $macthes[1];
    }
    
    function getVersionAndBuild()
    {
        $versionPath = Util::getPleskRootPath().'/version';
        if (!file_exists($versionPath)) {
            Log::fatal("Plesk version file is not exists $versionPath");
        }
        $version = file_get_contents($versionPath);
        $version = trim($version);
        return $version;
    }
    
    function getLatestPleskVersionAsString()
    {
        return 'Parallels Panel ' . PLESK_VERSION;
    }
}

class Package
{
	function getManager($field, $package)
	{
	    $redhat = 'rpm -q --queryformat \'%{' . $field . '}\n\' ' . $package;
    	$debian = 'dpkg-query --show --showformat=\'${' . $field . '}\n\' '. $package;
    	$suse = 'rpm -q --queryformat \'%{' . $field . '}\n\' ' . $package;
    	$manager = false;
    	
    	if (PleskOS::isRedHatLike()) {
    		$manager = $redhat;
    	} elseif (PleskOS::isDebLike()) {
    		$manager = $debian;
    	} elseif (PleskOS::isSuseLike()) {
    		$manager = $suse;
    	} else {
    		return false;
    	}
    	
    	return $manager;
	}
	
	/* DPKG doesn't supports ${Release}
	 *  
	 */

	function getRelease($package)
	{
		$release = false;
		
		$manager = Package::getManager('Release', $package);
		
		if (!$manager) {
			return false;
		}		
		
		$release = Util::exec($manager, $code);
		if (!$code === 0) {
			return false;
		}
		return $release;
	}
	
	function getVersion($package)
	{
		$version = false;
		
		$manager = Package::getManager('Version', $package);
		
		if (!$manager) {
			return false;
		}
		
		$version = Util::exec($manager, $code);
		if (!$code === 0) {
			return false;
		}
		return $version;
	}
}

class Util
{
    function isWindows()
    {
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            return true;
        }
        return false;
    }
    
    function isLinux()
    {
        return !Util::isWindows();
    }
	
    function exec($cmd, &$code)
    {
        exec($cmd, $output, $code);
        return trim(implode("\n", $output));
    }
	
	function getArch()
    {
        global $arch;
        if (!empty($arch))
            return $arch;

        $arch = 'i386';
        if (Util::isLinux()) {
            $cmd = 'uname -m';
            $x86_64 = 'x86_64';
            $output = Util::exec($cmd, $code);
            if (!empty($output) && stristr($output, $x86_64)) {
                $arch = 'x86_64';
            }
        } else {
            $cmd = 'systeminfo';
            $output = Util::exec($cmd, $code);
            if (preg_match('/System Type:[\s]+(.*)/', $output, $macthes) && stristr($macthes[1], '64')) {
                $arch = 'x86_64';
            }
        }
        return $arch;
    }
    
    function getPleskRootPath()
    {
    	global $_pleskRootPath;
    	if (empty($_pleskRootPath)) {
    		if (Util::isLinux()) {
    			if (PleskOS::isDebLike()) {
    				$_pleskRootPath = '/opt/psa';
    			} else {
    				$_pleskRootPath = '/usr/local/psa';
    			}
    		}
    		if (Util::isWindows()) {
    			$_pleskRootPath = Util::regPleskQuery('PRODUCT_ROOT_D', true);
    		}
    	}

    	return $_pleskRootPath;
    }
    
    function getPleskDbName()
    {
        $dbName = 'psa';
        if (Util::isWindows()) {
            $dbName = Util::regPleskQuery('mySQLDBName');
        }
        return $dbName;
    }
    
    function getPleskDbLogin()
    {
        $dbLogin = 'admin';
        if (Util::isWindows()) {
            $dbLogin = Util::regPleskQuery('PLESK_DATABASE_LOGIN');
        }
        return $dbLogin;
    }
    
    function getPleskDbType()
    {
        $dbType = 'mysql';
        if (Util::isWindows()) {
            $dbType = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME'));
        }
        return $dbType;
    }
    
    function getPleskDbHost()
    {
    	$dbHost = 'localhost';
    	if (Util::isWindows()) {
    		$dbProvider = strtolower(Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME'));
    		if ($dbProvider == 'mysql' || $dbProvider == 'mssql') {
    			$dbHost = Util::regPleskQuery('MySQL_DB_HOST');
    		}
    	}
    	return $dbHost;
    }
    
    function getPleskDbPort()
    {
        $dbPort = '3306';
        if (Util::isWindows()) {
            $dbPort = Util::regPleskQuery('MYSQL_PORT');
        }
        return $dbPort;
    }
    
    function regPleskQuery($key, $returnResult=false)
    {
    	$arch = Util::getArch();
    	if ($arch == 'x86_64') {
    		$reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node\Plesk\Psa Config\Config" /v '.$key;
    	} else {
    		$reg = 'REG QUERY "HKLM\SOFTWARE\Plesk\Psa Config\Config" /v '.$key;
    	}
    	$output = Util::exec($reg, $code);
    
    	if ($returnResult && $code!=0) {
    		return false;
    	}
    
    	if ($code!=0) {
    		Log::info($reg);
    		Log::info($output);
    		Log::fatal("Unable to get '$key' from registry");
    	}
    	if (!preg_match("/\w+\s+REG_SZ\s+(.*)/i", trim($output), $matches)) {
    		Log::fatal('Unable to macth registry value by key '.$key.'. Output: ' .  trim($output));
    	}
    
    	return $matches[1];
    }
    
    function regQuery($path, $key, $returnResult=false)
    {
    	
    	$arch = Util::getArch();
    	if ($arch == 'x86_64') {
    		$reg = 'REG QUERY "HKLM\SOFTWARE\Wow6432Node' . $path .  '" '.$key; 
    	} else {
    		$reg = 'REG QUERY "HKLM\SOFTWARE' . $path .  '" '.$key;
    	}
    	$output = Util::exec($reg, $code);

    	if ($returnResult && $code!=0) {
    		return false;
    	}
    
    	if ($code!=0) {
    		Log::info($reg);
    		Log::info($output);
    		Log::fatal("Unable to get '$key' from registry");
    	}
    	if (!preg_match("/\s+(REG_SZ|REG_DWORD)\s+(.*)/i", trim($output), $matches)) {
    		Log::fatal('Unable to match registry value by key '.$key.'. Output: ' .  trim($output));
    	}
    
    	return $matches[2];
    }
    
    function getSystemDisk()
    {
    	$code = 0;
    	$cmd = 'echo %SYSTEMROOT%';
    	$output = Util::exec($cmd, $code);
    	return substr($output, 0, 3);
    }
    
    function getSystemRoot()
    {
    	$code = 0;
    	$cmd = 'echo %SYSTEMROOT%';
    	$output = Util::exec($cmd, $code);
    	return $output;
    }
    
    function getComputerName()
    {
    	$code = 0;
    	$cmd = 'echo %COMPUTERNAME%';
    	$output = Util::exec($cmd, $code);
    	return $output;
    }
    
    function readfile($file)
	{
		if (!is_file($file) || !is_readable($file))
			return null;
		$lines = file($file);
		if ($lines === false)
			return null;
		return trim(implode("\n", $lines));
	}
	
	function readfileToArray($file)
	{
		if (!is_file($file) || !is_readable($file))
			return null;
		$lines = file($file);
		if ($lines === false)
			return null;
		return $lines;
	}
	
	function getSettingFromPsaConf($setting)
	{
		$file = '/etc/psa/psa.conf';
		if (!is_file($file) || !is_readable($file))
			return null;
		$lines = file($file);
		if ($lines === false)
			return null;
		foreach ($lines as $line) {
			if (preg_match("/^{$setting}\s.*/", $line, $match_setting)) {
				if (preg_match("/[\s].*/i", $match_setting[0], $match_value)) {
					$value = trim($match_value[0]);
					return $value;
				}
			}
		}
		return null;
	}
	
	function getPleskLicense() {
		$pleskDir = Util::getPleskRootPath();
		
		$code = 0;
		$keys = array();
		$output = Util::exec('"' . $pleskDir . '/bin/keyinfo" -l', $code);
		
		foreach (preg_split('/[\r\n]+/', $output) as $l) {
    		list($k, $v) = explode(':', $l);
    		$keys[trim($k)] = trim($v);
		}
		return $keys;
	}
	
	function getMailServer()
    {    
    	if (Util::isLinux()) {
    		return;
    	}
    	
    	$currentMailServer = Util::regQuery('\PLESK\PSA Config\Config\Packages\mailserver', '/ve', true);		
    	return $currentMailServer;
    }
    
    function getMailContentPath() {
    	if (Util::isLinux()) {
    		return;
    	}
    	
    	$mailServer = Util::getMailServer();

    	if ($mailServer == 'mailenable') {
    		$path = Util::regQuery('\Mail Enable\Mail Enable', '/v "Mail Root"', true);
    	}
    	
    	if ($mailServer == 'merak') {
    		$merakInstallPath = Util::regQuery('\IceWarp\IceWarp Server', '/v InstallDir', true);
    		$path = $merakInstallPath . '\mail';
    	}
    	
    	if ($mailServer == 'smartermail') {
    		$smInstallPath = Util::regQuery('\SmarterTools\SmarterMail', '/v InstallPath', true);
    		$smConfig = $smInstallPath . 'Service\mailConfig.xml';
    		
    		if (file_exists($smConfig)) {
    		
	    		$doc = new DOMDocument();
				$doc->load($smConfig);		
				$xpath = new DOMXPath($doc);
				$raw = $xpath->query('/MailConfigDataSet/MailConfig/rootMailPath');
				foreach($raw as $r) {
					$path = $r->nodeValue . '\domains';				
				}
    		}
    	}
    	
    	if (is_dir($path)) {
    		return $path;
    	} else {
    		return false;
    	}
    }
    
    function getAllPleskComponents()
    {
    	$components = array();
    	
   		if (Util::isLinux() && PleskVersion::is10_4_or_above()) {
   			$cmd = '/usr/local/psa/admin/bin/packagemng -l';
   			$code = 0;
			$output = Util::exec($cmd, $code);
   			
   			foreach (preg_split('/[\r\n]+/', $output) as $l) {
	    		list($name, $version) = explode(':', $l);
	    		$components[trim($name)] = trim($version);
			}
   		} else {
	   		$db = PleskDb::getInstance();
			$tmp = $db->fetchAll("SELECT name, version FROM Components");
			
			foreach($tmp as $item) {
				if ($item['version'] == 'not_installed') {
					$components[$item['name']] = '';
				} else { 
					$components[$item['name']] = $item['version'];
				}
			}
			
   		}
   		
		return $components; 	
    }
    
    function getUsedPleskComponents()
    {
    	$components = Util::getAllPleskComponents();
    	
    	$db = PleskDb::getInstance();
		$coldfusion = $db->fetchOne("SELECT count(*) FROM hosting WHERE coldfusion = 'true'");
		if ($coldfusion == 0) {
			unset($components['coldfusion']);
		}
		
		$miva = $db->fetchOne("SELECT count(*) FROM hosting WHERE miva = 'true'");
		if ($miva == 0) {
			unset($components['miva']);
			unset($components['psa-miva']);
		}
		
		$asp = $db->fetchOne("SELECT count(*) FROM hosting WHERE asp = 'true'");
		if ($asp == 0) {
			unset($components['asp']);
		}
		
		
		/*
		 * Translation old names to new names
		 */
		 
		if (isset($components['kav4ms'])) {
			$components['psa-kav8'] = $components['kav4ms'];
			unset($components['kav4ms']);
		}

		/*
		 * Deleting old components
		 */
		
		if (isset($components['drweb-qmail'])) {
			unset($components['drweb-qmail']);
		}
		
		if (isset($components['psa-manual-custom-skin-guide'])) {			
			unset($components['psa-manual-custom-skin-guide']);
		}
		
		/*
		 * Deleting configuration depended components
		 */
		if (isset($components['iisftp'])) {
			unset($components['iisftp']);
		}
		
		if (isset($components['psa-qmail-rblsmtpd'])) {
			unset($components['psa-qmail-rblsmtpd']);
		}
		
		if (isset($components['psa-qmail'])) {
			unset($components['psa-qmail']);
		}
		
		if (isset($components['postfix'])) {
			unset($components['postfix']);
		}
		
		/*
		 * Deleting additional entries of same components
		 */
		 
		if (isset($components['psa-turba'])) {
			unset($components['psa-turba']);
		}
		
		if (isset($components['psa-imp'])) {
			unset($components['psa-imp']);
		}
		
		if (isset($components['psa-spamassassin'])) {
			unset($components['psa-spamassassin']);
		}
		
		if (isset($components['psa-tomcat-configurator'])) {
			unset($components['psa-tomcat-configurator']);
		}
		
		if (isset($components['coldfusion-support'])) {
			unset($components['coldfusion-support']);
		}
		
		if (isset($components['psa-rubyrails-configurator'])) {
			unset($components['psa-rubyrails-configurator']);
		}
		
		return $components;
    }
    
    function getPleskComponentsInfoOnWindows() {
    	$pleskDir = Util::getPleskRootPath();		
		$code = 0;
		$cmd = '"' . $pleskDir . '\admin\bin\defpackagemng.exe" --get';
		$output = Util::exec($cmd, $code);
		
		if ($code <> 0) {
			Log::error('Unable to execute: ' . $cmd . ' Error code: ' . $code);
		}
		$doc = new DOMDocument();
		$doc->loadXML($output);
		
		return $doc;
    }
    
    function getSystemUsers() {
    	$system_users = array();
		if (Util::isWindows()) {
			$wmi = new COM('winmgmts:\\');
			if (!is_object($wmi)) {
				Log::error('Unable to get WMI object');
			}
			
			$users = $wmi->ExecQuery('Select * from Win32_UserAccount');
			foreach($users as $u) {
				$local_users[] = $u->name;
			}
		} else {
    		$passwd = Util::readFileToArray('/etc/passwd');
			foreach($passwd as $line) {
				$eline = explode(':', $line);
				$system_users[] = array('login' => $eline[0], 'id' => $eline[2], 'home' => $eline[5]);
			}
		}
		return $system_users;
    }
    
    function getAdminId() {
        $db = PleskDb::getInstance();
        $sql = "SELECT id FROM clients WHERE type='admin'";
        $adminId = $db->fetchOne($sql);
        
        if (empty($adminId)) {
            Log::fatal('Unable to find Plesk administrator. Please check SQL: ' . $sql);
        }
        
        return $adminId;
    }
}

class SSHMaster {
    var $control_path;
    var $login;
    var $host;
    var $port;

    function __construct() {
    	global $options;
        $this->login = $login = $options->_login;
        $this->host = $host = $options->_host;
        $this->port = $port = $options->_port;
        $control_path = "$login@$host:$port.sock";

        $sus = escapeshellarg("/bin/bash -c 'set -m && suspend'");
        $cmd = "ssh -f -M -S $control_path -p $port $login@$host $sus";
        $proc = proc_open($cmd, array(), $pipes);
        if (!$proc)
            die("Failed to run ssh master '$control_path'\n");

        $proc_s = proc_get_status($proc);
        if (!$proc_s)
            die("Failed to get proc status\n");

        $pid = $proc_s['pid'];
        if (pcntl_waitpid($pid, $status) != $pid)
            die("Failed to wait for child #$pid\n");

        if (!pcntl_wifexited($status) || pcntl_wexitstatus($status) != 0)
            die("Failed to connect to '$host'\n");

        proc_close($proc);
        $this->control_path = $control_path;
    }

    function __destruct() {
        if ($this->control_path) {
            $cmd = "ssh -S $this->control_path -O exit host 2>/dev/null";
            system($cmd, $ec);
            if ($ec != 0)
                print "Failed to exit ssh master '$this->control_path'\n";
        }
    }
    
    function exec($cmd) {
	    $cmd = escapeshellarg($cmd);
	   	Log::step('Execute on source server: ' . $cmd);
	    $out = shell_exec("ssh -S $this->control_path host $cmd");
	    if (is_null($out))
	        die("'$cmd' has been failed\n");
	
	    return $out;
	}
	
	function copyToSource($from, $to) {
		$cmd = "scp -P $this->port -o ControlPath=$this->control_path $from $this->login@$this->host:$to";
		Log::step('Execute: ' . $cmd);
		shell_exec($cmd);
	}
	
	function copyFromSource($from, $to) {
		$cmd = "scp -P $this->port -o ControlPath=$this->control_path $this->login@$this->host:$from $to";
		Log::info('Execute: ' . $cmd);
		shell_exec($cmd);
	}
};

class Source {
	var $isSource = null;
	var $admin_db_password = null;
	var $used_space = null;
	var $clients_count = null;
	var $domains_count = null;
	var $domain_aliases_count = null;
	var $mails_count = null;
	var $max_allowed_packet = null;
	var $maillists_count = null;
	var $pg_databases_count = null;
	var $domains_with_hosting_count = null;
	var $arch = null;
	var $system_users = array();
	var $smb_users_wo_uuid = null;
	var $is_mysql_working = null;
	var $plesk_configured = null;
	var $plesk_running = null;
	var $unknown_databases = null;
	var $mysql_wait_timeout = null;
	var $components = null;
	var $unknown_system_user = array();
	
	function Source() {
		global $options;
		$this->isSource = $options->isSource();
		$this->admin_db_password = $options->getDbPasswd();
	}

	function collect_general_info() {
		$this->arch = Util::getArch();
	}
	
	function collect_info() {
		
		$this->collect_general_info();
	}
	
	function dump($file) {
		@unlink($file);
		$this->collect_info();
		$this->validate();
		Log::step('Info collected');
		$src = serialize($this);
		Log::step('Serialized');
		file_put_contents($file, $src);
		Log::step('Dump saved to ' . $file);
	}
	
	function get_dump() {
		global $options;
		
		$file = $options->_dump;
		
		if (is_null($file)) {
			//$sshm = new SSHMaster();
			global $sshm;
			
			$sshm->copyToSource(__FILE__, '/root/' . basename(__FILE__));
			
			$cmd = '/root/' . basename(__FILE__) . " --source";		
			$out = $sshm->exec($cmd);

			$sshm->copyFromSource('/root/' .  DUMP_FILENAME, dirname(__FILE__) . '/' . DUMP_FILENAME);
			
			$file = dirname(__FILE__) . '/' . DUMP_FILENAME;		
		} 
		
		
		if (!file_exists($file)) {
			Log::fatal('File ' . $file . ' does not exists.');
		}
		
		return file_get_contents($file);
		
	}
		
	function unserialize() {
		
		$str = Source::get_dump();
		if (empty($str)) {
			Log::fatal('Dump is empty.');
			
		} 
		return unserialize($str);
	}
	
	function validate() {		
		if (Util::isLinux()) {
			$this->check_mysql(); 
			$this->check_discspace_linux();
			$this->check_apache_pipelog(); //:INFO: --- Warn if source has more than 900 sites or more than 250 sites and destination has no enabled apache_pipelog --- #RT 1366209
			$this->check_unknown_databases();
			$this->check_sshd_config();
			$this->check_unknown_system_users();
			$this->check_perl_bigint();
			$this->check_system_locales();
			$this->check_inodes();
			$this->check_maillists();
			$this->check_webalizer_version();
		}
		
		if (Util::isWindows()) {
			$this->check_discspace_windows();
			$this->check_mssql_instance_name();
			$this->check_smartermail_version();
			$this->check_siteapppackages();
			$this->check_compare_mail_server();
		}
		
		if (PleskVersion::is10x_or_above()) {
			$this->check_smb_users_uuid();
			$this->check_smb_users_roleId();
		}
		
		$this->check_plesk_running();
		$this->check_plesk_configured();
		$this->check_license();
		$this->check_max_allowed_packet();
		$this->check_aps_catalog();
		$this->check_mailman(); //:INFO: --- Mailing List are not migrated because of mailman on the destination server was not configured --- #1350589
		$this->check_postgresql(); //:INFO: --- PG DB aren't migrated if target have no configured postgresql server --- #81274
		$this->check_system_users(); //:INFO: --- Warn if destination has system user with same name as domain's system user from source, but such domain doesn't exists in Plesk  --- #RT 1353158
		$this->check_mysql_wait_timeout();
		$this->check_installed_components();
		$this->check_disabled_webmails();
		$this->check_bl_diagnoseDomainAdmsOwnedByAdministrator();
		$this->check_bl_diagnoseDomainAdmsOwnedByResellers();
		$this->check_bl_diagnoseClientsHaveMoreDomainsThanOneOwnedByAdmin();
		$this->check_bl_diagnoseClientsHaveDomainAdministratorsOwnedByAdmin();
		$this->check_bl_diagnoseClientsHaveNoDomainsOwnedByAdmin();
		$this->check_bl_diagnoseClientPermissions();
		$this->check_bl_diagnoseClientsHaveMoreDomainsThanOneOwnedByReseller();
		$this->check_bl_diagnoseClientsHaveDomainAdministratorsOwnedByReseller();
		$this->check_bl_diagnoseClientsHaveNoDomainsOwnedByReseller();
		$this->check_bl_diagnoseDomainOwnersDontExist();
		$this->check_remote_db_server();
	}
	
	function check_compare_mail_server() {
		$mail_server = Util::getMailServer();
		if ($this->isSource) {
			$this->mail_server = $mail_server;
			return;
		}
		
		if ($mail_server <> $this->mail_server) {
			Log::warning("You have different mail servers on Source and Destination servers. Because of different features of mailservers on source and destination servers you can see warnings about some these features are not supported on destination Plesk server.");
			Log::warning("Mail server on Source: " . $this->mail_server);
			Log::warning("Mail server on Destination: " . $mail_server);
		}
	}
	
	function check_remote_db_server() {
		
		$db = PleskDb::getInstance();
		$remote_db_servers = $db->fetchAll("SELECT host, type FROM DatabaseServers WHERE host <> 'localhost' AND host <> '127.0.0.1' AND host <> '.'");
		
		if ($this->isSource) {
			$this->remote_db_servers = $remote_db_servers;
			return;
		}
		
		if (count($this->remote_db_servers) > 0) {
			foreach ($this->remote_db_servers as $key => $rdb_on_source) {
				foreach ($remote_db_servers as $rdb_on_dest) {
					if ($rdb_on_source['type'] == $rdb_on_dest['type']) {
						unset($this->remote_db_servers[$key]);
						break;
					}
				}
			}
			
			if (count($this->remote_db_servers) > 0) {
				Log::info("Not all remote database servers from Source are registered on Destination Plesk server. All databases from following remote database servers on Source server will be migrated to local database servers on Destination server:");
				foreach ($this->remote_db_servers as $key => $rdb_on_source) {
					Log::info('Host: ' . $rdb_on_source['host'] . ' Type: ' . $rdb_on_source['type']);
				}
			}
			
		}
	}
	
	function check_webalizer_version() {
		$webalizer_version = Package::getVersion('webalizer');
		
		if ($this->isSource) {
			$this->webalizer_version = $webalizer_version;
			$db = PleskDb::getInstance();
			$this->webalizer_count = $db->fetchOne("SELECT count(*) FROM hosting WHERE webstat='webalizer'");
			return;
		}
		
		if ($this->webalizer_count > 0) {
			if (version_compare($this->webalizer_version, $webalizer_version, '>')) {
				Log::warning("Webalizer package on Destination server should be upgraded at least to version {$this->webalizer_version} as on Source server. Otherwise statistics data may be corrupted for domains which are using Webalizer.");
			}
		}
	}
	
	function check_maillists() {
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->mail_lists_count = $db->fetchOne("SELECT count(*) FROM MailLists");
			return;
		}
		
		if ($this->mail_lists_count > 0) {
			Log::warning("There are domain's mail lists on Source server. All mail list members will receive welcome messages about being added to their mail list again. That may confusing your customers. Please check KB article http://kb.parallels.com/en/113641 for more details.");
		}
	}
	
	function check_inodes() {
		$inodes = array();
		$output = '';
		$i = 0;
		exec('df -ilP', $output);
		
		foreach($output as $line) {
			if ($i > 0) {
				$eline = preg_split('/\s+/', $line);
				$inodes[trim($eline[5])] = array('total' => (int)trim($eline[1]), 'used' => (int)trim($eline[2]), 'free' => (int)trim($eline[3]));
			}
			$i++;
		}
		
		if ($this->isSource) {
			$this->inodes = $inodes;
			return;
		}
		
		if (!is_null($this->inodes)) {
			foreach ($this->inodes as $mount => $info) {
				if (isset($inodes[$mount])) {
					if ($inodes[$mount]['free'] < $info['used']) {
						Log::warning("Mount point {$mount} on Destination server has less free inodes than used on Source server. Please increase inodes limit on Destination server.");
					}
				}
			}
		}
	}
	
	function check_bl_diagnoseDomainOwnersDontExist() {
        if ($this->isSource) {
        	$this->domainOwnersDontExist = array();
        	if (!PleskVersion::is9x()) {
        		return;
        	}
        	
        	$db = PleskDb::getInstance();
			$sql = 'SELECT name FROM domains AS d LEFT JOIN clients AS c ON c.id = d.cl_id WHERE c.id IS NULL;';
		    $this->domainOwnersDontExist = $db->fetchAll($sql);
		    return;
        }
        	
		$details = 0;
		$totalDomains = 0;
		foreach ($this->domainOwnersDontExist as $key => $domain)
		{
		    $details .= "----Domain '{$domain['name']}' belongs to owner that does not exist" . PHP_EOL;
		    $totalDomains++;
		}
	
		if ($totalDomains > 0)
		{
			$logPath = APP_PATH.'/domain_owners_dont_exists.log';
	        Log::write($logPath, $details, 'w');
		    $warn = 'You have '.$totalDomains.' domains whose owners do not exist.';
			$warn.= ' This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
		    Log::warning($warn);
	        Log::warning('See details in log ' . $logPath);
	        Log::resultWarning();
	        return;
		}
	}
	
	function check_bl_diagnoseClientsHaveNoDomainsOwnedByReseller() {
        if ($this->isSource) {
        	$this->clientsHaveNoDomainsOwnedByReseller = array();
        	if (!PleskVersion::is9x()) {
        		return;
        	}
        	$db = PleskDb::getInstance();
	        $sql = "SELECT clients.id, clients.login, clients.pname FROM clients WHERE type='reseller'";
	        $resellers = $db->fetchAll($sql);
	        
	        foreach ($resellers as $reseller) {
	            $sql = 'SELECT clients.id, clients.pname FROM clients 
	                WHERE parent_id='.$reseller['id'].' AND id NOT IN (SELECT cl_id FROM domains)
	            ';
	            $clients = $db->fetchAll($sql);
	            
	            if (sizeof($clients) > 0) {
	                $this->clientsHaveNoDomainsOwnedByReseller[$reseller['login']] = $clients;
	            }
	        }
	        return;
        }        
        $totalResellers = sizeof($this->clientsHaveNoDomainsOwnedByReseller);
        $totalClients = 0;
        $details = '';
        foreach ($this->clientsHaveNoDomainsOwnedByReseller as $reseller => $clients) {
            $details .= "Reseller with login '{$reseller}' has " . sizeof($clients) . ' clients' . PHP_EOL;
            $totalClients += sizeof($clients);
            foreach ($clients as $client) {
                $details .= "----Client '{$client['pname']}' has no domains" . PHP_EOL;
            }
        }
        
        if ($totalResellers) {
            $logPath = APP_PATH.'/reseller_clients_have_no_domains.log';
            Log::write($logPath, $details, 'w');
            
            $warn = 'You have '.$totalResellers.' resellers with '.$totalClients.' clients that have no domains defined.';
            $warn.= ' After transitions these Clients will not be able to login into the control panel until you or Reseller create a subscription for them.';
			$warn.= ' This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
            Log::warning($warn);
            
            Log::warning('See details in log ' . $logPath);
        }
	}

	function check_bl_diagnoseClientsHaveDomainAdministratorsOwnedByReseller() {
        if ($this->isSource) {
        	$this->clientsHaveDomainAdministratorsOwnedByReseller = array();
        	if (!PleskVersion::is9x()) {
        		return;
        	}        	
        	$db = PleskDb::getInstance();
	        $sql = "SELECT clients.id, clients.login, clients.pname FROM clients WHERE type='reseller'";
	        $resellers = $db->fetchAll($sql);
	       
	        foreach ($resellers as $reseller) {
	            $sql ='SELECT clients.id, clients.pname, count(domains.name) AS count_dom_adm
	                FROM ((clients 
	                INNER JOIN domains ON (clients.id=domains.cl_id AND clients.parent_id = '.$reseller['id'].')) 
	                INNER JOIN dom_level_usrs ON(domains.id=dom_level_usrs.dom_id))
	                GROUP BY clients.id, clients.pname
	                HAVING count(domains.name) > 1
	            ';
	            $clients = $db->fetchAll($sql);
	            
	            if (sizeof($clients) > 0) {
	                $this->clientsHaveDomainAdministratorsOwnedByReseller[$reseller['login']] = $clients;
	            }
	        }
	
	        return;
        }

        $totalResellers = sizeof($this->clientsHaveDomainAdministratorsOwnedByReseller);
        $totalClients = 0;
        $details = '';
        foreach ($this->clientsHaveDomainAdministratorsOwnedByReseller as $reseller => $clients) {
            $details .= "Reseller with login '{$reseller}' has " . sizeof($clients) . ' clients' . PHP_EOL;
            $totalClients += sizeof($clients);
            foreach ($clients as $client) {
                $details .= "----Client '{$client['pname']}' has {$client['count_dom_adm']} domain administrators" . PHP_EOL;
            }
        }
        
        if ($totalResellers) {
            $logPath = APP_PATH.'/reseller_clients_have_domain_administators.log';
            Log::write($logPath, $details, 'w');
            
            $warn = 'You have '.$totalResellers.' resellers with '.$totalClients.' clients with Domain Administrators defined on more than one domain.';
            $warn.= ' After transitions these Clients will have problems, because in Plesk 10.x users belonging to a Customer have access to all Customer’s subscriptions.';
            $warn.= ' Probably you should consult with your resellers of the path forward for these customers.';
			$warn.= ' This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
            Log::warning($warn);
            
            Log::warning('See details in log ' . $logPath);
        }
	}
	
	function check_bl_diagnoseClientsHaveMoreDomainsThanOneOwnedByReseller() {
        if ($this->isSource) {
        	$this->clientsHaveMoreDomainsThanOneOwnedByReseller = array();
        	if (!PleskVersion::is9x()) {
        		return;
        	}
        	$db = PleskDb::getInstance();
	        $sql = "SELECT clients.id, clients.login, clients.pname FROM clients WHERE type='reseller'";
	        $resellers = $db->fetchAll($sql);
	        
	        //:INFO: Get list of resellers with clients who have more than one domain
	        $resellerMatched = array();
	        foreach ($resellers as $reseller) {
	            $sql = 'SELECT clients.id, clients.login, clients.perm_id, clients.pname, count(domains.id) as count_dom FROM clients 
	                INNER JOIN domains ON(domains.cl_id = clients.id AND clients.parent_id = '.$reseller['id'].') 
	                GROUP BY clients.id, clients.login, clients.perm_id, clients.pname
	                HAVING count(domains.id) > 1
	            ';
	            $clients = $db->fetchAll($sql);
	            if (sizeof($clients) > 0) {
	                $resellerMatched[$reseller['login']] = $clients;
	            }
	        }
	
	        //:INFO: Check that clients has permissions 'create_domains' and 'change_limits'
	        foreach ($resellerMatched as $key => $clients) {
	            foreach ($clients as $cl_key => $client) {
	                if (empty($client['perm_id'])) {
	                    //:INFO: client permissions based on default template
	                    unset($resellerMatched[$key][$cl_key]);
	                    continue;
	                }
	                
	                $sql = "SELECT count(*) FROM Permissions 
	                    WHERE id={$client['perm_id']} AND value='true' AND 
	                    (permission = 'create_domains' OR permission = 'change_limits')
	                ";
	                $count = $db->fetchOne($sql);
	                if ($count != 2) {
	                    //:INFO: Client has no permissions and we unset him.
	                    unset($resellerMatched[$key][$cl_key]);
	                }
	            }
	            //:INFO: unset reseller if client list is empty
	            if (!sizeof($resellerMatched[$key])) {
	                unset($resellerMatched[$key]);
	            }
	        }
	        $this->clientsHaveMoreDomainsThanOneOwnedByReseller = $resellerMatched;
	        return;
        }
        
        $totalResellers = sizeof($this->clientsHaveMoreDomainsThanOneOwnedByReseller);
        $totalClients = 0;
        $details = '';
        foreach ($this->clientsHaveMoreDomainsThanOneOwnedByReseller as $reseller => $clients) {
            $details .= "Reseller with login '{$reseller}' has " . sizeof($clients) . ' clients' . PHP_EOL;
            $totalClients += sizeof($clients);
            foreach ($clients as $client) {
                $details .= "----Client '{$client['pname']}' has {$client['count_dom']} domains" . PHP_EOL;
            }
        }
        
        if ($totalResellers) {
            $logPath = APP_PATH.'/reseller_clients_have_domains.log';
            Log::write($logPath, $details, 'w');
            
            $warn = 'You have '.$totalResellers.' resellers with '.$totalClients.' clients who are free to manage resources on their domains themselves within the resource limits that you gave them.';
            $warn.= ' In Plesk 10 and above the resources are defined in a subscription.';
            $warn.= ' The Customer cannot redistribute resources between his/her subscriptions.';
            $warn.= ' After upgrade you will be suggested to redistribute Clients’ resources between the existing subscriptions (current domains).';
			$warn.= ' This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
            Log::warning($warn);
            
            Log::warning('See details in log ' . $logPath);
        }
	}
	
	function check_bl_diagnoseClientPermissions() {
        if ($this->isSource ) {
        	if (!PleskVersion::is9x() || !PleskVersion::is8x()) {
        		return;
        	}        	
        	$db = PleskDb::getInstance();
       
	        $where = 'WHERE perm_id is NULL';
	        if (PleskVersion::is9x()) {
	            $where = "WHERE perm_id is NULL AND id<>".Util::getAdminId();
	        }
	        //Get client list where perm_id is null. It means that client never modified permissions and have default permissions
	        $sql = "SELECT clients.pname, clients.login FROM clients {$where}";
	        $this->clientsWithDefaultPermissions = $db->fetchAll($sql);
	        return;
        }
        
        if (sizeof($this->clientsWithDefaultPermissions)) {
            $details = 'Client list where perm_id is null. It means that client never modified permissions and has default permissions' . PHP_EOL . PHP_EOL;
            foreach ($this->clientsWithDefaultPermissions as $client) {
                $details .= "Client '{$client['pname']}' with login '{$client['login']}' has default permissions" . PHP_EOL . PHP_EOL;
            }
            $logPath = APP_PATH.'/clients_have_default_permissions.log';
            Log::write($logPath, $details, 'w');

            $warn = 'You have '.sizeof($this->clientsWithDefaultPermissions).' clients or resellers with default permissions.';
            $warn .= ' Due to the changes in business model in Plesk 10, default permissions are different from other versions.';
            $warn .= ' You should go to the Client/Reseller permission page for each user on Source server and save changes in order to permission values were saved in database.';
			$warn .= ' This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
            Log::warning($warn);            
            Log::warning('See details in log ' . $logPath);
        }
	}
	
	function check_bl_diagnoseClientsHaveNoDomainsOwnedByAdmin() {
        if ($this->isSource) {
        	$this->clientsHaveNoDomainsOwnedByAdmin = array();
        	if (!PleskVersion::is9x() || !PleskVersion::is8x()) {
        		return;
        	}  
        	$filterOwnedByAdmin = '';
	        if (PleskVersion::is9x()) {
	            $filterOwnedByAdmin = "AND type='client' AND parent_id=".Util::getAdminId();
	        }
	        $db = PleskDb::getInstance();
	        $sql = 'SELECT clients.id, clients.pname FROM clients 
	            WHERE id NOT IN (SELECT cl_id FROM domains) '.$filterOwnedByAdmin.'
	        ';
	        $this->clientsHaveNoDomainsOwnedByAdmin = $db->fetchAll($sql);
	        return;
        }
        
        $details = '';
        foreach ($this->clientsHaveNoDomainsOwnedByAdmin as $client) {
            $details .= "Client '{$client['pname']}' has no domains" . PHP_EOL . PHP_EOL;
        }
        
        if (sizeof($this->clientsHaveNoDomainsOwnedByAdmin)) {
            $logPath = APP_PATH.'/admin_clients_have_no_domains.log';
            Log::write($logPath, $details, 'w');
            
            $warn  = 'Your have ' . sizeof($this->clientsHaveNoDomainsOwnedByAdmin) . ' clients with no domains defined.';
            $warn .= ' After transitions these Clients will not be able to login into the control panel until you create a subscription for them.';
            $warn .= ' An alternative solution is upgrading them to resellers after conversion.';
			$warn .= ' This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
            Log::warning($warn);
            Log::warning('See details in log ' . $logPath);            
            return;
        }
	}
	
	function check_bl_diagnoseClientsHaveDomainAdministratorsOwnedByAdmin() {
        if ($this->isSource) {
        	$this->clientsHaveDomainAdministratorsOwnedByAdmin = array();
        	if (!PleskVersion::is9x() || !PleskVersion::is8x()) {
        		return;
        	}  
	        $filterOwnedByAdmin = '';
	        if (PleskVersion::is9x()) {
	            $filterOwnedByAdmin = "WHERE type='client' AND parent_id=".Util::getAdminId();
	        }
	        
	        $db = PleskDb::getInstance();
	        $sql ='SELECT clients.id, clients.pname, count(domains.name) AS count_dom_adm  
	            FROM ((clients 
	            INNER JOIN domains ON (clients.id=domains.cl_id))
	            INNER JOIN dom_level_usrs ON(domains.id=dom_level_usrs.dom_id))
	            '.$filterOwnedByAdmin.' 
	            GROUP BY clients.id, clients.pname
	            HAVING count(domains.name) > 1
	        ';
	        $this->clientsHaveDomainAdministratorsOwnedByAdmin = $db->fetchAll($sql);
	        
	        return;
        }
        
        $details = '';
        foreach ($this->clientsHaveDomainAdministratorsOwnedByAdmin as $client) {
            $details .= "Client '{$client['pname']}' has {$client['count_dom_adm']} domain administrators" . PHP_EOL . PHP_EOL;
        }
        
        if (sizeof($this->clientsHaveDomainAdministratorsOwnedByAdmin)) {
            $logPath = APP_PATH.'/admin_clients_have_domain_administators.log';
            Log::write($logPath, $details, 'w');
            
            $warn = 'Your have '.sizeof($this->clientsHaveDomainAdministratorsOwnedByAdmin).' clients with Domain Administrators defined on more than one domain.';
            $warn.= ' After transitions these Clients will have problems, because since Plesk 10.x users belonging to a Customer have access to all Customer’s subscriptions.';
            $warn.= ' You will avoid the problem if after upgrade the Clients will be upgraded to Resellers and Domain Administrators to the Customers.';
			$warn.= ' This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
            Log::warning($warn);
            
            Log::warning('See details in log ' . $logPath);
        }
	}
	
	function check_bl_diagnoseClientsHaveMoreDomainsThanOneOwnedByAdmin() {
        if ($this->isSource) {
        	$this->clientsHaveMoreDomainsThanOneOwnedByAdmin = array();
        	if (!PleskVersion::is9x() || !PleskVersion::is8x()) {
        		return;
        	}  
	        $db = PleskDb::getInstance();
	        $filterOwnedByAdmin = '';
	        if (PleskVersion::is9x()) {
	            $filterOwnedByAdmin = "WHERE type='client' AND parent_id=".Util::getAdminId();
	        }
	        $sql = 'SELECT clients.id, clients.pname, clients.perm_id, count(domains.id) as count_dom FROM clients 
	            INNER JOIN domains ON(domains.cl_id = clients.id) 
	            '.$filterOwnedByAdmin.' 
	            GROUP BY clients.id, clients.pname, clients.perm_id
	            HAVING count(domains.id) > 1
	        ';
	        $this->clientsHaveMoreDomainsThanOneOwnedByAdmin = $db->fetchAll($sql);
	        
	        foreach ($this->clientsHaveMoreDomainsThanOneOwnedByAdmin as $key => $client) {
	            if (empty($client['perm_id'])) {
	                //:INFO: client permissions based on default template
	                unset($this->clientsHaveMoreDomainsThanOneOwnedByAdmin[$key]);
	                continue;
	            }
	            
	            $sql = "SELECT count(*) FROM Permissions 
	                WHERE id={$client['perm_id']} AND value='true' AND 
	                (permission = 'create_domains' OR permission = 'change_limits')
	            ";
	            $count = $db->fetchOne($sql);
	            
	            //:INFO: Client has no permissions and we unset him.
	            if ($count != 2) {
	                unset($this->clientsHaveMoreDomainsThanOneOwnedByAdmin[$key]);
	            }
	        }
	        return;			
        }

        $total = sizeof($this->clientsHaveMoreDomainsThanOneOwnedByAdmin);
        $details = '';
        
        foreach ($this->clientsHaveMoreDomainsThanOneOwnedByAdmin as $clientOwnedByAdmin) {
            $details .= "Client '{$clientOwnedByAdmin['pname']}' has {$clientOwnedByAdmin['count_dom']} domains" . PHP_EOL . PHP_EOL;
        }
        
        //:INFO: count of clients > 0
        if ($total) {
            $logPath = APP_PATH.'/admin_clients_have_domains.log';
            Log::write($logPath, $details, 'w');
            
            $warn = 'You have '.$total.' clients who are free to manage resources on their domains themselves within the resource limits that you gave them.';
            $warn.= ' In Plesk 10.x and above the resources are defined in a subscription.';
            $warn.= ' The Customer cannot redistribute resources between his/her subscriptions.';
            $warn.= ' If you want to leave the same degree of flexibility for these Customers, you should consider converting them to Resellers after upgrade.';
			$warn.= ' This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
            Log::warning($warn);
            
            Log::warning('See details in log ' . $logPath);
        }		
	}
	
	function check_bl_diagnoseDomainAdmsOwnedByResellers() {
        if ($this->isSource) {
        	$this->domainAdmsOwnedByResellers = array();
        	if (!PleskVersion::is9x()) {
        		return;
        	}  
            $db = PleskDb::getInstance();
	        $sql = "SELECT clients.id, clients.login FROM clients WHERE type='reseller'";
	        $resellers = $db->fetchAll($sql);
	        
	        foreach ($resellers as $reseller) {
	            $sql = "SELECT domains.name FROM domains INNER JOIN dom_level_usrs ON(domains.id=dom_level_usrs.dom_id) WHERE cl_id = {$reseller['id']}";
	            $domains = $db->fetchAll($sql);
	            
	            if (sizeof($domains) > 1) {
	                $this->domainAdmsOwnedByResellers[$reseller['login']] = $domains;
	            }
	        }
	        return;
        }
        

        $details = '';
        $totalDomains = 0;
        foreach ($this->domainAdmsOwnedByResellers as $reseller => $domains) {
            $details .= "Reseller '{$reseller}' has " . sizeof($domains) . " domain administrators" . PHP_EOL . PHP_EOL;
            $totalDomains += sizeof($domains);
        }
        
        if (sizeof($this->domainAdmsOwnedByResellers)>0) {
            $logPath = APP_PATH.'/reseller_domains_with_dom_admins.log';
            Log::write($logPath, $details, 'w');
            
            $warn = 'You have '.sizeof($this->domainAdmsOwnedByResellers).' resellers with '.$totalDomains.' domains with separate domain administrators. ';
            $warn .= 'In Plesk 10.x and above these users will see all domains of their Resellers. ';
            $warn .= 'You should consider converting them to customers after upgrade to avoid security problem. ';
			$warn .= 'This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
            Log::warning($warn);
            Log::warning('See details in log ' . $logPath); 
        }
    }
	
	function check_bl_diagnoseDomainAdmsOwnedByAdministrator() {
		if ($this->isSource) {
			$this->domainAdmsOwnedByAdministrator = array();
			if (!PleskVersion::is9x()) {
        		return;
        	} 
			$db = PleskDb::getInstance();
	        $sql = 'SELECT domains.name FROM domains INNER JOIN dom_level_usrs ON(domains.id=dom_level_usrs.dom_id) WHERE domains.cl_id='.Util::getAdminId();
	
	        $this->domainAdmsOwnedByAdministrator = $db->fetchAll($sql);
	        if (sizeof($this->domainAdmsOwnedByAdministrator) <= 1) {
	            $this->domainAdmsOwnedByAdministrator = array();
	        }
	        return;
		}
				        
        $details = 'The following domains on Source server have domain administrator: ' . PHP_EOL . PHP_EOL;
        foreach ($this->domainAdmsOwnedByAdministrator as $domainOwnedByAdmin) {
            $details .= "'{$domainOwnedByAdmin['name']}'" . PHP_EOL;
        }
        
        if (sizeof($this->domainAdmsOwnedByAdministrator)>0) {
            $logPath = APP_PATH.'/admin_domains_with_dom_admins.log';
            Log::write($logPath, $details, 'w');
            
            $warn = 'You have '.sizeof($this->domainAdmsOwnedByAdministrator).' domains with separate Domain Administrators. ';
            $warn .= 'In Plesk 10 and above these users will see all your domains. ';
            $warn .= 'You should consider converting them to Customers after upgrade to avoid security problem. ';
			$warn .= 'This guide may be useful to you http://download1.parallels.com/Plesk/PP11/11.0/Doc/en-US/online/plesk-installation-upgrade-migration-guide/70381.htm';
            Log::warning($warn);
            
            Log::info('See details in log ' . $logPath);
        }
	}
	
	function check_siteapppackages() {
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$broken_siteapppackages = $db->fetchOne("select 1 from apsapplicationitems where apsapplicationitems.pkg_id not in (select id from siteapppackages)");
			if ($broken_siteapppackages == '1') {
				$this->broken_siteapppackages = true;
			}
			return;
		}
		
		if ($this->broken_siteapppackages) {
			Log::warning('Relations between tables siteapppackages and apsapplicationitems on Source server are broken. Please check article http://kb.parallels.com/115730 for more details.');
		}

	}
	
	function check_smb_users_roleId() {
		$db = PleskDb::getInstance();
		$smb_users_wo_roleId = $db->fetchOne("select 1 from smb_users where roleId not in (select id from smb_roles)");
		
		if ($this->isSource) {
			if ($smb_users_wo_roleId == '1') {
				$this->smb_users_wo_roleId = true;
			}
			return;
		}
		
		if ($this->smb_users_wo_roleId) {
			Log::warning('There are corrupted records in smb_users table on Source Plesk server. Please check article http://kb.parallels.com/115653 for more details.');
		}
		
		if ($smb_users_wo_roleId == '1') {
			Log::warning('There are corrupted records in smb_users table on Destination Plesk server. Please check article http://kb.parallels.com/115653 for more details.');
		}
	}
	
	function check_smartermail_version() {
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->smarter_mail_version = $db->fetchOne("SELECT version FROM components WHERE name = 'smartermail'");	
			return;
		}	
		
		if (!is_null($this->smarter_mail_version) && $this->smarter_mail_version <> 'not_installed') {
			if (version_compare($this->smarter_mail_version, '6.5.3586', '<')) {
				Log::warning("SmarterMail server version $this->smarter_mail_version which is installed on Source server have a bug which could cause interruption of mailbox content transfer if it contains corrupted messages. Please upgrade SmarterMail server at least to version 6.5.3586.");
			}
		}	
	}
	
	function check_system_locales() {
		if ($this->isSource) {
			return;
		}
		
		$code = 0;
		$output = Util::exec("locale -a", $code);
		$locales = explode("\n", $output);
				
		if (!in_array('en_US.utf8', $locales)) {
			Log::emergency('Migration will fails because system locale en_US.utf8 is not installed on Destination server.');
			exit(2);
		}	
	}
	
	function check_perl_bigint() {
		if ($this->isSource) {
			$code = 0;
			$output = Util::exec("perl -Mbigint -le 'print 0'", $code);
			$this->perl_bigint = $output;
			return;	
		}
		
		if ($this->perl_bigint == 'NaN') {
			Log::warning('There is Perl modules inconsistensy on Source server. Please check article http://kb.parallels.com/115646 for more details.');
		}
	}		
	
	function check_mssql_instance_name() {
		if ($this->isSource) {
			$this->mssql_hosts = array();
			$db = PleskDb::getInstance();
			$this->mssql_hosts = $db->fetchCol("SELECT host FROM databaseservers WHERE type = 'mssql'");	
			return;
		}	
		
		$db = PleskDb::getInstance();
		$dest_mssql_hosts = $db->fetchCol("SELECT host FROM databaseservers WHERE type = 'mssql'");	
		
		foreach($this->mssql_hosts as $source_host) {
			if (!in_array($source_host, $dest_mssql_hosts)) {
				Log::warning("MS SQL Server ${source_host} not registered on Source server. Applications of end-users may fail to work.");
			}
		}	
	}

	function check_unknown_system_users() {
		if ($this->isSource) {
			$users = Util::getSystemUsers();
			$db = PleskDb::getInstance();
			$plesk_users = $db->fetchCol("select login from sys_users");
			$this->unknown_system_users = array();
			foreach($users as $u) {
				if (!in_array($u['login'], $plesk_users)
					&& $u['id'] > 1000
					&& stristr($u['home'], '/home') <> FALSE) {
					$this->unknown_system_users[] = $u;
				}
			}
			return;
		}
		
		foreach($this->unknown_system_users as $u) {
			Log::warning("Files in ${u['home']} of unknown system user ${u['login']} on Source server will be not migrated to Destination server.");
		}
	}
		
	function check_sshd_config() {
		$sshd = Util::readFileToArray('/etc/ssh/sshd_config');		
		if ($sshd) {
	    	foreach ($sshd as $line) {
	    		if (preg_match('/^TCPKeepAlive\s+yes/i', $line, $match)
	    			|| preg_match('/^ClientAliveInterval\s+3/i', $line, $match)
	    			|| preg_match('/^ClientAliveCountMax\s+10/i', $line, $match)) {
	    			$warning = true;
	    			break;
	    		}
	    	}
	    }
		
		if ($this->isSource) {
	    	if ($warning) {
   				$this->sshd_config_warning = true;
	    		return;
	    	}
	    }

		if ($this->sshd_config_warning) {
			Log::warning("/etc/ssh/sshd_config on Source server should by tuned to avoid migration fails. Please check article http://kb.parallels.com/113870 for more details.");
		}
		
		if ($warning) {
	    	Log::warning("/etc/ssh/sshd_config on Destination server should by tuned to avoid migration fails. Please check article http://kb.parallels.com/113870 for more details.");
	    }		
	}
	
	function check_disabled_webmails() {
		if ($this->isSource) {
			return;
		}
		
		if (Util::isLinux()) {
			$db = PleskDb::getInstance();
			$webmails = $db->fetchCol("SELECT name FROM Webmails WHERE enabled='false'");
			foreach ($webmails as $webmail) {
				Log::warning("Webmail $webmail support for domains will be lost because $webmail is disabled in Plesk server settings on Destination server.");
			}
		} else {
			$pkgs = Util::getPleskComponentsInfoOnWindows();
			
			$xpath = new DOMXPath($pkgs);
			$webmails = $xpath->query("//packages/type[starts-with(@name, 'webmail.')]");
			
			foreach($webmails as $wm) {
				if ($wm->childNodes->item(0)->getAttribute('state') === '') {
					if ($wm->getAttribute('default') == 'none') {
						$webmail = $wm->childNodes->item(0)->getAttribute('description');
						Log::warning("Webmail $webmail support for domains will be lost because $webmail is disabled in Plesk server settings on Destination server.");
					}
				}
			}
		}
	}
	
	function check_installed_components() {
		if ($this->isSource) {		
			$this->components = Util::getUsedPleskComponents();
			return;
		}
		
		$dest_components = Util::getAllPleskComponents();
		
		foreach($this->components as $name => $version) {
			if (!empty($version)) {
				if (empty($dest_components[$name])) {
					Log::warning("Plesk component $name is installed on Source server, but does not installed on Destination server");
				}
			}
		}
	}
	
	function check_mysql_wait_timeout() {		
		if ($this->isSource) {
			if (Util::getPleskDbType() <> 'mysql') {
				return;
			}
			$db = PleskDb::getInstance();
			$vars = $db->fetchAll("show variables");
			foreach ($vars as $var) {
				if ($var['Variable_name'] == 'wait_timeout') {
					$this->mysql_wait_timeout = $var['Value'];
				}
			}
			return;
		}	
		
		if (!is_null($this->mysql_wait_timeout) && $this->mysql_wait_timeout < 28800) {
			Log::warning('MySQL global variable "wait_timeout" on Source server was customized. Too low value of "wait_timeout" can interrupt migration process. Please check article http://kb.parallels.com/115598 for details.');
		}
		
		if (Util::getPleskDbType() <> 'mysql') {
			return;
		}
		
		$db = PleskDb::getInstance();
		$vars = $db->fetchAll("show variables");
			foreach ($vars as $var) {
				if ($var['Variable_name'] == 'wait_timeout') {
					$mysql_wait_timeout = $var['Value'];
				}
			}
		
		if ($mysql_wait_timeout < 28800) {
			Log::warning('MySQL global variable "wait_timeout" on Destination server was customized. Too low value of "wait_timeout" can interrupt migration process. Please check article http://kb.parallels.com/115598 for details.');
		}
	}
	
	function check_unknown_databases() {
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->unknown_databases = $db->fetchAll("select SCHEMA_NAME from information_schema.SCHEMATA where SCHEMA_NAME not in (select name from psa.data_bases) AND SCHEMA_NAME not in ('information_schema','mysql','performance_schema') AND  SCHEMA_NAME not like '%phpmyadmin%' AND SCHEMA_NAME not in ('apsc','atmail','billing','horde','psa','sitebuilder5','task_manager')");			
			return;
		}
		
		if (!empty($this->unknown_databases)) {
			Log::warning('Unknown MySQL database(s) are exist on Source server. Databases which are not managed by Plesk will be not migrated.');
			Log::info('Unknown MySQL database(s):');
			foreach($this->unknown_databases as $database) {
				Log::info($database['SCHEMA_NAME']);
			}
		}
	}
	
	function check_plesk_running() {
		if (Util::isWindows()) {
			$cmd = 'net start | find /I "Plesk Management Service"';
			$check = 'Plesk Management Service';				
		} else {
			$cmd = '/etc/init.d/psa status';
			$check = 'running';
		}
		$code = 1;
		$output = Util::exec($cmd, $code);
		
		if ($this->isSource) {
			if (stristr($output, $check)) {
				$this->plesk_running = true;
			} else {
				$this->plesk_running = false;
			}
			return;
		}
		
		if (!$this->plesk_running) {
			Log::emergency('Plesk is not running on Source server.');
		}
		
		if (!stristr($output, $check)) {
			Log::emergency('Plesk is not running on Destination server.');
		}
	}
	
	function check_plesk_configured() {
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->plesk_configured = $db->fetchOne("SELECT 1 FROM misc WHERE val = 'true' AND param = 'psa_configured'");
			return;
		}
		
		if ($this->plesk_configured <> '1') {
			Log::warning('Source server is not configured.');
		}
		
		$db = PleskDb::getInstance();
		$local_plesk_configured = $db->fetchOne("SELECT 1 FROM misc WHERE val = 'true' AND param = 'psa_configured'");
		
		if ($local_plesk_configured <> '1') {
			Log::emergency('Destination Plesk server is not configured.');
		}
	}
	
	
	function check_mysql() {
		if ($this->isSource) {
			$mysql = new DbClientMysql('localhost', 'admin', $this->admin_db_password, 'mysql', 3306);
	    	if ($mysql->hasErrors()) {
	    		$this->is_mysql_working = false;
	            Log::emergency('Unable to connect to local MySQL server.');
	            return;
	        }
		}
		
		if ($this->is_mysql_working === false) {
			Log::emergency('Unable to connect to local MySQL server on Source server.');
		}
		
		$mysql = new DbClientMysql('localhost', 'admin', $this->admin_db_password, 'mysql', 3306);
	    if ($mysql->hasErrors()) {
			Log::emergency('Unable to connect to local MySQL server as admin with password ' . $this->admin_db_password);
		}		
	}
	
	function check_smb_users_uuid() {
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->smb_users_wo_uuid = $db->fetchOne("SELECT 1 FROM smb_users WHERE uuid=''");
			return;
		}
		
		if ($this->smb_users_wo_uuid == '1') {
			Log::warning('There are corrupted records in smb_users table on Source Plesk server. Please check article http://kb.parallels.com/115569 for more details.');
		}
		
		$db = PleskDb::getInstance();
		$local_smb_users_wo_uuid = $db->fetchOne("SELECT 1 FROM smb_users WHERE uuid=''");
		
		if ($local_smb_users_wo_uuid == '1') {
			Log::warning('There are corrupted records in smb_users table on Destination Plesk server. Please check article http://kb.parallels.com/115569 for more details.');
		}
	}
	
	//:INFO: --- Warn if destination has system user with same name as domain's system user from source, but doesn't belongs to domain  --- #RT 1353158
	function check_system_users() {
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->system_users = $db->fetchAll("SELECT name, login FROM hosting, sys_users, domains WHERE sys_user_id = sys_users.id AND dom_id = domains.id");
			return;
		}
		
		$local_users = array();
		if (Util::isWindows()) {
			$wmi = new COM('winmgmts:\\');
			if (!is_object($wmi)) {
				Log::error('Unable to get WMI object');
			}
			
			$users = $wmi->ExecQuery('Select * from Win32_UserAccount');
			foreach($users as $u) {
				$local_users[] = $u->name;
			}
		} else {
			$passwd = Util::readFileToArray('/etc/passwd');
			foreach($passwd as $line) {
				$eline = explode(':', $line);
				$local_users[] = $eline[0];
			}
		}
		
		$db = PleskDb::getInstance();
		$local_domains = $db->fetchCol("SELECT name FROM domains");
		foreach ($this->system_users as $user) {
			if (in_array($user['login'], $local_users)) {
				if (!in_array($user['name'], $local_domains)) {
					Log::warning(sprintf("System user %s of domain %s already exists on destination server", $user['login'], $user['name']));
				}
			}
		}
	}
	
	//:INFO: --- Warn if source has more than 900 sites or more than 250 sites and destination has no enabled apache_pipelog --- #RT 1366209
	function check_apache_pipelog() {
		if ($this->arch == 'x86_64') {
			return;
		}
				
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->domains_with_hosting_count = $db->fetchOne("SELECT count(*) FROM domains WHERE htype <> 'none'");
			return;
		}
		
		if ($this->domains_with_hosting_count > 900) {
			Log::warning("Your source server has more that 900 domains. Probably you need to recompile Apache server with increased number of file descriptors(FD_SETSIZE). Please check article http://kb.parallels.com/en/260 for more details");
		} else {
			if ($this->domains_with_hosting_count > 250) {
				$db = PleskDb::getInstance();
				$pipelog = $db->fetchOne("SELECT val FROM misc WHERE param = 'apache_pipelog'");
				if (strtolower($pipelog) <> 'true') {
					Log::warning("Your source server has more that 250 domains. Apache may fail to work because of a problem involving the file descriptors limit. Please check article http://kb.parallels.com/en/2066 for more details");
				}
			}
		}
	}
	
	//:INFO: --- PG DB aren't migrated if target have no configured postgresql server --- #81274
	function check_postgresql() {
		if (Util::isWindows()) {
			return;
		}
		
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->pg_databases_count = $db->fetchOne("SELECT count(*) FROM data_bases WHERE type = 'postgresql'");
			return;
		}
		
		if ($this->pg_databases_count > 0) {
			$db = PleskDb::getInstance();
			$cnt_pgservers = $db->fetchOne("SELECT count(*) FROM DatabaseServers where type = 'postgresql' and last_error = 'no_error'");
			if ($cnt_pgservers == 0) {
				Log::warning("PostgreSQL Databases will not be migrated because PostgreSQL Server is not configured or not registered properly. You can configure PostgreSQL Server in Tools & Settings > Database Servers");
			}
		}
	}
	
	//:INFO: --- Mailing List are not migrated because of mailman on the destination server was not configured --- #1350589
	function check_mailman() {	
		if (Util::isWindows()) {
			return;
		}
		
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->maillists_count = $db->fetchOne("SELECT count(*) FROM MailLists");
			return;
		}
		
		if ($this->maillists_count > 0) {
			$out = shell_exec("/usr/local/psa/admin/bin/listmng checkpresence mailman");
			if (trim($out) == '1') {
				Log::warning("Mail lists will not be migrated because Mailing Lists Server is not configured. You can configure Mail Lists Server in Tools & Settings");
			}
		}
		
	}
	
	function check_aps_catalog() {
		if ($this->isSource) {
			return;
		}
		
		$pleskDir = Util::getPleskRootPath();		
		$code = 0;
		$output = Util::exec('"' . $pleskDir . '/bin/aps" --get-registered-aps-catalogs-xml', $code);
		
		
		$doc = new DOMDocument();
		$doc->loadXML($output);		
		$xpath = new DOMXPath($doc);
		$urls = $xpath->query('/catalogs/catalog/url');
		for ($i = 0; $i < $urls->length; ++$i) {
		    $url = $urls->item(0)->nodeValue;
		    $c = parse_url($url);
		    $host = $c['host'];
		    $port = array_key_exists('port', $c) ? $c['port'] : 80;
		    if (!fsockopen($host, $port))
		        Log::warning("APS catalog at '$url' should be accessible to successfully migrate applications without package");
		}
	}
	
	function check_max_allowed_packet() {
		if (Util::isWindows()) {
			$dbprovider = Util::regPleskQuery('PLESK_DATABASE_PROVIDER_NAME');
	        if ($dbprovider <> 'MySQL') {
				return;	        		
	        }
		}
		
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$tmp = $db->fetchAll("SHOW variables LIKE 'max_allowed_packet'");
			$this->max_allowed_packet = $tmp[0]['Value'];
			return;
		}
		$db = PleskDb::getInstance();
		$tmp = $db->fetchAll("SHOW variables LIKE 'max_allowed_packet'");
		$max_allowed_packet = $tmp[0]['Value'];
		if ($max_allowed_packet < $this->max_allowed_packet)
		    Log::warning("Local MySQL variable 'max_allowed_packet' should be increased up to '$this->max_allowed_packet' to successfully migrate large blob databases");
		
	}
	
	function check_license() {
		
		if ($this->isSource) {
			$db = PleskDb::getInstance();
			$this->clients_count = $db->fetchOne("SELECT count(*) FROM clients");
			$this->domains_count = $db->fetchOne("SELECT count(*) FROM domains");
			if (Util::isWindows()) {
				$this->domain_aliases_count = $db->fetchOne("SELECT count(*) FROM domain_aliases");
			} else {
				$this->domain_aliases_count = $db->fetchOne("SELECT count(*) FROM domainaliases");
			}
			$this->mails_count = $db->fetchOne("SELECT count(*) FROM mail");
			$this->tomcat = $db->fetchOne("select 1 from DomainServices where type = 'tomcat' and status = 0");
			return;
		}
		
		$keys = Util::getPleskLicense();
		
		$lim_msg = "Currently installed license has insufficient %s limit '%u' to successfully migrate all '%u' %s";

		// clients
		$lim_cl = $keys['lim_cl'];
		if ($lim_cl >= 0 && $lim_cl < $this->clients_count)
		    Log::warning(sprintf($lim_msg, 'clients', $lim_cl, $this->clients_count, 'clients'));
		
		// domains
		$lim_dom = $keys['lim_dom'];
		if ($lim_dom >= 0 && $lim_dom < $this->domains_count)
		    Log::warning(sprintf($lim_msg, 'domains', $lim_dom, $this->domains_count, 'domains'));
		
		// domain aliases - there is no such limit in Plesk for Windows
		if (Util::isLinux()) {
			$lim_domain_aliases = $keys['lim_domain_aliases'];
			if ($lim_domain_aliases >= 0 && $lim_domain_aliases < $this->domain_aliases_count)
			    Log::warning(sprintf($lim_msg, 'domain aliases', $lim_domain_aliases, $this->domain_aliases_count, 'domain aliases'));
		}
		
		// mails
		$lim_mn = $keys['lim_mn'];
		if ($lim_mn >= 0 && $lim_mn < $this->mails_count)
		    Log::warning(sprintf($lim_msg, 'mailnames', $lim_mn, $this->mails_count, 'mailnames'));
		
		// tomcat
		$lim_tomcat = $keys['lim_tomcat'];
		if ($lim_tomcat == 0 && $this->tomcat == '1') {
			Log::warning("Plesk license on Destination server does not allows to use Java applications.");
		}
		
	}
	
	function check_discspace_linux() {
		
		if ($this->isSource) {
			$this->used_space = disk_total_space('/var') - disk_free_space('/var');
			return;
		}
		
		$free_space = disk_free_space('/var/');
		if ($free_space < $this->used_space) {
		    $gb = $this->used_space / (1024 * 1024 * 1024);
		    Log::warning("Disk space at /var/ has to be increased at least up to ${gb}G");
		}
	}
	
	function check_discspace_windows() {
		
		if ($this->isSource) {
			$obj = new COM('scripting.filesystemobject');
		    if (is_object($obj)) {
		    	
		    	$paths = array();
				$paths[] = Util::regPleskQuery('HTTPD_VHOSTS_D', true);
				$paths[] = Util::regPleskQuery('MYSQL_VAR_D', true);				
				$paths[] = Util::getMailContentPath();				
				
				$this->used_space = array();
				foreach ($paths as $path) {
					if (is_string($path)) {
						$ref = $obj->getfolder($path);
						$this->used_space[$path] = $ref->size;
					}
				}
		    	$obj = null;
		    }
			return;
		}
		
		if (!is_array($this->used_space)) {
			Log::error('Invalid $this->used_space variable');
			return;
		}
		
		$total = 0;
		foreach ($this->used_space as $path => $used_space) {
			$disk = substr($path, 0, 3);
			if ($disk <> substr($path, 0, 3)) {
				$same_disk = false;
			}
			
			$free_space = disk_free_space($path);
			$total = $total + $used_space;
			if ($free_space < $used_space) {
				$gb = round($used_space / (1024 * 1024 * 1024), 1);
				Log::warning("Disk space at $path has to be increased at least up to ${gb}G");
			}
		}
		
		$same_disk = true;
		foreach ($this->used_space as $path => $used_space) {
			if ($disk <> substr($path, 0, 3)) {
				$same_disk = false;
			}
		}
		
		if ($same_disk) {
			if ($free_space < $total) {
				$gb = round($total / (1024 * 1024 * 1024), 1);
				Log::warning("Disk space at $disk has to be increased at least up to ${gb}G");
			}
		}
		
	}
}

//:INFO: Validate options
$options = new GetOpt();
Log::step('Options parsed');
if ($options->isSource()) {
	$src = new Source();
	Log::step('Source created');
	$src->dump(dirname(__FILE__) . '/' . DUMP_FILENAME);
	Log::step('Exit');
	exit(0);
}
if (Util::isLinux()) {
	$sshm = new SSHMaster();
}
$src = Source::unserialize($options->_dump);
$src->isSource = $options->isSource();
$src->admin_db_password = $options->getDbPasswd();
$src->validate();
Log::step('Done');