. * * @package TeamSpeak3 * @version 1.1.24 * @author Sven 'ScP' Paulsen * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. */ /** * @class TeamSpeak3_Node_Host * @brief Class describing a TeamSpeak 3 server instance and all it's parameters. */ class TeamSpeak3_Node_Host extends TeamSpeak3_Node_Abstract { /** * @ignore */ protected $whoami = null; /** * @ignore */ protected $version = null; /** * @ignore */ protected $serverList = null; /** * @ignore */ protected $permissionEnds = null; /** * @ignore */ protected $permissionList = null; /** * @ignore */ protected $permissionCats = null; /** * @ignore */ protected $predefined_query_name = null; /** * @ignore */ protected $exclude_query_clients = FALSE; /** * @ignore */ protected $start_offline_virtual = FALSE; /** * @ignore */ protected $sort_clients_channels = FALSE; /** * The TeamSpeak3_Node_Host constructor. * * @param TeamSpeak3_Adapter_ServerQuery $squery * @return TeamSpeak3_Node_Host */ public function __construct(TeamSpeak3_Adapter_ServerQuery $squery) { $this->parent = $squery; } /** * Returns the primary ID of the selected virtual server. * * @return integer */ public function serverSelectedId() { return $this->whoamiGet("virtualserver_id", 0); } /** * Returns the primary UDP port of the selected virtual server. * * @return integer */ public function serverSelectedPort() { return $this->whoamiGet("virtualserver_port", 0); } /** * Returns the servers version information including platform and build number. * * @param string $ident * @return mixed */ public function version($ident = null) { if($this->version === null) { $this->version = $this->request("version")->toList(); } return ($ident && isset($this->version[$ident])) ? $this->version[$ident] : $this->version; } /** * Selects a virtual server by ID to allow further interaction. * * @param integer $sid * @param boolean $virtual * @return void */ public function serverSelect($sid, $virtual = null) { if($this->whoami !== null && $this->serverSelectedId() == $sid) return; $virtual = ($virtual !== null) ? $virtual : $this->start_offline_virtual; $getargs = func_get_args(); $this->execute("use", array("sid" => $sid, $virtual ? "-virtual" : null)); if($sid != 0 && $this->predefined_query_name !== null) { $this->execute("clientupdate", array("client_nickname" => (string) $this->predefined_query_name)); } $this->whoamiReset(); $this->setStorage("_server_use", array(__FUNCTION__, $getargs)); TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerselected", $this); } /** * Alias for serverSelect(). * * @param integer $sid * @param boolean $virtual * @return void */ public function serverSelectById($sid, $virtual = null) { $this->serverSelect($sid, $virtual); } /** * Selects a virtual server by UDP port to allow further interaction. * * @param integer $port * @param boolean $virtual * @return void */ public function serverSelectByPort($port, $virtual = null) { if($this->whoami !== null && $this->serverSelectedPort() == $port) return; $virtual = ($virtual !== null) ? $virtual : $this->start_offline_virtual; $getargs = func_get_args(); $this->execute("use", array("port" => $port, $virtual ? "-virtual" : null)); if($port != 0 && $this->predefined_query_name !== null) { $this->execute("clientupdate", array("client_nickname" => (string) $this->predefined_query_name)); } $this->whoamiReset(); $this->setStorage("_server_use", array(__FUNCTION__, $getargs)); TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerselected", $this); } /** * Deselects the active virtual server. * * @return void */ public function serverDeselect() { $this->serverSelect(0); $this->delStorage("_server_use"); } /** * Returns the ID of a virtual server matching the given port. * * @param integer $port * @return integer */ public function serverIdGetByPort($port) { $sid = $this->execute("serveridgetbyport", array("virtualserver_port" => $port))->toList(); return $sid["server_id"]; } /** * Returns the port of a virtual server matching the given ID. * * @param integer $sid * @return integer */ public function serverGetPortById($sid) { if(!array_key_exists((string) $sid, $this->serverList())) { throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); } return $this->serverList[intval((string) $sid)]["virtualserver_port"]; } /** * Returns the TeamSpeak3_Node_Server object matching the currently selected ID. * * @return TeamSpeak3_Node_Server */ public function serverGetSelected() { return $this->serverGetById($this->serverSelectedId()); } /** * Returns the TeamSpeak3_Node_Server object matching the given ID. * * @param integer $sid * @return TeamSpeak3_Node_Server */ public function serverGetById($sid) { $this->serverSelectById($sid); return new TeamSpeak3_Node_Server($this, array("virtualserver_id" => intval($sid))); } /** * Returns the TeamSpeak3_Node_Server object matching the given port number. * * @param integer $port * @return TeamSpeak3_Node_Server */ public function serverGetByPort($port) { $this->serverSelectByPort($port); return new TeamSpeak3_Node_Server($this, array("virtualserver_id" => $this->serverSelectedId())); } /** * Returns the first TeamSpeak3_Node_Server object matching the given name. * * @param string $name * @throws TeamSpeak3_Adapter_ServerQuery_Exception * @return TeamSpeak3_Node_Server */ public function serverGetByName($name) { foreach($this->serverList() as $server) { if($server["virtualserver_name"] == $name) return $server; } throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); } /** * Returns the first TeamSpeak3_Node_Server object matching the given unique identifier. * * @param string $uid * @throws TeamSpeak3_Adapter_ServerQuery_Exception * @return TeamSpeak3_Node_Server */ public function serverGetByUid($uid) { foreach($this->serverList() as $server) { if($server["virtualserver_unique_identifier"] == $uid) return $server; } throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); } /** * Returns the first TeamSpeak3_Node_Server object matching the given TSDNS hostname. Like the * TeamSpeak 3 Client, this method will start looking for a TSDNS server on the second-level * domain including a fallback to the third-level domain of the specified $tsdns parameter. * * @param string $tsdns * @throws TeamSpeak3_Adapter_ServerQuery_Exception * @return TeamSpeak3_Node_Server */ public function serverGetByTSDNS($tsdns) { $parts = TeamSpeak3_Helper_Uri::getFQDNParts($tsdns); $query = TeamSpeak3_Helper_String::factory(array_shift($parts)); while($part = array_shift($parts)) { $query->prepend($part); try { $port = TeamSpeak3::factory("tsdns://" . $query . "/?timeout=3")->resolve($tsdns)->section(":", 1); return $this->serverGetByPort($port == "" ? 9987 : $port); } catch(TeamSpeak3_Transport_Exception $e) { /* skip "Connection timed out" and "Connection refused" */ if($e->getCode() != 10060 && $e->getCode() != 10061) throw $e; } } throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); } /** * Creates a new virtual server using given properties and returns an assoc * array containing the new ID and initial admin token. * * @param array $properties * @return array */ public function serverCreate(array $properties = array()) { $this->serverListReset(); $detail = $this->execute("servercreate", $properties)->toList(); $server = new TeamSpeak3_Node_Server($this, array("virtualserver_id" => intval($detail["sid"]))); TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServercreated", $this, $detail["sid"]); TeamSpeak3_Helper_Signal::getInstance()->emit("notifyTokencreated", $server, $detail["token"]); return $detail; } /** * Deletes the virtual server specified by ID. * * @param integer $sid * @return void */ public function serverDelete($sid) { $this->serverListReset(); $this->execute("serverdelete", array("sid" => $sid)); TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerdeleted", $this, $sid); } /** * Starts the virtual server specified by ID. * * @param integer $sid * @return void */ public function serverStart($sid) { if($sid == $this->serverSelectedId()) { $this->serverDeselect(); } $this->execute("serverstart", array("sid" => $sid)); $this->serverListReset(); TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerstarted", $this, $sid); } /** * Stops the virtual server specified by ID. * * @param integer $sid * @return void */ public function serverStop($sid) { if($sid == $this->serverSelectedId()) { $this->serverDeselect(); } $this->execute("serverstop", array("sid" => $sid)); $this->serverListReset(); TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServerstopped", $this, $sid); } /** * Stops the entire TeamSpeak 3 Server instance by shutting down the process. * * @return void */ public function serverStopProcess() { TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServershutdown", $this); $this->execute("serverprocessstop"); } /** * Returns an array filled with TeamSpeak3_Node_Server objects. * * @param array $filter * @return array */ public function serverList(array $filter = array()) { if($this->serverList === null) { $servers = $this->request("serverlist -uid")->toAssocArray("virtualserver_id"); $this->serverList = array(); foreach($servers as $sid => $server) { $this->serverList[$sid] = new TeamSpeak3_Node_Server($this, $server); } $this->resetNodeList(); } return $this->filterList($this->serverList, $filter); } /** * Resets the list of virtual servers. * * @return void */ public function serverListReset() { $this->resetNodeList(); $this->serverList = null; } /** * Returns a list of IP addresses used by the server instance on multi-homed machines. * * @return array */ public function bindingList($subsystem = "voice") { return $this->execute("bindinglist", array("subsystem" => $subsystem))->toArray(); } /** * Returns a list of permissions available on the server instance. * * @return array */ public function permissionList() { if($this->permissionList === null) { $this->fetchPermissionList(); } foreach($this->permissionList as $permname => $permdata) { if(isset($permdata["permcatid"]) && $permdata["permgrant"]) { continue; } $this->permissionList[$permname]["permcatid"] = $this->permissionGetCategoryById($permdata["permid"]); $this->permissionList[$permname]["permgrant"] = $this->permissionGetGrantById($permdata["permid"]); $grantsid = "i_needed_modify_power_" . substr($permname, 2); if(!$permdata["permname"]->startsWith("i_needed_modify_power_") && !isset($this->permissionList[$grantsid])) { $this->permissionList[$grantsid]["permid"] = $this->permissionList[$permname]["permgrant"]; $this->permissionList[$grantsid]["permname"] = TeamSpeak3_Helper_String::factory($grantsid); $this->permissionList[$grantsid]["permdesc"] = null; $this->permissionList[$grantsid]["permcatid"] = 0xFF; $this->permissionList[$grantsid]["permgrant"] = $this->permissionList[$permname]["permgrant"]; } } return $this->permissionList; } /** * Returns a list of permission categories available on the server instance. * * @return array */ public function permissionCats() { if($this->permissionCats === null) { $this->fetchPermissionCats(); } return $this->permissionCats; } /** * Returns a list of permission category endings available on the server instance. * * @return array */ public function permissionEnds() { if($this->permissionEnds === null) { $this->fetchPermissionList(); } return $this->permissionCats; } /** * Returns an array filled with all permission categories known to the server including * their ID, name and parent. * * @return array */ public function permissionTree() { $permtree = array(); foreach($this->permissionCats() as $key => $val) { $permtree[$val]["permcatid"] = $val; $permtree[$val]["permcathex"] = "0x" . dechex($val); $permtree[$val]["permcatname"] = TeamSpeak3_Helper_String::factory(TeamSpeak3_Helper_Convert::permissionCategory($val)); $permtree[$val]["permcatparent"] = $permtree[$val]["permcathex"]{3} == 0 ? 0 : hexdec($permtree[$val]["permcathex"]{2} . 0); $permtree[$val]["permcatchilren"] = 0; $permtree[$val]["permcatcount"] = 0; if(isset($permtree[$permtree[$val]["permcatparent"]])) { $permtree[$permtree[$val]["permcatparent"]]["permcatchilren"]++; } if($permtree[$val]["permcatname"]->contains("/")) { $permtree[$val]["permcatname"] = $permtree[$val]["permcatname"]->section("/", 1)->trim(); } foreach($this->permissionList() as $permission) { if($permission["permid"]["permcatid"] == $val) { $permtree[$val]["permcatcount"]++; } } } return $permtree; } /** * Returns the IDs of all clients, channels or groups using the permission with the * specified ID. * * @param integer $permid * @return array */ public function permissionFind($permid) { if(!is_array($permid)) { $permident = (is_numeric($permid)) ? "permid" : "permsid"; } else { $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; } return $this->execute("permfind", array($permident => $permid))->toArray(); } /** * Returns the ID of the permission matching the given name. * * @param string $name * @throws TeamSpeak3_Adapter_ServerQuery_Exception * @return integer */ public function permissionGetIdByName($name) { if(!array_key_exists((string) $name, $this->permissionList())) { throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid permission ID", 0xA02); } return $this->permissionList[(string) $name]["permid"]; } /** * Returns the name of the permission matching the given ID. * * @param integer $permid * @throws TeamSpeak3_Adapter_ServerQuery_Exception * @return TeamSpeak3_Helper_String */ public function permissionGetNameById($permid) { foreach($this->permissionList() as $name => $perm) { if($perm["permid"] == $permid) return new TeamSpeak3_Helper_String($name); } throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid permission ID", 0xA02); } /** * Returns the internal category of the permission matching the given ID. * * All pre-3.0.7 permission IDs are are 2 bytes wide. The first byte identifies the category while * the second byte is the permission count within that group. * * @param integer $permid * @return integer */ public function permissionGetCategoryById($permid) { if(!is_numeric($permid)) { $permid = $this->permissionGetIdByName($permid); } if($permid < 0x1000) { if($this->permissionEnds === null) { $this->fetchPermissionList(); } if($this->permissionCats === null) { $this->fetchPermissionCats(); } $catids = array_values($this->permissionCats()); foreach($this->permissionEnds as $key => $val) { if($val >= $permid && isset($catids[$key])) { return $catids[$key]; } } return 0; } else { return (int) $permid >> 8; } } /** * Returns the internal ID of the i_needed_modify_power_* or grant permission. * * Every permission has an associated i_needed_modify_power_* permission, for example b_client_ban_create has an * associated permission called i_needed_modify_power_client_ban_create. * * @param integer $permid * @return integer */ public function permissionGetGrantById($permid) { if(!is_numeric($permid)) { $permid = $this->permissionGetIdByName($permid); } if($permid < 0x1000) { return (int) $permid+0x8000; } else { return (int) bindec(substr(decbin($permid), -8))+0xFF00; } } /** * Adds a set of specified permissions to all regular server groups on all virtual servers. The target groups will * be identified by the value of their i_group_auto_update_type permission specified with $sgtype. * * @param integer $sgtype * @param integer $permid * @param integer $permvalue * @param integer $permnegated * @param integer $permskip * @return void */ public function serverGroupPermAutoAssign($sgtype, $permid, $permvalue, $permnegated = FALSE, $permskip = FALSE) { if(!is_array($permid)) { $permident = (is_numeric($permid)) ? "permid" : "permsid"; } else { $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; } $this->execute("servergroupautoaddperm", array("sgtype" => $sgtype, $permident => $permid, "permvalue" => $permvalue, "permnegated" => $permnegated, "permskip" => $permskip)); } /** * Removes a set of specified permissions from all regular server groups on all virtual servers. The target groups * will be identified by the value of their i_group_auto_update_type permission specified with $sgtype. * * @param integer $sgtype * @param integer $permid * @return void */ public function serverGroupPermAutoRemove($sgtype, $permid) { if(!is_array($permid)) { $permident = (is_numeric($permid)) ? "permid" : "permsid"; } else { $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; } $this->execute("servergroupautodelperm", array("sgtype" => $sgtype, $permident => $permid)); } /** * Returns an array containing the value of a specified permission for your own client. * * @param integer $permid * @return array */ public function selfPermCheck($permid) { if(!is_array($permid)) { $permident = (is_numeric($permid)) ? "permid" : "permsid"; } else { $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; } return $this->execute("permget", array($permident => $permid))->toAssocArray("permsid"); } /** * Changes the server instance configuration using given properties. * * @param array $properties * @return void */ public function modify(array $properties) { $this->execute("instanceedit", $properties); $this->resetNodeInfo(); } /** * Sends a text message to all clients on all virtual servers in the TeamSpeak 3 Server instance. * * @param string $msg * @return void */ public function message($msg) { $this->execute("gm", array("msg" => $msg)); } /** * Displays a specified number of entries (1-100) from the servers log. * * @param integer $lines * @param integer $begin_pos * @param boolean $reverse * @param boolean $instance * @return array */ public function logView($lines = 30, $begin_pos = null, $reverse = null, $instance = TRUE) { return $this->execute("logview", array("lines" => $lines, "begin_pos" => $begin_pos, "instance" => $instance, "reverse" => $reverse))->toArray(); } /** * Writes a custom entry into the server instance log. * * @param string $logmsg * @param integer $loglevel * @return void */ public function logAdd($logmsg, $loglevel = TeamSpeak3::LOGLEVEL_INFO) { $sid = $this->serverSelectedId(); $this->serverDeselect(); $this->execute("logadd", array("logmsg" => $logmsg, "loglevel" => $loglevel)); $this->serverSelect($sid); } /** * Authenticates with the TeamSpeak 3 Server instance using given ServerQuery login credentials. * * @param string $username * @param string $password * @return void */ public function login($username, $password) { $this->execute("login", array("client_login_name" => $username, "client_login_password" => $password)); $this->whoamiReset(); $crypt = new TeamSpeak3_Helper_Crypt($username); $this->setStorage("_login_user", $username); $this->setStorage("_login_pass", $crypt->encrypt($password)); TeamSpeak3_Helper_Signal::getInstance()->emit("notifyLogin", $this); } /** * Deselects the active virtual server and logs out from the server instance. * * @return void */ public function logout() { $this->request("logout"); $this->whoamiReset(); $this->delStorage("_login_user"); $this->delStorage("_login_pass"); TeamSpeak3_Helper_Signal::getInstance()->emit("notifyLogout", $this); } /** * Returns information about your current ServerQuery connection. * * @return array */ public function whoami() { if($this->whoami === null) { $this->whoami = $this->request("whoami")->toList(); } return $this->whoami; } /** * Returns a single value from the current ServerQuery connection info. * * @param string $ident * @param mixed $default * @return mixed */ public function whoamiGet($ident, $default = null) { if(array_key_exists($ident, $this->whoami())) { return $this->whoami[$ident]; } return $default; } /** * Sets a single value in the current ServerQuery connection info. * * @param string $ident * @param mixed $value * @return mixed */ public function whoamiSet($ident, $value = null) { $this->whoami(); $this->whoami[$ident] = (is_numeric($value)) ? (int) $value : TeamSpeak3_Helper_String::factory($value); } /** * Resets the current ServerQuery connection info. * * @return void */ public function whoamiReset() { $this->whoami = null; } /** * Returns the hostname or IPv4 address the adapter is connected to. * * @return string */ public function getAdapterHost() { return $this->getParent()->getTransportHost(); } /** * Returns the network port the adapter is connected to. * * @return string */ public function getAdapterPort() { return $this->getParent()->getTransportPort(); } /** * @ignore */ protected function fetchNodeList() { $servers = $this->serverList(); foreach($servers as $server) { $this->nodeList[] = $server; } } /** * @ignore */ protected function fetchNodeInfo() { $info1 = $this->request("hostinfo")->toList(); $info2 = $this->request("instanceinfo")->toList(); $this->nodeInfo = array_merge($this->nodeInfo, $info1, $info2); } /** * @ignore */ protected function fetchPermissionList() { $reply = $this->request("permissionlist -new")->toArray(); $start = 1; $this->permissionEnds = array(); $this->permissionList = array(); foreach($reply as $line) { if(array_key_exists("group_id_end", $line)) { $this->permissionEnds[] = $line["group_id_end"]; } else { $this->permissionList[$line["permname"]->toString()] = array_merge(array("permid" => $start++), $line); } } } /** * @ignore */ protected function fetchPermissionCats() { $permcats = array(); $reflects = new ReflectionClass("TeamSpeak3"); foreach($reflects->getConstants() as $key => $val) { if(!TeamSpeak3_Helper_String::factory($key)->startsWith("PERM_CAT") || $val == 0xFF) { continue; } $permcats[$key] = $val; } $this->permissionCats = $permcats; } /** * Sets a pre-defined nickname for ServerQuery clients which will be used automatically * after selecting a virtual server. * * @param string $name * @return void */ public function setPredefinedQueryName($name = null) { $this->setStorage("_query_nick", $name); $this->predefined_query_name = $name; } /** * Returns the pre-defined nickname for ServerQuery clients which will be used automatically * after selecting a virtual server. * * @return string */ public function getPredefinedQueryName() { return $this->predefined_query_name; } /** * Sets the option to decide whether ServerQuery clients should be excluded from node * lists or not. * * @param boolean $exclude * @return void */ public function setExcludeQueryClients($exclude = FALSE) { $this->setStorage("_query_hide", $exclude); $this->exclude_query_clients = $exclude; } /** * Returns the option to decide whether ServerQuery clients should be excluded from node * lists or not. * * @return boolean */ public function getExcludeQueryClients() { return $this->exclude_query_clients; } /** * Sets the option to decide whether offline servers will be started in virtual mode * by default or not. * * @param boolean $virtual * @return void */ public function setUseOfflineAsVirtual($virtual = FALSE) { $this->setStorage("_do_virtual", $virtual); $this->start_offline_virtual = $virtual; } /** * Returns the option to decide whether offline servers will be started in virtual mode * by default or not. * * @return boolean */ public function getUseOfflineAsVirtual() { return $this->start_offline_virtual; } /** * Sets the option to decide whether clients should be sorted before sub-channels to support * the new TeamSpeak 3 Client display mode or not. * * @param boolean $first * @return void */ public function setLoadClientlistFirst($first = FALSE) { $this->setStorage("_client_top", $first); $this->sort_clients_channels = $first; } /** * Returns the option to decide whether offline servers will be started in virtual mode * by default or not. * * @return boolean */ public function getLoadClientlistFirst() { return $this->sort_clients_channels; } /** * Returns the underlying TeamSpeak3_Adapter_ServerQuery object. * * @return TeamSpeak3_Adapter_ServerQuery */ public function getAdapter() { return $this->getParent(); } /** * Returns a unique identifier for the node which can be used as a HTML property. * * @return string */ public function getUniqueId() { return "ts3_h"; } /** * Returns the name of a possible icon to display the node object. * * @return string */ public function getIcon() { return "host"; } /** * Returns a symbol representing the node. * * @return string */ public function getSymbol() { return "+"; } /** * Re-authenticates with the TeamSpeak 3 Server instance using given ServerQuery login * credentials and re-selects a previously selected virtual server. * * @return void */ public function __wakeup() { $username = $this->getStorage("_login_user"); $password = $this->getStorage("_login_pass"); if($username && $password) { $crypt = new TeamSpeak3_Helper_Crypt($username); $this->login($username, $crypt->decrypt($password)); } $this->predefined_query_name = $this->getStorage("_query_nick"); $this->exclude_query_clients = $this->getStorage("_query_hide", FALSE); $this->start_offline_virtual = $this->getStorage("_do_virtual", FALSE); $this->sort_clients_channels = $this->getStorage("_client_top", FALSE); if($server = $this->getStorage("_server_use")) { $func = array_shift($server); $args = array_shift($server); try { call_user_func_array(array($this, $func), $args); } catch(Exception $e) { $class = get_class($e); throw new $class($e->getMessage(), $e->getCode()); } } } /** * Returns a string representation of this node. * * @return string */ public function __toString() { return (string) $this->getAdapterHost(); } }