aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/includes/functions_jabber.php
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/includes/functions_jabber.php')
-rw-r--r--phpBB/includes/functions_jabber.php1635
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('&amp;', '&gt;', '&lt;', '&quot;', '&apos;'), $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