3 /***************************************************************************
5 Class.Jabber.PHP v0.1.3.1
6 (c) 2002 Carlo "Gossip" Zottmann
7 http://phpjabber.g-blog.net *** gossip@jabber.g-blog.net
9 The FULL documentation and examples for this software can be found at
10 http://phpjabber.g-blog.net (not many doc comments in here, sorry)
12 last modified: 2002-10-09 21:57:20
15 If you want to write addons or extensions, please follow the coding style
16 recommendations @ http://www.phpbuilder.net/columns/tim20010101.php3
18 ***************************************************************************/
20 /***************************************************************************
22 * The Notice below must appear in each file of the Source Code of any copy
23 * you distribute of the Licensed Product or any Modifications thereto.
24 * Contributors to any Modifications may add their own copyright notices to
25 * identify their own contributions.
29 * The contents of this file are subject to the Jabber Open Source License
30 * Version 1.0 (the "License"). You may not copy or use this file, in either
31 * source code or executable form, except in compliance with the License. You
32 * may obtain a copy of the License at http://www.jabber.com/license/ or at
33 * http://www.opensource.org/.
35 * Software distributed under the License is distributed on an "AS IS" basis,
36 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
37 * for the specific language governing rights and limitations under the
42 * Portions created by or assigned to Jabber.com, Inc. are
43 * Copyright (c) 2000 Jabber.com, Inc. All Rights Reserved. Contact
44 * information for Jabber.com, Inc. is available at http://www.jabber.com/.
46 * Portions Copyright (c) 2002-present Carlo Zottmann,
47 * http://phpjabber.g-blog.net
49 * Other portions copyright their respective owners.
53 * Special thanks to the Jabber Open Source Contributors for their
54 * suggestions and support of Jabber.
56 ***************************************************************************/
62 Jabber::AccountRegistration($reg_email {string}, $reg_name {string})
65 Jabber::SendPacket($xml {string})
67 Jabber::RosterUpdate()
68 Jabber::RosterAddUser($jid {string}, $id {string}, $name {string})
69 Jabber::RosterRemoveUser($jid {string}, $id {string})
71 Jabber::Subscribe($jid {string})
72 Jabber::Unsubscribe($jid {string})
74 Jabber::CallHandler($message {array})
75 Jabber::CruiseControl([$seconds {number}])
77 Jabber::SubscriptionApproveRequest($to {string})
78 Jabber::SubscriptionDenyRequest($to {string})
80 Jabber::GetFirstFromQueue()
81 Jabber::GetFromQueueById($packet_type {string}, $id {string})
83 Jabber::SendMessage($to {string}, $id {number}, $type {string}, $content {array}[, $payload {array}])
84 Jabber::SendIq($to {string}, $type {string}, $id {string}, $xmlns {string}[, $payload {string}])
85 Jabber::SendPresence($type {string}[, $to {string}[, $status {string}[, $show {string}[, $priority {number}]]]])
87 Jabber::SendError($to {string}, $id {string}, $error_number {number}[, $error_message {string}])
89 Jabber::GetInfoFromMessageFrom($message {array})
90 Jabber::GetInfoFromMessageType($message {array})
91 Jabber::GetInfoFromMessageId($message {array})
92 Jabber::GetInfoFromMessageThread($message {array})
93 Jabber::GetInfoFromMessageSubject($message {array})
94 Jabber::GetInfoFromMessageBody($message {array})
95 Jabber::GetInfoFromMessageError($message {array})
97 Jabber::GetInfoFromIqFrom($message {array})
98 Jabber::GetInfoFromIqType($message {array})
99 Jabber::GetInfoFromIqId($message {array})
100 Jabber::GetInfoFromIqKey($message {array})
102 Jabber::GetInfoFromPresenceFrom($message {array})
103 Jabber::GetInfoFromPresenceType($message {array})
104 Jabber::GetInfoFromPresenceStatus($message {array})
105 Jabber::GetInfoFromPresenceShow($message {array})
106 Jabber::GetInfoFromPresencePriority($message {array})
109 MakeXML::AddPacketDetails($string {string}[, $value {string/number}])
110 MakeXML::BuildPacket([$array {array}])
135 var $subscription_queue;
137 var $iq_version_name;
139 var $iq_version_version;
149 $this->server = forge_get_config('jabber_host');
150 $this->port = forge_get_config('jabber_port');
152 $this->username = forge_get_config('jabber_user');
153 $this->password = forge_get_config('jabber_password');
154 $this->resource = 'home';
156 $this->enable_logging = FALSE;
157 $this->logfile = array();
159 $this->packet_queue = array();
160 $this->subscription_queue = array();
162 $this->iq_sleep_timer = 1;
164 $this->iq_version_name = "Class.Jabber.PHP by Carlo 'Gossip' Zottmann, gossip@jabber.g-blog.net";
165 $this->iq_version_version = "0.1.3";
166 $this->iq_version_os = getStringFromServer('SERVER_SOFTWARE');
168 $this->connection_class = "CJP_StandardConnector";
170 $this->error_codes = array(400 => "Bad Request",
171 401 => "Unauthorized",
172 402 => "Payment Required",
175 405 => "Not Allowed",
176 406 => "Not Acceptable",
177 407 => "Registration Required",
178 408 => "Request Timeout",
180 500 => "Internal Server Error",
181 501 => "Not Implemented",
182 502 => "Remove Server Error",
183 503 => "Service Unavailable",
184 504 => "Remove Server Timeout",
185 510 => "Disconnected");
192 $this->CONNECTOR = new $this->connection_class;
193 $this->connection = $this->CONNECTOR->OpenSocket($this->server, $this->port);
195 if ($this->connection) {
197 socket_set_blocking($this->connection, 0);
198 socket_set_timeout($this->connection, 31536000);
200 $this->SendPacket("<?xml version='1.0' encoding='UTF-8' ?>\n");
201 $this->SendPacket("<stream:stream to='" . $this->server . "' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>\n");
205 if ($this->_check_connected()) {
211 if ($this->enable_logging) {
212 $this->logfile[] = "<strong>Error:</strong> Connect() #1";
220 if ($this->enable_logging) {
221 $this->logfile[] = "<strong>Error:</strong> Connect() #2";
230 function Disconnect()
232 $this->SendPacket("</stream:stream>");
233 $this->CONNECTOR->CloseSocket($this->connection);
235 if ($this->enable_logging) {
236 echo "<h2>logging enabled, logged events below:</h2>\n";
237 echo (count($this->logfile) > 0) ? implode("<br />\n", $this->logfile) : "No logged events.";
245 // Currently, we only support plaintext authentication. This ain't
246 // perfect, but it works. I'll add <digest/> support later on...
248 if ($this->resource) {
249 $this->jid = $this->username . "@" . $this->server . "/" . $this->resource;
251 $this->jid = $this->username . "@" . $this->server;
254 $auth_id = "auth_" . time();
256 $payload = "<username>" . $this->username . "</username>
257 <password>" . $this->password . "</password>
258 <resource>" . $this->resource . "</resource>";
260 $packet = $this->SendIq(NULL, "set", $auth_id, "jabber:iq:auth", $payload);
262 if ($this->GetInfoFromIqType($packet) == "result" && $this->GetInfoFromIqId($packet) == $auth_id) {
268 if ($this->enable_logging) {
269 $this->logfile[] = "<strong>Error:</strong> SendAuth() #1";
278 function AccountRegistration($reg_email = NULL, $reg_name = NULL)
280 $packet = $this->SendIq($this->server, "get", "reg_01", "jabber:iq:register");
284 $key = $this->GetInfoFromIqKey($packet); // just in case a key was passed back from the server
287 $payload = "<username>" . $this->username . "</username>
288 <password>" . $this->password . "</password>
289 <email>$reg_email</email>
290 <name>$reg_name</name>\n";
291 $payload .= ($key) ? "<key>$key</key>\n" : "";
293 $packet = $this->SendIq($this->server, "set", "reg_01", "jabber:iq:register", $payload);
295 if ($this->GetInfoFromIqType($packet) == "result") {
297 if (isset($packet["iq"]["#"]["query"][0]["#"]["registered"][0]["#"])) {
303 if ($this->resource) {
304 $this->jid = $this->username . "@" . $this->server . "/" . $this->resource;
306 $this->jid = $this->username . "@" . $this->server;
309 } elseif ($this->GetInfoFromIqType($packet) == "error") {
311 if (isset($packet["iq"]["#"]["error"][0]["#"])) {
312 $return_code = "Error " . $packet["iq"]["#"]["error"][0]["@"]["code"] . ": " . $packet["iq"]["#"]["error"][0]["#"];
327 function SendPacket($xml)
331 if ($this->CONNECTOR->WriteToSocket($this->connection, $xml)) {
333 if ($this->enable_logging) {
334 $this->logfile[] = "<strong>SEND:</strong> " . nl2br(htmlspecialchars($xml));
341 if ($this->enable_logging) {
342 $this->logfile[] = "<strong>Error:</strong> SendPacket() #1";
355 while ($line = $this->CONNECTOR->ReadFromSocket($this->connection, 4096)) {
359 $incoming = trim($incoming);
361 if ($this->enable_logging && $incoming != "") {
362 $this->logfile[] = "<strong>RECV:</strong> " . nl2br(htmlspecialchars($incoming));
365 if ($incoming != "") {
366 $temp = $this->_split_incoming($incoming);
368 for ($a = 0; $a < count($temp); $a++) {
369 $this->packet_queue[] = $this->xmlize($temp[$a]);
378 function StripJID($jid = NULL)
380 preg_match("/(.*)\/(.*)/Ui", $jid, $temp);
381 return ($temp[1] != "") ? $temp[1] : $jid;
386 function SendMessage($to, $type = "normal", $id = NULL, $content = NULL, $payload = NULL)
388 if ($to && is_array($content)) {
390 if (!$id) { $id = $type . "_" . time(); }
392 $content = $this->_array_htmlspecialchars($content);
394 $xml = "<message to='$to' type='$type' id='$id'>\n";
396 if ($content["thread"]) {
397 $xml .= "<thread>" . $content["thread"] . "</thread>\n";
399 if ($content['subject']) {
400 $xml .= "<subject>" . $content['subject'] . "</subject>\n";
403 $xml .= "<body>" . $content["body"] . "</body>\n";
405 $xml .= "</message>\n";
408 if ($this->SendPacket($xml)) {
414 if ($this->enable_logging) {
415 $this->logfile[] = "<strong>Error:</strong> SendMessage() #1";
423 if ($this->enable_logging) {
424 $this->logfile[] = "<strong>Error:</strong> SendMessage() #2";
433 function SendPresence($type = NULL, $to = NULL, $status = NULL, $show = NULL, $priority = NULL)
436 $xml .= ($to) ? " to='$to'" : "";
437 $xml .= ($type) ? " type='$type'" : "";
438 $xml .= ($status || $show || $priority) ? ">\n" : " />\n";
440 $xml .= ($status) ? " <status>$status</status>\n" : "";
441 $xml .= ($show) ? " <show>$show</show>\n" : "";
442 $xml .= ($priority) ? " <priority>$priority</priority>\n" : "";
444 $xml .= ($status || $show || $priority) ? "</presence>\n" : "";
446 if ($this->SendPacket($xml)) {
452 if ($this->enable_logging) {
453 $this->logfile[] = "<strong>Error:</strong> SendPresence() #1";
462 function SendError($to, $id = NULL, $error_number, $error_message = NULL)
464 $xml = "<iq type='error' to='$to'";
465 $xml .= ($id) ? " id='$id'" : "";
467 $xml .= " <error code='$error_number'>";
468 $xml .= ($error_message) ? $error_message : $this->error_codes[$error_number];
469 $xml .= "</error>\n";
472 $this->SendPacket($xml);
477 function RosterUpdate()
479 $roster_request_id = "roster_" . time();
481 $incoming_array = $this->SendIq(NULL, "get", $roster_request_id, "jabber:iq:roster");
483 if (is_array($incoming_array)) {
485 if ($incoming_array["iq"]["@"]["type"] == "result"
486 && $incoming_array["iq"]["@"]["id"] == $roster_request_id
487 && $incoming_array["iq"]["#"]["query"]["0"]["@"]["xmlns"] == "jabber:iq:roster")
490 $number_of_contacts = count($incoming_array["iq"]["#"]["query"][0]["#"]["item"]);
491 $this->roster = array();
493 for ($a = 0; $a < $number_of_contacts; $a++) {
495 $this->roster[$a] = array( "jid" => $incoming_array["iq"]["#"]["query"][0]["#"]["item"][$a]["@"]["jid"],
496 "name" => $incoming_array["iq"]["#"]["query"][0]["#"]["item"][$a]["@"]["name"],
497 "subscription" => $incoming_array["iq"]["#"]["query"][0]["#"]["item"][$a]["@"]["subscription"],
498 "group" => $incoming_array["iq"]["#"]["query"][0]["#"]["item"][$a]["#"]["group"][0]["#"]
506 if ($this->enable_logging) {
507 $this->logfile[] = "<strong>Error:</strong> RosterUpdate() #1";
515 if ($this->enable_logging) {
516 $this->logfile[] = "<strong>Error:</strong> RosterUpdate() #2";
525 function RosterAddUser($jid = NULL, $id = NULL, $name = NULL)
527 $id = ($id) ? $id : "adduser_" . time();
531 $payload = " <item jid='$jid'";
532 $payload .= ($name) ? " name='" . htmlspecialchars($name) . "'" : "";
535 $packet = $this->SendIq(NULL, "set", $id, "jabber:iq:roster", $payload);
537 if ($this->GetInfoFromIqType($packet) == "result") {
539 $this->RosterUpdate();
544 if ($this->enable_logging) {
545 $this->logfile[] = "<strong>Error:</strong> RosterAddUser() #2";
553 if ($this->enable_logging) {
554 $this->logfile[] = "<strong>Error:</strong> RosterAddUser() #1";
563 function RosterRemoveUser($jid = NULL, $id = NULL)
567 $packet = $this->SendIq(NULL, "set", $id, "jabber:iq:roster", "<item jid='$jid' subscription='remove'/>");
569 if ($this->GetInfoFromIqType($packet) == "result") {
571 $this->RosterUpdate();
576 if ($this->enable_logging) {
577 $this->logfile[] = "<strong>Error:</strong> RosterRemoveUser() #2";
585 if ($this->enable_logging) {
586 $this->logfile[] = "<strong>Error:</strong> RosterRemoveUser() #1";
595 function GetFirstFromQueue()
597 reset($this->packet_queue);
598 list($key, $value) = each($this->packet_queue);
599 unset($this->packet_queue[$key]);
601 return (is_array($value)) ? $value : FALSE;
606 function GetFromQueueById($packet_type, $id)
608 $found_message = FALSE;
610 foreach ($this->packet_queue as $key => $value) {
612 if ($value["$packet_type"]["@"]["id"] == $id) {
614 $found_message = $value;
615 unset($this->packet_queue[$key]);
621 return (is_array($found_message)) ? $found_message : FALSE;
626 function CallHandler($packet = NULL)
628 $packet_type = $this->_get_packet_type($packet);
630 if ($packet_type == "message") {
632 $type = $packet["message"]["@"]["type"];
633 $type = ($type != "") ? $type : "normal";
634 $funcmeth = "Handler_message_$type";
636 } elseif ($packet_type == "iq") {
638 $this->TraverseXMLize($packet);
640 $namespace = $packet["iq"]["#"]["query"][0]["@"]["xmlns"];
641 $namespace = str_replace(":", "_", $namespace);
642 $funcmeth = "Handler_iq_$namespace";
644 } elseif ($packet_type == "presence") {
646 $type = $packet["presence"]["@"]["type"];
647 $type = ($type != "") ? $type : "available";
648 $funcmeth = "Handler_presence_$type";
653 if ($funcmeth != "") {
655 if (function_exists($funcmeth)) {
657 call_user_func($funcmeth, $packet);
659 } elseif(method_exists($this, $funcmeth)) {
661 call_user_func(array(&$this, $funcmeth), $packet);
663 } elseif ($this->enable_logging) {
665 $this->Handler_NOT_IMPLEMENTED($packet);
666 $this->logfile[] = "<strong>Error:</strong> CallHandler() #1 - neither method nor function $funcmeth() available";
674 function CruiseControl($seconds = -1)
678 while ($count != $seconds) {
682 $packet = $this->GetFirstFromQueue();
683 $this->CallHandler($packet);
684 } while (count($this->packet_queue) > 1);
695 function SubscriptionAcceptRequest($to = NULL)
697 return ($to) ? $this->SendPresence("subscribed", $to) : FALSE;
702 function SubscriptionDenyRequest($to = NULL)
704 return ($to) ? /* still needs to be done */ TRUE : FALSE;
709 function Subscribe($to = NULL)
711 return ($to) ? $this->SendPresence("subscribe", $to) : FALSE;
716 function Unsubscribe($to = NULL)
718 return ($to) ? $this->SendPresence("unsubscribe", $to) : FALSE;
723 function SendIq($to = NULL, $type = "get", $id = NULL, $xmlns = NULL, $payload = NULL)
725 if (!preg_match("/^(get|set|result|error)$/", $type)) {
728 if ($this->enable_logging) {
729 $this->logfile[] = "<strong>Error:</strong> SendIq() #2 - type must be 'get', 'set', 'result' or 'error'";
734 } elseif ($id && $xmlns) {
736 $xml = "<iq type='$type' id='$id'";
737 $xml .= ($to) ? " to='$to'" : "";
739 <query xmlns='$xmlns'>
744 $this->SendPacket($xml);
745 sleep($this->iq_sleep_timer);
748 return (preg_match("/^(get|set)$/", $type)) ? $this->GetFromQueueById("iq", $id) : TRUE;
752 if ($this->enable_logging) {
753 $this->logfile[] = "<strong>Error:</strong> SendIq() #1 - to, id and xmlns are mandatory";
762 // ======================================================================
764 // ======================================================================
768 function _listen_incoming()
772 while ($line = $this->CONNECTOR->ReadFromSocket($this->connection, 4096)) {
776 $incoming = trim($incoming);
778 if ($this->enable_logging && $incoming != "") {
779 $this->logfile[] = "<strong>RECV:</strong> " . nl2br(htmlspecialchars($incoming));
782 return $this->xmlize($incoming);
787 function _check_connected()
789 $incoming_array = $this->_listen_incoming();
791 if (is_array($incoming_array)) {
793 if ($incoming_array["stream:stream"]["@"]["from"] == $this->server
794 && $incoming_array["stream:stream"]["@"]["xmlns"] == "jabber:client"
795 && $incoming_array["stream:stream"]["@"]["xmlns:stream"] == "http://etherx.jabber.org/streams")
798 $this->stream_id = $incoming_array["stream:stream"]["@"]["id"];
804 if ($this->enable_logging) {
805 $this->logfile[] = "<strong>Error:</strong> _check_connected() #1";
813 if ($this->enable_logging) {
814 $this->logfile[] = "<strong>Error:</strong> _check_connected() #2";
823 function _get_packet_type($packet = NULL)
825 if (is_array($packet)) {
827 $packet_type = key($packet);
830 return ($packet_type) ? $packet_type : FALSE;
835 function _split_incoming($incoming)
837 $temp = preg_split("/<(message|iq|presence|stream)/", $incoming, -1, PREG_SPLIT_DELIM_CAPTURE);
840 for ($a = 1; $a < count($temp); $a = $a + 2) {
841 $array[] = "<" . $temp[$a] . $temp[($a + 1)];
849 // _array_htmlspecialchars()
850 // applies htmlspecialchars() to all values in an array
852 function _array_htmlspecialchars($array)
854 if (is_array($array)) {
855 foreach ($array as $k => $v) {
857 $v = $this->_array_htmlspecialchars($v);
859 $v = htmlspecialchars($v);
869 // ======================================================================
870 // <message/> parsers
871 // ======================================================================
875 function GetInfoFromMessageFrom($packet = NULL)
877 return (is_array($packet)) ? $packet["message"]["@"]["from"] : FALSE;
882 function GetInfoFromMessageType($packet = NULL)
884 return (is_array($packet)) ? $packet["message"]["@"]["type"] : FALSE;
889 function GetInfoFromMessageId($packet = NULL)
891 return (is_array($packet)) ? $packet["message"]["@"]["id"] : FALSE;
896 function GetInfoFromMessageThread($packet = NULL)
898 return (is_array($packet)) ? $packet["message"]["#"]["thread"][0]["#"] : FALSE;
903 function GetInfoFromMessageSubject($packet = NULL)
905 return (is_array($packet)) ? $packet["message"]["#"]["subject"][0]["#"] : FALSE;
910 function GetInfoFromMessageBody($packet = NULL)
912 return (is_array($packet)) ? $packet["message"]["#"]["body"][0]["#"] : FALSE;
917 function GetInfoFromMessageError($packet = NULL)
919 $error = preg_replace("/^\/$/", "", ($packet["message"]["#"]["error"][0]["@"]["code"] . "/" . $packet["message"]["#"]["error"][0]["#"]));
920 return (is_array($packet)) ? $error : FALSE;
925 // ======================================================================
927 // ======================================================================
931 function GetInfoFromIqFrom($packet = NULL)
933 return (is_array($packet)) ? $packet["iq"]["@"]["from"] : FALSE;
938 function GetInfoFromIqType($packet = NULL)
940 return (is_array($packet)) ? $packet["iq"]["@"]["type"] : FALSE;
945 function GetInfoFromIqId($packet = NULL)
947 return (is_array($packet)) ? $packet["iq"]["@"]["id"] : FALSE;
952 function GetInfoFromIqKey($packet = NULL)
954 return (is_array($packet)) ? $packet["iq"]["#"]["query"][0]["#"]["key"][0]["#"] : FALSE;
959 // ======================================================================
960 // <presence/> parsers
961 // ======================================================================
965 function GetInfoFromPresenceFrom($packet = NULL)
967 return (is_array($packet)) ? $packet["presence"]["@"]["from"] : FALSE;
972 function GetInfoFromPresenceType($packet = NULL)
974 return (is_array($packet)) ? $packet["presence"]["@"]["type"] : FALSE;
979 function GetInfoFromPresenceStatus($packet = NULL)
981 return (is_array($packet)) ? $packet["presence"]["#"]["status"][0]["#"] : FALSE;
986 function GetInfoFromPresenceShow($packet = NULL)
988 return (is_array($packet)) ? $packet["presence"]["#"]["show"][0]["#"] : FALSE;
993 function GetInfoFromPresencePriority($packet = NULL)
995 return (is_array($packet)) ? $packet["presence"]["#"]["priority"][0]["#"] : FALSE;
1000 // ======================================================================
1001 // <message/> handlers
1002 // ======================================================================
1006 function Handler_message_normal($packet)
1008 $from = $packet["message"]["@"]["from"];
1009 $this->logfile[] = "<strong>message</strong> (type normal) from $from";
1014 function Handler_message_chat($packet)
1016 $from = $packet["message"]["@"]["from"];
1017 $this->logfile[] = "<strong>message</strong> (type chat) from $from";
1022 function Handler_message_groupchat($packet)
1024 $from = $packet["message"]["@"]["from"];
1025 $this->logfile[] = "<strong>message</strong> (type groupchat) from $from";
1030 function Handler_message_headline($packet)
1032 $from = $packet["message"]["@"]["from"];
1033 $this->logfile[] = "<strong>message</strong> (type headline) from $from";
1038 function Handler_message_error($packet)
1040 $from = $packet["message"]["@"]["from"];
1041 $this->logfile[] = "<strong>message</strong> (type error) from $from";
1046 // ======================================================================
1048 // ======================================================================
1052 // application version updates
1053 function Handler_iq_jabber_iq_autoupdate($packet)
1055 $from = $this->GetInfoFromIqFrom($packet);
1056 $id = $this->GetInfoFromIqId($packet);
1058 $this->SendError($from, $id, 501);
1059 $this->logfile[] = "<strong>jabber:iq:autoupdate</strong> from $from";
1064 // interactive server component properties
1065 function Handler_iq_jabber_iq_agent($packet)
1067 $from = $this->GetInfoFromIqFrom($packet);
1068 $id = $this->GetInfoFromIqId($packet);
1070 $this->SendError($from, $id, 501);
1071 $this->logfile[] = "<strong>jabber:iq:agent</strong> from $from";
1076 // method to query interactive server components
1077 function Handler_iq_jabber_iq_agents($packet)
1079 $from = $this->GetInfoFromIqFrom($packet);
1080 $id = $this->GetInfoFromIqId($packet);
1082 $this->SendError($from, $id, 501);
1083 $this->logfile[] = "<strong>jabber:iq:agents</strong> from $from";
1088 // simple client authentication
1089 function Handler_iq_jabber_iq_auth($packet)
1091 $from = $this->GetInfoFromIqFrom($packet);
1092 $id = $this->GetInfoFromIqId($packet);
1094 $this->SendError($from, $id, 501);
1095 $this->logfile[] = "<strong>jabber:iq:auth</strong> from $from";
1101 function Handler_iq_jabber_iq_oob($packet)
1103 $from = $this->GetInfoFromIqFrom($packet);
1104 $id = $this->GetInfoFromIqId($packet);
1106 $this->SendError($from, $id, 501);
1107 $this->logfile[] = "<strong>jabber:iq:oob</strong> from $from";
1112 // method to store private data on the server
1113 function Handler_iq_jabber_iq_private($packet)
1115 $from = $this->GetInfoFromIqFrom($packet);
1116 $id = $this->GetInfoFromIqId($packet);
1118 $this->SendError($from, $id, 501);
1119 $this->logfile[] = "<strong>jabber:iq:private</strong> from $from";
1124 // method for interactive registration
1125 function Handler_iq_jabber_iq_register($packet)
1127 $from = $this->GetInfoFromIqFrom($packet);
1128 $id = $this->GetInfoFromIqId($packet);
1130 $this->SendError($from, $id, 501);
1131 $this->logfile[] = "<strong>jabber:iq:register</strong> from $from";
1136 // client roster management
1137 function Handler_iq_jabber_iq_roster($packet)
1139 $from = $this->GetInfoFromIqFrom($packet);
1140 $id = $this->GetInfoFromIqId($packet);
1142 $this->SendError($from, $id, 501);
1143 $this->logfile[] = "<strong>jabber:iq:roster</strong> from $from";
1148 // method for searching a user database
1149 function Handler_iq_jabber_iq_search($packet)
1151 $from = $this->GetInfoFromIqFrom($packet);
1152 $id = $this->GetInfoFromIqId($packet);
1154 $this->SendError($from, $id, 501);
1155 $this->logfile[] = "<strong>jabber:iq:search</strong> from $from";
1160 // method for requesting the current time
1161 function Handler_iq_jabber_iq_time($packet)
1163 $type = $this->GetInfoFromIqType($packet);
1164 $from = $this->GetInfoFromIqFrom($packet);
1165 $id = $this->GetInfoFromIqId($packet);
1166 $id = ($id != "") ? $id : "time_" . time();
1168 if ($type == "get") {
1170 $payload = "<utc>" . gmdate("Ydm\TH:i:s") . "</utc>
1171 <tz>" . date("T") . "</tz>
1172 <display>" . date("Y/d/m h:i:s A") . "</display>";
1174 $this->SendIq($from, "result", $id, "jabber:iq:time", $payload);
1177 $this->logfile[] = "<strong>jabber:iq:time</strong> (type $type) from $from";
1182 // method for requesting version
1183 function Handler_iq_jabber_iq_version($packet)
1185 $type = $this->GetInfoFromIqType($packet);
1186 $from = $this->GetInfoFromIqFrom($packet);
1187 $id = $this->GetInfoFromIqId($packet);
1188 $id = ($id != "") ? $id : "version_" . time();
1190 if ($type == "get") {
1192 $payload = "<name>" . $this->iq_version_name . "</name>
1193 <os>" . $this->iq_version_os . "</os>
1194 <version>" . $this->iq_version_version . "</version>";
1196 $this->SendIq($from, "result", $id, "jabber:iq:version", $payload);
1199 $this->logfile[] = "<strong>jabber:iq:version</strong> (type $type) from $from";
1204 // ======================================================================
1205 // <presence/> handlers
1206 // ======================================================================
1210 function Handler_presence_available($packet)
1212 $from = $this->GetInfoFromPresenceFrom($packet);
1214 $show_status = $this->GetInfoFromPresenceStatus($packet) . " / " . $this->GetInfoFromPresenceShow($packet);
1215 $show_status = ($show_status != " / ") ? " ($addendum)" : "";
1217 $this->logfile[] = "<strong>Presence:</strong> (type: available) - $from is available $show_status";
1222 function Handler_presence_unavailable($packet)
1224 $from = $this->GetInfoFromPresenceFrom($packet);
1226 $show_status = $this->GetInfoFromPresenceStatus($packet) . " / " . $this->GetInfoFromPresenceShow($packet);
1227 $show_status = ($show_status != " / ") ? " ($addendum)" : "";
1229 $this->logfile[] = "<strong>Presence:</strong> (type: unavailable) - $from is unavailable $show_status";
1234 function Handler_presence_subscribe($packet)
1236 $from = $this->GetInfoFromPresenceFrom($packet);
1237 $this->subscription_queue[] = $from;
1238 $this->RosterUpdate();
1240 $this->logfile[] = "<strong>Presence:</strong> (type: subscribe) - Subscription request from $from, was added to \$this->subscription_queue, roster updated";
1245 function Handler_presence_subscribed($packet)
1247 $from = $this->GetInfoFromPresenceFrom($packet);
1248 $this->RosterUpdate();
1250 $this->logfile[] = "<strong>Presence:</strong> (type: subscribed) - Subscription allowed by $from, roster updated";
1255 function Handler_presence_unsubscribe($packet)
1257 $from = $this->GetInfoFromPresenceFrom($packet);
1258 $this->SendPresence("unsubscribed", $from);
1259 $this->RosterUpdate();
1261 $this->logfile[] = "<strong>Presence:</strong> (type: unsubscribe) - Request to unsubscribe from $from, was automatically approved, roster updated";
1266 function Handler_presence_unsubscribed($packet)
1268 $from = $this->GetInfoFromPresenceFrom($packet);
1269 $this->RosterUpdate();
1271 $this->logfile[] = "<strong>Presence:</strong> (type: unsubscribed) - Unsubscribed from $from's presence";
1276 // ======================================================================
1278 // ======================================================================
1282 // Generic handler for unsupported requests
1283 function Handler_NOT_IMPLEMENTED($packet)
1285 $packet_type = $this->_get_packet_type($packet);
1286 $from = call_user_func(array(&$this, "GetInfoFrom" . ucfirst($packet_type) . "From"), $packet);
1287 $id = call_user_func(array(&$this, "GetInfoFrom" . ucfirst($packet_type) . "Id"), $packet);
1289 $this->SendError($from, $id, 501);
1290 $this->logfile[] = "<strong>Unrecognized <$packet_type/></strong> from $from";
1295 // ======================================================================
1297 // m@d pr0ps to the coders ;)
1298 // ======================================================================
1303 // (c) Hans Anderson / http://www.hansanderson.com/php/xml/
1305 function xmlize($data) {
1306 $vals = $index = $array = array();
1307 $parser = xml_parser_create();
1308 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
1309 xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
1310 xml_parse_into_struct($parser, $data, $vals, $index);
1311 xml_parser_free($parser);
1315 $tagname = $vals[$i]['tag'];
1316 $array[$tagname]["@"] = $vals[$i]["attributes"];
1317 $array[$tagname]["#"] = $this->_xml_depth($vals, $i);
1325 // (c) Hans Anderson / http://www.hansanderson.com/php/xml/
1327 function _xml_depth($vals, &$i) {
1328 $children = array();
1330 if ($vals[$i]['value']) {
1331 array_push($children, trim($vals[$i]['value']));
1334 while (++$i < count($vals)) {
1336 switch ($vals[$i]['type']) {
1339 array_push($children, trim($vals[$i]['value']));
1343 $tagname = $vals[$i]['tag'];
1344 $size = sizeof($children["$tagname"]);
1345 $children[$tagname][$size]["#"] = trim($vals[$i]['value']);
1346 if ($vals[$i]["attributes"]) {
1347 $children[$tagname][$size]["@"] = $vals[$i]["attributes"];
1352 $tagname = $vals[$i]['tag'];
1353 $size = sizeof($children["$tagname"]);
1354 if ($vals[$i]["attributes"]) {
1355 $children["$tagname"][$size]["@"] = $vals[$i]["attributes"];
1356 $children["$tagname"][$size]["#"] = $this->_xml_depth($vals, $i);
1358 $children["$tagname"][$size]["#"] = $this->_xml_depth($vals, $i);
1375 // (c) acebone@f2s.com, a HUGE help!
1377 function TraverseXMLize($array, $arrName = "array", $level = 0) {
1382 while (list($key, $val) = @each($array)) {
1383 if (is_array($val)) {
1384 $this->TraverseXMLize($val, $arrName . "[" . $key . "]", $level + 1);
1386 echo '$' . $arrName . '[' . $key . '] = "' . $val . "\"\n";
1399 class MakeXML extends Jabber
1411 function AddPacketDetails($string, $value = NULL)
1413 if (preg_match("/\(([0-9]*)\)$/i", $string)) {
1414 $string .= "/[\"#\"]";
1417 $temp = @explode("/", $string);
1419 for ($a = 0; $a < count($temp); $a++) {
1420 $temp[$a] = preg_replace("/^[@]{1}([a-z0-9_]*)$/i", "[\"@\"][\"\\1\"]", $temp[$a]);
1421 $temp[$a] = preg_replace("/^([a-z0-9_]*)\(([0-9]*)\)$/i", "[\"\\1\"][\\2]", $temp[$a]);
1422 $temp[$a] = preg_replace("/^([a-z0-9_]*)$/i", "[\"\\1\"]", $temp[$a]);
1425 $node = implode("", $temp);
1427 // Yeahyeahyeah, I know it's ugly... get over it. ;)
1428 echo "\$this->nodes$node = \"" . htmlspecialchars($value) . "\";<br/>";
1429 eval("\$this->nodes$node = \"" . htmlspecialchars($value) . "\";");
1434 function BuildPacket($array = NULL)
1438 $array = $this->nodes;
1441 if (is_array($array)) {
1443 array_multisort($array, SORT_ASC, SORT_STRING);
1445 foreach ($array as $key => $value) {
1447 if (is_array($value) && $key == "@") {
1449 foreach ($value as $subkey => $subvalue) {
1450 $subvalue = htmlspecialchars($subvalue);
1451 $text .= " $subkey='$subvalue'";
1456 } elseif ($key == "#") {
1458 $text .= htmlspecialchars($value);
1460 } elseif (is_array($value)) {
1462 for ($a = 0; $a < count($value); $a++) {
1466 if (!$this->_preg_grep_keys("/^@/", $value[$a])) {
1470 $text .= $this->BuildPacket($value[$a]);
1472 $text .= "</$key>\n";
1477 $value = htmlspecialchars($value);
1478 $text .= "<$key>$value</$key>\n";
1490 function _preg_grep_keys($pattern, $array)
1492 while (list($key, $val) = each($array)) {
1493 if (preg_match($pattern, $key)) {
1494 $newarray[$key] = $val;
1497 return (is_array($newarray)) ? $newarray : FALSE;
1503 class CJP_StandardConnector
1505 function OpenSocket($server, $port)
1507 return fsockopen($server, $port);
1512 function CloseSocket($connection)
1514 return fclose($connection);
1518 function WriteToSocket($connection, $data)
1520 return fwrite($connection, $data);
1525 function ReadFromSocket($connection, $chunksize)
1527 return fread($connection, $chunksize);