From 838a8eb146ce72a5cd03df61e57f9a05140709fb Mon Sep 17 00:00:00 2001 From: moodler Date: Mon, 15 Sep 2008 05:55:58 +0000 Subject: [PATCH] MDL-16500 Removed the old Jabber class from the module and moved to a new one called xmpphp in core libraries Also cleaned up some notices in message/edit.php --- lib/jabber/XMPP/Exception.php | 39 + lib/jabber/XMPP/Log.php | 116 + lib/jabber/XMPP/XMLObj.php | 155 ++ lib/jabber/XMPP/XMLStream.php | 604 +++++ lib/jabber/XMPP/XMPP.php | 321 +++ lib/jabber/XMPP/XMPP_Old.php | 111 + message/edit.php | 10 +- message/output/jabber/jabberclass/LICENSE | 504 ---- message/output/jabber/jabberclass/README | 59 - .../jabberclass/class_ConnectionSocket.php | 86 - .../jabber/jabberclass/class_Jabber.php | 2062 ----------------- .../jabber/jabberclass/class_SHA1Library.php | 264 --- .../jabber/jabberclass/class_XMLParser.php | 139 -- .../jabber/jabberclass/jabber_example.php | 224 -- .../output/jabber/message_output_jabber.php | 69 +- message/output/jabber/version.php | 4 +- version.php | 2 +- 17 files changed, 1378 insertions(+), 3391 deletions(-) create mode 100755 lib/jabber/XMPP/Exception.php create mode 100644 lib/jabber/XMPP/Log.php create mode 100644 lib/jabber/XMPP/XMLObj.php create mode 100644 lib/jabber/XMPP/XMLStream.php create mode 100644 lib/jabber/XMPP/XMPP.php create mode 100644 lib/jabber/XMPP/XMPP_Old.php delete mode 100644 message/output/jabber/jabberclass/LICENSE delete mode 100644 message/output/jabber/jabberclass/README delete mode 100644 message/output/jabber/jabberclass/class_ConnectionSocket.php delete mode 100644 message/output/jabber/jabberclass/class_Jabber.php delete mode 100644 message/output/jabber/jabberclass/class_SHA1Library.php delete mode 100644 message/output/jabber/jabberclass/class_XMLParser.php delete mode 100644 message/output/jabber/jabberclass/jabber_example.php diff --git a/lib/jabber/XMPP/Exception.php b/lib/jabber/XMPP/Exception.php new file mode 100755 index 0000000000000..32b2e0924059f --- /dev/null +++ b/lib/jabber/XMPP/Exception.php @@ -0,0 +1,39 @@ + + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + */ + +/** + * XMPPHP Exception + * + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMPPHP_Exception extends Exception { +} diff --git a/lib/jabber/XMPP/Log.php b/lib/jabber/XMPP/Log.php new file mode 100644 index 0000000000000..635e68da475ca --- /dev/null +++ b/lib/jabber/XMPP/Log.php @@ -0,0 +1,116 @@ + + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + */ + +/** + * XMPPHP Log + * + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMPPHP_Log { + + const LEVEL_ERROR = 0; + const LEVEL_WARNING = 1; + const LEVEL_INFO = 2; + const LEVEL_DEBUG = 3; + const LEVEL_VERBOSE = 4; + + /** + * @var array + */ + protected $data = array(); + + /** + * @var array + */ + protected $names = array('ERROR', 'WARNING', 'INFO', 'DEBUG', 'VERBOSE'); + + /** + * @var integer + */ + protected $runlevel; + + /** + * @var boolean + */ + protected $printout; + + /** + * Constructor + * + * @param boolean $printout + * @param string $runlevel + */ + public function __construct($printout = false, $runlevel = self::LEVEL_INFO) { + $this->printout = (boolean)$printout; + $this->runlevel = (int)$runlevel; + } + + /** + * Add a message to the log data array + * If printout in this instance is set to true, directly output the message + * + * @param string $msg + * @param integer $runlevel + */ + public function log($msg, $runlevel = self::LEVEL_INFO) { + $time = time(); + $this->data[] = array($this->runlevel, $msg, $time); + if($this->printout and $runlevel <= $this->runlevel) { + $this->writeLine($msg, $runlevel, $time); + } + } + + /** + * Output the complete log. + * Log will be cleared if $clear = true + * + * @param boolean $clear + * @param integer $runlevel + */ + public function printout($clear = true, $runlevel = null) { + if($runlevel === null) { + $runlevel = $this->runlevel; + } + foreach($this->data as $data) { + if($runlevel <= $data[0]) { + $this->writeLine($data[1], $runlevel, $data[2]); + } + } + if($clear) { + $this->data = array(); + } + } + + protected function writeLine($msg, $runlevel, $time) { + //echo date('Y-m-d H:i:s', $time)." [".$this->names[$runlevel]."]: ".$msg."\n"; + echo $time." [".$this->names[$runlevel]."]: ".$msg."\n"; + } +} diff --git a/lib/jabber/XMPP/XMLObj.php b/lib/jabber/XMPP/XMLObj.php new file mode 100644 index 0000000000000..79fef9b243c71 --- /dev/null +++ b/lib/jabber/XMPP/XMLObj.php @@ -0,0 +1,155 @@ + + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + */ + +/** + * XMPPHP XML Object + * + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMPPHP_XMLObj { + /** + * Tag name + * + * @var string + */ + public $name; + + /** + * Namespace + * + * @var string + */ + public $ns; + + /** + * Attributes + * + * @var array + */ + public $attrs = array(); + + /** + * Subs? + * + * @var array + */ + public $subs = array(); + + /** + * Node data + * + * @var string + */ + public $data = ''; + + /** + * Constructor + * + * @param string $name + * @param string $ns + * @param array $attrs + * @param string $data + */ + public function __construct($name, $ns = '', $attrs = array(), $data = '') { + $this->name = strtolower($name); + $this->ns = $ns; + if(is_array($attrs) && count($attrs)) { + foreach($attrs as $key => $value) { + $this->attrs[strtolower($key)] = $value; + } + } + $this->data = $data; + } + + /** + * Dump this XML Object to output. + * + * @param integer $depth + */ + public function printObj($depth = 0) { + print str_repeat("\t", $depth) . $this->name . " " . $this->ns . ' ' . $this->data; + print "\n"; + foreach($this->subs as $sub) { + $sub->printObj($depth + 1); + } + } + + /** + * Return this XML Object in xml notation + * + * @param string $str + */ + public function toString($str = '') { + $str .= "<{$this->name} xmlns='{$this->ns}' "; + foreach($this->attrs as $key => $value) { + if($key != 'xmlns') { + $value = htmlspecialchars($value); + $str .= "$key='$value' "; + } + } + $str .= ">"; + foreach($this->subs as $sub) { + $str .= $sub->toString(); + } + $body = htmlspecialchars($this->data); + $str .= "$bodyname}>"; + return $str; + } + + /** + * Has this XML Object the given sub? + * + * @param string $name + * @return boolean + */ + public function hasSub($name) { + foreach($this->subs as $sub) { + if($sub->name == $name) return true; + } + return false; + } + + /** + * Return a sub + * + * @param string $name + * @param string $attrs + * @param string $ns + */ + public function sub($name, $attrs = null, $ns = null) { + foreach($this->subs as $sub) { + if($sub->name == $name) { + return $sub; + } + } + } +} diff --git a/lib/jabber/XMPP/XMLStream.php b/lib/jabber/XMPP/XMLStream.php new file mode 100644 index 0000000000000..d3c59de53e5a4 --- /dev/null +++ b/lib/jabber/XMPP/XMLStream.php @@ -0,0 +1,604 @@ + + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + */ + +/** XMPPHP_Exception */ +require_once 'Exception.php'; + +/** XMPPHP_XMLObj */ +require_once 'XMLObj.php'; + +/** XMPPHP_Log */ +require_once 'Log.php'; + +/** + * XMPPHP XML Stream + * + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMPPHP_XMLStream { + /** + * @var resource + */ + protected $socket; + /** + * @var resource + */ + protected $parser; + /** + * @var string + */ + protected $buffer; + /** + * @var integer + */ + protected $xml_depth = 0; + /** + * @var string + */ + protected $host; + /** + * @var integer + */ + protected $port; + /** + * @var string + */ + protected $stream_start = ''; + /** + * @var string + */ + protected $stream_end = ''; + /** + * @var boolean + */ + protected $disconnected = false; + /** + * @var boolean + */ + protected $sent_disconnect = false; + /** + * @var array + */ + protected $ns_map = array(); + /** + * @var array + */ + protected $current_ns = array(); + /** + * @var array + */ + protected $xmlobj = null; + /** + * @var array + */ + protected $nshandlers = array(); + /** + * @var array + */ + protected $idhandlers = array(); + /** + * @var array + */ + protected $eventhandlers = array(); + /** + * @var integer + */ + protected $lastid = 0; + /** + * @var string + */ + protected $default_ns; + /** + * @var string + */ + protected $until = ''; + /** + * @var array + */ + protected $until_happened = false; + /** + * @var array + */ + protected $until_payload = array(); + /** + * @var XMPPHP_Log + */ + protected $log; + /** + * @var boolean + */ + protected $reconnect = true; + /** + * @var boolean + */ + protected $been_reset = false; + /** + * @var boolean + */ + protected $is_server; + /** + * @var float + */ + protected $last_send = 0; + + /** + * Constructor + * + * @param string $host + * @param string $port + * @param boolean $printlog + * @param string $loglevel + * @param boolean $is_server + */ + public function __construct($host = null, $port = null, $printlog = false, $loglevel = null, $is_server = false) { + $this->reconnect = !$is_server; + $this->is_server = $is_server; + $this->host = $host; + $this->port = $port; + $this->setupParser(); + $this->log = new XMPPHP_Log($printlog, $loglevel); + } + + /** + * Destructor + * Cleanup connection + */ + public function __destruct() { + if(!$this->disconnected && $this->socket) { + $this->disconnect(); + } + } + + /** + * Return the log instance + * + * @return XMPPHP_Log + */ + public function getLog() { + return $this->log; + } + + /** + * Get next ID + * + * @return integer + */ + public function getId() { + $this->lastid++; + return $this->lastid; + } + + /** + * Add ID Handler + * + * @param integer $id + * @param string $pointer + * @param string $obj + */ + public function addIdHandler($id, $pointer, $obj = null) { + $this->idhandlers[$id] = array($pointer, $obj); + } + + /** + * Add Handler + * + * @param integer $id + * @param string $ns + * @param string $pointer + * @param string $obj + * @param integer $depth + */ + public function addHandler($name, $ns, $pointer, $obj = null, $depth = 1) { + $this->nshandlers[] = array($name,$ns,$pointer,$obj, $depth); + } + + /** + * Add Evemt Handler + * + * @param integer $id + * @param string $pointer + * @param string $obj + */ + public function addEventHandler($name, $pointer, $obj) { + $this->eventhanders[] = array($name, $pointer, $obj); + } + + /** + * Connect to XMPP Host + * + * @param integer $timeout + * @param boolean $persistent + * @param boolean $sendinit + */ + public function connect($timeout = 30, $persistent = false, $sendinit = true) { + $this->disconnected = false; + $this->sent_disconnect = false; + if($persistent) { + $conflag = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT; + } else { + $conflag = STREAM_CLIENT_CONNECT; + } + $this->log->log("Connecting to tcp://{$this->host}:{$this->port}"); + try { + $this->socket = @stream_socket_client("tcp://{$this->host}:{$this->port}", $errno, $errstr, $timeout, $conflag); + } catch (Exception $e) { + throw new XMPPHP_Exception($e->getMessage()); + } + if(!$this->socket) { + $this->log->log("Could not connect.", XMPPHP_Log::LEVEL_ERROR); + $this->disconnected = true; + + throw new XMPPHP_Exception('Could not connect.'); + } + stream_set_blocking($this->socket, 1); + if($sendinit) $this->send($this->stream_start); + } + + /** + * Reconnect XMPP Host + */ + public function doReconnect() { + if(!$this->is_server) { + $this->log->log("Reconnecting...", XMPPHP_Log::LEVEL_WARNING); + $this->connect(30, false, false); + $this->reset(); + } + } + + /** + * Disconnect from XMPP Host + */ + public function disconnect() { + $this->log->log("Disconnecting...", XMPPHP_Log::LEVEL_VERBOSE); + $this->reconnect = false; + $this->send($this->stream_end); + $this->sent_disconnect = true; + $this->processUntil('end_stream', 5); + $this->disconnected = true; + } + + /** + * Are we are disconnected? + * + * @return boolean + */ + public function isDisconnected() { + return $this->disconnected; + } + + private function __process() { + $read = array($this->socket); + $write = null; + $except = null; + $updated = @stream_select($read, $write, $except, 1); + if ($updated > 0) { + $buff = @fread($this->socket, 1024); + if(!$buff) { + if($this->reconnect) { + $this->doReconnect(); + } else { + fclose($this->socket); + return false; + } + } + $this->log->log("RECV: $buff", XMPPHP_Log::LEVEL_VERBOSE); + xml_parse($this->parser, $buff, false); + } + } + + /** + * Process + * + * @return string + */ + public function process() { + $updated = ''; + while(!$this->disconnect) { + $this->__process(); + } + } + + /** + * Process until a timeout occurs + * + * @param integer $timeout + * @return string + */ + public function processTime($timeout = -1) { + $start = time(); + $updated = ''; + while(!$this->disconnected and ($timeout == -1 or time() - $start < $timeout)) { + $this->__process(); + } + } + + /** + * Process until a specified event or a timeout occurs + * + * @param string|array $event + * @param integer $timeout + * @return string + */ + public function processUntil($event, $timeout=-1) { + $start = time(); + if(!is_array($event)) $event = array($event); + $this->until[] = $event; + end($this->until); + $event_key = key($this->until); + reset($this->until); + $updated = ''; + while(!$this->disconnected and $this->until[$event_key] and (time() - $start < $timeout or $timeout == -1)) { + $this->__process(); + } + if(array_key_exists($event_key, $this->until_payload)) { + $payload = $this->until_payload[$event_key]; + } else { + $payload = array(); + } + unset($this->until_payload[$event_key]); + return $payload; + } + + /** + * Obsolete? + */ + public function Xapply_socket($socket) { + $this->socket = $socket; + } + + /** + * XML start callback + * + * @see xml_set_element_handler + * + * @param resource $parser + * @param string $name + */ + public function startXML($parser, $name, $attr) { + if($this->been_reset) { + $this->been_reset = false; + $this->xml_depth = 0; + } + $this->xml_depth++; + if(array_key_exists('XMLNS', $attr)) { + $this->current_ns[$this->xml_depth] = $attr['XMLNS']; + } else { + $this->current_ns[$this->xml_depth] = $this->current_ns[$this->xml_depth - 1]; + if(!$this->current_ns[$this->xml_depth]) $this->current_ns[$this->xml_depth] = $this->default_ns; + } + $ns = $this->current_ns[$this->xml_depth]; + foreach($attr as $key => $value) { + if(strstr($key, ":")) { + $key = explode(':', $key); + $key = $key[1]; + $this->ns_map[$key] = $value; + } + } + if(!strstr($name, ":") === false) + { + $name = explode(':', $name); + $ns = $this->ns_map[$name[0]]; + $name = $name[1]; + } + $obj = new XMPPHP_XMLObj($name, $ns, $attr); + if($this->xml_depth > 1) { + $this->xmlobj[$this->xml_depth - 1]->subs[] = $obj; + } + $this->xmlobj[$this->xml_depth] = $obj; + } + + /** + * XML end callback + * + * @see xml_set_element_handler + * + * @param resource $parser + * @param string $name + */ + public function endXML($parser, $name) { + #$this->log->log("Ending $name", XMPPHP_Log::LEVEL_DEBUG); + #print "$name\n"; + if($this->been_reset) { + $this->been_reset = false; + $this->xml_depth = 0; + } + $this->xml_depth--; + if($this->xml_depth == 1) { + #clean-up old objects + $found = false; + foreach($this->nshandlers as $handler) { + if($handler[4] != 1 and $this->xmlobj[2]->hasSub($handler[0])) { + $searchxml = $this->xmlobj[2]->sub($handler[0]); + } elseif(is_array($this->xmlobj) and array_key_exists(2, $this->xmlobj)) { + $searchxml = $this->xmlobj[2]; + } + if($searchxml !== null and $searchxml->name == $handler[0] and ($searchxml->ns == $handler[1] or (!$handler[1] and $searchxml->ns == $this->default_ns))) { + if($handler[3] === null) $handler[3] = $this; + $this->log->log("Calling {$handler[2]}", XMPPHP_Log::LEVEL_DEBUG); + $handler[3]->$handler[2]($this->xmlobj[2]); + } + } + foreach($this->idhandlers as $id => $handler) { + if(array_key_exists('id', $this->xmlobj[2]->attrs) and $this->xmlobj[2]->attrs['id'] == $id) { + if($handler[1] === null) $handler[1] = $this; + $handler[1]->$handler[0]($this->xmlobj[2]); + #id handlers are only used once + unset($this->idhandlers[$id]); + break; + } + } + if(is_array($this->xmlobj)) { + $this->xmlobj = array_slice($this->xmlobj, 0, 1); + if(isset($this->xmlobj[0]) && $this->xmlobj[0] instanceof XMPPHP_XMLObj) { + $this->xmlobj[0]->subs = null; + } + } + unset($this->xmlobj[2]); + } + if($this->xml_depth == 0 and !$this->been_reset) { + if(!$this->disconnected) { + if(!$this->sent_disconnect) { + $this->send($this->stream_end); + } + $this->disconnected = true; + $this->sent_disconnect = true; + fclose($this->socket); + if($this->reconnect) { + $this->doReconnect(); + } + } + $this->event('end_stream'); + } + } + + /** + * XML character callback + * @see xml_set_character_data_handler + * + * @param resource $parser + * @param string $data + */ + public function charXML($parser, $data) { + if(array_key_exists($this->xml_depth, $this->xmlobj)) { + $this->xmlobj[$this->xml_depth]->data .= $data; + } + } + + /** + * Event? + * + * @param string $name + * @param string $payload + */ + public function event($name, $payload = null) { + $this->log->log("EVENT: $name", XMPPHP_Log::LEVEL_DEBUG); + foreach($this->eventhandlers as $handler) { + if($name == $handler[0]) { + if($handler[2] === null) { + $handler[2] = $this; + } + $handler[2]->$handler[1]($payload); + } + } + foreach($this->until as $key => $until) { + if(is_array($until)) { + if(in_array($name, $until)) { + $this->until_payload[$key][] = array($name, $payload); + $this->until[$key] = false; + } + } + } + } + + /** + * Read from socket + */ + public function read() { + $buff = @fread($this->socket, 1024); + if(!$buff) { + if($this->reconnect) { + $this->doReconnect(); + } else { + fclose($this->socket); + return false; + } + } + $this->log->log("RECV: $buff", XMPPHP_Log::LEVEL_VERBOSE); + xml_parse($this->parser, $buff, false); + } + + /** + * Send to socket + * + * @param string $msg + */ + public function send($msg, $rec=false) { + if($this->time() - $this->last_send < .1) { + usleep(100000); + } + $wait = true; + while($wait) { + $read = null; + $write = array($this->socket); + $except = null; + $select = @stream_select($read, $write, $except, 0, 0); + if($select === False) { + $this->doReconnect(); + return false; + } elseif ($select > 0) { + $wait = false; + } else { + usleep(100000); + //$this->processTime(.25); + } + } + $sentbytes = @fwrite($this->socket, $msg, 1024); + $this->last_send = $this->time(); + $this->log->log("SENT: " . mb_substr($msg, 0, $sentbytes, '8bit'), XMPPHP_Log::LEVEL_VERBOSE); + if($sentbytes === FALSE) { + $this->doReconnect(); + } elseif ($sentbytes != mb_strlen($msg, '8bit')) { + $this->send(mb_substr($msg, $sentbytes, mb_strlen($msg, '8bit'), '8bit'), true); + } + } + + public function time() { + list($usec, $sec) = explode(" ", microtime()); + return (float)$sec + (float)$usec; + } + + /** + * Reset connection + */ + public function reset() { + $this->xml_depth = 0; + unset($this->xmlobj); + $this->xmlobj = array(); + $this->setupParser(); + if(!$this->is_server) { + $this->send($this->stream_start); + } + $this->been_reset = true; + } + + /** + * Setup the XML parser + */ + public function setupParser() { + $this->parser = xml_parser_create('UTF-8'); + xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, 'UTF-8'); + xml_set_object($this->parser, $this); + xml_set_element_handler($this->parser, 'startXML', 'endXML'); + xml_set_character_data_handler($this->parser, 'charXML'); + } +} diff --git a/lib/jabber/XMPP/XMPP.php b/lib/jabber/XMPP/XMPP.php new file mode 100644 index 0000000000000..5ba409513392f --- /dev/null +++ b/lib/jabber/XMPP/XMPP.php @@ -0,0 +1,321 @@ + + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + */ + +/** XMPPHP_XMLStream */ +require_once "XMLStream.php"; + +/** + * XMPPHP Main Class + * + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + * @version $Id$ + */ +class XMPPHP_XMPP extends XMPPHP_XMLStream { + /** + * @var string + */ + protected $server; + + /** + * @var string + */ + protected $user; + + /** + * @var string + */ + protected $password; + + /** + * @var string + */ + protected $resource; + + /** + * @var string + */ + protected $fulljid; + + /** + * @var string + */ + protected $basejid; + + /** + * @var boolean + */ + protected $authed = false; + + /** + * @var boolean + */ + protected $auto_subscribe = false; + + /** + * @var boolean + */ + protected $use_encryption = true; + + /** + * Constructor + * + * @param string $host + * @param integer $port + * @param string $user + * @param string $password + * @param string $resource + * @param string $server + * @param boolean $printlog + * @param string $loglevel + */ + public function __construct($host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null) { + parent::__construct($host, $port, $printlog, $loglevel); + + $this->user = $user; + $this->password = $password; + $this->resource = $resource; + if(!$server) $server = $host; + $this->basejid = $this->user . '@' . $this->host; + + $this->stream_start = ''; + $this->stream_end = ''; + $this->default_ns = 'jabber:client'; + + $this->addHandler('features', 'http://etherx.jabber.org/streams', 'features_handler'); + $this->addHandler('success', 'urn:ietf:params:xml:ns:xmpp-sasl', 'sasl_success_handler'); + $this->addHandler('failure', 'urn:ietf:params:xml:ns:xmpp-sasl', 'sasl_failure_handler'); + $this->addHandler('proceed', 'urn:ietf:params:xml:ns:xmpp-tls', 'tls_proceed_handler'); + $this->addHandler('message', 'jabber:client', 'message_handler'); + $this->addHandler('presence', 'jabber:client', 'presence_handler'); + } + + /** + * Turn encryption on/ff + * + * @param boolean $useEncryption + */ + public function useEncryption($useEncryption = true) { + $this->use_encryption = $useEncryption; + } + + /** + * Turn on auto-authorization of subscription requests. + * + * @param boolean $autoSubscribe + */ + public function autoSubscribe($autoSubscribe = true) { + $this->auto_subscribe = $autoSubscribe; + } + + /** + * Send XMPP Message + * + * @param string $to + * @param string $body + * @param string $type + * @param string $subject + */ + public function message($to, $body, $type = 'chat', $subject = null, $payload = null) { + $to = htmlspecialchars($to); + $body = htmlspecialchars($body); + $subject = htmlspecialchars($subject); + + $out = ""; + if($subject) $out .= "$subject"; + $out .= "$body"; + if($payload) $out .= $payload; + $out .= ""; + + $this->send($out); + } + + /** + * Set Presence + * + * @param string $status + * @param string $show + * @param string $to + */ + public function presence($status = null, $show = 'available', $to = null, $type='available') { + if($type == 'available') $type = ''; + $to = htmlspecialchars($to); + $status = htmlspecialchars($status); + if($show == 'unavailable') $type = 'unavailable'; + + $out = "send($out); + } + + /** + * Message handler + * + * @param string $xml + */ + public function message_handler($xml) { + if(isset($xml->attrs['type'])) { + $payload['type'] = $xml->attrs['type']; + } else { + $payload['type'] = 'chat'; + } + $payload['from'] = $xml->attrs['from']; + $payload['body'] = $xml->sub('body')->data; + $this->log->log("Message: {$xml->sub('body')->data}", XMPPHP_Log::LEVEL_DEBUG); + $this->event('message', $payload); + } + + /** + * Presence handler + * + * @param string $xml + */ + public function presence_handler($xml) { + $payload['type'] = (isset($xml->attrs['type'])) ? $xml->attrs['type'] : 'available'; + $payload['show'] = (isset($xml->sub('show')->data)) ? $xml->sub('show')->data : $payload['type']; + $payload['from'] = $xml->attrs['from']; + $payload['status'] = (isset($xml->sub('status')->data)) ? $xml->sub('status')->data : ''; + $this->log->log("Presence: {$payload['from']} [{$payload['show']}] {$payload['status']}", XMPPHP_Log::LEVEL_DEBUG); + if($xml->attrs['type'] == 'subscribe') { + if($this->auto_subscribe) $this->send(""); + $this->event('subscription_requested', $payload); + } elseif($xml->attrs['type'] == 'subscribed') { + $this->event('subscription_accepted', $payload); + } else { + $this->event('presence', $payload); + } + } + + /** + * Features handler + * + * @param string $xml + */ + protected function features_handler($xml) { + if($xml->hasSub('starttls') and $this->use_encryption) { + $this->send(""); + } elseif($xml->hasSub('bind')) { + $id = $this->getId(); + $this->addIdHandler($id, 'resource_bind_handler'); + $this->send("{$this->resource}"); + } else { + $this->log->log("Attempting Auth..."); + $this->send("" . base64_encode("\x00" . $this->user . "\x00" . $this->password) . ""); + } + } + + /** + * SASL success handler + * + * @param string $xml + */ + protected function sasl_success_handler($xml) { + $this->log->log("Auth success!"); + $this->authed = true; + $this->reset(); + } + + /** + * SASL feature handler + * + * @param string $xml + */ + protected function sasl_failure_handler($xml) { + $this->log->log("Auth failed!", XMPPHP_Log::LEVEL_ERROR); + $this->disconnect(); + + throw new XMPPHP_Exception('Auth failed!'); + } + + /** + * Resource bind handler + * + * @param string $xml + */ + protected function resource_bind_handler($xml) { + if($xml->attrs['type'] == 'result') { + $this->log->log("Bound to " . $xml->sub('bind')->sub('jid')->data); + $this->fulljid = $xml->sub('bind')->sub('jid')->data; + } + $id = $this->getId(); + $this->addIdHandler($id, 'session_start_handler'); + $this->send(""); + } + + /** + * Retrieves the roster + * + */ + public function getRoster() { + $id = $this->getID(); + $this->addIdHandler($id, 'roster_get_handler'); + $this->send(""); + } + + /** + * Roster retrieval handler + * + * @param string $xml + */ + protected function roster_get_handler($xml) { + // TODO: make this work + } + + /** + * Session start handler + * + * @param string $xml + */ + protected function session_start_handler($xml) { + $this->log->log("Session started"); + $this->event('session_start'); + } + + /** + * TLS proceed handler + * + * @param string $xml + */ + protected function tls_proceed_handler($xml) { + $this->log->log("Starting TLS encryption"); + stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT); + $this->reset(); + } +} diff --git a/lib/jabber/XMPP/XMPP_Old.php b/lib/jabber/XMPP/XMPP_Old.php new file mode 100644 index 0000000000000..ab0466e7d887f --- /dev/null +++ b/lib/jabber/XMPP/XMPP_Old.php @@ -0,0 +1,111 @@ + + * @author Stephan Wentz + * @copyright 2008 Nathanael C. Fritz + */ + +/** XMPPHP_XMPP + * + * This file is unnecessary unless you need to connect to older, non-XMPP-compliant servers like Dreamhost's. + * In this case, use instead of XMPPHP_XMPP, otherwise feel free to delete it. + * The old Jabber protocol wasn't standardized, so use at your own risk. + * + */ +require_once "XMPP.php"; + + class XMPPHP_XMPPOld extends XMPPHP_XMPP { + /** + * + * @var string + */ + protected $session_id; + + public function __construct($host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null) { + parent::__construct($host, $port, $user, $password, $resource, $server, $printlog, $loglevel); + + } + + /** + * Override XMLStream's startXML + * + * @param parser $parser + * @param string $name + * @param array $attr + */ + protected function startXML($parser, $name, $attr) { + if($this->xml_depth == 0 and $attr['version'] != '1.0') { + $this->session_id = $attr['ID']; + $this->authenticate(); + } + parent::startXML($parser, $name, $attr); + } + + /** + * Send Authenticate Info Request + * + */ + public function authenticate() { + $id = $this->getId(); + $this->addidhandler($id, 'authfieldshandler'); + $this->send("{$this->user}"); + } + + /** + * Retrieve auth fields and send auth attempt + * + * @param XMLObj $xml + */ + public function authFieldsHandler($xml) { + $id = $this->getId(); + $this->addidhandler($id, 'oldAuthResultHandler'); + if($xml->sub('query')->hasSub('digest')) { + $hash = sha1($this->session_id . $this->password); + print "{$this->session_id} {$this->password}\n"; + $out = "{$this->user}{$hash}{$this->resource}"; + } else { + $out = "{$this->user}{$this->password}{$this->resource}"; + } + $this->send($out); + + } + + /** + * Determine authenticated or failure + * + * @param XMLObj $xml + */ + public function oldAuthResultHandler($xml) { + if($xml->attrs['type'] != 'result') { + $this->log->log("Auth failed!", XMPPHP_Log::LEVEL_ERROR); + $this->disconnect(); + throw new XMPPHP_Exception('Auth failed!'); + } else { + $this->log->log("Session started"); + $this->event('session_start'); + } + } + } + + +?> diff --git a/message/edit.php b/message/edit.php index 34b7f8731aee3..4d012bc7273bc 100644 --- a/message/edit.php +++ b/message/edit.php @@ -230,8 +230,14 @@ foreach (array('loggedin', 'loggedoff') as $state){ $state_res = get_string($state, 'message'); echo ''.$state_res.''."\n"; - foreach ( $processors as $processorid => $processor){ - $checked = $preferences->{$provider->component.'_'.$provider->name.'_'.$state}[$processor->name]==1?" checked=\"checked\"":""; + foreach ( $processors as $processorid => $processor) { + if (!isset($preferences->{$provider->component.'_'.$provider->name.'_'.$state})) { + $checked = ''; + } else if (!isset($preferences->{$provider->component.'_'.$provider->name.'_'.$state}[$processor->name])) { + $checked = ''; + } else { + $checked = $preferences->{$provider->component.'_'.$provider->name.'_'.$state}[$processor->name]==1?" checked=\"checked\"":""; + } echo ''."\n"; } echo ''."\n"; diff --git a/message/output/jabber/jabberclass/LICENSE b/message/output/jabber/jabberclass/LICENSE deleted file mode 100644 index cbee875ba6ddb..0000000000000 --- a/message/output/jabber/jabberclass/LICENSE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/message/output/jabber/jabberclass/README b/message/output/jabber/jabberclass/README deleted file mode 100644 index 91d2caa45ebc7..0000000000000 --- a/message/output/jabber/jabberclass/README +++ /dev/null @@ -1,59 +0,0 @@ -Jabber Client Library -Version 0.9rc1 -Copyright 2002-2007, Centova Technologies Inc. -http://www.centova.com - -Portions Copyright 2002, Carlo Zottmann -============================================================================ - -This file was contributed (in part or whole) by a third party, and is -released under the GNU LGPL. Please see the CREDITS and LICENSE sections -below for details. - -**************************************************************************** - -DETAILS - -This is an event-driven Jabber client class implementation. This library -allows PHP scripts to connect to and communicate with Jabber servers. - - -CREDITS & COPYRIGHTS - -This class was originally based on Class.Jabber.PHP v0.4 (Copyright 2002, -Carlo "Gossip" Zottmann). - -The code for this class has since been nearly completely rewritten by Steve -Blinch for Centova Technologies Inc. All such modified code is Copyright -2002-2007, Centova Technologies Inc. - -The original Class.Jabber.PHP was released under the GNU General Public -License (GPL); however, we have received written permission from the -original author and copyright holder, Carlo Zottmann, to relicense our -version of this class and release it under the GNU Lesser General Public -License (LGPL). - -LICENSE - -class_Jabber.php - Jabber Client Library -Copyright (C) 2002-2007, Centova Technologies Inc. -Copyright (C) 2002, Carlo Zottmann - - -This library is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as published by the -Free Software Foundation; either version 2.1 of the License, or (at your -option) any later version. - -This library is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License -for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this library; if not, write to the Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -JABBER is a registered trademark of Jabber Inc. - diff --git a/message/output/jabber/jabberclass/class_ConnectionSocket.php b/message/output/jabber/jabberclass/class_ConnectionSocket.php deleted file mode 100644 index 1213478791b4f..0000000000000 --- a/message/output/jabber/jabberclass/class_ConnectionSocket.php +++ /dev/null @@ -1,86 +0,0 @@ -socket = @fsockopen($hostname, $port, $errno, $errstr, $timeout)) { - socket_set_blocking($this->socket, 0); - socket_set_timeout($this->socket, 31536000); - - return true; - } else { - $this->error = "{$errstr} (#{$errno})"; - return false; - } - } - - function socket_close() { - return fclose($this->socket); - } - - function socket_write($data) { - return fwrite($this->socket, $data); - } - - function socket_read($byte_count) - { - set_magic_quotes_runtime(0); - $buffer = fread($this->socket, $byte_count); - set_magic_quotes_runtime(get_magic_quotes_runtime()); - - return $buffer; - } - -} -?> \ No newline at end of file diff --git a/message/output/jabber/jabberclass/class_Jabber.php b/message/output/jabber/jabberclass/class_Jabber.php deleted file mode 100644 index bf4d7bd72d0a8..0000000000000 --- a/message/output/jabber/jabberclass/class_Jabber.php +++ /dev/null @@ -1,2062 +0,0 @@ -_call_handler("authenticated"); -$this->_call_handler("authfailure",-1,"No authentication method available",""); -$this->_call_handler("deregistered",$this->jid); -$this->_call_handler("deregfailure",-2,"Unrecognized response from server"); -$this->_call_handler("error",$code,$msg,$xmlns,$packet); -$this->_call_handler("heartbeat"); -$this->_call_handler("message_chat",$from,$to,$body,$subject,$thread,$id,$extended,$packet); -$this->_call_handler("message_groupchat",$packet); -$this->_call_handler("message_headline",$from,$to,$body,$subject,$extended,$packet); -$this->_call_handler("message_normal",$from,$to,$body,$subject,$thread,$id,$extended,$packet); -$this->_call_handler("msgevent_composing_start",$from); -$this->_call_handler("msgevent_composing_stop",$from); -$this->_call_handler("msgevent_delivered",$from); -$this->_call_handler("msgevent_displayed",$from); -$this->_call_handler("msgevent_offline",$from); -$this->_call_handler("passwordchanged"); -$this->_call_handler("passwordfailure",-2,"Unrecognized response from server"); -$this->_call_handler("regfailure",-1,"Username already registered",""); -$this->_call_handler("registered",$this->jid); -$this->_call_handler("rosteradded"); -$this->_call_handler("rosteraddfailure",-2,"Unrecognized response from server"); -$this->_call_handler("rosterremoved"); -$this->_call_handler("rosterremovefailure",-2,"Unrecognized response from server"); -$this->_call_handler("rosterupdate",$jid,$is_new); -$this->_call_handler("servicefields",&$fields,$packet_id,$reg_key,$reg_instructions,&$reg_x); -$this->_call_handler("servicefieldsfailure",-2,"Unrecognized response from server"); -$this->_call_handler("serviceregfailure",-2,"Unrecognized response from server"); -$this->_call_handler("serviceregistered",$jid); -$this->_call_handler('servicederegfailure",-2,"Unrecognized response from server"); -$this->_call_handler('servicederegistered"); -$this->_call_handler("serviceupdate",$jid,$is_new); -$this->_call_handler("terminated"); -$this->_call_handler('connected'); -$this->_call_handler('disconnected'); // called when the connection to the Jabber server is lost unexpectedly -$this->_call_handler('probe',$packet); -$this->_call_handler('stream_error',$packet); -$this->_call_handler('subscribe',$packet); -$this->_call_handler('subscribed',$packet); -$this->_call_handler('unsubscribe',$packet); -$this->_call_handler('unsubscribed',$packet); -$this->_call_handler("privatedata",$packetid,$namespace,$values); -$this->_call_handler('debug_log',$msg); -$this->_call_handler("contactupdated",$packetid); -$this->_call_handler("contactupdatefailure",-2,"Unrecognized response from server"); - -*/ - -require_once(dirname(__FILE__)."/class_ConnectionSocket.php"); -require_once(dirname(__FILE__)."/class_XMLParser.php"); - -// Version string -define("CLASS_JABBER_VERSION","0.9rc1"); - -// Default connection timeout -define("DEFAULT_CONNECT_TIMEOUT",15); - -// Default Jabber resource -define("DEFAULT_RESOURCE","JabberClass"); - -// Minimum/Maximum callback frequencies -define("MIN_CALLBACK_FREQ",1); // more than once per second is dangerous -define("MAX_CALLBACK_FREQ",10); // less than once every 10 seconds will be very, very slow - -// Make sure we have SHA1 support, one way or another, such that we can -// perform encrypted logins. -if (!function_exists('sha1')) { // PHP v4.3.0+ supports sha1 internally - - if (function_exists('mhash')) { // is the Mhash extension installed? - - // implement the sha1() function using mhash - function sha1($str) { - return bin2hex(mhash(MHASH_SHA1, $str)); - } - - } else { - - // implement the sha1() function in native PHP using the SHA1Library class; - // this is slow, but it's better than plaintext. - require_once(dirname(__FILE__)."/class_SHA1Library.php"); - } - -} - -// Jabber communication class -class Jabber { - var $jid = ""; - var $use_msg_composing = true; - var $use_msg_delivered = false; - var $use_msg_displayed = false; - var $use_msg_offline = false; - - var $_server_host = ""; - var $_server_ip = ""; - var $_server_port = 5222; - var $_connect_timeout = DEFAULT_CONNECT_TIMEOUT; - var $_username = ""; - var $_password = ""; - var $_resource = ""; - - var $_iq_version_name = "class_Jabber.php - http://www.centova.com - Copyright 2003-2007, Centova Technologies Inc."; - var $_iq_version_version= CLASS_JABBER_VERSION; - //var $_iq_version_os = $_SERVER['SERVER_SOFTWARE']; - - var $_connector = "ConnectionSocket"; - var $_authenticated = false; - - var $_packet_queue = array(); - var $_last_ping_time = 0; - - var $_iq_handlers = array(); - var $_event_handlers = array(); - - var $execute_loop = true; - - // DEBUGGING ONLY - causes the log file to be closed/flushed after each write - var $_log_flush = true; - - // if true, roster updates generate only one "rosterupdate" event, - // regardless of how many contacts were actually updated/added; - // useful for the initial roster download - var $roster_single_update = false; - - // if true, service updates generate only one "serviceupdate" event, - // regardless of how many services were actually updated/added; - // useful for retrieving a service list - var $service_single_update = false; - - // if true, contacts without "@"'s in their name will be assumed - // to be services and will not be listed in the roster; if the - // corresponding JID is found in the $this->services array, its - // "status" and "show" elements will be updated to reflect the - // presence/availability of the service (and the "serviceupdate" - // event will be fired) - var $handle_services_internally = false; - - // If true, the server software name and version will automatically be queried - // and stored in $this->server_software and $this->server_version at login - var $auto_server_identify = true; - - var $server_software = ""; - var $server_version = ""; - var $server_os = ""; - - var $protocol_version = false; // set this to an XMPP protocol revision to include it in the tag - - // Constructor - function Jabber($enable_logging = false) { - $this->_use_log = $enable_logging; - $this->_unique_counter = 0; - $this->_log_open(); - - $this->xml = &new XMLParser(); - } - - // ==== General Methods ================================================================== - - // set a handler method for a specific Jabber event; valid handler names - // are listed at the top of this script - function set_handler($handler_name,&$handler_object,$method_name) { - $this->_event_handlers[$handler_name] = array(&$handler_object,$method_name); - } - - function set_handler_object(&$handler_object,$handlers) { - foreach ($handlers as $handler_name=>$method_name) { - $this->set_handler( - $handler_name, - $handler_object, - $method_name - ); - } - } - - // same as above, but accepts a plain ol' function instead of a method - function set_handler_function($handler_name,$method_name) { - $this->_event_handlers[$handler_name] = $method_name; - } - - // calls the specified handler with the specified parameters; accepts: - // - // $handler_name - the name of the handler (as defined with ::set_handler()) - // to call - // (optional) other parameters - the parameters to pass to the handler method - function _call_handler() { - - $numargs = func_num_args(); - if ($numargs<1) return false; - - $arg_list = func_get_args(); - $handler_name = array_shift($arg_list); - - if (($handler_name!="debug_log") && ($handler_name!="heartbeat")) $this->_log("Calling handler: $handler_name"); - - - if ($this->_event_handlers[$handler_name]) { - - // ---- REMOVE THIS AFTER BENCHMARKING! ---- - if (defined('JX_HANDLER_BENCHMARK')) $GLOBALS["jxeh"]->t_start('event.'.$handler_name); - // ---- REMOVE THIS AFTER BENCHMARKING! ---- - - call_user_func_array(&$this->_event_handlers[$handler_name],$arg_list); - - // ---- REMOVE THIS AFTER BENCHMARKING! ---- - if (defined('JX_HANDLER_BENCHMARK')) $GLOBALS["jxeh"]->t_end('event.'.$handler_name); - // ---- REMOVE THIS AFTER BENCHMARKING! ---- - - } - } - - // posix platforms support usleep(), to sleep for a specific number of - // microseonds; we use that when possible, as it allows for a more responsive - // interface - function posix_sleep() { - $micro_seconds = 250000; - usleep($micro_seconds); - - return round($micro_seconds/1000000,2); - } - - // Windows doesn't support usleep(), so we have to sleep for minimum 1-second - // intervals.. this makes the interface a bit more sluggish, but allows for - // Win32 compatibility - function win32_sleep() { - $secs = 1; - sleep($secs); - - return $secs; - } - - - // returns a unique ID to be sent with packets - function _unique_id($prefix) { - $this->_unique_counter++; - return $prefix."_" . md5(time() . $_SERVER['REMOTE_ADDR'] . $this->_unique_counter); - } - - // public method for creating a log entry - function log($msg,$level=1) { - $this->_log($msg,$level); - } - - // private method for creating a log entry - function _log($msg,$level = 1) { - if ($this->_use_log) { - if ($this->_log_flush) $this->_log_file = @fopen(dirname(__FILE__)."/log/logfile.txt","a"); - - if ($this->_log_file) { - fwrite($this->_log_file,"$msg\n"); - if ($this->_log_flush) fclose($this->_log_file); - } - - $this->_call_handler("debug_log",$msg,$level); - } - } - - // debug method for creating a log entry (for ease of commenting-out :) ) - function dlog($msg,$level=1) { - $this->_log($msg,$level); - } - - - function _log_open() { - if ($this->_use_log) { - $this->_log_file = @fopen(dirname(__FILE__)."/log/logfile.txt","w"); - if ($this->_log_file && $this->_log_flush) { - fclose($this->_log_file); - } - } - } - - function _log_close() { - if ($this->_use_log && $this->_log_file && !$this->_log_flush) { - fclose($this->_log_file); - } - } - - // splits a JID into its three components; returns an array - // of (username,domain,resource) - function _split_jid($jid) { - preg_match("/(([^\@]+)\@)?([^\/]+)(\/(.*))?$/",$jid,$matches); - return array($matches[2],$matches[3],$matches[5]); - } - - function _bare_jid($jid) { - list($u_username,$u_domain,$u_resource) = $this->_split_jid($jid); - return ($u_username?$u_username."@":"").$u_domain; - } - - - - // ==== Core Jabber Methods ============================================================== - - // Connects to the specified Jabber server. - // - // Returns true if the socket was opened, otherwise false. - // A "connected" event is also fired when the server responds to our packet. - // - // $server_host - Hostname of your Jabber server (portion after the "@" in your JID) - // $server_port - Port for your Jabber server - // $connect_timeout - Maximum number of seconds to wait for a connection - // $alternate_ip - If $server_host does not resolve to your Jabber server's IP, - // specify the correct IP to connect to here - // - // - function connect($server_host,$server_port=5222,$connect_timeout=null,$alternate_ip=false) { - - if (is_null($connect_timeout)) $connect_timeout = DEFAULT_CONNECT_TIMEOUT; - $connector = $this->_connector; - - $this->_connection = &new $connector(); - $this->_server_host = $server_host; - $this->_server_port = $server_port; - $this->_server_ip = $alternate_ip ? $alternate_ip : $server_host; - $this->_connect_timeout = $connect_timeout; - - $this->roster = array(); - $this->services = array(); - - $this->_is_win32 = (substr(strtolower(php_uname()),0,3)=="win"); - $this->_sleep_func = $this->_is_win32 ? "win32_sleep" : "posix_sleep"; - - return $this->_connect_socket(); - } - - function _connect_socket() { - $this->log('connecting: '.$this->_server_ip.' '.$this->_server_port.' '.$this->_connect_timeout); - if ($this->_connection->socket_open($this->_server_ip,$this->_server_port,$this->_connect_timeout)) { - $this->_send("\n"); - - $xmpp_version = ($this->protocol_version) ? " version='{$this->protocol_version}'" : ''; - - $this->_send("\n"); - return true; - } else { - $this->error = $this->_connection->error; - return false; - } - } - - // disconnect from the server - function disconnect() { - - $this->_send(""); - - $this->_log_close(); - return $this->_connection->socket_close(); - } - - - // logs in to the server - function login($username,$password,$resource=NULL) { - if (!$username || !$password) return false; - - // setup handler to automatically respond to the request - $auth_id = $this->_unique_id("auth"); - $this->_set_iq_handler("_on_authentication_methods",$auth_id,"result"); - $this->_set_iq_handler("_on_authentication_result",$auth_id,"error"); - - // prepare our shiny new JID - $this->_username = $username; - $this->_password = $password; - $this->_resource = !is_null($resource) ? $resource : DEFAULT_RESOURCE; - $this->jid = "{$this->_username}@{$this->_server_host}/{$this->_resource}"; - - // request available authentication methods - $payload = "{$this->_username}"; - $packet = $this->_send_iq(NULL, 'get', $auth_id, "jabber:iq:auth", $payload); - - return true; - } - - // browse the services (transports) available on the server - function browse() { - $browse_id = $this->_unique_id("browse"); - $this->_set_iq_handler("_on_browse_result",$browse_id); - - return $this->_send_iq($this->_server_host, 'get', $browse_id, "jabber:iq:browse"); - } - - // retrieve the user's roster from the jabber server - function get_roster() { - $roster_id = $this->_unique_id("roster"); - $this->_set_iq_handler("_on_roster_result",$roster_id); - - return $this->_send_iq(NULL, 'get', $roster_id, "jabber:iq:roster"); - } - - // sets a user's presence (when simply used to set your availability, it's more convenient - // to call this way, as usually only the first 2 fields are necessary) - function set_presence($show = NULL, $status = NULL, $to = NULL, $priority = NULL) { - return $this->send_presence(NULL,$to,$show,$status,$priority); - } - - // sends presence to another contact/entity - function send_presence($type = NULL, $to = NULL, $show = NULL, $status = NULL, $priority = NULL) { - $xml = "\n" : " />\n"; - - $xml .= ($status) ? " $status\n" : ''; - $xml .= ($show) ? " $show\n" : ''; - $xml .= ($priority) ? " $priority\n" : ''; - - $xml .= ($status || $show || $priority) ? "\n" : ''; - - if ($this->_send($xml)) { - return true; - } else { - $this->_log("ERROR: send_presence() #1"); - return false; - } - - } - - // indicate (to another contact) that the user is composing a message - function composing($to,$id,$start=true) { - $payload = "".($start?"$id":"").""; - return $this->message($to,"normal",NULL,NULL,NULL,NULL,$payload); - } - - function xmlentities($string, $quote_style=ENT_QUOTES) { - return htmlspecialchars($string,$quote_style); - - $trans = get_html_translation_table(HTML_ENTITIES, $quote_style); - foreach ($trans as $key => $value) - $trans[$key] = '&#'.ord($key).';'; - return strtr($string, $trans); - } - - function message($to, $type = "normal", $id = NULL, $body = NULL, $thread = NULL, $subject = NULL, $payload = NULL, $raw = false) { - if ($to && ($body || $subject || $payload)) { - if (!$id) $id = $this->_unique_id("msg"); - -// $body = htmlspecialchars($body); -// $subject = htmlspecialchars($subject); - - if (!$raw) { - $body = $this->xmlentities($body); - $subject = $this->xmlentities($subject); - $thread = $this->xmlentities($thread); - } - - //$body = str_replace("ç","ç",$body); - - $xml = "\n"; - - if ($subject) $xml .= "$subject\n"; - if ($thread) $xml .= "$thread\n"; - if ($body) $xml .= "$body\n"; - - if ($body || $subject) { - $jabber_x_event = ""; - if ($this->use_msg_composing) $jabber_x_event .= ""; - if ($this->use_msg_delivered) $jabber_x_event .= ""; - if ($this->use_msg_displayed) $jabber_x_event .= ""; - if ($this->use_msg_offline) $jabber_x_event .= ""; - if ($jabber_x_event) $xml .= "$jabber_x_event"; - } - - $xml .= $payload; - $xml .= "\n"; - - if ($this->_send($xml)) { - return true; - } else { - $this->_log("ERROR: message() #1"); - return false; - } - } else { - $this->_log("ERROR: message() #2"); - return false; - } - } - - // create a new Jabber account - function register($username, $password, $reg_email = NULL, $reg_name = NULL) { - if (!$username || !$password) return false; - - $reg_id = $this->_unique_id("reg"); - $this->_set_iq_handler("_on_register_get_result",$reg_id); - - $this->_username = $this->xmlentities($username); - $this->_password = $this->xmlentities($password); - $this->_reg_email = $this->xmlentities($reg_email); - $this->_reg_name = $this->xmlentities($reg_name); - - return $this->_send_iq($this->_server_host, 'get', $reg_id, 'jabber:iq:register'); - } - - // cancels an existing Jabber account, removing it from the server (careful!) - // - // Note: on jabberd 1.4.2 this always seems to return 503 Service Unavailable for me; - // not sure if this is a problem with this method, a problem with my server, or a - // problem with jabberd 1.4.2. - function deregister() { - $dereg_id = $this->_unique_id("dereg"); - $this->_set_iq_handler("_on_deregister_result",$dereg_id); - - $payload = ""; - return $this->_send_iq($this->_server_host, 'set', $dereg_id, "jabber:iq:register", $payload, $this->jid); - } - - - // changes the user's password - function change_password($newpassword) { - if (!$newpassword) return false; - - $chg_id = $this->_unique_id("chg"); - $this->_set_iq_handler("_on_chgpassword_result",$chg_id); - - $newpassword = $this->xmlentities($newpassword); - - $payload = "{$this->_username}$newpassword"; - return $this->_send_iq($this->_server_host, 'set', $chg_id, "jabber:iq:register", $payload); - } - - // subscribes to an entity's presence ($request_message specifies the "reason for requesting subscription" message) - function subscribe($to,$request_message=NULL) { - return $this->send_presence("subscribe", $to, NULL, $request_message); - } - - // unsubscribes from an entity's presence - function unsubscribe($to) { - return $this->send_presence("unsubscribe", $to); - } - - // accepts a subscription request from an entity - function subscription_request_accept($to) { - return $this->send_presence("subscribed", $to); - } - - // denies a subscription request from an entity - function subscription_request_deny($to) { - return $this->send_presence("unsubscribed", $to); - } - - // get the registration fields for a service/transport - function query_service_fields($transport) - { - $reg_id = $this->_unique_id("reg"); - $this->_set_iq_handler("_on_servicefields_result",$reg_id); - - if ($this->_send_iq($transport, 'get', $reg_id, "jabber:iq:register", NULL, $this->jid)) { - return $reg_id; - } else { - return false; - } - } - - - // register with a service/transport - function register_service($transport,$reg_id,$reg_key = NULL,$fields) - { - if (!$transport || !$reg_id || !$fields) return false; - - $this->_set_iq_handler("_on_serviceregister_result",$reg_id); - - - $payload = ($reg_key) ? "$reg_key\n" : ''; - foreach ($fields as $element => $value) { - $payload .= "<$element>".$this->xmlentities($value)."\n"; - } - - return $this->_send_iq($transport, 'set', $reg_id, "jabber:iq:register", $payload); - } - - function deregister_service($transport,$reg_id,$reg_key = NULL) { - if (!$transport || !$reg_id) return false; - - $this->_set_iq_handler("_on_servicedereg_initial_result",$reg_id); - - $payload = ""; - return $this->_send_iq($transport, 'set', $reg_id, "jabber:iq:register", $payload); - } - - // adds a contact to the roster - function roster_add($jid, $name = NULL, $group = NULL) { - if (!$jid) return false; - $add_id = $this->_unique_id("add"); - - $this->_set_iq_handler("_on_rosteradd_result",$add_id); - - $payload = "". $this->xmlentities($group). "\n\n"; - - if ($this->_send_iq(NULL, 'set', $add_id, "jabber:iq:roster", $payload)) { - return $add_id; - } else { - return false; - } - } - - function roster_remove($jid) { - if (!$jid) return false; - $rem_id = $this->_unique_id("remove"); - - $this->_set_iq_handler("_on_rosterremove_result",$rem_id); - - $payload = ""; - - if ($this->_send_iq(NULL, 'set', $rem_id, "jabber:iq:roster", $payload)) { - return $rem_id; - } else { - return false; - } - } - - // updates a roster contact's name and/or group - function roster_update($jid,$name = NULL,$group = NULL) { - if (!$jid) return false; - $update_id = $this->_unique_id("update"); - - $this->_set_iq_handler("_on_rosterupdate_result",$update_id); - - $payload = "". $this->xmlentities($group) . "\n\n"; - - if ($this->_send_iq(NULL, 'set', $update_id, "jabber:iq:roster", $payload)) { - return $add_id; - } else { - return false; - } - } - - // adds a contact to the roster and subscribes to his presence in one step; - // simply a time saver. - function add_contact($jid,$name = NULL,$group = NULL) { - if ($this->roster_add($jid,$name,$group)) { - return $this->subscribe($jid); - } else { - return false; - } - } - - // alias for roster_remove() - function remove_contact($jid) { - return $this->roster_remove($jid); - } - - function set_private_data($namespace,$rootelement,$values) { - if ((!$namespace) || (!$rootelement) || (!$values)) return false; - - $data_id = $this->_unique_id("privdata"); - -// $this->_set_iq_handler("_on_xxx_result",$data_id); // we don't really need the result from this... do we? - - $payload = "<$rootelement xmlns='$namespace'>"; - foreach ($values as $key=>$value) { - $payload .= "<$key>$value"; - } - $payload .= ""; - - if ($this->_send_iq(NULL, 'set', $data_id, "jabber:iq:private", $payload)) { - return $data_id; - } else { - return false; - } - } - - function get_private_data($namespace,$rootelement) { - if ((!$namespace) || (!$rootelement)) return false; - - $data_id = $this->_unique_id("privdata"); - $this->_set_iq_handler("_on_private_data",$data_id); - - $payload = "<$rootelement xmlns='$namespace' />"; - - if ($this->_send_iq(NULL, 'get', $data_id, "jabber:iq:private", $payload)) { - return $data_id; - } else { - return false; - } - } - - function adjust_callback_frequency($factor) { - if ($this->active_cbk_freq<0) return; - - $this->dlog("Setting callback frequency factor to $factor"); - - $this->active_cbk_freq = $this->initial_cbk_freq*$factor; - - $this->dlog("Setting active frequency to {$this->active_cbk_freq}"); - - if ($this->active_cbk_freqactive_cbk_freq = MIN_CALLBACK_FREQ; - if ($this->active_cbk_freq>MAX_CALLBACK_FREQ) $this->active_cbk_freq = MAX_CALLBACK_FREQ; - } - - - // begin execution loop... sort of a ghetto-multithreading type thing, I guess... :) - function execute($callback_freq = -1,$seconds = -1) - { - $sleepfunc = $this->_sleep_func; - $this->active_cbk_freq = $this->initial_cbk_freq = $callback_freq; - - $count = 0; - $cb_count = 0; - - // set terminated to true in any event handler to cause this method to exit immediately - $this->terminated = false; - - while (($count != $seconds) && (!$this->terminated)) { - - // check to see if there are any packets waiting - if ($this->_receive()) { - - while (count($this->_packet_queue)) { - $packet = $this->_get_next_packet(); - - // if a packet was available (should always be) - if ($packet) { - // check the packet type, and dispatch the appropriate handler - if (!empty($packet['iq'])) { - $this->_handle_iq($packet); - } elseif (!empty($packet['message'])) { - $this->_handle_message($packet); - } elseif (!empty($packet['presence'])) { - $this->_handle_presence($packet); - } elseif (!empty($packet['stream:stream'])) { - $this->_handle_stream($packet); - } elseif (!empty($packet['stream:features'])) { - $this->_handle_stream_features($packet); - } elseif (!empty($packet['stream:error'])) { - $this->_handle_stream_error($packet); - } else { - $this->_log("Unknown packet type!"); - $x = $this->dump($packet); - $this->_log($x); - } - } - } - } - - - $sleeptime = $this->$sleepfunc(); - - $count += $sleeptime; - $cb_count += $sleeptime; - - if ($this->_last_ping_time != date("H:i")) { - if (!$this->_send(" ",true)) { - // Lost connection to Jabber server! - $this->_call_handler('disconnected'); - $this->terminated = true; - } - $this->_last_ping_time = date("H:i"); - } - - if (($this->active_cbk_freq>0) && ($cb_count>=$this->active_cbk_freq) && ($this->_authenticated)) { - - $this->dlog("Heartbeat - cbcount:{$cb_count} / active_cbk_freq:{$this->active_cbk_freq}"); - - $this->_call_handler("heartbeat"); - $cb_count = 0; - } - - if (!$this->execute_loop) break; - } - - if ($this->execute_loop) $this->_call_handler("terminated"); - - return TRUE; - } - - - - - - - - - // ==== Event Handlers (Raw Packets) ===================================================== - - // Sets a handler for a particular IQ packet ID (and optionally packet type). - // Assumes that $method is the name of a method of $this - function _set_iq_handler($method,$id,$type=NULL) { - if (is_null($type)) $type = "_all"; - $this->_iq_handlers[$id][$type] = array(&$this,$method); - } - - - function _node($packet,$path,$checkset = false) { - $cursor = &$packet; - - $pathlength = count($path); - for ($i=0; $i<$pathlength; $i++) { - $last = ($i==$pathlength-1); - - $element = $path[$i]; - - if (!is_array($cursor) || !isset($cursor[$element])) return ($checkset ? false : NULL); - - if ($last) { - if ($checkset) { - return isset($cursor[$element]); - } else { - return $cursor[$element]; - } - } else { - $cursor = &$cursor[$element]; - } - - } - - return ($checkset ? false : NULL); - } - - function _nodeset($packet,$path) { - return $this->_node($packet,$path,true); - } - - // handle IQ packets - function _handle_iq(&$packet) { - $iq_id = $this->_node($packet,array('iq','@','id')); - - $iq_type = $this->_node($packet,array('iq','@','type')); - - // see if we already have a handler setup for this ID number; the vast majority of IQ - // packets are handled by their ID number, since they are usually in response to a - // request we submitted - if ($this->_iq_handlers[$iq_id]) { - - // OK, is there a handler for this specific packet type as well? - if ($this->_iq_handlers[$iq_id][$iq_type]) { - // yup - try the handler for our packet type - $iqt = $iq_type; - } else { - // nope - try the catch-all handler - $iqt = "_all"; - } - - $this->dlog("Handling $iq_id [$iqt]"); - $handler_method = $this->_iq_handlers[$iq_id][$iqt]; - unset($this->_iq_handlers[$iq_id][$iqt]); - - if ($handler_method) { - call_user_func($handler_method,&$packet); - } else { - $this->_log("Don't know what to do with packet: ".$this->dump($packet)); - } - } else { - // this packet didn't have an ID number (or the ID number wasn't recognized), so - // see if we can salvage it. - switch($iq_type) { - case "get": - if (!$this->_node($packet,array('iq','#','query'))) return; - - $xmlns = $this->_node($packet,array('iq','#','query',0,'@','xmlns')); - switch($xmlns) { - case "jabber:iq:version": - // handle version inquiry/response - $this->_handle_version_packet($packet); - break; - case "jabber:iq:time": - // handle time inquiry/response - $this->_handle_time_packet($packet); - break; - default: - // unknown XML namespace; borkie borkie! - break; - } - break; - - case "set": // handle packets - if (!$this->_node($packet,array('iq','#','query'))) return; - - $xmlns = $this->_node($packet,array('iq','#','query',0,'@','xmlns')); - switch($xmlns) { - case "jabber:iq:roster": - $this->_on_roster_result($packet); - break; - default: - // unknown XML namespace; borkie borkie! - break; - } - break; - - default: - // don't know what to do with other types of IQ packets! - break; - - } - } - } - - function varset($v) { - return is_string($v) ? strlen($v)>0 : !empty($v); - } - - // handle Message packets - function _handle_message(&$packet) { - // events that we recognize - $events = array("composing","offine","delivered","displayed"); - - // grab the message details - $type = $this->_node($packet,array('message','@','type')); - if (!$type) $type = "chat"; - - $from = $this->_node($packet,array('message','@','from')); - $to = $this->_node($packet,array('message','@','to')); - $id = $this->_node($packet,array('message','@','id')); - - list($f_username,$f_domain,$f_resource) = $this->_split_jid($from); - $from_jid = ($f_username?"{$f_username}@":"").$f_domain; - - $body = $this->_node($packet,array('message','#','body',0,'#')); - $subject = $this->_node($packet,array('message','#','subject',0,'#')); - $thread = $this->_node($packet,array('message','#','thread',0,'#')); - - // handle extended message info (to a certain extent, anyway)... - // if any of the tags in $events are passed under an x element in the - // jabber:x:event namespace, $extended[tagname] is set to TRUE - $extended = false; - $extended_id = NULL; - $x = $this->_node($packet,array('message','#','x')); - - if (is_array($x)) { - foreach ($x as $key=>$element) { - if ($this->_node($element,array('@','xmlns'))=="jabber:x:event") { - if ( !isset($element['#']) || !is_array($element['#']) ) continue; - - foreach ($element['#'] as $tag=>$element_content) { - if (in_array($tag,$events)) { - $extended[$tag] = true; - } - if ($tag=="id") { - $extended_id = $this->_node($element_content,array('0','#')); - if (!$extended) $extended = array(); - } - } - } - } - } - - // if a message contains an x tag in the jabber:x:event namespace, - // and doesn't contain a body or subject, then it's an event notification - if (!$this->varset($body) && !$this->varset($subject) && is_array($extended)) { - - // is this a composing event (which needs special handling)? - if (isset($extended['composing'])) { - $this->_call_handler("msgevent_composing_start",$from); - $this->roster[$from_jid]["composing"] = true; - } else { - if ($this->roster[$from_jid]["composing"]) { - $this->_call_handler("msgevent_composing_stop",$from); - $this->roster[$from_jid]["composing"] = false; - } - } - - foreach ($extended as $event=>$value) { - $this->_call_handler("msgevent_$event",$from); - } - - // don't process the rest of the message event, as it's not really a message - return; - } - - - // process the message - switch($type) { - case "error": - $this->_handle_error(&$packet); - break; - case "groupchat": - $this->_call_handler("message_groupchat",$packet); - break; - case "headline": - $this->_call_handler("message_headline",$from,$to,$body,$subject,$x,$packet); - break; - case "chat": - case "normal": - default: - if ($this->roster[$from_jid]["composing"]) $this->roster[$from_jid]["composing"] = false; - if (($type!="chat") && ($type!="normal")) $type = "normal"; - $this->_call_handler("message_$type",$from,$to,$body,$subject,$thread,$id,$extended,$packet); - break; - - } - } - - // handle Presence packets - function _handle_presence(&$packet) { - - $type = $this->_node($packet,array('presence','@','type')); - if (!$type) $type = "available"; - - $from = $this->_node($packet,array('presence','@','from')); - - list($f_username,$f_domain,$f_resource) = $this->_split_jid($from); - $from_jid = ($f_username?"{$f_username}@":"").$f_domain; - - $is_service = (!strlen($f_username)); - - $exists = ($is_service && $this->handle_services_internally) ? isset($this->services[$from_jid]) : isset($this->roster[$from_jid]); - // $this->dlog("TRACE::_handle_presence() called with from=$from, exists=[$exists]"); - - $nothing = false; - $rosteritem = &$nothing; - - /* - // Merak doesn't send roster items for gateway contacts for some reason - it just throws - // presence packets at you all willy-nilly... so we simulate a roster update if a non-roster - // presence packet is received and we've identified the server as Merak - - // This doesn't work, as internally Merak records the contacts as having no subscription, - // but doesn't send any subscription requests to the client. Craptacular. - if (!$exists && $this->is_merak && !$is_service) { - $this->roster[$from_jid] = array( - "username" => $f_username, - "domain" => $f_domain, - "resource" => $f_resource, - "jid" => $from_jid, - "transport" => $this->get_transport($f_domain) - ); - $exists = true; - } - */ - - if ($exists) { - if ($is_service && $this->handle_services_internally) { - // $this->dlog("SVC: rosteritem=service[{$from_jid}]"); - $use_services_array = true; - $rosteritem = &$this->services[$from_jid]; - } else { - // $this->dlog("SVC: rosteritem=roster[{$from_jid}]"); - $use_services_array = false; - $rosteritem = &$this->roster[$from_jid]; - - unset($rosteritem['customnickname']); - } - } else { - // Ignore roster updates for JIDs not in our roster, except - // for subscription requests... - - if ($type=="available") { - // ... but make note of the presence of non-roster items here, in case - // the roster item is sent AFTER the presence packet... then we can apply the - // presence when the roster item is received - $show = $this->_show($this->_node($packet,array('presence','#','show',0,'#'))); - $this->presence_cache[$from_jid] = array( - "status"=>$this->_node($packet,array('presence','#','status',0,'#')), - "show"=>$show ? $show : "on" - ); - // $this->dlog("TRACE::_handle_presence(): Caching presence for [$from_jid]; type=available, status=[".$this->presence_cache[$from_jid]["status"]."], show=[".$this->presence_cache[$from_jid]["show"]."]"); - - return; - } - - if ($type!="subscribe") { - // $this->dlog("TRACE::_handle_presence(): type!=subscribe; exiting _handle_presence()"); - return; - } - // $this->dlog("TRACE::_handle_presence(): type=subscribe; passing through"); - } - $call_update = false; - - /* - ob_start(); - echo "\n----PRESENCE----\n"; - echo "[$type]\n"; - var_dump($packet); - echo "----END PRESENCE----\n\n"; - $y = ob_get_contents(); - $this->dlog($y); - ob_end_clean(); - */ - - switch($type) { - case "error": - $this->_handle_error(&$packet); - break; - case "probe": - $this->_call_handler('probe',$packet); - break; - case "subscribe": - // note: $rosteritem is not set here - $this->_call_handler('subscribe',$packet); - break; - case "subscribed": - $this->_call_handler('subscribed',$packet); - break; - case "unsubscribe": - $this->_call_handler('unsubscribe',$packet); - break; - case "unsubscribed": - $this->_call_handler('unsubscribed',$packet); - break; - case "unavailable": - // $this->dlog("NOTE: Setting rosteritem[status] for ".($use_services_array?"service":"roster item")." $from_jid to off (unavailable)"); - $rosteritem["show"] = "off"; - $call_update = true; - break; - case "available": - $rosteritem["status"] = $this->_node($packet,array('presence','#','status',0,'#')); - $show = $this->_show($this->_node($packet,array('presence','#','show',0,'#'))); - $rosteritem["show"] = $show ? $show : "on"; // away, chat, xa, dnd, or "" = online - - if ($this->_node($packet,array('presence','#','x',0,'@','xmlns'))=='vcard-temp:x:update') { - $rosteritem['customnickname'] = $this->_node($packet,array('presence','#','x',0,'#','nickname',0,'#')); - } - - // $this->dlog("NOTE: Setting rosteritem[status] for ".($use_services_array?"service":"roster item")." $from_jid to ".$rosteritem["status"]); - $call_update = true; - break; - default: - $this->_log("Unknown presence type: $type"); - break; - } - if ($call_update) { - if ($use_services_array) { - // $this->dlog("TRACE::_handle_presence(): calling serviceupdate for $from"); - $this->_call_handler("serviceupdate",$from,false); - } else { - // $this->dlog("TRACE::_handle_presence(): calling rosterupdate for $from"); - $this->_call_handler("rosterupdate",$from,false); - } - } - } - - // handle Stream packets - function _handle_stream(&$packet) { - $ss = $this->_node($packet,array('stream:stream','@')); - if (is_array($ss)) { - if ($ss['from'] == $this->_server_host - && $ss['xmlns'] == "jabber:client" - && $ss["xmlns:stream"] == "http://etherx.jabber.org/streams") - { - $this->_stream_id = $this->_node($packet,array("stream:stream",'@','id')); - $this->_call_handler('connected'); - return; - } - } - - $this->_log("Unrecognized stream packet"); - var_dump($packet); - } - - // handle Stream features packets - function _handle_stream_features(&$packet) { - $this->features = &$packet; - } - - // handle stream error - function _handle_stream_error(&$packet) { - $this->_call_handler('stream_error',$packet); - } - - - - // ==== Event Handlers (Event Specific) ================================================== - - // receives a list of authentication methods and sends an authentication - // request with the most appropriate one - function _on_authentication_methods(&$packet) { - $auth_id = $this->_node($packet,array('iq','@','id')); - $auth_request_sent = true; - - // check for auth method availability in descending order (best to worst) - - // Note: As noted in JEP-0078 (http://www.jabber.org/jeps/jep-0078.html), the so-called - // "zero-knowledge" authentication is no stronger than digest authentication, and is not - // even documented in JEP-0078 anymore. As such, it is not supported here. - // - // SASL authentication is not yet supported (for unrelated reasons). - - // digest - if ($this->_nodeset($packet,array('iq','#','query',0,'#','digest'))) { - $this->_sendauth_digest($auth_id); - - // plain text - } elseif ($this->_node($packet,array('iq','#','query',0,'#','password'))) { - $this->_sendauth_plaintext($auth_id); - - // no auth methods - } else { - $auth_request_sent = false; - $this->_call_handler("authfailure",-1,"No authentication method available",""); - $this->_log("ERROR: _on_authentication_methods() #2 - No auth method available!"); - } - - if ($auth_request_sent) { - $this->_set_iq_handler("_on_authentication_result",$auth_id); - } - - } - - // receives the results of an authentication attempt - function _on_authentication_result(&$packet) { - $auth_id = $this->_node($packet,array('iq','@','id')); - $result_type = $this->_node($packet,array('iq','@','type')); - - if ($result_type=="result") { - if ($this->auto_server_identify) $this->request_version($this->_server_host); - - $this->_call_handler("authenticated"); - $this->_authenticated = true; - } elseif ($result_type=="error") { - $this->_handle_iq_error(&$packet,"authfailure"); - } - } - - // receives the results of a service browse query - function _on_browse_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - -// $this->_log("BROWSE packet: ".var_export($packet,true)); - - // did we get a result? if so, process it, and remember the service list - if ($packet_type=="result") { - - $this->services = array(); - - //$this->_log("SERVICES: ".print_r($packet,true)); - - //$this->_log("\n\nSOFTWARE: ".$this->server_software." v".$this->server_version."\n\n"); - - if ($this->_node($packet,array('iq','#','service'))) { - // Jabberd uses the 'service' element - $servicekey = $itemkey = 'service'; - } elseif ($this->_node($packet,array('iq','#','item'))) { - // Older versions of Merak use 'item' - $servicekey = $itemkey = 'item'; - } elseif ($this->_node($packet,array('iq','#','query'))) { - // Newer versions of Merak use 'query' - $servicekey = 'query'; - $itemkey = 'item'; - } else { - // try to figure out what to use - $k = array_keys($this->_node($packet,array('iq','#'))); - $servicekey = $k[0]; - if (!$servicekey) return; - } - // if the item key is incorrect, try to figure that out as well - if ($this->_node($packet,array('iq','#',$servicekey)) && !$this->_node($packet,array('iq','#',$servicekey,0,'#',$itemkey))) { - $k = array_keys($this->_node($packet,array('iq','#',$servicekey,0,'#'))); - $itemkey = $k[0]; - } - - $number_of_services = is_array($this->_node($packet,array('iq','#',$servicekey,0,'#',$itemkey))) ? count($this->_node($packet,array('iq','#',$servicekey,0,'#',$itemkey))) : 0; - - $services_updated = false; - for ($a = 0; $a < $number_of_services; $a++) - { - $svc = $this->_node($packet,array('iq','#',$servicekey,0,'#',$itemkey,$a)); - - $jid = strtolower($this->_node($svc,array('@','jid'))); - $is_new = !isset($this->services[$jid]); - $this->services[$jid] = array( - "type" => strtolower($this->_node($svc,array('@','type'))), - "status" => "Offline", - "show" => "off", - "name" => $this->_node($svc,array('@','name')), - "namespaces" => array() - ); - - $number_of_namespaces = is_array($this->_node($packet,array('iq','#',$servicekey,0,'#',$itemkey,$a,'#','ns'))) ? count($this->_node($packet,array('iq','#',$servicekey,0,'#',$itemkey,$a,'#','ns'))) : 0; - for ($b = 0; $b < $number_of_namespaces; $b++) { - $this->services[$jid]['namespaces'][$b] = $this->_node($packet,array('iq','#',$servicekey,0,'#',$itemkey,$a,'#','ns',$b,'#')); - } - - if ($this->service_single_update) { - $services_updated = true; - } else { - $this->_call_handler("serviceupdate",$jid,$is_new); - } - } - - if ($this->service_single_update && $services_updated) { - $this->_call_handler("serviceupdate",NULL,$is_new); - } - - $this->_log("Received service list"); - //$this->_log("Received service list: ".print_r($this->services,true)); - // choke on error - } elseif ($packet_type=="error") { - $this->_handle_iq_error($packet); - - // confusion sets in - } else { - $this->_log("Don't know what to do with jabber:iq:browse packet!"); - } - } - - // request software version from a JabberID - function request_version($jid) { - - $this->_log('Requesting version information from '.$jid); - // setup handler to automatically respond to the request (it would anyway, - // because of how we handle version packets, but... hey, why not be thorough) - $ver_id = $this->_unique_id("ver"); - - $this->_set_iq_handler("_handle_version_packet",$ver_id); - - return $this->_send_iq($jid, 'get', $ver_id, "jabber:iq:version"); - } - - // handle a jabber:iq:version packet (either a request, or a response) - function _handle_version_packet(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - $from = $this->_node($packet,array('iq','@','from')); - $packetid = $this->_node($packet,array('iq','@','id')); - - if ($packet_type=="result") { - // did we get a result? if so, process it, and update the contact's version information - $jid = $this->_bare_jid($from); - - $version = $this->_node($packet,array('iq','#','query',0,'#')); - $this->_log("$jid/".$this->_server_host); - if ($jid==$this->_server_host) { - //$this->_log("\n\n\n\nVERSION: ".print_r($version,true)."\n\n\n\n".print_r($packet,true)."\n\n\n\n"); - $this->server_software = $this->_node($version,array('name',0,'#')); - $this->server_version = $this->_node($version,array('version',0,'#')); - $this->server_os = $this->_node($version,array('os',0,'#')); - - $this->is_merak = strtolower(substr($this->server_software,0,5))=="merak"; - } elseif ($this->roster[$jid]) { - $this->roster[$jid]["version"] = $version; - } - - // $this->dlog("TRACE::_handle_version_packet(): calling rosterupdate for $jid"); - $this->_call_handler("rosterupdate",$jid,false); - - } elseif ($packet_type=="get") { - // did we get an inquiry? if so, send our version info - $payload = "{$this->_iq_version_name}{$this->_iq_version_version}"; - if ($this->_iq_version_os) $payload .= "{$this->_iq_version_os}"; - $packet = $this->_send_iq($from, 'result', $packetid, "jabber:iq:version", $payload); - } - // other types of packets are probably just error responses (eg: the remote - // client doesn't support jabber:iq:version requests) so we ignore those - - return true; - } - - // handle a jabber:iq:time packet (either a request, or a response) - function _handle_time_packet(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - $from = $this->_node($packet,array('iq','@','from')); - $packetid = $this->_node($packet,array('iq','@','id')); - - if ($packet_type=="result") { - // did we get a result? if so, process it, and update the contact's time information - $jid = $this->_bare_jid($from); - - $timeinfo = $this->_node($packet,array('iq','#','query',0,'#')); - $this->roster[$jid]["time"] = $timeinfo; - - // $this->dlog("TRACE::_handle_time_packet(): calling rosterupdate for $jid"); - $this->_call_handler("rosterupdate",$jid,false); - } elseif ($packet_type=="get") { - // did we get an inquiry? if so, send our time info - $utc = gmdate('Ymd\TH:i:s'); - $tz = date("T"); - $display = date("D M d H:i:s Y"); - - $payload = "{$utc}{$tz}{$display}"; - $packet = $this->_send_iq($from, 'result', $packetid, "jabber:iq:time", $payload); - } - // other types of packets are probably just error responses (eg: the remote - // client doesn't support jabber:iq:time requests) so we ignore those - - return true; - } - - // receives the results of a roster query - // - // Note: You should always browse services BEFORE calling get_roster(), as this - // will ensure that the correct services get marked as "registered" in $this->services, - // and each roster contact will automatically have its "transport" element set to the - // correct transport. - function _on_roster_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - - // did we get a result? if so, process it, and remember the service list - if (($packet_type=="result") || ($packet_type=="set")) { - - $roster_updated = false; - - $itemlist = $this->_node($packet,array('iq','#','query',0,'#','item')); - $number_of_contacts = is_array($itemlist) ? count($itemlist) : 0; - - //echo "
"; echo "itemlist:\n"; var_dump($itemlist); echo "
"; - - for ($a = 0; $a < $number_of_contacts; $a++) - { - if (!isset($itemlist[$a])) continue; - - $queryitem = &$itemlist[$a]; - //echo "
"; echo "itemlist:\n"; var_dump($queryitem); echo "
"; - $jid = strtolower($this->_node($queryitem,array('@','jid'))); - - $subscription = $this->_node($queryitem,array('@','subscription')); - - - list($u_username,$u_domain,$u_resource) = $this->_split_jid($jid); - //echo "[$u_username/$u_domain/$u_resource/$jid]"; - $jid = ($u_username?"{$u_username}@":"").$u_domain; - - - $is_new = !isset($this->roster[$jid]); - - //$x = $this->dump($this->roster[$jid]); - // $this->dlog("TRACE::_on_roster_result(): processing roster contact [{$jid}] (is_new=={$is_new}; existing item=[{$x}])"); - - - // Is it a transport? - $is_service = (!strlen($u_username)); - if ($is_service) { - // are we registered with it? - /*if ($u_resource=="registered") {*/ - if (!in_array($subscription,array("none","remove"))) { // if we're not subscribed to it, then we'll consider it unregistered - $this->services[$jid]["registered"] = true; - } - /*}*/ - } - - // don't add the entry to the roster if it's a service, and we've been - // configured to handle service presence internally (via $this->services) - if (!($is_service && $this->handle_services_internally)) { - // if not new, don't clobber the old presence/availability - $u_jid = $u_username."@".$u_domain; - $status = $is_new?"Offline":$this->roster[$jid]["status"]; - $show = $is_new?"off":$this->roster[$jid]["show"]; - - // if presence was received before roster, grab the show value from the presence - if ($this->presence_cache[$u_jid]) { - if (!$show || $is_new) { - $show = $this->presence_cache[$u_jid]["show"]; - // $this->dlog("TRACE::_on_roster_result: Using cached 'show' state for [{$u_jid}]; show=[{$show}]"); - } - if (!$status || $is_new) { - $status = $this->presence_cache[$u_jid]["status"]; - // $this->dlog("TRACE::_on_roster_result: Using cached 'status' state for [{$u_jid}]; status=[{$status}]"); - } - - // remove any cached presence info, as the roster item now exists - // $this->dlog("TRACE::_on_roster_result: Clearing presence cache for {$u_jid}"); - unset($this->presence_cache[$u_jid]); - } - - $nodename = $this->_node($queryitem,array('@','name')); - $rostername = strlen($nodename) ? $nodename : $u_username; - - - // prepare the roster item - $rosteritem = array( - "name" => $rostername, - "subscription" => $this->_node($queryitem,array('@','subscription')), - "ask" => $this->_node($queryitem,array('@','ask')), - "group" => $this->_node($queryitem,array('#','group',0,'#')), - "status" => $status, - "show" => $show, - "username" => $u_username, - "domain" => $u_domain, - "resource" => $u_resource, - "jid" => $u_jid, - "transport" => $this->get_transport($u_domain) - ); - if ($is_new) { - // if it's a new entry, just add it to the roster - $this->roster[$jid] = $rosteritem; - } else { - // otherwise, carefully update the existing entry, preserving - // any elements that may have been added externally - foreach ($rosteritem as $k=>$v) { - $this->roster[$jid][$k] = $v; - } - } - - //$this->_log('ROSTER UPDATE: '.print_r($this->roster[$jid],true)); - // you may wish to set roster_single_update to TRUE before - // calling your initial browse(); this will allow you to - // initialize your entire roster in one swoop, rather than - // doing it contact-by-contact - if ($this->roster_single_update) { - // $this->dlog("TRACE::_on_roster_result(): updated contact for future roster_single_update; jid=$jid,is_new=[$is_new]"); - - $roster_updated = true; - } else { - // $this->dlog("TRACE::_on_roster_result(): calling rosterupdate for jid=$jid,is_new=$is_new (individual)"); - $this->_call_handler("rosterupdate",$jid,$is_new); - } - } - } - - if ($this->roster_single_update && $roster_updated) { - // $this->dlog("TRACE::_on_roster_result(): calling rosterupdate for jid=NULL,is_new=false (roster_single_update==true)"); - $this->_call_handler("rosterupdate",NULL,false); - } - - $this->_log("Received roster"); - // choke on error - } elseif ($packet_type=="error") { - $this->_handle_iq_error($packet); - - // confusion sets in - } else { - $this->_log("Don't know what to do with jabber:iq:roster packet!"); - } - } - - function _is_error_packet($packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - return ( $packet_type == 'error' && $this->_nodeset($packet,array('iq','#','error',0,'#')) ); - } - - // receives the results of an account registration 'get' query (retrieving fields) - function _on_register_get_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - $reg_id = $this->_unique_id("reg"); - - if ($packet_type=="result") { - - if ($this->_nodeset($packet,array('iq','#','query',0,'#','registered',0,'#'))) { - $this->_call_handler("regfailure",-1,"Username already registered",""); - return; - } - - $key = $this->_node($packet,array('iq','#','query',0,'#','key',0,'#')); - unset($packet); - - // Looks like CJP just hardcoded these fields, regardless of what the server sends...?! - // FIXME: parse fields dynamically this when time permits - $payload = "{$this->_username} - {$this->_password} - {$this->_reg_email} - {$this->_reg_name}\n"; - - $payload .= ($key) ? "$key\n" : ''; - - $this->_set_iq_handler("_on_register_set_result",$reg_id); - $this->_send_iq($this->_server_host, 'set', $reg_id, "jabber:iq:register", $payload); - - - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"regfailure"); - - } else { - $this->_call_handler("regfailure",-2,"Unrecognized response from server",""); - } - } - - // receives the results of an account registration 'set' query (the actual result of - // the account registration attempt) - function _on_register_set_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - $error_code = 0; - - if ($packet_type=="result") { - - if ($this->_resource) { - $this->jid = "{$this->_username}@{$this->_server_host}/{$this->_resource}"; - } else { - $this->jid = "{$this->_username}@{$this->_server_host}"; - } - $this->_call_handler("registered",$this->jid); - - } elseif ($this->_is_error_packet($packet)) { - // "conflict" error, i.e. already registered - if ($this->_node($packet,array('iq','#','error',0,'@','code')) == '409') { - $this->_call_handler("regfailure",-1,"Username already registered",""); - } else { - $this->_handle_iq_error(&$packet,"regfailure"); - } - - } else { - $this->_call_handler("regfailure",-2,"Unrecognized response from server"); - } - } - - function _on_deregister_result(&$packet) { - - $packet_type = $this->_node($packet,array('iq','@','type')); - - if ($packet_type=="result") { - $this->_call_handler("deregistered",$this->jid); - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"deregfailure"); - } else { - $this->_call_handler("deregfailure",-2,"Unrecognized response from server"); - } - } - - - // receives the result of a password change - function _on_chgpassword_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - if ($packet_type=="result") { - $this->_call_handler("passwordchanged"); - - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"passwordfailure"); - } else { - $this->_call_handler("passwordfailure",-2,"Unrecognized response from server"); - } - } - - // receives the result of a service (transport) registration - function _on_servicefields_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - $packet_id = $this->_node($packet,array('iq','@','id')); - - if ($packet_type=="result") { - - $reg_key = ""; - $reg_instructions = ""; - $reg_x = ""; - $fields = array(); - - foreach ($this->_node($packet,array('iq','#','query',0,'#')) as $element => $data) { - switch($element) { - case "key": - $reg_key = $this->_node($data,array(0,'#')); - break; - case "instructions": - $reg_instructions = $this->_node($data,array(0,'#')); - break; - case "x": - $reg_x = $this->_node($data,array(0,'#')); - break; - default: - $fields[] = $element; - break; - } - } - $this->_call_handler("servicefields",&$fields,$packet_id,$reg_key,$reg_instructions,&$reg_x); - - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"servicefieldsfailure"); - } else { - $this->_call_handler("servicefieldsfailure",-2,"Unrecognized response from server"); - } - } - - function _on_serviceregister_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - $from = $this->_node($packet,array('iq','@','from')); - if ($packet_type == 'result') { - if ($this->_nodeset($packet,array('iq','#','query',0,'#','registered',0,'#'))) { - $this->_call_handler("serviceregfailure",-1,"Already registered with service",""); - } else { - $jid = $this->_bare_jid($from); - $this->_call_handler("serviceregistered",$from); - } - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"serviceregfailure"); - } else { - $this->_call_handler("serviceregfailure",-2,"Unrecognized response from server"); - } - } - - function _on_servicedereg_initial_result(&$packet) { - - $packet_type = $this->_node($packet,array('iq','@','type')); - $from = $this->_node($packet,array('iq','@','from')); - - if ($packet_type == 'result') { - - // we're now deregistered with the transport, but we need to remove - // our roster subscription - $dereg_id = $this->_unique_id("svcdereg"); - $this->_set_iq_handler("_on_servicedereg_final_result",$dereg_id); - - - $this->services[$from]["registered"] = false; - $this->services[$from]["subscription"] = "none"; - - $payload = ""; - - $this->dlog("TRACE:: _on_servicedereg_initial_result() has positive result, setting handler ID#$dereg_id for final result"); - - if ($this->_send_iq(NULL, 'set', $dereg_id, "jabber:iq:roster", $payload)) { - $this->dlog("TRACE:: _on_deregister_initial_result() SENT, existing"); - - return $dereg_id; - } else { - $this->dlog("TRACE:: _on_deregister_initial_result() FAILURE!!"); - - return false; - } - - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"servicederegfailure"); - } else { - $this->_call_handler("servicederegfailure",-2,"Unrecognized response from server"); - } - } - - function _on_servicedereg_final_result(&$packet) { - $this->dlog("TRACE:: _on_deregister_final_result() called!"); - - $packet_type = $this->_node($packet,array('iq','@','type')); - if ($packet_type == 'result') { - $this->_call_handler("servicederegistered"); - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"servicederegfailure"); - } else { - $this->_call_handler("servicederegfailure",-2,"Unrecognized response from server"); - } - } - - function _on_rosteradd_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type'));; - if ($packet_type == 'result') { - - $this->_call_handler("rosteradded",$this->_node($packet,array('iq','@','id'))); - - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"rosteraddfailure"); - } else { - $this->_call_handler("rosteraddfailure",-2,"Unrecognized response from server"); - } - } - - function _on_rosterupdate_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - if ($packet_type == 'result') { - $this->_call_handler("contactupdated",$this->_node($packet,array('iq','@','id'))); - - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"contactupdatefailure"); - } else { - $this->_call_handler("contactupdatefailure",-2,"Unrecognized response from server"); - } - } - function _on_rosterremove_result(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - if ($packet_type == 'result') { - $this->_call_handler("rosterremoved",$this->_node($packet,array('iq','@','id'))); - - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"rosterremovefailure"); - } else { - $this->_call_handler("rosterremovefailure",-2,"Unrecognized response from server"); - } - } - - function _on_private_data(&$packet) { - $packet_type = $this->_node($packet,array('iq','@','type')); - if ($packet_type == 'result') { - - $rootnode = $this->_node($packet,array('iq','#','query',0,'#')); - unset($rootnode[0]); - $rootnode = array_shift($rootnode); - $data = $rootnode[0]; - $namespace = $this->_node($data,array('@','xmlns')); - $rawvalues = $this->_node($data,array('#')); - - $values = array(); - if (is_array($rawvalues)) { - foreach ($rawvalues as $k=>$v) { - $values[$k] = $this->_node($v,array(0,'#')); - } - } - - $this->_call_handler("privatedata",$this->_node($packet,array('iq','@','id')),$namespace,$values); - - } elseif ($this->_is_error_packet($packet)) { - $this->_handle_iq_error(&$packet,"privatedatafailure"); - } else { - $this->_call_handler("privatedatafailure",-2,"Unrecognized response from server"); - } - } - - - // handles a generic IQ error; fires the specified error handler method - // with the error code/message retrieved from the IQ packet - function _handle_iq_error(&$packet,$error_handler="error") { - $error = $this->_node($packet,array('iq','#','error',0)); - $xmlns = $this->_node($packet,array('iq','#','query',0,'@','xmlns')); - $this->_call_handler( - $error_handler, - $this->_node($error,array('@','code')), - $this->_node($error,array('#')), - $xmlns, - $packet - ); - } - - // handles a generic error; fires the specified error handler method - // with the error code/message retrieved from the packet - function _handle_error(&$packet,$error_handler="error") { - $packet = array_shift($packet); - $error = $this->_node($packet,array('#','error',0)); - $xmlns = $this->_node($packet,array('#','query',0,'@','xmlns')); - $this->_call_handler( - $error_handler, - $this->_node($error,array('@','code')), - $this->_node($error,array('#')), - $xmlns, - $packet - ); - } - - - - // ==== Authentication Methods =========================================================== - - function _sendauth_digest($auth_id) { - $this->_log("Using digest authentication"); - - $payload = "{$this->_username} - {$this->_resource} - " . sha1($this->_stream_id . $this->_password) . ""; - - $this->_send_iq(NULL, 'set', $auth_id, "jabber:iq:auth", $payload); - } - - function _sendauth_plaintext($auth_id) { - $this->_log("Using plaintext authentication"); - - $payload = "{$this->_username} - {$this->_password} - {$this->_resource}"; - - $this->_send_iq(NULL, 'set', $auth_id, "jabber:iq:auth", $payload); - } - - - // ==== Helper Methods =================================================================== - - function _show($show) { - // off is not valid, but is used internally - $valid_shows = array("","away","chat","dnd","xa","off"); - if (!in_array($show,$valid_shows)) $show = ""; - - return $show; - } - - function dump(&$v) { - ob_start(); - var_dump($v); - $x = ob_get_contents(); - ob_end_clean(); - return $x; - - - return print_r($v,true); - } - - - function standardize_transport($transport,$force=true) { - $transports = array("msn","aim","yim","icq","jab"); - if (!in_array($transport,$transports)) { - if ($transport=="aol") { - $transport = "aim"; - } elseif ($transport=="yahoo") { - $transport = "yim"; - } else { - if ($force) $transport = "jab"; - } - } - return $transport; - } - - function get_transport($domain) { - $transport = $this->services[$domain]["type"]; - return $this->standardize_transport($transport); - } - - - - - - // ==== Packet Handling & Connection Methods ============================================= - - // generates and transmits an IQ packet - function _send_iq($to = NULL, $type = 'get', $id = NULL, $xmlns = NULL, $payload = NULL, $from = NULL) { - if (!preg_match("/^(get|set|result|error)$/", $type)) { - unset($type); - - $this->_log("ERROR: _send_iq() #2 - type must be 'get', 'set', 'result' or 'error'"); - return false; - - } elseif ($id && $xmlns) { - $xml = "_send($xml); - } else { - $this->_log("ERROR: SendIq() #1 - to, id and xmlns are mandatory"); - return false; - } - } - - - // writes XML data to the socket; trims and UTF8 encodes $xml before - // sending unless $pristine is true - function _send($xml,$pristine = false) { - // need UTF8 encoding to prevent character coding issues when - // users enter international characters - /* - if (!$pristine) { - $xml = trim(utf8_encode($xml)); - if (!$xml) return false; - } - */ - if(strlen($xml)==0) return true; - - if ($res = $this->_connection->socket_write($xml)) { - $this->_log("SEND: $xml"); - } else { - $this->_log("ERROR SENDING: $xml"); - } - return $res; - } - - - - function _receive() { - unset($incoming); - $packet_count = 0; - - $sleepfunc = $this->_sleep_func; - - $iterations = 0; - $empties = 0; - do { - $line = $this->_connection->socket_read(16384); - if (strlen($line)==0) { - $empties++; - if ($empties>15) break; - } else { - $empties = 0; - } - - $incoming .= $line; - $iterations++; - - // the iteration limit is just a brake to prevent infinite loops if - // something goes awry in socket_read() - } while($iterations<200); - - $incoming = trim($incoming); - - if ($incoming != "") { - //$this->_log("RECV: $incoming"); - - $temp = $this->_split_incoming($incoming); - - $packet_count = count($temp); - - for ($a = 0; $a < $packet_count; $a++) { - $this->_packet_queue[] = $this->xml->xmlize($temp[$a]); - - $this->_log("RECV: ".$temp[$a]); - //.$this->_packet_queue[count($this->_packet_queue)-1]); - } - } - - return $packet_count; - } - - function _get_next_packet() { - return array_shift($this->_packet_queue); - } - - function _split_incoming($incoming) { - $temp = preg_split("/<(message|iq|presence|stream)(?=[\:\s\>])/", $incoming, -1, PREG_SPLIT_DELIM_CAPTURE); - $array = array(); - - for ($a = 1; $a < count($temp); $a = $a + 2) { - $array[] = "<" . $temp[$a] . $temp[($a + 1)]; - } - - return $array; - } - - -} - -?> \ No newline at end of file diff --git a/message/output/jabber/jabberclass/class_SHA1Library.php b/message/output/jabber/jabberclass/class_SHA1Library.php deleted file mode 100644 index 2b1e526ee9b1c..0000000000000 --- a/message/output/jabber/jabberclass/class_SHA1Library.php +++ /dev/null @@ -1,264 +0,0 @@ -binb2hex($this->core_sha1($this->str2binb($s),strlen($s) * $this->chrsz));} - function b64_sha1($s){return $this->binb2b64($this->core_sha1($this->str2binb($s),strlen($s) * $this->chrsz));} - function str_sha1($s){return $this->binb2str($this->core_sha1($this->str2binb($s),strlen($s) * $this->chrsz));} - function hex_hmac_sha1($key, $data){ return $this->binb2hex($this->core_hmac_sha1($key, $data));} - function b64_hmac_sha1($key, $data){ return $this->binb2b64($this->core_hmac_sha1($key, $data));} - function str_hmac_sha1($key, $data){ return $this->binb2str($this->core_hmac_sha1($key, $data));} - - /* - * Perform a simple self-test to see if the VM is working - */ - function sha1_vm_test() - { - return $this->hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; - } - - /* - * Calculate the SHA-1 of an array of big-endian words, and a bit $length - */ - function core_sha1($x, $len) - { - /* append padding */ - $x[$len >> 5] |= 0x80 << (24 - $len % 32); - $x[(($len + 64 >> 9) << 4) + 15] = $len; - - $w = Array(); - $a = 1732584193; - $b = -271733879; - $c = -1732584194; - $d = 271733878; - $e = -1009589776; - - for($i = 0; $i < sizeof($x); $i += 16) - { - $olda = $a; - $oldb = $b; - $oldc = $c; - $oldd = $d; - $olde = $e; - - for($j = 0; $j < 80; $j++) - { - if ($j < 16) - $w[$j] = $x[$i + $j]; - else - $w[$j] = $this->rol($w[$j-3] ^ $w[$j-8] ^ $w[$j-14] ^ $w[$j-16], 1); - - $t = $this->safe_add( $this->safe_add($this->rol($a, 5), $this->sha1_ft($j, $b, $c, $d)), - $this->safe_add($this->safe_add($e, $w[$j]), $this->sha1_kt($j))); - $e = $d; - $d = $c; - $c = $this->rol($b, 30); - $b = $a; - $a = $t; - } - - $a = $this->safe_add($a, $olda); - $b = $this->safe_add($b, $oldb); - $c = $this->safe_add($c, $oldc); - $d = $this->safe_add($d, $oldd); - $e = $this->safe_add($e, $olde); - } - - return Array($a, $b, $c, $d, $e); - } - - /* - * Joror: PHP does not have the java(script) >>> operator, so this is a - * replacement function. Credits to Terium. - */ - function zerofill_rightshift($a, $b) - { - $z = hexdec(80000000); - if ($z & $a) - { - $a >>= 1; - $a &= (~ $z); - $a |= 0x40000000; - $a >>= ($b-1); - } - else - { - $a >>= $b; - } - return $a; - } - - /* - * Perform the appropriate triplet combination function for the current - * iteration - */ - function sha1_ft($t, $b, $c, $d) - { - if($t < 20) return ($b & $c) | ((~$b) & $d); - if($t < 40) return $b ^ $c ^ $d; - if($t < 60) return ($b & $c) | ($b & $d) | ($c & $d); - return $b ^ $c ^ $d; - } - - /* - * Determine the appropriate additive constant for the current iteration - * Silly php does not understand the inline-if operator well when nested, - * so that's why it's ()ed now. - */ - function sha1_kt($t) - { - return ($t < 20) ? 1518500249 : (($t < 40) ? 1859775393 : - (($t < 60) ? -1894007588 : -899497514)); - } - - /* - * Calculate the HMAC-SHA1 of a key and some data - */ - function core_hmac_sha1($key, $data) - { - $bkey = $this->str2binb($key); - if(sizeof($bkey) > 16) $bkey = $this->core_sha1($bkey, sizeof($key) * $this->chrsz); - - $ipad = Array(); - $opad = Array(); - - for($i = 0; $i < 16; $i++) - { - $ipad[$i] = $bkey[$i] ^ 0x36363636; - $opad[$i] = $bkey[$i] ^ 0x5C5C5C5C; - } - - $hash = $this->core_sha1(array_merge($ipad,$this->str2binb($data)), 512 + sizeof($data) * $this->chrsz); - return $this->core_sha1(array_merge($opad,$hash), 512 + 160); - } - - /* - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ - function safe_add($x, $y) - { - $lsw = ($x & 0xFFFF) + ($y & 0xFFFF); - $msw = ($x >> 16) + ($y >> 16) + ($lsw >> 16); - return ($msw << 16) | ($lsw & 0xFFFF); - } - - /* - * Bitwise rotate a 32-bit number to the left. - */ - function rol($num, $cnt) - { - return ($num << $cnt) | $this->zerofill_rightshift($num, (32 - $cnt)); - } - - /* - * Convert an 8-bit or 16-bit string to an array of big-endian words - * In 8-bit function, characters >255 have their hi-byte silently ignored. - */ - function str2binb($str) - { - $bin = Array(); - $mask = (1 << $this->chrsz) - 1; - for($i = 0; $i < strlen($str) * $this->chrsz; $i += $this->chrsz) - $bin[$i >> 5] |= (ord($str{$i / $this->chrsz}) & $mask) << (24 - $i%32); - - return $bin; - } - - /* - * Convert an array of big-endian words to a string - */ - function binb2str($bin) - { - $str = ""; - $mask = (1 << $this->chrsz) - 1; - for($i = 0; $i < sizeof($bin) * 32; $i += $this->chrsz) - $str .= chr($this->zerofill_rightshift($bin[$i>>5], 24 - $i%32) & $mask); - return $str; - } - - /* - * Convert an array of big-endian words to a hex string. - */ - function binb2hex($binarray) - { - $hex_tab = $this->hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; - $str = ""; - for($i = 0; $i < sizeof($binarray) * 4; $i++) - { - $str .= $hex_tab{($binarray[$i>>2] >> ((3 - $i%4)*8+4)) & 0xF} . - $hex_tab{($binarray[$i>>2] >> ((3 - $i%4)*8 )) & 0xF}; - } - - return $str; - } - - /* - * Convert an array of big-endian words to a base-64 string - */ - function binb2b64($binarray) - { - $tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - $str = ""; - for($i = 0; i < sizeof($binarray) * 4; $i += 3) - { - $triplet = ((($binarray[$i >> 2] >> 8 * (3 - $i %4)) & 0xFF) << 16) - | ((($binarray[$i+1 >> 2] >> 8 * (3 - ($i+1)%4)) & 0xFF) << 8 ) - | (($binarray[$i+2 >> 2] >> 8 * (3 - ($i+2)%4)) & 0xFF); - for($j = 0; $j < 4; $j++) - { - if($i * 8 + $j * 6 > sizeof($binarray) * 32) $str .= $this->b64pad; - else $str .= $tab{($triplet >> 6*(3-j)) & 0x3F}; - } - } - return $str; - } -} - -if ( !function_exists('sha1') ) -{ - function sha1( $string, $raw_output = false ) - { - $library = &new SHA1Library(); - - return $raw_output ? $library->str_sha1($string) : $library->hex_sha1($string); - } -} -?> \ No newline at end of file diff --git a/message/output/jabber/jabberclass/class_XMLParser.php b/message/output/jabber/jabberclass/class_XMLParser.php deleted file mode 100644 index 335ec24a58617..0000000000000 --- a/message/output/jabber/jabberclass/class_XMLParser.php +++ /dev/null @@ -1,139 +0,0 @@ -_xml_depth($vals, $i); - - return $array; - } - - - - // _xml_depth() - // (c) Hans Anderson / http://www.hansanderson.com/php/xml/ - - function _xml_depth($vals, &$i) { - $children = array(); - - if ($vals[$i]['value']) { - array_push($children, trim($vals[$i]['value'])); - } - - while (++$i < count($vals)) { - switch ($vals[$i]['type']) { - case 'cdata': - array_push($children, trim($vals[$i]['value'])); - break; - - case 'complete': - $tagname = $vals[$i]['tag']; - $size = sizeof($children[$tagname]); - $children[$tagname][$size]['#'] = trim($vals[$i]['value']); - if ($vals[$i]['attributes']) { - $children[$tagname][$size]['@'] = $vals[$i]['attributes']; - } - break; - - case 'open': - $tagname = $vals[$i]['tag']; - $size = sizeof($children[$tagname]); - if ($vals[$i]['attributes']) { - $children[$tagname][$size]['@'] = $vals[$i]['attributes']; - $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); - } else { - $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); - } - break; - - case 'close': - return $children; - break; - } - } - - return $children; - } - - - - // TraverseXMLize() - // (c) acebone@f2s.com, a HUGE help! - - function TraverseXMLize($array, $arrName = "array", $level = 0) { - if ($level == 0) { - echo "
";
-		}
-
-		while (list($key, $val) = @each($array)) {
-			if (is_array($val)) {
-				$this->TraverseXMLize($val, $arrName . "[" . $key . "]", $level + 1);
-			} else {
-				echo '$' . $arrName . '[' . $key . '] = "' . $val . "\"\n";
-			}
-		}
-
-		if ($level == 0) {
-			echo "
"; - } - } - -} -?> \ No newline at end of file diff --git a/message/output/jabber/jabberclass/jabber_example.php b/message/output/jabber/jabberclass/jabber_example.php deleted file mode 100644 index 6528bec4c60e3..0000000000000 --- a/message/output/jabber/jabberclass/jabber_example.php +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/local/bin/php -q -jab = &$jab; - $this->first_roster_update = true; - - echo "Created!\n"; - $this->countdown = 0; - } - - // called when a connection to the Jabber server is established - function handleConnected() { - echo "Connected!\n"; - - // now that we're connected, tell the Jabber class to login - echo "Authenticating ...\n"; - $this->jab->login(JABBER_USERNAME,JABBER_PASSWORD); - } - - // called after a login to indicate the the login was successful - function handleAuthenticated() { - echo "Authenticated!\n"; - - - echo "Fetching service list and roster ...\n"; - - // browser for transport gateways - $this->jab->browse(); - - // retrieve this user's roster - $this->jab->get_roster(); - - // set this user's presence - $this->jab->set_presence("","Ya, I'm online... so what?"); - } - - // called after a login to indicate that the login was NOT successful - function handleAuthFailure($code,$error) { - echo "Authentication failure: $error ($code)\n"; - - // set terminated to TRUE in the Jabber class to tell it to exit - $this->jab->terminated = true; - } - - // called periodically by the Jabber class to allow us to do our own - // processing - function handleHeartbeat() { - echo "Heartbeat - "; - - // if the countdown is in progress, determine if we need to take any action - if ($this->countdown>0) { - $this->countdown--; - - // display our countdown progress - echo "Countdown: {$this->countdown}\n"; - - - // first, we want to fire our composing event - if ($this->countdown==7) { - echo "Composing start\n"; - $this->jab->composing($this->last_msg_from,$this->last_msg_id); - } - - // next, we want to indicate that we've stopped composing a message - if ($this->countdown==5) { - echo "Composing stop\n"; - $this->jab->composing($this->last_msg_from,$this->last_msg_id,false); - } - - // next, we indicate that we're composing again - if ($this->countdown==3) { - echo "Composing start\n"; - $this->jab->composing($this->last_msg_from,$this->last_msg_id); - } - - // and finally, we send a message to the remote user and tell the Jabber class - // to exit - if ($this->countdown==1) { - echo "Send message\n"; - $this->jab->message($this->last_msg_from,"chat",NULL,"Hello! You said: ".$this->last_message); - $this->jab->terminated = true; - } - } else { - echo "Waiting for incoming message ...\n"; - } - /* - reset($this->jab->roster); - foreach ($this->jab->roster as $jid=>$details) { - echo "$jid\t\t\t".$details["transport"]."\t".$details["show"]."\t".$details["status"]."\n"; - } - */ - } - - // called when an error is received from the Jabber server - function handleError($code,$error,$xmlns) { - echo "Error: $error ($code)".($xmlns?" in $xmlns":"")."\n"; - } - - // called when a message is received from a remote contact - function handleMessage($from,$to,$body,$subject,$thread,$id,$extended) { - echo "Incoming message!\n"; - echo "From: $from\t\tTo: $to\n"; - echo "Subject: $subject\tThread; $thread\n"; - echo "Body: $body\n"; - echo "ID: $id\n"; - var_dump($extended); - echo "\n"; - - $this->last_message = $body; - - $this->last_msg_id = $id; - $this->last_msg_from = $from; - - // for the purposes of our example, we start a countdown here to do some - // random events, just for the sake of demonstration - echo "Starting countdown\n"; - $this->countdown = 10; - } - - function _contact_info($contact) { - return sprintf("Contact %s (JID %s) has status %s and message %s\n",$contact['name'],$contact['jid'],$contact['show'],$contact['status']); - } - - function handleRosterUpdate($jid) { - if ($this->first_roster_update) { - // the first roster update indicates that the entire roster has been - // downloaded for the first time - echo "Roster downloaded:\n"; - - foreach ($this->jab->roster as $k=>$contact) { - echo $this->_contact_info($contact); - } - $this->first_roster_update = false; - } else { - // subsequent roster updates indicate changes for individual roster items - $contact = $this->jab->roster[$jid]; - echo "Contact updated: " . $this->_contact_info($contact); - } - } - - function handleDebug($msg,$level) { - echo "DBG: $msg\n"; - } - -} - -// include the Jabber class -require_once("class_Jabber.php"); - -// create an instance of the Jabber class -$display_debug_info = false; -$jab = new Jabber($display_debug_info); - -// create an instance of our event handler class -$test = new TestMessenger($jab); - -// set handlers for the events we wish to be notified about -$jab->set_handler("connected",$test,"handleConnected"); -$jab->set_handler("authenticated",$test,"handleAuthenticated"); -$jab->set_handler("authfailure",$test,"handleAuthFailure"); -$jab->set_handler("heartbeat",$test,"handleHeartbeat"); -$jab->set_handler("error",$test,"handleError"); -$jab->set_handler("message_normal",$test,"handleMessage"); -$jab->set_handler("message_chat",$test,"handleMessage"); -$jab->set_handler("debug_log",$test,"handleDebug"); -$jab->set_handler("rosterupdate",$test,"handleRosterUpdate"); - -echo "Connecting ...\n"; - -// connect to the Jabber server -if (!$jab->connect(JABBER_SERVER)) { - die("Could not connect to the Jabber server!\n"); -} - -// now, tell the Jabber class to begin its execution loop -$jab->execute(CBK_FREQ,RUN_TIME); - -// Note that we will not reach this point (and the execute() method will not -// return) until $jab->terminated is set to TRUE. The execute() method simply -// loops, processing data from (and to) the Jabber server, and firing events -// (which are handled by our TestMessenger class) until we tell it to terminate. -// -// This event-based model will be familiar to programmers who have worked on -// desktop applications, particularly in Win32 environments. - -// disconnect from the Jabber server -$jab->disconnect(); -?> \ No newline at end of file diff --git a/message/output/jabber/message_output_jabber.php b/message/output/jabber/message_output_jabber.php index 1ed8d6c36ad14..167e4a2544ac9 100644 --- a/message/output/jabber/message_output_jabber.php +++ b/message/output/jabber/message_output_jabber.php @@ -40,39 +40,7 @@ define("RUN_TIME",15); // set a maximum run time of 15 seconds require_once($CFG->dirroot.'/message/output/lib.php'); -require_once($CFG->dirroot.'/message/output/jabber/jabberclass/class_Jabber.php'); - -class JabberMessenger { - function JabberMessenger(&$jab, $message) { - $this->jab = &$jab; - $this->message = $message; - $this->first_roster_update = true; - $this->countdown = 0; - } - // called when a connection to the Jabber server is established - function handleConnected() { - $this->jab->login(JABBER_USERNAME,JABBER_PASSWORD); - } - // called after a login to indicate the the login was successful - function handleAuthenticated() { - global $DB; - $userfrom = $DB->get_record('user', array('id' => $this->message->useridfrom)); - $userto = $DB->get_record('user', array('id' => $this->message->useridto)); - - $jabberdest = get_user_preferences('message_processor_jabber_jabberid', $userto->email , $userto->id); - if (empty($jabberdest)){ - $jabberdest = $userto->email; - } - $this->jab->message($jabberdest,"chat",NULL,fullname($userfrom)." says: ".$this->message->fullmessage); - $this->jab->terminated = true; - } - // called after a login to indicate that the login was NOT successful - function handleAuthFailure($code,$error) { - // set terminated to TRUE in the Jabber class to tell it to exit - $this->jab->terminated = true; - } -} - +require_once($CFG->libdir.'/jabber/XMPP/XMPP.php'); class message_output_jabber extends message_output { @@ -82,26 +50,31 @@ class message_output_jabber extends message_output { * @return true if ok, false if error */ function send_message($message){ + global $DB; - //jabber object - $jab = new Jabber(True); - // create an instance of our event handler class - $test = new JabberMessenger($jab, $message); - - // set handlers for the events we wish to be notified about - $jab->set_handler("connected",$test,"handleConnected"); - $jab->set_handler("authenticated",$test,"handleAuthenticated"); - $jab->set_handler("authfailure",$test,"handleAuthFailure"); - - if (!$jab->connect(JABBER_SERVER)) { + if (!$userfrom = $DB->get_record('user', array('id' => $message->useridfrom))) { + return false; + } + if (!$userto = $DB->get_record('user', array('id' => $this->message->useridto))) { return false; } + if (!$jabberaddress = get_user_preferences('message_processor_jabber_jabberid', $userto->email, $userto->id)) { + $jabberaddress = $userto->email; + } + $jabbermessage = fullname($userfrom).': '.$message->fullmessage; - // now, tell the Jabber class to begin its execution loop - // don't way for events - $jab->execute(-1,RUN_TIME); - $jab->disconnect(); + $conection = new XMPPHP_XMPP(JABBER_SERVER, 5222, JABBER_USERNAME, JABBER_PASSWORD, 'moodle', JABBER_SERVER); + try { + $conn->connect(); + $conn->processUntil('session_start'); + $conn->presence(); + $conn->message($jabberaddress, $jabbermessage); + $conn->disconnect(); + } catch(XMPPHP_Exception $e) { + return false; + } + return true; } diff --git a/message/output/jabber/version.php b/message/output/jabber/version.php index 54b060e67e42d..9abc46157b839 100755 --- a/message/output/jabber/version.php +++ b/message/output/jabber/version.php @@ -32,7 +32,7 @@ * @package */ -$plugin->version = 2008072401; -$plugin->requires = 2008072401; +$plugin->version = 2008090900; +$plugin->requires = 2008091500; ?> diff --git a/version.php b/version.php index aa9ad54424802..e1f31d89542e6 100644 --- a/version.php +++ b/version.php @@ -6,7 +6,7 @@ // This is compared against the values stored in the database to determine // whether upgrades should be performed (see lib/db/*.php) - $version = 2008091000; // YYYYMMDD = date of the last version bump + $version = 2008091500; // YYYYMMDD = date of the last version bump // XX = daily increments $release = '2.0 dev (Build: 20080915)'; // Human-friendly version name