<?php
namespace ThurData\Servers\KerioEmail\Api;
use ThurData\Servers\KerioEmail\Api\KerioConnectApi;
/**
 *
 * Administration API for Kerio Connect - Sample Class.
 *
 * @copyright	Copyright &copy; 2012-2012 Kerio Technologies s.r.o.
 * @version		1.3.0.62
 */

class KerioWhmcs extends KerioConnectApi {

	/**
	 * Class constructor.
	 * Register application
	 *
	 * @param   string   Application name
	 * @param   string   Vendor of the application
	 * @param   string   Application versiopn
	 *
	 * @return  void
	 */
	public function __construct($name, $vendor, $version) {
		$this->api = parent::__construct($name, $vendor, $version);

		return $this->api;
	}

	/**
	 * Login and get list of available constants user by Kerio Connect
	 *
	 * @param   string   Hostname of remote server
	 * @param   string   Administrator username
	 * @param   string   Administrator password
	 *
	 * @return  void
	 */
	public function login($hostname, $username, $password) {
		$login = parent::login($hostname, $username, $password);

		$this->getServerConstants();

		return $login;
	}

	/**
	 * Obtain server constants
	 *
	 * @param   void
	 * @return  void
	 */
	protected function getServerConstants() {
		$this->constants = parent::getConstants();
	}

	/**
	 * Return list of available constants
	 *
	 * @param   void
	 * @return	void
	 */
	public function getConstants() {
		return $this->constants;
	}

	/**
	 * Get list of available domains
	 *
	 * @param   array   List of fields to be obtained from engine
	 * @return	array	List of available domains
	 */
	public function getDomains($fields) {
		$method = 'Domains.get';

		$params = array(
			'query' => array(
				'fields' => $fields
			)
		);

		$result = $this->sendRequest($method, $params);

		return $result['list'];
	}

	/**
	 * Get Id of a domain by name
	 *
	 * @param   string  Domain name
	 * @return	string	Domain Id
	 */
	public function getDomainId($domain) {
		$method = 'Domains.get';

		$params = array(
			'query' => array(
				'fields' => array(
					'id',
					'name'
				)
			)
		);

		$result = $this->sendRequest($method, $params);

		foreach($result['list'] as $key) {
			if ($key['name'] == $domain) {
				return $key['id'];
			}
		}

		return FALSE;
	}

	/**
	 * Get list of users from a domain
	 *
	 * @param   array   List of fields to be obtained from engine
	 * @param	string	Domain Id
	 * @param   array   Additional condition for the request
	 *
	 * @return	array	List of users
	 */
	public function getUsers($fields, $domainId, $conditions = null) {
		$method = 'Users.get';

		$params = array(
			'query' => array(
				'fields' => $fields,
				'orderBy' => array(array(
					'columnName' => 'loginName',
					'direction' => 'Asc'
				))
			),
			'domainId' => $domainId
		);

		if ($conditions) {
			$params['query']['conditions'] = $conditions;
		}

		$result = $this->sendRequest($method, $params);

		return $result['list'];
	}

	/**
	 * Get address of a user
	 *
	 * @param	string	User Id
	 *
	 * @return	array	address of user
	 */
	public function getAddress($id) {
		$method = 'Users.getPersonalContact';

		$params = array(
			'userIds' => array(
					$id,
				)
			);
		$result = $this->sendRequest($method, $params);
		return $result;
	}

	/**
	 * Set address of a user
	 *
	 * @param	string	User Id
	 * @param	array	User Attributes
	 *
	 * @return	array	address of user
	 */
	public function setAddress($id, $fields) {
		$method = 'Users.setPersonalContact';

		$params = array(
			'userIds' => array(
					$id,
				),
			'contact' => $fields,
			);
		$result = $this->sendRequest($method, $params);
		return $result;
	}

	/**
	 * Get login name by user's Id
	 * 
	 * @param	string	User Id
	 * @param	string	Domain Id
	 * 
	 * @return	string	Login name
	 */
	public function getUserById($userId, $domainId) {
		$fields = array('id', 'loginName');
		$userList = $this->getUsers($fields, $domainId);
		
		foreach ($userList as $user) {
			if ($user['id'] == $userId) return $user['loginName']; 
		}
		
		return FALSE;
	}

	/**
	 * Get list of groups from a domain
	 *
	 * @param   array   List of fields to be obtained from engine
	 * @param	string	Domain Id
	 * @param   array   Additional condition for the request
	 *
	 * @return	array	List of groups
	 */
	public function getGroups($fields, $domainId, $conditions = null) {
		$method = 'Groups.get';

		$params = array(
			'query' => array(
				'fields' => $fields,
				'orderBy' => array(array(
					'columnName' => 'name',
					'direction' => 'Asc'
				))
			),
			'domainId' => $domainId
		);

		if ($conditions) {
			$params['query']['conditions'] = $conditions;
		}

		$result = $this->sendRequest($method, $params);

		return $result['list'];
	}

	/**
	 * Create new group
	 *
	 * @param	array   User defined params
	 * @return	array	Result of create action
	 */
	public function createGroup($params) {
		$method = 'Groups.create';

		$result = $this->sendRequest($method, $params);

		return $result['result'];
	}

	/**
	 * Add members to group of given ID
	 *
	 * @param	string  Group ID
	 * @param	array	List of user IDs to be added
	 *
	 * @return  void
	 */
	public function addMembersToGroup($groupId, $userList) {
		$method = 'Groups.addMemberList';

		$params = array(
			'userList' => $userList,
			'groupId'  => $groupId
		);

		$this->sendRequest($method, $params);
	}

	/**
	 * Get list of mailing lists from a domain
	 *
	 * @param   array   List of fields to be obtained from engine
	 * @param	string	Domain Id
	 * @param   array   Additional condition for the request
	 *
	 * @return	array	List of mailing lists
	 */
	public function getMailingLists($fields, $domainId, $conditions = null) {
		$method = 'MailingLists.get';

		$params = array(
			'query' => array(
				'fields' => $fields,
				'orderBy' => array(array(
					'columnName' => 'name',
					'direction' => 'Asc'
				))
			),
			'domainId' => $domainId
		);

		if ($conditions) {
			$params['query']['conditions'] = $conditions;
		}

		$result = $this->sendRequest($method, $params);

		return $result['list'];
	}

	/**
	 * Create new mailinglist
	 *
	 * @param	array   Mailinglist
	 * @return	array	Result of create action
	 */
	public function createMailinglist($list) {
		$method = 'MailingLists.create';
		$params['mailingLists'] = array($list);
		$result = $this->sendRequest($method, $params);

		return $result['result'];
	}

	/**
	 * Modify mailinglist
	 *
	 * @param	string  MailinglistID
	 * @param	array	fields to set
	 * @return	array	Result of delete action
	 */
	public function modifyMailinglist($fields,$mlId) {
		$method = 'MailingLists.set';
		$params['mlIds'] = array($mlId);
		$params['pattern'] = $fields;
		$result = $this->sendRequest($method, $params);

		return $result;
	}

	/**
	 * Delete mailinglist
	 *
	 * @param	string  MailinglistID
	 * @return	array	Result of delete action
	 */
	public function deleteMailinglist($mlId) {
		$method = 'MailingLists.remove';
		$params['mlIds'] = array($mlId);
		$result = $this->sendRequest($method, $params);

		return $result;
	}

	/**
	 * Get list of mailing lists from a domain
	 *
	 * @param   array   List of fields to be obtained from engine
	 * @param	string  Mailing list Id
	 *
	 * @return	array	List of mailing lists
	 */
	public function getMlUserList($fields, $mlId) {
		$method = 'MailingLists.getMlUserList';

		$params = array(
			'query' => array(
				'fields' => $fields
			),
			'mlId' => $mlId
		);

		$result = $this->sendRequest($method, $params);

		return $result['list'];
	}

	/**
	 * Add users to mailing list
	 *
	 * @param   array   List of fields of users to ba added
	 * @param	string  Mailing list Id
	 *
	 * @return	array	List of mailing lists
	 */
	public function addMlUserList($members, $mlId) {
		$method = 'MailingLists.addMlUserList';

		$params['members'] = $members;
		$params['mlId'] = $mlId;

		$result = $this->sendRequest($method, $params);

		return $result;
	}

	/**
	 * Remove users from mailing list
	 *
	 * @param   array   List of fields of users to ba added
	 * @param	string  Mailing list Id
	 *
	 * @return	array	List of mailing lists
	 */
	public function delMlUserList($members, $mlId) {
		$method = 'MailingLists.removeMlUserList';

		$params['members'] = $members;
		$params['mlId'] = $mlId;

		$result = $this->sendRequest($method, $params);

		return $result;
	}

	/**
	 * Get list of resources from a domain
	 *
	 * @param   array   List of fields to be obtained from engine
	 * @param	string	Domain Id
	 * @param   array   Additional condition for the request
	 *
	 * @return	array	List of mailing lists
	 */
	public function getResources($fields, $domainId, $conditions = null) {
		$method = 'Resources.get';

		$params = array(
			'query' => array(
				'fields' => $fields,
				'orderBy' => array(array(
					'columnName' => 'name',
					'direction' => 'Asc'
				))
			),
			'domainId' => $domainId
		);

		if ($conditions) {
			$params['query']['conditions'] = $conditions;
		}

		$result = $this->sendRequest($method, $params);

		return $result['list'];
	}

	/**
	 * Create resource.
	 *
	 * @param	array	Resource attributes
	 * @param	string	Domain ID
	 * @return	array	Result
	 */
	function createResouce($attr, $domain) {
		$params = array(
			'resources' => array(array(
				'name' => $attr['name'],
				'description' => $attr['description'],
				'type' => $attr['type'],
				'isEnabled' => $attr['status'] === 'active' ? TRUE : FALSE,
				'resourceUsers' => array(array('id' => $domain, 'type' => 'AuthDomainPrincipal')),
				'manager' => array('id' => $attr['manager'], 'type' => 'UserPrincipal'),
				'domainId' => $domain
			))
		);

		$result = $this->sendRequest('Resources.create', $params);
		return $result;
	}

	/**
	 * Update resource.
	 *
	 * @param	array	Resource attributes
	 * @param	string	Resource ID
	 * @return	array	Result
	 */
	function updateResouce($attr, $resource) {
		$params = array(
			'resourceIds' => array($resource),
			'pattern' => $attr 
		);
	
		$result = $this->sendRequest('Resources.set', $params);
		return $result;
	}

	/**
	 * Remove resource.
	 *
	 * @param	string	Resource ID
	 * @return	array	Result
	 */
	function delResouce($resource) {
		$params = array(
			'resourceIds' => array($resource)
		);
	
		$result = $this->sendRequest('Resources.remove', $params);
		return $result;
	}

	/**
	 * Get list of aliases from a domain
	 * 
	 * @param	array	List of fields to be obtained from engine
	 * @param	string	Domain Id
	 * @param	array	Additional condition for the request
	 * 
	 * @return	array	List of aliases
	 */
	public function getAliases($fields, $domainId, $conditions = null) {
		$method = 'Aliases.get';

		$params = array(
			'query' => array(
					'fields' => $fields,
					'orderBy' => array(array(
							'columnName' => 'name',
							'direction' => 'Asc'
					)),
					'combining' => 'Or'
			),
			'domainId' => $domainId
		);

		if ($conditions) {
			$params['query']['conditions'] = $conditions;
		}
		
		$result = $this->sendRequest($method, $params);
		
		return $result['list'];
	}

	/**
	 * Get list of all services
	 *
	 * @param   void
	 * @return	array	List of services
	 */
	function getServices() {
		$method = 'Services.get';
		$params = array();

		$result = $this->sendRequest($method, $params);

		return $result['services'];
	}

	/**
	 * Get list of all services
	 *
	 * @param   void
	 * @return	array	List of services
	 */
	function getServerStatistics() {
		$method = 'Statistics.get';
		$params = array();

		$result = $this->sendRequest($method, $params);

		return $result['statistics'];
	}

	/**
	 * Get server info
	 *
	 * @param   void
	 * @return	array	List of services
	 */
	function getServerInfo() {
		$method = 'Server.getProductInfo';
		$params = array();

		$result = $this->sendRequest($method, $params);

		return $result;
	}

	/**
	 * Create alias.
	 *
	 * @param	string	Domain ID
	 * @param	string	Alias
	 * @param	string	Email
	 * @param	string	Description, optional
	 * @return	array	Result
	 */
	function createAlias($domain, $alias, $email, $description = '') {
		$params = array(
			'aliases' => array(array(
				'name' => $alias,
				'domainId' => $domain,
				'deliverTo' => $email,
				'description' => $description,
				'deliverToSelect' => 'TypeEmailAddress'
			))
		);
		$result = $this->sendRequest('Aliases.create', $params);
		return $result;
	}

	/**
	 * Delete Alias.
	 *
	 * @param	string	aliasID
	 * @return	array	Result
	 */
	function deleteAlias($aliasID) {
		$params = array(
			'aliasIds' => array($aliasID),
		);
		$result = $this->sendRequest('Aliases.remove', $params);
		return $result;
	}

	/**
	 * Create user.
	 *
	 * @param	string	Domain ID
	 * @param	string	Username
	 * @param	string	Password
	 * @return	array	Result
	 */
	function createUser($domain, $username, $password, $active = TRUE) {
		$params = array(
			'users' => array(array(
				'loginName' => $username,
				'password' => $password,
				'domainId' => $domain,
				'isEnabled' => $active
			))
		);
		$result = $this->sendRequest('Users.create', $params);
		return $result;
	}

	/**
	 * Modify user.
	 *
	 * @param	string	User ID
	 * @param	array	Attributes
	 * @return	array	Result
	 */
	function modifyUser($userId, $attr) {
		$params = array(
			'userIds' => [ $userId ],
			'pattern' => $attr
		);
		$result = $this->sendRequest('Users.set', $params);
		return $result;
	}

	/**
	 * Count user.
	 *
	 * @param	string	Domain ID
	 * @return	int	Result
	 */
	function countUser($domainId) {
		$params = array(
			'domainId' => $domainId
		);
		$result = $this->sendRequest('Domains.getUserCountInfo', $params);
		return intval($result['countInfo']['currentUsers']);
	}

	/**
	 * Delete user.
	 *
	 * @param	string	User ID
	 * @return	array	Result
	 */
	function deleteUser($userId) {
		$params = array(
			'requests' => array(
				array(
					'userId' => $userId,
					'mode' => 'DSModeDeactivate',
					'method' => 'UDeleteFolder',
					'targetUserId' => '',
					'removeReferences' => TRUE,
				),
			),
		);
		$result = $this->sendRequest('Users.remove', $params);
		return $result;
	}

	/**
	 * Create domain.
	 *
	 * @param	string	Domain name
	 * @return	array	Result
	 */
	function createDomain($domain) {
		$params = array(
			'domains' => array(array(
				'name' => $domain
			))
		);
		$result = $this->sendRequest('Domains.create', $params);
		return $result;
	}
	
	/**
	 * Modify domain.
	 *
	 * @param	string	DomainID
	 * @param	array	Attributes
	 * @return	array	Result
	 */
	function modifyDomain($domainID, $attr) {
		$params = array(
			'domainIds' => array($domainID),
			'pattern' => $attr,
		);
		$result = $this->sendRequest('Domains.set', $params);
		return $result;
	}
	
	/**
	 * Delete domain.
	 *
	 * @param	string	DomainID
	 * @return	array	Result
	 */
	function deleteDomain($domainID) {
		$params = array(
			'domainIds' => array($domainID),
		);
		$result = $this->sendRequest('Domains.remove', $params);
		return $result;
	}
	
	/**
	 * get domain key.
	 *
	 * @param	string	Domain
	 * @return	array	Result
	 */
	function getDkimDnsRecord($domain) {
		$params = array(
			'domain' => $domain,
		);
		$result = $this->sendRequest('Domains.getDkimDnsRecord', $params);
		return $result;
	}
	
	/**
	 * Get list of IP addresses from a file.
	 *
	 * Local function used in example spam_blacklist
	 *
	 * @param	string	Filename
	 * @return	array	List of IP addresses
	 * @throws	KerioApiException
	 */
	public function getBlacklistRecords($file) {
		$blacklist = array();
		if(file_exists($file) && is_readable($file)) {
			$data = file_get_contents($file);
			foreach (preg_split("/\n/", $data) as $record) {
				if (empty($record)) continue;
				array_push($blacklist, $record);
			}
		}
		else {
			throw new KerioApiException(sprintf('Cannot open file %s', $file));
		}
		return $blacklist;
	}

	/**
	 * Get list of IP addesses from a group
	 *
	 * Local function used in example spam_blacklist
	 *
	 * @param	string	Group name
	 * @return	array	List of IP addresses
	 */
	public function getIpGroupList($name) {
		$params = array(
			"query" => array(
				"conditions" => array(array(
					"fieldName" => "name",
					"comparator" => "Like",
					"value" => $name
				)),
				"orderBy" => array(array(
					"columnName" => "item",
					"direction" => "Asc"
				))
			)
		);
		$result = $this->sendRequest('IpAddressGroups.get', $params);
		return $result['list'];
	}

	/**
	 * Add a IP address to a IP Group
	 *
	 * Local function used in example spam_blacklist
	 *
	 * @param	string	Group name
	 * @param	string	IP address
	 * @param	string	Description, optional
	 * @return	array	Result
	 */
	public function addHostToIpGroup($group, $ip, $description = '') {
		if(empty($description)) {
			$description = sprintf('Automatically added on %s', date(DATE_RFC822));
		}
		$params = array(
			"groups" => array(array(
				"groupId" => "",
				"groupName" => $group,
				"host" => $ip,
				"type" => "Host",
				"description" => $description,
				"enabled" => TRUE
			))
		);
		$result = $this->sendRequest('IpAddressGroups.create', $params);
		return $result;
	}

	/**
	 * Remove a IP address from a IP Group
	 *
	 * Local function used in example spam_blacklist
	 *
	 * @param	string	Group name
	 * @param	string	IP address
	 * @return	array	Result
	 */
	public function removeHostFromIpGroup($group, $ip) {
		$list = $this->getIpGroupList(NULL);
		foreach ($list as $record) {
			if(($record['groupName'] != $group) || ($record['host'] != $ip)) continue;
			$hostId = $record['id'];
		}
		$params = array("groupIds" => array($hostId));
		$result = $this->sendRequest('IpAddressGroups.remove', $params);
		return $result;
	}

	/**
	 * Random password generator
	 * 
	 * Local function used in example createUser.
	 * 
	 * @param	integer	Password lenght, default 10
	 * @return	string	Random password
	 */
	function genRandomPassword($length = 10) {
		$characters = '0123456789abcdefghijklmnopqrstuvwxyz';
		$string = '';

		for ($p = 0; $p < $length; $p++) {
			$string .= $characters[mt_rand(0, (strlen($characters))-1)];
		}
		
		return $string;
	}
}
