[ Index ] |
PHP Cross Reference of phpBB 3.0 Beta 3 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * @package phpBB3 5 * @version $Id: functions_jabber.php,v 1.23 2006/11/03 17:49:08 acydburn Exp $ 6 * @copyright (c) 2006 phpBB Group 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 8 * 9 */ 10 11 /** 12 * 13 * Class.Jabber.PHP v0.4.2 14 * (c) 2004 Nathan "Fritzy" Fritz 15 * http://cjphp.netflint.net *** fritzy@netflint.net 16 * 17 * This is a bugfix version, specifically for those who can't get 18 * 0.4 to work on Jabberd2 servers. 19 * 20 * last modified: 24.03.2004 13:01:53 21 * 22 * Modified by phpBB Development Team 23 * version: v0.4.3a 24 * 25 * @package phpBB3 26 */ 27 class jabber 28 { 29 var $server; 30 var $port; 31 var $username; 32 var $password; 33 var $resource; 34 var $jid; 35 36 var $connection; 37 var $delay_disconnect; 38 39 var $stream_id; 40 41 var $enable_logging; 42 var $log_array; 43 44 var $iq_sleep_timer; 45 var $last_ping_time; 46 47 var $packet_queue; 48 49 var $iq_version_name; 50 var $iq_version_os; 51 var $iq_version_version; 52 53 var $error_codes; 54 55 var $connected; 56 var $keep_alive_id; 57 var $returned_keep_alive; 58 var $txnid; 59 60 var $connector; 61 62 /** 63 * Constructor 64 */ 65 function jabber($server, $port, $username, $password, $resource) 66 { 67 $this->server = ($server) ? $server : 'localhost'; 68 $this->port = ($port) ? $port : '5222'; 69 $this->username = $username; 70 $this->password = $password; 71 $this->resource = ($resource) ? $resource : NULL; 72 73 $this->enable_logging = true; 74 $this->log_array = array(); 75 76 $this->packet_queue = array(); 77 $this->iq_sleep_timer = $this->delay_disconnect = 1; 78 79 $this->returned_keep_alive = true; 80 $this->txnid = 0; 81 82 $this->iq_version_name = "Class.Jabber.PHP -- http://cjphp.netflint.net -- by Nathan 'Fritzy' Fritz, fritz@netflint.net"; 83 $this->iq_version_version = '0.4'; 84 $this->iq_version_os = $_SERVER['SERVER_SOFTWARE']; 85 86 $this->error_codes = array( 87 400 => 'Bad Request', 88 401 => 'Unauthorized', 89 402 => 'Payment Required', 90 403 => 'Forbidden', 91 404 => 'Not Found', 92 405 => 'Not Allowed', 93 406 => 'Not Acceptable', 94 407 => 'Registration Required', 95 408 => 'Request Timeout', 96 409 => 'Conflict', 97 500 => 'Internal Server Error', 98 501 => 'Not Implemented', 99 502 => 'Remove Server Error', 100 503 => 'Service Unavailable', 101 504 => 'Remove Server Timeout', 102 510 => 'Disconnected' 103 ); 104 } 105 106 /** 107 * Connect 108 */ 109 function connect() 110 { 111 $this->connector = new cjp_standard_connector; 112 113 if ($this->connector->open_socket($this->server, $this->port)) 114 { 115 $this->send_packet("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); 116 $this->send_packet("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); 117 118 sleep(2); 119 120 if ($this->_check_connected()) 121 { 122 $this->connected = true; // Nathan Fritz 123 return true; 124 } 125 else 126 { 127 $this->add_to_log('ERROR: connect() #1'); 128 return false; 129 } 130 } 131 else 132 { 133 $this->add_to_log('ERROR: connect() #2'); 134 return false; 135 } 136 } 137 138 /** 139 * Disconnect 140 */ 141 function disconnect() 142 { 143 if (is_int($this->delay_disconnect)) 144 { 145 sleep($this->delay_disconnect); 146 } 147 148 $this->send_packet('</stream:stream>'); 149 $this->connector->close_socket(); 150 } 151 152 /** 153 * Send authentication request 154 */ 155 function send_auth() 156 { 157 $this->auth_id = 'auth_' . md5(time() . $_SERVER['REMOTE_ADDR']); 158 $this->resource = ($this->resource != NULL) ? $this->resource : ('Class.Jabber.PHP ' . md5($this->auth_id)); 159 $this->jid = "{$this->username}@{$this->server}/{$this->resource}"; 160 161 // request available authentication methods 162 $payload = "<username>{$this->username}</username>"; 163 $packet = $this->send_iq(NULL, 'get', $this->auth_id, 'jabber:iq:auth', $payload); 164 165 // was a result returned? 166 if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) 167 { 168 // yes, now check for auth method availability in descending order (best to worst) 169 if (isset($packet['iq']['#']['query'][0]['#']['sequence'][0]['#']) && isset($packet['iq']['#']['query'][0]['#']['token'][0]['#'])) 170 { 171 // auth_0k 172 return $this->_sendauth_ok($packet['iq']['#']['query'][0]['#']['token'][0]['#'], $packet['iq']['#']['query'][0]['#']['sequence'][0]['#']); 173 } 174 else if (isset($packet['iq']['#']['query'][0]['#']['digest'])) 175 { 176 // digest 177 return $this->_sendauth_digest(); 178 } 179 else if ($packet['iq']['#']['query'][0]['#']['password']) 180 { 181 // plain text 182 return $this->_sendauth_plaintext(); 183 } 184 else 185 { 186 $this->add_to_log('ERROR: send_auth() #2 - No auth method available!'); 187 return false; 188 } 189 } 190 else 191 { 192 // no result returned 193 $this->add_to_log('ERROR: send_auth() #1'); 194 return false; 195 } 196 } 197 198 /** 199 * Register account 200 */ 201 function account_registration($reg_email = NULL, $reg_name = NULL) 202 { 203 $packet = $this->send_iq($this->server, 'get', 'reg_01', 'jabber:iq:register'); 204 205 if ($packet) 206 { 207 // just in case a key was passed back from the server 208 $key = $this->get_info_from_iq_key($packet); 209 unset($packet); 210 211 $payload = "<username>{$this->username}</username> 212 <password>{$this->password}</password> 213 <email>$reg_email</email> 214 <name>$reg_name</name>\n"; 215 216 $payload .= ($key) ? "<key>$key</key>\n" : ''; 217 218 $packet = $this->send_iq($this->server, 'set', 'reg_01', 'jabber:iq:register', $payload); 219 220 if ($this->get_info_from_iq_type($packet) == 'result') 221 { 222 $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; 223 $this->jid = ($this->resource) ? "{$this->username}@{$this->server}/{$this->resource}" : "{$this->username}@{$this->server}"; 224 } 225 else if ($this->get_info_from_iq_type($packet) == 'error' && isset($packet['iq']['#']['error'][0]['#'])) 226 { 227 // "conflict" error, i.e. already registered 228 if ($packet['iq']['#']['error'][0]['@']['code'] == '409') 229 { 230 $return_code = 1; 231 } 232 else 233 { 234 $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; 235 } 236 } 237 238 return $return_code; 239 } 240 else 241 { 242 return 3; 243 } 244 } 245 246 /** 247 * Change password 248 */ 249 function change_password($new_password) 250 { 251 $packet = $this->send_iq($this->server, 'get', 'A0', 'jabber:iq:register'); 252 253 if ($packet) 254 { 255 // just in case a key was passed back from the server 256 $key = $this->get_info_from_iq_key($packet); 257 unset($packet); 258 259 $payload = "<username>{$this->username}</username> 260 <password>{$new_password}</password>\n"; 261 $payload .= ($key) ? "<key>$key</key>\n" : ''; 262 263 $packet = $this->send_iq($this->server, 'set', 'A0', 'jabber:iq:register', $payload); 264 265 if ($this->get_info_from_iq_type($packet) == 'result') 266 { 267 $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; 268 } 269 else if ($this->get_info_from_iq_type($packet) == 'error' && isset($packet['iq']['#']['error'][0]['#'])) 270 { 271 // "conflict" error, i.e. already registered 272 if ($packet['iq']['#']['error'][0]['@']['code'] == '409') 273 { 274 $return_code = 1; 275 } 276 else 277 { 278 $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; 279 } 280 } 281 282 return $return_code; 283 } 284 else 285 { 286 return 3; 287 } 288 } 289 290 /** 291 * Send packet 292 */ 293 function send_packet($xml) 294 { 295 $xml = trim($xml); 296 297 if ($this->connector->write_to_socket($xml)) 298 { 299 $this->add_to_log('SEND: ' . $xml); 300 return true; 301 } 302 else 303 { 304 $this->add_to_log('ERROR: send_packet() #1'); 305 return false; 306 } 307 } 308 309 /** 310 * Listen to socket 311 */ 312 function listen() 313 { 314 $incoming = ''; 315 316 while ($line = $this->connector->read_from_socket(4096)) 317 { 318 $incoming .= $line; 319 } 320 321 $incoming = trim($incoming); 322 323 if ($incoming != '') 324 { 325 $this->add_to_log('RECV: ' . $incoming); 326 $temp = $this->_split_incoming($incoming); 327 328 for ($i = 0, $size = sizeof($temp); $i < $size; $i++) 329 { 330 $this->packet_queue[] = $this->xmlize($temp[$i]); 331 } 332 } 333 334 return true; 335 } 336 337 /** 338 * Strip jid 339 */ 340 function strip_jid($jid = NULL) 341 { 342 preg_match('#(.*)\/(.*)#Ui', $jid, $temp); 343 return ($temp[1] != '') ? $temp[1] : $jid; 344 } 345 346 /** 347 * Send a message 348 */ 349 function send_message($to, $type = 'normal', $id = NULL, $content = NULL, $payload = NULL) 350 { 351 if ($to && is_array($content)) 352 { 353 if (!$id) 354 { 355 $id = $type . '_' . time(); 356 } 357 358 $this->_array_xmlspecialchars($content); 359 360 $xml = "<message to='$to' type='$type' id='$id'>\n"; 361 362 if (!empty($content['subject'])) 363 { 364 $xml .= '<subject>' . $content['subject'] . "</subject>\n"; 365 } 366 367 if (!empty($content['thread'])) 368 { 369 $xml .= '<thread>' . $content['thread'] . "</thread>\n"; 370 } 371 372 $xml .= '<body>' . $content['body'] . "</body>\n"; 373 $xml .= $payload; 374 $xml .= "</message>\n"; 375 376 if ($this->send_packet($xml)) 377 { 378 return true; 379 } 380 else 381 { 382 $this->add_to_log('ERROR: send_message() #1'); 383 } 384 } 385 else 386 { 387 $this->add_to_log('ERROR: send_message() #2'); 388 return false; 389 } 390 } 391 392 /** 393 * Send presence 394 */ 395 function send_presence($type = NULL, $to = NULL, $status = NULL, $show = NULL, $priority = NULL) 396 { 397 $xml = '<presence'; 398 $xml .= ($to) ? " to='$to'" : ''; 399 $xml .= ($type) ? " type='$type'" : ''; 400 $xml .= ($status || $show || $priority) ? ">\n" : " />\n"; 401 402 $xml .= ($status) ? " <status>$status</status>\n" : ''; 403 $xml .= ($show) ? " <show>$show</show>\n" : ''; 404 $xml .= ($priority) ? " <priority>$priority</priority>\n" : ''; 405 406 $xml .= ($status || $show || $priority) ? "</presence>\n" : ''; 407 408 if ($this->send_packet($xml)) 409 { 410 return true; 411 } 412 else 413 { 414 $this->add_to_log('ERROR: send_presence() #1'); 415 return false; 416 } 417 } 418 419 /** 420 * Send error 421 */ 422 function send_error($to, $id = NULL, $error_number, $error_message = NULL) 423 { 424 $xml = "<iq type='error' to='$to'"; 425 $xml .= ($id) ? " id='$id'" : ''; 426 $xml .= ">\n"; 427 $xml .= " <error code='$error_number'>"; 428 $xml .= ($error_message) ? $error_message : $this->error_codes[$error_number]; 429 $xml .= "</error>\n"; 430 $xml .= '</iq>'; 431 432 $this->send_packet($xml); 433 } 434 435 /** 436 * Get first from queue 437 */ 438 function get_first_from_queue() 439 { 440 return array_shift($this->packet_queue); 441 } 442 443 /** 444 * Get from queue by id 445 */ 446 function get_from_queue_by_id($packet_type, $id) 447 { 448 $found_message = false; 449 450 foreach ($this->packet_queue as $key => $value) 451 { 452 if ($value[$packet_type]['@']['id'] == $id) 453 { 454 $found_message = $value; 455 unset($this->packet_queue[$key]); 456 457 break; 458 } 459 } 460 461 return (is_array($found_message)) ? $found_message : false; 462 } 463 464 /** 465 * Call handler 466 */ 467 function call_handler($packet = NULL) 468 { 469 $packet_type = $this->_get_packet_type($packet); 470 471 if ($packet_type == 'message') 472 { 473 $type = $packet['message']['@']['type']; 474 $type = ($type != '') ? $type : 'normal'; 475 $funcmeth = "handler_message_$type"; 476 } 477 else if ($packet_type == 'iq') 478 { 479 $namespace = $packet['iq']['#']['query'][0]['@']['xmlns']; 480 $namespace = str_replace(':', '_', $namespace); 481 $funcmeth = "handler_iq_$namespace"; 482 } 483 else if ($packet_type == 'presence') 484 { 485 $type = $packet['presence']['@']['type']; 486 $type = ($type != '') ? $type : 'available'; 487 $funcmeth = "handler_presence_$type"; 488 } 489 490 if ($funcmeth != '') 491 { 492 if (function_exists($funcmeth)) 493 { 494 call_user_func($funcmeth, $packet); 495 } 496 else if (method_exists($this, $funcmeth)) 497 { 498 call_user_func(array(&$this, $funcmeth), $packet); 499 } 500 else 501 { 502 $this->handler_not_implemented($packet); 503 $this->add_to_log("ERROR: call_handler() #1 - neither method nor function $funcmeth() available"); 504 } 505 } 506 } 507 508 /** 509 * Cruise Control 510 */ 511 function cruise_control($seconds = -1) 512 { 513 $count = 0; 514 515 while ($count != $seconds) 516 { 517 $this->listen(); 518 519 do 520 { 521 $packet = $this->get_first_from_queue(); 522 523 if ($packet) 524 { 525 $this->call_handler($packet); 526 } 527 } 528 while (sizeof($this->packet_queue) > 1); 529 530 $count += 0.25; 531 usleep(250000); 532 533 if (($this->last_ping_time + 180) < time()) 534 { 535 // Modified by Nathan Fritz 536 if ($this->returned_keep_alive == false) 537 { 538 $this->connected = false; 539 $this->add_to_log('EVENT: Disconnected'); 540 } 541 542 if ($this->returned_keep_alive == true) 543 { 544 $this->connected = true; 545 } 546 547 $this->returned_keep_alive = false; 548 549 $this->keep_alive_id = 'keep_alive_' . time(); 550 // $this->send_packet("<iq id='{$this->keep_alive_id}'/>", 'cruise_control'); 551 $this->send_packet("<iq type='get' from='{$this->username}@{$this->server}/{$this->resource}' to='{$this->server}' id='{$this->keep_alive_id}'><query xmlns='jabber:iq:time' /></iq>"); 552 $this->last_ping_time = time(); 553 } 554 } 555 556 return true; 557 } 558 559 /** 560 * Send iq 561 */ 562 function send_iq($to = NULL, $type = 'get', $id = NULL, $xmlns = NULL, $payload = NULL, $from = NULL) 563 { 564 if (!preg_match('#^(get|set|result|error)$#', $type)) 565 { 566 unset($type); 567 568 $this->add_to_log("ERROR: send_iq() #2 - type must be 'get', 'set', 'result' or 'error'"); 569 return false; 570 } 571 else if ($id && $xmlns) 572 { 573 $xml = "<iq type='$type' id='$id'"; 574 $xml .= ($to) ? " to='" . htmlspecialchars($to) . "'" : ''; 575 $xml .= ($from) ? " from='$from'" : ''; 576 $xml .= "> 577 <query xmlns='$xmlns'> 578 $payload 579 </query> 580 </iq>"; 581 582 $this->send_packet($xml); 583 sleep($this->iq_sleep_timer); 584 $this->listen(); 585 586 return (preg_match('#^(get|set)$#', $type)) ? $this->get_from_queue_by_id('iq', $id) : true; 587 } 588 else 589 { 590 $this->add_to_log('ERROR: send_iq() #1 - to, id and xmlns are mandatory'); 591 return false; 592 } 593 } 594 595 /** 596 * get the transport registration fields 597 * method written by Steve Blinch, http://www.blitzaffe.com 598 */ 599 function transport_registration_details($transport) 600 { 601 $this->txnid++; 602 $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); 603 604 if ($packet) 605 { 606 $res = array(); 607 608 foreach ($packet['iq']['#']['query'][0]['#'] as $element => $data) 609 { 610 if ($element != 'instructions' && $element != 'key') 611 { 612 $res[] = $element; 613 } 614 } 615 616 return $res; 617 } 618 else 619 { 620 return 3; 621 } 622 } 623 624 /** 625 * register with the transport 626 * method written by Steve Blinch, http://www.blitzaffe.com 627 */ 628 function transport_registration($transport, $details) 629 { 630 $this->txnid++; 631 $packet = $this->send_iq($transport, 'get', "reg_{$this->txnid}", 'jabber:iq:register', NULL, $this->jid); 632 633 if ($packet) 634 { 635 // just in case a key was passed back from the server 636 $key = $this->get_info_from_iq_key($packet); 637 unset($packet); 638 639 $payload = ($key) ? "<key>$key</key>\n" : ''; 640 foreach ($details as $element => $value) 641 { 642 $payload .= "<$element>$value</$element>\n"; 643 } 644 645 $packet = $this->send_iq($transport, 'set', "reg_{$this->txnid}", 'jabber:iq:register', $payload); 646 647 if ($this->get_info_from_iq_type($packet) == 'result') 648 { 649 $return_code = (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) ? 1 : 2; 650 } 651 else if ($this->get_info_from_iq_type($packet) == 'error') 652 { 653 if (isset($packet['iq']['#']['error'][0]['#'])) 654 { 655 $return_code = 'Error ' . $packet['iq']['#']['error'][0]['@']['code'] . ': ' . $packet['iq']['#']['error'][0]['#']; 656 $this->add_to_log('ERROR: transport_registration()'); 657 } 658 } 659 660 return $return_code; 661 } 662 else 663 { 664 return 3; 665 } 666 } 667 668 /** 669 * Return log 670 */ 671 function get_log() 672 { 673 if ($this->enable_logging && sizeof($this->log_array)) 674 { 675 return implode("\n\n", $this->log_array); 676 } 677 678 return ''; 679 } 680 681 /** 682 * Add information to log 683 */ 684 function add_to_log($string) 685 { 686 if ($this->enable_logging) 687 { 688 $this->log_array[] = htmlspecialchars($string); 689 } 690 } 691 692 693 // ====================================================================== 694 // private methods 695 // ====================================================================== 696 697 /** 698 * Send auth 699 * @access private 700 */ 701 function _sendauth_ok($zerok_token, $zerok_sequence) 702 { 703 // initial hash of password 704 $zerok_hash = sha1($this->password); 705 706 // sequence 0: hash of hashed-password and token 707 $zerok_hash = sha1($zerok_hash . $zerok_token); 708 709 // repeat as often as needed 710 for ($i = 0; $i < $zerok_sequence; $i++) 711 { 712 $zerok_hash = sha1($zerok_hash); 713 } 714 715 $payload = "<username>{$this->username}</username> 716 <hash>$zerok_hash</hash> 717 <resource>{$this->resource}</resource>"; 718 719 $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); 720 721 // was a result returned? 722 if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) 723 { 724 return true; 725 } 726 else 727 { 728 $this->add_to_log('ERROR: _sendauth_ok() #1'); 729 return false; 730 } 731 } 732 733 /** 734 * Send auth digest 735 * @access private 736 */ 737 function _sendauth_digest() 738 { 739 $payload = "<username>{$this->username}</username> 740 <resource>{$this->resource}</resource> 741 <digest>" . sha1($this->stream_id . $this->password) . "</digest>"; 742 743 $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); 744 745 // was a result returned? 746 if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) 747 { 748 return true; 749 } 750 else 751 { 752 $this->add_to_log('ERROR: _sendauth_digest() #1'); 753 return false; 754 } 755 } 756 757 /** 758 * Send auth plain 759 * @access private 760 */ 761 function _sendauth_plaintext() 762 { 763 $payload = "<username>{$this->username}</username> 764 <password>{$this->password}</password> 765 <resource>{$this->resource}</resource>"; 766 767 $packet = $this->send_iq(NULL, 'set', $this->auth_id, 'jabber:iq:auth', $payload); 768 769 // was a result returned? 770 if ($this->get_info_from_iq_type($packet) == 'result' && $this->get_info_from_iq_id($packet) == $this->auth_id) 771 { 772 return true; 773 } 774 else 775 { 776 $this->add_to_log('ERROR: _sendauth_plaintext() #1'); 777 return false; 778 } 779 } 780 781 /** 782 * Listen on socket 783 * @access private 784 */ 785 function _listen_incoming() 786 { 787 $incoming = ''; 788 789 while ($line = $this->connector->read_from_socket(4096)) 790 { 791 $incoming .= $line; 792 } 793 794 $incoming = trim($incoming); 795 796 if ($incoming != '') 797 { 798 $this->add_to_log('RECV: ' . $incoming); 799 } 800 801 return $this->xmlize($incoming); 802 } 803 804 /** 805 * Check if connected 806 * @access private 807 */ 808 function _check_connected() 809 { 810 $incoming_array = $this->_listen_incoming(); 811 812 if (is_array($incoming_array)) 813 { 814 if ($incoming_array['stream:stream']['@']['from'] == $this->server && $incoming_array['stream:stream']['@']['xmlns'] == 'jabber:client' && $incoming_array['stream:stream']['@']['xmlns:stream'] == 'http://etherx.jabber.org/streams') 815 { 816 $this->stream_id = $incoming_array['stream:stream']['@']['id']; 817 818 if (!empty($incoming_array['stream:stream']['#']['stream:features'][0]['#']['starttls'][0]['@']['xmlns']) && $incoming_array['stream:stream']['#']['stream:features'][0]['#']['starttls'][0]['@']['xmlns'] == 'urn:ietf:params:xml:ns:xmpp-tls') 819 { 820 return $this->_starttls(); 821 } 822 else 823 { 824 return true; 825 } 826 } 827 else 828 { 829 $this->add_to_log('ERROR: _check_connected() #1'); 830 return false; 831 } 832 } 833 else 834 { 835 $this->add_to_log('ERROR: _check_connected() #2'); 836 return false; 837 } 838 } 839 840 /** 841 * Start TLS/SSL session if supported (PHP5.1) 842 * @access private 843 */ 844 function _starttls() 845 { 846 if (!function_exists('stream_socket_enable_crypto') || !function_exists('stream_get_meta_data') || !function_exists('socket_set_blocking')) 847 { 848 $this->add_to_log('WARNING: TLS is not available'); 849 return true; 850 } 851 852 $this->send_packet("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n"); 853 sleep(2); 854 $incoming_array = $this->_listen_incoming(); 855 856 if (!is_array($incoming_array)) 857 { 858 $this->add_to_log('ERROR: _starttls() #1'); 859 return false; 860 } 861 862 if ($incoming_array['proceed']['@']['xmlns'] != 'urn:ietf:params:xml:ns:xmpp-tls') 863 { 864 $this->add_to_log('ERROR: _starttls() #2'); 865 return false; 866 } 867 868 $meta = stream_get_meta_data($this->connector->active_socket); 869 socket_set_blocking($this->connector->active_socket, 1); 870 871 if (!stream_socket_enable_crypto($this->connector->active_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) 872 { 873 socket_set_blocking($this->connector->active_socket, $meta['blocked']); 874 $this->add_to_log('ERROR: _starttls() #3'); 875 return false; 876 } 877 socket_set_blocking($this->connector->active_socket, $meta['blocked']); 878 879 $this->send_packet("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); 880 $this->send_packet("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>\n"); 881 sleep(2); 882 883 if (!$this->_check_connected()) 884 { 885 $this->add_to_log('ERROR: _starttls() #4'); 886 return false; 887 } 888 889 return true; 890 } 891 892 /** 893 * Get packet type 894 * @access private 895 */ 896 function _get_packet_type($packet = NULL) 897 { 898 if (is_array($packet)) 899 { 900 reset($packet); 901 $packet_type = key($packet); 902 } 903 904 return ($packet_type) ? $packet_type : false; 905 } 906 907 /** 908 * Split incoming packet 909 * @access private 910 */ 911 function _split_incoming($incoming) 912 { 913 $temp = preg_split('#<(message|iq|presence|stream)#', $incoming, -1, PREG_SPLIT_DELIM_CAPTURE); 914 $array = array(); 915 916 for ($i = 1, $size = sizeof($temp); $i < $size; $i += 2) 917 { 918 $array[] = '<' . $temp[$i] . $temp[($i + 1)]; 919 } 920 921 return $array; 922 } 923 924 /** 925 * Recursively prepares the strings in an array to be used in XML data. 926 * @access private 927 */ 928 function _array_xmlspecialchars(&$array) 929 { 930 if (is_array($array)) 931 { 932 foreach ($array as $k => $v) 933 { 934 if (is_array($v)) 935 { 936 $this->_array_xmlspecialchars($array[$k]); 937 } 938 else 939 { 940 $this->_xmlspecialchars($array[$k]); 941 } 942 } 943 } 944 } 945 946 /** 947 * Prepares a string for usage in XML data. 948 * @access private 949 */ 950 function _xmlspecialchars(&$string) 951 { 952 // we only have a few entities in xml 953 $string = str_replace(array('&', '>', '<', '"', '\''), array('&', '>', '<', '"', '''), $string); 954 } 955 956 // ====================================================================== 957 // <message/> parsers 958 // ====================================================================== 959 960 /** 961 * Get info from message (from) 962 */ 963 function get_info_from_message_from($packet = NULL) 964 { 965 return (is_array($packet)) ? $packet['message']['@']['from'] : false; 966 } 967 968 /** 969 * Get info from message (type) 970 */ 971 function get_info_from_message_type($packet = NULL) 972 { 973 return (is_array($packet)) ? $packet['message']['@']['type'] : false; 974 } 975 976 /** 977 * Get info from message (id) 978 */ 979 function get_info_from_message_id($packet = NULL) 980 { 981 return (is_array($packet)) ? $packet['message']['@']['id'] : false; 982 } 983 984 /** 985 * Get info from message (thread) 986 */ 987 function get_info_from_message_thread($packet = NULL) 988 { 989 return (is_array($packet)) ? $packet['message']['#']['thread'][0]['#'] : false; 990 } 991 992 /** 993 * Get info from message (subject) 994 */ 995 function get_info_from_message_subject($packet = NULL) 996 { 997 return (is_array($packet)) ? $packet['message']['#']['subject'][0]['#'] : false; 998 } 999 1000 /** 1001 * Get info from message (body) 1002 */ 1003 function get_info_from_message_body($packet = NULL) 1004 { 1005 return (is_array($packet)) ? $packet['message']['#']['body'][0]['#'] : false; 1006 } 1007 1008 /** 1009 * Get info from message (xmlns) 1010 */ 1011 function get_info_from_message_xmlns($packet = NULL) 1012 { 1013 return (is_array($packet)) ? $packet['message']['#']['x'] : false; 1014 } 1015 1016 /** 1017 * Get info from message (error) 1018 */ 1019 function get_info_from_message_error($packet = NULL) 1020 { 1021 $error = preg_replace('#^\/$#', '', ($packet['message']['#']['error'][0]['@']['code'] . '/' . $packet['message']['#']['error'][0]['#'])); 1022 return (is_array($packet)) ? $error : false; 1023 } 1024 1025 // ====================================================================== 1026 // <iq/> parsers 1027 // ====================================================================== 1028 1029 /** 1030 * Get info from iq (from) 1031 */ 1032 function get_info_from_iq_from($packet = NULL) 1033 { 1034 return (is_array($packet)) ? $packet['iq']['@']['from'] : false; 1035 } 1036 1037 /** 1038 * Get info from iq (type) 1039 */ 1040 function get_info_from_iq_type($packet = NULL) 1041 { 1042 return (is_array($packet)) ? $packet['iq']['@']['type'] : false; 1043 } 1044 1045 /** 1046 * Get info from iq (id) 1047 */ 1048 function get_info_from_iq_id($packet = NULL) 1049 { 1050 return (is_array($packet)) ? $packet['iq']['@']['id'] : false; 1051 } 1052 1053 /** 1054 * Get info from iq (key) 1055 */ 1056 function get_info_from_iq_key($packet = NULL) 1057 { 1058 return (is_array($packet) && isset($packet['iq']['#']['query'][0]['#']['key'][0]['#'])) ? $packet['iq']['#']['query'][0]['#']['key'][0]['#'] : false; 1059 } 1060 1061 /** 1062 * Get info from iq (error) 1063 */ 1064 function get_info_from_iq_error($packet = NULL) 1065 { 1066 $error = preg_replace('#^\/$#', '', ($packet['iq']['#']['error'][0]['@']['code'] . '/' . $packet['iq']['#']['error'][0]['#'])); 1067 return (is_array($packet)) ? $error : false; 1068 } 1069 1070 // ====================================================================== 1071 // <message/> handlers 1072 // ====================================================================== 1073 1074 /** 1075 * Message type normal 1076 */ 1077 function handler_message_normal($packet) 1078 { 1079 $from = $packet['message']['@']['from']; 1080 $this->add_to_log("EVENT: Message (type normal) from $from"); 1081 } 1082 1083 /** 1084 * Message type chat 1085 */ 1086 function handler_message_chat($packet) 1087 { 1088 $from = $packet['message']['@']['from']; 1089 $this->add_to_log("EVENT: Message (type chat) from $from"); 1090 } 1091 1092 /** 1093 * Message type groupchat 1094 */ 1095 function handler_message_groupchat($packet) 1096 { 1097 $from = $packet['message']['@']['from']; 1098 $this->add_to_log("EVENT: Message (type groupchat) from $from"); 1099 } 1100 1101 /** 1102 * Message type headline 1103 */ 1104 function handler_message_headline($packet) 1105 { 1106 $from = $packet['message']['@']['from']; 1107 $this->add_to_log("EVENT: Message (type headline) from $from"); 1108 } 1109 1110 /** 1111 * Message type error 1112 */ 1113 function handler_message_error($packet) 1114 { 1115 $from = $packet['message']['@']['from']; 1116 $this->add_to_log("EVENT: Message (type error) from $from"); 1117 } 1118 1119 // ====================================================================== 1120 // <iq/> handlers 1121 // ====================================================================== 1122 1123 /** 1124 * application version updates 1125 */ 1126 function handler_iq_jabber_iq_autoupdate($packet) 1127 { 1128 $from = $this->get_info_from_iq_from($packet); 1129 $id = $this->get_info_from_iq_id($packet); 1130 1131 $this->send_error($from, $id, 501); 1132 $this->add_to_log("EVENT: jabber:iq:autoupdate from $from"); 1133 } 1134 1135 /** 1136 * interactive server component properties 1137 */ 1138 function handler_iq_jabber_iq_agent($packet) 1139 { 1140 $from = $this->get_info_from_iq_from($packet); 1141 $id = $this->get_info_from_iq_id($packet); 1142 1143 $this->send_error($from, $id, 501); 1144 $this->add_to_log("EVENT: jabber:iq:agent from $from"); 1145 } 1146 1147 /** 1148 * method to query interactive server components 1149 */ 1150 function handler_iq_jabber_iq_agents($packet) 1151 { 1152 $from = $this->get_info_from_iq_from($packet); 1153 $id = $this->get_info_from_iq_id($packet); 1154 1155 $this->send_error($from, $id, 501); 1156 $this->add_to_log("EVENT: jabber:iq:agents from $from"); 1157 } 1158 1159 /** 1160 * simple client authentication 1161 */ 1162 function handler_iq_jabber_iq_auth($packet) 1163 { 1164 $from = $this->get_info_from_iq_from($packet); 1165 $id = $this->get_info_from_iq_id($packet); 1166 1167 $this->send_error($from, $id, 501); 1168 $this->add_to_log("EVENT: jabber:iq:auth from $from"); 1169 } 1170 1171 /** 1172 * out of band data 1173 */ 1174 function handler_iq_jabber_iq_oob($packet) 1175 { 1176 $from = $this->get_info_from_iq_from($packet); 1177 $id = $this->get_info_from_iq_id($packet); 1178 1179 $this->send_error($from, $id, 501); 1180 $this->add_to_log("EVENT: jabber:iq:oob from $from"); 1181 } 1182 1183 /** 1184 * method to store private data on the server 1185 */ 1186 function handler_iq_jabber_iq_private($packet) 1187 { 1188 $from = $this->get_info_from_iq_from($packet); 1189 $id = $this->get_info_from_iq_id($packet); 1190 1191 $this->send_error($from, $id, 501); 1192 $this->add_to_log("EVENT: jabber:iq:private from $from"); 1193 } 1194 1195 /** 1196 * method for interactive registration 1197 */ 1198 function handler_iq_jabber_iq_register($packet) 1199 { 1200 $from = $this->get_info_from_iq_from($packet); 1201 $id = $this->get_info_from_iq_id($packet); 1202 1203 $this->send_error($from, $id, 501); 1204 $this->add_to_log("EVENT: jabber:iq:register from $from"); 1205 } 1206 1207 /** 1208 * client roster management 1209 */ 1210 function handler_iq_jabber_iq_roster($packet) 1211 { 1212 $from = $this->get_info_from_iq_from($packet); 1213 $id = $this->get_info_from_iq_id($packet); 1214 1215 $this->send_error($from, $id, 501); 1216 $this->add_to_log("EVENT: jabber:iq:roster from $from"); 1217 } 1218 1219 /** 1220 * method for searching a user database 1221 */ 1222 function handler_iq_jabber_iq_search($packet) 1223 { 1224 $from = $this->get_info_from_iq_from($packet); 1225 $id = $this->get_info_from_iq_id($packet); 1226 1227 $this->send_error($from, $id, 501); 1228 $this->add_to_log("EVENT: jabber:iq:search from $from"); 1229 } 1230 1231 /** 1232 * method for requesting the current time 1233 */ 1234 function handler_iq_jabber_iq_time($packet) 1235 { 1236 if ($this->keep_alive_id == $this->get_info_from_iq_id($packet)) 1237 { 1238 $this->returned_keep_alive = true; 1239 $this->connected = true; 1240 1241 $this->add_to_log('EVENT: Keep-Alive returned, connection alive.'); 1242 } 1243 1244 $type = $this->get_info_from_iq_type($packet); 1245 $from = $this->get_info_from_iq_from($packet); 1246 $id = $this->get_info_from_iq_id($packet); 1247 $id = ($id != '') ? $id : 'time_' . time(); 1248 1249 if ($type == 'get') 1250 { 1251 $payload = '<utc>' . gmdate("Ydm\TH:i:s") . '</utc><tz>' . date('T') . '</tz><display>' . date("Y/d/m h:i:s A") . '</display>'; 1252 $this->send_iq($from, 'result', $id, 'jabber:iq:time', $payload); 1253 } 1254 1255 $this->add_to_log("EVENT: jabber:iq:time (type $type) from $from"); 1256 } 1257 1258 /** 1259 */ 1260 function handler_iq_error($packet) 1261 { 1262 // We'll do something with these later. This is a placeholder so that errors don't bounce back and forth. 1263 } 1264 1265 /** 1266 * method for requesting version 1267 */ 1268 function handler_iq_jabber_iq_version($packet) 1269 { 1270 $type = $this->get_info_from_iq_type($packet); 1271 $from = $this->get_info_from_iq_from($packet); 1272 $id = $this->get_info_from_iq_id($packet); 1273 $id = ($id != '') ? $id : 'version_' . time(); 1274 1275 if ($type == 'get') 1276 { 1277 $payload = "<name>{$this->iq_version_name}</name> 1278 <os>{$this->iq_version_os}</os> 1279 <version>{$this->iq_version_version}</version>"; 1280 1281 //$this->SendIq($from, 'result', $id, "jabber:iq:version", $payload); 1282 } 1283 1284 $this->add_to_log("EVENT: jabber:iq:version (type $type) from $from -- DISABLED"); 1285 } 1286 1287 // ====================================================================== 1288 // Generic handlers 1289 // ====================================================================== 1290 1291 /** 1292 * Generic handler for unsupported requests 1293 */ 1294 function handler_not_implemented($packet) 1295 { 1296 $packet_type = $this->_get_packet_type($packet); 1297 $from = call_user_func(array(&$this, 'get_info_from_' . strtolower($packet_type) . '_from'), $packet); 1298 $id = call_user_func(array(&$this, 'get_info_from_' . strtolower($packet_type) . '_id'), $packet); 1299 1300 $this->send_error($from, $id, 501); 1301 $this->add_to_log("EVENT: Unrecognized <$packet_type/> from $from"); 1302 } 1303 1304 // ====================================================================== 1305 // Third party code 1306 // m@d pr0ps to the coders ;) 1307 // ====================================================================== 1308 1309 /** 1310 * xmlize() 1311 * @author Hans Anderson 1312 * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ 1313 */ 1314 function xmlize($data, $skip_white = 1, $encoding = 'UTF-8') 1315 { 1316 $data = trim($data); 1317 1318 $vals = $index = $array = array(); 1319 $parser = xml_parser_create($encoding); 1320 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); 1321 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, $skip_white); 1322 xml_parse_into_struct($parser, $data, $vals, $index); 1323 xml_parser_free($parser); 1324 1325 $i = 0; 1326 $tagname = $vals[$i]['tag']; 1327 1328 $array[$tagname]['@'] = (isset($vals[$i]['attributes'])) ? $vals[$i]['attributes'] : array(); 1329 $array[$tagname]['#'] = $this->_xml_depth($vals, $i); 1330 1331 return $array; 1332 } 1333 1334 /** 1335 * _xml_depth() 1336 * @author Hans Anderson 1337 * @copyright Hans Anderson / http://www.hansanderson.com/php/xml/ 1338 */ 1339 function _xml_depth($vals, &$i) 1340 { 1341 $children = array(); 1342 1343 if (isset($vals[$i]['value'])) 1344 { 1345 array_push($children, $vals[$i]['value']); 1346 } 1347 1348 while (++$i < sizeof($vals)) 1349 { 1350 switch ($vals[$i]['type']) 1351 { 1352 case 'open': 1353 1354 $tagname = (isset($vals[$i]['tag'])) ? $vals[$i]['tag'] : ''; 1355 $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0; 1356 1357 if (isset($vals[$i]['attributes'])) 1358 { 1359 $children[$tagname][$size]['@'] = $vals[$i]['attributes']; 1360 } 1361 1362 $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); 1363 1364 break; 1365 1366 case 'cdata': 1367 array_push($children, $vals[$i]['value']); 1368 break; 1369 1370 case 'complete': 1371 1372 $tagname = $vals[$i]['tag']; 1373 $size = (isset($children[$tagname])) ? sizeof($children[$tagname]) : 0; 1374 $children[$tagname][$size]['#'] = (isset($vals[$i]['value'])) ? $vals[$i]['value'] : array(); 1375 1376 if (isset($vals[$i]['attributes'])) 1377 { 1378 $children[$tagname][$size]['@'] = $vals[$i]['attributes']; 1379 } 1380 1381 break; 1382 1383 case 'close': 1384 return $children; 1385 break; 1386 } 1387 } 1388 1389 return $children; 1390 } 1391 1392 /** 1393 * TraverseXMLize() 1394 * @author acebone@f2s.com 1395 * @copyright acebone@f2s.com, a HUGE help! 1396 */ 1397 function traverse_xmlize($array, $arr_name = 'array', $level = 0) 1398 { 1399 if ($level == 0) 1400 { 1401 echo '<pre>'; 1402 } 1403 1404 foreach ($array as $key => $val) 1405 { 1406 if (is_array($val)) 1407 { 1408 $this->traverse_xmlize($val, $arr_name . '[' . $key . ']', $level + 1); 1409 } 1410 else 1411 { 1412 $GLOBALS['traverse_array'][] = '$' . $arr_name . '[' . $key . '] = "' . $val . "\"\n"; 1413 } 1414 } 1415 1416 if ($level == 0) 1417 { 1418 echo '</pre>'; 1419 } 1420 1421 return 1; 1422 } 1423 } 1424 1425 /** 1426 * Jabber Connector 1427 * @package phpBB3 1428 */ 1429 class cjp_standard_connector 1430 { 1431 var $active_socket; 1432 1433 /** 1434 * Open socket 1435 */ 1436 function open_socket($server, $port) 1437 { 1438 if (function_exists('dns_get_record')) 1439 { 1440 $record = dns_get_record("_xmpp-client._tcp.$server", DNS_SRV); 1441 1442 if (!empty($record)) 1443 { 1444 $server = $record[0]['target']; 1445 $port = $record[0]['port']; 1446 } 1447 } 1448 1449 $errno = 0; 1450 $errstr = ''; 1451 1452 if ($this->active_socket = @fsockopen($server, $port, $errno, $errstr, 5)) 1453 { 1454 @socket_set_blocking($this->active_socket, 0); 1455 @socket_set_timeout($this->active_socket, 31536000); 1456 1457 return true; 1458 } 1459 else 1460 { 1461 return false; 1462 } 1463 } 1464 1465 /** 1466 * Close socket 1467 */ 1468 function close_socket() 1469 { 1470 return @fclose($this->active_socket); 1471 } 1472 1473 /** 1474 * Write to socket 1475 */ 1476 function write_to_socket($data) 1477 { 1478 return @fwrite($this->active_socket, $data); 1479 } 1480 1481 /** 1482 * Read from socket 1483 */ 1484 function read_from_socket($chunksize) 1485 { 1486 $buffer = @fread($this->active_socket, $chunksize); 1487 $buffer = (STRIP) ? stripslashes($buffer) : $buffer; 1488 1489 return $buffer; 1490 } 1491 } 1492 1493 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Nov 22 00:35:05 2006 | Cross-referenced by PHPXref 0.6 |