[ Index ]

PHP Cross Reference of phpBB 3.0 Beta 3

title

Body

[close]

/includes/ -> functions_jabber.php (source)

   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('&amp;', '&gt;', '&lt;', '&quot;', '&apos;'), $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  ?>


Generated: Wed Nov 22 00:35:05 2006 Cross-referenced by PHPXref 0.6