imgPath = $imgPath; $cm = CacheManager::i(); $this->serverInfo = $cm->getServerInfo(); $this->channelList = $cm->getChannelList(); $this->clientList = $cm->getClientList(); $this->serverGroupList = $cm->getServerGroupList(); $this->channelGroupList = $cm->getChannelGroupList(); } /** * Checks if we have successfully loaded all required data from cache. * Loading data from CacheManager might fail for example when the server is offline, * or when we dont have required permissions to check for a specific item. * @return bool true on success, false otherwise */ public function checkRequiredData() { return isset($this->channelList, $this->clientList, $this->serverGroupList, $this->channelGroupList); } private function add($html, ...$args) { foreach ($args as $i => $iValue) { // Prevent argument placeholder injection $iValue = str_replace(["{", "}"], ["{", "}"], $iValue); $html = str_ireplace('{' . $i . '}', $iValue, $html); } $this->resultHtml .= $html; } public function renderViewer() { if (!$this->checkRequiredData()) { throw new \Exception("Failed to load required data from the cache. " . "Is the server online? Do we have enough permissions?"); } $suffixIcons = ""; if ($icon = $this->serverInfo["virtualserver_icon_id"]) { $suffixIcons = $this->getIcon($icon, __get("VIEWER_SERVER_ICON")); } $html = <<
{0}{1} {2}
EOD; $this->add( $html, $this->getIcon("server_green.svg"), Utils::escape($this->serverInfo["virtualserver_name"]), $suffixIcons ); foreach ($this->channelList as $channel) { // Start rendering the top channels, they are gonna // render all the childrens recursively if ($channel["pid"] === 0) { $this->renderChannel(new TeamSpeakChannel($channel)); } } return $this->resultHtml; } public function getIcon($name, $tooltip = null, $alt = "Icon") { if (is_string($name)) { $path = "{$this->imgPath}/$name"; } else { $path = "api/geticon.php?iconid=" . (int) $name; } $ttip = $tooltip ? ' data-toggle="tooltip" title="' . Utils::escape($tooltip) . '"' : ""; return '' . Utils::escape($alt) . ''; } /** * @param $channel TeamSpeakChannel */ public function renderChannel($channel) { $hasParent = $channel->getParentId(); $isHidden = in_array($channel->getId(), $this->hiddenChannels); $channelDisplayName = $channel->getDisplayName(); $channelClasses = $hasParent ? "has-parent" : "no-parent"; $channelIcon = ""; $suffixIcons = ""; // If this channel is occupied if ($channel->isOccupied(false, $this->renderQueryClients) && !$isHidden) { $channelClasses .= " is-occupied"; } else if ($channel->isOccupied(true, $this->renderQueryClients) && !$isHidden) { $channelClasses .= " occupied-childs"; } else { $channelClasses .= " not-occupied"; } if ($channel->isSpacer()) { $channelClasses .= " is-spacer"; switch($channel->getSpacerAlign()) { case TeamSpeak3::SPACER_ALIGN_REPEAT: $channelClasses .= " spacer-repeat"; $channelDisplayName = str_repeat($channelDisplayName, 200); break; case TeamSpeak3::SPACER_ALIGN_CENTER: $channelClasses .= " spacer-center"; break; case TeamSpeak3::SPACER_ALIGN_RIGHT: $channelClasses .= " spacer-right"; break; case TeamSpeak3::SPACER_ALIGN_LEFT: $channelClasses .= " spacer-left"; break; } } else { $channelIcon = $this->getChannelIcon($channel, $isHidden); $suffixIcons = $this->getChannelSuffixIcons($channel); } $html = <<
{3}{4} {5}
EOD; $this->add( $html, $channelClasses, $channel->getId(), $channel->isSpacer() ? "" : ' tabindex="0"', $channelIcon, Utils::escape($channelDisplayName), $suffixIcons ); if (!$isHidden) { foreach ($channel->getChannelMembers($this->renderQueryClients) as $member) { $this->renderClient($member); } } foreach ($channel->getChildChannels() as $member) { $this->renderChannel($member); } $this->add('' . PHP_EOL . PHP_EOL); } public function renderClient($client) { $isQuery = (bool) $client["client_type"]; $clientSGIDs = explode(",", $client["client_servergroups"]); $clientServerGroups = []; $beforeName = []; $afterName = []; if (isset($client["client_away_message"])) { $afterName[] = "[{$client["client_away_message"]}]"; } foreach ($this->serverGroupList as $servergroup) { $groupid = $servergroup["sgid"]; if (in_array($groupid, $clientSGIDs)) { $clientServerGroups[$groupid] = $servergroup; if ($servergroup["namemode"] === TeamSpeak3::GROUP_NAMEMODE_BEFORE) { $beforeName[] = "[{$servergroup["name"]}]"; } if ($servergroup["namemode"] === TeamSpeak3::GROUP_NAMEMODE_BEHIND) { $afterName[] = "[{$servergroup["name"]}]"; } } } $clientIcon = $this->getClientIcon($client); $suffixIcons = $this->getClientSuffixIcons($client, $clientServerGroups, 0); $html = << {2}{3} {4} EOD; $clientName = implode(" ", $beforeName); // prefix groups $clientName .= " {$client["client_nickname"]} "; // nickname $clientName .= implode(" ", $afterName); // suffix groups $clientName = Utils::escape(trim($clientName)); // trim and sanitize $this->add( $html, $isQuery ? " is-query" : "", $client["client_database_id"], $clientIcon, $clientName, $suffixIcons ); } private function getChannelIcon(TeamSpeakChannel $channel, $isHidden) { $subscribed = $isHidden ? "" : "_subscribed"; $unsub = $isHidden ? __get("VIEWER_CHANNEL_UNSUB1") : ""; if ($channel->isDefaultChannel()) { return $this->getIcon("channel_default.svg", __get("VIEWER_DEFAULT_CHANNEL")); } if ($channel->isFullyOccupied()) { return $this->getIcon("channel_red{$subscribed}.svg", __get("VIEWER_CHANNEL_OCCUPIED") . $unsub); } if ($channel->hasPassword()) { return $this->getIcon("channel_yellow{$subscribed}.svg", __get("VIEWER_CHANNEL_PASSWORD") . $unsub); } return $this->getIcon("channel_green{$subscribed}.svg", $isHidden ? __get("VIEWER_CHANNEL_UNSUB2") : null); } private function getChannelSuffixIcons(TeamSpeakChannel $channel) { $info = $channel->getInfo(); $html = ""; if($channel->isDefaultChannel()) { $html .= $this->getIcon("default.svg", __get("VIEWER_DEFAULT_CHANNEL")); } if($info["channel_flag_password"]) { $html .= $this->getIcon("channel_private.svg", __get("VIEWER_CHANNEL_PASSWORD")); } $codec = $info["channel_codec"]; if($codec === TeamSpeak3::CODEC_CELT_MONO || $codec === TeamSpeak3::CODEC_OPUS_MUSIC) { $html .= $this->getIcon("music.svg", __get("VIEWER_CHANNEL_MUSIC_CODED")); } if($info["channel_needed_talk_power"]) { $html .= $this->getIcon("moderated.svg", __get("VIEWER_CHANNEL_MODERATED")); } if($info["channel_icon_id"]) { $html .= $this->getIcon($info["channel_icon_id"], __get("VIEWER_CHANNEL_ICON")); } return $html; } public function getClientIcon($client) { if($client["client_type"]) { return $this->getIcon("server_query.svg"); } if($client["client_away"]) { return $this->getIcon("away.svg", Utils::escape($client["client_away_message"]) ?: __get("VIEWER_CLIENT_AWAY")); } if(!$client["client_output_hardware"]) { return $this->getIcon("hardware_output_muted.svg", __get("VIEWER_CLIENT_OUTPUT_DISABLED")); } if($client["client_output_muted"]) { return $this->getIcon("output_muted.svg", __get("VIEWER_CLIENT_OUTPUT_MUTED")); } if(!$client["client_input_hardware"]) { return $this->getIcon("hardware_input_muted.svg", __get("VIEWER_CLIENT_MIC_DISABLED")); } if($client["client_input_muted"]) { return $this->getIcon("input_muted.svg", __get("VIEWER_CLIENT_MIC_MUTED")); } if($client["client_is_channel_commander"]) { return $this->getIcon("player_commander_off.svg", __get("VIEWER_CLIENT_COMMANDER")); } return $this->getIcon("player_off.svg"); } public function getClientSuffixIcons($client, $groups, $cntp) { $html = ""; if($client["client_is_priority_speaker"]) { $html .= $this->getIcon("capture.svg", __get("VIEWER_CLIENT_PRIORITY_SPEAKER")); } if($client["client_is_channel_commander"]) { $html .= $this->getIcon("channel_commander.svg", __get("VIEWER_CLIENT_COMMANDER")); } if($client["client_is_talker"]) { $html .= $this->getIcon("talk_power_grant.svg", __get("VIEWER_CLIENT_TALK_POWER_GRANTED")); } else if($cntp && $cntp > $client["client_talk_power"]) { $html .= $this->getIcon("input_muted.svg", __get("VIEWER_CLIENT_TALK_POWER_INSUFFICIENT")); } foreach ($groups as $group) { if ($group["iconid"]) { $icon = $group["iconid"]; } else { $icon = "broken_image.svg"; continue; // If the group does not have an icon, we skip this group. // However, you can comment out the above "continue" statement // to show the group with a "broken-image" icons. } $html .= $this->getIcon($icon, Utils::escape($group["name"])); } if($client["client_icon_id"]) { $html .= $this->getIcon($client["client_icon_id"], __get("VIEWER_CLIENT_ICON")); } if($client["client_country"]) { $country = $client["client_country"]; $countryLower = strtolower($country); $html .= ''; } return $html; } }