diff options
Diffstat (limited to 'phpBB/includes/functions_jabber.php')
-rw-r--r-- | phpBB/includes/functions_jabber.php | 1635 |
1 files changed, 468 insertions, 1167 deletions
diff --git a/phpBB/includes/functions_jabber.php b/phpBB/includes/functions_jabber.php index 3872346bbc..3ad96df928 100644 --- a/phpBB/includes/functions_jabber.php +++ b/phpBB/includes/functions_jabber.php @@ -10,665 +10,212 @@ /** * -* Class.Jabber.PHP v0.4.2 -* (c) 2004 Nathan "Fritzy" Fritz -* http://cjphp.netflint.net *** fritzy@netflint.net +* Jabber class from Flyspray project +* @version class.jabber2.php 1209 2007-05-12 13:39:10Z floele +* @copyright 2006 Flyspray.org +* @author: Florian Schmitz (floele) * -* This is a bugfix version, specifically for those who can't get -* 0.4 to work on Jabberd2 servers. -* -* last modified: 24.03.2004 13:01:53 -* -* Modified by phpBB Development Team -* version: v0.4.3 +* Modified by Acyd Burn * * @package phpBB3 */ class jabber { + var $connection = null; + var $session = array(); + var $timeout = 10; + var $server; var $port; var $username; var $password; - var $resource; - var $jid; - - var $connection; - var $delay_disconnect; - - var $stream_id; + var $use_ssl; var $enable_logging; var $log_array; - var $iq_sleep_timer; - var $last_ping_time; - - var $packet_queue; - - var $iq_version_name; - var $iq_version_os; - var $iq_version_version; - - var $error_codes; - - var $connected; - var $keep_alive_id; - var $returned_keep_alive; - var $txnid; - - var $connector; + var $features = array(); - var $version; - var $show_version; - - /** - * Constructor - */ - function jabber($server, $port, $username, $password, $resource) + function jabber($server, $port, $username, $password, $use_ssl = false) { $this->server = ($server) ? $server : 'localhost'; - $this->port = ($port) ? $port : '5222'; + $this->port = ($port) ? $port : 5222; $this->username = $username; $this->password = $password; - $this->resource = ($resource) ? $resource : NULL; - - $this->enable_logging = true; - $this->log_array = array(); + $this->use_ssl = ($use_ssl && $this->can_use_ssl) ? true : false; - $this->version = '1.0'; - $this->show_version = false; - - $this->packet_queue = array(); - $this->iq_sleep_timer = $this->delay_disconnect = 1; - - $this->returned_keep_alive = true; - $this->txnid = 0; - - $this->iq_version_name = "Class.Jabber.PHP -- http://cjphp.netflint.net -- by Nathan 'Fritzy' Fritz, fritz@netflint.net"; - $this->iq_version_version = '0.4'; - $this->iq_version_os = $_SERVER['SERVER_SOFTWARE']; - - $this->error_codes = array( - 400 => 'Bad Request', - 401 => 'Unauthorised', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Registration Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Remove Server Error', - 503 => 'Service Unavailable', - 504 => 'Remove Server Timeout', - 510 => 'Disconnected' - ); - } - - /** - * Connect - */ - function connect() - { - $this->connector = new cjp_standard_connector; - - if ($this->connector->open_socket($this->server, $this->port)) + // Change port if we use SSL + if ($this->port == 5222 && $this->use_ssl) { - $this->send_packet("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); - $this->send_packet("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'" . (($this->show_version) ? " version='{$this->version}'" : '') . ">\n"); - - sleep(2); - - if ($this->_check_connected()) - { - $this->connected = true; // Nathan Fritz - return true; - } - else - { - $this->add_to_log('ERROR: connect() #1'); - return false; - } + $this->port = 5223; } - else - { - $this->add_to_log('ERROR: connect() #2'); - return false; - } - } - - /** - * Disconnect - */ - function disconnect() - { - if (is_int($this->delay_disconnect)) - { - sleep($this->delay_disconnect); - } - - $this->send_packet('</stream:stream>'); - $this->connector->close_socket(); - } - - /** - * Send authentication request - */ - function send_auth() - { - $this->auth_id = 'auth_' . md5(time() . $_SERVER['REMOTE_ADDR']); - $this->resource = ($this->resource != NULL) ? $this->resource : ('Class.Jabber.PHP ' . md5($this->auth_id)); - $this->jid = "{$this->username}@{$this->server}/{$this->resource}"; - - // request available authentication methods - $payload = "<username>{$this->username}</username>"; - $packet = $this->send_iq(NULL, 'get', $this->auth_id, 'jabber:iq:auth', $payload); - - // was a result returned? - if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) - { - // yes, now check for auth method availability in descending order (best to worst) - if (isset($packet['iq']['#']['query'][0]['#']['sequence'][0]['#']) && isset($packet['iq']['#']['query'][0]['#']['token'][0]['#'])) - { - // auth_0k - return $this->_sendauth_ok($packet['iq']['#']['query'][0]['#']['token'][0]['#'], $packet['iq']['#']['query'][0]['#']['sequence'][0]['#']); - } - else if (isset($packet['iq']['#']['query'][0]['#']['digest'])) - { - // digest - return $this->_sendauth_digest(); - } - else if ($packet['iq']['#']['query'][0]['#']['password']) - { - // plain text - return $this->_sendauth_plaintext(); - } - else - { - $this->add_to_log('ERROR: send_auth() #2 - No auth method available!'); - return false; - } - } - else - { - // no result returned - $this->add_to_log('ERROR: send_auth() #1'); - return false; - } - } - - /** - * Register account - */ - function account_registration($reg_email = NULL, $reg_name = NULL) - { - $packet = $this->send_iq($this->server, 'get', 'reg_01', 'jabber:iq:register'); - - if ($packet) - { - // just in case a key was passed back from the server - $key = $this->get_info_from_iq_key($packet); - unset($packet); - - $payload = "<username>{$this->username}</username> - <password>{$this->password}</password> - <email>$reg_email</email> - <name>$reg_name</name>\n"; - - $payload .= ($key) ? "<key>$key</key>\n" : ''; - $packet = $this->send_iq($this->server, 'set', 'reg_01', 'jabber:iq:register', $payload); - - if ($this->get_info_from_iq_type($packet) == 'result') - { - $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; - $this->jid = ($this->resource) ? "{$this->username}@{$this->server}/{$this->resource}" : "{$this->username}@{$this->server}"; - } - else if ($this->get_info_from_iq_type($packet) == 'error' && isset($packet['iq']['#']['error'][0]['#'])) - { - // "conflict" error, i.e. already registered - if ($packet['iq']['#']['error'][0]['@']['code'] == '409') - { - $return_code = 1; - } - else - { - $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; - } - } - - return $return_code; - } - else - { - return 3; - } + $this->enable_logging = true; + $this->log_array = array(); } /** - * Change password + * Able to use the SSL functionality? */ - function change_password($new_password) + function can_use_ssl() { - $packet = $this->send_iq($this->server, 'get', 'A0', 'jabber:iq:register'); - - if ($packet) - { - // just in case a key was passed back from the server - $key = $this->get_info_from_iq_key($packet); - unset($packet); - - $payload = "<username>{$this->username}</username> - <password>{$new_password}</password>\n"; - $payload .= ($key) ? "<key>$key</key>\n" : ''; - - $packet = $this->send_iq($this->server, 'set', 'A0', 'jabber:iq:register', $payload); - - if ($this->get_info_from_iq_type($packet) == 'result') - { - $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; - } - else if ($this->get_info_from_iq_type($packet) == 'error' && isset($packet['iq']['#']['error'][0]['#'])) - { - // "conflict" error, i.e. already registered - if ($packet['iq']['#']['error'][0]['@']['code'] == '409') - { - $return_code = 1; - } - else - { - $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; - } - } - - return $return_code; - } - else - { - return 3; - } + // Will not work with PHP >= 5.2.1 until timeout problem with ssl hasn't been fixed (http://bugs.php.net/41236) + return (version_compare(PHP_VERSION, '5.2.1', '<') && @extension_loaded('openssl')) ? true : false; } /** - * Send packet + * Able to use TLS? */ - function send_packet($xml) + function can_use_tls() { - $xml = trim($xml); - - if ($this->connector->write_to_socket($xml)) + if (!@extension_loaded('openssl') || !function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('socket_set_blocking') || !function_exists('stream_get_wrappers')) { - $this->add_to_log('SEND: ' . $xml); - return true; - } - else - { - $this->add_to_log('ERROR: send_packet() #1'); return false; } - } - - /** - * Listen to socket - */ - function listen() - { - $incoming = ''; - - while ($line = $this->connector->read_from_socket(4096)) - { - $incoming .= $line; - } - $incoming = trim($incoming); + // Make sure the encryption stream is supported + $streams = stream_get_wrappers(); - if ($incoming != '') + if (!in_array('streams.crypto', $streams)) { - $this->add_to_log('RECV: ' . $incoming); - $temp = $this->_split_incoming($incoming); - - for ($i = 0, $size = sizeof($temp); $i < $size; $i++) - { - $this->packet_queue[] = $this->xmlize($temp[$i]); - } + return false; } return true; } /** - * Strip jid - */ - function strip_jid($jid = NULL) - { - preg_match('#(.*)\/(.*)#Ui', $jid, $temp); - return ($temp[1] != '') ? $temp[1] : $jid; - } - - /** - * Send a message + * Connect */ - function send_message($to, $type = 'normal', $id = NULL, $content = NULL, $payload = NULL) + function connect() { - if ($to && is_array($content)) - { - if (!$id) - { - $id = $type . '_' . time(); - } - - $this->_array_xmlspecialchars($content); - - $xml = "<message to='$to' type='$type' id='$id'>\n"; - - if (!empty($content['subject'])) - { - $xml .= '<subject>' . $content['subject'] . "</subject>\n"; - } - - if (!empty($content['thread'])) - { - $xml .= '<thread>' . $content['thread'] . "</thread>\n"; - } - - $xml .= '<body>' . $content['body'] . "</body>\n"; - $xml .= $payload; - $xml .= "</message>\n"; - - if ($this->send_packet($xml)) - { - return true; - } - else - { - $this->add_to_log('ERROR: send_message() #1'); - } - } - else +/* if (!$this->check_jid($this->username . '@' . $this->server)) { - $this->add_to_log('ERROR: send_message() #2'); + $this->add_to_log('Error: Jabber ID is not valid: ' . $this->username . '@' . $this->server); return false; - } - } - - /** - * Send presence - */ - function send_presence($type = NULL, $to = NULL, $status = NULL, $show = NULL, $priority = NULL) - { - $xml = '<presence'; - $xml .= ($to) ? " to='$to'" : ''; - $xml .= ($type) ? " type='$type'" : ''; - $xml .= ($status || $show || $priority) ? ">\n" : " />\n"; - - $xml .= ($status) ? " <status>$status</status>\n" : ''; - $xml .= ($show) ? " <show>$show</show>\n" : ''; - $xml .= ($priority) ? " <priority>$priority</priority>\n" : ''; + }*/ - $xml .= ($status || $show || $priority) ? "</presence>\n" : ''; + $this->session['ssl'] = $this->use_ssl; - if ($this->send_packet($xml)) + if ($this->open_socket($this->server, $this->port, $this->use_ssl)) { - return true; + $this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); + $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); } else { - $this->add_to_log('ERROR: send_presence() #1'); + $this->add_to_log('Error: connect() #2'); return false; } - } - - /** - * Send error - */ - function send_error($to, $id = NULL, $error_number, $error_message = NULL) - { - $xml = "<iq type='error' to='$to'"; - $xml .= ($id) ? " id='$id'" : ''; - $xml .= ">\n"; - $xml .= " <error code='$error_number'>"; - $xml .= ($error_message) ? $error_message : $this->error_codes[$error_number]; - $xml .= "</error>\n"; - $xml .= '</iq>'; - - $this->send_packet($xml); - } - /** - * Get first from queue - */ - function get_first_from_queue() - { - return array_shift($this->packet_queue); + // Now we listen what the server has to say...and give appropriate responses + $this->response($this->listen()); + return true; } /** - * Get from queue by id + * Disconnect */ - function get_from_queue_by_id($packet_type, $id) + function disconnect() { - $found_message = false; - - foreach ($this->packet_queue as $key => $value) + if ($this->connected()) { - if ($value[$packet_type]['@']['id'] == $id) + // disconnect gracefully + if (isset($this->session['sent_presence'])) { - $found_message = $value; - unset($this->packet_queue[$key]); - - break; + $this->presence('offline', '', true); } + + $this->send('</stream:stream>'); + $this->session = array(); + return fclose($this->connection); } - return (is_array($found_message)) ? $found_message : false; + return false; } /** - * Call handler + * Connected? */ - function call_handler($packet = NULL) + function connected() { - $packet_type = $this->_get_packet_type($packet); - - if ($packet_type == 'message') - { - $type = $packet['message']['@']['type']; - $type = ($type != '') ? $type : 'normal'; - $funcmeth = "handler_message_$type"; - } - else if ($packet_type == 'iq') - { - $namespace = $packet['iq']['#']['query'][0]['@']['xmlns']; - $namespace = str_replace(':', '_', $namespace); - $funcmeth = "handler_iq_$namespace"; - } - else if ($packet_type == 'presence') - { - $type = $packet['presence']['@']['type']; - $type = ($type != '') ? $type : 'available'; - $funcmeth = "handler_presence_$type"; - } - - if ($funcmeth != '') - { - if (function_exists($funcmeth)) - { - call_user_func($funcmeth, $packet); - } - else if (method_exists($this, $funcmeth)) - { - call_user_func(array(&$this, $funcmeth), $packet); - } - else - { - $this->handler_not_implemented($packet); - $this->add_to_log("ERROR: call_handler() #1 - neither method nor function $funcmeth() available"); - } - } + return (is_resource($this->connection) && !feof($this->connection)) ? true : false; } + /** - * Cruise Control + * Initiates login (using data from contructor, after calling connect()) + * @access public + * @return bool */ - function cruise_control($seconds = -1) + function login() { - $count = 0; - - while ($count != $seconds) + if (!sizeof($this->features)) { - $this->listen(); - - do - { - $packet = $this->get_first_from_queue(); - - if ($packet) - { - $this->call_handler($packet); - } - } - while (sizeof($this->packet_queue) > 1); - - $count += 0.25; - usleep(250000); - - if (($this->last_ping_time + 180) < time()) - { - // Modified by Nathan Fritz - if ($this->returned_keep_alive == false) - { - $this->connected = false; - $this->add_to_log('EVENT: Disconnected'); - } - - if ($this->returned_keep_alive == true) - { - $this->connected = true; - } - - $this->returned_keep_alive = false; - - $this->keep_alive_id = 'keep_alive_' . time(); - // $this->send_packet("<iq id='{$this->keep_alive_id}'/>", 'cruise_control'); - $this->send_packet("<iq type='get' from='{$this->username}@{$this->server}/{$this->resource}' to='{$this->server}' id='{$this->keep_alive_id}'><query xmlns='jabber:iq:time' /></iq>"); - $this->last_ping_time = time(); - } + $this->add_to_log('Error: No feature information from server available.'); + return false; } - return true; + return $this->response($this->features); } /** - * Send iq + * Send data to the Jabber server + * @param string $xml + * @access public + * @return bool */ - function send_iq($to = NULL, $type = 'get', $id = NULL, $xmlns = NULL, $payload = NULL, $from = NULL) + function send($xml) { - if (!preg_match('#^(get|set|result|error)$#', $type)) + if ($this->connected()) { - unset($type); - - $this->add_to_log("ERROR: send_iq() #2 - type must be 'get', 'set', 'result' or 'error'"); - return false; - } - else if ($id && $xmlns) - { - $xml = "<iq type='$type' id='$id'"; - $xml .= ($to) ? " to='" . htmlspecialchars($to) . "'" : ''; - $xml .= ($from) ? " from='$from'" : ''; - $xml .= "> - <query xmlns='$xmlns'> - $payload - </query> - </iq>"; - - $this->send_packet($xml); - sleep($this->iq_sleep_timer); - $this->listen(); - - return (preg_match('#^(get|set)$#', $type)) ? $this->get_from_queue_by_id('iq', $id) : true; + $xml = trim($xml); + $this->add_to_log('SEND: '. $xml); + return fwrite($this->connection, $xml); } else { - $this->add_to_log('ERROR: send_iq() #1 - to, id and xmlns are mandatory'); + $this->add_to_log('Error: Could not send, connection lost (flood?).'); return false; } } /** - * get the transport registration fields - * method written by Steve Blinch, http://www.blitzaffe.com + * OpenSocket + * @param string $server host to connect to + * @param int $port port number + * @param bool $use_ssl use ssl or not + * @access public + * @return bool */ - function transport_registration_details($transport) + function open_socket($server, $port, $use_ssl = false) { - $this->txnid++; - $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); - - if ($packet) + if (@function_exists('dns_get_record')) { - $res = array(); - - foreach ($packet['iq']['#']['query'][0]['#'] as $element => $data) + $record = dns_get_record("_xmpp-client._tcp.$server", DNS_SRV); + if (!empty($record)) { - if ($element != 'instructions' && $element != 'key') - { - $res[] = $element; - } + $server = $record[0]['target']; } - - return $res; } else { - return 3; + $this->add_to_log('Warning: dns_get_record function not found. GTalk will not work.'); } - } - /** - * register with the transport - * method written by Steve Blinch, http://www.blitzaffe.com - */ - function transport_registration($transport, $details) - { - $this->txnid++; - $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); + $server = $use_ssl ? 'ssl://' . $server : $server; - if ($packet) + if ($this->connection = @fsockopen($server, $port, $errorno, $errorstr, $this->timeout)) { - // just in case a key was passed back from the server - $key = $this->get_info_from_iq_key($packet); - unset($packet); - - $payload = ($key) ? "<key>$key</key>\n" : ''; - foreach ($details as $element => $value) - { - $payload .= "<$element>$value</$element>\n"; - } - - $packet = $this->send_iq($transport, 'set', "reg_{$this->txnid}", 'jabber:iq:register', $payload); - - if ($this->get_info_from_iq_type($packet) == 'result') - { - $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; - } - else if ($this->get_info_from_iq_type($packet) == 'error') - { - if (isset($packet['iq']['#']['error'][0]['#'])) - { - $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; - $this->add_to_log('ERROR: transport_registration()'); - } - } + socket_set_blocking($this->connection, 0); + socket_set_timeout($this->connection, 60); - return $return_code; - } - else - { - return 3; + return true; } + + // Apparently an error occured... + $this->add_to_log('Error: open_socket() - ' . $errorstr); + return false; } /** @@ -678,7 +225,7 @@ class jabber { if ($this->enable_logging && sizeof($this->log_array)) { - return implode("<br /><br />", $this->log_array); + return '<br /><br />' . implode("<br /><br />", $this->log_array); } return ''; @@ -691,640 +238,483 @@ class jabber { if ($this->enable_logging) { - $this->log_array[] = htmlspecialchars($string); + $this->log_array[] = utf8_htmlspecialchars($string); } } - - // ====================================================================== - // private methods - // ====================================================================== - /** - * Send auth - * @access private + * Listens to the connection until it gets data or the timeout is reached. + * Thus, it should only be called if data is expected to be received. + * @access public + * @return mixed either false for timeout or an array with the received data */ - function _sendauth_ok($zerok_token, $zerok_sequence) + function listen($timeout = 10, $wait = false) { - // initial hash of password - $zerok_hash = sha1($this->password); - - // sequence 0: hash of hashed-password and token - $zerok_hash = sha1($zerok_hash . $zerok_token); - - // repeat as often as needed - for ($i = 0; $i < $zerok_sequence; $i++) + if (!$this->connected()) { - $zerok_hash = sha1($zerok_hash); + return false; } - $payload = "<username>{$this->username}</username> - <hash>$zerok_hash</hash> - <resource>{$this->resource}</resource>"; - - $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); + // Wait for a response until timeout is reached + $start = time(); + $data = ''; - // was a result returned? - if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) + do { - return true; + $read = trim(fread($this->connection, 4096)); + $data .= $read; } - else - { - $this->add_to_log('ERROR: _sendauth_ok() #1'); - return false; - } - } + while (time() <= $start + $timeout && ($wait || $data == '' || $read != '' || (substr(rtrim($data), -1) != '>'))); - /** - * Send auth digest - * @access private - */ - function _sendauth_digest() - { - $payload = "<username>{$this->username}</username> - <resource>{$this->resource}</resource> - <digest>" . sha1($this->stream_id . $this->password) . "</digest>"; - - $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); - - // was a result returned? - if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) + if ($data != '') { - return true; + $this->add_to_log('RECV: '. $data); + return $this->xmlize($data); } else { - $this->add_to_log('ERROR: _sendauth_digest() #1'); + $this->add_to_log('Timeout, no response from server.'); return false; } } /** - * Send auth plain - * @access private + * Initiates account registration (based on data used for contructor) + * @access public + * @return bool */ - function _sendauth_plaintext() + function register() { - $payload = "<username>{$this->username}</username> - <password>{$this->password}</password> - <resource>{$this->resource}</resource>"; - - $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); - - // was a result returned? - if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) - { - return true; - } - else + if (!isset($this->session['id']) || isset($this->session['jid'])) { - $this->add_to_log('ERROR: _sendauth_plaintext() #1'); + $this->add_to_log('Error: Cannot initiate registration.'); return false; } + + $this->send("<iq type='get' id='reg_1'><query xmlns='jabber:iq:register'/></iq>"); + return $this->response($this->listen()); } /** - * Listen on socket - * @access private + * Sets account presence. No additional info required (default is "online" status) + * @param $message online, offline... + * @param $type dnd, away, chat, xa or nothing + * @access public + * @return bool */ - function _listen_incoming() + function send_presence($message = '', $type = '', $unavailable = false) { - $incoming = ''; - - while ($line = $this->connector->read_from_socket(4096)) + if (!isset($this->session['jid'])) { - $incoming .= $line; - } - - $incoming = trim($incoming); - - if ($incoming != '') - { - $this->add_to_log('RECV: ' . $incoming); + $this->add_to_log('ERROR: send_presence() - Cannot set presence at this point, no jid given.'); + return false; } - return $this->xmlize($incoming); - } + $type = strtolower($type); + $type = (in_array($type, array('dnd', 'away', 'chat', 'xa'))) ? '<show>'. $type .'</show>' : ''; - /** - * Check if connected - * @access private - */ - function _check_connected($in_tls = false) - { - $incoming_array = $this->_listen_incoming(); - - if (is_array($incoming_array)) - { - if ($incoming_array['stream:stream']['@']['from'] == $this->server && $incoming_array['stream:stream']['@']['xmlns'] == 'jabber:client' && $incoming_array['stream:stream']['@']['xmlns:stream'] == 'http://etherx.jabber.org/streams') - { - $this->stream_id = $incoming_array['stream:stream']['@']['id']; + $unavailable = ($unavailable) ? " type='unavailable'" : ''; + $message = ($message) ? '<status>' . utf8_htmlspecialchars($message) .'</status>' : ''; - // We only start TLS authentication if not called within TLS authentication itself, which may produce a never ending loop... - if (!$in_tls) - { - if (!empty($incoming_array['stream:stream']['#']['stream:features'][0]['#']['starttls'][0]['@']['xmlns']) && $incoming_array['stream:stream']['#']['stream:features'][0]['#']['starttls'][0]['@']['xmlns'] == 'urn:ietf:params:xml:ns:xmpp-tls') - { - return $this->_starttls(); - } - } + $this->session['sent_presence'] = !$unavailable; - return true; - } - else - { - $this->add_to_log('ERROR: _check_connected() #1'); - return false; - } - } - else - { - $this->add_to_log('ERROR: _check_connected() #2'); - return false; - } + return $this->send("<presence$unavailable>" . $type . $message . '</presence>'); } /** - * Start TLS/SSL session if supported (PHP5.1) - * @access private + * This handles all the different XML elements + * @param array $xml + * @access public + * @return bool */ - function _starttls() + function response($xml) { - if (!function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('socket_set_blocking') || !function_exists('stream_get_wrappers')) + if (!is_array($xml) || !sizeof($xml)) { - $this->add_to_log('WARNING: TLS is not available'); - return true; - } - - // Make sure the encryption stream is supported - $streams = stream_get_wrappers(); - - if (!in_array('streams.crypto', $streams)) - { - $this->add_to_log('WARNING: SSL/crypto stream not supported'); - return true; - } - - $this->send_packet("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n"); - sleep(2); - $incoming_array = $this->_listen_incoming(); - - if (!is_array($incoming_array)) - { - $this->add_to_log('ERROR: _starttls() #1'); - return false; - } - - if ($incoming_array['proceed']['@']['xmlns'] != 'urn:ietf:params:xml:ns:xmpp-tls') - { - $this->add_to_log('ERROR: _starttls() #2'); return false; } - $meta = stream_get_meta_data($this->connector->active_socket); - socket_set_blocking($this->connector->active_socket, 1); - - $result = @stream_socket_enable_crypto($this->connector->active_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); - if (!$result) + // did we get multiple elements? do one after another + // array('message' => ..., 'presence' => ...) + if (sizeof($xml) > 1) { - socket_set_blocking($this->connector->active_socket, $meta['blocked']); - $this->add_to_log('ERROR: _starttls() #3'); - return false; + foreach ($xml as $key => $value) + { + $this->response(array($key => $value)); + } + return; } - - socket_set_blocking($this->connector->active_socket, $meta['blocked']); - - $this->send_packet("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); - $this->send_packet("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'" . (($this->show_version) ? " version='{$this->version}'" : '') . ">\n"); - sleep(2); - - if (!$this->_check_connected(true)) + else { - $this->add_to_log('ERROR: _starttls() #4'); - return false; + // or even multiple elements of the same type? + // array('message' => array(0 => ..., 1 => ...)) + if (sizeof(reset($xml)) > 1) + { + foreach (reset($xml) as $value) + { + $this->response(array(key($xml) => array(0 => $value))); + } + return; + } } - return true; - } - - /** - * Get packet type - * @access private - */ - function _get_packet_type($packet = NULL) - { - if (is_array($packet)) + switch (key($xml)) { - reset($packet); - $packet_type = key($packet); - } - - return ($packet_type) ? $packet_type : false; - } + case 'stream:stream': + // Connection initialised (or after authentication). Not much to do here... + $this->session['id'] = $xml['stream:stream'][0]['@']['id']; - /** - * Split incoming packet - * @access private - */ - function _split_incoming($incoming) - { - $temp = preg_split('#<(message|iq|presence|stream)#', $incoming, -1, PREG_SPLIT_DELIM_CAPTURE); - $array = array(); - - for ($i = 1, $size = sizeof($temp); $i < $size; $i += 2) - { - $array[] = '<' . $temp[$i] . $temp[($i + 1)]; - } - - return $array; - } - - /** - * Recursively prepares the strings in an array to be used in XML data. - * @access private - */ - function _array_xmlspecialchars(&$array) - { - if (is_array($array)) - { - foreach ($array as $k => $v) - { - if (is_array($v)) + if (isset($xml['stream:stream'][0]['#']['stream:features'])) { - $this->_array_xmlspecialchars($array[$k]); + // we already got all info we need + $this->features = $xml['stream:stream'][0]['#']; } else { - $this->_xmlspecialchars($array[$k]); + $this->features = $this->listen(); } - } - } - } - - /** - * Prepares a string for usage in XML data. - * @access private - */ - function _xmlspecialchars(&$string) - { - // we only have a few entities in xml - $string = str_replace(array('&', '>', '<', '"', '\''), array('&', '>', '<', '"', '''), $string); - } - - // ====================================================================== - // <message/> parsers - // ====================================================================== - - /** - * Get info from message (from) - */ - function get_info_from_message_from($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['@']['from'] : false; - } - - /** - * Get info from message (type) - */ - function get_info_from_message_type($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['@']['type'] : false; - } - - /** - * Get info from message (id) - */ - function get_info_from_message_id($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['@']['id'] : false; - } - - /** - * Get info from message (thread) - */ - function get_info_from_message_thread($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['#']['thread'][0]['#'] : false; - } - /** - * Get info from message (subject) - */ - function get_info_from_message_subject($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['#']['subject'][0]['#'] : false; - } - - /** - * Get info from message (body) - */ - function get_info_from_message_body($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['#']['body'][0]['#'] : false; - } - - /** - * Get info from message (xmlns) - */ - function get_info_from_message_xmlns($packet = NULL) - { - return (is_array($packet)) ? $packet['message']['#']['x'] : false; - } - - /** - * Get info from message (error) - */ - function get_info_from_message_error($packet = NULL) - { - $error = preg_replace('#^\/$#', '', ($packet['message']['#']['error'][0]['@']['code'] . '/' . $packet['message']['#']['error'][0]['#'])); - return (is_array($packet)) ? $error : false; - } + // go on with authentication? + if (isset($this->features['stream:features'][0]['#']['bind'])) + { + return $this->response($this->features); + } + break; - // ====================================================================== - // <iq/> parsers - // ====================================================================== + case 'stream:features': + // Resource binding after successful authentication + if (isset($this->session['authenticated'])) + { + // session required? + $this->session['sess_required'] = isset($xml['stream:features'][0]['#']['session']); + + $this->send("<iq type='set' id='bind_1'> + <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> + <resource>functions_jabber.phpbb.php</resource> + </bind> + </iq>"); + return $this->response($this->listen()); + } - /** - * Get info from iq (from) - */ - function get_info_from_iq_from($packet = NULL) - { - return (is_array($packet)) ? $packet['iq']['@']['from'] : false; - } + // Let's use TLS if SSL is not enabled and we can actually use it + if (!$this->session['ssl'] && $this->can_use_tls() && isset($xml['stream:features'][0]['#']['starttls'])) + { + $this->add_to_log('Switching to TLS.'); + $this->send("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n"); + return $this->response($this->listen()); + } - /** - * Get info from iq (type) - */ - function get_info_from_iq_type($packet = NULL) - { - return (is_array($packet)) ? $packet['iq']['@']['type'] : false; - } + // Does the server support SASL authentication? + // I hope so, because we do (and no other method). + if (isset($xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns']) && $xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns'] == 'urn:ietf:params:xml:ns:xmpp-sasl') + { + // Now decide on method + $methods = array(); - /** - * Get info from iq (id) - */ - function get_info_from_iq_id($packet = NULL) - { - return (is_array($packet)) ? $packet['iq']['@']['id'] : false; - } + foreach ($xml['stream:features'][0]['#']['mechanisms'][0]['#']['mechanism'] as $value) + { + $methods[] = $value['#']; + } - /** - * Get info from iq (key) - */ - function get_info_from_iq_key($packet = NULL) - { - return (is_array($packet) && isset($packet['iq']['#']['query'][0]['#']['key'][0]['#'])) ? $packet['iq']['#']['query'][0]['#']['key'][0]['#'] : false; - } + // we prefer this one + if (in_array('DIGEST-MD5', $methods)) + { + $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>"); + } + else if (in_array('PLAIN', $methods) && ($this->session['ssl'] || $this->session['tls'])) + { + // we don't want to use this (neither does the server usually) if no encryption is in place + $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>" + . base64_encode(chr(0) . $this->username . '@' . $this->server . chr(0) . $this->password) . + '</auth>'); + } + else + { + // not good... + $this->add_to_log('Error: No authentication method supported.'); + $this->disconnect(); + return false; + } - /** - * Get info from iq (error) - */ - function get_info_from_iq_error($packet = NULL) - { - $error = preg_replace('#^\/$#', '', ($packet['iq']['#']['error'][0]['@']['code'] . '/' . $packet['iq']['#']['error'][0]['#'])); - return (is_array($packet)) ? $error : false; - } + return $this->response($this->listen()); + } + else + { + // ok, this is it. bye. + $this->add_to_log('Error: Server does not offer SASL authentication.'); + $this->disconnect(); + return false; + } + break; - // ====================================================================== - // <message/> handlers - // ====================================================================== + case 'challenge': + // continue with authentication...a challenge literally -_- + $decoded = base64_decode($xml['challenge'][0]['#']); + $decoded = $this->parse_data($decoded); - /** - * Message type normal - */ - function handler_message_normal($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type normal) from $from"); - } + if (!isset($decoded['digest-uri'])) + { + $decoded['digest-uri'] = 'xmpp/'. $this->server; + } - /** - * Message type chat - */ - function handler_message_chat($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type chat) from $from"); - } + // better generate a cnonce, maybe it's needed + $str = ''; + mt_srand((double)microtime()*10000000); - /** - * Message type groupchat - */ - function handler_message_groupchat($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type groupchat) from $from"); - } + for ($i = 0; $i < 32; $i++) + { + $str .= chr(mt_rand(0, 255)); + } + $decoded['cnonce'] = base64_encode($str); - /** - * Message type headline - */ - function handler_message_headline($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type headline) from $from"); - } + // second challenge? + if (isset($decoded['rspauth'])) + { + $this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"); + } + else + { + $response = array( + 'username' => $this->username, + 'response' => $this->encrypt_password(array_merge($decoded, array('nc' => '00000001'))), + 'charset' => 'utf-8', + 'nc' => '00000001', + ); + + foreach (array('nonce', 'qop', 'digest-uri', 'realm', 'cnonce') as $key) + { + if (isset($decoded[$key])) + { + $response[$key] = $decoded[$key]; + } + } - /** - * Message type error - */ - function handler_message_error($packet) - { - $from = $packet['message']['@']['from']; - $this->add_to_log("EVENT: Message (type error) from $from"); - } + $this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" . base64_encode($this->implode_data($response)) . '</response>'); + } - // ====================================================================== - // <iq/> handlers - // ====================================================================== + return $this->response($this->listen()); + break; - /** - * application version updates - */ - function handler_iq_jabber_iq_autoupdate($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + case 'failure': + $this->add_to_log('Error: Server sent "failure".'); + $this->disconnect(); + return false; + break; - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:autoupdate from $from"); - } + case 'proceed': + // continue switching to TLS + $meta = stream_get_meta_data($this->connection); + socket_set_blocking($this->connection, 1); - /** - * interactive server component properties - */ - function handler_iq_jabber_iq_agent($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + if (!stream_socket_enable_crypto($this->connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) + { + $this->add_to_log('Error: TLS mode change failed.'); + return false; + } - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:agent from $from"); - } + socket_set_blocking($this->connection, $meta['blocked']); + $this->session['tls'] = true; - /** - * method to query interactive server components - */ - function handler_iq_jabber_iq_agents($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + // new stream + $this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); + $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:agents from $from"); - } + return $this->response($this->listen()); + break; - /** - * simple client authentication - */ - function handler_iq_jabber_iq_auth($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + case 'success': + // Yay, authentication successful. + $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); + $this->session['authenticated'] = true; - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:auth from $from"); - } + // we have to wait for another response + return $this->response($this->listen()); + break; - /** - * out of band data - */ - function handler_iq_jabber_iq_oob($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + case 'iq': + // we are not interested in IQs we did not expect + if (!isset($xml['iq'][0]['@']['id'])) + { + return false; + } - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:oob from $from"); - } + // multiple possibilities here + switch ($xml['iq'][0]['@']['id']) + { + case 'bind_1': + $this->session['jid'] = $xml['iq'][0]['#']['bind'][0]['#']['jid'][0]['#']; + + // and (maybe) yet another request to be able to send messages *finally* + if ($this->session['sess_required']) + { + $this->send("<iq to='{$this->server}' type='set' id='sess_1'> + <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/> + </iq>"); + return $this->response($this->listen()); + } + + return true; + break; + + case 'sess_1': + return true; + break; + + case 'reg_1': + // more than instructions, username and password? + if (sizeof($xml['iq'][0]['#']['query'][0]['#']) > 3) + { + $this->add_to_log('Server requires too much data for registration.'); + return false; + } + + $this->send("<iq type='set' id='reg_2'> + <query xmlns='jabber:iq:register'> + <username>" . utf8_htmlspecialchars($this->username) . "</username> + <password>" . utf8_htmlspecialchars($this->password) . "</password> + </query> + </iq>"); + return $this->response($this->listen()); + break; + + case 'reg_2': + // registration end + if (isset($xml['iq'][0]['#']['error'])) + { + $this->add_to_log('Warning: Registration failed.'); + return false; + } + return true; + break; + + case 'unreg_1': + return true; + break; + + default: + $this->add_to_log('Notice: Received unexpected IQ.'); + return false; + break; + } + break; - /** - * method to store private data on the server - */ - function handler_iq_jabber_iq_private($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + case 'message': + // we are only interested in content... + if (!isset($xml['message'][0]['#']['body'])) + { + return false; + } - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:private from $from"); - } + $message['body'] = $xml['message'][0]['#']['body'][0]['#']; + $message['from'] = $xml['message'][0]['@']['from']; - /** - * method for interactive registration - */ - function handler_iq_jabber_iq_register($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + if (isset($xml['message'][0]['#']['subject'])) + { + $message['subject'] = $xml['message'][0]['#']['subject'][0]['#']; + } + $this->session['messages'][] = $message; + break; - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:register from $from"); + default: + // hm...don't know this response + $this->add_to_log('Notice: Unknown server response (' . key($xml) . ')'); + return false; + break; + } } - /** - * client roster management - */ - function handler_iq_jabber_iq_roster($packet) + function send_message($to, $text, $subject = '', $type = 'normal') { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); - - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:roster from $from"); - } + if (!isset($this->session['jid'])) + { + return false; + } - /** - * method for searching a user database - */ - function handler_iq_jabber_iq_search($packet) - { - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); + if (!in_array($type, array('chat', 'normal', 'error', 'groupchat', 'headline'))) + { + $type = 'normal'; + } - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: jabber:iq:search from $from"); + return $this->send("<message from='" . utf8_htmlspecialchars($this->session['jid']) . "' to='" . utf8_htmlspecialchars($to) . "' type='$type' id='" . uniqid('msg') . "'> + <subject>" . utf8_htmlspecialchars($subject) . "</subject> + <body>" . utf8_htmlspecialchars($text) . "</body> + </message>" + ); } /** - * method for requesting the current time + * Encrypts a password as in RFC 2831 + * @param array $data Needs data from the client-server connection + * @access public + * @return string */ - function handler_iq_jabber_iq_time($packet) + function encrypt_password($data) { - if ($this->keep_alive_id == $this->get_info_from_iq_id($packet)) + // let's me think about <challenge> again... + foreach (array('realm', 'cnonce', 'digest-uri') as $key) { - $this->returned_keep_alive = true; - $this->connected = true; - - $this->add_to_log('EVENT: Keep-Alive returned, connection alive.'); + if (!isset($data[$key])) + { + $data[$key] = ''; + } } - $type = $this->get_info_from_iq_type($packet); - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); - $id = ($id != '') ? $id : 'time_' . time(); + $pack = md5($this->username . ':' . $data['realm'] . ':' . $this->password); - if ($type == 'get') + if (isset($data['authzid'])) { - $payload = '<utc>' . gmdate("Ydm\TH:i:s") . '</utc><tz>' . date('T') . '</tz><display>' . date("Y/d/m h:i:s A") . '</display>'; - $this->send_iq($from, 'result', $id, 'jabber:iq:time', $payload); + $a1 = pack('H32', $pack) . sprintf(':%s:%s:%s', $data['nonce'], $data['cnonce'], $data['authzid']); + } + else + { + $a1 = pack('H32', $pack) . sprintf(':%s:%s', $data['nonce'], $data['cnonce']); } - $this->add_to_log("EVENT: jabber:iq:time (type $type) from $from"); - } + // should be: qop = auth + $a2 = 'AUTHENTICATE:'. $data['digest-uri']; - /** - */ - function handler_iq_error($packet) - { - // We'll do something with these later. This is a placeholder so that errors don't bounce back and forth. + return md5(sprintf('%s:%s:%s:%s:%s:%s', md5($a1), $data['nonce'], $data['nc'], $data['cnonce'], $data['qop'], md5($a2))); } /** - * method for requesting version + * parse_data like a="b",c="d",... + * @param string $data + * @access public + * @return array a => b ... */ - function handler_iq_jabber_iq_version($packet) + function parse_data($data) { - $type = $this->get_info_from_iq_type($packet); - $from = $this->get_info_from_iq_from($packet); - $id = $this->get_info_from_iq_id($packet); - $id = ($id != '') ? $id : 'version_' . time(); + // super basic, but should suffice + $data = explode(',', $data); + $pairs = array(); - if ($type == 'get') + foreach ($data as $pair) { - $payload = "<name>{$this->iq_version_name}</name> - <os>{$this->iq_version_os}</os> - <version>{$this->iq_version_version}</version>"; - - //$this->SendIq($from, 'result', $id, "jabber:iq:version", $payload); + $dd = strpos($pair, '='); + if ($dd) + { + $pairs[substr($pair, 0, $dd)] = trim(substr($pair, $dd + 1), '"'); + } } - - $this->add_to_log("EVENT: jabber:iq:version (type $type) from $from -- DISABLED"); + return $pairs; } - // ====================================================================== - // Generic handlers - // ====================================================================== - /** - * Generic handler for unsupported requests + * opposite of jabber::parse_data() + * @param array $data + * @access public + * @return string */ - function handler_not_implemented($packet) + function implode_data($data) { - $packet_type = $this->_get_packet_type($packet); - $from = call_user_func(array(&$this, 'get_info_from_' . strtolower($packet_type) . '_from'), $packet); - $id = call_user_func(array(&$this, 'get_info_from_' . strtolower($packet_type) . '_id'), $packet); - - $this->send_error($from, $id, 501); - $this->add_to_log("EVENT: Unrecognized <$packet_type/> from $from"); + $return = array(); + foreach ($data as $key => $value) + { + $return[] = $key . '="' . $value . '"'; + } + return implode(',', $return); } - // ====================================================================== - // Third party code - // m@d pr0ps to the coders ;) - // ====================================================================== - /** * xmlize() * @author Hans Anderson @@ -1334,6 +724,12 @@ class jabber { $data = trim($data); + if (substr($data, 0, 5) != '<?xml') + { + // mod + $data = '<root>'. $data . '</root>'; + } + $vals = $index = $array = array(); $parser = xml_parser_create($encoding); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); @@ -1344,8 +740,13 @@ class jabber $i = 0; $tagname = $vals[$i]['tag']; - $array[$tagname]['@'] = (isset($vals[$i]['attributes'])) ? $vals[$i]['attributes'] : array(); - $array[$tagname]['#'] = $this->_xml_depth($vals, $i); + $array[$tagname][0]['@'] = (isset($vals[$i]['attributes'])) ? $vals[$i]['attributes'] : array(); + $array[$tagname][0]['#'] = $this->_xml_depth($vals, $i); + + if (substr($data, 0, 5) != '<?xml') + { + $array = $array['root'][0]['#']; + } return $array; } @@ -1407,106 +808,6 @@ class jabber return $children; } - - /** - * TraverseXMLize() - * @author acebone@f2s.com - * @copyright acebone@f2s.com, a HUGE help! - */ - function traverse_xmlize($array, $arr_name = 'array', $level = 0) - { - if ($level == 0) - { - echo '<pre>'; - } - - foreach ($array as $key => $val) - { - if (is_array($val)) - { - $this->traverse_xmlize($val, $arr_name . '[' . $key . ']', $level + 1); - } - else - { - $GLOBALS['traverse_array'][] = '$' . $arr_name . '[' . $key . '] = "' . $val . "\"\n"; - } - } - - if ($level == 0) - { - echo '</pre>'; - } - - return 1; - } -} - -/** -* Jabber Connector -* @package phpBB3 -*/ -class cjp_standard_connector -{ - var $active_socket; - - /** - * Open socket - */ - function open_socket($server, $port) - { - if (function_exists('dns_get_record')) - { - $record = dns_get_record("_xmpp-client._tcp.$server", DNS_SRV); - - if (!empty($record)) - { - $server = $record[0]['target']; - $port = $record[0]['port']; - } - } - - $errno = 0; - $errstr = ''; - - if ($this->active_socket = @fsockopen($server, $port, $errno, $errstr, 5)) - { - @socket_set_blocking($this->active_socket, 0); - @socket_set_timeout($this->active_socket, 31536000); - - return true; - } - else - { - return false; - } - } - - /** - * Close socket - */ - function close_socket() - { - return @fclose($this->active_socket); - } - - /** - * Write to socket - */ - function write_to_socket($data) - { - return @fwrite($this->active_socket, $data); - } - - /** - * Read from socket - */ - function read_from_socket($chunksize) - { - $buffer = @fread($this->active_socket, $chunksize); - $buffer = (STRIP) ? stripslashes($buffer) : $buffer; - - return $buffer; - } } ?>
\ No newline at end of file |