1<?php
2
3namespace BirknerAlex\XMPPHP;
4
5    /**
6     * XMPPHP: The PHP XMPP Library
7     * Copyright (C) 2008  Nathanael C. Fritz
8     * This file is part of SleekXMPP.
9     *
10     * XMPPHP is free software; you can redistribute it and/or modify
11     * it under the terms of the GNU General Public License as published by
12     * the Free Software Foundation; either version 2 of the License, or
13     * (at your option) any later version.
14     *
15     * XMPPHP is distributed in the hope that it will be useful,
16     * but WITHOUT ANY WARRANTY; without even the implied warranty of
17     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     * GNU General Public License for more details.
19     *
20     * You should have received a copy of the GNU General Public License
21     * along with XMPPHP; if not, write to the Free Software
22     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
23     *
24     * @category   xmpphp
25     * @package    XMPPHP
26     * @author     Nathanael C. Fritz <JID: fritzy@netflint.net>
27     * @author     Stephan Wentz <JID: stephan@jabber.wentz.it>
28     * @author     Michael Garvin <JID: gar@netflint.net>
29     * @author     Alexander Birkner (https://github.com/BirknerAlex)
30     * @copyright  2008 Nathanael C. Fritz
31     */
32
33/**
34 * XMPPHP Main Class
35 *
36 * @category   xmpphp
37 * @package    XMPPHP
38 * @author     Nathanael C. Fritz <JID: fritzy@netflint.net>
39 * @author     Stephan Wentz <JID: stephan@jabber.wentz.it>
40 * @author     Michael Garvin <JID: gar@netflint.net>
41 * @copyright  2008 Nathanael C. Fritz
42 * @version    $Id$
43 */
44class BOSH extends XMPP
45{
46    protected $rid;
47    protected $sid;
48    protected $http_server;
49    protected $http_buffer = Array();
50    protected $session = false;
51
52    public function connect($server, $wait = '1', $session = false)
53    {
54        $this->http_server = $server;
55        $this->use_encryption = false;
56        $this->session = $session;
57
58        $this->rid = 3001;
59        $this->sid = null;
60        if ($session) {
61            $this->loadSession();
62        }
63        if (!$this->sid) {
64            $body = $this->__buildBody();
65            $body->addAttribute('hold', '1');
66            $body->addAttribute('to', $this->host);
67            $body->addAttribute('route', "xmpp:{$this->host}:{$this->port}");
68            $body->addAttribute('secure', 'true');
69            $body->addAttribute('xmpp:version', '1.6', 'urn:xmpp:xbosh');
70            $body->addAttribute('wait', strval($wait));
71            $body->addAttribute('ack', '1');
72            $body->addAttribute('xmlns:xmpp', 'urn:xmpp:xbosh');
73            $buff = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>";
74            xml_parse($this->parser, $buff, false);
75            $response = $this->__sendBody($body);
76            $rxml = new \SimpleXMLElement($response);
77            $this->sid = $rxml['sid'];
78
79        } else {
80            $buff = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>";
81            xml_parse($this->parser, $buff, false);
82        }
83    }
84
85    public function __sendBody($body = null, $recv = true)
86    {
87        if (!$body) {
88            $body = $this->__buildBody();
89        }
90        $ch = curl_init($this->http_server);
91        curl_setopt($ch, CURLOPT_HEADER, 0);
92        curl_setopt($ch, CURLOPT_POST, 1);
93        curl_setopt($ch, CURLOPT_POSTFIELDS, $body->asXML());
94        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
95        $header = array('Accept-Encoding: gzip, deflate', 'Content-Type: text/xml; charset=utf-8');
96        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
97        curl_setopt($ch, CURLOPT_VERBOSE, 0);
98        $output = '';
99        if ($recv) {
100            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
101            $output = curl_exec($ch);
102            $this->http_buffer[] = $output;
103        }
104        curl_close($ch);
105        return $output;
106    }
107
108    public function __buildBody($sub = null)
109    {
110        $xml = new \SimpleXMLElement("<body xmlns='http://jabber.org/protocol/httpbind' xmlns:xmpp='urn:xmpp:xbosh' />");
111        $xml->addAttribute('content', 'text/xml; charset=utf-8');
112        $xml->addAttribute('rid', $this->rid);
113        $this->rid += 1;
114        if ($this->sid) $xml->addAttribute('sid', $this->sid);
115        #if($this->sid) $xml->addAttribute('xmlns', 'http://jabber.org/protocol/httpbind');
116        $xml->addAttribute('xml:lang', 'en');
117        if ($sub) { // ok, so simplexml is lame
118            $p = dom_import_simplexml($xml);
119            $c = dom_import_simplexml($sub);
120            $cn = $p->ownerDocument->importNode($c, true);
121            $p->appendChild($cn);
122            $xml = simplexml_import_dom($p);
123        }
124        return $xml;
125    }
126
127    public function __process()
128    {
129        if ($this->http_buffer) {
130            $this->__parseBuffer();
131        } else {
132            $this->__sendBody();
133            $this->__parseBuffer();
134        }
135    }
136
137    public function __parseBuffer()
138    {
139        while ($this->http_buffer) {
140            $idx = key($this->http_buffer);
141            $buffer = $this->http_buffer[$idx];
142            unset($this->http_buffer[$idx]);
143            if ($buffer) {
144                $xml = new \SimpleXMLElement($buffer);
145                $children = $xml->xpath('child::node()');
146                foreach ($children as $child) {
147                    $buff = $child->asXML();
148                    $this->log->log("RECV: $buff", Log::LEVEL_VERBOSE);
149                    xml_parse($this->parser, $buff, false);
150                }
151            }
152        }
153    }
154
155    public function send($msg)
156    {
157        $this->log->log("SEND: $msg", Log::LEVEL_VERBOSE);
158        $msg = new \SimpleXMLElement($msg);
159        #$msg->addAttribute('xmlns', 'jabber:client');
160        $this->__sendBody($this->__buildBody($msg), true);
161        #$this->__parseBuffer();
162    }
163
164    public function reset()
165    {
166        $this->xml_depth = 0;
167        unset($this->xmlobj);
168        $this->xmlobj = array();
169        $this->setupParser();
170        #$this->send($this->stream_start);
171        $body = $this->__buildBody();
172        $body->addAttribute('to', $this->host);
173        $body->addAttribute('xmpp:restart', 'true', 'urn:xmpp:xbosh');
174        $buff = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>";
175        $response = $this->__sendBody($body);
176        $this->been_reset = true;
177        xml_parse($this->parser, $buff, false);
178    }
179
180    public function loadSession()
181    {
182        if (isset($_SESSION['XMPPHP_BOSH_RID'])) $this->rid = $_SESSION['XMPPHP_BOSH_RID'];
183        if (isset($_SESSION['XMPPHP_BOSH_SID'])) $this->sid = $_SESSION['XMPPHP_BOSH_SID'];
184        if (isset($_SESSION['XMPPHP_BOSH_authed'])) $this->authed = $_SESSION['XMPPHP_BOSH_authed'];
185        if (isset($_SESSION['XMPPHP_BOSH_jid'])) $this->jid = $_SESSION['XMPPHP_BOSH_jid'];
186        if (isset($_SESSION['XMPPHP_BOSH_fulljid'])) $this->fulljid = $_SESSION['XMPPHP_BOSH_fulljid'];
187    }
188
189    public function saveSession()
190    {
191        $_SESSION['XMPPHP_BOSH_RID'] = (string)$this->rid;
192        $_SESSION['XMPPHP_BOSH_SID'] = (string)$this->sid;
193        $_SESSION['XMPPHP_BOSH_authed'] = (boolean)$this->authed;
194        $_SESSION['XMPPHP_BOSH_jid'] = (string)$this->jid;
195        $_SESSION['XMPPHP_BOSH_fulljid'] = (string)$this->fulljid;
196    }
197}