<?php

require_once dirname(__FILE__).'/../../../classes/error_ce.php';
require_once dirname(__FILE__).'/../../../classes/observable.php';
require_once dirname(__FILE__).'/../../../encrypted/commonfunctions.php';
require_once dirname(__FILE__).'/../../../common/xmlFunctions.php';
require_once dirname(__FILE__).'/../../../classes/user.php';

class PleskServer extends Observable
{
    var $rpcHandlerVersion = '1.3.1.0';
    var $rpcHandlerPort = 8443;
    var $rpcHandlerPath = '/enterprise/control/agent.php';
    var $host;
    var $user;
    var $password;
    var $limitsVars = array('max_dom', 'max_subdom', 'disk_space', 'max_traffic', 'max_wu', 'max_db', 'max_box', 'mbox_quota',
                            'max_redir', 'max_mg', 'max_resp', 'max_maillists', 'max_webapps');

    // @access	public
    function PleskServer($host, $user, $password)
    {
        $this->host = $host;
        $this->user = $user;
        $this->password = $password;
    }

    // @return	int	    userId in Plesk
    // @access	public
    function addUser($login, $password, $userID)
    {
        // can't set a pname (full client name) because it would have to be different for each domain the client has
        $tUser =& new User($userID);
        $tUser->populateCustomFields();
        $phone = $tUser->getPhone();
        $email = $tUser->getEmail();
        $address = $tUser->getAddress();
        $city = $tUser->getCity();
        $state = $tUser->getState();
        $pcode = $tUser->getZipCode();
        $country = $tUser->getCountry();
        $organization = $tUser->getOrganization();
        $request = "
            <client>
                <add>
                    <gen_info>
                        <pname>$login</pname>
                        <login>$login</login>
                        <passwd>$password</passwd>
                        <phone>$phone</phone>
                        <email>$email</email>
                        <address>$address</address> 
                        <city>$city</city>
                        <state>$state</state>
                        <pcode>$pcode</pcode>
                        <country>$country</country>";
        if(strlen($organization) != 0){
        	$request .= "
                        <cname>$organization</cname>
                    </gen_info>
                </add>
            </client>";
        } else {
        	$request .= "
        			 </gen_info>
                </add>
            </client>";
        }
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'client', 'add', $errMessage)) {
            return new Error_CE($errorCode, "Couldn't insert domain in Plesk. Plesk returned: $errMessage");
        }
        if ($this->_returnedStatus($response, 'client', 'add') != 'ok') {
            return new Error_CE(101, 'Error contacting Plesk server when trying to add user');
        }

        return $response['packet']['#']['client'][0]['#']['add'][0]['#']['result'][0]['#']['id'][0]['#'];
    }

    // @access	public
    function addResellerPermissionsAndLimits($userId, $packageVars= array())
    {
        $limits = $this->_getLimits($packageVars, true);

        $request = "
            <client>
                <set>
                    <filter>
                        <id>$userId</id>
                    </filter>
                    <values>
                        <permissions>
                            <create_domains>true</create_domains>
                        </permissions>
                        $limits
                    </values>
                </set>
            </client>";
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'client', 'set', $errMessage)) {
            return new Error_CE($errorCode, "Plesk returned: $errMessage");
        }
        if ($this->_returnedStatus($response, 'client', 'set') != 'ok') {
            return new Error_CE(101, 'Error contacting Plesk server when trying to give user the Create Domains permission');
        }

        return true;
    }

    // @access	public
    function addIpToUser($userId, $ip)
    {
        $request = "
            <client>
                <ippool_add_ip>
                    <client_id>$userId</client_id>
                    <ip_address>$ip</ip_address>
                </ippool_add_ip>
            </client>";
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'client', 'ippool_add_ip', $errMessage)) {
            return new Error_CE($errorCode, "Plesk returned: $errMessage");
        }
        if ($this->_returnedStatus($response, 'client', 'ippool_add_ip') != 'ok') {
            return new Error_CE(101, 'Error contacting Plesk server when trying to add IP to user');
        }
    }

    // @access	public
    function removeIpFromUser($userId, $ip)
    {
        $request = "
            <client>
                <ippool_del_ip>
                    <client_id>$userId</client_id>
                    <ip_address>$ip</ip_address>
                </ippool_del_ip>
            </client>";
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'client', 'ippool_del_ip', $errMessage)) {
            return new Error_CE($errorCode, "Plesk returned: $errMessage");
        }
        if ($this->_returnedStatus($response, 'client', 'ippool_del_ip') != 'ok') {
            return new Error_CE(101, 'Error contacting Plesk server when trying to remove IP from user\s IP pool');
        }
    }

    // @return	int	    domainId in Plesk
    // @access	public
    function addDomainToUser($userId, $login, $password, $domainName, $ip, $packageVars)
    {
        $hostingParams = '';
        $preferences = '';
        $this->_processPackageVars($hostingParams, $preferences, $packageVars, $login, $password);
        $limits = $this->_getLimits($packageVars, false);

        if ($userId) {
            $user = "<client_id>$userId</client_id>";
        } else {
            $user = '';
        }

        $request = "
            <domain>
                <add>
                    <gen_setup>
                        <name>$domainName</name>
                        $user
                        <ip_address>$ip</ip_address>
                    </gen_setup>
                    <hosting>
                        <vrt_hst>
                                    <ftp_login>$login</ftp_login>
                                    <ftp_password>$password</ftp_password>
                                    $hostingParams
                                    <ip_address>$ip</ip_address>
                        </vrt_hst>
                    </hosting>
                    <user>
                        <enabled>true</enabled>
                        <password>$password</password>
                    </user>
                    $limits
                    $preferences
                </add>
            </domain>";
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'domain', 'add', $errMessage)) {
            return new Error_CE($errorCode, "Plesk returned: $errMessage");
        }
        if ($this->_returnedStatus($response, 'domain', 'add') != 'ok') {
            return new Error_CE(101, 'Error contacting Plesk server when trying to add domain to user');
        }

        return $response['packet']['#']['domain'][0]['#']['add'][0]['#']['result'][0]['#']['id'][0]['#'];
    }

    // @access	public
    function deleteUser($userId)
    {
    	$request = "
            <client>
                <del>
                    <filter>
                        <id>$userId</id>
                    </filter>
                </del>
            </client>";
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'client', 'del', $errMessage)) {
            return new Error_CE($errorCode, "Plesk returned: $errMessage");
        }
        if ($this->_returnedStatus($response, 'client', 'del') != 'ok') {
            return new Error_CE(101, 'Error contacting Plesk server when trying to delete user');
        }
    }

	/*Plesk client and domain status.
	* Bit mask with bit flags:
	
	* 0 - object is active
	* 4 - object is under backup/restore
	
	* 16 - object is disabled by Administrator
	
	* 64 - object is disabled by Client
	* 
	* 256 - object expired
	* Only 0, 16 and 64 flags are available for setting*/
    function setDomainStatus($domainId, $status)
    {
    	$request = "
    		<domain>
    			<set>
    				<filter>
    					<id>$domainId</id>
					</filter>
					<values>
    					<gen_setup>
							<status>$status</status>
						</gen_setup>
					</values>
				</set>
			</domain>";
    	$request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'client', 'set', $errMessage)) {
            return new Error_CE($errorCode, "Plesk returned: $errMessage");
        }
        return true;	
    }
    
    // @access	public
    function updateAccount($dbUserId, $userId, $login, $password)
    {    	
    	$tUser =& new User($dbUserId);
        $tUser->populateCustomFields();
        $phone = $tUser->getPhone();
        $email = $tUser->getEmail();
        $address = $tUser->getAddress();
        $city = $tUser->getCity();
        $state = $tUser->getState();
        $pcode = $tUser->getZipCode();
        $country = $tUser->getCountry();
        $organization = $tUser->getOrganization();
    	$request = "
            <client>
                <set>
                    <filter>
                        <id>$userId</id>
                    </filter>
                    <values>
                        <gen_info>
                            <pname>$login</pname>
                            <login>$login</login>
                            <passwd>$password</passwd>
                            <phone>$phone</phone>
                            <email>$email</email>
                            <address>$address</address> 
                            <city>$city</city>
                            <state>$state</state>
                            <pcode>$pcode</pcode>
                            <country>$country</country>";
        if(strlen($organization) != 0){
        	$request .= "
                        <cname>$organization</cname>
                    </gen_info>
				</values>
			</set>
		</client>";
        } else {
        	$request .= "
        			 </gen_info>
				</values>        			 
            </set>
        </client>";
        }
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'client', 'set', $errMessage)) {
            return new Error_CE($errorCode, "Plesk returned: $errMessage");
        }
        if ($this->_returnedStatus($response, 'client', 'set') != 'ok') {
            return new Error_CE(101, 'Error contacting Plesk server when trying to update user data');
        }

        return true;
    }

    // @access	public
    function updateDomain($domainId, $login, $password, $ip, $packageVars)
    {
    	$hostingParams = '';
        $preferences = '';
        $this->_processPackageVars($hostingParams, $preferences, $packageVars, $login, $password);
        $limits = $this->_getLimits($packageVars, false);
        $request = "
            <domain>
                <set>
                    <filter>
                        <id>$domainId</id>
                    </filter>
                    <values>
                        <hosting>
                            <vrt_hst>
                                <ftp_login>$login</ftp_login>
                                <ftp_password>$password</ftp_password>
                                $hostingParams
                            </vrt_hst>
                        </hosting>
                        <user>
                            <enabled>true</enabled>
                            <password>$password</password>
                        </user>
                        $limits
                        $preferences
                    </values>
                </set>
            </domain>";
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'domain', 'set', $errMessage)) {
            return new Error_CE($errorCode, "Plesk returned: $errMessage");
        }
        if ($this->_returnedStatus($response, 'domain', 'set') != 'ok') {
            return new Error_CE(101, 'Error contacting Plesk server when trying to update domain');
        }

        return true;
    }

    function deleteDomain($domainId)
    {
    	$request = "
            <domain>
                <del>
                    <filter>
                        <id>$domainId</id>
                    </filter>
                </del>
            </domain>";
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        if (is_error($response)) {
            return $response;
        }
        $response = xmlize($response);
        if ($errorCode = $this->_errorCode($response, 'domain', 'del', $errMessage)) {
            return new Error_CE($errorCode, "Plesk returned: $errMessage");
        }
        if ($this->_returnedStatus($response, 'domain', 'del') != 'ok') {
            return new Error_CE(101, 'Error contacting Plesk server when trying to delete user');
        }
    }

    function getGenInfo()
    {
    	$request = <<<EOF
    <server>
        <get>
            <gen_info/>
        </get>
    </server>
EOF;
        $request = $this->_buildRequest($request);
        $response = $this->_sendRequest($request);
        
        return $response;
    }

    // @access	private
    function _processPackageVars(&$hostingParams, &$preferences, $packageVars, $login, $password)
    {
        $frontPageSupport = false;
        if (is_array($packageVars)) {
            foreach ($packageVars as $name => $value) {
                if (in_array($name, $this->limitsVars) || $name == 'reseller_account')
                {
                    continue;
                }

                if ($name == 'ftp_quota') {
                    if (!is_numeric($value)) {
                        continue;
                    }
                    $value = floor($value);
                } elseif ($value == '1') {
                    $value = 'true';
                } elseif ($value == '0') {
                    $value = 'false';
                }
                if ($name == 'www') {
                    $preferences = "<prefs><www>$value</www></prefs>";
                    continue;
                }
                if (($name == 'fp_ssl' || $name == 'fp_auth')
                    && !$frontPageSupport) {
                    continue;
                }
                if ($name == 'webstat') {
                    $value = strtolower($value);
                    $arr = array('awstats', 'webalizer', 'smarterstats', 'urchin', 'none');
                    if (!in_array($value, $arr)) {
                        $value = 'none';
                    }
                }

                $hostingParams .= "<$name>$value</$name>\n";

                if ($name == 'fp' && $value == 'true') {
                    $frontPageSupport = true;
                }
            }

            if ($frontPageSupport) {
                $hostingParams .= "<fp_admin_login>$login</fp_admin_login>\n<fp_admin_password>$password</fp_admin_password>\n";
            }
        }

        return true;
    }

    // @access	private
    function _getLimits($packageVars, $useMax_dom)
    {
        $limits = array();
        if (is_array($packageVars)) {
            foreach ($packageVars as $name => $value) {
                if (is_numeric($value) && in_array($name, $this->limitsVars))
                {
                    if ($name == 'max_dom' && !$useMax_dom) {
                        continue;
                    }
                    $limits[] = "<$name>".floor($value)."</$name>\n";
                }
            }
        }

        if ($limits) {
            $limits = "<limits>\n".implode('', $limits)."</limits>\n";
        } else {
            $limits = '';
        }

        return $limits;
    }

    // @access	private
    function _buildRequest($commands)
    {
        $proto = $this->rpcHandlerVersion;
        $request = <<<EOF
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
    <packet version="$proto">
EOF;
        $request .= "$commands\n</packet>";

        return $request;
    }

    // @access	private
    function _sendRequest($request, $skipAuth = false)
    {
        $headers = array();
        if (!$skipAuth) {
            $headers = array(
                'HTTP_AUTH_LOGIN: ' . $this->user,
                'HTTP_AUTH_PASSWD: ' . $this->password,
            );
        }

        $headers = array_merge($headers, array(
                'HTTP_PRETTY_PRINT: TRUE',
                'Content-Type: text/xml',
        ));

        $response = curlRequest(    "https://{$this->host}:{$this->rpcHandlerPort}{$this->rpcHandlerPath}",
                                    $request, $headers, true);
        
        return $response;
    }

    // @access	private
    function _errorCode($response, $target, $operation, &$errMessage)
    {
        // operation error
        if (isset($response['packet']['#'][$target][0]['#'][$operation][0]['#']['result'][0]['#']['errcode'][0]['#'])) {
            $errMessage = $response['packet']['#'][$target][0]['#'][$operation][0]['#']['result'][0]['#']['errtext'][0]['#'];
            return $response['packet']['#'][$target][0]['#'][$operation][0]['#']['result'][0]['#']['errcode'][0]['#'];
        }

        // general error
        if (isset($response['packet']['#']['system'][0]['#']['errcode'][0]['#'])) {
            $errMessage = $response['packet']['#']['system'][0]['#']['errtext'][0]['#'];
            return $response['packet']['#']['system'][0]['#']['errcode'][0]['#'];
        }

        // no errors
        return false;
    }

    // @access	private
    function _returnedStatus($response, $target, $operation)
    {
        if (!isset($response['packet']['#'][$target][0]['#'][$operation][0]['#']['result'][0]['#']['status'][0]['#'])) {
            return false;
        }

        return $response['packet']['#'][$target][0]['#'][$operation][0]['#']['result'][0]['#']['status'][0]['#'];
    }
}

?>
