<?php
/**
 * OpenSRS Domain Registrar Plugin Communication Class
 *
 * Expanded from the orginal class written by Mike Mallinson
 *
 * @category Plugin
 * @package  ClientExec
 * @author   Jason Yates <jason@clientexec.com>
 * @license  ClientExec License
 * @version  2
 * @link     http://www.clientexec.com
 */

require_once dirname(__FILE__).'/../../../newedge/classes/XmlFunctions.php';

/**
 * OpenSRS Class
 *
 * @category Plugin
 * @package  ClientExec
 * @author   Jason Yates <jason@clientexec.com>
 * @license  ClientExec License
 * @version  2
 * @link     http://www.clientexec.com
 */
class OpenSRS
{
    var $apiVersion = '0.9';

    var $port;
    var $host;
    var $user;
    var $key;
    var $logger;

    /**
     * Constructs a new OpenSRS object.
     *
     * @return OpenSRS An OpenSRS object
     */
    function OpenSRS($host, $port, $user, $key, $logger)
    {
        $this->host = $host;
        $this->port = $port;
        $this->user = $user;
        $this->key = $key;
        $this->logger = $logger;
    }
    
    /**
     * Checks the availibility of a domain.
     *
     * UPDATED: To use name_suggest as OpenSRS say it is faster
     *
     * @param string $domain The domain name to lookup
     * @return an xmlized array result - use print_r() to view the structure
     */
    function lookup_domain($domain, $tld, $namesuggest)
    {

        // Build the namesuggest items
        $i = 1;
        $namesuggestXml = "";
        foreach($namesuggest AS $key) {
            $namesuggestXml .= "<item key='".$i."'>".$key."</item>";
            ++$i;
        }

        // Build the request
        $request = "<data_block>
                      <dt_assoc>
                        <item key='protocol'>XCP</item>
                        <item key='action'>name_suggest</item>
                        <item key='object'>domain</item>
                        <item key='attributes'>
                          <dt_assoc>
                            <item key='services'>
                                <dt_array>
                                    <item key='0'>lookup</item>
                                </dt_array>
                            </item>
                            <item key='searchstring'>".$domain."</item>
                            <item key='tlds'>
                              <dt_array>
                                <item key='0'>".$tld."</item>
                                ".$namesuggestXml."
                              </dt_array>
                            </item>
                          </dt_assoc>
                        </item>
                        <item key='lookup'>
                          <dt_assoc>
                             <item key='no_cache_tlds'>1</item>
                          </dt_assoc>
                        </item>
                      </dt_assoc>
                    </data_block>";

        // Send the request to OpenSRS
        $response = $this->_buildAndSendRequest($request);

        // Check the response
        if ($response == null) {
            return null;
        }

        // XMLize the reply
        $response = XmlFunctions::xmlize($response);

        // Get the response
        $response = @$response['OPS_envelope']['#']['body'][0]['#']['data_block'][0]['#']['dt_assoc'][0]['#']['item'][5]['#']['dt_assoc'][0]['#']['item'][0]['#']['dt_assoc'][0]['#']['item'];

        // Check the response again, due to some possible auth failures
        if ($response == null) {
            return null;
        }

        $finalArray = array();
        $finalArray['status'] = array("response_text" => $response[1]['#'], "response_code" => $response[2]['#']);

        // Loop it
        foreach ($response[3]['#']['dt_array'][0]['#']['item'] AS $key) {

            // Make a working array
            $workingArray = array();
            $key = $key['#']['dt_assoc'][0]['#']['item'];

            // Add the domain
            $workingArray['domain'] = $key[0]['#'];

            // Explode the domain into parts
            $domainExplode = @explode(".", $workingArray['domain']);
            if(@$domainExplode[2]) {
                $workingArray['tld'] = $domainExplode[1].".".$domainExplode[2];
            } else {
                $workingArray['tld'] = $domainExplode[1];
            }

            $workingArray['sld'] = $domainExplode[0];

            // Validate the SLD because oPenSRS returns duplicate domains with -'s taken out.
            if($workingArray['sld'] != $domain) {
                continue;
            }

            // Re-work the status
            if($key[1]['#'] == 'available') {
                $domainStatus = 0;
            } else {
                $domainStatus = 1;
            }

            $workingArray['status'] = $domainStatus;

            $finalArray['result'][] = $workingArray;
        }
        //return the final array of checked domains
        return $finalArray;
    }
    
    /**
     * Registers a domain name with OpenSRS.
     *
     * @param array $params An array of parameters.
     * @return an xmlized array result - use print_r() to view the structure
     */
    function register_domain($params)
    {
        $contactblock = "  <dt_assoc>
                            <item key='state'>".$params['RegistrantStateProvince']."</item>
                            <item key='first_name'>".$params['RegistrantFirstName']."</item>
                            <item key='country'>".$params['RegistrantCountry']."</item>
                            <item key='address1'>".$params['RegistrantAddress1']."</item>
                            <item key='last_name'>".$params['RegistrantLastName']."</item>
                            <item key='address2'></item>
                            <item key='address3'></item>
                            <item key='postal_code'>".$params['RegistrantPostalCode']."</item>
                            <item key='fax'></item>
                            <item key='city'>".$params['RegistrantCity']."</item>
                            <item key='phone'>".$params['RegistrantPhone']."</item>
                            <item key='email'>".$params['RegistrantEmailAddress']."</item>
                            <item key='org_name'>".$params['RegistrantOrganizationName']."</item>
                            <item key='lang_pref'>".$params['RegistrantLanguage']."</item>
                           </dt_assoc>";
        
        /* tld specific items */
        switch($params['tld']) {
            case 'ca':
                $tldspecific = "<item key='isa_trademark'>".$params['ExtendedAttributes']['cira-isa-trademark']."</item>
                 <item key='legal_type'>".$params['ExtendedAttributes']['cira_legal_type']."</item>";
                break;
            case 'us':
                $tldspecific = "<item key='tld_data'>
                        <dt_assoc>
                          <item key='nexus'>
                           <dt_assoc>
                            <item key='category'>".$params['ExtendedAttributes']['us_nexus']."</item>
                            <item key='app_purpose'>".$params['ExtendedAttributes']['us_purpose']."</item>
                            <item key='validator'>".$params['RegistrantCountry']."</item>
                           </dt_assoc>
                          </item>
                         </dt_assoc>
                        </item>";
                break;
            case 'name':
                $tldspecific = "<item key='tld_data'>
                      <dt_assoc>
                       <item key='forwarding_email'>".$params['RegistrantEmailAddress']."</item>
                      </dt_assoc>
                     </item>";
                break;
            default:
                $tldspecific = "";
                break;
        }
        
        /* custom name servers */
        $ns = "";
        if ($params['Custom NS']) {
            $ns = "<item key='nameserver_list'>
                    <dt_array>";
            for ($i = 1; $i <= 12; $i++) {
                if (isset($params["NS$i"])) {
                    $ns.= "<item key='".($i-1)."'>
                          <dt_assoc>
                           <item key='sortorder'>".$i."</item>
                           <item key='name'>".$params['NS'.$i]['hostname']."</item>
                          </dt_assoc>
                         </item>";
                } else {
                    break;
                }
            }
            $ns .= " </dt_array>
                    </item>";
        }

        $request = "<data_block>
                     <dt_assoc>
                      <item key='action'>SW_REGISTER</item>
                      <item key='object'>DOMAIN</item>
                      <item key='protocol'>XCP</item>
                      <item key='attributes'>
                       <dt_assoc>
                        <item key='auto_renew'>".$params['renewname']."</item>
                        <item key='contact_set'>
                         <dt_assoc>
                          <item key='admin'>
                           ".$contactblock."
                          </item>
                          <item key='billing'>
                           ".$contactblock."
                          </item>
                          <item key='owner'>
                           ".$contactblock."
                          </item>
                          <item key='tech'>
                           ".$contactblock."
                          </item>
                         </dt_assoc>
                        </item>
                        <item key='custom_nameservers'>".$params['Custom NS']."</item>
                        <item key='custom_tech_contact'>1</item>
                        <item key='domain'>".$params['domain']."</item>
                        <item key='f_lock_domain'>1</item>
                        <item key='handle'>process</item>
                        ".$tldspecific."
                        ".$ns."
                        <item key='period'>".$params['NumYears']."</item>
                        <item key='reg_username'>".$params['DomainUsername']."</item>
                        <item key='reg_password'>".$params['DomainPassword']."</item>
                        <item key='type'>new</item>
                       </dt_assoc>
                      </item>
                     </dt_assoc>
                    </data_block>";
        
        $response = $this->_buildAndSendRequest($request);
        if ($response == null) {
            return null;
        }
        $response = XmlFunctions::xmlize($response);
        return $response['OPS_envelope']['#']['body'][0]['#']['data_block'][0]['#']['dt_assoc'][0]['#']['item'];
    }


    /**
     * Sets the renew status of a domain
     *
     * @param string $domain The domain name to lookup
     * @return an xmlized array result - use print_r() to view the structure
     */
    function set_autorenew($domain, $tld, $autorenew, $cookie = null)
    {

        // Fix to stop null $autorenew values
        if($autorenew == null) {
            $autorenew = 0;
        }

        // Build the request
        $request = "<data_block>
                      <dt_assoc>
                        <item key='protocol'>XCP</item>
                        <item key='action'>modify</item>
                        <item key='object'>domain</item>
                        <item key='domain'>".$domain.".".$tld."</item>
                        <item key='attributes'>
                          <dt_assoc>
                            <item key='affect_domains'>0</item>
                            <item key='auto_renew'>".$autorenew."</item>
                            <item key='let_expire'>0</item>
                            <item key='data'>expire_action</item>
                          </dt_assoc>
                        </item>
                      </dt_assoc>
                    </data_block>";

        // Send the request to OpenSRS
        $response = $this->_buildAndSendRequest($request);

        // Check the response
        if ($response == null) {
            return null;
        }

        // XMLize the reply
        $response = XmlFunctions::xmlize($response);

        // Get the response
        $response = $response['OPS_envelope']['#']['body'][0]['#']['data_block'][0]['#']['dt_assoc'][0]['#']['item'];

        // Process the response
        $finalArray = array();
        if(isset($response[4]['#'])) {
            // Success
            $finalArray['status'] = array("response_text" => $response[1]['#'], "response_code" => $response[4]['#']);
        } else {
            // Probably failed
            $finalArray['status'] = array("response_text" => $response[1]['#'], "response_code" => $response[2]['#']);
        }

        return $finalArray;
    }


    /**
     * Sets the renew status of a domain
     *
     * @param string $domain The domain name to lookup
     * @return an xmlized array result - use print_r() to view the structure
     */
    function get_domain_info($domain, $tld, $type)
    {
        // Build the request
        $request = "<data_block>
                      <dt_assoc>
                        <item key='protocol'>XCP</item>
                        <item key='action'>get</item>
                        <item key='object'>domain</item>
                        <item key='domain'>$domain.$tld</item>
                        <item key='attributes'>
                          <dt_assoc>
                            <item key='type'>all_info</item>
                            <item key='limit'>10</item>>
                          </dt_assoc>
                        </item>
                      </dt_assoc>
                    </data_block>";

        // Send the request to OpenSRS
        $response = $this->_buildAndSendRequest($request);

        

        // Check the response
        if ($response == null) {
            return null;
        }

        // XMLize the reply
        $response = XmlFunctions::xmlize($response);

        // Get the first part of the response
        $response = $response['OPS_envelope']['#']['body'][0]['#']['data_block'][0]['#']['dt_assoc'][0]['#']['item'];
        // Process the response
        $finalArray = array();
        $finalArray['status'] = array("response_text" => $response[2]['#'], "response_code" => $response[5]['#']);

        if ( $response[4]['#'] == 'Authentication Error.' ) {
            // This function is called and sometime causes errors when viewing a domain, but we do not want to throw an exception each time.
            $this->logger->log(4, "Authentication Error with OpenSRS.");
            return null;
        }


        // Determine what we are outputting
        if($type == 'general') {

            // Set the next block of the response
            $response = $response[4]['#']['dt_assoc'][0]['#']['item'];

            // Process the standard info
            $finalArray['generalInfo'] = array('auto_renew' => $response[0]['#'],
                                               'registry_createdate' => $response[4]['#'],
                                               'registry_expiredate' => $response[5]['#']);

        } elseif($type == 'contact') {

            // Set the next block of the response
            $response = $response[4]['#']['dt_assoc'][0]['#']['item'][1]['#']['dt_assoc'][0]['#']['item'];

            $i = 0;
            $info = array();
            foreach (array('Admin', 'Registrant', 'Tech', 'Billing') as $type) {

                $data =  $response[$i]['#']['dt_assoc'][0]['#']['item'];
                if (is_array($data)) {
                    $info[$type]['OrganizationName']  = array('Organization', $data[2]['#']);
                    $info[$type]['JobTitle']  = array('Job Title', '');
                    $info[$type]['FirstName'] = array('First Name', $data[12]['#']);
                    $info[$type]['LastName']  = array('Last Name', $data[5]['#']);
                    $info[$type]['Address1']  = array('Address 1', $data[11]['#']);
                    $info[$type]['Address2']  = array('Address 2', $data[4]['#']);
                    $info[$type]['City']      = array('City', $data[8]['#']);
                    $info[$type]['StateProvChoice']  = array('State or Province', $data[4]['#']);
                    $info[$type]['StateProv']  = array('Province / State', $data[4]['#']);
                    $info[$type]['Country']   = array('Country', $data[0]['#']);
                    $info[$type]['PostalCode']  = array('Postal Code', $data[9]['#']);
                    $info[$type]['EmailAddress']     = array('E-mail', $data[7]['#']);
                    $info[$type]['Phone']  = array('Phone', $data[3]['#']);
                    $info[$type]['PhoneExt']  = array('Phone Ext', '');
                    $info[$type]['Fax']       = array('Fax', $data[10]['#']);
                } else {
                    $info[$type] = array(
                        'OrganizationName'  => array($this->user->lang('Organization'), ''),
                        'JobTitle'          => array($this->user->lang('Job Title'), ''),
                        'FirstName'         => array($this->user->lang('First Name'), ''),
                        'LastName'          => array($this->user->lang('Last Name'), ''),
                        'Address1'          => array($this->user->lang('Address').' 1', ''),
                        'Address2'          => array($this->user->lang('Address').' 2', ''),
                        'City'              => array($this->user->lang('City'), ''),
                        'StateProvChoice'   => array($this->user->lang('State or Province'), ''),
                        'StateProv'         => array($this->user->lang('Province').'/'.$this->user->lang('State'), ''),
                        'Country'           => array($this->user->lang('Country'), ''),
                        'PostalCode'        => array($this->user->lang('Postal Code'), ''),
                        'EmailAddress'      => array($this->user->lang('E-mail'), ''),
                        'Phone'             => array($this->user->lang('Phone'), ''),
                        'PhoneExt'          => array($this->user->lang('Phone Ext'), ''),
                        'Fax'               => array($this->user->lang('Fax'), ''),
                    );
                }


                ++$i;
            }

            // Have to return here as the classes dont support status
            return $info;
        }

        return $finalArray;
    }
    
    
    /**
     * Get a list of domains from OpenSRS
     *
     * @param string $domain The domain name to lookup
     * @return an xmlized array result - use print_r() to view the structure
     */
    function get_domains_list($page)
    {

        $previousYear = date("Y")-1;
        $nextYears = date("Y")+11;
        $limit = 100;

        // Build the request
        $request = "<data_block>
                      <dt_assoc>
                        <item key='protocol'>XCP</item>
                        <item key='action'>get_domains_by_expiredate</item>
                        <item key='object'>domain</item>
                        <item key='attributes'>
                          <dt_assoc>
                            <item key='limit'>$limit</item>
                            <item key='exp_from'>".$previousYear."-01-01</item>
                            <item key='exp_to'>".$nextYears."-01-01</item>
                            <item key='page'>".$page."</item>
                          </dt_assoc>
                        </item>
                      </dt_assoc>
                    </data_block>";

        // Send the request to OpenSRS
        $response = $this->_buildAndSendRequest($request);

        // Check the response
        if ($response == null) {
            return null;
        }

        // XMLize the reply
        $response = XmlFunctions::xmlize($response);

        // Get the first part of the response
        $response = @$response['OPS_envelope']['#']['body'][0]['#']['data_block'][0]['#']['dt_assoc'][0]['#']['item'];

        $domainsList = array();
        if (@$response[4]['#']['dt_assoc'][0]['#']['item'][3]['#'] > 0) {
            $i = 0;
            foreach ($response[4]['#']['dt_assoc'][0]['#']['item'][0]['#']['dt_array'][0]['#']['item'] as $domain) {
                $domain = $domain['#']['dt_assoc'][0]['#']['item'];

                $splitDomain = $this->splitDomain($domain[1]['#']);

                $data['id'] = ++$i;
                $data['sld'] = $splitDomain[0];
                $data['tld'] = $splitDomain[1];
                $data['exp'] = $domain[2]['#'];
                $domainsList[] = $data;
            }
        }

        $metaData = array();
        $metaData['total'] = @$response[4]['#']['dt_assoc'][0]['#']['item'][3]['#'];
        $metaData['start'] = ($page * $limit) - $limit;
        $metaData['end'] = $page * $limit;
        $metaData['next'] = ++$page;
        $metaData['numPerPage'] = $limit;

        return array($domainsList, $metaData);
    }

    /**
     * Sets the renew status of a domain
     *
     * @param string $domain The domain name to lookup
     * @return an xmlized array result - use print_r() to view the structure
     */

    function get_cookie($params) {

        // Build the request
        $request = "<data_block>
                      <dt_assoc>
                        <item key='protocol'>XCP</item>
                        <item key='action'>set</item>
                        <item key='object'>cookie</item>
                        <item key='attributes'>
                          <dt_assoc>
                            <item key='reg_username'>".$params['domainUsername']."</item>
                            <item key='reg_password'>".$params['domainPassword']."</item>
                            <item key='domain'>".$params['sld'].".".$params['tld']."</item>
                          </dt_assoc>
                        </item>
                      </dt_assoc>
                    </data_block>";

        // Send the request to OpenSRS
        $response = $this->_buildAndSendRequest($request);

        // Check the response
        if ($response == null) {
            throw new Exception("OpenSRS API Error: Unable to communicate with OpenSRS.");
        }

        // XMLize the reply
        $response = XmlFunctions::xmlize($response);

        // Get the response
        $response = $response['OPS_envelope']['#']['body'][0]['#']['data_block'][0]['#']['dt_assoc'][0]['#']['item'];

        // Check the response code
        if(@$response[4]['#'] == '415') {

            // Throw error
            throw new Exception("OpenSRS API Error: Unable to authenticate using the Domain Username & Password.");
        }

        // Get the cookie
        $response = $response[4]['#']['dt_assoc'][0]['#']['item'][1]['#'];

        // return it
        return $response;
    }

    /**
     * Private function used for building the xml request and sending it.
     *
     * @param String $request The xml request body
     * @return The xml string response
     */
    function _buildAndSendRequest($request)
    {
        // Make the start of the XML request
        $request = '<?xml version=\'1.0\' encoding="UTF-8" standalone="no" ?>
                    <!DOCTYPE OPS_envelope SYSTEM "ops.dtd">
                    <OPS_envelope>
                     <header>
                      <version>'.$this->apiVersion.'</version>
                     </header>
                     <body>
                       '.$request.'
                     </body>
                    </OPS_envelope>';

        // Generate the signature
        $signature = md5(md5($request.$this->key).$this->key);

        // Contruct the headers
        $header = "POST ".$this->host." HTTP/1.0\r\n";
        $header .= "Content-Type: text/xml\r\n";
        $header .= "X-Username: " . $this->user . "\r\n";
        $header .= "X-Signature: " . $signature . "\r\n";
        $header .= "Content-Length: " . strlen($request) . "\r\n\r\n";

        // Open the connection
        $fp = @fsockopen ("ssl://$this->host", $this->port, $errno, $errstr, 30);
        if (!$fp) {
            $this->logger->log(4, "Couldn't connect to OpenSRS: $errno, $errstr");
            throw new Exception("OpenSRS API Error: Unable to communicate with OpenSRS. Please check your settings.");
        }

        // Send the request
        fputs ($fp, $header . $request);
        $response = "";

        // Gather the reply
        while (!feof($fp)) 
        {
            $response .= fgets ($fp, 1024);
        }

        // Close the file
        fclose($fp);

        // Log the reply
        $this->logger->log(4, "OpenSRS response: " . $response);

        // drop the headers so we can xmlize it
        $arrResponse = explode("\n", $response);
        $response = "";
        $flag = false;
        foreach ($arrResponse as $line)
        {
            if ($flag) $response .= $line."\n";
            else if (trim($line) == "") $flag = true;
        }

        // Return the final reply
        return $response;
    }

    function splitDomain($domain)
    {
        if (($position = strpos($domain, '.')) === false) {
            return array($domain, '');
        }
        return array(mb_substr($domain, 0, $position), mb_substr($domain, $position + 1));
    }
}

?>
