<commit_before><?php
/**
* Jaxl (Jabber XMPP Library)
*
* Copyright (c) 2009-2012, <NAME> <<EMAIL>>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of <NAME> nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/

require_once JAXL_CWD.'/xmpp/xmpp_nss.php';
require_once JAXL_CWD.'/xmpp/xmpp_jid.php';
require_once JAXL_CWD.'/xmpp/xmpp_msg.php';
require_once JAXL_CWD.'/xmpp/xmpp_pres.php';
require_once JAXL_CWD.'/xmpp/xmpp_iq.php';

require_once JAXL_CWD.'/core/jaxl_xml.php';
require_once JAXL_CWD.'/core/jaxl_xml_stream.php';
require_once JAXL_CWD.'/core/jaxl_util.php';
require_once JAXL_CWD.'/core/jaxl_socket.php';

/**
 * 
 * Enter description here ...
 * @author abhinavsingh
 *
 */
abstract class XMPPStream {
	
	private $state = "setup";
	
	// jid with binding resource value
	public $full_jid = null;
	
	// input parameters
	public $jid = null;
	public $pass = null;
	public $resource = null;
	public $force_tls = false;
	
	// underlying socket/bosh and xml stream ref
	protected $trans = null;
	protected $xml = null;
	
	// stanza id
	protected $last_id = 0;
	
	//
	// abstract methods
	//
	
	abstract public function handle_stream_start($stanza);
	abstract public function handle_auth_mechs($mechs);
	abstract public function handle_auth_success();
	abstract public function handle_auth_failure($reason);
	abstract public function handle_iq($stanza);
	abstract public function handle_presence($stanza);
	abstract public function handle_message($stanza);
	abstract public function handle_other($event, $args);
	
	//
	// public api
	// 
	
	public function __construct($transport, $jid, $pass=null, $resource=null, $force_tls=false) {
		$this->jid = $jid;
		$this->pass = $<PASSWORD>;
		$this->resource = $resource ? $resource : md5(time());
		$this->force_tls = $force_tls;
		
		$this->trans = $transport;
		$this->xml = new JAXLXmlStream();
		
		$this->trans->set_callback(array(&$this->xml, "parse"));
		$this->xml->set_callback(array(&$this, "start_cb"), array(&$this, "end_cb"), array(&$this, "stanza_cb"));
	}
	
	public function __destruct() {
		//_debug("cleaning up xmpp stream...");
	}
	
	public function __call($event, $args) {
		if($this->state) {
			_debug("calling ".$this->state." for event ".$event."");
			$r = call_user_func(array(&$this, $this->state), $event, $args);
			
			if(is_array($r) && sizeof($r) == 2) {
				list($this->state, $ret) = $r;
			}
			else if(is_array($r) && sizeof($r) == 1) {
				$this->state = $r[0];
			}
			else {
				$this->state = $r;
			}
			
			_debug("current state ".$this->state);
			if(is_array($r) && sizeof($r) == 2) return $ret;
		}
		else {
			_debug("invalid state found, nothing called for event ".$event."");
		}
	}
	
	public function send($stanza) {
		$this->trans->send($stanza->to_string());
	}
	
	public function send_raw($data) {
		$this->trans->send($data);
	}
	
	//
	// pkt creation utilities
	//
	
	public function get_start_stream($jid) {
		return '<stream:stream xmlns:stream="'.NS_XMPP.'" version="1.0" from="'.$jid->bare.'" to="'.$jid->domain.'" xmlns="'.NS_JABBER_CLIENT.'" xml:lang="en" xmlns:xml="'.NS_XML.'">';
	}
	
	public function get_end_stream() {
		return '</stream:stream>';
	}
	
	public function get_starttls_pkt() {
		$stanza = new JAXLXml('starttls', NS_TLS);
		return $stanza;
	}
	
	public function get_compress_pkt($method) {
		$stanza = new JAXLXml('compress', NS_COMPRESSION_PROTOCOL);
		$stanza->c('method')->t($method);
		return $stanza;
	}
	
	public function get_auth_pkt($mechanism, $user, $pass) {
		$stanza = new JAXLXml('auth', NS_SASL, array('mechanism'=>$mechanism));
		
		switch($mechanism) {
			case 'PLAIN':
				$stanza->t(base64_encode("\x00".$user."\x00".$pass));
				break;
			case 'DIGEST-MD5':
				break;
			case 'CRAM-MD5':
				break;
			case 'SCRAM-SHA-1':
				break;
			case 'ANONYMOUS':
				break;
			default:
				break;
		}
		
		return $stanza;
	}
	
	public function get_challenge_response_pkt($challenge) {
		$stanza = new JAXLXml('response', NS_SASL);
		$decoded = $this->explode_data(base64_decode($challenge));
		
		if(!isset($decoded['rspauth'])) {
			_debug("calculating response to challenge");
			$stanza->t($this->get_challenge_response($decoded));
		}<commit_msg>In EXTERNAL auth case with certificates (no password set), put '=' in the stanza to follow RFC 6120<commit_after><?php
/**
* Jaxl (Jabber XMPP Library)
*
* Copyright (c) 2009-2012, <NAME> <<EMAIL>>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of <NAME> nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/

require_once JAXL_CWD.'/xmpp/xmpp_nss.php';
require_once JAXL_CWD.'/xmpp/xmpp_jid.php';
require_once JAXL_CWD.'/xmpp/xmpp_msg.php';
require_once JAXL_CWD.'/xmpp/xmpp_pres.php';
require_once JAXL_CWD.'/xmpp/xmpp_iq.php';

require_once JAXL_CWD.'/core/jaxl_xml.php';
require_once JAXL_CWD.'/core/jaxl_xml_stream.php';
require_once JAXL_CWD.'/core/jaxl_util.php';
require_once JAXL_CWD.'/core/jaxl_socket.php';

/**
 * 
 * Enter description here ...
 * @author abhinavsingh
 *
 */
abstract class XMPPStream {
	
	private $state = "setup";
	
	// jid with binding resource value
	public $full_jid = null;
	
	// input parameters
	public $jid = null;
	public $pass = null;
	public $resource = null;
	public $force_tls = false;
	
	// underlying socket/bosh and xml stream ref
	protected $trans = null;
	protected $xml = null;
	
	// stanza id
	protected $last_id = 0;
	
	//
	// abstract methods
	//
	
	abstract public function handle_stream_start($stanza);
	abstract public function handle_auth_mechs($mechs);
	abstract public function handle_auth_success();
	abstract public function handle_auth_failure($reason);
	abstract public function handle_iq($stanza);
	abstract public function handle_presence($stanza);
	abstract public function handle_message($stanza);
	abstract public function handle_other($event, $args);
	
	//
	// public api
	// 
	
	public function __construct($transport, $jid, $pass=<PASSWORD>, $resource=null, $force_tls=false) {
		$this->jid = $jid;
		$this->pass = $pass;
		$this->resource = $resource ? $resource : md5(time());
		$this->force_tls = $force_tls;
		
		$this->trans = $transport;
		$this->xml = new JAXLXmlStream();
		
		$this->trans->set_callback(array(&$this->xml, "parse"));
		$this->xml->set_callback(array(&$this, "start_cb"), array(&$this, "end_cb"), array(&$this, "stanza_cb"));
	}
	
	public function __destruct() {
		//_debug("cleaning up xmpp stream...");
	}
	
	public function __call($event, $args) {
		if($this->state) {
			_debug("calling ".$this->state." for event ".$event."");
			$r = call_user_func(array(&$this, $this->state), $event, $args);
			
			if(is_array($r) && sizeof($r) == 2) {
				list($this->state, $ret) = $r;
			}
			else if(is_array($r) && sizeof($r) == 1) {
				$this->state = $r[0];
			}
			else {
				$this->state = $r;
			}
			
			_debug("current state ".$this->state);
			if(is_array($r) && sizeof($r) == 2) return $ret;
		}
		else {
			_debug("invalid state found, nothing called for event ".$event."");
		}
	}
	
	public function send($stanza) {
		$this->trans->send($stanza->to_string());
	}
	
	public function send_raw($data) {
		$this->trans->send($data);
	}
	
	//
	// pkt creation utilities
	//
	
	public function get_start_stream($jid) {
		return '<stream:stream xmlns:stream="'.NS_XMPP.'" version="1.0" from="'.$jid->bare.'" to="'.$jid->domain.'" xmlns="'.NS_JABBER_CLIENT.'" xml:lang="en" xmlns:xml="'.NS_XML.'">';
	}
	
	public function get_end_stream() {
		return '</stream:stream>';
	}
	
	public function get_starttls_pkt() {
		$stanza = new JAXLXml('starttls', NS_TLS);
		return $stanza;
	}
	
	public function get_compress_pkt($method) {
		$stanza = new JAXLXml('compress', NS_COMPRESSION_PROTOCOL);
		$stanza->c('method')->t($method);
		return $stanza;
	}
	
	public function get_auth_pkt($mechanism, $user, $pass) {
		$stanza = new JAXLXml('auth', NS_SASL, array('mechanism'=>$mechanism));
		
		switch($mechanism) {
			case 'PLAIN':
				$stanza->t(base64_encode("\x00".$user."\x00".$pass));
				break;
			case 'DIGEST-MD5':
				break;
			case 'CRAM-MD5':
				break;
			case 'SCRAM-SHA-1':
				break;
			case 'ANONYMOUS':
				break;
			case 'EXTERNAL':
				// If no password, then we are probably doing certificate auth, so follow RFC 6120 form and pass '='.
				if(strlen($pass) == 0)
					$stanza->t('=');
				break;
			default:
				break;
		}
		
		return $stanza;
	}
	
	public function get_challenge_response_pkt($challenge) {
		$stanza = new JAXLXml('response', NS_SASL);
		$decoded = $this->explode_data(base64_decode($challenge));
		
		if(!isset($decoded['rspauth'])) {
			_debug("calculating response to challenge");
			$stanza->t($this->get_challenge_response($decoded));
		}
{'fraction_non_alphanumeric': 0.1434325744308231, 'fraction_numerical': 0.005516637478108582, 'mean_word_length': 4.238990825688074, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 82, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 24}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7018292', 'n_tokens_mistral': 4274, 'n_tokens_neox': 3790, 'n_words': 1051}