PHP Classes

File: class.jabber.php

Recommend this page to a friend!
  Classes of Carlo Zottmann   Class.Jabber.PHP   class.jabber.php   Download  
File: class.jabber.php
Role: Class source
Content type: text/plain
Description: v0.4
Class: Class.Jabber.PHP
API to interact with the Jabber network
Author: By
Last change: transport/gateway connection methods (ICQ/AIM/Yahoo/MSN/IRC anyone?), some bugfixes.
Date: 20 years ago
Size: 43,004 bytes
 

Contents

Class file image Download
<?php /*************************************************************************** Class.Jabber.PHP v0.4 (c) 2002 Carlo "Gossip" Zottmann http://phpjabber.g-blog.net *** gossip@jabber.g-blog.net The FULL documentation and examples for this software can be found at http://phpjabber.g-blog.net (not many doc comments in here, sorry) last modified: 27.04.2003 13:01:53 CET ***************************************************************************/ /*************************************************************************** * * ***************************************************************************/ /* Jabber::Connect() Jabber::Disconnect() Jabber::SendAuth() Jabber::AccountRegistration($reg_email {string}, $reg_name {string}) Jabber::Listen() Jabber::SendPacket($xml {string}) Jabber::RosterUpdate() Jabber::RosterAddUser($jid {string}, $id {string}, $name {string}) Jabber::RosterRemoveUser($jid {string}, $id {string}) Jabber::RosterExistsJID($jid {string}) Jabber::Subscribe($jid {string}) Jabber::Unsubscribe($jid {string}) Jabber::CallHandler($message {array}) Jabber::CruiseControl([$seconds {number}]) Jabber::SubscriptionApproveRequest($to {string}) Jabber::SubscriptionDenyRequest($to {string}) Jabber::GetFirstFromQueue() Jabber::GetFromQueueById($packet_type {string}, $id {string}) Jabber::SendMessage($to {string}, $id {number}, $type {string}, $content {array}[, $payload {array}]) Jabber::SendIq($to {string}, $type {string}, $id {string}, $xmlns {string}[, $payload {string}]) Jabber::SendPresence($type {string}[, $to {string}[, $status {string}[, $show {string}[, $priority {number}]]]]) Jabber::SendError($to {string}, $id {string}, $error_number {number}[, $error_message {string}]) Jabber::TransportRegistrationDetails($transport {string}) Jabber::TransportRegistration($transport {string}, $details {array}) Jabber::GetvCard($jid {string}[, $id {string}]) -- EXPERIMENTAL -- Jabber::GetInfoFromMessageFrom($packet {array}) Jabber::GetInfoFromMessageType($packet {array}) Jabber::GetInfoFromMessageId($packet {array}) Jabber::GetInfoFromMessageThread($packet {array}) Jabber::GetInfoFromMessageSubject($packet {array}) Jabber::GetInfoFromMessageBody($packet {array}) Jabber::GetInfoFromMessageError($packet {array}) Jabber::GetInfoFromIqFrom($packet {array}) Jabber::GetInfoFromIqType($packet {array}) Jabber::GetInfoFromIqId($packet {array}) Jabber::GetInfoFromIqKey($packet {array}) Jabber::GetInfoFromIqError($packet {array}) Jabber::GetInfoFromPresenceFrom($packet {array}) Jabber::GetInfoFromPresenceType($packet {array}) Jabber::GetInfoFromPresenceStatus($packet {array}) Jabber::GetInfoFromPresenceShow($packet {array}) Jabber::GetInfoFromPresencePriority($packet {array}) Jabber::AddToLog($string {string}) Jabber::PrintLog() MakeXML::AddPacketDetails($string {string}[, $value {string/number}]) MakeXML::BuildPacket([$array {array}]) */ class Jabber { var $server; var $port; var $username; var $password; var $resource; var $jid; var $connection; var $delay_disconnect; var $stream_id; var $roster; var $enable_logging; var $log_array; var $log_filename; var $log_filehandler; var $iq_sleep_timer; var $last_ping_time; var $packet_queue; var $subscription_queue; var $iq_version_name; var $iq_version_os; var $iq_version_version; var $error_codes; var $connected; var $keep_alive_id; var $returned_keep_alive; var $txnid; var $CONNECTOR; function Jabber() { $this->server = "localhost"; $this->port = "5222"; $this->username = "larry"; $this->password = "curly"; $this->resource = NULL; $this->enable_logging = FALSE; $this->log_array = array(); $this->log_filename = ''; $this->log_filehandler = FALSE; $this->packet_queue = array(); $this->subscription_queue = array(); $this->iq_sleep_timer = 1; $this->delay_disconnect = 1; $this->returned_keep_alive = TRUE; $this->txnid = 0; $this->iq_version_name = "Class.Jabber.PHP -- http://phpjabber.g-blog.net -- by Carlo 'Gossip' Zottmann, gossip@jabber.g-blog.net"; $this->iq_version_version = "0.4"; $this->iq_version_os = $_SERVER['SERVER_SOFTWARE']; $this->connection_class = "CJP_StandardConnector"; $this->error_codes = array(400 => "Bad Request", 401 => "Unauthorized", 402 => "Payment Required", 403 => "Forbidden", 404 => "Not Found", 405 => "Not Allowed", 406 => "Not Acceptable", 407 => "Registration Required", 408 => "Request Timeout", 409 => "Conflict", 500 => "Internal Server Error", 501 => "Not Implemented", 502 => "Remove Server Error", 503 => "Service Unavailable", 504 => "Remove Server Timeout", 510 => "Disconnected"); } function Connect() { $this->_create_logfile(); $this->CONNECTOR = new $this->connection_class; if ($this->CONNECTOR->OpenSocket($this->server, $this->port)) { $this->SendPacket("<?xml version='1.0' encoding='UTF-8' ?" . ">\n"); $this->SendPacket("<stream:stream to='{$this->server}' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>\n"); sleep(2); if ($this->_check_connected()) { $this->connected = TRUE; // Nathan Fritz return TRUE; } else { $this->AddToLog("ERROR: Connect() #1"); return FALSE; } } else { $this->AddToLog("ERROR: Connect() #2"); return FALSE; } } function Disconnect() { if (is_int($this->delay_disconnect)) { sleep($this->delay_disconnect); } $this->SendPacket("</stream:stream>"); $this->CONNECTOR->CloseSocket(); $this->_close_logfile(); $this->PrintLog(); } function SendAuth() { $this->auth_id = "auth_" . md5(time() . $_SERVER['REMOTE_ADDR']); $this->resource = ($this->resource != NULL) ? $this->resource : ("Class.Jabber.PHP " . md5($this->auth_id)); $this->jid = "{$this->username}@{$this->server}/{$this->resource}"; // request available authentication methods $payload = "<username>{$this->username}</username>"; $packet = $this->SendIq(NULL, 'get', $this->auth_id, "jabber:iq:auth", $payload); // was a result returned? if ($this->GetInfoFromIqType($packet) == 'result' && $this->GetInfoFromIqId($packet) == $this->auth_id) { // yes, now check for auth method availability in descending order (best to worst) if (!function_exists(mhash)) { $this->AddToLog("ATTENTION: SendAuth() - mhash() is not available; screw 0k and digest method, we need to go with plaintext auth"); } // auth_0k if (function_exists(mhash) && isset($packet['iq']['#']['query'][0]['#']['sequence'][0]["#"]) && isset($packet['iq']['#']['query'][0]['#']['token'][0]["#"])) { return $this->_sendauth_0k($packet['iq']['#']['query'][0]['#']['token'][0]["#"], $packet['iq']['#']['query'][0]['#']['sequence'][0]["#"]); } // digest elseif (function_exists(mhash) && isset($packet['iq']['#']['query'][0]['#']['digest'])) { return $this->_sendauth_digest(); } // plain text elseif ($packet['iq']['#']['query'][0]['#']['password']) { return $this->_sendauth_plaintext(); } // dude, you're fucked { $this->AddToLog("ERROR: SendAuth() #2 - No auth method available!"); return FALSE; } } else { // no result returned $this->AddToLog("ERROR: SendAuth() #1"); return FALSE; } } function AccountRegistration($reg_email = NULL, $reg_name = NULL) { $packet = $this->SendIq($this->server, 'get', 'reg_01', 'jabber:iq:register'); if ($packet) { $key = $this->GetInfoFromIqKey($packet); // just in case a key was passed back from the server unset($packet); $payload = "<username>{$this->username}</username> <password>{$this->password}</password> <email>$reg_email</email> <name>$reg_name</name>\n"; $payload .= ($key) ? "<key>$key</key>\n" : ''; $packet = $this->SendIq($this->server, 'set', "reg_01", "jabber:iq:register", $payload); if ($this->GetInfoFromIqType($packet) == 'result') { if (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) { $return_code = 1; } else { $return_code = 2; } if ($this->resource) { $this->jid = "{$this->username}@{$this->server}/{$this->resource}"; } else { $this->jid = "{$this->username}@{$this->server}"; } } elseif ($this->GetInfoFromIqType($packet) == 'error' && isset($packet['iq']['#']['error'][0]['#'])) { // "conflict" error, i.e. already registered if ($packet['iq']['#']['error'][0]['@']['code'] == '409') { $return_code = 1; } else { $return_code = "Error " . $packet['iq']['#']['error'][0]['@']['code'] . ": " . $packet['iq']['#']['error'][0]['#']; } } return $return_code; } else { return 3; } } function SendPacket($xml) { $xml = trim($xml); if ($this->CONNECTOR->WriteToSocket($xml)) { $this->AddToLog("SEND: $xml"); return TRUE; } else { $this->AddToLog('ERROR: SendPacket() #1'); return FALSE; } } function Listen() { unset($incoming); while ($line = $this->CONNECTOR->ReadFromSocket(4096)) { $incoming .= $line; } $incoming = trim($incoming); if ($incoming != "") { $this->AddToLog("RECV: $incoming"); } if ($incoming != "") { $temp = $this->_split_incoming($incoming); for ($a = 0; $a < count($temp); $a++) { $this->packet_queue[] = $this->xmlize($temp[$a]); } } return TRUE; } function StripJID($jid = NULL) { preg_match("/(.*)\/(.*)/Ui", $jid, $temp); return ($temp[1] != "") ? $temp[1] : $jid; } function SendMessage($to, $type = "normal", $id = NULL, $content = NULL, $payload = NULL) { if ($to && is_array($content)) { if (!$id) { $id = $type . "_" . time(); } $content = $this->_array_htmlspecialchars($content); $xml = "<message to='$to' type='$type' id='$id'>\n"; if ($content['subject']) { $xml .= "<subject>" . $content['subject'] . "</subject>\n"; } if ($content['thread']) { $xml .= "<thread>" . $content['thread'] . "</thread>\n"; } $xml .= "<body>" . $content['body'] . "</body>\n"; $xml .= $payload; $xml .= "</message>\n"; if ($this->SendPacket($xml)) { return TRUE; } else { $this->AddToLog("ERROR: SendMessage() #1"); return FALSE; } } else { $this->AddToLog("ERROR: SendMessage() #2"); return FALSE; } } function SendPresence($type = NULL, $to = NULL, $status = NULL, $show = NULL, $priority = NULL) { $xml = "<presence"; $xml .= ($to) ? " to='$to'" : ''; $xml .= ($type) ? " type='$type'" : ''; $xml .= ($status || $show || $priority) ? ">\n" : " />\n"; $xml .= ($status) ? " <status>$status</status>\n" : ''; $xml .= ($show) ? " <show>$show</show>\n" : ''; $xml .= ($priority) ? " <priority>$priority</priority>\n" : ''; $xml .= ($status || $show || $priority) ? "</presence>\n" : ''; if ($this->SendPacket($xml)) { return TRUE; } else { $this->AddToLog("ERROR: SendPresence() #1"); return FALSE; } } function SendError($to, $id = NULL, $error_number, $error_message = NULL) { $xml = "<iq type='error' to='$to'"; $xml .= ($id) ? " id='$id'" : ''; $xml .= ">\n"; $xml .= " <error code='$error_number'>"; $xml .= ($error_message) ? $error_message : $this->error_codes[$error_number]; $xml .= "</error>\n"; $xml .= "</iq>"; $this->SendPacket($xml); } function RosterUpdate() { $roster_request_id = "roster_" . time(); $incoming_array = $this->SendIq(NULL, 'get', $roster_request_id, "jabber:iq:roster"); if (is_array($incoming_array)) { if ($incoming_array['iq']['@']['type'] == 'result' && $incoming_array['iq']['@']['id'] == $roster_request_id && $incoming_array['iq']['#']['query']['0']['@']['xmlns'] == "jabber:iq:roster") { $number_of_contacts = count($incoming_array['iq']['#']['query'][0]['#']['item']); $this->roster = array(); for ($a = 0; $a < $number_of_contacts; $a++) { $this->roster[$a] = array( "jid" => strtolower($incoming_array['iq']['#']['query'][0]['#']['item'][$a]['@']['jid']), "name" => $incoming_array['iq']['#']['query'][0]['#']['item'][$a]['@']['name'], "subscription" => $incoming_array['iq']['#']['query'][0]['#']['item'][$a]['@']['subscription'], "group" => $incoming_array['iq']['#']['query'][0]['#']['item'][$a]['#']['group'][0]['#'] ); } return TRUE; } else { $this->AddToLog("ERROR: RosterUpdate() #1"); return FALSE; } } else { $this->AddToLog("ERROR: RosterUpdate() #2"); return FALSE; } } function RosterAddUser($jid = NULL, $id = NULL, $name = NULL) { $id = ($id) ? $id : "adduser_" . time(); if ($jid) { $payload = " <item jid='$jid'"; $payload .= ($name) ? " name='" . htmlspecialchars($name) . "'" : ''; $payload .= "/>\n"; $packet = $this->SendIq(NULL, 'set', $id, "jabber:iq:roster", $payload); if ($this->GetInfoFromIqType($packet) == 'result') { $this->RosterUpdate(); return TRUE; } else { $this->AddToLog("ERROR: RosterAddUser() #2"); return FALSE; } } else { $this->AddToLog("ERROR: RosterAddUser() #1"); return FALSE; } } function RosterRemoveUser($jid = NULL, $id = NULL) { $id = ($id) ? $id : 'deluser_' . time(); if ($jid && $id) { $packet = $this->SendIq(NULL, 'set', $id, "jabber:iq:roster", "<item jid='$jid' subscription='remove'/>"); if ($this->GetInfoFromIqType($packet) == 'result') { $this->RosterUpdate(); return TRUE; } else { $this->AddToLog("ERROR: RosterRemoveUser() #2"); return FALSE; } } else { $this->AddToLog("ERROR: RosterRemoveUser() #1"); return FALSE; } } function RosterExistsJID($jid = NULL) { if ($jid) { if ($this->roster) { for ($a = 0; $a < count($this->roster); $a++) { if ($this->roster[$a]['jid'] == strtolower($jid)) { return $a; } } } else { $this->AddToLog("ERROR: RosterExistsJID() #2"); return FALSE; } } else { $this->AddToLog("ERROR: RosterExistsJID() #1"); return FALSE; } } function GetFirstFromQueue() { return array_shift($this->packet_queue); } function GetFromQueueById($packet_type, $id) { $found_message = FALSE; foreach ($this->packet_queue as $key => $value) { if ($value[$packet_type]['@']['id'] == $id) { $found_message = $value; unset($this->packet_queue[$key]); break; } } return (is_array($found_message)) ? $found_message : FALSE; } function CallHandler($packet = NULL) { $packet_type = $this->_get_packet_type($packet); if ($packet_type == "message") { $type = $packet['message']['@']['type']; $type = ($type != "") ? $type : "normal"; $funcmeth = "Handler_message_$type"; } elseif ($packet_type == "iq") { $namespace = $packet['iq']['#']['query'][0]['@']['xmlns']; $namespace = str_replace(":", "_", $namespace); $funcmeth = "Handler_iq_$namespace"; } elseif ($packet_type == "presence") { $type = $packet['presence']['@']['type']; $type = ($type != "") ? $type : "available"; $funcmeth = "Handler_presence_$type"; } if ($funcmeth != '') { if (function_exists($funcmeth)) { call_user_func($funcmeth, $packet); } elseif (method_exists($this, $funcmeth)) { call_user_func(array(&$this, $funcmeth), $packet); } else { $this->Handler_NOT_IMPLEMENTED($packet); $this->AddToLog("ERROR: CallHandler() #1 - neither method nor function $funcmeth() available"); } } } function CruiseControl($seconds = -1) { $count = 0; while ($count != $seconds) { $this->Listen(); do { $packet = $this->GetFirstFromQueue(); if ($packet) { $this->CallHandler($packet); } } while (count($this->packet_queue) > 1); $count += 0.25; usleep(250000); if ($this->last_ping_time != date('H:i')) { // Modified by Nathan Fritz if ($this->returned_keep_alive == FALSE) { $this->connected = FALSE; $this->AddToLog('EVENT: Disconnected'); } $this->returned_keep_alive = FALSE; $this->keep_alive_id = 'keep_alive_' . time(); $this->SendPacket("<iq id='{$this->keep_alive_id}'/>", 'CruiseControl'); // ** $this->last_ping_time = date("H:i"); } } return TRUE; } function SubscriptionAcceptRequest($to = NULL) { return ($to) ? $this->SendPresence("subscribed", $to) : FALSE; } function SubscriptionDenyRequest($to = NULL) { return ($to) ? $this->SendPresence("unsubscribed", $to) : FALSE; } function Subscribe($to = NULL) { return ($to) ? $this->SendPresence("subscribe", $to) : FALSE; } function Unsubscribe($to = NULL) { return ($to) ? $this->SendPresence("unsubscribe", $to) : FALSE; } function SendIq($to = NULL, $type = 'get', $id = NULL, $xmlns = NULL, $payload = NULL, $from = NULL) { if (!preg_match("/^(get|set|result|error)$/", $type)) { unset($type); $this->AddToLog("ERROR: SendIq() #2 - type must be 'get', 'set', 'result' or 'error'"); return FALSE; } elseif ($id && $xmlns) { $xml = "<iq type='$type' id='$id'"; $xml .= ($to) ? " to='$to'" : ''; $xml .= ($from) ? " from='$from'" : ''; $xml .= "> <query xmlns='$xmlns'> $payload </query> </iq>"; $this->SendPacket($xml); sleep($this->iq_sleep_timer); $this->Listen(); return (preg_match("/^(get|set)$/", $type)) ? $this->GetFromQueueById("iq", $id) : TRUE; } else { $this->AddToLog("ERROR: SendIq() #1 - to, id and xmlns are mandatory"); return FALSE; } } // get the transport registration fields // method written by Steve Blinch, http://www.blitzaffe.com function TransportRegistrationDetails($transport) { $this->txnid++; $packet = $this->SendIq($transport, 'get', "reg_{$this->txnid}", "jabber:iq:register", NULL, $this->jid); if ($packet) { $res = array(); foreach ($packet['iq']['#']['query'][0]['#'] as $element => $data) { if ($element != 'instructions' && $element != 'key') { $res[] = $element; } } return $res; } else { return 3; } } // register with the transport // method written by Steve Blinch, http://www.blitzaffe.com function TransportRegistration($transport, $details) { $this->txnid++; $packet = $this->SendIq($transport, 'get', "reg_{$this->txnid}", "jabber:iq:register", NULL, $this->jid); if ($packet) { $key = $this->GetInfoFromIqKey($packet); // just in case a key was passed back from the server unset($packet); $payload = ($key) ? "<key>$key</key>\n" : ''; foreach ($details as $element => $value) { $payload .= "<$element>$value</$element>\n"; } $packet = $this->SendIq($transport, 'set', "reg_{$this->txnid}", "jabber:iq:register", $payload); if ($this->GetInfoFromIqType($packet) == 'result') { if (isset($packet['iq']['#']['query'][0]['#']['registered'][0]['#'])) { $return_code = 1; } else { $return_code = 2; } } elseif ($this->GetInfoFromIqType($packet) == 'error') { if (isset($packet['iq']['#']['error'][0]['#'])) { $return_code = "Error " . $packet['iq']['#']['error'][0]['@']['code'] . ": " . $packet['iq']['#']['error'][0]['#']; $this->AddToLog('ERROR: TransportRegistration()'); } } return $return_code; } else { return 3; } } function GetvCard($jid = NULL, $id = NULL) { if (!$id) { $id = "vCard_" . md5(time() . $_SERVER['REMOTE_ADDR']); } if ($jid) { $xml = "<iq type='get' to='$jid' id='$id'> <vCard xmlns='vcard-temp'/> </iq>"; $this->SendPacket($xml); sleep($this->iq_sleep_timer); $this->Listen(); return $this->GetFromQueueById("iq", $id); } else { $this->AddToLog("ERROR: GetvCard() #1 - to and id are mandatory"); return FALSE; } } function PrintLog() { if ($this->enable_logging) { if ($this->log_filehandler) { echo "<h2>Logging enabled, logged events have been written to the file {$this->log_filename}.</h2>\n"; } else { echo "<h2>Logging enabled, logged events below:</h2>\n"; echo "<pre>\n"; echo (count($this->log_array) > 0) ? implode("\n\n\n", $this->log_array) : "No logged events."; echo "</pre>\n"; } } } // ====================================================================== // private methods // ====================================================================== function _sendauth_0k($zerok_token, $zerok_sequence) { // initial hash of password $zerok_hash = mhash(MHASH_SHA1, $this->password); $zerok_hash = bin2hex($zerok_hash); // sequence 0: hash of hashed-password and token $zerok_hash = mhash(MHASH_SHA1, $zerok_hash . $zerok_token); $zerok_hash = bin2hex($zerok_hash); // repeat as often as needed for ($a = 0; $a < $zerok_sequence; $a++) { $zerok_hash = mhash(MHASH_SHA1, $zerok_hash); $zerok_hash = bin2hex($zerok_hash); } $payload = "<username>{$this->username}</username> <hash>$zerok_hash</hash> <resource>{$this->resource}</resource>"; $packet = $this->SendIq(NULL, 'set', $this->auth_id, "jabber:iq:auth", $payload); // was a result returned? if ($this->GetInfoFromIqType($packet) == 'result' && $this->GetInfoFromIqId($packet) == $this->auth_id) { return TRUE; } else { $this->AddToLog("ERROR: _sendauth_0k() #1"); return FALSE; } } function _sendauth_digest() { $payload = "<username>{$this->username}</username> <resource>{$this->resource}</resource> <digest>" . bin2hex(mhash(MHASH_SHA1, $this->stream_id . $this->password)) . "</digest>"; $packet = $this->SendIq(NULL, 'set', $this->auth_id, "jabber:iq:auth", $payload); // was a result returned? if ($this->GetInfoFromIqType($packet) == 'result' && $this->GetInfoFromIqId($packet) == $this->auth_id) { return TRUE; } else { $this->AddToLog("ERROR: _sendauth_digest() #1"); return FALSE; } } function _sendauth_plaintext() { $payload = "<username>{$this->username}</username> <password>{$this->password}</password> <resource>{$this->resource}</resource>"; $packet = $this->SendIq(NULL, 'set', $this->auth_id, "jabber:iq:auth", $payload); // was a result returned? if ($this->GetInfoFromIqType($packet) == 'result' && $this->GetInfoFromIqId($packet) == $this->auth_id) { return TRUE; } else { $this->AddToLog("ERROR: _sendauth_plaintext() #1"); return FALSE; } } function _listen_incoming() { unset($incoming); while ($line = $this->CONNECTOR->ReadFromSocket(4096)) { $incoming .= $line; } $incoming = trim($incoming); if ($incoming != "") { $this->AddToLog("RECV: $incoming"); } return $this->xmlize($incoming); } function _check_connected() { $incoming_array = $this->_listen_incoming(); if (is_array($incoming_array)) { 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") { $this->stream_id = $incoming_array["stream:stream"]['@']['id']; return TRUE; } else { $this->AddToLog("ERROR: _check_connected() #1"); return FALSE; } } else { $this->AddToLog("ERROR: _check_connected() #2"); return FALSE; } } function _get_packet_type($packet = NULL) { if (is_array($packet)) { reset($packet); $packet_type = key($packet); } return ($packet_type) ? $packet_type : FALSE; } function _split_incoming($incoming) { $temp = preg_split("/<(message|iq|presence|stream)/", $incoming, -1, PREG_SPLIT_DELIM_CAPTURE); $array = array(); for ($a = 1; $a < count($temp); $a = $a + 2) { $array[] = "<" . $temp[$a] . $temp[($a + 1)]; } return $array; } function _create_logfile() { if ($this->log_filename != '' && $this->enable_logging) { $this->log_filehandler = fopen($this->log_filename, 'w'); } } function AddToLog($string) { if ($this->enable_logging) { if ($this->log_filehandler) { fwrite($this->log_filehandler, $string . "\n\n"); } else { $this->log_array[] = htmlspecialchars($string); } } } function _close_logfile() { if ($this->log_filehandler) { fclose($this->log_filehandler); } } // _array_htmlspecialchars() // applies htmlspecialchars() to all values in an array function _array_htmlspecialchars($array) { if (is_array($array)) { foreach ($array as $k => $v) { if (is_array($v)) { $v = $this->_array_htmlspecialchars($v); } else { $v = htmlspecialchars($v); } } } return $array; } // ====================================================================== // <message/> parsers // ====================================================================== function GetInfoFromMessageFrom($packet = NULL) { return (is_array($packet)) ? $packet['message']['@']['from'] : FALSE; } function GetInfoFromMessageType($packet = NULL) { return (is_array($packet)) ? $packet['message']['@']['type'] : FALSE; } function GetInfoFromMessageId($packet = NULL) { return (is_array($packet)) ? $packet['message']['@']['id'] : FALSE; } function GetInfoFromMessageThread($packet = NULL) { return (is_array($packet)) ? $packet['message']['#']['thread'][0]['#'] : FALSE; } function GetInfoFromMessageSubject($packet = NULL) { return (is_array($packet)) ? $packet['message']['#']['subject'][0]['#'] : FALSE; } function GetInfoFromMessageBody($packet = NULL) { return (is_array($packet)) ? $packet['message']['#']['body'][0]['#'] : FALSE; } function GetInfoFromMessageError($packet = NULL) { $error = preg_replace("/^\/$/", "", ($packet['message']['#']['error'][0]['@']['code'] . "/" . $packet['message']['#']['error'][0]['#'])); return (is_array($packet)) ? $error : FALSE; } // ====================================================================== // <iq/> parsers // ====================================================================== function GetInfoFromIqFrom($packet = NULL) { return (is_array($packet)) ? $packet['iq']['@']['from'] : FALSE; } function GetInfoFromIqType($packet = NULL) { return (is_array($packet)) ? $packet['iq']['@']['type'] : FALSE; } function GetInfoFromIqId($packet = NULL) { return (is_array($packet)) ? $packet['iq']['@']['id'] : FALSE; } function GetInfoFromIqKey($packet = NULL) { return (is_array($packet)) ? $packet['iq']['#']['query'][0]['#']['key'][0]['#'] : FALSE; } function GetInfoFromIqError($packet = NULL) { $error = preg_replace("/^\/$/", "", ($packet['iq']['#']['error'][0]['@']['code'] . "/" . $packet['iq']['#']['error'][0]['#'])); return (is_array($packet)) ? $error : FALSE; } // ====================================================================== // <presence/> parsers // ====================================================================== function GetInfoFromPresenceFrom($packet = NULL) { return (is_array($packet)) ? $packet['presence']['@']['from'] : FALSE; } function GetInfoFromPresenceType($packet = NULL) { return (is_array($packet)) ? $packet['presence']['@']['type'] : FALSE; } function GetInfoFromPresenceStatus($packet = NULL) { return (is_array($packet)) ? $packet['presence']['#']['status'][0]['#'] : FALSE; } function GetInfoFromPresenceShow($packet = NULL) { return (is_array($packet)) ? $packet['presence']['#']['show'][0]['#'] : FALSE; } function GetInfoFromPresencePriority($packet = NULL) { return (is_array($packet)) ? $packet['presence']['#']['priority'][0]['#'] : FALSE; } // ====================================================================== // <message/> handlers // ====================================================================== function Handler_message_normal($packet) { $from = $packet['message']['@']['from']; $this->AddToLog("EVENT: Message (type normal) from $from"); } function Handler_message_chat($packet) { $from = $packet['message']['@']['from']; $this->AddToLog("EVENT: Message (type chat) from $from"); } function Handler_message_groupchat($packet) { $from = $packet['message']['@']['from']; $this->AddToLog("EVENT: Message (type groupchat) from $from"); } function Handler_message_headline($packet) { $from = $packet['message']['@']['from']; $this->AddToLog("EVENT: Message (type headline) from $from"); } function Handler_message_error($packet) { $from = $packet['message']['@']['from']; $this->AddToLog("EVENT: Message (type error) from $from"); } // ====================================================================== // <iq/> handlers // ====================================================================== // application version updates function Handler_iq_jabber_iq_autoupdate($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: jabber:iq:autoupdate from $from"); } // interactive server component properties function Handler_iq_jabber_iq_agent($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: jabber:iq:agent from $from"); } // method to query interactive server components function Handler_iq_jabber_iq_agents($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: jabber:iq:agents from $from"); } // simple client authentication function Handler_iq_jabber_iq_auth($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: jabber:iq:auth from $from"); } // out of band data function Handler_iq_jabber_iq_oob($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: jabber:iq:oob from $from"); } // method to store private data on the server function Handler_iq_jabber_iq_private($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: jabber:iq:private from $from"); } // method for interactive registration function Handler_iq_jabber_iq_register($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: jabber:iq:register from $from"); } // client roster management function Handler_iq_jabber_iq_roster($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: jabber:iq:roster from $from"); } // method for searching a user database function Handler_iq_jabber_iq_search($packet) { $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: jabber:iq:search from $from"); } // method for requesting the current time function Handler_iq_jabber_iq_time($packet) { $type = $this->GetInfoFromIqType($packet); $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $id = ($id != "") ? $id : "time_" . time(); if ($type == 'get') { $payload = "<utc>" . gmdate("Ydm\TH:i:s") . "</utc> <tz>" . date("T") . "</tz> <display>" . date("Y/d/m h:i:s A") . "</display>"; $this->SendIq($from, 'result', $id, "jabber:iq:time", $payload); } $this->AddToLog("EVENT: jabber:iq:time (type $type) from $from"); } // method for requesting version function Handler_iq_jabber_iq_version($packet) { $type = $this->GetInfoFromIqType($packet); $from = $this->GetInfoFromIqFrom($packet); $id = $this->GetInfoFromIqId($packet); $id = ($id != "") ? $id : "version_" . time(); if ($type == 'get') { $payload = "<name>{$this->iq_version_name}</name> <os>{$this->iq_version_os}</os> <version>{$this->iq_version_version}</version>"; $this->SendIq($from, 'result', $id, "jabber:iq:version", $payload); } $this->AddToLog("EVENT: jabber:iq:version (type $type) from $from"); } // keepalive method, added by Nathan Fritz function Handler_iq_($packet) { if ($this->keep_alive_id == $this->GetInfoFromIqId($packet)) { $this->returned_keep_alive = TRUE; $this->AddToLog('EVENT: Keep-Alive returned, connection alive.'); } } // ====================================================================== // <presence/> handlers // ====================================================================== function Handler_presence_available($packet) { $from = $this->GetInfoFromPresenceFrom($packet); $show_status = $this->GetInfoFromPresenceStatus($packet) . " / " . $this->GetInfoFromPresenceShow($packet); $show_status = ($show_status != " / ") ? " ($addendum)" : ''; $this->AddToLog("EVENT: Presence (type: available) - $from is available $show_status"); } function Handler_presence_unavailable($packet) { $from = $this->GetInfoFromPresenceFrom($packet); $show_status = $this->GetInfoFromPresenceStatus($packet) . " / " . $this->GetInfoFromPresenceShow($packet); $show_status = ($show_status != " / ") ? " ($addendum)" : ''; $this->AddToLog("EVENT: Presence (type: unavailable) - $from is unavailable $show_status"); } function Handler_presence_subscribe($packet) { $from = $this->GetInfoFromPresenceFrom($packet); $this->SubscriptionAcceptRequest($from); $this->RosterUpdate(); $this->log_array[] = "<b>Presence:</b> (type: subscribe) - Subscription request from $from, was added to \$this->subscription_queue, roster updated"; } function Handler_presence_subscribed($packet) { $from = $this->GetInfoFromPresenceFrom($packet); $this->RosterUpdate(); $this->AddToLog("EVENT: Presence (type: subscribed) - Subscription allowed by $from, roster updated"); } function Handler_presence_unsubscribe($packet) { $from = $this->GetInfoFromPresenceFrom($packet); $this->SendPresence("unsubscribed", $from); $this->RosterUpdate(); $this->AddToLog("EVENT: Presence (type: unsubscribe) - Request to unsubscribe from $from, was automatically approved, roster updated"); } function Handler_presence_unsubscribed($packet) { $from = $this->GetInfoFromPresenceFrom($packet); $this->RosterUpdate(); $this->AddToLog("EVENT: Presence (type: unsubscribed) - Unsubscribed from $from's presence"); } // Added By Nathan Fritz function Handler_presence_error($packet) { $from = $this->GetInfoFromPresenceFrom($packet); $this->AddToLog("EVENT: Presence (type: error) - Error in $from's presence"); } // ====================================================================== // Generic handlers // ====================================================================== // Generic handler for unsupported requests function Handler_NOT_IMPLEMENTED($packet) { $packet_type = $this->_get_packet_type($packet); $from = call_user_func(array(&$this, "GetInfoFrom" . ucfirst($packet_type) . "From"), $packet); $id = call_user_func(array(&$this, "GetInfoFrom" . ucfirst($packet_type) . "Id"), $packet); $this->SendError($from, $id, 501); $this->AddToLog("EVENT: Unrecognized <$packet_type/> from $from"); } // ====================================================================== // Third party code // m@d pr0ps to the coders ;) // ====================================================================== // xmlize() // (c) Hans Anderson / http://www.hansanderson.com/php/xml/ function xmlize($data) { $vals = $index = $array = array(); $parser = xml_parser_create(); xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); xml_parse_into_struct($parser, $data, $vals, $index); xml_parser_free($parser); $i = 0; $tagname = $vals[$i]['tag']; $array[$tagname]['@'] = $vals[$i]['attributes']; $array[$tagname]['#'] = $this->_xml_depth($vals, $i); return $array; } // _xml_depth() // (c) Hans Anderson / http://www.hansanderson.com/php/xml/ function _xml_depth($vals, &$i) { $children = array(); if ($vals[$i]['value']) { array_push($children, trim($vals[$i]['value'])); } while (++$i < count($vals)) { switch ($vals[$i]['type']) { case 'cdata': array_push($children, trim($vals[$i]['value'])); break; case 'complete': $tagname = $vals[$i]['tag']; $size = sizeof($children[$tagname]); $children[$tagname][$size]['#'] = trim($vals[$i]['value']); if ($vals[$i]['attributes']) { $children[$tagname][$size]['@'] = $vals[$i]['attributes']; } break; case 'open': $tagname = $vals[$i]['tag']; $size = sizeof($children[$tagname]); if ($vals[$i]['attributes']) { $children[$tagname][$size]['@'] = $vals[$i]['attributes']; $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); } else { $children[$tagname][$size]['#'] = $this->_xml_depth($vals, $i); } break; case 'close': return $children; break; } } return $children; } // TraverseXMLize() // (c) acebone@f2s.com, a HUGE help! function TraverseXMLize($array, $arrName = "array", $level = 0) { if ($level == 0) { echo "<pre>"; } while (list($key, $val) = @each($array)) { if (is_array($val)) { $this->TraverseXMLize($val, $arrName . "[" . $key . "]", $level + 1); } else { echo '$' . $arrName . '[' . $key . '] = "' . $val . "\"\n"; } } if ($level == 0) { echo "</pre>"; } } } class MakeXML extends Jabber { var $nodes; function MakeXML() { $nodes = array(); } function AddPacketDetails($string, $value = NULL) { if (preg_match("/\(([0-9]*)\)$/i", $string)) { $string .= "/[\"#\"]"; } $temp = @explode("/", $string); for ($a = 0; $a < count($temp); $a++) { $temp[$a] = preg_replace("/^[@]{1}([a-z0-9_]*)$/i", "[\"@\"][\"\\1\"]", $temp[$a]); $temp[$a] = preg_replace("/^([a-z0-9_]*)\(([0-9]*)\)$/i", "[\"\\1\"][\\2]", $temp[$a]); $temp[$a] = preg_replace("/^([a-z0-9_]*)$/i", "[\"\\1\"]", $temp[$a]); } $node = implode("", $temp); // Yeahyeahyeah, I know it's ugly... get over it. ;) echo "\$this->nodes$node = \"" . htmlspecialchars($value) . "\";<br/>"; eval("\$this->nodes$node = \"" . htmlspecialchars($value) . "\";"); } function BuildPacket($array = NULL) { if (!$array) { $array = $this->nodes; } if (is_array($array)) { array_multisort($array, SORT_ASC, SORT_STRING); foreach ($array as $key => $value) { if (is_array($value) && $key == "@") { foreach ($value as $subkey => $subvalue) { $subvalue = htmlspecialchars($subvalue); $text .= " $subkey='$subvalue'"; } $text .= ">\n"; } elseif ($key == "#") { $text .= htmlspecialchars($value); } elseif (is_array($value)) { for ($a = 0; $a < count($value); $a++) { $text .= "<$key"; if (!$this->_preg_grep_keys("/^@/", $value[$a])) { $text .= ">"; } $text .= $this->BuildPacket($value[$a]); $text .= "</$key>\n"; } } else { $value = htmlspecialchars($value); $text .= "<$key>$value</$key>\n"; } } return $text; } } function _preg_grep_keys($pattern, $array) { while (list($key, $val) = each($array)) { if (preg_match($pattern, $key)) { $newarray[$key] = $val; } } return (is_array($newarray)) ? $newarray : FALSE; } } class CJP_StandardConnector { var $active_socket; function OpenSocket($server, $port) { if ($this->active_socket = fsockopen($server, $port)) { socket_set_blocking($this->active_socket, 0); socket_set_timeout($this->active_socket, 31536000); return TRUE; } else { return FALSE; } } function CloseSocket() { return fclose($this->active_socket); } function WriteToSocket($data) { return fwrite($this->active_socket, $data); } function ReadFromSocket($chunksize) { set_magic_quotes_runtime(0); $buffer = fread($this->active_socket, $chunksize); set_magic_quotes_runtime(get_magic_quotes_gpc()); return $buffer; } } ?>