--- /dev/null
+<?php
+/**
+ * XMPPHP: The PHP XMPP Library
+ * Copyright (C) 2008 Nathanael C. Fritz
+ * This file is part of SleekXMPP.
+ *
+ * XMPPHP is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * XMPPHP 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XMPPHP; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @category xmpphp
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @copyright 2008 Nathanael C. Fritz
+ */
+
+/**
+ * XMPPHP Exception
+ *
+ * @category xmpphp
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @copyright 2008 Nathanael C. Fritz
+ * @version $Id$
+ */
+class XMPPHP_Exception extends Exception {
+}
--- /dev/null
+<?php
+/**
+ * XMPPHP: The PHP XMPP Library
+ * Copyright (C) 2008 Nathanael C. Fritz
+ * This file is part of SleekXMPP.
+ *
+ * XMPPHP is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * XMPPHP 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XMPPHP; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @category xmpphp
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @copyright 2008 Nathanael C. Fritz
+ */
+
+/**
+ * XMPPHP Log
+ *
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @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";
+ }
+}
--- /dev/null
+<?php
+/**
+ * XMPPHP: The PHP XMPP Library
+ * Copyright (C) 2008 Nathanael C. Fritz
+ * This file is part of SleekXMPP.
+ *
+ * XMPPHP is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * XMPPHP 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XMPPHP; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @category xmpphp
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @copyright 2008 Nathanael C. Fritz
+ */
+
+/**
+ * XMPPHP XML Object
+ *
+ * @category xmpphp
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @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 .= "$body</{$this->name}>";
+ 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;
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * XMPPHP: The PHP XMPP Library
+ * Copyright (C) 2008 Nathanael C. Fritz
+ * This file is part of SleekXMPP.
+ *
+ * XMPPHP is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * XMPPHP 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XMPPHP; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @category xmpphp
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @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 <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @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 = '<stream>';
+ /**
+ * @var string
+ */
+ protected $stream_end = '</stream>';
+ /**
+ * @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');
+ }
+}
--- /dev/null
+<?php
+/**
+ * XMPPHP: The PHP XMPP Library
+ * Copyright (C) 2008 Nathanael C. Fritz
+ * This file is part of SleekXMPP.
+ *
+ * XMPPHP is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * XMPPHP 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XMPPHP; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @category xmpphp
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @copyright 2008 Nathanael C. Fritz
+ */
+
+/** XMPPHP_XMLStream */
+require_once "XMLStream.php";
+
+/**
+ * XMPPHP Main Class
+ *
+ * @category xmpphp
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @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 = '<stream:stream to="' . $server . '" xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" version="1.0">';
+ $this->stream_end = '</stream:stream>';
+ $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 = "<message from='{$this->fulljid}' to='$to' type='$type'>";
+ if($subject) $out .= "<subject>$subject</subject>";
+ $out .= "<body>$body</body>";
+ if($payload) $out .= $payload;
+ $out .= "</message>";
+
+ $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 = "<presence";
+ if($to) $out .= " to='$to'";
+ if($type) $out .= " type='$type'";
+ if($show == 'available' and !$status) {
+ $out .= "/>";
+ } else {
+ $out .= ">";
+ if($show != 'available') $out .= "<show>$show</show>";
+ if($status) $out .= "<status>$status</status>";
+ $out .= "</presence>";
+ }
+
+ $this->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("<presence type='subscribed' to='{$xml->attrs['from']}' from='{$this->fulljid}' /><presence type='subscribe' to='{$xml->attrs['from']}' from='{$this->fulljid}' />");
+ $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("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'><required /></starttls>");
+ } elseif($xml->hasSub('bind')) {
+ $id = $this->getId();
+ $this->addIdHandler($id, 'resource_bind_handler');
+ $this->send("<iq xmlns=\"jabber:client\" type=\"set\" id=\"$id\"><bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"><resource>{$this->resource}</resource></bind></iq>");
+ } else {
+ $this->log->log("Attempting Auth...");
+ $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>" . base64_encode("\x00" . $this->user . "\x00" . $this->password) . "</auth>");
+ }
+ }
+
+ /**
+ * 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("<iq xmlns='jabber:client' type='set' id='$id'><session xmlns='urn:ietf:params:xml:ns:xmpp-session' /></iq>");
+ }
+
+ /**
+ * Retrieves the roster
+ *
+ */
+ public function getRoster() {
+ $id = $this->getID();
+ $this->addIdHandler($id, 'roster_get_handler');
+ $this->send("<iq xmlns='jabber:client' type='get' id='$id'><query xmlns='jabber:iq:roster' /></iq>");
+ }
+
+ /**
+ * 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();
+ }
+}
--- /dev/null
+<?php
+/**
+ * XMPPHP: The PHP XMPP Library
+ * Copyright (C) 2008 Nathanael C. Fritz
+ * This file is part of SleekXMPP.
+ *
+ * XMPPHP is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * XMPPHP 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XMPPHP; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * @category xmpphp
+ * @package XMPPHP
+ * @author Nathanael C. Fritz <JID: fritzy@netflint.net>
+ * @author Stephan Wentz <JID: stephan@jabber.wentz.it>
+ * @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("<iq type='get' id='$id'><query xmlns='jabber:iq:auth'><username>{$this->user}</username></query></iq>");
+ }
+
+ /**
+ * 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 = "<iq type='set' id='$id'><query xmlns='jabber:iq:auth'><username>{$this->user}</username><digest>{$hash}</digest><resource>{$this->resource}</resource></query></iq>";
+ } else {
+ $out = "<iq type='set' id='$id'><query xmlns='jabber:iq:auth'><username>{$this->user}</username><digest>{$this->password}</digest><resource>{$this->resource}</resource></query></iq>";
+ }
+ $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');
+ }
+ }
+ }
+
+
+?>
foreach (array('loggedin', 'loggedoff') as $state){
$state_res = get_string($state, 'message');
echo '<tr><td align="right">'.$state_res.'</td>'."\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 '<td align="center"><input type="checkbox" name="'.$provider->component.'_'.$provider->name.'_'.$state.'['.$processor->name.']" '.$checked.' /></td>'."\n";
}
echo '</tr>'."\n";
+++ /dev/null
- GNU LESSER GENERAL PUBLIC LICENSE\r
- Version 2.1, February 1999\r
-\r
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.\r
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
- Everyone is permitted to copy and distribute verbatim copies\r
- of this license document, but changing it is not allowed.\r
-\r
-[This is the first released version of the Lesser GPL. It also counts\r
- as the successor of the GNU Library Public License, version 2, hence\r
- the version number 2.1.]\r
-\r
- Preamble\r
-\r
- The licenses for most software are designed to take away your\r
-freedom to share and change it. By contrast, the GNU General Public\r
-Licenses are intended to guarantee your freedom to share and change\r
-free software--to make sure the software is free for all its users.\r
-\r
- This license, the Lesser General Public License, applies to some\r
-specially designated software packages--typically libraries--of the\r
-Free Software Foundation and other authors who decide to use it. You\r
-can use it too, but we suggest you first think carefully about whether\r
-this license or the ordinary General Public License is the better\r
-strategy to use in any particular case, based on the explanations below.\r
-\r
- When we speak of free software, we are referring to freedom of use,\r
-not price. Our General Public Licenses are designed to make sure that\r
-you have the freedom to distribute copies of free software (and charge\r
-for this service if you wish); that you receive source code or can get\r
-it if you want it; that you can change the software and use pieces of\r
-it in new free programs; and that you are informed that you can do\r
-these things.\r
-\r
- To protect your rights, we need to make restrictions that forbid\r
-distributors to deny you these rights or to ask you to surrender these\r
-rights. These restrictions translate to certain responsibilities for\r
-you if you distribute copies of the library or if you modify it.\r
-\r
- For example, if you distribute copies of the library, whether gratis\r
-or for a fee, you must give the recipients all the rights that we gave\r
-you. You must make sure that they, too, receive or can get the source\r
-code. If you link other code with the library, you must provide\r
-complete object files to the recipients, so that they can relink them\r
-with the library after making changes to the library and recompiling\r
-it. And you must show them these terms so they know their rights.\r
-\r
- We protect your rights with a two-step method: (1) we copyright the\r
-library, and (2) we offer you this license, which gives you legal\r
-permission to copy, distribute and/or modify the library.\r
-\r
- To protect each distributor, we want to make it very clear that\r
-there is no warranty for the free library. Also, if the library is\r
-modified by someone else and passed on, the recipients should know\r
-that what they have is not the original version, so that the original\r
-author's reputation will not be affected by problems that might be\r
-introduced by others.\r
-\f\r
- Finally, software patents pose a constant threat to the existence of\r
-any free program. We wish to make sure that a company cannot\r
-effectively restrict the users of a free program by obtaining a\r
-restrictive license from a patent holder. Therefore, we insist that\r
-any patent license obtained for a version of the library must be\r
-consistent with the full freedom of use specified in this license.\r
-\r
- Most GNU software, including some libraries, is covered by the\r
-ordinary GNU General Public License. This license, the GNU Lesser\r
-General Public License, applies to certain designated libraries, and\r
-is quite different from the ordinary General Public License. We use\r
-this license for certain libraries in order to permit linking those\r
-libraries into non-free programs.\r
-\r
- When a program is linked with a library, whether statically or using\r
-a shared library, the combination of the two is legally speaking a\r
-combined work, a derivative of the original library. The ordinary\r
-General Public License therefore permits such linking only if the\r
-entire combination fits its criteria of freedom. The Lesser General\r
-Public License permits more lax criteria for linking other code with\r
-the library.\r
-\r
- We call this license the "Lesser" General Public License because it\r
-does Less to protect the user's freedom than the ordinary General\r
-Public License. It also provides other free software developers Less\r
-of an advantage over competing non-free programs. These disadvantages\r
-are the reason we use the ordinary General Public License for many\r
-libraries. However, the Lesser license provides advantages in certain\r
-special circumstances.\r
-\r
- For example, on rare occasions, there may be a special need to\r
-encourage the widest possible use of a certain library, so that it becomes\r
-a de-facto standard. To achieve this, non-free programs must be\r
-allowed to use the library. A more frequent case is that a free\r
-library does the same job as widely used non-free libraries. In this\r
-case, there is little to gain by limiting the free library to free\r
-software only, so we use the Lesser General Public License.\r
-\r
- In other cases, permission to use a particular library in non-free\r
-programs enables a greater number of people to use a large body of\r
-free software. For example, permission to use the GNU C Library in\r
-non-free programs enables many more people to use the whole GNU\r
-operating system, as well as its variant, the GNU/Linux operating\r
-system.\r
-\r
- Although the Lesser General Public License is Less protective of the\r
-users' freedom, it does ensure that the user of a program that is\r
-linked with the Library has the freedom and the wherewithal to run\r
-that program using a modified version of the Library.\r
-\r
- The precise terms and conditions for copying, distribution and\r
-modification follow. Pay close attention to the difference between a\r
-"work based on the library" and a "work that uses the library". The\r
-former contains code derived from the library, whereas the latter must\r
-be combined with the library in order to run.\r
-\f\r
- GNU LESSER GENERAL PUBLIC LICENSE\r
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r
-\r
- 0. This License Agreement applies to any software library or other\r
-program which contains a notice placed by the copyright holder or\r
-other authorized party saying it may be distributed under the terms of\r
-this Lesser General Public License (also called "this License").\r
-Each licensee is addressed as "you".\r
-\r
- A "library" means a collection of software functions and/or data\r
-prepared so as to be conveniently linked with application programs\r
-(which use some of those functions and data) to form executables.\r
-\r
- The "Library", below, refers to any such software library or work\r
-which has been distributed under these terms. A "work based on the\r
-Library" means either the Library or any derivative work under\r
-copyright law: that is to say, a work containing the Library or a\r
-portion of it, either verbatim or with modifications and/or translated\r
-straightforwardly into another language. (Hereinafter, translation is\r
-included without limitation in the term "modification".)\r
-\r
- "Source code" for a work means the preferred form of the work for\r
-making modifications to it. For a library, complete source code means\r
-all the source code for all modules it contains, plus any associated\r
-interface definition files, plus the scripts used to control compilation\r
-and installation of the library.\r
-\r
- Activities other than copying, distribution and modification are not\r
-covered by this License; they are outside its scope. The act of\r
-running a program using the Library is not restricted, and output from\r
-such a program is covered only if its contents constitute a work based\r
-on the Library (independent of the use of the Library in a tool for\r
-writing it). Whether that is true depends on what the Library does\r
-and what the program that uses the Library does.\r
- \r
- 1. You may copy and distribute verbatim copies of the Library's\r
-complete source code as you receive it, in any medium, provided that\r
-you conspicuously and appropriately publish on each copy an\r
-appropriate copyright notice and disclaimer of warranty; keep intact\r
-all the notices that refer to this License and to the absence of any\r
-warranty; and distribute a copy of this License along with the\r
-Library.\r
-\r
- You may charge a fee for the physical act of transferring a copy,\r
-and you may at your option offer warranty protection in exchange for a\r
-fee.\r
-\f\r
- 2. You may modify your copy or copies of the Library or any portion\r
-of it, thus forming a work based on the Library, and copy and\r
-distribute such modifications or work under the terms of Section 1\r
-above, provided that you also meet all of these conditions:\r
-\r
- a) The modified work must itself be a software library.\r
-\r
- b) You must cause the files modified to carry prominent notices\r
- stating that you changed the files and the date of any change.\r
-\r
- c) You must cause the whole of the work to be licensed at no\r
- charge to all third parties under the terms of this License.\r
-\r
- d) If a facility in the modified Library refers to a function or a\r
- table of data to be supplied by an application program that uses\r
- the facility, other than as an argument passed when the facility\r
- is invoked, then you must make a good faith effort to ensure that,\r
- in the event an application does not supply such function or\r
- table, the facility still operates, and performs whatever part of\r
- its purpose remains meaningful.\r
-\r
- (For example, a function in a library to compute square roots has\r
- a purpose that is entirely well-defined independent of the\r
- application. Therefore, Subsection 2d requires that any\r
- application-supplied function or table used by this function must\r
- be optional: if the application does not supply it, the square\r
- root function must still compute square roots.)\r
-\r
-These requirements apply to the modified work as a whole. If\r
-identifiable sections of that work are not derived from the Library,\r
-and can be reasonably considered independent and separate works in\r
-themselves, then this License, and its terms, do not apply to those\r
-sections when you distribute them as separate works. But when you\r
-distribute the same sections as part of a whole which is a work based\r
-on the Library, the distribution of the whole must be on the terms of\r
-this License, whose permissions for other licensees extend to the\r
-entire whole, and thus to each and every part regardless of who wrote\r
-it.\r
-\r
-Thus, it is not the intent of this section to claim rights or contest\r
-your rights to work written entirely by you; rather, the intent is to\r
-exercise the right to control the distribution of derivative or\r
-collective works based on the Library.\r
-\r
-In addition, mere aggregation of another work not based on the Library\r
-with the Library (or with a work based on the Library) on a volume of\r
-a storage or distribution medium does not bring the other work under\r
-the scope of this License.\r
-\r
- 3. You may opt to apply the terms of the ordinary GNU General Public\r
-License instead of this License to a given copy of the Library. To do\r
-this, you must alter all the notices that refer to this License, so\r
-that they refer to the ordinary GNU General Public License, version 2,\r
-instead of to this License. (If a newer version than version 2 of the\r
-ordinary GNU General Public License has appeared, then you can specify\r
-that version instead if you wish.) Do not make any other change in\r
-these notices.\r
-\f\r
- Once this change is made in a given copy, it is irreversible for\r
-that copy, so the ordinary GNU General Public License applies to all\r
-subsequent copies and derivative works made from that copy.\r
-\r
- This option is useful when you wish to copy part of the code of\r
-the Library into a program that is not a library.\r
-\r
- 4. You may copy and distribute the Library (or a portion or\r
-derivative of it, under Section 2) in object code or executable form\r
-under the terms of Sections 1 and 2 above provided that you accompany\r
-it with the complete corresponding machine-readable source code, which\r
-must be distributed under the terms of Sections 1 and 2 above on a\r
-medium customarily used for software interchange.\r
-\r
- If distribution of object code is made by offering access to copy\r
-from a designated place, then offering equivalent access to copy the\r
-source code from the same place satisfies the requirement to\r
-distribute the source code, even though third parties are not\r
-compelled to copy the source along with the object code.\r
-\r
- 5. A program that contains no derivative of any portion of the\r
-Library, but is designed to work with the Library by being compiled or\r
-linked with it, is called a "work that uses the Library". Such a\r
-work, in isolation, is not a derivative work of the Library, and\r
-therefore falls outside the scope of this License.\r
-\r
- However, linking a "work that uses the Library" with the Library\r
-creates an executable that is a derivative of the Library (because it\r
-contains portions of the Library), rather than a "work that uses the\r
-library". The executable is therefore covered by this License.\r
-Section 6 states terms for distribution of such executables.\r
-\r
- When a "work that uses the Library" uses material from a header file\r
-that is part of the Library, the object code for the work may be a\r
-derivative work of the Library even though the source code is not.\r
-Whether this is true is especially significant if the work can be\r
-linked without the Library, or if the work is itself a library. The\r
-threshold for this to be true is not precisely defined by law.\r
-\r
- If such an object file uses only numerical parameters, data\r
-structure layouts and accessors, and small macros and small inline\r
-functions (ten lines or less in length), then the use of the object\r
-file is unrestricted, regardless of whether it is legally a derivative\r
-work. (Executables containing this object code plus portions of the\r
-Library will still fall under Section 6.)\r
-\r
- Otherwise, if the work is a derivative of the Library, you may\r
-distribute the object code for the work under the terms of Section 6.\r
-Any executables containing that work also fall under Section 6,\r
-whether or not they are linked directly with the Library itself.\r
-\f\r
- 6. As an exception to the Sections above, you may also combine or\r
-link a "work that uses the Library" with the Library to produce a\r
-work containing portions of the Library, and distribute that work\r
-under terms of your choice, provided that the terms permit\r
-modification of the work for the customer's own use and reverse\r
-engineering for debugging such modifications.\r
-\r
- You must give prominent notice with each copy of the work that the\r
-Library is used in it and that the Library and its use are covered by\r
-this License. You must supply a copy of this License. If the work\r
-during execution displays copyright notices, you must include the\r
-copyright notice for the Library among them, as well as a reference\r
-directing the user to the copy of this License. Also, you must do one\r
-of these things:\r
-\r
- a) Accompany the work with the complete corresponding\r
- machine-readable source code for the Library including whatever\r
- changes were used in the work (which must be distributed under\r
- Sections 1 and 2 above); and, if the work is an executable linked\r
- with the Library, with the complete machine-readable "work that\r
- uses the Library", as object code and/or source code, so that the\r
- user can modify the Library and then relink to produce a modified\r
- executable containing the modified Library. (It is understood\r
- that the user who changes the contents of definitions files in the\r
- Library will not necessarily be able to recompile the application\r
- to use the modified definitions.)\r
-\r
- b) Use a suitable shared library mechanism for linking with the\r
- Library. A suitable mechanism is one that (1) uses at run time a\r
- copy of the library already present on the user's computer system,\r
- rather than copying library functions into the executable, and (2)\r
- will operate properly with a modified version of the library, if\r
- the user installs one, as long as the modified version is\r
- interface-compatible with the version that the work was made with.\r
-\r
- c) Accompany the work with a written offer, valid for at\r
- least three years, to give the same user the materials\r
- specified in Subsection 6a, above, for a charge no more\r
- than the cost of performing this distribution.\r
-\r
- d) If distribution of the work is made by offering access to copy\r
- from a designated place, offer equivalent access to copy the above\r
- specified materials from the same place.\r
-\r
- e) Verify that the user has already received a copy of these\r
- materials or that you have already sent this user a copy.\r
-\r
- For an executable, the required form of the "work that uses the\r
-Library" must include any data and utility programs needed for\r
-reproducing the executable from it. However, as a special exception,\r
-the materials to be distributed need not include anything that is\r
-normally distributed (in either source or binary form) with the major\r
-components (compiler, kernel, and so on) of the operating system on\r
-which the executable runs, unless that component itself accompanies\r
-the executable.\r
-\r
- It may happen that this requirement contradicts the license\r
-restrictions of other proprietary libraries that do not normally\r
-accompany the operating system. Such a contradiction means you cannot\r
-use both them and the Library together in an executable that you\r
-distribute.\r
-\f\r
- 7. You may place library facilities that are a work based on the\r
-Library side-by-side in a single library together with other library\r
-facilities not covered by this License, and distribute such a combined\r
-library, provided that the separate distribution of the work based on\r
-the Library and of the other library facilities is otherwise\r
-permitted, and provided that you do these two things:\r
-\r
- a) Accompany the combined library with a copy of the same work\r
- based on the Library, uncombined with any other library\r
- facilities. This must be distributed under the terms of the\r
- Sections above.\r
-\r
- b) Give prominent notice with the combined library of the fact\r
- that part of it is a work based on the Library, and explaining\r
- where to find the accompanying uncombined form of the same work.\r
-\r
- 8. You may not copy, modify, sublicense, link with, or distribute\r
-the Library except as expressly provided under this License. Any\r
-attempt otherwise to copy, modify, sublicense, link with, or\r
-distribute the Library is void, and will automatically terminate your\r
-rights under this License. However, parties who have received copies,\r
-or rights, from you under this License will not have their licenses\r
-terminated so long as such parties remain in full compliance.\r
-\r
- 9. You are not required to accept this License, since you have not\r
-signed it. However, nothing else grants you permission to modify or\r
-distribute the Library or its derivative works. These actions are\r
-prohibited by law if you do not accept this License. Therefore, by\r
-modifying or distributing the Library (or any work based on the\r
-Library), you indicate your acceptance of this License to do so, and\r
-all its terms and conditions for copying, distributing or modifying\r
-the Library or works based on it.\r
-\r
- 10. Each time you redistribute the Library (or any work based on the\r
-Library), the recipient automatically receives a license from the\r
-original licensor to copy, distribute, link with or modify the Library\r
-subject to these terms and conditions. You may not impose any further\r
-restrictions on the recipients' exercise of the rights granted herein.\r
-You are not responsible for enforcing compliance by third parties with\r
-this License.\r
-\f\r
- 11. If, as a consequence of a court judgment or allegation of patent\r
-infringement or for any other reason (not limited to patent issues),\r
-conditions are imposed on you (whether by court order, agreement or\r
-otherwise) that contradict the conditions of this License, they do not\r
-excuse you from the conditions of this License. If you cannot\r
-distribute so as to satisfy simultaneously your obligations under this\r
-License and any other pertinent obligations, then as a consequence you\r
-may not distribute the Library at all. For example, if a patent\r
-license would not permit royalty-free redistribution of the Library by\r
-all those who receive copies directly or indirectly through you, then\r
-the only way you could satisfy both it and this License would be to\r
-refrain entirely from distribution of the Library.\r
-\r
-If any portion of this section is held invalid or unenforceable under any\r
-particular circumstance, the balance of the section is intended to apply,\r
-and the section as a whole is intended to apply in other circumstances.\r
-\r
-It is not the purpose of this section to induce you to infringe any\r
-patents or other property right claims or to contest validity of any\r
-such claims; this section has the sole purpose of protecting the\r
-integrity of the free software distribution system which is\r
-implemented by public license practices. Many people have made\r
-generous contributions to the wide range of software distributed\r
-through that system in reliance on consistent application of that\r
-system; it is up to the author/donor to decide if he or she is willing\r
-to distribute software through any other system and a licensee cannot\r
-impose that choice.\r
-\r
-This section is intended to make thoroughly clear what is believed to\r
-be a consequence of the rest of this License.\r
-\r
- 12. If the distribution and/or use of the Library is restricted in\r
-certain countries either by patents or by copyrighted interfaces, the\r
-original copyright holder who places the Library under this License may add\r
-an explicit geographical distribution limitation excluding those countries,\r
-so that distribution is permitted only in or among countries not thus\r
-excluded. In such case, this License incorporates the limitation as if\r
-written in the body of this License.\r
-\r
- 13. The Free Software Foundation may publish revised and/or new\r
-versions of the Lesser General Public License from time to time.\r
-Such new versions will be similar in spirit to the present version,\r
-but may differ in detail to address new problems or concerns.\r
-\r
-Each version is given a distinguishing version number. If the Library\r
-specifies a version number of this License which applies to it and\r
-"any later version", you have the option of following the terms and\r
-conditions either of that version or of any later version published by\r
-the Free Software Foundation. If the Library does not specify a\r
-license version number, you may choose any version ever published by\r
-the Free Software Foundation.\r
-\f\r
- 14. If you wish to incorporate parts of the Library into other free\r
-programs whose distribution conditions are incompatible with these,\r
-write to the author to ask for permission. For software which is\r
-copyrighted by the Free Software Foundation, write to the Free\r
-Software Foundation; we sometimes make exceptions for this. Our\r
-decision will be guided by the two goals of preserving the free status\r
-of all derivatives of our free software and of promoting the sharing\r
-and reuse of software generally.\r
-\r
- NO WARRANTY\r
-\r
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\r
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\r
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\r
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY\r
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\r
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\r
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\r
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r
-\r
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\r
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\r
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\r
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\r
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\r
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\r
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\r
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\r
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\r
-DAMAGES.\r
-\r
- END OF TERMS AND CONDITIONS\r
-\f\r
- How to Apply These Terms to Your New Libraries\r
-\r
- If you develop a new library, and you want it to be of the greatest\r
-possible use to the public, we recommend making it free software that\r
-everyone can redistribute and change. You can do so by permitting\r
-redistribution under these terms (or, alternatively, under the terms of the\r
-ordinary General Public License).\r
-\r
- To apply these terms, attach the following notices to the library. It is\r
-safest to attach them to the start of each source file to most effectively\r
-convey the exclusion of warranty; and each file should have at least the\r
-"copyright" line and a pointer to where the full notice is found.\r
-\r
- <one line to give the library's name and a brief idea of what it does.>\r
- Copyright (C) <year> <name of author>\r
-\r
- This library is free software; you can redistribute it and/or\r
- modify it under the terms of the GNU Lesser General Public\r
- License as published by the Free Software Foundation; either\r
- version 2.1 of the License, or (at your option) any later version.\r
-\r
- This library is distributed in the hope that it will be useful,\r
- but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- Lesser General Public License for more details.\r
-\r
- You should have received a copy of the GNU Lesser General Public\r
- License along with this library; if not, write to the Free Software\r
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-\r
-Also add information on how to contact you by electronic and paper mail.\r
-\r
-You should also get your employer (if you work as a programmer) or your\r
-school, if any, to sign a "copyright disclaimer" for the library, if\r
-necessary. Here is a sample; alter the names:\r
-\r
- Yoyodyne, Inc., hereby disclaims all copyright interest in the\r
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.\r
-\r
- <signature of Ty Coon>, 1 April 1990\r
- Ty Coon, President of Vice\r
-\r
-That's all there is to it!\r
-\r
-\r
+++ /dev/null
-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.
-
+++ /dev/null
-<?php
-/*
- * 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
- *
- * Connection handling class used by class_Jabber.php. Used as a generic
- * socket interface to connect to 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 and Centova Technologies Inc. All such modified code is Copyright 2003-2006,
- * 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_ConnectionSocket.php - Connection Socket Library
- * Part of class_Jabber.php - Jabber Client Library
- * Copyright (C) 2003-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
- *
- */
-class ConnectionSocket {
- var $socket = null;
-
- function socket_open($hostname,$port,$timeout) {
- if ($this->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
+++ /dev/null
-<?php
-/* 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.
- *
- *
- * HISTORY
- *
- * v0.9rc1 (Unreleased)
- * - Fixed problem with _split_incoming() method that would incorrectly
- * parse packets starting with reserved element names
- * - Added support for obtaining nicknames from vCard updates
- * - Added default value to constructor's debug argument
- * - Various minor code cleanups and typo fixes
- * - Added support for PHP 5
- *
- * v0.8 - Internal release
- * v0.7 - Internal release
- * v0.6 - Internal release
- * v0.5 - Initial port from class.jabber.php
- *
- *
- * 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.
- *
- */
-
-/*
-
-The following events are available to be handled by user applications
-(use ::set_handler($handler_name...) to assign a handler method to an event).
-
-$this->_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 <stream:stream> 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 <stream> 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("<?xml version='1.0' encoding='UTF-8' ?" . ">\n");
-
- $xmpp_version = ($this->protocol_version) ? " version='{$this->protocol_version}'" : '';
-
- $this->_send("<stream:stream to='{$this->_server_host}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'{$xmpp_version}>\n");
- return true;
- } else {
- $this->error = $this->_connection->error;
- return false;
- }
- }
-
- // disconnect from the server
- function disconnect() {
-
- $this->_send("</stream:stream>");
-
- $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 = "<username>{$this->_username}</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 = "<presence";
- $xml .= ($to) ? " to='$to'" : '';
- $xml .= ($type) ? " type='$type'" : '';
- $xml .= ($status || $show || $priority) ? ">\n" : " />\n";
-
- $xml .= ($status) ? " <status>$status</status>\n" : '';
- $xml .= ($show) ? " <show>$show</show>\n" : '';
- $xml .= ($priority) ? " <priority>$priority</priority>\n" : '';
-
- $xml .= ($status || $show || $priority) ? "</presence>\n" : '';
-
- 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 = "<x xmlns='jabber:x:event'><composing/>".($start?"<id>$id</id>":"")."</x>";
- 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 = "<message to='$to' type='$type' id='$id'>\n";
-
- if ($subject) $xml .= "<subject>$subject</subject>\n";
- if ($thread) $xml .= "<thread>$thread</thread>\n";
- if ($body) $xml .= "<body>$body</body>\n";
-
- if ($body || $subject) {
- $jabber_x_event = "";
- if ($this->use_msg_composing) $jabber_x_event .= "<composing/>";
- if ($this->use_msg_delivered) $jabber_x_event .= "<delivered/>";
- if ($this->use_msg_displayed) $jabber_x_event .= "<displayed/>";
- if ($this->use_msg_offline) $jabber_x_event .= "<offline/>";
- if ($jabber_x_event) $xml .= "<x xmlns='jabber:x:event'>$jabber_x_event</x>";
- }
-
- $xml .= $payload;
- $xml .= "</message>\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 = "<remove/>";
- 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 = "<username>{$this->_username}</username><password>$newpassword</password>";
- 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) ? "<key>$reg_key</key>\n" : '';
- foreach ($fields as $element => $value) {
- $payload .= "<$element>".$this->xmlentities($value)."</$element>\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 = "<remove/>";
- 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 = "<item jid='$jid'";
- $payload .= ($name) ? " name='" . $this->xmlentities($name) . "'" : '';
- $payload .= (($group) ? "><group>". $this->xmlentities($group). "</group>\n</item": "/") . ">\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 = "<item jid='$jid' subscription='remove'/>";
-
- 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 = "<item jid='$jid'";
- $payload .= ($name) ? " name='" . $this->xmlentities($name) . "'" : '';
- $payload .= (($group) ? "><group>". $this->xmlentities($group) . "</group>\n</item": "/") . ">\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</$key>";
- }
- $payload .= "</$rootelement>";
-
- 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_freq<MIN_CALLBACK_FREQ) $this->active_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 <iq type="set"> 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 = "<name>{$this->_iq_version_name}</name><version>{$this->_iq_version_version}</version>";
- if ($this->_iq_version_os) $payload .= "<os>{$this->_iq_version_os}</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>{$utc}</utc><tz>{$tz}</tz><display>{$display}</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 "<pre>"; echo "itemlist:\n"; var_dump($itemlist); echo "</pre>";
-
- for ($a = 0; $a < $number_of_contacts; $a++)
- {
- if (!isset($itemlist[$a])) continue;
-
- $queryitem = &$itemlist[$a];
- //echo "<pre>"; echo "itemlist:\n"; var_dump($queryitem); echo "</pre>";
- $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 = "<username>{$this->_username}</username>
- <password>{$this->_password}</password>
- <email>{$this->_reg_email}</email>
- <name>{$this->_reg_name}</name>\n";
-
- $payload .= ($key) ? "<key>$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 = "<item jid='{$from}' subscription='remove'/>";
-
- $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 = "<username>{$this->_username}</username>
- <resource>{$this->_resource}</resource>
- <digest>" . sha1($this->_stream_id . $this->_password) . "</digest>";
-
- $this->_send_iq(NULL, 'set', $auth_id, "jabber:iq:auth", $payload);
- }
-
- function _sendauth_plaintext($auth_id) {
- $this->_log("Using plaintext authentication");
-
- $payload = "<username>{$this->_username}</username>
- <password>{$this->_password}</password>
- <resource>{$this->_resource}</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 = "<iq type='$type' id='$id'";
- $xml .= ($to) ? " to='$to'" : '';
- $xml .= ($from) ? " from='$from'" : '';
- $xml .= ">
- <query xmlns='$xmlns'>
- $payload
- </query>
-</iq>";
-
- return $this->_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
+++ /dev/null
-<?
-/*
- * This file was contributed (in part or whole) by a third party, and is
- * released under a BSD-compatible free software license. Please see the
- * CREDITS and LICENSE sections below for details.
- *
- *****************************************************************************
- *
- * DETAILS
- *
- * A PHP implementation of the Secure Hash Algorithm, SHA-1, as defined in
- * FIPS PUB 180-1. This is used by Centova only when using PHP
- * versions older than 4.3.0 (which did not support the sha1() function) and
- * the server does not have the mhash extension installed.
- *
- *
- * CREDITS/LICENSE
- *
- * Adjusted from the Javascript implementation by Joror (daan@parse.nl).
- *
- * Javascript Version 2.1 Copyright Paul Johnston 2000 - 2002.
- * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
- * Distributed under the BSD License
- * See http://pajhome.org.uk/crypt/md5 for details.
- *
- */
-
-class SHA1Library
-{
- /*
- * Configurable variables. You may need to tweak these to be compatible with
- * the server-side, but the defaults work in most cases.
- */
- var $hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
- var $b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
- var $chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
-
- /*
- * These are the functions you'll usually want to call
- * They take string arguments and return either hex or base-64 encoded strings
- */
- function hex_sha1($s){return $this->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
+++ /dev/null
-<?php
-/*
- * This file was contributed (in part or whole) by a third party, and is
- * released under a BSD-compatible free software license. Please see the
- * CREDITS and LICENSE sections below for details.
- *
- *****************************************************************************
- *
- * DETAILS
- *
- * Provides the XML parser used by class_Jabber.php to parse Jabber XML data
- * received from the Jabber server.
- *
- *
- * CREDITS
- *
- * Originally by Hans Anderson (http://www.hansanderson.com/php/xml)
- * Adapted for class.jabber.php by Carlo Zottman (http://phpjabber.g-blog.net)
- * Adapted for class_Jabber.php by Steve Blinch (http://www.centova.com)
- *
- *
- * LICENSE
- *
- * xmlize() is by Hans Anderson, www.hansanderson.com/contact/
- *
- * Ye Ole "Feel Free To Use it However" License [PHP, BSD, GPL].
- * some code in xml_depth is based on code written by other PHPers
- * as well as one Perl script. Poor programming practice and organization
- * on my part is to blame for the credit these people aren't receiving.
- * None of the code was copyrighted, though.
- *
- *
- * REFERENCE
- *
- * @ = attributes
- * # = nested tags
- *
-*/
-
-class XMLParser {
-
- function XMLParser() {
- }
-
- // xmlize()
- // (c) Hans Anderson / http://www.hansanderson.com/php/xml/
-
- function xmlize($data) {
- $vals = $index = $array = array();
- $parser = xml_parser_create();
- xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
-
- // XML_OPTION_SKIP_WHITE is disabled as it clobbers valid
- // newlines in instant messages
- xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
- xml_parse_into_struct($parser, $data, $vals, $index);
- xml_parser_free($parser);
-
- $i = 0;
-
- $tagname = $vals[$i]['tag'];
- $array[$tagname]['@'] = $vals[$i]['attributes'];
- $array[$tagname]['#'] = $this->_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 "<pre>";
- }
-
- 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 "</pre>";
- }
- }
-
-}
-?>
\ No newline at end of file
+++ /dev/null
-#!/usr/local/bin/php -q
-<?php
-/* Jabber Class Example
- * Copyright 2002-2007, Steve Blinch
- * http://code.blitzaffe.com
- * ============================================================================
- *
- * DETAILS
- *
- * Provides a very basic example of how to use class_Jabber.php.
- *
- * This example connects to a Jabber server, logs in, fetches (and displays)
- * the roster, and then waits until a message is received from another contact.
- *
- * It then starts a countdown which, in sequence:
- *
- * 1) sends a "composing" event to the other contact (eg: "so-and-so is typing a message"),
- * 2) sends a "composing stopped" event,
- * 3) sends another "composing" event",
- * 4) sends a message to the other contact,
- * 5) logs out
- *
- */
-
-// set your Jabber server hostname, username, and password here
-define("JABBER_SERVER","jabber.blitzaffe.com");
-define("JABBER_USERNAME","helium");
-define("JABBER_PASSWORD","zv4.5k1p8");
-
-define("RUN_TIME",30); // set a maximum run time of 30 seconds
-define("CBK_FREQ",1); // fire a callback event every second
-
-
-// This class handles all events fired by the Jabber client class; you
-// can optionally use individual functions instead of a class, but this
-// method is a bit cleaner.
-class TestMessenger {
-
- function TestMessenger(&$jab) {
- $this->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
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 {
* @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;
}
* @package
*/
-$plugin->version = 2008072401;
-$plugin->requires = 2008072401;
+$plugin->version = 2008090900;
+$plugin->requires = 2008091500;
?>
// 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