* @revision 04 * @license http://creativecommons.org/licenses/by-sa/3.0/de/ Creative Commons Attribution-Share Alike 3.0 Germany * @homepage http://oss.tiggerswelt.net/oscar/ * @copyright Copyright © 2009 tiggersWelt.net */ // Load our required classes require_once ("oscar/roster/group.php"); require_once ("oscar/roster/contact.php"); require_once ("oscar/roster/transaction.php"); /** * Oscar Roster * * @class Oscar_Roster * @package Oscar * @author Bernd Holzmueller **/ class Oscar_Roster { private $Parent = null; private $Groups = array (); private $Users = array (); private $privacyList = array ( "Allow" => array (), "Deny" => array (), ); private $transactionLocal = null; private $transactionRemote = null; private $lastMod = 0; private $Version = 0; private $Diff = 0; private $maxID = 1; // Name of class to create contacts from private $contactClass = "Oscar_Roster_Contact"; // {{{ __construct /** * Create a new roster * * @param object $Parent * * @access friendly * @return void */ function __construct ($Parent) { $this->Parent = $Parent; } // }}} public function getLocalTransaction () { } // {{{ requestRefresh /** * Refresh the roster * * @access public * @return void */ public function requestRefresh () { $SNAC = new Oscar_SNAC_SSI_Checkout ($this->Parent); $SNAC->Counter = count ($this->Users) + count ($this->Groups) + count ($this->privacyList ["Allow"]) + count ($this->privacyList ["Deny"]) + $this->Diff; $SNAC->ModTime = $this->lastChange; return $SNAC->writeFLAP (); } // }}} // {{{ updateFromSNAC /** * Update the roster by a received SNAC of type SNAC_Feedbag_Reply * * @param object $SNAC * * @access public * @return void */ public function updateFromSNAC ($SNAC) { // Validate the incoming SNAC if (!($SNAC instanceof Oscar_SNAC_Feedbag_Reply)) return false; $this->lastChange = $SNAC->LastMod; $this->Version = $SNAC->Version; if (!is_array ($Items = $SNAC->Items)) return $this->Parent->rosterUpdate ($this->Version, $this->lastChange); // Append groups to roster foreach ($Items as $ID=>$Item) { $Handled = false; if ($Item->ItemID > $this->maxID) $this->maxID = $Item->ItemID; // Ignore master-Group for the moment switch ($Item->Type) { // Buddy-Item case Oscar_SNAC_Feedbag_Item::TYPE_BUDDY: $Handled = true; $this->updateUser ($Item); break; // Buddy-Group case Oscar_SNAC_Feedbag_Item::TYPE_GROUP: $Handled = true; $this->updateGroup ($Item); break; // Permit case Oscar_SNAC_Feedbag_Item::TYPE_PERMIT: $Handled = true; $this->privacyList ["Allow"][$Item->getID ()] = $Item->Name; break; // Reject case Oscar_SNAC_Feedbag_Item::TYPE_DENY: $Handled = true; $this->privacyList ["Allow"][$Item->getID ()] = $Item->Name; break; // Default Permit/Deny-Setting case Oscar_SNAC_Feedbag_Item::TYPE_PDINFO: if (is_array ($Item->TLVs)) foreach ($Item->TLVs as $TLV) if ($Handled = ($TLV instanceof Oscar_TLV_PrivacySetting)) { $this->privacyList ["Default"] = $TLV->Setting; break; } default: $this->Diff++; break; } if ($Handled) unset ($Items [$ID]); } // Debug unhandled items foreach ($Items as $Item) { print " 0x" . dechex ($Item->GroupID) . "/0x" . dechex ($Item->ItemID) . "/0x" . dechex ($Item->Type) . " " . $Item->Name . " (" . count ($Item->TLVs) . ")\n"; foreach ($Item->TLVs as $TLV) print " " . $TLV->toString () . "\n"; } $this->Parent->rosterUpdate ($this->Version, $this->lastChange); } // }}} // {{{ setContactClass /** * Set Class to create roster contacts from * * @param string $Class * * @access public * @return bool **/ public function setContactClass ($Class) { if (!is_subclass_of ($Class, "Oscar_Roster_Contact")) return false; $this->contactClass = $Class; return true; } // }}} // {{{ createContact /** * Create a new contact-handle * * @access private * @return object **/ private function createContact ($ID, $Name) { return new $this->contactClass ($ID, $Name, $this); } // }}} // {{{ updateGroup /** * Update a group from an SSI-Update * * @param object $Group * * @access private * @return void */ public function updateGroup ($Group) { // Get a valid group-handle if (!isset ($this->Groups [$Group->GroupID])) { $Item = new Oscar_Roster_Group; $Item->ID = $Group->GroupID; } else $Item = $this->Groups [$Group->GroupID]; // Update the handle $Item->Name = $Group->Name; // Store back (just to be sure) $this->Groups [$Group->GroupID] = $Item; } // }}} // {{{ updateUser /** * Update a user from an SSI-Update * * @param object $User * * @access private * @return void */ private function updateUser ($User) { if (!($User instanceof Oscar_SNAC_Feedbag_Item)) return false; $idx = $User->getID (); if (!isset ($this->Users [$idx])) $this->Users [$idx] = self::createContact ($idx, $User->Name); $Item = $this->Users [$idx]; // Create link to assigned group if (isset ($this->Groups [$User->GroupID])) { if (is_object ($Item->Group) && ($Item->Group->ID != $User->GroupID)) { $Item->Group->removeUser ($Item); $this->Groups [$User->GroupID]->addUser ($Item); } } else $Item->Group = null; if (is_array ($User->TLVs)) $Item->update ($User); } // }}} // {{{ setOffline /** * Set all users on our roster offlin * * @param bool $Callback (optional) Run default callback on contacts * * @access public * @return void **/ public function setOffline ($Callback = true) { foreach ($this->Users as $idx=>$User) { if (!$User->isOnline ()) continue; $User->setStatus (array (), Oscar_TLV_Status::STATUS_OFFLINE); if ($Callback) $this->Parent->contactOffline ($User->getName ()); } } // }}} // {{{ getContact /** * Get a contact-handle from roster * * @param string $User * * @access public * @return object */ public function getContact ($Name, $Create = false) { if (isset ($this->Users [$Name])) return $this->Users [$Name]; foreach ($this->Users as $User) if ($User->getName () == $Name) return $User; if (!$Create) return false; # TODO: Reimplement this # $this->Users [$User] = self::createContact ($User); } // }}} // {{{ getContacts /** * Get all users on our roster * * @access public * @return array **/ public function getContacts () { return $this->Users; } // }}} // {{{ getOscar /** * Retrive handle of our parent * * @access public * @return object **/ public function getOscar () { return $this->Parent; } // }}} public function addContact ($UID, $Question = "", $Complete = true) { // Retrive handle of our parent client if (!is_object ($Parent = $this->getOscar ())) return false; // Retrive handle of our transaction if (!is_object ($Transaction = $this->getLocalTransaction ())) return false; // Create a new item $Handle = new Oscar_SNAC_Feedbag_Item ($Parent); foreach ($this->Groups as $Group) { $Handle->GroupID = $Group->ID; break; } $Handle->ItemID = ++$this->maxID; $Handle->Type = Oscar_SNAC_Feedbag_Item::TYPE_BUDDY; $Handle->Name = $UID; # TODO: Where to put the question to? // Put item to transaction $Transaction->add (array ($Handle)); // Complete transaction if ($Complete) $Transaction->finish (); } } ?>