~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to www/php/phpBB3/includes/functions_jabber.php

Merge setup-stuff.

phpBB is gone, configuration, setup and jail building are completely redone.

Please read doc/setup/install_proc.txt, or you'll not get far.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
<?php
2
 
/**
3
 
*
4
 
* @package phpBB3
5
 
* @version $Id: functions_jabber.php,v 1.40 2007/10/05 14:30:10 acydburn Exp $
6
 
* @copyright (c) 2007 phpBB Group
7
 
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
8
 
*
9
 
*/
10
 
 
11
 
/**
12
 
* @ignore
13
 
*/
14
 
if (!defined('IN_PHPBB'))
15
 
{
16
 
        exit;
17
 
}
18
 
 
19
 
/**
20
 
*
21
 
* Jabber class from Flyspray project
22
 
*
23
 
* @version class.jabber2.php 1306 2007-06-21
24
 
* @copyright 2006 Flyspray.org
25
 
* @author Florian Schmitz (floele)
26
 
*
27
 
* Modified by Acyd Burn
28
 
*
29
 
* @package phpBB3
30
 
*/
31
 
class jabber
32
 
{
33
 
        var $connection = null;
34
 
        var $session = array();
35
 
        var $timeout = 10;
36
 
 
37
 
        var $server;
38
 
        var $port;
39
 
        var $username;
40
 
        var $password;
41
 
        var $use_ssl;
42
 
        var $resource = 'functions_jabber.phpbb.php';
43
 
 
44
 
        var $enable_logging;
45
 
        var $log_array;
46
 
 
47
 
        var $features = array();
48
 
 
49
 
        /**
50
 
        */
51
 
        function jabber($server, $port, $username, $password, $use_ssl = false)
52
 
        {
53
 
                $this->server                           = ($server) ? $server : 'localhost';
54
 
                $this->port                                     = ($port) ? $port : 5222;
55
 
                $this->username                         = $username;
56
 
                $this->password                         = $password;
57
 
                $this->use_ssl                          = ($use_ssl && $this->can_use_ssl()) ? true : false;
58
 
 
59
 
                // Change port if we use SSL
60
 
                if ($this->port == 5222 && $this->use_ssl)
61
 
                {
62
 
                        $this->port = 5223;
63
 
                }
64
 
 
65
 
                $this->enable_logging           = true;
66
 
                $this->log_array                        = array();
67
 
        }
68
 
 
69
 
        /**
70
 
        * Able to use the SSL functionality?
71
 
        */
72
 
        function can_use_ssl()
73
 
        {
74
 
                // Will not work with PHP >= 5.2.1 or < 5.2.3RC2 until timeout problem with ssl hasn't been fixed (http://bugs.php.net/41236)
75
 
                return ((version_compare(PHP_VERSION, '5.2.1', '<') || version_compare(PHP_VERSION, '5.2.3RC2', '>=')) && @extension_loaded('openssl')) ? true : false;
76
 
        }
77
 
 
78
 
        /**
79
 
        * Able to use TLS?
80
 
        */
81
 
        function can_use_tls()
82
 
        {
83
 
                if (!@extension_loaded('openssl') || !function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('socket_set_blocking') || !function_exists('stream_get_wrappers'))
84
 
                {
85
 
                        return false;
86
 
                }
87
 
 
88
 
                /**
89
 
                * Make sure the encryption stream is supported
90
 
                * Also seem to work without the crypto stream if correctly compiled
91
 
 
92
 
                $streams = stream_get_wrappers();
93
 
 
94
 
                if (!in_array('streams.crypto', $streams))
95
 
                {
96
 
                        return false;
97
 
                }
98
 
                */
99
 
 
100
 
                return true;
101
 
        }
102
 
 
103
 
        /**
104
 
        * Sets the resource which is used. No validation is done here, only escaping.
105
 
        * @param string $name
106
 
        * @access public
107
 
        */
108
 
        function set_resource($name)
109
 
        {
110
 
                $this->resource = $name;
111
 
        }
112
 
 
113
 
        /**
114
 
        * Connect
115
 
        */
116
 
        function connect()
117
 
        {
118
 
/*              if (!$this->check_jid($this->username . '@' . $this->server))
119
 
                {
120
 
                        $this->add_to_log('Error: Jabber ID is not valid: ' . $this->username . '@' . $this->server);
121
 
                        return false;
122
 
                }*/
123
 
 
124
 
                $this->session['ssl'] = $this->use_ssl;
125
 
 
126
 
                if ($this->open_socket($this->server, $this->port, $this->use_ssl))
127
 
                {
128
 
                        $this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n");
129
 
                        $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n");
130
 
                }
131
 
                else
132
 
                {
133
 
                        $this->add_to_log('Error: connect() #2');
134
 
                        return false;
135
 
                }
136
 
 
137
 
                // Now we listen what the server has to say...and give appropriate responses
138
 
                $this->response($this->listen());
139
 
                return true;
140
 
        }
141
 
 
142
 
        /**
143
 
        * Disconnect
144
 
        */
145
 
        function disconnect()
146
 
        {
147
 
                if ($this->connected())
148
 
                {
149
 
                        // disconnect gracefully
150
 
                        if (isset($this->session['sent_presence']))
151
 
                        {
152
 
                                $this->send_presence('offline', '', true);
153
 
                        }
154
 
 
155
 
                        $this->send('</stream:stream>');
156
 
                        $this->session = array();
157
 
                        return fclose($this->connection);
158
 
                }
159
 
 
160
 
                return false;
161
 
        }
162
 
 
163
 
        /**
164
 
        * Connected?
165
 
        */
166
 
        function connected()
167
 
        {
168
 
                return (is_resource($this->connection) && !feof($this->connection)) ? true : false;
169
 
        }
170
 
 
171
 
 
172
 
        /**
173
 
        * Initiates login (using data from contructor, after calling connect())
174
 
        * @access public
175
 
        * @return bool
176
 
        */
177
 
        function login()
178
 
        {
179
 
                if (!sizeof($this->features))
180
 
                {
181
 
                        $this->add_to_log('Error: No feature information from server available.');
182
 
                        return false;
183
 
                }
184
 
 
185
 
                return $this->response($this->features);
186
 
        }
187
 
 
188
 
        /**
189
 
        * Send data to the Jabber server
190
 
        * @param string $xml
191
 
        * @access public
192
 
        * @return bool
193
 
        */
194
 
        function send($xml)
195
 
        {
196
 
                if ($this->connected())
197
 
                {
198
 
                        $xml = trim($xml);
199
 
                        $this->add_to_log('SEND: '. $xml);
200
 
                        return fwrite($this->connection, $xml);
201
 
                }
202
 
                else
203
 
                {
204
 
                        $this->add_to_log('Error: Could not send, connection lost (flood?).');
205
 
                        return false;
206
 
                }
207
 
        }
208
 
 
209
 
        /**
210
 
        * OpenSocket
211
 
        * @param string $server host to connect to
212
 
        * @param int $port port number
213
 
        * @param bool $use_ssl use ssl or not
214
 
        * @access public
215
 
        * @return bool
216
 
        */
217
 
        function open_socket($server, $port, $use_ssl = false)
218
 
        {
219
 
                if (@function_exists('dns_get_record'))
220
 
                {
221
 
                        $record = @dns_get_record("_xmpp-client._tcp.$server", DNS_SRV);
222
 
                        if (!empty($record) && !empty($record[0]['target']))
223
 
                        {
224
 
                                $server = $record[0]['target'];
225
 
                        }
226
 
                }
227
 
 
228
 
                $server = $use_ssl ? 'ssl://' . $server : $server;
229
 
 
230
 
                if ($this->connection = @fsockopen($server, $port, $errorno, $errorstr, $this->timeout))
231
 
                {
232
 
                        socket_set_blocking($this->connection, 0);
233
 
                        socket_set_timeout($this->connection, 60);
234
 
 
235
 
                        return true;
236
 
                }
237
 
 
238
 
                // Apparently an error occured...
239
 
                $this->add_to_log('Error: open_socket() - ' . $errorstr);
240
 
                return false;
241
 
        }
242
 
 
243
 
        /**
244
 
        * Return log
245
 
        */
246
 
        function get_log()
247
 
        {
248
 
                if ($this->enable_logging && sizeof($this->log_array))
249
 
                {
250
 
                        return implode("<br /><br />", $this->log_array);
251
 
                }
252
 
 
253
 
                return '';
254
 
        }
255
 
 
256
 
        /**
257
 
        * Add information to log
258
 
        */
259
 
        function add_to_log($string)
260
 
        {
261
 
                if ($this->enable_logging)
262
 
                {
263
 
                        $this->log_array[] = utf8_htmlspecialchars($string);
264
 
                }
265
 
        }
266
 
 
267
 
        /**
268
 
        * Listens to the connection until it gets data or the timeout is reached.
269
 
        * Thus, it should only be called if data is expected to be received.
270
 
        * @access public
271
 
        * @return mixed either false for timeout or an array with the received data
272
 
        */
273
 
        function listen($timeout = 10, $wait = false)
274
 
        {
275
 
                if (!$this->connected())
276
 
                {
277
 
                        return false;
278
 
                }
279
 
 
280
 
                // Wait for a response until timeout is reached
281
 
                $start = time();
282
 
                $data = '';
283
 
 
284
 
                do
285
 
                {
286
 
                        $read = trim(fread($this->connection, 4096));
287
 
                        $data .= $read;
288
 
                }
289
 
                while (time() <= $start + $timeout && ($wait || $data == '' || $read != '' || (substr(rtrim($data), -1) != '>')));
290
 
 
291
 
                if ($data != '')
292
 
                {
293
 
                        $this->add_to_log('RECV: '. $data);
294
 
                        return $this->xmlize($data);
295
 
                }
296
 
                else
297
 
                {
298
 
                        $this->add_to_log('Timeout, no response from server.');
299
 
                        return false;
300
 
                }
301
 
        }
302
 
 
303
 
        /**
304
 
        * Initiates account registration (based on data used for contructor)
305
 
        * @access public
306
 
        * @return bool
307
 
        */
308
 
        function register()
309
 
        {
310
 
                if (!isset($this->session['id']) || isset($this->session['jid']))
311
 
                {
312
 
                        $this->add_to_log('Error: Cannot initiate registration.');
313
 
                        return false;
314
 
                }
315
 
 
316
 
                $this->send("<iq type='get' id='reg_1'><query xmlns='jabber:iq:register'/></iq>");
317
 
                return $this->response($this->listen());
318
 
        }
319
 
 
320
 
        /**
321
 
        * Sets account presence. No additional info required (default is "online" status)
322
 
        * @param $message online, offline...
323
 
        * @param $type dnd, away, chat, xa or nothing
324
 
        * @param $unavailable set this to true if you want to become unavailable
325
 
        * @access public
326
 
        * @return bool
327
 
        */
328
 
        function send_presence($message = '', $type = '', $unavailable = false)
329
 
        {
330
 
                if (!isset($this->session['jid']))
331
 
                {
332
 
                        $this->add_to_log('ERROR: send_presence() - Cannot set presence at this point, no jid given.');
333
 
                        return false;
334
 
                }
335
 
 
336
 
                $type = strtolower($type);
337
 
                $type = (in_array($type, array('dnd', 'away', 'chat', 'xa'))) ? '<show>'. $type .'</show>' : '';
338
 
 
339
 
                $unavailable = ($unavailable) ? " type='unavailable'" : '';
340
 
                $message = ($message) ? '<status>' . utf8_htmlspecialchars($message) .'</status>' : '';
341
 
 
342
 
                $this->session['sent_presence'] = !$unavailable;
343
 
 
344
 
                return $this->send("<presence$unavailable>" . $type . $message . '</presence>');
345
 
        }
346
 
 
347
 
        /**
348
 
        * This handles all the different XML elements
349
 
        * @param array $xml
350
 
        * @access public
351
 
        * @return bool
352
 
        */
353
 
        function response($xml)
354
 
        {
355
 
                if (!is_array($xml) || !sizeof($xml))
356
 
                {
357
 
                        return false;
358
 
                }
359
 
 
360
 
                // did we get multiple elements? do one after another
361
 
                // array('message' => ..., 'presence' => ...)
362
 
                if (sizeof($xml) > 1)
363
 
                {
364
 
                        foreach ($xml as $key => $value)
365
 
                        {
366
 
                                $this->response(array($key => $value));
367
 
                        }
368
 
                        return;
369
 
                }
370
 
                else
371
 
                {
372
 
                        // or even multiple elements of the same type?
373
 
                        // array('message' => array(0 => ..., 1 => ...))
374
 
                        if (sizeof(reset($xml)) > 1)
375
 
                        {
376
 
                                foreach (reset($xml) as $value)
377
 
                                {
378
 
                                        $this->response(array(key($xml) => array(0 => $value)));
379
 
                                }
380
 
                                return;
381
 
                        }
382
 
                }
383
 
 
384
 
                switch (key($xml))
385
 
                {
386
 
                        case 'stream:stream':
387
 
                                // Connection initialised (or after authentication). Not much to do here...
388
 
                                $this->session['id'] = $xml['stream:stream'][0]['@']['id'];
389
 
 
390
 
                                if (isset($xml['stream:stream'][0]['#']['stream:features']))
391
 
                                {
392
 
                                        // we already got all info we need
393
 
                                        $this->features = $xml['stream:stream'][0]['#'];
394
 
                                }
395
 
                                else
396
 
                                {
397
 
                                        $this->features = $this->listen();
398
 
                                }
399
 
 
400
 
                                // go on with authentication?
401
 
                                if (isset($this->features['stream:features'][0]['#']['bind']) || !empty($this->session['tls']))
402
 
                                {
403
 
                                        return $this->response($this->features);
404
 
                                }
405
 
                        break;
406
 
 
407
 
                        case 'stream:features':
408
 
                                // Resource binding after successful authentication
409
 
                                if (isset($this->session['authenticated']))
410
 
                                {
411
 
                                        // session required?
412
 
                                        $this->session['sess_required'] = isset($xml['stream:features'][0]['#']['session']);
413
 
 
414
 
                                        $this->send("<iq type='set' id='bind_1'>
415
 
                                                <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
416
 
                                                        <resource>" . utf8_htmlspecialchars($this->resource) . '</resource>
417
 
                                                </bind>
418
 
                                        </iq>');
419
 
                                        return $this->response($this->listen());
420
 
                                }
421
 
 
422
 
                                // Let's use TLS if SSL is not enabled and we can actually use it
423
 
                                if (!$this->session['ssl'] && $this->can_use_tls() && $this->can_use_ssl() && isset($xml['stream:features'][0]['#']['starttls']))
424
 
                                {
425
 
                                        $this->add_to_log('Switching to TLS.');
426
 
                                        $this->send("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n");
427
 
                                        return $this->response($this->listen());
428
 
                                }
429
 
 
430
 
                                // Does the server support SASL authentication?
431
 
 
432
 
                                // I hope so, because we do (and no other method).
433
 
                                if (isset($xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns']) && $xml['stream:features'][0]['#']['mechanisms'][0]['@']['xmlns'] == 'urn:ietf:params:xml:ns:xmpp-sasl')
434
 
                                {
435
 
                                        // Now decide on method
436
 
                                        $methods = array();
437
 
 
438
 
                                        foreach ($xml['stream:features'][0]['#']['mechanisms'][0]['#']['mechanism'] as $value)
439
 
                                        {
440
 
                                                $methods[] = $value['#'];
441
 
                                        }
442
 
 
443
 
                                        // we prefer DIGEST-MD5
444
 
                                        // we don't want to use plain authentication (neither does the server usually) if no encryption is in place
445
 
 
446
 
                                        // http://www.xmpp.org/extensions/attic/jep-0078-1.7.html
447
 
                                        // The plaintext mechanism SHOULD NOT be used unless the underlying stream is encrypted (using SSL or TLS)
448
 
                                        // and the client has verified that the server certificate is signed by a trusted certificate authority.
449
 
 
450
 
                                        if (in_array('DIGEST-MD5', $methods))
451
 
                                        {
452
 
                                                $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='DIGEST-MD5'/>");
453
 
                                        }
454
 
                                        else if (in_array('PLAIN', $methods) && ($this->session['ssl'] || !empty($this->session['tls'])))
455
 
                                        {
456
 
                                                $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>"
457
 
                                                        . base64_encode(chr(0) . $this->username . '@' . $this->server . chr(0) . $this->password) .
458
 
                                                        '</auth>');
459
 
                                        }
460
 
                                        else if (in_array('ANONYMOUS', $methods))
461
 
                                        {
462
 
                                                $this->send("<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'/>");
463
 
                                        }
464
 
                                        else
465
 
                                        {
466
 
                                                // not good...
467
 
                                                $this->add_to_log('Error: No authentication method supported.');
468
 
                                                $this->disconnect();
469
 
                                                return false;
470
 
                                        }
471
 
 
472
 
                                        return $this->response($this->listen());
473
 
                                }
474
 
                                else
475
 
                                {
476
 
                                        // ok, this is it. bye.
477
 
                                        $this->add_to_log('Error: Server does not offer SASL authentication.');
478
 
                                        $this->disconnect();
479
 
                                        return false;
480
 
                                }
481
 
                        break;
482
 
 
483
 
                        case 'challenge':
484
 
                                // continue with authentication...a challenge literally -_-
485
 
                                $decoded = base64_decode($xml['challenge'][0]['#']);
486
 
                                $decoded = $this->parse_data($decoded);
487
 
 
488
 
                                if (!isset($decoded['digest-uri']))
489
 
                                {
490
 
                                        $decoded['digest-uri'] = 'xmpp/'. $this->server;
491
 
                                }
492
 
 
493
 
                                // better generate a cnonce, maybe it's needed
494
 
                                $str = '';
495
 
                                mt_srand((double)microtime()*10000000);
496
 
 
497
 
                                for ($i = 0; $i < 32; $i++)
498
 
                                {
499
 
                                        $str .= chr(mt_rand(0, 255));
500
 
                                }
501
 
                                $decoded['cnonce'] = base64_encode($str);
502
 
 
503
 
                                // second challenge?
504
 
                                if (isset($decoded['rspauth']))
505
 
                                {
506
 
                                        $this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
507
 
                                }
508
 
                                else
509
 
                                {
510
 
                                        // Make sure we only use 'auth' for qop (relevant for $this->encrypt_password())
511
 
                                        // If the <response> is choking up on the changed parameter we may need to adjust encrypt_password() directly
512
 
                                        if (isset($decoded['qop']) && $decoded['qop'] != 'auth' && strpos($decoded['qop'], 'auth') !== false)
513
 
                                        {
514
 
                                                $decoded['qop'] = 'auth';
515
 
                                        }
516
 
 
517
 
                                        $response = array(
518
 
                                                'username'      => $this->username,
519
 
                                                'response'      => $this->encrypt_password(array_merge($decoded, array('nc' => '00000001'))),
520
 
                                                'charset'       => 'utf-8',
521
 
                                                'nc'            => '00000001',
522
 
                                        );
523
 
 
524
 
                                        foreach (array('nonce', 'qop', 'digest-uri', 'realm', 'cnonce') as $key)
525
 
                                        {
526
 
                                                if (isset($decoded[$key]))
527
 
                                                {
528
 
                                                        $response[$key] = $decoded[$key];
529
 
                                                }
530
 
                                        }
531
 
 
532
 
                                        $this->send("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" . base64_encode($this->implode_data($response)) . '</response>');
533
 
                                }
534
 
 
535
 
                                return $this->response($this->listen());
536
 
                        break;
537
 
 
538
 
                        case 'failure':
539
 
                                $this->add_to_log('Error: Server sent "failure".');
540
 
                                $this->disconnect();
541
 
                                return false;
542
 
                        break;
543
 
 
544
 
                        case 'proceed':
545
 
                                // continue switching to TLS
546
 
                                $meta = stream_get_meta_data($this->connection);
547
 
                                socket_set_blocking($this->connection, 1);
548
 
 
549
 
                                if (!stream_socket_enable_crypto($this->connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT))
550
 
                                {
551
 
                                        $this->add_to_log('Error: TLS mode change failed.');
552
 
                                        return false;
553
 
                                }
554
 
 
555
 
                                socket_set_blocking($this->connection, $meta['blocked']);
556
 
                                $this->session['tls'] = true;
557
 
 
558
 
                                // new stream
559
 
                                $this->send("<?xml version='1.0' encoding='UTF-8' ?" . ">\n");
560
 
                                $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n");
561
 
 
562
 
                                return $this->response($this->listen());
563
 
                        break;
564
 
 
565
 
                        case 'success':
566
 
                                // Yay, authentication successful.
567
 
                                $this->send("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n");
568
 
                                $this->session['authenticated'] = true;
569
 
 
570
 
                                // we have to wait for another response
571
 
                                return $this->response($this->listen());
572
 
                        break;
573
 
 
574
 
                        case 'iq':
575
 
                                // we are not interested in IQs we did not expect
576
 
                                if (!isset($xml['iq'][0]['@']['id']))
577
 
                                {
578
 
                                        return false;
579
 
                                }
580
 
 
581
 
                                // multiple possibilities here
582
 
                                switch ($xml['iq'][0]['@']['id'])
583
 
                                {
584
 
                                        case 'bind_1':
585
 
                                                $this->session['jid'] = $xml['iq'][0]['#']['bind'][0]['#']['jid'][0]['#'];
586
 
 
587
 
                                                // and (maybe) yet another request to be able to send messages *finally*
588
 
                                                if ($this->session['sess_required'])
589
 
                                                {
590
 
                                                        $this->send("<iq to='{$this->server}' type='set' id='sess_1'>
591
 
                                                                <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>
592
 
                                                                </iq>");
593
 
                                                        return $this->response($this->listen());
594
 
                                                }
595
 
 
596
 
                                                return true;
597
 
                                        break;
598
 
 
599
 
                                        case 'sess_1':
600
 
                                                return true;
601
 
                                        break;
602
 
 
603
 
                                        case 'reg_1':
604
 
                                                $this->send("<iq type='set' id='reg_2'>
605
 
                                                                <query xmlns='jabber:iq:register'>
606
 
                                                                        <username>" . utf8_htmlspecialchars($this->username) . "</username>
607
 
                                                                        <password>" . utf8_htmlspecialchars($this->password) . "</password>
608
 
                                                                </query>
609
 
                                                        </iq>");
610
 
                                                return $this->response($this->listen());
611
 
                                        break;
612
 
 
613
 
                                        case 'reg_2':
614
 
                                                // registration end
615
 
                                                if (isset($xml['iq'][0]['#']['error']))
616
 
                                                {
617
 
                                                        $this->add_to_log('Warning: Registration failed.');
618
 
                                                        return false;
619
 
                                                }
620
 
                                                return true;
621
 
                                        break;
622
 
 
623
 
                                        case 'unreg_1':
624
 
                                                return true;
625
 
                                        break;
626
 
 
627
 
                                        default:
628
 
                                                $this->add_to_log('Notice: Received unexpected IQ.');
629
 
                                                return false;
630
 
                                        break;
631
 
                                }
632
 
                        break;
633
 
 
634
 
                        case 'message':
635
 
                                // we are only interested in content...
636
 
                                if (!isset($xml['message'][0]['#']['body']))
637
 
                                {
638
 
                                        return false;
639
 
                                }
640
 
 
641
 
                                $message['body'] = $xml['message'][0]['#']['body'][0]['#'];
642
 
                                $message['from'] = $xml['message'][0]['@']['from'];
643
 
 
644
 
                                if (isset($xml['message'][0]['#']['subject']))
645
 
                                {
646
 
                                        $message['subject'] = $xml['message'][0]['#']['subject'][0]['#'];
647
 
                                }
648
 
                                $this->session['messages'][] = $message;
649
 
                        break;
650
 
 
651
 
                        default:
652
 
                                // hm...don't know this response
653
 
                                $this->add_to_log('Notice: Unknown server response (' . key($xml) . ')');
654
 
                                return false;
655
 
                        break;
656
 
                }
657
 
        }
658
 
 
659
 
        function send_message($to, $text, $subject = '', $type = 'normal')
660
 
        {
661
 
                if (!isset($this->session['jid']))
662
 
                {
663
 
                        return false;
664
 
                }
665
 
 
666
 
                if (!in_array($type, array('chat', 'normal', 'error', 'groupchat', 'headline')))
667
 
                {
668
 
                        $type = 'normal';
669
 
                }
670
 
 
671
 
                return $this->send("<message from='" . utf8_htmlspecialchars($this->session['jid']) . "' to='" . utf8_htmlspecialchars($to) . "' type='$type' id='" . uniqid('msg') . "'>
672
 
                        <subject>" . utf8_htmlspecialchars($subject) . "</subject>
673
 
                        <body>" . utf8_htmlspecialchars($text) . "</body>
674
 
                        </message>"
675
 
                );
676
 
        }
677
 
 
678
 
        /**
679
 
        * Encrypts a password as in RFC 2831
680
 
        * @param array $data Needs data from the client-server connection
681
 
        * @access public
682
 
        * @return string
683
 
        */
684
 
        function encrypt_password($data)
685
 
        {
686
 
                // let's me think about <challenge> again...
687
 
                foreach (array('realm', 'cnonce', 'digest-uri') as $key)
688
 
                {
689
 
                        if (!isset($data[$key]))
690
 
                        {
691
 
                                $data[$key] = '';
692
 
                        }
693
 
                }
694
 
 
695
 
                $pack = md5($this->username . ':' . $data['realm'] . ':' . $this->password);
696
 
 
697
 
                if (isset($data['authzid']))
698
 
                {
699
 
                        $a1 = pack('H32', $pack)  . sprintf(':%s:%s:%s', $data['nonce'], $data['cnonce'], $data['authzid']);
700
 
                }
701
 
                else
702
 
                {
703
 
                        $a1 = pack('H32', $pack)  . sprintf(':%s:%s', $data['nonce'], $data['cnonce']);
704
 
                }
705
 
 
706
 
                // should be: qop = auth
707
 
                $a2 = 'AUTHENTICATE:'. $data['digest-uri'];
708
 
 
709
 
                return md5(sprintf('%s:%s:%s:%s:%s:%s', md5($a1), $data['nonce'], $data['nc'], $data['cnonce'], $data['qop'], md5($a2)));
710
 
        }
711
 
 
712
 
        /**
713
 
        * parse_data like a="b",c="d",... or like a="a, b", c, d="e", f=g,...
714
 
        * @param string $data
715
 
        * @access public
716
 
        * @return array a => b ...
717
 
        */
718
 
        function parse_data($data)
719
 
        {
720
 
                $data = explode(',', $data);
721
 
                $pairs = array();
722
 
                $key = false;
723
 
 
724
 
                foreach ($data as $pair)
725
 
                {
726
 
                        $dd = strpos($pair, '=');
727
 
 
728
 
                        if ($dd)
729
 
                        {
730
 
                                $key = trim(substr($pair, 0, $dd));
731
 
                                $pairs[$key] = trim(trim(substr($pair, $dd + 1)), '"');
732
 
                        }
733
 
                        else if (strpos(strrev(trim($pair)), '"') === 0 && $key)
734
 
                        {
735
 
                                // We are actually having something left from "a, b" values, add it to the last one we handled.
736
 
                                $pairs[$key] .= ',' . trim(trim($pair), '"');
737
 
                                continue;
738
 
                        }
739
 
                }
740
 
 
741
 
                return $pairs;
742
 
        }
743
 
 
744
 
        /**
745
 
        * opposite of jabber::parse_data()
746
 
        * @param array $data
747
 
        * @access public
748
 
        * @return string
749
 
        */
750
 
        function implode_data($data)
751
 
        {
752
 
                $return = array();
753
 
                foreach ($data as $key => $value)
754
 
                {
755
 
                        $return[] = $key . '="' . $value . '"';
756
 
                }
757
 
                return implode(',', $return);
758
 
        }
759
 
 
760
 
        /**
761
 
        * xmlize()
762
 
        * @author Hans Anderson
763
 
        * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/
764
 
        */
765
 
        function xmlize($data, $skip_white = 1, $encoding = 'UTF-8')
766
 
        {
767
 
                $data = trim($data);
768
 
 
769
 
                if (substr($data, 0, 5) != '<?xml')
770
 
                {
771
 
                        // mod
772
 
                        $data = '<root>'. $data . '</root>';
773
 
                }
774
 
 
775
 
                $vals = $index = $array = array();
776
 
                $parser = xml_parser_create($encoding);
777
 
                xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
778
 
                xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, $skip_white);
779
 
                xml_parse_into_struct($parser, $data, $vals, $index);
780
 
                xml_parser_free($parser);
781
 
 
782
 
                $i = 0;
783
 
                $tagname = $vals[$i]['tag'];
784
 
 
785
 
                $array[$tagname][0]['@'] = (isset($vals[$i]['attributes'])) ? $vals[$i]['attributes'] : array();
786
 
                $array[$tagname][0]['#'] = $this->_xml_depth($vals, $i);
787
 
 
788
 
                if (substr($data, 0, 5) != '<?xml')
789
 
                {
790
 
                        $array = $array['root'][0]['#'];
791
 
                }
792
 
 
793
 
                return $array;
794
 
        }
795
 
 
796
 
        /**
797
 
        * _xml_depth()
798
 
        * @author Hans Anderson
799
 
        * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/
800
 
        */
801
 
        function _xml_depth($vals, &$i)
802
 
        {
803
 
                $children = array();
804
 
 
805
 
                if (isset($vals[$i]['value']))
806
 
                {
807
 
                        array_push($children, $vals[$i]['value']);
808
 
                }
809
 
 
810
 
                while (++$i < sizeof($vals))
811
 
                {
812
 
                        switch ($vals[$i]['type'])
813
 
                        {
814
 
                                case 'open':
815
 
 
816
 
                                        $tagname = (isset($vals[$i]['tag'])) ? $vals[$i]['tag'] : '';
817
 
                                        $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0;
818
 
 
819
 
                                        if (isset($vals[$i]['attributes']))
820
 
                                        {
821
 
                                                $children[$tagname][$size]['@'] = $vals[$i]['attributes'];
822
 
                                        }
823
 
 
824
 
                                        $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i);
825
 
 
826
 
                                break;
827
 
 
828
 
                                case 'cdata':
829
 
                                        array_push($children, $vals[$i]['value']);
830
 
                                break;
831
 
 
832
 
                                case 'complete':
833
 
 
834
 
                                        $tagname = $vals[$i]['tag'];
835
 
                                        $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0;
836
 
                                        $children[$tagname][$size]['#'] = (isset($vals[$i]['value'])) ? $vals[$i]['value'] : array();
837
 
 
838
 
                                        if (isset($vals[$i]['attributes']))
839
 
                                        {
840
 
                                                $children[$tagname][$size]['@'] = $vals[$i]['attributes'];
841
 
                                        }
842
 
 
843
 
                                break;
844
 
 
845
 
                                case 'close':
846
 
                                        return $children;
847
 
                                break;
848
 
                        }
849
 
                }
850
 
 
851
 
                return $children;
852
 
        }
853
 
}
854
 
 
855
 
?>
 
 
b'\\ No newline at end of file'