diff --git a/lib/jabber/XMPP/BOSH.php b/lib/jabber/XMPP/BOSH.php index befaf60a771..51b707715b4 100644 --- a/lib/jabber/XMPP/BOSH.php +++ b/lib/jabber/XMPP/BOSH.php @@ -1,188 +1,197 @@ - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - */ -/** XMPPHP_XMLStream */ -require_once dirname(__FILE__) . "/XMPP.php"; +namespace BirknerAlex\XMPPHP; + + /** + * 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 + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @copyright 2008 Nathanael C. Fritz + */ /** * XMPPHP Main Class - * - * @category xmpphp - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin + * + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin * @copyright 2008 Nathanael C. Fritz - * @version $Id$ + * @version $Id$ */ -class XMPPHP_BOSH extends XMPPHP_XMPP { +class BOSH extends XMPP +{ + protected $rid; + protected $sid; + protected $http_server; + protected $http_buffer = Array(); + protected $session = false; - protected $rid; - protected $sid; - protected $http_server; - protected $http_buffer = Array(); - protected $session = false; + public function connect($server, $wait = '1', $session = false) + { + $this->http_server = $server; + $this->use_encryption = false; + $this->session = $session; - public function connect($server, $wait='1', $session=false) { - $this->http_server = $server; - $this->use_encryption = false; - $this->session = $session; + $this->rid = 3001; + $this->sid = null; + if ($session) { + $this->loadSession(); + } + if (!$this->sid) { + $body = $this->__buildBody(); + $body->addAttribute('hold', '1'); + $body->addAttribute('to', $this->host); + $body->addAttribute('route', "xmpp:{$this->host}:{$this->port}"); + $body->addAttribute('secure', 'true'); + $body->addAttribute('xmpp:version', '1.6', 'urn:xmpp:xbosh'); + $body->addAttribute('wait', strval($wait)); + $body->addAttribute('ack', '1'); + $body->addAttribute('xmlns:xmpp', 'urn:xmpp:xbosh'); + $buff = ""; + xml_parse($this->parser, $buff, false); + $response = $this->__sendBody($body); + $rxml = new \SimpleXMLElement($response); + $this->sid = $rxml['sid']; - $this->rid = 3001; - $this->sid = null; - if($session) - { - $this->loadSession(); - } - if(!$this->sid) { - $body = $this->__buildBody(); - $body->addAttribute('hold','1'); - $body->addAttribute('to', $this->host); - $body->addAttribute('route', "xmpp:{$this->host}:{$this->port}"); - $body->addAttribute('secure','true'); - $body->addAttribute('xmpp:version','1.6', 'urn:xmpp:xbosh'); - $body->addAttribute('wait', strval($wait)); - $body->addAttribute('ack','1'); - $body->addAttribute('xmlns:xmpp','urn:xmpp:xbosh'); - $buff = ""; - xml_parse($this->parser, $buff, false); - $response = $this->__sendBody($body); - $rxml = new SimpleXMLElement($response); - $this->sid = $rxml['sid']; + } else { + $buff = ""; + xml_parse($this->parser, $buff, false); + } + } - } else { - $buff = ""; - xml_parse($this->parser, $buff, false); - } - } + public function __sendBody($body = null, $recv = true) + { + if (!$body) { + $body = $this->__buildBody(); + } + $ch = curl_init($this->http_server); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body->asXML()); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + $header = array('Accept-Encoding: gzip, deflate', 'Content-Type: text/xml; charset=utf-8'); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_VERBOSE, 0); + $output = ''; + if ($recv) { + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $output = curl_exec($ch); + $this->http_buffer[] = $output; + } + curl_close($ch); + return $output; + } - public function __sendBody($body=null, $recv=true) { - if(!$body) { - $body = $this->__buildBody(); - } - $ch = curl_init($this->http_server); - curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $body->asXML()); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - $header = array('Accept-Encoding: gzip, deflate','Content-Type: text/xml; charset=utf-8'); - curl_setopt($ch, CURLOPT_HTTPHEADER, $header ); - curl_setopt($ch, CURLOPT_VERBOSE, 0); - $output = ''; - if($recv) { - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - $output = curl_exec($ch); - $this->http_buffer[] = $output; - } - curl_close($ch); - return $output; - } + public function __buildBody($sub = null) + { + $xml = new \SimpleXMLElement(""); + $xml->addAttribute('content', 'text/xml; charset=utf-8'); + $xml->addAttribute('rid', $this->rid); + $this->rid += 1; + if ($this->sid) $xml->addAttribute('sid', $this->sid); + #if($this->sid) $xml->addAttribute('xmlns', 'http://jabber.org/protocol/httpbind'); + $xml->addAttribute('xml:lang', 'en'); + if ($sub) { // ok, so simplexml is lame + $p = dom_import_simplexml($xml); + $c = dom_import_simplexml($sub); + $cn = $p->ownerDocument->importNode($c, true); + $p->appendChild($cn); + $xml = simplexml_import_dom($p); + } + return $xml; + } - public function __buildBody($sub=null) { - $xml = new SimpleXMLElement(""); - $xml->addAttribute('content', 'text/xml; charset=utf-8'); - $xml->addAttribute('rid', $this->rid); - $this->rid += 1; - if($this->sid) $xml->addAttribute('sid', $this->sid); - #if($this->sid) $xml->addAttribute('xmlns', 'http://jabber.org/protocol/httpbind'); - $xml->addAttribute('xml:lang', 'en'); - if($sub) { // ok, so simplexml is lame - $p = dom_import_simplexml($xml); - $c = dom_import_simplexml($sub); - $cn = $p->ownerDocument->importNode($c, true); - $p->appendChild($cn); - $xml = simplexml_import_dom($p); - } - return $xml; - } + public function __process() + { + if ($this->http_buffer) { + $this->__parseBuffer(); + } else { + $this->__sendBody(); + $this->__parseBuffer(); + } + } - public function __process() { - if($this->http_buffer) { - $this->__parseBuffer(); - } else { - $this->__sendBody(); - $this->__parseBuffer(); - } - } + public function __parseBuffer() + { + while ($this->http_buffer) { + $idx = key($this->http_buffer); + $buffer = $this->http_buffer[$idx]; + unset($this->http_buffer[$idx]); + if ($buffer) { + $xml = new \SimpleXMLElement($buffer); + $children = $xml->xpath('child::node()'); + foreach ($children as $child) { + $buff = $child->asXML(); + $this->log->log("RECV: $buff", Log::LEVEL_VERBOSE); + xml_parse($this->parser, $buff, false); + } + } + } + } - public function __parseBuffer() { - while ($this->http_buffer) { - $idx = key($this->http_buffer); - $buffer = $this->http_buffer[$idx]; - unset($this->http_buffer[$idx]); - if($buffer) { - $xml = new SimpleXMLElement($buffer); - $children = $xml->xpath('child::node()'); - foreach ($children as $child) { - $buff = $child->asXML(); - $this->log->log("RECV: $buff", XMPPHP_Log::LEVEL_VERBOSE); - xml_parse($this->parser, $buff, false); - } - } - } - } + public function send($msg) + { + $this->log->log("SEND: $msg", Log::LEVEL_VERBOSE); + $msg = new \SimpleXMLElement($msg); + #$msg->addAttribute('xmlns', 'jabber:client'); + $this->__sendBody($this->__buildBody($msg), true); + #$this->__parseBuffer(); + } - public function send($msg) { - $this->log->log("SEND: $msg", XMPPHP_Log::LEVEL_VERBOSE); - $msg = new SimpleXMLElement($msg); - #$msg->addAttribute('xmlns', 'jabber:client'); - $this->__sendBody($this->__buildBody($msg), true); - #$this->__parseBuffer(); - } + public function reset() + { + $this->xml_depth = 0; + unset($this->xmlobj); + $this->xmlobj = array(); + $this->setupParser(); + #$this->send($this->stream_start); + $body = $this->__buildBody(); + $body->addAttribute('to', $this->host); + $body->addAttribute('xmpp:restart', 'true', 'urn:xmpp:xbosh'); + $buff = ""; + $response = $this->__sendBody($body); + $this->been_reset = true; + xml_parse($this->parser, $buff, false); + } - public function reset() { - $this->xml_depth = 0; - unset($this->xmlobj); - $this->xmlobj = array(); - $this->setupParser(); - #$this->send($this->stream_start); - $body = $this->__buildBody(); - $body->addAttribute('to', $this->host); - $body->addAttribute('xmpp:restart', 'true', 'urn:xmpp:xbosh'); - $buff = ""; - $response = $this->__sendBody($body); - $this->been_reset = true; - xml_parse($this->parser, $buff, false); - } + public function loadSession() + { + if (isset($_SESSION['XMPPHP_BOSH_RID'])) $this->rid = $_SESSION['XMPPHP_BOSH_RID']; + if (isset($_SESSION['XMPPHP_BOSH_SID'])) $this->sid = $_SESSION['XMPPHP_BOSH_SID']; + if (isset($_SESSION['XMPPHP_BOSH_authed'])) $this->authed = $_SESSION['XMPPHP_BOSH_authed']; + if (isset($_SESSION['XMPPHP_BOSH_jid'])) $this->jid = $_SESSION['XMPPHP_BOSH_jid']; + if (isset($_SESSION['XMPPHP_BOSH_fulljid'])) $this->fulljid = $_SESSION['XMPPHP_BOSH_fulljid']; + } - public function loadSession() { - if(isset($_SESSION['XMPPHP_BOSH_RID'])) $this->rid = $_SESSION['XMPPHP_BOSH_RID']; - if(isset($_SESSION['XMPPHP_BOSH_SID'])) $this->sid = $_SESSION['XMPPHP_BOSH_SID']; - if(isset($_SESSION['XMPPHP_BOSH_authed'])) $this->authed = $_SESSION['XMPPHP_BOSH_authed']; - if(isset($_SESSION['XMPPHP_BOSH_jid'])) $this->jid = $_SESSION['XMPPHP_BOSH_jid']; - if(isset($_SESSION['XMPPHP_BOSH_fulljid'])) $this->fulljid = $_SESSION['XMPPHP_BOSH_fulljid']; - } - - public function saveSession() { - $_SESSION['XMPPHP_BOSH_RID'] = (string) $this->rid; - $_SESSION['XMPPHP_BOSH_SID'] = (string) $this->sid; - $_SESSION['XMPPHP_BOSH_authed'] = (boolean) $this->authed; - $_SESSION['XMPPHP_BOSH_jid'] = (string) $this->jid; - $_SESSION['XMPPHP_BOSH_fulljid'] = (string) $this->fulljid; - } -} + public function saveSession() + { + $_SESSION['XMPPHP_BOSH_RID'] = (string)$this->rid; + $_SESSION['XMPPHP_BOSH_SID'] = (string)$this->sid; + $_SESSION['XMPPHP_BOSH_authed'] = (boolean)$this->authed; + $_SESSION['XMPPHP_BOSH_jid'] = (string)$this->jid; + $_SESSION['XMPPHP_BOSH_fulljid'] = (string)$this->fulljid; + } +} \ No newline at end of file diff --git a/lib/jabber/XMPP/Exception.php b/lib/jabber/XMPP/Exception.php index da59bc7918b..c8129abdabc 100644 --- a/lib/jabber/XMPP/Exception.php +++ b/lib/jabber/XMPP/Exception.php @@ -1,41 +1,47 @@ * @author Stephan Wentz - * @author Michael Garvin + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) * @copyright 2008 Nathanael C. Fritz */ /** - * XMPPHP Exception + * XMPPHP Main Class * - * @category xmpphp + * @category xmpphp * @package XMPPHP * @author Nathanael C. Fritz * @author Stephan Wentz - * @author Michael Garvin + * @author Michael Garvin * @copyright 2008 Nathanael C. Fritz * @version $Id$ */ -class XMPPHP_Exception extends Exception { +class Exception extends ObjectException { } diff --git a/lib/jabber/XMPP/Log.php b/lib/jabber/XMPP/Log.php index a9bce3d8410..0ceaeace882 100644 --- a/lib/jabber/XMPP/Log.php +++ b/lib/jabber/XMPP/Log.php @@ -1,42 +1,47 @@ - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - */ + +namespace BirknerAlex\XMPPHP; + + /** + * 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 + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @copyright 2008 Nathanael C. Fritz + */ /** - * XMPPHP Log - * - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin + * XMPPHP Main Class + * + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin * @copyright 2008 Nathanael C. Fritz - * @version $Id$ + * @version $Id$ */ -class XMPPHP_Log { +class Log { const LEVEL_ERROR = 0; const LEVEL_WARNING = 1; diff --git a/lib/jabber/XMPP/README.txt b/lib/jabber/XMPP/README.txt deleted file mode 100644 index 0c2f53df6d9..00000000000 --- a/lib/jabber/XMPP/README.txt +++ /dev/null @@ -1,43 +0,0 @@ -About -================================================================================ -XMPPHP is an elegant PHP library for XMPP (aka Jabber, Google Talk, etc). - -Homepage: http://code.google.com/p/xmpphp -Author: Nathan Fritz, jabber id: fritzy [at] netflint.net -Co-Author: Stephan Wentz, jabber id: stephan [at] jabber.wentz.it - -If you have any questions (no matter how dumb), please send me an IM. I enjoy -helping people with my code. - - -Requirements -================================================================================ -* PHP 5.x -* SSL Support Compiled - -History -================================================================================ -Carlo Zottmann handed me maintenance of Class.Jabber.PHP years and years ago -(2003?). While I did fix some bugs, I never did much with it. I promised many -people that it would return as a PHP5 rewrite. That day has finally come. - -This code is based on my experience with Class.Jabber.PHP, but more closely -related to my Python library, SleekXMPP (http://code.google.com/p/sleekxmpp). - -Documentation -================================================================================ -For now, look at the examples. In the near future, I'll have better -documentation on the website. - -TODO -================================================================================ -* Documentation -* MUC Support - -License Exception -=============================================================================== -Please contact Nathan Fritz for library exceptions if you would like to -distribute XMPPHP with a non-GPL compatible license. - -Also, if you would like to distribute XMPPHP as part of a commercial package, -I sell commercial licenses. diff --git a/lib/jabber/XMPP/Roster.php b/lib/jabber/XMPP/Roster.php index 69457b22a19..99ec8c12bdf 100644 --- a/lib/jabber/XMPP/Roster.php +++ b/lib/jabber/XMPP/Roster.php @@ -1,43 +1,46 @@ - * @author Stephan Wentz - * @author Michael Garvin + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) * @copyright 2008 Nathanael C. Fritz */ /** - * XMPPHP Roster Object - * - * @category xmpphp - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin + * XMPPHP Main Class + * + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin * @copyright 2008 Nathanael C. Fritz - * @version $Id$ + * @version $Id$ */ - class Roster { /** * Roster array, handles contacts and presence. Indexed by jid. @@ -118,15 +121,17 @@ class Roster { * @param string $status */ public function setPresence($presence, $priority, $show, $status) { - list($jid, $resource) = explode("/", $presence); + $presence = explode('/', $presence, 2); + $jid = $presence[0]; + $resource = isset($presence[1]) ? $presence[1] : ''; if ($show != 'unavailable') { if (!$this->isContact($jid)) { $this->addContact($jid, 'not-in-roster'); } - $resource = $resource ? $resource : ''; $this->roster_array[$jid]['presence'][$resource] = array('priority' => $priority, 'show' => $show, 'status' => $status); } else { //Nuke unavailable resources to save memory unset($this->roster_array[$jid]['resource'][$resource]); + unset($this->roster_array[$jid]['presence'][$resource]); } } @@ -137,7 +142,7 @@ class Roster { * @param string $jid */ public function getPresence($jid) { - $split = explode("/", $jid); + $split = explode('/', $jid, 2); $jid = $split[0]; if($this->isContact($jid)) { $current = array('resource' => '', 'active' => '', 'priority' => -129, 'show' => '', 'status' => ''); //Priorities can only be -128 = 127 diff --git a/lib/jabber/XMPP/XMLObj.php b/lib/jabber/XMPP/XMLObj.php index 0d3e2199120..0bb314db76b 100644 --- a/lib/jabber/XMPP/XMLObj.php +++ b/lib/jabber/XMPP/XMLObj.php @@ -1,43 +1,47 @@ - - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - */ + + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @copyright 2008 Nathanael C. Fritz + */ /** - * XMPPHP XML Object - * - * @category xmpphp - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin + * XMPPHP Main Class + * + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin * @copyright 2008 Nathanael C. Fritz - * @version $Id$ + * @version $Id$ */ -class XMPPHP_XMLObj { +class XMLObj { /** * Tag name * diff --git a/lib/jabber/XMPP/XMLStream.php b/lib/jabber/XMPP/XMLStream.php index 41c7a78dea1..badc805225e 100644 --- a/lib/jabber/XMPP/XMLStream.php +++ b/lib/jabber/XMPP/XMLStream.php @@ -1,52 +1,47 @@ + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @copyright 2008 Nathanael C. Fritz + */ + /** - * 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 + * XMPPHP Main Class * - * @category xmpphp - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin * @copyright 2008 Nathanael C. Fritz + * @version $Id$ */ - -/** XMPPHP_Exception */ -require_once dirname(__FILE__) . '/Exception.php'; - -/** XMPPHP_XMLObj */ -require_once dirname(__FILE__) . '/XMLObj.php'; - -/** XMPPHP_Log */ -require_once dirname(__FILE__) . '/Log.php'; - -/** - * XMPPHP XML Stream - * - * @category xmpphp - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - * @version $Id$ - */ -class XMPPHP_XMLStream { +class XMLStream { /** * @var resource */ @@ -82,7 +77,7 @@ class XMPPHP_XMLStream { /** * @var boolean */ - protected $disconnected = false; + protected $disconnected = true; /** * @var boolean */ @@ -124,13 +119,13 @@ class XMPPHP_XMLStream { */ protected $default_ns; /** - * @var string + * @var string[] */ - protected $until = []; + protected $until = array(); /** - * @var string + * @var int[] */ - protected $until_count = []; + protected $until_count = array(); /** * @var array */ @@ -140,7 +135,7 @@ class XMPPHP_XMLStream { */ protected $until_payload = array(); /** - * @var XMPPHP_Log + * @var Log */ protected $log; /** @@ -183,7 +178,7 @@ class XMPPHP_XMLStream { $this->host = $host; $this->port = $port; $this->setupParser(); - $this->log = new XMPPHP_Log($printlog, $loglevel); + $this->log = new Log($printlog, $loglevel); } /** @@ -199,7 +194,7 @@ class XMPPHP_XMLStream { /** * Return the log instance * - * @return XMPPHP_Log + * @return Log */ public function getLog() { return $this->log; @@ -263,7 +258,7 @@ class XMPPHP_XMLStream { $ns_tags = array($xpath); } foreach($ns_tags as $ns_tag) { - list($l, $r) = explode("}", $ns_tag); + list($l, $r) = explode('}', $ns_tag); if ($r != null) { $xpart = array(substr($l, 1), $r); } else { @@ -288,9 +283,12 @@ class XMPPHP_XMLStream { /** * Connect to XMPP Host * - * @param integer $timeout + * @param integer $timeout Timeout in seconds * @param boolean $persistent - * @param boolean $sendinit + * @param boolean $sendinit Send XMPP starting sequence after connect + * automatically + * + * @throws Exception When the connection fails */ public function connect($timeout = 30, $persistent = false, $sendinit = true) { $this->sent_disconnect = false; @@ -310,10 +308,10 @@ class XMPPHP_XMLStream { try { $this->socket = @stream_socket_client("$conntype://{$this->host}:{$this->port}", $errno, $errstr, $timeout, $conflag); } catch (Exception $e) { - throw new XMPPHP_Exception($e->getMessage()); + throw new Exception($e->getMessage()); } if(!$this->socket) { - $this->log->log("Could not connect.", XMPPHP_Log::LEVEL_ERROR); + $this->log->log("Could not connect.", Log::LEVEL_ERROR); $this->disconnected = true; # Take it easy for a few seconds sleep(min($timeout, 5)); @@ -324,16 +322,20 @@ class XMPPHP_XMLStream { stream_set_blocking($this->socket, 1); if($sendinit) $this->send($this->stream_start); } else { - throw new XMPPHP_Exception("Could not connect before timeout."); + throw new Exception("Could not connect before timeout."); } } /** * Reconnect XMPP Host + * + * @throws Exception When the connection fails + * @uses $reconnectTimeout + * @see setReconnectTimeout() */ public function doReconnect() { if(!$this->is_server) { - $this->log->log("Reconnecting ($this->reconnectTimeout)...", XMPPHP_Log::LEVEL_WARNING); + $this->log->log("Reconnecting ($this->reconnectTimeout)...", Log::LEVEL_WARNING); $this->connect($this->reconnectTimeout, false, false); $this->reset(); $this->event('reconnect'); @@ -348,7 +350,7 @@ class XMPPHP_XMLStream { * Disconnect from XMPP Host */ public function disconnect() { - $this->log->log("Disconnecting...", XMPPHP_Log::LEVEL_VERBOSE); + $this->log->log("Disconnecting...", Log::LEVEL_VERBOSE); if(false == (bool) $this->socket) { return; } @@ -369,14 +371,57 @@ class XMPPHP_XMLStream { } /** - * Core reading tool - * 0 -> only read if data is immediately ready - * NULL -> wait forever and ever - * integer -> process for this amount of time + * Checks if the given string is closed with the same tag as it is + * opened. We try to be as fast as possible here. + * + * @param string $buff Read buffer of __process() + * + * @return boolean true if the buffer seems to be complete */ - - private function __process($maximum=5) { - + protected function bufferComplete($buff) + { + if (substr($buff, -1) != '>') { + return false; + } + //we always have a space since the namespace needs to be + //declared. could be a tab, though + $start = substr( + $buff, 1, + min(strpos($buff, '>', 2), strpos($buff, ' ', 2)) - 1 + ); + $stop = substr($buff, -strlen($start) - 3); + + if ($start == '?xml') { + //starting with an xml tag. this means a stream is being + // opened, which is not much of data, so no fear it's + // not complete + return true; + } + if (substr($stop, -2) == '/>') { + //one tag, i.e. + return true; + } + if ('' == $stop) { + return true; + } + + return false; + } + + /** + * Core reading tool + * + * @param mixed $maximum Limit when to return + * - 0: only read if data is immediately ready + * - NULL: wait forever and ever + * - integer: process for this amount of microseconds + * @param boolean $return_when_received Immediately return when data have been + * received + * + * @return boolean True when all goes well, false when something fails + */ + private function __process($maximum = 5, $return_when_received = false) + { $remaining = $maximum; do { @@ -396,7 +441,7 @@ class XMPPHP_XMLStream { } $updated = @stream_select($read, $write, $except, $secs, $usecs); if ($updated === false) { - $this->log->log("Error on stream_select()", XMPPHP_Log::LEVEL_VERBOSE); + $this->log->log("Error on stream_select()", Log::LEVEL_VERBOSE); if ($this->reconnect) { $this->doReconnect(); } else { @@ -405,19 +450,34 @@ class XMPPHP_XMLStream { return false; } } else if ($updated > 0) { - # XXX: Is this big enough? - $buff = @fread($this->socket, 4096); - if(!$buff) { - if($this->reconnect) { - $this->doReconnect(); - } else { - fclose($this->socket); - $this->socket = NULL; - return false; + $buff = ''; + do { + if ($buff != '') { + //disable blocking for now because fread() will + // block until the 4k are full if we already + // read a part of the packet + stream_set_blocking($this->socket, 0); } - } - $this->log->log("RECV: $buff", XMPPHP_Log::LEVEL_VERBOSE); + $part = fread($this->socket, 4096); + stream_set_blocking($this->socket, 1); + + if (!$part && feof($this->socket)) { + if($this->reconnect) { + $this->doReconnect(); + } else { + fclose($this->socket); + $this->socket = NULL; + return false; + } + } + $this->log->log("RECV: $part", Log::LEVEL_VERBOSE); + $buff .= $part; + } while (!$this->bufferComplete($buff)); + xml_parse($this->parser, $buff, false); + if ($return_when_received) { + return true; + } } else { # $updated == 0 means no changes during timeout. } @@ -440,8 +500,11 @@ class XMPPHP_XMLStream { /** * Process until a timeout occurs * - * @param integer $timeout + * @param integer $timeout Time in seconds + * * @return string + * + * @see __process() */ public function processTime($timeout=NULL) { if (is_null($timeout)) { @@ -454,23 +517,43 @@ class XMPPHP_XMLStream { /** * Process until a specified event or a timeout occurs * - * @param string|array $event - * @param integer $timeout - * @return string + * @param string|array $event Event name or array of event names + * @param integer $timeout Timeout in seconds + * + * @return array Payload */ - public function processUntil($event, $timeout=-1) { + public function processUntil($event, $timeout = -1) + { + if ($this->disconnected) { + throw new Exception('You need to connect first'); + } + $start = time(); - if(!is_array($event)) $event = array($event); + if (!is_array($event)) { + $event = array($event); + } + $this->until[] = $event; end($this->until); $event_key = key($this->until); reset($this->until); + $this->until_count[$event_key] = 0; $updated = ''; - while(!$this->disconnected and $this->until_count[$event_key] < 1 and (time() - $start < $timeout or $timeout == -1)) { - $this->__process(); + while (!$this->disconnected + && $this->until_count[$event_key] < 1 + && ($timeout == -1 || time() - $start < $timeout) + ) { + $maximum = $timeout == -1 + ? NULL + : ($timeout - (time() - $start)) * 1000000; + $ret = $this->__process($maximum, true); + if (!$ret) { + break; + } } - if(array_key_exists($event_key, $this->until_payload)) { + + if (array_key_exists($event_key, $this->until_payload)) { $payload = $this->until_payload[$event_key]; unset($this->until_payload[$event_key]); unset($this->until_count[$event_key]); @@ -478,6 +561,7 @@ class XMPPHP_XMLStream { } else { $payload = array(); } + return $payload; } @@ -522,7 +606,7 @@ class XMPPHP_XMLStream { $ns = $this->ns_map[$name[0]]; $name = $name[1]; } - $obj = new XMPPHP_XMLObj($name, $ns, $attr); + $obj = new XMLObj($name, $ns, $attr); if($this->xml_depth > 1) { $this->xmlobj[$this->xml_depth - 1]->subs[] = $obj; } @@ -538,7 +622,7 @@ class XMPPHP_XMLStream { * @param string $name */ public function endXML($parser, $name) { - #$this->log->log("Ending $name", XMPPHP_Log::LEVEL_DEBUG); + #$this->log->log("Ending $name", Log::LEVEL_DEBUG); #print "$name\n"; if($this->been_reset) { $this->been_reset = false; @@ -563,7 +647,7 @@ class XMPPHP_XMLStream { } if ($searchxml !== null) { if($handler[2] === null) $handler[2] = $this; - $this->log->log("Calling {$handler[1]}", XMPPHP_Log::LEVEL_DEBUG); + $this->log->log("Calling {$handler[1]}", Log::LEVEL_DEBUG); $handler[2]->{$handler[1]}($this->xmlobj[2]); } } @@ -577,7 +661,7 @@ class XMPPHP_XMLStream { } 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); + $this->log->log("Calling {$handler[2]}", Log::LEVEL_DEBUG); $handler[3]->{$handler[2]}($this->xmlobj[2]); } } @@ -592,7 +676,7 @@ class XMPPHP_XMLStream { } if(is_array($this->xmlobj)) { $this->xmlobj = array_slice($this->xmlobj, 0, 1); - if(isset($this->xmlobj[0]) && $this->xmlobj[0] instanceof XMPPHP_XMLObj) { + if(isset($this->xmlobj[0]) && $this->xmlobj[0] instanceof XMLObj) { $this->xmlobj[0]->subs = null; } } @@ -634,7 +718,7 @@ class XMPPHP_XMLStream { * @param string $payload */ public function event($name, $payload = null) { - $this->log->log("EVENT: $name", XMPPHP_Log::LEVEL_DEBUG); + $this->log->log("EVENT: $name", Log::LEVEL_DEBUG); foreach($this->eventhandlers as $handler) { if($name == $handler[0]) { if($handler[2] === null) { @@ -643,6 +727,7 @@ class XMPPHP_XMLStream { $handler[2]->{$handler[1]}($payload); } } + foreach($this->until as $key => $until) { if(is_array($until)) { if(in_array($name, $until)) { @@ -670,7 +755,7 @@ class XMPPHP_XMLStream { return false; } } - $this->log->log("RECV: $buff", XMPPHP_Log::LEVEL_VERBOSE); + $this->log->log("RECV: $buff", Log::LEVEL_VERBOSE); xml_parse($this->parser, $buff, false); } @@ -705,20 +790,20 @@ class XMPPHP_XMLStream { # TODO: retry send here return false; } elseif ($select > 0) { - $this->log->log("Socket is ready; send it.", XMPPHP_Log::LEVEL_VERBOSE); + $this->log->log("Socket is ready; send it.", Log::LEVEL_VERBOSE); } else { - $this->log->log("Socket is not ready; break.", XMPPHP_Log::LEVEL_ERROR); + $this->log->log("Socket is not ready; break.", Log::LEVEL_ERROR); return false; } $sentbytes = @fwrite($this->socket, $msg); - $this->log->log("SENT: " . mb_substr($msg, 0, $sentbytes, '8bit'), XMPPHP_Log::LEVEL_VERBOSE); + $this->log->log("SENT: " . mb_substr($msg, 0, $sentbytes, '8bit'), Log::LEVEL_VERBOSE); if($sentbytes === FALSE) { - $this->log->log("ERROR sending message; reconnecting.", XMPPHP_Log::LEVEL_ERROR); + $this->log->log("ERROR sending message; reconnecting.", Log::LEVEL_ERROR); $this->doReconnect(); return false; } - $this->log->log("Successfully sent $sentbytes bytes.", XMPPHP_Log::LEVEL_VERBOSE); + $this->log->log("Successfully sent $sentbytes bytes.", Log::LEVEL_VERBOSE); return $sentbytes; } diff --git a/lib/jabber/XMPP/XMPP.php b/lib/jabber/XMPP/XMPP.php index c0f8963396b..9714529b3a3 100644 --- a/lib/jabber/XMPP/XMPP.php +++ b/lib/jabber/XMPP/XMPP.php @@ -1,47 +1,47 @@ - * @author Stephan Wentz - * @author Michael Garvin - * @copyright 2008 Nathanael C. Fritz - */ -/** XMPPHP_XMLStream */ -require_once dirname(__FILE__) . "/XMLStream.php"; -require_once dirname(__FILE__) . "/Roster.php"; +namespace BirknerAlex\XMPPHP; + + /** + * 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 + * @author Stephan Wentz + * @author Michael Garvin + * @author Alexander Birkner (https://github.com/BirknerAlex) + * @copyright 2008 Nathanael C. Fritz + */ /** * XMPPHP Main Class - * - * @category xmpphp - * @package XMPPHP - * @author Nathanael C. Fritz - * @author Stephan Wentz - * @author Michael Garvin + * + * @category xmpphp + * @package XMPPHP + * @author Nathanael C. Fritz + * @author Stephan Wentz + * @author Michael Garvin * @copyright 2008 Nathanael C. Fritz - * @version $Id$ + * @version $Id$ */ -class XMPPHP_XMPP extends XMPPHP_XMLStream { +class XMPP extends XMLStream { /** * @var string */ @@ -117,6 +117,7 @@ class XMPPHP_XMPP extends XMPPHP_XMLStream { $this->password = $password; $this->resource = $resource; if(!$server) $server = $host; + $this->server = $server; $this->basejid = $this->user . '@' . $this->host; $this->roster = new Roster(); @@ -162,11 +163,14 @@ class XMPPHP_XMPP extends XMPPHP_XMLStream { * @param string $subject */ public function message($to, $body, $type = 'chat', $subject = null, $payload = null) { - if(is_null($type)) - { + if ($this->disconnected) { + throw new Exception('You need to connect first'); + } + + if(empty($type)) { $type = 'chat'; } - + $to = htmlspecialchars($to); $body = htmlspecialchars($body); $subject = htmlspecialchars($subject); @@ -187,7 +191,11 @@ class XMPPHP_XMPP extends XMPPHP_XMLStream { * @param string $show * @param string $to */ - public function presence($status = null, $show = 'available', $to = null, $type='available', $priority=0) { + public function presence($status = null, $show = 'available', $to = null, $type='available', $priority=null) { + if ($this->disconnected) { + throw new Exception('You need to connect first'); + } + if($type == 'available') $type = ''; $to = htmlspecialchars($to); $status = htmlspecialchars($status); @@ -196,13 +204,13 @@ class XMPPHP_XMPP extends XMPPHP_XMLStream { $out = "sub('body'); $payload['from'] = $xml->attrs['from']; - $payload['body'] = $xml->sub('body')->data; + $payload['body'] = is_object($body) ? $body->data : FALSE; // $xml->sub('body')->data; $payload['xml'] = $xml; - $this->log->log("Message: {$xml->sub('body')->data}", XMPPHP_Log::LEVEL_DEBUG); + $this->log->log("Message: {$payload['body']}", Log::LEVEL_DEBUG); $this->event('message', $payload); } @@ -251,7 +260,7 @@ class XMPPHP_XMPP extends XMPPHP_XMLStream { if($this->track_presence) { $this->roster->setPresence($payload['from'], $payload['priority'], $payload['show'], $payload['status']); } - $this->log->log("Presence: {$payload['from']} [{$payload['show']}] {$payload['status']}", XMPPHP_Log::LEVEL_DEBUG); + $this->log->log("Presence: {$payload['from']} [{$payload['show']}] {$payload['status']}", Log::LEVEL_DEBUG); if(array_key_exists('type', $xml->attrs) and $xml->attrs['type'] == 'subscribe') { if($this->auto_subscribe) { $this->send(""); @@ -304,10 +313,10 @@ class XMPPHP_XMPP extends XMPPHP_XMLStream { * @param string $xml */ protected function sasl_failure_handler($xml) { - $this->log->log("Auth failed!", XMPPHP_Log::LEVEL_ERROR); + $this->log->log("Auth failed!", Log::LEVEL_ERROR); $this->disconnect(); - throw new XMPPHP_Exception('Auth failed!'); + throw new Exception('Auth failed!'); } /** diff --git a/lib/jabber/XMPP/XMPP_Old.php b/lib/jabber/XMPP/XMPP_Old.php deleted file mode 100644 index 43f56b15466..00000000000 --- a/lib/jabber/XMPP/XMPP_Old.php +++ /dev/null @@ -1,114 +0,0 @@ - - * @author Stephan Wentz - * @author Michael Garvin - * @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); - if(!$server) $server = $host; - $this->stream_start = ''; - $this->fulljid = "{$user}@{$server}/{$resource}"; - } - - /** - * Override XMLStream's startXML - * - * @param parser $parser - * @param string $name - * @param array $attr - */ - public function startXML($parser, $name, $attr) { - if($this->xml_depth == 0) { - $this->session_id = $attr['ID']; - $this->authenticate(); - } - parent::startXML($parser, $name, $attr); - } - - /** - * Send Authenticate Info Request - * - */ - public function authenticate() { - $id = $this->getId(); - $this->addidhandler($id, 'authfieldshandler'); - $this->send("{$this->user}"); - } - - /** - * Retrieve auth fields and send auth attempt - * - * @param XMLObj $xml - */ - public function authFieldsHandler($xml) { - $id = $this->getId(); - $this->addidhandler($id, 'oldAuthResultHandler'); - if($xml->sub('query')->hasSub('digest')) { - $hash = sha1($this->session_id . $this->password); - print "{$this->session_id} {$this->password}\n"; - $out = "{$this->user}{$hash}{$this->resource}"; - } else { - $out = "{$this->user}{$this->password}{$this->resource}"; - } - $this->send($out); - - } - - /** - * Determine authenticated or failure - * - * @param XMLObj $xml - */ - public function oldAuthResultHandler($xml) { - if($xml->attrs['type'] != 'result') { - $this->log->log("Auth failed!", XMPPHP_Log::LEVEL_ERROR); - $this->disconnect(); - throw new XMPPHP_Exception('Auth failed!'); - } else { - $this->log->log("Session started"); - $this->event('session_start'); - } - } - } - - -?>