* @revision 05 * @license http://creativecommons.org/licenses/by-sa/3.0/de/ Creative Commons Attribution-Share Alike Germany * @homepage http://oss.tiggerswelt.net/xmpp * @copyright Copyright © 2008 tiggersWelt.net */ class XMPP_ICQ_Transport extends tiggerXMPP_Component { // Storage for OSCAR-Clients private $Clients = array (); function __construct ($Domain, $Router, $RouterPort = 5347) { // Inherit to our parent parent::__construct ($Domain, $Router, $RouterPort, tiggerXMPP_Stream::DEBUG_PACKETS); $this->loadClients (); } // ================================================================ // Client handling stuff protected function loadClients () { $this->Clients = XMPP_Component_Client::listItems ($this); } public function addClient ($JID, $Username, $Password) { // Check if client is already registered if (is_object ($this->getClient ($JID))) return true; // Make sure we have a nice JID $JID = $this->getJID (true, true, false, $JID); // Create new OSCAR-Connection $OSCAR = new OSCAR_Transport ($JID, $this, $Username, $Password, false); if (!$OSCAR->login ()) { print "Login failed\n"; return false; } // Create a new Client $Client = new XMPP_Component_Client ($JID, $OSCAR); // Store login-information if (!$Client->setLogin ($Username, $Password)) { $OSCAR->logout (); return false; } // Subscribe to this entity $this->subscribeContact ($JID); $this->setPresence (self::PRESENCE_ONLINE, "", null, $JID); $this->pushRoster ($JID); $this->Clients [$JID] = $Client; return true; } public function getClient ($JID) { // Get a cleaned JID $BareJID = $this->getJID (true, true, false, $JID); if (!isset ($this->Clients [$BareJID])) return false; return $this->Clients [$BareJID]; } // {{{ getOSCAR /** * Find an OSCAR-Connection for a given JID * * @param string $JID * * @access public * @return object */ public function getOSCAR ($JID) { if (!is_object ($Client = $this->getClient ($JID))) return false; return $Client->getOSCAR (); } // }}} // {{{ probeClients /** * Check status of our XMPP-Clients * * @params bool $Online (optional) Check offline clients as well * * @access public * @return void */ public function probeClients ($Online = false) { foreach ($this->Clients as $JID=>$Client) if ($Online || !$Client->isOnline ()) { $this->requestPresence ($JID); $this->setPresence (self::PRESENCE_ONLINE, "", null, $JID); } } // }}} // {{{ readBlock /** * Read and handle incoming events from both XMPP and OSCAR * * @param bool $Block (optional) Enter blocking mode (default) * @param bool $Handle (optional) Handle the incoming event from XMPP directly (default) * @access public * @return mixed */ public function readBlock ($Block = true, $Handle = true) { $rc = parent::readBlock ($Block, $Handle); foreach ($this->Clients as $Client) if (is_object ($OSCAR = $Client->getOSCAR ())) $OSCAR->handleEvent (); return $rc; } // }}} // ================================================================ // Presence (Status) Forwarding // {{{ contactStatus /** * Forward Status-Changes to OSCAR * * @access protected * @return void */ protected function contactStatus ($JID, $Status, $Message, $Priority, $Receiver) { // Discard non-domain stati if (intval ($this->getJID (true, false, false, $Receiver)) != 0) return true; // Try to get OSCAR-Instance if (!is_object ($Client = self::getOSCAR ($JID))) return false; // Check if we are still connected if (!$Client->isOnline ()) { print "Client $JID went online\n"; if (!$Client->login ()) return false; $this->setPresence (self::PRESENCE_ONLINE, "", null, $JID); } // Map XMPP-Statuses to OSCAR $Map = array ( tiggerXMPP_Stream::PRESENCE_OFFLINE => Oscar_TLV_Status::STATUS_OFFLINE, tiggerXMPP_Stream::PRESENCE_ONLINE => Oscar_TLV_Status::STATUS_ONLINE, tiggerXMPP_Stream::PRESENCE_AWAY => Oscar_TLV_Status::STATUS_AWAY, tiggerXMPP_Stream::PRESENCE_XA => Oscar_TLV_Status::STATUS_NA, tiggerXMPP_Stream::PRESENCE_DND => Oscar_TLV_Status::STATUS_DND, tiggerXMPP_Stream::PRESENCE_CHAT => Oscar_TLV_Status::STATUS_FREEFORCHAT, ); // Set the status $Client->setAwayMessage ($Message, $Map [$Status]); $this->setPresence ($Status, $Message, null, $JID); } // }}} // {{{ contactOffline /** * Disconnect from OSCAR when our XMPP-Client changes status to offline * * @access public * @return void */ protected function contactOffline ($JID, $Message, $Receiver = null) { // Try to get OSCAR-Instance if (!is_object ($Client = self::getOSCAR ($JID))) return false; // Discard non-domain stati if (intval ($this->getJID (true, false, false, $Receiver)) != 0) return true; // Close connection $Client->logoff (); } // }}} // ================================================================ // IM Forwarding // {{{ receiveMessage /** * Forward received messages to OSCAR * * @access protected * @return void */ protected function receiveMessage ($From, $Subject, $Body, $Type = self::MESSAGE_NORMAL, $ID = null, $To = null, $Thread = null) { // Check if the client is logged in if (!is_object ($Client = self::getOSCAR ($From))) return $this->sendMessage ($From, "Well, there is no instance for you :-/", $Type); // Get the receiver of the message $Receiver = intval ($this->getJID (true, false, false, $To)); // Handle local message if ($Receiver == 0) { $Body = strtolower ($Body); if ($Body == "ping") return $this->sendMessage ($From, "PONG", $Type); elseif ($Body == "push") $this->pushRoster ($From); elseif ($Body == "die") throw new Exception ("User requested me to die"); elseif (substr ($Body, 0, 6) == "macro ") { if (!is_file ("macro/" . substr ($Body, 6) . ".php")) return $this->sendMessage ($From, "Macro not found", $Type); include ("macro/" . substr ($Body, 6) . ".php"); } return; } // Forward the message to OSCAR return $Client->sendMessage ($Receiver, str_replace ("^^", "", $Body)); } // }}} // ================================================================ // Roster Stuff // {{{ pushRoster /** * Push the roster to a JID * * @param string $JID * * @access private * @return void */ private function pushRoster ($JID) { // Retrive OSCAR-Object for JID if (!is_object ($Client = self::getOSCAR ($JID))) return false; // Retrive Roster from OSCAR if (!is_object ($Roster = $Client->getRoster ())) return false; // Retrive Contacts from Roster if (!is_array ($Users = $Roster->getContacts ())) return false; // Create a jabberd2-component packet #$Response = new XML_Tag ("route"); #$Response->xmlns = "http://jabberd.jabberstudio.org/ns/component/1.0"; #$Response->from = $this->getJID (false, true, false); #$Response->to = $this->getJID (false, true, false, $JID); // Append IQ-Packet #$Response->Subtags ["iq"] = array ($IQ = new XML_Tag ("iq", $Response)); # $Response = $IQ = new XML_Tag ("iq"); #$IQ->from = $this->getJID (false, true, false); #$IQ->to = $JID; #$IQ->type = "set"; #$IQ->id = "rosterpush_" . time (); // Append query-packet #$IQ->Subtags ["query"] = array ($Query = new XML_Tag ("query", $IQ)); #$Query->xmlns = "jabber:iq:roster"; #$Query->Subtags ["item"] = array (); // XEP 144 Method $Response = new XML_Tag ("message"); $Response->from = $this->getJID (false, true, false); $Response->to = $JID; $Response->Subtags ["body"][] = new XML_Tag ("body", $Response, "Your ICQ-Roster"); $Response->Subtags ["x"][] = $Query = new XML_Tag ("x", $Response); $Query->xmlns = "http://jabber.org/protocol/rosterx"; // Append Users foreach ($Users as $User) { $Query->Subtags ["item"][] = $Item = new XML_Tag ("item", $Query); $Item->jid = intval (trim ($User->getName ())) . "@" . $Response->from; #$Item->name = trim ($User->Alias != "" ? $User->Alias : $User->getName ()); $Item->name = intval ($User->getName ()); #$Item->subscription = "both"; $Item->action = "add"; if (is_object ($User->Group)) $Item->Subtags ["group"] = array (new XML_Tag ("group", $Item, trim ($Group->Name))); unset ($Item); # self::presencePacket ($JID, "subscribed", $User->getName () . "@" . $this->Domain); # $Client->contactStatus ($User, $User->getStatus ()); } $this->sendXML ($Response); } // }}} // {{{ subscribeRequest /** * Handle incoming subscription-request * XMPP-Client wants to add an OSCAR-Client to his roster * * @param string $JID * @param string $ToJID * * @access protected * @return bool */ protected function subscribeRequest ($JID, $ToJID) { // Retrive requested UIN $UIN = intval ($this->getJID (true, false, false, $ToJID)); // Try to get OSCAR-Handle for the requesting entity if (!is_object ($OSCAR = $this->getOSCAR ($JID))) return false; // Subscriptions to ourself if ($UIN == 0) return true; // Retrive Roster from OSCAR if (!is_object ($Roster = $OSCAR->getRoster ())) return false; // Retrive Contacts from Roster if (is_object ($Roster->getContact ($UIN))) return true; // Add contact to our roster $Roster->addContact ($UIN); return null; } // }}} // {{{ unsubscribeRequest /** * Handle incoming unsubscribe-request * XMPP Client wants to remove us or an OSCAR-Contact from his roster * * @param string $JID * @param string $ToJID * * @access publoc * @return bool */ protected function unsubscribeRequest ($JID, $ToJID) { // Retrive requested UIN $UIN = intval ($this->getJID (true, false, false, $ToJID)); $JID = $this->getJID (true, true, false, $JID); // Retrive Client-Handle for this entity if (!is_object ($Client = $this->getClient ($JID))) return true; // Try to get OSCAR-Handle for the requesting entity if (!is_object ($OSCAR = $this->getOSCAR ($JID))) return true; // Request to our self if ($UIN == 0) { // Clean the remote roster $Me = $this->getJID (false, true, false); if (is_array ($Users = $Roster->getContacts ())) foreach ($Users as $User) $this->presencePacket ($JID, "unsubscribed", intval (trim ($User->getName ())) . "@" . $Me); $this->presencePacket ($JID, "unsubscribed", $Me); $this->unsubscribeContact ($JID); // Logout from OSCAR $OSCAR->logoff (); // Remove the client $Client->remove (); unset ($this->Clients [$ToJID]); return true; } # TODO: Handle real unsubscribes / Remove UIN from *our* roster return false; } // }}} // {{{ subscribed /** * Handle granted subscribtion * XMPP-Client allowed some OSCAR-User to add him to his roster * * @param string $JID * @param string $toJID Receiving JID (useful for components) * * @access protected * @return void */ protected function subscribed ($JID, $ToJID) { // Retrive requested UIN $UIN = intval ($this->getJID (true, false, false, $ToJID)); // Try to get Oscar-Handle for the requesting entity if (($UIN == 0) || !is_object ($Oscar = $this->getOscar ($JID))) return; // Forward the event to OSCAR $Oscar->acceptAuthorization ($UIN); } // }}} // {{{ unsubscribed /** * Handle removed subscribtion * XMPP-Client revoked auth from an OSCAR-Client * * @param string $JID * @param string $toJID Receiving JID (useful for components) * * @access protected * @return void */ protected function unsubscribed ($JID, $ToJID) { // Retrive requested UIN $UIN = intval ($this->getJID (true, false, false, $ToJID)); // Try to get Oscar-Handle for the requesting entity if (($UIN == 0) || !is_object ($Oscar = $this->getOscar ($JID))) return; // Forward the event to OSCAR $Oscar->removeAuthorization ($UIN); } // }}} } ?>