PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/gforge/common/include/Jabber.class.php

https://github.com/neymanna/fusionforge
PHP | 1533 lines | 928 code | 462 blank | 143 comment | 138 complexity | 94d2719c264d9a9486e5b2960915bcfd MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /***************************************************************************
  3. Class.Jabber.PHP v0.1.3.1
  4. (c) 2002 Carlo "Gossip" Zottmann
  5. http://phpjabber.g-blog.net *** gossip@jabber.g-blog.net
  6. The FULL documentation and examples for this software can be found at
  7. http://phpjabber.g-blog.net (not many doc comments in here, sorry)
  8. last modified: 2002-10-09 21:57:20
  9. NOTE:
  10. If you want to write addons or extensions, please follow the coding style
  11. recommendations @ http://www.phpbuilder.net/columns/tim20010101.php3
  12. ***************************************************************************/
  13. /***************************************************************************
  14. *
  15. * The Notice below must appear in each file of the Source Code of any copy
  16. * you distribute of the Licensed Product or any Modifications thereto.
  17. * Contributors to any Modifications may add their own copyright notices to
  18. * identify their own contributions.
  19. *
  20. * License
  21. *
  22. * The contents of this file are subject to the Jabber Open Source License
  23. * Version 1.0 (the "License"). You may not copy or use this file, in either
  24. * source code or executable form, except in compliance with the License. You
  25. * may obtain a copy of the License at http://www.jabber.com/license/ or at
  26. * http://www.opensource.org/.
  27. *
  28. * Software distributed under the License is distributed on an "AS IS" basis,
  29. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  30. * for the specific language governing rights and limitations under the
  31. * License.
  32. *
  33. * Copyrights
  34. *
  35. * Portions created by or assigned to Jabber.com, Inc. are
  36. * Copyright (c) 2000 Jabber.com, Inc. All Rights Reserved. Contact
  37. * information for Jabber.com, Inc. is available at http://www.jabber.com/.
  38. *
  39. * Portions Copyright (c) 2002-present Carlo Zottmann,
  40. * http://phpjabber.g-blog.net
  41. *
  42. * Other portions copyright their respective owners.
  43. *
  44. * Acknowledgements
  45. *
  46. * Special thanks to the Jabber Open Source Contributors for their
  47. * suggestions and support of Jabber.
  48. *
  49. ***************************************************************************/
  50. /*
  51. Jabber::Connect()
  52. Jabber::Disconnect()
  53. Jabber::SendAuth()
  54. Jabber::AccountRegistration($reg_email {string}, $reg_name {string})
  55. Jabber::Listen()
  56. Jabber::SendPacket($xml {string})
  57. Jabber::RosterUpdate()
  58. Jabber::RosterAddUser($jid {string}, $id {string}, $name {string})
  59. Jabber::RosterRemoveUser($jid {string}, $id {string})
  60. Jabber::Subscribe($jid {string})
  61. Jabber::Unsubscribe($jid {string})
  62. Jabber::CallHandler($message {array})
  63. Jabber::CruiseControl([$seconds {number}])
  64. Jabber::SubscriptionApproveRequest($to {string})
  65. Jabber::SubscriptionDenyRequest($to {string})
  66. Jabber::GetFirstFromQueue()
  67. Jabber::GetFromQueueById($packet_type {string}, $id {string})
  68. Jabber::SendMessage($to {string}, $id {number}, $type {string}, $content {array}[, $payload {array}])
  69. Jabber::SendIq($to {string}, $type {string}, $id {string}, $xmlns {string}[, $payload {string}])
  70. Jabber::SendPresence($type {string}[, $to {string}[, $status {string}[, $show {string}[, $priority {number}]]]])
  71. Jabber::SendError($to {string}, $id {string}, $error_number {number}[, $error_message {string}])
  72. Jabber::GetInfoFromMessageFrom($message {array})
  73. Jabber::GetInfoFromMessageType($message {array})
  74. Jabber::GetInfoFromMessageId($message {array})
  75. Jabber::GetInfoFromMessageThread($message {array})
  76. Jabber::GetInfoFromMessageSubject($message {array})
  77. Jabber::GetInfoFromMessageBody($message {array})
  78. Jabber::GetInfoFromMessageError($message {array})
  79. Jabber::GetInfoFromIqFrom($message {array})
  80. Jabber::GetInfoFromIqType($message {array})
  81. Jabber::GetInfoFromIqId($message {array})
  82. Jabber::GetInfoFromIqKey($message {array})
  83. Jabber::GetInfoFromPresenceFrom($message {array})
  84. Jabber::GetInfoFromPresenceType($message {array})
  85. Jabber::GetInfoFromPresenceStatus($message {array})
  86. Jabber::GetInfoFromPresenceShow($message {array})
  87. Jabber::GetInfoFromPresencePriority($message {array})
  88. MakeXML::AddPacketDetails($string {string}[, $value {string/number}])
  89. MakeXML::BuildPacket([$array {array}])
  90. */
  91. class Jabber
  92. {
  93. var $server;
  94. var $port;
  95. var $username;
  96. var $password;
  97. var $resource;
  98. var $jid;
  99. var $connection;
  100. var $stream_id;
  101. var $roster;
  102. var $enable_logging;
  103. var $logfile;
  104. var $iq_sleep_timer;
  105. var $packet_queue;
  106. var $subscription_queue;
  107. var $iq_version_name;
  108. var $iq_version_os;
  109. var $iq_version_version;
  110. var $error_codes;
  111. var $CONNECTOR;
  112. function Jabber()
  113. {
  114. $this->server = $GLOBALS['sys_jabber_server'];
  115. $this->port = $GLOBALS['sys_jabber_port'];
  116. $this->username = $GLOBALS['sys_jabber_user'];
  117. $this->password = $GLOBALS['sys_jabber_pass'];
  118. $this->resource = 'home';
  119. $this->enable_logging = FALSE;
  120. $this->logfile = array();
  121. $this->packet_queue = array();
  122. $this->subscription_queue = array();
  123. $this->iq_sleep_timer = 1;
  124. $this->iq_version_name = "Class.Jabber.PHP by Carlo 'Gossip' Zottmann, gossip@jabber.g-blog.net";
  125. $this->iq_version_version = "0.1.3";
  126. $this->iq_version_os = getStringFromServer('SERVER_SOFTWARE');
  127. $this->connection_class = "CJP_StandardConnector";
  128. $this->error_codes = array(400 => "Bad Request",
  129. 401 => "Unauthorized",
  130. 402 => "Payment Required",
  131. 403 => "Forbidden",
  132. 404 => "Not Found",
  133. 405 => "Not Allowed",
  134. 406 => "Not Acceptable",
  135. 407 => "Registration Required",
  136. 408 => "Request Timeout",
  137. 409 => "Conflict",
  138. 500 => "Internal Server Error",
  139. 501 => "Not Implemented",
  140. 502 => "Remove Server Error",
  141. 503 => "Service Unavailable",
  142. 504 => "Remove Server Timeout",
  143. 510 => "Disconnected");
  144. }
  145. function Connect()
  146. {
  147. $this->CONNECTOR = new $this->connection_class;
  148. $this->connection = $this->CONNECTOR->OpenSocket($this->server, $this->port);
  149. if ($this->connection) {
  150. socket_set_blocking($this->connection, 0);
  151. socket_set_timeout($this->connection, 31536000);
  152. $this->SendPacket("<?xml version='1.0' encoding='UTF-8' ?>\n");
  153. $this->SendPacket("<stream:stream to='" . $this->server . "' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>\n");
  154. sleep(2);
  155. if ($this->_check_connected()) {
  156. return TRUE;
  157. } else {
  158. if ($this->enable_logging) {
  159. $this->logfile[] = "<strong>Error:</strong> Connect() #1";
  160. }
  161. return FALSE;
  162. }
  163. } else {
  164. if ($this->enable_logging) {
  165. $this->logfile[] = "<strong>Error:</strong> Connect() #2";
  166. }
  167. return FALSE;
  168. }
  169. }
  170. function Disconnect()
  171. {
  172. $this->SendPacket("</stream:stream>");
  173. $this->CONNECTOR->CloseSocket($this->connection);
  174. if ($this->enable_logging) {
  175. echo "<h2>logging enabled, logged events below:</h2>\n";
  176. echo (count($this->logfile) > 0) ? implode("<br /><br />\n", $this->logfile) : "No logged events.";
  177. }
  178. }
  179. function SendAuth()
  180. {
  181. // Currently, we only support plaintext authentication. This ain't
  182. // perfect, but it works. I'll add <digest/> support later on...
  183. if ($this->resource) {
  184. $this->jid = $this->username . "@" . $this->server . "/" . $this->resource;
  185. } else {
  186. $this->jid = $this->username . "@" . $this->server;
  187. }
  188. $auth_id = "auth_" . time();
  189. $payload = "<username>" . $this->username . "</username>
  190. <password>" . $this->password . "</password>
  191. <resource>" . $this->resource . "</resource>";
  192. $packet = $this->SendIq(NULL, "set", $auth_id, "jabber:iq:auth", $payload);
  193. if ($this->GetInfoFromIqType($packet) == "result" && $this->GetInfoFromIqId($packet) == $auth_id) {
  194. return TRUE;
  195. } else {
  196. if ($this->enable_logging) {
  197. $this->logfile[] = "<strong>Error:</strong> SendAuth() #1";
  198. }
  199. return FALSE;
  200. }
  201. }
  202. function AccountRegistration($reg_email = NULL, $reg_name = NULL)
  203. {
  204. $packet = $this->SendIq($this->server, "get", "reg_01", "jabber:iq:register");
  205. if ($packet) {
  206. $key = $this->GetInfoFromIqKey($packet); // just in case a key was passed back from the server
  207. unset($packet);
  208. $payload = "<username>" . $this->username . "</username>
  209. <password>" . $this->password . "</password>
  210. <email>$reg_email</email>
  211. <name>$reg_name</name>\n";
  212. $payload .= ($key) ? "<key>$key</key>\n" : "";
  213. $packet = $this->SendIq($this->server, "set", "reg_01", "jabber:iq:register", $payload);
  214. if ($this->GetInfoFromIqType($packet) == "result") {
  215. if (isset($packet["iq"]["#"]["query"][0]["#"]["registered"][0]["#"])) {
  216. $return_code = 1;
  217. } else {
  218. $return_code = 2;
  219. }
  220. if ($this->resource) {
  221. $this->jid = $this->username . "@" . $this->server . "/" . $this->resource;
  222. } else {
  223. $this->jid = $this->username . "@" . $this->server;
  224. }
  225. } elseif ($this->GetInfoFromIqType($packet) == "error") {
  226. if (isset($packet["iq"]["#"]["error"][0]["#"])) {
  227. $return_code = "Error " . $packet["iq"]["#"]["error"][0]["@"]["code"] . ": " . $packet["iq"]["#"]["error"][0]["#"];
  228. }
  229. }
  230. return $return_code;
  231. } else {
  232. return 3;
  233. }
  234. }
  235. function SendPacket($xml)
  236. {
  237. $xml = trim($xml);
  238. if ($this->CONNECTOR->WriteToSocket($this->connection, $xml)) {
  239. if ($this->enable_logging) {
  240. $this->logfile[] = "<strong>SEND:</strong> " . nl2br(htmlspecialchars($xml));
  241. }
  242. return TRUE;
  243. } else {
  244. if ($this->enable_logging) {
  245. $this->logfile[] = "<strong>Error:</strong> SendPacket() #1";
  246. }
  247. return FALSE;
  248. }
  249. }
  250. function Listen()
  251. {
  252. unset($incoming);
  253. while ($line = $this->CONNECTOR->ReadFromSocket($this->connection, 4096)) {
  254. $incoming .= $line;
  255. }
  256. $incoming = trim($incoming);
  257. if ($this->enable_logging && $incoming != "") {
  258. $this->logfile[] = "<strong>RECV:</strong> " . nl2br(htmlspecialchars($incoming));
  259. }
  260. if ($incoming != "") {
  261. $temp = $this->_split_incoming($incoming);
  262. for ($a = 0; $a < count($temp); $a++) {
  263. $this->packet_queue[] = $this->xmlize($temp[$a]);
  264. }
  265. }
  266. return TRUE;
  267. }
  268. function StripJID($jid = NULL)
  269. {
  270. preg_match("/(.*)\/(.*)/Ui", $jid, $temp);
  271. return ($temp[1] != "") ? $temp[1] : $jid;
  272. }
  273. function SendMessage($to, $type = "normal", $id = NULL, $content = NULL, $payload = NULL)
  274. {
  275. if ($to && is_array($content)) {
  276. if (!$id) { $id = $type . "_" . time(); }
  277. $content = $this->_array_htmlspecialchars($content);
  278. $xml = "<message to='$to' type='$type' id='$id'>\n";
  279. if ($content["thread"]) {
  280. $xml .= "<thread>" . $content["thread"] . "</thread>\n";
  281. }
  282. if ($content['subject']) {
  283. $xml .= "<subject>" . $content['subject'] . "</subject>\n";
  284. }
  285. $xml .= "<body>" . $content["body"] . "</body>\n";
  286. $xml .= $payload;
  287. $xml .= "</message>\n";
  288. if ($this->SendPacket($xml)) {
  289. return TRUE;
  290. } else {
  291. if ($this->enable_logging) {
  292. $this->logfile[] = "<strong>Error:</strong> SendMessage() #1";
  293. }
  294. return FALSE;
  295. }
  296. } else {
  297. if ($this->enable_logging) {
  298. $this->logfile[] = "<strong>Error:</strong> SendMessage() #2";
  299. }
  300. return FALSE;
  301. }
  302. }
  303. function SendPresence($type = NULL, $to = NULL, $status = NULL, $show = NULL, $priority = NULL)
  304. {
  305. $xml = "<presence";
  306. $xml .= ($to) ? " to='$to'" : "";
  307. $xml .= ($type) ? " type='$type'" : "";
  308. $xml .= ($status || $show || $priority) ? ">\n" : " />\n";
  309. $xml .= ($status) ? " <status>$status</status>\n" : "";
  310. $xml .= ($show) ? " <show>$show</show>\n" : "";
  311. $xml .= ($priority) ? " <priority>$priority</priority>\n" : "";
  312. $xml .= ($status || $show || $priority) ? "</presence>\n" : "";
  313. if ($this->SendPacket($xml)) {
  314. return TRUE;
  315. } else {
  316. if ($this->enable_logging) {
  317. $this->logfile[] = "<strong>Error:</strong> SendPresence() #1";
  318. }
  319. return FALSE;
  320. }
  321. }
  322. function SendError($to, $id = NULL, $error_number, $error_message = NULL)
  323. {
  324. $xml = "<iq type='error' to='$to'";
  325. $xml .= ($id) ? " id='$id'" : "";
  326. $xml .= ">\n";
  327. $xml .= " <error code='$error_number'>";
  328. $xml .= ($error_message) ? $error_message : $this->error_codes[$error_number];
  329. $xml .= "</error>\n";
  330. $xml .= "</iq>";
  331. $this->SendPacket($xml);
  332. }
  333. function RosterUpdate()
  334. {
  335. $roster_request_id = "roster_" . time();
  336. $incoming_array = $this->SendIq(NULL, "get", $roster_request_id, "jabber:iq:roster");
  337. if (is_array($incoming_array)) {
  338. if ($incoming_array["iq"]["@"]["type"] == "result"
  339. && $incoming_array["iq"]["@"]["id"] == $roster_request_id
  340. && $incoming_array["iq"]["#"]["query"]["0"]["@"]["xmlns"] == "jabber:iq:roster")
  341. {
  342. $number_of_contacts = count($incoming_array["iq"]["#"]["query"][0]["#"]["item"]);
  343. $this->roster = array();
  344. for ($a = 0; $a < $number_of_contacts; $a++) {
  345. $this->roster[$a] = array( "jid" => $incoming_array["iq"]["#"]["query"][0]["#"]["item"][$a]["@"]["jid"],
  346. "name" => $incoming_array["iq"]["#"]["query"][0]["#"]["item"][$a]["@"]["name"],
  347. "subscription" => $incoming_array["iq"]["#"]["query"][0]["#"]["item"][$a]["@"]["subscription"],
  348. "group" => $incoming_array["iq"]["#"]["query"][0]["#"]["item"][$a]["#"]["group"][0]["#"]
  349. );
  350. }
  351. return TRUE;
  352. } else {
  353. if ($this->enable_logging) {
  354. $this->logfile[] = "<strong>Error:</strong> RosterUpdate() #1";
  355. }
  356. return FALSE;
  357. }
  358. } else {
  359. if ($this->enable_logging) {
  360. $this->logfile[] = "<strong>Error:</strong> RosterUpdate() #2";
  361. }
  362. return FALSE;
  363. }
  364. }
  365. function RosterAddUser($jid = NULL, $id = NULL, $name = NULL)
  366. {
  367. $id = ($id) ? $id : "adduser_" . time();
  368. if ($jid) {
  369. $payload = " <item jid='$jid'";
  370. $payload .= ($name) ? " name='" . htmlspecialchars($name) . "'" : "";
  371. $payload .= "/>\n";
  372. $packet = $this->SendIq(NULL, "set", $id, "jabber:iq:roster", $payload);
  373. if ($this->GetInfoFromIqType($packet) == "result") {
  374. $this->RosterUpdate();
  375. return TRUE;
  376. } else {
  377. if ($this->enable_logging) {
  378. $this->logfile[] = "<strong>Error:</strong> RosterAddUser() #2";
  379. }
  380. return FALSE;
  381. }
  382. } else {
  383. if ($this->enable_logging) {
  384. $this->logfile[] = "<strong>Error:</strong> RosterAddUser() #1";
  385. }
  386. return FALSE;
  387. }
  388. }
  389. function RosterRemoveUser($jid = NULL, $id = NULL)
  390. {
  391. if ($jid && $id) {
  392. $packet = $this->SendIq(NULL, "set", $id, "jabber:iq:roster", "<item jid='$jid' subscription='remove'/>");
  393. if ($this->GetInfoFromIqType($packet) == "result") {
  394. $this->RosterUpdate();
  395. return TRUE;
  396. } else {
  397. if ($this->enable_logging) {
  398. $this->logfile[] = "<strong>Error:</strong> RosterRemoveUser() #2";
  399. }
  400. return FALSE;
  401. }
  402. } else {
  403. if ($this->enable_logging) {
  404. $this->logfile[] = "<strong>Error:</strong> RosterRemoveUser() #1";
  405. }
  406. return FALSE;
  407. }
  408. }
  409. function GetFirstFromQueue()
  410. {
  411. reset($this->packet_queue);
  412. list($key, $value) = each($this->packet_queue);
  413. unset($this->packet_queue[$key]);
  414. return (is_array($value)) ? $value : FALSE;
  415. }
  416. function GetFromQueueById($packet_type, $id)
  417. {
  418. $found_message = FALSE;
  419. foreach ($this->packet_queue as $key => $value) {
  420. if ($value["$packet_type"]["@"]["id"] == $id) {
  421. $found_message = $value;
  422. unset($this->packet_queue[$key]);
  423. break;
  424. }
  425. }
  426. return (is_array($found_message)) ? $found_message : FALSE;
  427. }
  428. function CallHandler($packet = NULL)
  429. {
  430. $packet_type = $this->_get_packet_type($packet);
  431. if ($packet_type == "message") {
  432. $type = $packet["message"]["@"]["type"];
  433. $type = ($type != "") ? $type : "normal";
  434. $funcmeth = "Handler_message_$type";
  435. } elseif ($packet_type == "iq") {
  436. $this->TraverseXMLize($packet);
  437. $namespace = $packet["iq"]["#"]["query"][0]["@"]["xmlns"];
  438. $namespace = str_replace(":", "_", $namespace);
  439. $funcmeth = "Handler_iq_$namespace";
  440. } elseif ($packet_type == "presence") {
  441. $type = $packet["presence"]["@"]["type"];
  442. $type = ($type != "") ? $type : "available";
  443. $funcmeth = "Handler_presence_$type";
  444. }
  445. if ($funcmeth != "") {
  446. if (function_exists($funcmeth)) {
  447. call_user_func($funcmeth, $packet);
  448. } elseif(method_exists($this, $funcmeth)) {
  449. call_user_func(array(&$this, $funcmeth), $packet);
  450. } elseif ($this->enable_logging) {
  451. $this->Handler_NOT_IMPLEMENTED($packet);
  452. $this->logfile[] = "<strong>Error:</strong> CallHandler() #1 - neither method nor function $funcmeth() available";
  453. }
  454. }
  455. }
  456. function CruiseControl($seconds = -1)
  457. {
  458. $count = 0;
  459. while ($count != $seconds) {
  460. $this->Listen();
  461. do {
  462. $packet = $this->GetFirstFromQueue();
  463. $this->CallHandler($packet);
  464. } while (count($this->packet_queue) > 1);
  465. $count++;
  466. sleep(1);
  467. }
  468. return TRUE;
  469. }
  470. function SubscriptionAcceptRequest($to = NULL)
  471. {
  472. return ($to) ? $this->SendPresence("subscribed", $to) : FALSE;
  473. }
  474. function SubscriptionDenyRequest($to = NULL)
  475. {
  476. return ($to) ? /* still needs to be done */ TRUE : FALSE;
  477. }
  478. function Subscribe($to = NULL)
  479. {
  480. return ($to) ? $this->SendPresence("subscribe", $to) : FALSE;
  481. }
  482. function Unsubscribe($to = NULL)
  483. {
  484. return ($to) ? $this->SendPresence("unsubscribe", $to) : FALSE;
  485. }
  486. function SendIq($to = NULL, $type = "get", $id = NULL, $xmlns = NULL, $payload = NULL)
  487. {
  488. if (!preg_match("/^(get|set|result|error)$/", $type)) {
  489. unset($type);
  490. if ($this->enable_logging) {
  491. $this->logfile[] = "<strong>Error:</strong> SendIq() #2 - type must be 'get', 'set', 'result' or 'error'";
  492. }
  493. return FALSE;
  494. } elseif ($id && $xmlns) {
  495. $xml = "<iq type='$type' id='$id'";
  496. $xml .= ($to) ? " to='$to'" : "";
  497. $xml .= ">
  498. <query xmlns='$xmlns'>
  499. $payload
  500. </query>
  501. </iq>";
  502. $this->SendPacket($xml);
  503. sleep($this->iq_sleep_timer);
  504. $this->Listen();
  505. return (preg_match("/^(get|set)$/", $type)) ? $this->GetFromQueueById("iq", $id) : TRUE;
  506. } else {
  507. if ($this->enable_logging) {
  508. $this->logfile[] = "<strong>Error:</strong> SendIq() #1 - to, id and xmlns are mandatory";
  509. }
  510. return FALSE;
  511. }
  512. }
  513. // ======================================================================
  514. // internal methods
  515. // ======================================================================
  516. function _listen_incoming()
  517. {
  518. unset($incoming);
  519. while ($line = $this->CONNECTOR->ReadFromSocket($this->connection, 4096)) {
  520. $incoming .= $line;
  521. }
  522. $incoming = trim($incoming);
  523. if ($this->enable_logging && $incoming != "") {
  524. $this->logfile[] = "<strong>RECV:</strong> " . nl2br(htmlspecialchars($incoming));
  525. }
  526. return $this->xmlize($incoming);
  527. }
  528. function _check_connected()
  529. {
  530. $incoming_array = $this->_listen_incoming();
  531. if (is_array($incoming_array)) {
  532. if ($incoming_array["stream:stream"]["@"]["from"] == $this->server
  533. && $incoming_array["stream:stream"]["@"]["xmlns"] == "jabber:client"
  534. && $incoming_array["stream:stream"]["@"]["xmlns:stream"] == "http://etherx.jabber.org/streams")
  535. {
  536. $this->stream_id = $incoming_array["stream:stream"]["@"]["id"];
  537. return TRUE;
  538. } else {
  539. if ($this->enable_logging) {
  540. $this->logfile[] = "<strong>Error:</strong> _check_connected() #1";
  541. }
  542. return FALSE;
  543. }
  544. } else {
  545. if ($this->enable_logging) {
  546. $this->logfile[] = "<strong>Error:</strong> _check_connected() #2";
  547. }
  548. return FALSE;
  549. }
  550. }
  551. function _get_packet_type($packet = NULL)
  552. {
  553. if (is_array($packet)) {
  554. reset($packet);
  555. $packet_type = key($packet);
  556. }
  557. return ($packet_type) ? $packet_type : FALSE;
  558. }
  559. function _split_incoming($incoming)
  560. {
  561. $temp = preg_split("/<(message|iq|presence|stream)/", $incoming, -1, PREG_SPLIT_DELIM_CAPTURE);
  562. $array = array();
  563. for ($a = 1; $a < count($temp); $a = $a + 2) {
  564. $array[] = "<" . $temp[$a] . $temp[($a + 1)];
  565. }
  566. return $array;
  567. }
  568. // _array_htmlspecialchars()
  569. // applies htmlspecialchars() to all values in an array
  570. function _array_htmlspecialchars($array)
  571. {
  572. if (is_array($array)) {
  573. foreach ($array as $k => $v) {
  574. if (is_array($v)) {
  575. $v = $this->_array_htmlspecialchars($v);
  576. } else {
  577. $v = htmlspecialchars($v);
  578. }
  579. }
  580. }
  581. return $array;
  582. }
  583. // ======================================================================
  584. // <message/> parsers
  585. // ======================================================================
  586. function GetInfoFromMessageFrom($packet = NULL)
  587. {
  588. return (is_array($packet)) ? $packet["message"]["@"]["from"] : FALSE;
  589. }
  590. function GetInfoFromMessageType($packet = NULL)
  591. {
  592. return (is_array($packet)) ? $packet["message"]["@"]["type"] : FALSE;
  593. }
  594. function GetInfoFromMessageId($packet = NULL)
  595. {
  596. return (is_array($packet)) ? $packet["message"]["@"]["id"] : FALSE;
  597. }
  598. function GetInfoFromMessageThread($packet = NULL)
  599. {
  600. return (is_array($packet)) ? $packet["message"]["#"]["thread"][0]["#"] : FALSE;
  601. }
  602. function GetInfoFromMessageSubject($packet = NULL)
  603. {
  604. return (is_array($packet)) ? $packet["message"]["#"]["subject"][0]["#"] : FALSE;
  605. }
  606. function GetInfoFromMessageBody($packet = NULL)
  607. {
  608. return (is_array($packet)) ? $packet["message"]["#"]["body"][0]["#"] : FALSE;
  609. }
  610. function GetInfoFromMessageError($packet = NULL)
  611. {
  612. $error = preg_replace("/^\/$/", "", ($packet["message"]["#"]["error"][0]["@"]["code"] . "/" . $packet["message"]["#"]["error"][0]["#"]));
  613. return (is_array($packet)) ? $error : FALSE;
  614. }
  615. // ======================================================================
  616. // <iq/> parsers
  617. // ======================================================================
  618. function GetInfoFromIqFrom($packet = NULL)
  619. {
  620. return (is_array($packet)) ? $packet["iq"]["@"]["from"] : FALSE;
  621. }
  622. function GetInfoFromIqType($packet = NULL)
  623. {
  624. return (is_array($packet)) ? $packet["iq"]["@"]["type"] : FALSE;
  625. }
  626. function GetInfoFromIqId($packet = NULL)
  627. {
  628. return (is_array($packet)) ? $packet["iq"]["@"]["id"] : FALSE;
  629. }
  630. function GetInfoFromIqKey($packet = NULL)
  631. {
  632. return (is_array($packet)) ? $packet["iq"]["#"]["query"][0]["#"]["key"][0]["#"] : FALSE;
  633. }
  634. // ======================================================================
  635. // <presence/> parsers
  636. // ======================================================================
  637. function GetInfoFromPresenceFrom($packet = NULL)
  638. {
  639. return (is_array($packet)) ? $packet["presence"]["@"]["from"] : FALSE;
  640. }
  641. function GetInfoFromPresenceType($packet = NULL)
  642. {
  643. return (is_array($packet)) ? $packet["presence"]["@"]["type"] : FALSE;
  644. }
  645. function GetInfoFromPresenceStatus($packet = NULL)
  646. {
  647. return (is_array($packet)) ? $packet["presence"]["#"]["status"][0]["#"] : FALSE;
  648. }
  649. function GetInfoFromPresenceShow($packet = NULL)
  650. {
  651. return (is_array($packet)) ? $packet["presence"]["#"]["show"][0]["#"] : FALSE;
  652. }
  653. function GetInfoFromPresencePriority($packet = NULL)
  654. {
  655. return (is_array($packet)) ? $packet["presence"]["#"]["priority"][0]["#"] : FALSE;
  656. }
  657. // ======================================================================
  658. // <message/> handlers
  659. // ======================================================================
  660. function Handler_message_normal($packet)
  661. {
  662. $from = $packet["message"]["@"]["from"];
  663. $this->logfile[] = "<strong>message</strong> (type normal) from $from";
  664. }
  665. function Handler_message_chat($packet)
  666. {
  667. $from = $packet["message"]["@"]["from"];
  668. $this->logfile[] = "<strong>message</strong> (type chat) from $from";
  669. }
  670. function Handler_message_groupchat($packet)
  671. {
  672. $from = $packet["message"]["@"]["from"];
  673. $this->logfile[] = "<strong>message</strong> (type groupchat) from $from";
  674. }
  675. function Handler_message_headline($packet)
  676. {
  677. $from = $packet["message"]["@"]["from"];
  678. $this->logfile[] = "<strong>message</strong> (type headline) from $from";
  679. }
  680. function Handler_message_error($packet)
  681. {
  682. $from = $packet["message"]["@"]["from"];
  683. $this->logfile[] = "<strong>message</strong> (type error) from $from";
  684. }
  685. // ======================================================================
  686. // <iq/> handlers
  687. // ======================================================================
  688. // application version updates
  689. function Handler_iq_jabber_iq_autoupdate($packet)
  690. {
  691. $from = $this->GetInfoFromIqFrom($packet);
  692. $id = $this->GetInfoFromIqId($packet);
  693. $this->SendError($from, $id, 501);
  694. $this->logfile[] = "<strong>jabber:iq:autoupdate</strong> from $from";
  695. }
  696. // interactive server component properties
  697. function Handler_iq_jabber_iq_agent($packet)
  698. {
  699. $from = $this->GetInfoFromIqFrom($packet);
  700. $id = $this->GetInfoFromIqId($packet);
  701. $this->SendError($from, $id, 501);
  702. $this->logfile[] = "<strong>jabber:iq:agent</strong> from $from";
  703. }
  704. // method to query interactive server components
  705. function Handler_iq_jabber_iq_agents($packet)
  706. {
  707. $from = $this->GetInfoFromIqFrom($packet);
  708. $id = $this->GetInfoFromIqId($packet);
  709. $this->SendError($from, $id, 501);
  710. $this->logfile[] = "<strong>jabber:iq:agents</strong> from $from";
  711. }
  712. // simple client authentication
  713. function Handler_iq_jabber_iq_auth($packet)
  714. {
  715. $from = $this->GetInfoFromIqFrom($packet);
  716. $id = $this->GetInfoFromIqId($packet);
  717. $this->SendError($from, $id, 501);
  718. $this->logfile[] = "<strong>jabber:iq:auth</strong> from $from";
  719. }
  720. // out of band data
  721. function Handler_iq_jabber_iq_oob($packet)
  722. {
  723. $from = $this->GetInfoFromIqFrom($packet);
  724. $id = $this->GetInfoFromIqId($packet);
  725. $this->SendError($from, $id, 501);
  726. $this->logfile[] = "<strong>jabber:iq:oob</strong> from $from";
  727. }
  728. // method to store private data on the server
  729. function Handler_iq_jabber_iq_private($packet)
  730. {
  731. $from = $this->GetInfoFromIqFrom($packet);
  732. $id = $this->GetInfoFromIqId($packet);
  733. $this->SendError($from, $id, 501);
  734. $this->logfile[] = "<strong>jabber:iq:private</strong> from $from";
  735. }
  736. // method for interactive registration
  737. function Handler_iq_jabber_iq_register($packet)
  738. {
  739. $from = $this->GetInfoFromIqFrom($packet);
  740. $id = $this->GetInfoFromIqId($packet);
  741. $this->SendError($from, $id, 501);
  742. $this->logfile[] = "<strong>jabber:iq:register</strong> from $from";
  743. }
  744. // client roster management
  745. function Handler_iq_jabber_iq_roster($packet)
  746. {
  747. $from = $this->GetInfoFromIqFrom($packet);
  748. $id = $this->GetInfoFromIqId($packet);
  749. $this->SendError($from, $id, 501);
  750. $this->logfile[] = "<strong>jabber:iq:roster</strong> from $from";
  751. }
  752. // method for searching a user database
  753. function Handler_iq_jabber_iq_search($packet)
  754. {
  755. $from = $this->GetInfoFromIqFrom($packet);
  756. $id = $this->GetInfoFromIqId($packet);
  757. $this->SendError($from, $id, 501);
  758. $this->logfile[] = "<strong>jabber:iq:search</strong> from $from";
  759. }
  760. // method for requesting the current time
  761. function Handler_iq_jabber_iq_time($packet)
  762. {
  763. $type = $this->GetInfoFromIqType($packet);
  764. $from = $this->GetInfoFromIqFrom($packet);
  765. $id = $this->GetInfoFromIqId($packet);
  766. $id = ($id != "") ? $id : "time_" . time();
  767. if ($type == "get") {
  768. $payload = "<utc>" . gmdate("Ydm\TH:i:s") . "</utc>
  769. <tz>" . date("T") . "</tz>
  770. <display>" . date("Y/d/m h:i:s A") . "</display>";
  771. $this->SendIq($from, "result", $id, "jabber:iq:time", $payload);
  772. }
  773. $this->logfile[] = "<strong>jabber:iq:time</strong> (type $type) from $from";
  774. }
  775. // method for requesting version
  776. function Handler_iq_jabber_iq_version($packet)
  777. {
  778. $type = $this->GetInfoFromIqType($packet);
  779. $from = $this->GetInfoFromIqFrom($packet);
  780. $id = $this->GetInfoFromIqId($packet);
  781. $id = ($id != "") ? $id : "version_" . time();
  782. if ($type == "get") {
  783. $payload = "<name>" . $this->iq_version_name . "</name>
  784. <os>" . $this->iq_version_os . "</os>
  785. <version>" . $this->iq_version_version . "</version>";
  786. $this->SendIq($from, "result", $id, "jabber:iq:version", $payload);
  787. }
  788. $this->logfile[] = "<strong>jabber:iq:version</strong> (type $type) from $from";
  789. }
  790. // ======================================================================
  791. // <presence/> handlers
  792. // ======================================================================
  793. function Handler_presence_available($packet)
  794. {
  795. $from = $this->GetInfoFromPresenceFrom($packet);
  796. $show_status = $this->GetInfoFromPresenceStatus($packet) . " / " . $this->GetInfoFromPresenceShow($packet);
  797. $show_status = ($show_status != " / ") ? " ($addendum)" : "";
  798. $this->logfile[] = "<strong>Presence:</strong> (type: available) - $from is available $show_status";
  799. }
  800. function Handler_presence_unavailable($packet)
  801. {
  802. $from = $this->GetInfoFromPresenceFrom($packet);
  803. $show_status = $this->GetInfoFromPresenceStatus($packet) . " / " . $this->GetInfoFromPresenceShow($packet);
  804. $show_status = ($show_status != " / ") ? " ($addendum)" : "";
  805. $this->logfile[] = "<strong>Presence:</strong> (type: unavailable) - $from is unavailable $show_status";
  806. }
  807. function Handler_presence_subscribe($packet)
  808. {
  809. $from = $this->GetInfoFromPresenceFrom($packet);
  810. $this->subscription_queue[] = $from;
  811. $this->RosterUpdate();
  812. $this->logfile[] = "<strong>Presence:</strong> (type: subscribe) - Subscription request from $from, was added to \$this->subscription_queue, roster updated";
  813. }
  814. function Handler_presence_subscribed($packet)
  815. {
  816. $from = $this->GetInfoFromPresenceFrom($packet);
  817. $this->RosterUpdate();
  818. $this->logfile[] = "<strong>Presence:</strong> (type: subscribed) - Subscription allowed by $from, roster updated";
  819. }
  820. function Handler_presence_unsubscribe($packet)
  821. {
  822. $from = $this->GetInfoFromPresenceFrom($packet);
  823. $this->SendPresence("unsubscribed", $from);
  824. $this->RosterUpdate();
  825. $this->logfile[] = "<strong>Presence:</strong> (type: unsubscribe) - Request to unsubscribe from $from, was automatically approved, roster updated";
  826. }
  827. function Handler_presence_unsubscribed($packet)
  828. {
  829. $from = $this->GetInfoFromPresenceFrom($packet);
  830. $this->RosterUpdate();
  831. $this->logfile[] = "<strong>Presence:</strong> (type: unsubscribed) - Unsubscribed from $from's presence";
  832. }
  833. // ======================================================================
  834. // Generic handlers
  835. // ======================================================================
  836. // Generic handler for unsupported requests
  837. function Handler_NOT_IMPLEMENTED($packet)
  838. {
  839. $packet_type = $this->_get_packet_type($packet);
  840. $from = call_user_func(array(&$this, "GetInfoFrom" . ucfirst($packet_type) . "From"), $packet);
  841. $id = call_user_func(array(&$this, "GetInfoFrom" . ucfirst($packet_type) . "Id"), $packet);
  842. $this->SendError($from, $id, 501);
  843. $this->logfile[] = "<strong>Unrecognized &lt;$packet_type/&gt;</strong> from $from";
  844. }
  845. // ======================================================================
  846. // Third party code
  847. // m@d pr0ps to the coders ;)
  848. // ======================================================================
  849. // xmlize()
  850. // (c) Hans Anderson / http://www.hansanderson.com/php/xml/
  851. function xmlize($data) {
  852. $vals = $index = $array = array();
  853. $parser = xml_parser_create();
  854. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
  855. xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
  856. xml_parse_into_struct($parser, $data, $vals, $index);
  857. xml_parser_free($parser);
  858. $i = 0;
  859. $tagname = $vals[$i]['tag'];
  860. $array[$tagname]["@"] = $vals[$i]["attributes"];
  861. $array[$tagname]["#"] = $this->_xml_depth($vals, $i);
  862. return $array;
  863. }
  864. // _xml_depth()
  865. // (c) Hans Anderson / http://www.hansanderson.com/php/xml/
  866. function _xml_depth($vals, &$i) {
  867. $children = array();
  868. if ($vals[$i]['value']) {
  869. array_push($children, trim($vals[$i]['value']));
  870. }
  871. while (++$i < count($vals)) {
  872. switch ($vals[$i]['type']) {
  873. case 'cdata':
  874. array_push($children, trim($vals[$i]['value']));
  875. break;
  876. case 'complete':
  877. $tagname = $vals[$i]['tag'];
  878. $size = sizeof($children["$tagname"]);
  879. $children[$tagname][$size]["#"] = trim($vals[$i]['value']);
  880. if ($vals[$i]["attributes"]) {
  881. $children[$tagname][$size]["@"] = $vals[$i]["attributes"];
  882. }
  883. break;
  884. case 'open':
  885. $tagname = $vals[$i]['tag'];
  886. $size = sizeof($children["$tagname"]);
  887. if ($vals[$i]["attributes"]) {
  888. $children["$tagname"][$size]["@"] = $vals[$i]["attributes"];
  889. $children["$tagname"][$size]["#"] = $this->_xml_depth($vals, $i);
  890. } else {
  891. $children["$tagname"][$size]["#"] = $this->_xml_depth($vals, $i);
  892. }
  893. break;
  894. case 'close':
  895. return $children;
  896. break;
  897. }
  898. }
  899. return $children;
  900. }
  901. // TraverseXMLize()
  902. // (c) acebone@f2s.com, a HUGE help!
  903. function TraverseXMLize($array, $arrName = "array", $level = 0) {
  904. if ($level == 0) {
  905. echo "<pre>";
  906. }
  907. while (list($key, $val) = @each($array)) {
  908. if (is_array($val)) {
  909. $this->TraverseXMLize($val, $arrName . "[" . $key . "]", $level + 1);
  910. } else {
  911. echo '$' . $arrName . '[' . $key . '] = "' . $val . "\"\n";
  912. }
  913. }
  914. if ($level == 0) {
  915. echo "</pre>";
  916. }
  917. }
  918. }
  919. class MakeXML extends Jabber
  920. {
  921. var $nodes;
  922. function MakeXML()
  923. {
  924. $nodes = array();
  925. }
  926. function AddPacketDetails($string, $value = NULL)
  927. {
  928. if (preg_match("/\(([0-9]*)\)$/i", $string)) {
  929. $string .= "/[\"#\"]";
  930. }
  931. $temp = @explode("/", $string);
  932. for ($a = 0; $a < count($temp); $a++) {
  933. $temp[$a] = preg_replace("/^[@]{1}([a-z0-9_]*)$/i", "[\"@\"][\"\\1\"]", $temp[$a]);
  934. $temp[$a] = preg_replace("/^([a-z0-9_]*)\(([0-9]*)\)$/i", "[\"\\1\"][\\2]", $temp[$a]);
  935. $temp[$a] = preg_replace("/^([a-z0-9_]*)$/i", "[\"\\1\"]", $temp[$a]);
  936. }
  937. $node = implode("", $temp);
  938. // Yeahyeahyeah, I know it's ugly... get over it. ;)
  939. echo "\$this->nodes$node = \"" . htmlspecialchars($value) . "\";<br/>";
  940. eval("\$this->nodes$node = \"" . htmlspecialchars($value) . "\";");
  941. }
  942. function BuildPacket($array = NULL)
  943. {
  944. if (!$array) {
  945. $array = $this->nodes;
  946. }
  947. if (is_array($array)) {
  948. array_multisort($array, SORT_ASC, SORT_STRING);
  949. foreach ($array as $key => $value) {
  950. if (is_array($value) && $key == "@") {
  951. foreach ($value as $subkey => $subvalue) {
  952. $subvalue = htmlspecialchars($subvalue);
  953. $text .= " $subkey='$subvalue'";
  954. }
  955. $text .= ">\n";
  956. } elseif ($key == "#") {
  957. $text .= htmlspecialchars($value);
  958. } elseif (is_array($value)) {
  959. for ($a = 0; $a < count($value); $a++) {
  960. $text .= "<$key";
  961. if (!$this->_preg_grep_keys("/^@/", $value[$a])) {
  962. $text .= ">";
  963. }
  964. $text .= $this->BuildPacket($value[$a]);
  965. $text .= "</$key>\n";
  966. }
  967. } else {
  968. $value = htmlspecialchars($value);
  969. $text .= "<$key>$value</$key>\n";
  970. }
  971. }
  972. return $text;
  973. }
  974. }
  975. function _preg_grep_keys($pattern, $array)
  976. {
  977. while (list($key, $val) = each($array)) {
  978. if (preg_match($pattern, $key)) {
  979. $newarray[$key] = $val;
  980. }
  981. }
  982. return (is_array($newarray)) ? $newarray : FALSE;
  983. }
  984. }
  985. class CJP_StandardConnector
  986. {
  987. function OpenSocket($server, $port)
  988. {
  989. return fsockopen($server, $port);
  990. }
  991. function CloseSocket($connection)
  992. {
  993. return fclose($connection);
  994. }
  995. function WriteToSocket($connection, $data)
  996. {
  997. return fwrite($connection, $data);
  998. }
  999. function ReadFromSocket($connection, $chunksize)
  1000. {
  1001. return fread($connection, $chunksize);
  1002. }
  1003. }
  1004. ?>