<?php
/**
 * Simple class to integrate with Cisco Webex XML API.
 * Built on version 5.9 of Reference Guide.
 * Based on Webex class by Joshua McGinnis (http://joshuamcginnis.com/2010/07/12/webex-api-php-sdk).
 *
 * @author Joubert Guimarães de Assis "RedRat" <joubert@redrat.com.br>
 * @copyright Copyright (c) 2013, RedRat Consultoria
 * @license GPL version 2
 * @see Github, animes and mangás, cute girls and PHP, much PHP
 * @link http://developer.cisco.com/documents/4733862/4736722/xml_api_5+9.pdf
 * @link https://github.com/joubertredrat/phpebex-php-webex
 */

class Webex {
	
	private $username;
	private $password;
	private $siteID;
	private $partnerID;

	private $url_prefix;
	private $url_host;

	private $send_mode;

	private $data;

	private $action;

	const SEND_CURL 			= 'curl';
	const SEND_FSOCKS 			= 'fsocks';
	const PREFIX_HTTP 			= 'http';
	const PREFIX_HTTPS 			= 'https';
	const SUFIX_XML_API 		= 'WBXService/XMLService';
	const WEBEX_DOMAIN 			= 'webex.com';
	const XML_VERSION			= '1.0';
	const XML_ENCODING			= 'UTF-8';
	const USER_AGENT			= '';

	const API_SCHEMA_MEETING	= 'http://www.webex.com/schemas/2002/06/service/meeting';
	const API_SCHEMA_SERVICE	= 'http://www.webex.com/schemas/2002/06/service';

	const DATA_SENDER				= 'sender';
	const DATA_SENDER_POST_HEADER 	= 'post_header';
	const DATA_SENDER_POST_BODY 	= 'post_body';
	const DATA_SENDER_XML 			= 'xml';
	const DATA_RESPONSE				= 'response';
	const DATA_RESPONSE_XML			= 'xml';
	const DATA_RESPONSE_DATA		= 'data';

	/**
	 * Constructor of class.
	 *
	 * @return void
	 */
	public function __construct() {
		$this->action = 0;
		$this->response = array();
		$this->send_mode = in_array(self::SEND_CURL, get_loaded_extensions()) ? self::SEND_CURL : self::SEND_FSOCKS;
	}

	/**
	 * Get a possible modes to send a POST data.
	 *
	 * @return array Returns a list of send modes.
	 */
	public static function get_sendmode() {
		return array(self::SEND_CURL, self::SEND_FSOCKS);
	}

	/**
	 * Validates a customer webex domain.
	 *
	 * @param string $url Url to validate.
	 * @return bool Return true if a valid url or false if not.
	 */
	public static function validate_url($url) {
		$regex = "/^(http|https):\/\/(([A-Z0-9][A-Z0-9_-]*)+.(" . self::WEBEX_DOMAIN . ")$)/i";
		return (bool) preg_match($regex, $url);
	}

	/**
	 * Get port used by API.
	 *
	 * @param string $prefix Prefix to get a port.
	 * @return int Return a port.
	 */
	public static function get_port($prefix) {
		switch($prefix) {
			case self::PREFIX_HTTP:
				return 80;
			break;
			case self::PREFIX_HTTPS:
				return 443;
			break;
			default:
				exit(__CLASS__ . ' error report: Wrong prefix');
			break;
		}
	}

	/**
	 * Mode to send data.
	 *
	 * @param string mode to send.
	 * @return void
	 */
	public function set_sendmode($mode) {
		if(!in_array($mode, self::get_sendmode()))
			exit(__CLASS__ . ' error report: Wrong send mode');
		$this->send_mode = $mode;
	}

	/**
	 * Auth data to integrate with API.
	 *
	 * @param string $username Username to auth.
	 * @param string $password Password to auth.
	 * @param string $siteID Customer site id.
	 * @param string $partnerID Customer partnerID id.
	 * @return void
	 */
	public function set_auth($username, $password, $siteID, $partnerID, $url) {
		$this->username 	= $username;
		$this->password 	= $password;
		$this->siteID 		= $siteID;
		$this->partnerID 	= $partnerID;
		if(!self::validate_url($url))
			exit(__CLASS__ . ' error report: Wrong webex url');
		list($this->url_prefix, $this->url_host) = preg_split("$://$", $url);
	}

	/**
	 * Generates a XML to send a data to API.
	 *
	 * @param array $data Data to insert in XML in format:
	 *		$data['service']	= 'meeting';
	 *		$data['xml_header'] = '<item><subitem>data</subitem></item>';
	 *		$data['xml_body']	= '<item><subitem>data</subitem></item>';
	 * @return string Returns a XML generated.
	 */
	private function get_xml($data) {
		$xml 	= array();
		$xml[]	= '<?xml version="' . self::XML_VERSION . '" encoding="' . self::XML_ENCODING . '"?>';
		$xml[]	= 	'<serv:message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
		$xml[]	= 		'<header>';
		$xml[]	= 			'<securityContext>';
		$xml[]	= 				'<webExID>' . $this->username . '</webExID>';
		$xml[]	= 				'<password>' . $this->password . '</password>';
		$xml[]	= 				'<siteID>' . $this->siteID . '</siteID>';
		$xml[]	= 				'<partnerID>' . $this->partnerID . '</partnerID>';
		if(isset($data['xml_header']))
			$xml[]	= 			$data['xml_header'];
		$xml[]	= 			'</securityContext>';
		$xml[]	= 		'</header>';
		$xml[]	= 		'<body>';
		$xml[]	= 			'<bodyContent xsi:type="java:com.webex.service.binding.' . $data['service'] . '">';
		$xml[]	= 				$data['xml_body'];
		$xml[]	= 			'</bodyContent>';				
		$xml[]	= 		'</body>';
		$xml[]	= 	'</serv:message>';
		return implode('', $xml);
	}

	/**
	 * Test if have a auth data to use a API.
	 *
	 * @return bool Returns true if have data and false if not.
	 */
	public function has_auth() {
		return (bool) $this->username && $this->password && $this->siteID && $this->partnerID;
	}

	/**
	 * Generates a header and a body to send data to API.
	 *
	 * @return string Returns a response from API.
	 */
	private function send($xml) {
		$post_data['UID'] = $this->username;
		$post_data['PWD'] = $this->password;
		$post_data['SID'] = $this->siteID;
		$post_data['PID'] = $this->partnerID;
		$post_data['XML'] = $xml;

		// Really I dont know why xml api give a error on http_build_query :(
		$post_string = '';
		foreach ($post_data as $variable => $value) {
			$post_string .= '' . $variable . '=' . urlencode($value) . '&';
		}

		$post_header 		= array();
		$post_header[] 		= 'POST /' . self::SUFIX_XML_API . ' HTTP/1.0';
		$post_header[] 		= 'Host: ' . $this->url_host;
		$post_header[] 		= 'User-Agent: ' . self::USER_AGENT;
		if($this->send_mode == self::SEND_FSOCKS) {
			$post_header[] 	= 'Content-Type: application/xml';
			$post_header[] 	= 'Content-Length: ' . strlen($xml);
		}
		$data = array();
		$data['post_header'] = $post_header;
		$data['post_string'] = $post_string;

		$this->data[$this->action][self::DATA_SENDER][self::DATA_SENDER_POST_HEADER] 	= $post_header;
		$this->data[$this->action][self::DATA_SENDER][self::DATA_SENDER_POST_BODY] 		= $post_header;
		$this->data[$this->action][self::DATA_SENDER][self::DATA_SENDER_XML] 			= $xml;
		return $this->{'send_' . $this->send_mode}($data);
	}

	/**
	 * Send a data to Webex API using PHP curl.
	 *
	 * @param array $data Data to send to API in format:
	 * 		$data['post_header'] = "blablabla";
	 * 		$data['post_header'] = "post_string";
	 * @return string Returns a response from API.
	 */
	private function send_curl($data) {
		extract($data);
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $this->url_prefix . '://' . $this->url_host . '/' . self::SUFIX_XML_API);
		curl_setopt($ch, CURLOPT_PORT, self::get_port($this->url_prefix));
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $post_header);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$response = curl_exec($ch);
		if($response === false)
			exit(__CLASS__ . ' error report: Curl error - ' . curl_error($ch));
		curl_close($ch);
		return $response;
	}

	/**
	 * Send a data to Webex API using PHP file functions.
	 *
	 * @param array $data Data to send to API in format:
	 * 		$data['post_header'] = "blablabla";
	 * 		$data['post_header'] = "post_string";
	 * @return string Returns a response from API.
	 * @todo haha, I need to test this :)
	 */
	private function send_fsocks($data) {
		extract($data);
		$post_data = implode("\n", $post_header) . "\n\n" . $post_string . "\n";
		$fp = fsockopen($this->url_host, self::get_port($this->url_prefix), $errno, $error);
		if($fp) {
			fwrite($fp, $post_data);
			$response = '';
			while(!feof($fp)) {
				$response .= fgets($fp, 1024);
			}
			return $response;
		}
		else
			exit(__CLASS__ . ' error report: Fsocks error - (' . $errno . ') ' . $error);
	}

	/**
	 * Get response from a API.
	 *
	 * @param string $type Type of data to be requested.
	 * @param int $number number of sender to be requested.
	 * @return string|object Return a response.
	 */
	public function get_response($type = self::DATA_RESPONSE_DATA, $number = null) {
		if(isset($number) && is_int($number)) {
			if($number < 1 || $number > ($this->action - 1))
				exit(__CLASS__ . ' error report: Invalid response number');
			$number--;
		}
		else
			$number = ($this->action - 1);
		var_dump($number);
		switch($type) {
			case self::DATA_RESPONSE_XML:
			case self::DATA_RESPONSE_DATA:
				return $this->data[$number][self::DATA_RESPONSE][$type];
			break;
			default:
				exit(__CLASS__ . ' error report: I don\'t undestood that data you needs');
			break;
		}
	}

	/**
	 * @todo documentate in future.
	 */
	public function meeting_LstsummaryMeeting($maximumNum = 100) {
		if(!$this->has_auth())
			exit(__CLASS__ . ' error report: Auth data not found');
		$xml_body 	= array();
		$xml_body[] = '<listControl>';
		$xml_body[] = 	'<startFrom/>';
		$xml_body[] = 		'<maximumNum>' . $maximumNum . '</maximumNum>';
		$xml_body[] = '</listControl>';
		$xml_body[] = '<order>';
		$xml_body[] = 	'<orderBy>STARTTIME</orderBy>';
		$xml_body[] = 	'<orderAD>DESC</orderAD>';
		$xml_body[] = '</order>';
		$xml_body[] = '<dateScope>';
		$xml_body[] = '</dateScope>';

		$data['xml_body'] 	= implode('', $xml_body);
		$data['service'] 	= str_replace("_", ".", __FUNCTION__);
		$xml 				= $this->get_xml($data);
		$response 			= $this->send($xml);
		$xml 						= simplexml_load_string($response);
		$Data 						= new stdClass;
		$Data->header 				= new stdClass;
		$Data->header->response 	= new stdClass;
		$Data->bodyContent 			= array();

		$node 								= $xml->children(self::API_SCHEMA_SERVICE);
		$Data->header->response->result 	= (string) $node[0]->response->result;
		$Data->header->response->gsbStatus 	= (string) $node[0]->response->gsbStatus;

		$node_meeting = $node[1]->bodyContent;

		foreach($node_meeting->children(self::API_SCHEMA_MEETING) as $meeting) {
			//echo "<pre>";//print_r($meeting);echo "*--------------------------------*";
			if($meeting->meetingKey) {
				$MeetingData 						= new stdClass;
				$MeetingData->meetingKey 			= (string) $meeting->meetingKey;
				$MeetingData->confName 				= (string) $meeting->confName;
				$MeetingData->meetingType 			= (string) $meeting->meetingType;
				$MeetingData->hostWebExID 			= (string) $meeting->hostWebExID;
				$MeetingData->otherHostWebExID 		= (string) $meeting->otherHostWebExID;
				$MeetingData->timeZoneID 			= (string) $meeting->timeZoneID;
				$MeetingData->timeZone 				= (string) $meeting->timeZone;
				$MeetingData->status 				= (string) $meeting->status;
				$MeetingData->startDate 			= (string) $meeting->startDate;
				$MeetingData->duration 				= (string) $meeting->duration;
				$MeetingData->listStatus 			= (string) $meeting->listStatus;
				$MeetingData->hostJoined 			= (string) $meeting->hostJoined;
				$MeetingData->participantsJoined 	= (string) $meeting->participantsJoined;
				$MeetingData->telePresence 			= (string) $meeting->telePresence;
				$Data->bodyContent[] 				= $MeetingData;
			}
		}
		
		$this->data[$this->action][self::DATA_RESPONSE][self::DATA_RESPONSE_DATA] 	= $Data;
		$this->data[$this->action][self::DATA_RESPONSE][self::DATA_RESPONSE_XML] 	= $response;
		$this->action++;
		//print_r($response);
		return $Data;
	}
	
	function create_meeting($meeting_password='', $title='', $duration='20', $start_date=''){
		$xml = '';
		$xml = '<serv:message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
		$xml .= '<header>';
		$xml .= '<securityContext>';
		$xml .= 	'<webExID>' . $this->username . '</webExID>';
		$xml .= 	'<password>' . $this->password . '</password>';
		$xml .= 	'<siteID>' . $this->siteID . '</siteID>';
		$xml .= 	'<partnerID>' . $this->partnerID . '</partnerID>';
		$xml .= '</securityContext>';
		$xml .= '</header>';
		$xml .= '<body>';
		$xml .= '<bodyContent xsi:type="java:com.webex.service.binding.meeting.CreateMeeting">';
        
        if($meeting_password!=''){
			$xml .= '<accessControl>';
				$xml .= '<meetingPassword>'.$meeting_password.'</meetingPassword>';
			$xml .= '</accessControl>';
		}
		
        $xml .= '<metaData>';
            $xml .= '<confName>'.$title.'</confName>';
            //$xml .= '<meetingType>105</meetingType>';
        $xml .= '</metaData>';

        $xml .= '<enableOptions>';
            $xml .= '<multiVideo>True</multiVideo>';
            $xml .= '<audioVideo>True</audioVideo>';
            $xml .= '<supportUCFRichMedia>true</supportUCFRichMedia>';
            $xml .= '<chatAllAttendees>true</chatAllAttendees>';
            $xml .= '<chatHost>true</chatHost>';
            $xml .= '<chatPresenter>true</chatPresenter>';
            $xml .= '<attendeeList>true</attendeeList>';
            $xml .= '<voip>true</voip>';
        $xml .= '</enableOptions>';
       $xml .='<telephony>';
           $xml .='<telephonySupport>OTHER</telephonySupport>';
           $xml .='<extTelephonyDescription>!#TollFreeCallInCountryCode:1_1
					!#TollFreeCallInTelephonyCountryCode:+1
					!#TollFreeCallInNumber:8003477829
					!#ParticipantCode:194187</extTelephonyDescription>';
        $xml .='</telephony>';
        /*$xml .='<participants>';
            $xml .='<maxUserNumber>6</maxUserNumber>';
            //$xml .='<maxUserNumber>'.$userNumbers.'</maxUserNumber>';
            $xml .='<attendees>';
                $xml .='<attendee>';   
                    $xml .='<person>';
                        $xml .='<name>'.$host_name.'</name>';
                        $xml .='<email>'.$host_email.'</email>';
                    $xml .='</person>';
                    $xml .='<role>HOST</role>';
                $xml .='</attendee>';
                $xml .='<attendee>';   
                    $xml .='<person>';
                        $xml .='<name>'.$speaker_name.'</name>';
                        $xml .='<email>'.$speaker_email.'</email>';
                    $xml .='</person>';
                    $xml .='<role>ATTENDEE</role>';
                $xml .='</attendee>';
            $xml .='</attendees>';
        $xml .='</participants>';*/

        $xml .= '<schedule>';
            $xml .= '<startDate>'.$start_date.'</startDate>';
            $xml .= '<duration>'.$duration.'</duration>';
           // if($time_zome!='')$xml .= '<timeZoneID>20</timeZoneID>';
        $xml .= '</schedule>';
		$xml .= '</bodyContent>';
		$xml .= '</body>';
		$xml .= '</serv:message>';
		$response 	= $this->send($xml);
		return $response;
	}
	
	function delete_meeting($meetingID){
		$xml = '';
		$xml = '<serv:message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
		$xml .= '<header>';
		$xml .= '<securityContext>';
		$xml .= 	'<webExID>' . $this->username . '</webExID>';
		$xml .= 	'<password>' . $this->password . '</password>';
		$xml .= 	'<siteID>' . $this->siteID . '</siteID>';
		$xml .= 	'<partnerID>' . $this->partnerID . '</partnerID>';
		$xml .= '</securityContext>';
		$xml .= '</header>';
		
		$xml .= '<body>';
		$xml .= '<bodyContent xsi:type="java:com.webex.service.binding.meeting.DelMeeting">';
		$xml .= '<meetingKey>'.$meetingID.'</meetingKey>';
		$xml .= '</bodyContent>';
		$xml .= '</body>';
		$xml .= '</serv:message>';
		$response 	= $this->send($xml);
		return $response;
	}
	
	function get_meeting($meetingID){
		$xml = '';
		$xml = '<serv:message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
		$xml .= '<header>';
		$xml .= '<securityContext>';
		$xml .= 	'<webExID>' . $this->username . '</webExID>';
		$xml .= 	'<password>' . $this->password . '</password>';
		$xml .= 	'<siteID>' . $this->siteID . '</siteID>';
		$xml .= 	'<partnerID>' . $this->partnerID . '</partnerID>';
		$xml .= '</securityContext>';
		$xml .= '</header>';
		
		$xml .= '<body>';
		$xml .= '<bodyContent  xsi:type="java:com.webex.service.binding.meeting.GetMeeting">';
		$xml .= '<meetingKey>'.$meetingID.'</meetingKey>';
		$xml .= '</bodyContent>';
		$xml .= '</body>';
		$xml .= '</serv:message>';
		$response 	= $this->send($xml);
		$xml 						= simplexml_load_string($response);
		$Data 						= new stdClass;
		$Data->header 				= new stdClass;
		$Data->header->response 	= new stdClass;
		$Data->bodyContent 			= array();

		$node 								= $xml->children(self::API_SCHEMA_SERVICE);
		$Data->header->response->result 	= (string) $node[0]->response->result;
		$Data->header->response->gsbStatus 	= (string) $node[0]->response->gsbStatus;

		$node_meeting = $node[1]->bodyContent;
		
		foreach($node_meeting->children(self::API_SCHEMA_MEETING) as $meeting) {
			//echo "<pre>";print_r($meeting);echo "*--------------------------------*";
			if($meeting->meetingPassword) {
				$MeetingData['meetingPassword'] = (string) $meeting->meetingPassword;
			}
			if($meeting->confName) {
				$MeetingData['confName'] = (string) $meeting->confName;
			}
			if($meeting->maxUserNumber) {
				$MeetingData['maxUserNumber'] = (string) $meeting->maxUserNumber;
			}
			if($meeting->startDate) {
				$MeetingData['startDate'] = (string) $meeting->startDate;
			}
			if($meeting->timeZone) {
				$MeetingData['timeZone'] = (string) $meeting->timeZone;
			}
			if($meeting->duration) {
				$MeetingData['duration'] = (string) $meeting->duration;
			}
			if($meeting->hostWebExID) {
				$MeetingData['hostWebExID'] = (string) $meeting->hostWebExID;
			}
			if($meeting->telephonySupport) {
				$MeetingData['telephonySupport'] = (string) $meeting->telephonySupport;
			}
			if($meeting->timeZoneID) {
				$MeetingData['timeZoneID'] = (string) $meeting->timeZoneID;
			}
			if($meeting->meetingType) {
				$MeetingData['meetingType'] = (string) $meeting->meetingType;
			}
		}
		
		
		//print_r($response);
		return $MeetingData;
	}
}
