commit ae6c8a14198f0db0f97c42f6b284f8791399e1d9 Author: Dominik Dancs Date: Tue Jan 3 11:54:06 2017 +0100 Initial Commit diff --git a/hidden/.htaccess b/hidden/.htaccess new file mode 100644 index 0000000..03e18d1 --- /dev/null +++ b/hidden/.htaccess @@ -0,0 +1,3 @@ +Order deny,allow +Deny from all +Allow from localhost diff --git a/hidden/MinecraftQuery/MinecraftColors.php b/hidden/MinecraftQuery/MinecraftColors.php new file mode 100644 index 0000000..7d57377 --- /dev/null +++ b/hidden/MinecraftQuery/MinecraftColors.php @@ -0,0 +1,156 @@ +. +*/ + +class MinecraftColors { + const REGEX = '/(?:§|&)([0-9a-fklmnor])/i'; + + const START_TAG = ''; + const CLOSE_TAG = ''; + const CSS_COLOR = 'color: #'; + const EMPTY_TAGS = '/<[^\/>]*>([\s]?)*<\/[^>]*>/'; + const LINE_BREAK = '
'; + + static private $colors = array( + '0' => '000000', //Black + '1' => '0000AA', //Dark Blue + '2' => '00AA00', //Dark Green + '3' => '00AAAA', //Dark Aqua + '4' => 'AA0000', //Dark Red + '5' => 'AA00AA', //Dark Purple + '6' => 'FFAA00', //Gold + '7' => 'AAAAAA', //Gray + '8' => '555555', //Dark Gray + '9' => '5555FF', //Blue + 'a' => '55FF55', //Green + 'b' => '55FFFF', //Aqua + 'c' => 'FF5555', //Red + 'd' => 'FF55FF', //Light Purple + 'e' => 'FFFF55', //Yellow + 'f' => 'FFFFFF' //White + ); + + static private $formatting = array( + 'k' => '', //Obfuscated + 'l' => 'font-weight: bold;', //Bold + 'm' => 'text-decoration: line-through;', //Strikethrough + 'n' => 'text-decoration: underline;', //Underline + 'o' => 'font-style: italic;', //Italic + 'r' => '' //Reset + ); + + static private function UFT8Encode($text) { + //Encode the text in UTF-8, but only if it's not already. + if (mb_detect_encoding($text) != 'UTF-8') + $text = utf8_encode($text); + + return $text; + } + + static public function clean($text) { + $text = self::UFT8Encode($text); + $text = htmlspecialchars($text); + + return preg_replace(self::REGEX, '', $text); + } + + static public function convertToMOTD($text, $sign = '\u00A7') { + $text = self::UFT8Encode($text); + $text = htmlspecialchars($text); + + $text = preg_replace(self::REGEX, $sign.'${1}', $text); + $text = str_replace("\n", '\n', $text); + + return $text; + } + + static public function convertToHTML($text, $line_break_element = false) { + $text = self::UFT8Encode($text); + $text = htmlspecialchars($text); + + preg_match_all(self::REGEX, $text, $offsets); + + $colors = $offsets[0]; //This is what we are going to replace with HTML. + $color_codes = $offsets[1]; //This is the color numbers/characters only. + + //No colors? Just return the text. + if (empty($colors)) + return $text; + + $open_tags = 0; + + foreach ($colors as $index => $color) { + $color_code = strtolower($color_codes[$index]); + + //We have a normal color. + if (isset(self::$colors[$color_code])) { + $html = sprintf(self::START_TAG, self::CSS_COLOR.self::$colors[$color_code]); + + //New color clears the other colors and formatting. + if ($open_tags != 0) { + $html = str_repeat(self::CLOSE_TAG, $open_tags).$html; + $open_tags = 0; + } + + $open_tags++; + } + + //We have some formatting. + else { + switch ($color_code) { + //Reset is special, just close all open tags. + case 'r': + $html = ''; + + if ($open_tags != 0) { + $html = str_repeat(self::CLOSE_TAG, $open_tags); + $open_tags = 0; + } + + break; + + //Can't do obfuscated in CSS... + case 'k': + $html = ''; + + break; + + default: + $html = sprintf(self::START_TAG, self::$formatting[$color_code]); + $open_tags++; + + break; + } + } + + //Replace the color with the HTML code. We use preg_replace because of the limit parameter. + $text = preg_replace('/'.$color.'/', $html, $text, 1); + } + + //Still open tags? Close them! + if ($open_tags != 0) + $text = $text.str_repeat(self::CLOSE_TAG, $open_tags); + + //Replace \n with
+ if ($line_break_element) + $text = str_replace("\n", self::LINE_BREAK, $text); + + //Return the text without empty HTML tags. Only to clean up bad color formatting from the user. + return preg_replace(self::EMPTY_TAGS, '', $text); + } +} +?> \ No newline at end of file diff --git a/hidden/MinecraftQuery/MinecraftQueryClass.php b/hidden/MinecraftQuery/MinecraftQueryClass.php new file mode 100644 index 0000000..7201282 --- /dev/null +++ b/hidden/MinecraftQuery/MinecraftQueryClass.php @@ -0,0 +1,157 @@ +Socket = @FSockOpen( 'udp://' . $Ip, (int)$Port, $ErrNo, $ErrStr, $Timeout ); + if( $ErrNo || $this->Socket === false ) + { + throw new MinecraftQueryException( 'Could not create socket: ' . $ErrStr ); + } + Stream_Set_Timeout( $this->Socket, $Timeout ); + Stream_Set_Blocking( $this->Socket, true ); + try + { + $Challenge = $this->GetChallenge( ); + $this->GetStatus( $Challenge ); + } + // We catch this because we want to close the socket, not very elegant + catch( MinecraftQueryException $e ) + { + FClose( $this->Socket ); + throw new MinecraftQueryException( $e->getMessage( ) ); + } + FClose( $this->Socket ); + } + public function GetInfo( ) + { + return isset( $this->Info ) ? $this->Info : false; + } + public function GetPlayers( ) + { + return isset( $this->Players ) ? $this->Players : false; + } + private function GetChallenge( ) + { + $Data = $this->WriteData( self :: HANDSHAKE ); + if( $Data === false ) + { + throw new MinecraftQueryException( 'Failed to receive challenge.' ); + } + return Pack( 'N', $Data ); + } + private function GetStatus( $Challenge ) + { + $Data = $this->WriteData( self :: STATISTIC, $Challenge . Pack( 'c*', 0x00, 0x00, 0x00, 0x00 ) ); + if( !$Data ) + { + throw new MinecraftQueryException( 'Failed to receive status.' ); + } + $Last = ''; + $Info = Array( ); + $Data = SubStr( $Data, 11 ); // splitnum + 2 int + $Data = Explode( "\x00\x00\x01player_\x00\x00", $Data ); + if( Count( $Data ) !== 2 ) + { + throw new MinecraftQueryException( 'Failed to parse server\'s response.' ); + } + $Players = SubStr( $Data[ 1 ], 0, -2 ); + $Data = Explode( "\x00", $Data[ 0 ] ); + // Array with known keys in order to validate the result + // It can happen that server sends custom strings containing bad things (who can know!) + $Keys = Array( + 'hostname' => 'HostName', + 'gametype' => 'GameType', + 'version' => 'Version', + 'plugins' => 'Plugins', + 'map' => 'Map', + 'numplayers' => 'Players', + 'maxplayers' => 'MaxPlayers', + 'hostport' => 'HostPort', + 'hostip' => 'HostIp', + 'game_id' => 'GameName' + ); + foreach( $Data as $Key => $Value ) + { + if( ~$Key & 1 ) + { + if( !Array_Key_Exists( $Value, $Keys ) ) + { + $Last = false; + continue; + } + $Last = $Keys[ $Value ]; + $Info[ $Last ] = ''; + } + else if( $Last != false ) + { + $Info[ $Last ] = utf8_encode($Value); + } + } + // Ints + $Info[ 'Players' ] = IntVal( $Info[ 'Players' ] ); + $Info[ 'MaxPlayers' ] = IntVal( $Info[ 'MaxPlayers' ] ); + $Info[ 'HostPort' ] = IntVal( $Info[ 'HostPort' ] ); + // Parse "plugins", if any + if( $Info[ 'Plugins' ] ) + { + $Data = Explode( ": ", $Info[ 'Plugins' ], 2 ); + $Info[ 'RawPlugins' ] = $Info[ 'Plugins' ]; + $Info[ 'Software' ] = $Data[ 0 ]; + if( Count( $Data ) == 2 ) + { + $Info[ 'Plugins' ] = Explode( "; ", $Data[ 1 ] ); + } + } + else + { + $Info[ 'Software' ] = 'Vanilla'; + } + $this->Info = $Info; + if( empty( $Players ) ) + { + $this->Players = null; + } + else + { + $this->Players = Explode( "\x00", $Players ); + } + } + private function WriteData( $Command, $Append = "" ) + { + $Command = Pack( 'c*', 0xFE, 0xFD, $Command, 0x01, 0x02, 0x03, 0x04 ) . $Append; + $Length = StrLen( $Command ); + if( $Length !== FWrite( $this->Socket, $Command, $Length ) ) + { + throw new MinecraftQueryException( "Failed to write on socket." ); + } + $Data = FRead( $this->Socket, 4096 ); + if( $Data === false ) + { + throw new MinecraftQueryException( "Failed to read from socket." ); + } + if( StrLen( $Data ) < 5 || $Data[ 0 ] != $Command[ 2 ] ) + { + return false; + } + return SubStr( $Data, 5 ); + } +} + +?> \ No newline at end of file diff --git a/hidden/MinecraftQuery/MinecraftQueryException.php b/hidden/MinecraftQuery/MinecraftQueryException.php new file mode 100644 index 0000000..3e96a30 --- /dev/null +++ b/hidden/MinecraftQuery/MinecraftQueryException.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/hidden/SourceQuery/BaseSocket.php b/hidden/SourceQuery/BaseSocket.php new file mode 100644 index 0000000..cb4ccc7 --- /dev/null +++ b/hidden/SourceQuery/BaseSocket.php @@ -0,0 +1,131 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery; + + use xPaw\SourceQuery\Exception\InvalidPacketException; + + /** + * Base socket interface + * + * @package xPaw\SourceQuery + * + * @uses xPaw\SourceQuery\Exception\InvalidPacketException + */ + abstract class BaseSocket + { + public $Socket; + public $Engine; + + public $Address; + public $Port; + public $Timeout; + + public function __destruct( ) + { + $this->Close( ); + } + + abstract public function Close( ); + abstract public function Open( $Address, $Port, $Timeout, $Engine ); + abstract public function Write( $Header, $String = '' ); + abstract public function Read( $Length = 1400 ); + + protected function ReadInternal( $Buffer, $Length, $SherlockFunction ) + { + if( $Buffer->Remaining( ) === 0 ) + { + throw new InvalidPacketException( 'Failed to read any data from socket', InvalidPacketException::BUFFER_EMPTY ); + } + + $Header = $Buffer->GetLong( ); + + if( $Header === -1 ) // Single packet + { + // We don't have to do anything + } + else if( $Header === -2 ) // Split packet + { + $Packets = []; + $IsCompressed = false; + $ReadMore = false; + + do + { + $RequestID = $Buffer->GetLong( ); + + switch( $this->Engine ) + { + case SourceQuery::GOLDSOURCE: + { + $PacketCountAndNumber = $Buffer->GetByte( ); + $PacketCount = $PacketCountAndNumber & 0xF; + $PacketNumber = $PacketCountAndNumber >> 4; + + break; + } + case SourceQuery::SOURCE: + { + $IsCompressed = ( $RequestID & 0x80000000 ) !== 0; + $PacketCount = $Buffer->GetByte( ); + $PacketNumber = $Buffer->GetByte( ) + 1; + + if( $IsCompressed ) + { + $Buffer->GetLong( ); // Split size + + $PacketChecksum = $Buffer->GetUnsignedLong( ); + } + else + { + $Buffer->GetShort( ); // Split size + } + + break; + } + } + + $Packets[ $PacketNumber ] = $Buffer->Get( ); + + $ReadMore = $PacketCount > sizeof( $Packets ); + } + while( $ReadMore && $SherlockFunction( $Buffer, $Length ) ); + + $Data = Implode( $Packets ); + + // TODO: Test this + if( $IsCompressed ) + { + // Let's make sure this function exists, it's not included in PHP by default + if( !Function_Exists( 'bzdecompress' ) ) + { + throw new \RuntimeException( 'Received compressed packet, PHP doesn\'t have Bzip2 library installed, can\'t decompress.' ); + } + + $Data = bzdecompress( $Data ); + + if( CRC32( $Data ) !== $PacketChecksum ) + { + throw new InvalidPacketException( 'CRC32 checksum mismatch of uncompressed packet data.', InvalidPacketException::CHECKSUM_MISMATCH ); + } + } + + $Buffer->Set( SubStr( $Data, 4 ) ); + } + else + { + throw new InvalidPacketException( 'Socket read: Raw packet header mismatch. (0x' . DecHex( $Header ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + } + + return $Buffer; + } + } diff --git a/hidden/SourceQuery/Buffer.php b/hidden/SourceQuery/Buffer.php new file mode 100644 index 0000000..f9ecb0e --- /dev/null +++ b/hidden/SourceQuery/Buffer.php @@ -0,0 +1,199 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery; + + use xPaw\SourceQuery\Exception\InvalidPacketException; + + /** + * Class Buffer + * + * @package xPaw\SourceQuery + * + * @uses xPaw\SourceQuery\Exception\InvalidPacketException + */ + class Buffer + { + /** + * Buffer + * + * @var string + */ + private $Buffer; + + /** + * Buffer length + * + * @var int + */ + private $Length; + + /** + * Current position in buffer + * + * @var int + */ + private $Position; + + /** + * Sets buffer + * + * @param string $Buffer Buffer + */ + public function Set( $Buffer ) + { + $this->Buffer = $Buffer; + $this->Length = StrLen( $Buffer ); + $this->Position = 0; + } + + /** + * Get remaining bytes + * + * @return int Remaining bytes in buffer + */ + public function Remaining( ) + { + return $this->Length - $this->Position; + } + + /** + * Gets data from buffer + * + * @param int $Length Bytes to read + * + * @return string + */ + public function Get( $Length = -1 ) + { + if( $Length === 0 ) + { + return ''; + } + + $Remaining = $this->Remaining( ); + + if( $Length === -1 ) + { + $Length = $Remaining; + } + else if( $Length > $Remaining ) + { + return ''; + } + + $Data = SubStr( $this->Buffer, $this->Position, $Length ); + + $this->Position += $Length; + + return $Data; + } + + /** + * Get byte from buffer + * + * @return int + */ + public function GetByte( ) + { + return Ord( $this->Get( 1 ) ); + } + + /** + * Get short from buffer + * + * @return int + */ + public function GetShort( ) + { + if( $this->Remaining( ) < 2 ) + { + throw new InvalidPacketException( 'Not enough data to unpack a short.', InvalidPacketException::BUFFER_EMPTY ); + } + + $Data = UnPack( 'v', $this->Get( 2 ) ); + + return $Data[ 1 ]; + } + + /** + * Get long from buffer + * + * @return int + */ + public function GetLong( ) + { + if( $this->Remaining( ) < 4 ) + { + throw new InvalidPacketException( 'Not enough data to unpack a long.', InvalidPacketException::BUFFER_EMPTY ); + } + + $Data = UnPack( 'l', $this->Get( 4 ) ); + + return $Data[ 1 ]; + } + + /** + * Get float from buffer + * + * @return float + */ + public function GetFloat( ) + { + if( $this->Remaining( ) < 4 ) + { + throw new InvalidPacketException( 'Not enough data to unpack a float.', InvalidPacketException::BUFFER_EMPTY ); + } + + $Data = UnPack( 'f', $this->Get( 4 ) ); + + return $Data[ 1 ]; + } + + /** + * Get unsigned long from buffer + * + * @return int + */ + public function GetUnsignedLong( ) + { + if( $this->Remaining( ) < 4 ) + { + throw new InvalidPacketException( 'Not enough data to unpack an usigned long.', InvalidPacketException::BUFFER_EMPTY ); + } + + $Data = UnPack( 'V', $this->Get( 4 ) ); + + return $Data[ 1 ]; + } + + /** + * Read one string from buffer ending with null byte + * + * @return string + */ + public function GetString( ) + { + $ZeroBytePosition = StrPos( $this->Buffer, "\0", $this->Position ); + + if( $ZeroBytePosition === false ) + { + return ''; + } + + $String = $this->Get( $ZeroBytePosition - $this->Position ); + + $this->Position++; + + return $String; + } + } diff --git a/hidden/SourceQuery/Exception/AuthenticationException.php b/hidden/SourceQuery/Exception/AuthenticationException.php new file mode 100644 index 0000000..fee5d3a --- /dev/null +++ b/hidden/SourceQuery/Exception/AuthenticationException.php @@ -0,0 +1,19 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery\Exception; + + class AuthenticationException extends SourceQueryException + { + const BAD_PASSWORD = 1; + const BANNED = 2; + } diff --git a/hidden/SourceQuery/Exception/InvalidArgumentException.php b/hidden/SourceQuery/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..eb66b5c --- /dev/null +++ b/hidden/SourceQuery/Exception/InvalidArgumentException.php @@ -0,0 +1,18 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery\Exception; + + class InvalidArgumentException extends SourceQueryException + { + const TIMEOUT_NOT_INTEGER = 1; + } diff --git a/hidden/SourceQuery/Exception/InvalidPacketException.php b/hidden/SourceQuery/Exception/InvalidPacketException.php new file mode 100644 index 0000000..1e53640 --- /dev/null +++ b/hidden/SourceQuery/Exception/InvalidPacketException.php @@ -0,0 +1,21 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery\Exception; + + class InvalidPacketException extends SourceQueryException + { + const PACKET_HEADER_MISMATCH = 1; + const BUFFER_EMPTY = 2; + const BUFFER_NOT_EMPTY = 3; + const CHECKSUM_MISMATCH = 4; + } diff --git a/hidden/SourceQuery/Exception/SocketException.php b/hidden/SourceQuery/Exception/SocketException.php new file mode 100644 index 0000000..94a20ca --- /dev/null +++ b/hidden/SourceQuery/Exception/SocketException.php @@ -0,0 +1,20 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery\Exception; + + class SocketException extends SourceQueryException + { + const COULD_NOT_CREATE_SOCKET = 1; + const NOT_CONNECTED = 2; + const CONNECTION_FAILED = 3; + } diff --git a/hidden/SourceQuery/Exception/SourceQueryException.php b/hidden/SourceQuery/Exception/SourceQueryException.php new file mode 100644 index 0000000..8a8a872 --- /dev/null +++ b/hidden/SourceQuery/Exception/SourceQueryException.php @@ -0,0 +1,18 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery\Exception; + + abstract class SourceQueryException extends \Exception + { + // Base exception class + } diff --git a/hidden/SourceQuery/GoldSourceRcon.php b/hidden/SourceQuery/GoldSourceRcon.php new file mode 100644 index 0000000..a9c5ce3 --- /dev/null +++ b/hidden/SourceQuery/GoldSourceRcon.php @@ -0,0 +1,140 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery; + + use xPaw\SourceQuery\Exception\AuthenticationException; + + /** + * Class GoldSourceRcon + * + * @package xPaw\SourceQuery + * + * @uses xPaw\SourceQuery\Exception\AuthenticationException + */ + class GoldSourceRcon + { + /** + * Points to socket class + * + * @var Socket + */ + private $Socket; + + private $RconPassword; + private $RconRequestId; + private $RconChallenge; + + public function __construct( $Socket ) + { + $this->Socket = $Socket; + } + + public function Close( ) + { + $this->RconChallenge = 0; + $this->RconRequestId = 0; + $this->RconPassword = 0; + } + + public function Open( ) + { + // + } + + public function Write( $Header, $String = '' ) + { + $Command = Pack( 'cccca*', 0xFF, 0xFF, 0xFF, 0xFF, $String ); + $Length = StrLen( $Command ); + + return $Length === FWrite( $this->Socket->Socket, $Command, $Length ); + } + + /** + * @param int $Length + * @throws AuthenticationException + * @return bool + */ + public function Read( $Length = 1400 ) + { + // GoldSource RCON has same structure as Query + $Buffer = $this->Socket->Read( ); + + if( $Buffer->GetByte( ) !== SourceQuery::S2A_RCON ) + { + throw new InvalidPacketException( 'Invalid rcon response.', InvalidPacketException::PACKET_HEADER_MISMATCH ); + } + + $Buffer = $Buffer->Get( ); + $Trimmed = Trim( $Buffer ); + + if( $Trimmed === 'Bad rcon_password.' ) + { + throw new AuthenticationException( $Trimmed, AuthenticationException::BAD_PASSWORD ); + } + else if( $Trimmed === 'You have been banned from this server.' ) + { + throw new AuthenticationException( $Trimmed, AuthenticationException::BANNED ); + } + + $ReadMore = false; + + // There is no indentifier of the end, so we just need to continue reading + // TODO: Needs to be looked again, it causes timeouts + do + { + $this->Socket->Read( ); + + $ReadMore = $Buffer->Remaining( ) > 0 && $Buffer->GetByte( ) === SourceQuery::S2A_RCON; + + if( $ReadMore ) + { + $Packet = $Buffer->Get( ); + $Buffer .= SubStr( $Packet, 0, -2 ); + + // Let's assume if this packet is not long enough, there are no more after this one + $ReadMore = StrLen( $Packet ) > 1000; // use 1300? + } + } + while( $ReadMore ); + + $Buffer->Set( Trim( $Buffer ) ); + } + + public function Command( $Command ) + { + if( !$this->RconChallenge ) + { + throw new AuthenticationException( 'Tried to execute a RCON command before successful authorization.', AuthenticationException::BAD_PASSWORD ); + } + + $this->Write( 0, 'rcon ' . $this->RconChallenge . ' "' . $this->RconPassword . '" ' . $Command . "\0" ); + $Buffer = $this->Read( ); + + return $Buffer->Get( ); + } + + public function Authorize( $Password ) + { + $this->RconPassword = $Password; + + $this->Write( 0, 'challenge rcon' ); + $Buffer = $this->Socket->Read( ); + + if( $Buffer->Get( 14 ) !== 'challenge rcon' ) + { + throw new AuthenticationException( 'Failed to get RCON challenge.', AuthenticationException::BAD_PASSWORD ); + } + + $this->RconChallenge = Trim( $Buffer->Get( ) ); + } + } diff --git a/hidden/SourceQuery/Socket.php b/hidden/SourceQuery/Socket.php new file mode 100644 index 0000000..9780e72 --- /dev/null +++ b/hidden/SourceQuery/Socket.php @@ -0,0 +1,94 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery; + + use xPaw\SourceQuery\Exception\InvalidPacketException; + use xPaw\SourceQuery\Exception\SocketException; + + /** + * Class Socket + * + * @package xPaw\SourceQuery + * + * @uses xPaw\SourceQuery\Exception\InvalidPacketException + * @uses xPaw\SourceQuery\Exception\SocketException + */ + class Socket extends BaseSocket + { + public function Close( ) + { + if( $this->Socket ) + { + FClose( $this->Socket ); + + $this->Socket = null; + } + } + + public function Open( $Address, $Port, $Timeout, $Engine ) + { + $this->Timeout = $Timeout; + $this->Engine = $Engine; + $this->Port = $Port; + $this->Address = $Address; + + $this->Socket = @FSockOpen( 'udp://' . $Address, $Port, $ErrNo, $ErrStr, $Timeout ); + + if( $ErrNo || $this->Socket === false ) + { + throw new SocketException( 'Could not create socket: ' . $ErrStr, SocketException::COULD_NOT_CREATE_SOCKET ); + } + + Stream_Set_Timeout( $this->Socket, $Timeout ); + Stream_Set_Blocking( $this->Socket, true ); + } + + public function Write( $Header, $String = '' ) + { + $Command = Pack( 'ccccca*', 0xFF, 0xFF, 0xFF, 0xFF, $Header, $String ); + $Length = StrLen( $Command ); + + return $Length === FWrite( $this->Socket, $Command, $Length ); + } + + /** + * Reads from socket and returns Buffer. + * + * @throws InvalidPacketException + * + * @return Buffer Buffer + */ + public function Read( $Length = 1400 ) + { + $Buffer = new Buffer( ); + $Buffer->Set( FRead( $this->Socket, $Length ) ); + + $this->ReadInternal( $Buffer, $Length, [ $this, 'Sherlock' ] ); + + return $Buffer; + } + + public function Sherlock( $Buffer, $Length ) + { + $Data = FRead( $this->Socket, $Length ); + + if( StrLen( $Data ) < 4 ) + { + return false; + } + + $Buffer->Set( $Data ); + + return $Buffer->GetLong( ) === -2; + } + } diff --git a/hidden/SourceQuery/SourceQuery.php b/hidden/SourceQuery/SourceQuery.php new file mode 100644 index 0000000..8d897d0 --- /dev/null +++ b/hidden/SourceQuery/SourceQuery.php @@ -0,0 +1,559 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + */ + + namespace xPaw\SourceQuery; + + use xPaw\SourceQuery\Exception\InvalidArgumentException; + use xPaw\SourceQuery\Exception\InvalidPacketException; + use xPaw\SourceQuery\Exception\SocketException; + + /** + * Class SourceQuery + * + * @package xPaw\SourceQuery + * + * @uses xPaw\SourceQuery\Exception\InvalidArgumentException + * @uses xPaw\SourceQuery\Exception\InvalidPacketException + * @uses xPaw\SourceQuery\Exception\SocketException + */ + class SourceQuery + { + /** + * Engines + */ + const GOLDSOURCE = 0; + const SOURCE = 1; + + /** + * Packets sent + */ + const A2S_PING = 0x69; + const A2S_INFO = 0x54; + const A2S_PLAYER = 0x55; + const A2S_RULES = 0x56; + const A2S_SERVERQUERY_GETCHALLENGE = 0x57; + + /** + * Packets received + */ + const S2A_PING = 0x6A; + const S2A_CHALLENGE = 0x41; + const S2A_INFO = 0x49; + const S2A_INFO_OLD = 0x6D; // Old GoldSource, HLTV uses it + const S2A_PLAYER = 0x44; + const S2A_RULES = 0x45; + const S2A_RCON = 0x6C; + + /** + * Source rcon sent + */ + const SERVERDATA_EXECCOMMAND = 2; + const SERVERDATA_AUTH = 3; + + /** + * Source rcon received + */ + const SERVERDATA_RESPONSE_VALUE = 0; + const SERVERDATA_AUTH_RESPONSE = 2; + + /** + * Points to rcon class + * + * @var SourceRcon + */ + private $Rcon; + + /** + * Points to socket class + * + * @var Socket + */ + private $Socket; + + /** + * True if connection is open, false if not + * + * @var bool + */ + private $Connected; + + /** + * Contains challenge + * + * @var string + */ + private $Challenge; + + /** + * Use old method for getting challenge number + * + * @var bool + */ + private $UseOldGetChallengeMethod; + + public function __construct( BaseSocket $Socket = null ) + { + $this->Socket = $Socket ?: new Socket( ); + } + + public function __destruct( ) + { + $this->Disconnect( ); + } + + /** + * Opens connection to server + * + * @param string $Address Server ip + * @param int $Port Server port + * @param int $Timeout Timeout period + * @param int $Engine Engine the server runs on (goldsource, source) + * + * @throws InvalidArgumentException + * @throws SocketException + */ + public function Connect( $Address, $Port, $Timeout = 3, $Engine = self::SOURCE ) + { + $this->Disconnect( ); + + if( !is_int( $Timeout ) || $Timeout < 0 ) + { + throw new InvalidArgumentException( 'Timeout must be an integer.', InvalidArgumentException::TIMEOUT_NOT_INTEGER ); + } + + $this->Socket->Open( $Address, (int)$Port, $Timeout, (int)$Engine ); + + $this->Connected = true; + } + + /** + * Forces GetChallenge to use old method for challenge retrieval because some games use outdated protocol (e.g Starbound) + * + * @param bool $Value Set to true to force old method + * + * @returns bool Previous value + */ + public function SetUseOldGetChallengeMethod( $Value ) + { + $Previous = $this->UseOldGetChallengeMethod; + + $this->UseOldGetChallengeMethod = $Value === true; + + return $Previous; + } + + /** + * Closes all open connections + */ + public function Disconnect( ) + { + $this->Connected = false; + $this->Challenge = 0; + + $this->Socket->Close( ); + + if( $this->Rcon ) + { + $this->Rcon->Close( ); + + $this->Rcon = null; + } + } + + /** + * Sends ping packet to the server + * NOTE: This may not work on some games (TF2 for example) + * + * @throws InvalidPacketException + * @throws SocketException + * + * @return bool True on success, false on failure + */ + public function Ping( ) + { + if( !$this->Connected ) + { + throw new SocketException( 'Not connected.', SocketException::NOT_CONNECTED ); + } + + $this->Socket->Write( self::A2S_PING ); + $Buffer = $this->Socket->Read( ); + + return $Buffer->GetByte( ) === self::S2A_PING; + } + + /** + * Get server information + * + * @throws InvalidPacketException + * @throws SocketException + * + * @return array Returns an array with information on success + */ + public function GetInfo( ) + { + if( !$this->Connected ) + { + throw new SocketException( 'Not connected.', SocketException::NOT_CONNECTED ); + } + + $this->Socket->Write( self::A2S_INFO, "Source Engine Query\0" ); + $Buffer = $this->Socket->Read( ); + + $Type = $Buffer->GetByte( ); + + // Old GoldSource protocol, HLTV still uses it + if( $Type === self::S2A_INFO_OLD && $this->Socket->Engine === self::GOLDSOURCE ) + { + /** + * If we try to read data again, and we get the result with type S2A_INFO (0x49) + * That means this server is running dproto, + * Because it sends answer for both protocols + */ + + $Server[ 'Address' ] = $Buffer->GetString( ); + $Server[ 'HostName' ] = $Buffer->GetString( ); + $Server[ 'Map' ] = $Buffer->GetString( ); + $Server[ 'ModDir' ] = $Buffer->GetString( ); + $Server[ 'ModDesc' ] = $Buffer->GetString( ); + $Server[ 'Players' ] = $Buffer->GetByte( ); + $Server[ 'MaxPlayers' ] = $Buffer->GetByte( ); + $Server[ 'Protocol' ] = $Buffer->GetByte( ); + $Server[ 'Dedicated' ] = Chr( $Buffer->GetByte( ) ); + $Server[ 'Os' ] = Chr( $Buffer->GetByte( ) ); + $Server[ 'Password' ] = $Buffer->GetByte( ) === 1; + $Server[ 'IsMod' ] = $Buffer->GetByte( ) === 1; + + if( $Server[ 'IsMod' ] ) + { + $Mod[ 'Url' ] = $Buffer->GetString( ); + $Mod[ 'Download' ] = $Buffer->GetString( ); + $Buffer->Get( 1 ); // NULL byte + $Mod[ 'Version' ] = $Buffer->GetLong( ); + $Mod[ 'Size' ] = $Buffer->GetLong( ); + $Mod[ 'ServerSide' ] = $Buffer->GetByte( ) === 1; + $Mod[ 'CustomDLL' ] = $Buffer->GetByte( ) === 1; + } + + $Server[ 'Secure' ] = $Buffer->GetByte( ) === 1; + $Server[ 'Bots' ] = $Buffer->GetByte( ); + + if( isset( $Mod ) ) + { + $Server[ 'Mod' ] = $Mod; + } + + return $Server; + } + + if( $Type !== self::S2A_INFO ) + { + throw new InvalidPacketException( 'GetInfo: Packet header mismatch. (0x' . DecHex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + } + + $Server[ 'Protocol' ] = $Buffer->GetByte( ); + $Server[ 'HostName' ] = $Buffer->GetString( ); + $Server[ 'Map' ] = $Buffer->GetString( ); + $Server[ 'ModDir' ] = $Buffer->GetString( ); + $Server[ 'ModDesc' ] = $Buffer->GetString( ); + $Server[ 'AppID' ] = $Buffer->GetShort( ); + $Server[ 'Players' ] = $Buffer->GetByte( ); + $Server[ 'MaxPlayers' ] = $Buffer->GetByte( ); + $Server[ 'Bots' ] = $Buffer->GetByte( ); + $Server[ 'Dedicated' ] = Chr( $Buffer->GetByte( ) ); + $Server[ 'Os' ] = Chr( $Buffer->GetByte( ) ); + $Server[ 'Password' ] = $Buffer->GetByte( ) === 1; + $Server[ 'Secure' ] = $Buffer->GetByte( ) === 1; + + // The Ship (they violate query protocol spec by modifying the response) + if( $Server[ 'AppID' ] === 2400 ) + { + $Server[ 'GameMode' ] = $Buffer->GetByte( ); + $Server[ 'WitnessCount' ] = $Buffer->GetByte( ); + $Server[ 'WitnessTime' ] = $Buffer->GetByte( ); + } + + $Server[ 'Version' ] = $Buffer->GetString( ); + + // Extra Data Flags + if( $Buffer->Remaining( ) > 0 ) + { + $Server[ 'ExtraDataFlags' ] = $Flags = $Buffer->GetByte( ); + + // The server's game port + if( $Flags & 0x80 ) + { + $Server[ 'GamePort' ] = $Buffer->GetShort( ); + } + + // The server's steamid + // Want to play around with this? + // You can use https://github.com/xPaw/SteamID.php + if( $Flags & 0x10 ) + { + $SteamIDLower = $Buffer->GetUnsignedLong( ); + $SteamIDInstance = $Buffer->GetUnsignedLong( ); // This gets shifted by 32 bits, which should be steamid instance + $SteamID = 0; + + if( PHP_INT_SIZE === 4 ) + { + if( extension_loaded( 'gmp' ) ) + { + $SteamIDLower = gmp_abs( $SteamIDLower ); + $SteamIDInstance = gmp_abs( $SteamIDInstance ); + $SteamID = gmp_strval( gmp_or( $SteamIDLower, gmp_mul( $SteamIDInstance, gmp_pow( 2, 32 ) ) ) ); + } + else + { + throw new \RuntimeException( 'Either 64-bit PHP installation or "gmp" module is required to correctly parse server\'s steamid.' ); + } + } + else + { + $SteamID = $SteamIDLower | ( $SteamIDInstance << 32 ); + } + + $Server[ 'SteamID' ] = $SteamID; + + unset( $SteamIDLower, $SteamIDInstance, $SteamID ); + } + + // The spectator port and then the spectator server name + if( $Flags & 0x40 ) + { + $Server[ 'SpecPort' ] = $Buffer->GetShort( ); + $Server[ 'SpecName' ] = $Buffer->GetString( ); + } + + // The game tag data string for the server + if( $Flags & 0x20 ) + { + $Server[ 'GameTags' ] = $Buffer->GetString( ); + } + + // GameID -- alternative to AppID? + if( $Flags & 0x01 ) + { + $Server[ 'GameID' ] = $Buffer->GetUnsignedLong( ) | ( $Buffer->GetUnsignedLong( ) << 32 ); + } + + if( $Buffer->Remaining( ) > 0 ) + { + throw new InvalidPacketException( 'GetInfo: unread data? ' . $Buffer->Remaining( ) . ' bytes remaining in the buffer. Please report it to the library developer.', + InvalidPacketException::BUFFER_NOT_EMPTY ); + } + } + + return $Server; + } + + /** + * Get players on the server + * + * @throws InvalidPacketException + * @throws SocketException + * + * @return array Returns an array with players on success + */ + public function GetPlayers( ) + { + if( !$this->Connected ) + { + throw new SocketException( 'Not connected.', SocketException::NOT_CONNECTED ); + } + + $this->GetChallenge( self::A2S_PLAYER, self::S2A_PLAYER ); + + $this->Socket->Write( self::A2S_PLAYER, $this->Challenge ); + $Buffer = $this->Socket->Read( 14000 ); // Moronic Arma 3 developers do not split their packets, so we have to read more data + // This violates the protocol spec, and they probably should fix it: https://developer.valvesoftware.com/wiki/Server_queries#Protocol + + $Type = $Buffer->GetByte( ); + + if( $Type !== self::S2A_PLAYER ) + { + throw new InvalidPacketException( 'GetPlayers: Packet header mismatch. (0x' . DecHex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + } + + $Players = []; + $Count = $Buffer->GetByte( ); + + while( $Count-- > 0 && $Buffer->Remaining( ) > 0 ) + { + $Player[ 'Id' ] = $Buffer->GetByte( ); // PlayerID, is it just always 0? + $Player[ 'Name' ] = $Buffer->GetString( ); + $Player[ 'Frags' ] = $Buffer->GetLong( ); + $Player[ 'Time' ] = (int)$Buffer->GetFloat( ); + $Player[ 'TimeF' ] = GMDate( ( $Player[ 'Time' ] > 3600 ? "H:i:s" : "i:s" ), $Player[ 'Time' ] ); + + $Players[ ] = $Player; + } + + return $Players; + } + + /** + * Get rules (cvars) from the server + * + * @throws InvalidPacketException + * @throws SocketException + * + * @return array Returns an array with rules on success + */ + public function GetRules( ) + { + if( !$this->Connected ) + { + throw new SocketException( 'Not connected.', SocketException::NOT_CONNECTED ); + } + + $this->GetChallenge( self::A2S_RULES, self::S2A_RULES ); + + $this->Socket->Write( self::A2S_RULES, $this->Challenge ); + $Buffer = $this->Socket->Read( ); + + $Type = $Buffer->GetByte( ); + + if( $Type !== self::S2A_RULES ) + { + throw new InvalidPacketException( 'GetRules: Packet header mismatch. (0x' . DecHex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + } + + $Rules = []; + $Count = $Buffer->GetShort( ); + + while( $Count-- > 0 && $Buffer->Remaining( ) > 0 ) + { + $Rule = $Buffer->GetString( ); + $Value = $Buffer->GetString( ); + + if( !Empty( $Rule ) ) + { + $Rules[ $Rule ] = $Value; + } + } + + return $Rules; + } + + /** + * Get challenge (used for players/rules packets) + * + * @param $Header + * @param $ExpectedResult + * + * @throws InvalidPacketException + */ + private function GetChallenge( $Header, $ExpectedResult ) + { + if( $this->Challenge ) + { + return; + } + + if( $this->UseOldGetChallengeMethod ) + { + $Header = self::A2S_SERVERQUERY_GETCHALLENGE; + } + + $this->Socket->Write( $Header, "\xFF\xFF\xFF\xFF" ); + $Buffer = $this->Socket->Read( ); + + $Type = $Buffer->GetByte( ); + + switch( $Type ) + { + case self::S2A_CHALLENGE: + { + $this->Challenge = $Buffer->Get( 4 ); + + return; + } + case $ExpectedResult: + { + // Goldsource (HLTV) + + return; + } + case 0: + { + throw new InvalidPacketException( 'GetChallenge: Failed to get challenge.' ); + } + default: + { + throw new InvalidPacketException( 'GetChallenge: Packet header mismatch. (0x' . DecHex( $Type ) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH ); + } + } + } + + /** + * Sets rcon password, for future use in Rcon() + * + * @param string $Password Rcon Password + * + * @throws AuthenticationException + * @throws InvalidPacketException + * @throws SocketException + */ + public function SetRconPassword( $Password ) + { + if( !$this->Connected ) + { + throw new SocketException( 'Not connected.', SocketException::NOT_CONNECTED ); + } + + switch( $this->Socket->Engine ) + { + case SourceQuery::GOLDSOURCE: + { + $this->Rcon = new GoldSourceRcon( $this->Socket ); + + break; + } + case SourceQuery::SOURCE: + { + $this->Rcon = new SourceRcon( $this->Socket ); + + break; + } + } + + $this->Rcon->Open( ); + $this->Rcon->Authorize( $Password ); + } + + /** + * Sends a command to the server for execution. + * + * @param string $Command Command to execute + * + * @throws AuthenticationException + * @throws InvalidPacketException + * @throws SocketException + * + * @return string Answer from server in string + */ + public function Rcon( $Command ) + { + if( !$this->Connected ) + { + throw new SocketException( 'Not connected.', SocketException::NOT_CONNECTED ); + } + + if( $this->Rcon === null ) + { + throw new SocketException( 'You must set a RCON password before trying to execute a RCON command.', SocketException::NOT_CONNECTED ); + } + + return $this->Rcon->Command( $Command ); + } + } diff --git a/hidden/SourceQuery/SourceRcon.php b/hidden/SourceQuery/SourceRcon.php new file mode 100644 index 0000000..c132ad9 --- /dev/null +++ b/hidden/SourceQuery/SourceRcon.php @@ -0,0 +1,201 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + * + * @internal + */ + + namespace xPaw\SourceQuery; + + use xPaw\SourceQuery\Exception\AuthenticationException; + use xPaw\SourceQuery\Exception\InvalidPacketException; + use xPaw\SourceQuery\Exception\SocketException; + + /** + * Class SourceRcon + * + * @package xPaw\SourceQuery + * + * @uses xPaw\SourceQuery\Exception\AuthenticationException + * @uses xPaw\SourceQuery\Exception\InvalidPacketException + * @uses xPaw\SourceQuery\Exception\SocketException + */ + class SourceRcon + { + /** + * Points to socket class + * + * @var Socket + */ + private $Socket; + + private $RconSocket; + private $RconRequestId; + + public function __construct( $Socket ) + { + $this->Socket = $Socket; + } + + public function Close( ) + { + if( $this->RconSocket ) + { + FClose( $this->RconSocket ); + + $this->RconSocket = null; + } + + $this->RconRequestId = 0; + } + + public function Open( ) + { + if( !$this->RconSocket ) + { + $this->RconSocket = @FSockOpen( $this->Socket->Address, $this->Socket->Port, $ErrNo, $ErrStr, $this->Socket->Timeout ); + + if( $ErrNo || !$this->RconSocket ) + { + throw new SocketException( 'Can\'t connect to RCON server: ' . $ErrStr, SocketException::CONNECTION_FAILED ); + } + + Stream_Set_Timeout( $this->RconSocket, $this->Socket->Timeout ); + Stream_Set_Blocking( $this->RconSocket, true ); + } + } + + public function Write( $Header, $String = '' ) + { + // Pack the packet together + $Command = Pack( 'VV', ++$this->RconRequestId, $Header ) . $String . "\x00\x00"; + + // Prepend packet length + $Command = Pack( 'V', StrLen( $Command ) ) . $Command; + $Length = StrLen( $Command ); + + return $Length === FWrite( $this->RconSocket, $Command, $Length ); + } + + public function Read( ) + { + $Buffer = new Buffer( ); + $Buffer->Set( FRead( $this->RconSocket, 4 ) ); + + if( $Buffer->Remaining( ) < 4 ) + { + throw new InvalidPacketException( 'Rcon read: Failed to read any data from socket', InvalidPacketException::BUFFER_EMPTY ); + } + + $PacketSize = $Buffer->GetLong( ); + + $Buffer->Set( FRead( $this->RconSocket, $PacketSize ) ); + + $Data = $Buffer->Get( ); + + $Remaining = $PacketSize - StrLen( $Data ); + + while( $Remaining > 0 ) + { + $Data2 = FRead( $this->RconSocket, $Remaining ); + + $PacketSize = StrLen( $Data2 ); + + if( $PacketSize === 0 ) + { + throw new InvalidPacketException( 'Read ' . strlen( $Data ) . ' bytes from socket, ' . $Remaining . ' remaining', InvalidPacketException::BUFFER_EMPTY ); + + break; + } + + $Data .= $Data2; + $Remaining -= $PacketSize; + } + + $Buffer->Set( $Data ); + + return $Buffer; + } + + public function Command( $Command ) + { + $this->Write( SourceQuery::SERVERDATA_EXECCOMMAND, $Command ); + $Buffer = $this->Read( ); + + $Buffer->GetLong( ); // RequestID + + $Type = $Buffer->GetLong( ); + + if( $Type === SourceQuery::SERVERDATA_AUTH_RESPONSE ) + { + throw new AuthenticationException( 'Bad rcon_password.', AuthenticationException::BAD_PASSWORD ); + } + else if( $Type !== SourceQuery::SERVERDATA_RESPONSE_VALUE ) + { + throw new InvalidPacketException( 'Invalid rcon response.', InvalidPacketException::PACKET_HEADER_MISMATCH ); + } + + $Data = $Buffer->Get( ); + + // We do this stupid hack to handle split packets + // See https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#Multiple-packet_Responses + if( StrLen( $Data ) >= 4000 ) + { + do + { + $this->Write( SourceQuery::SERVERDATA_RESPONSE_VALUE ); + + $Buffer = $this->Read( ); + + $Buffer->GetLong( ); // RequestID + + if( $Buffer->GetLong( ) !== SourceQuery::SERVERDATA_RESPONSE_VALUE ) + { + break; + } + + $Data2 = $Buffer->Get( ); + + if( $Data2 === "\x00\x01\x00\x00\x00\x00" ) + { + break; + } + + $Data .= $Data2; + } + while( true ); + } + + return rtrim( $Data, "\0" ); + } + + public function Authorize( $Password ) + { + $this->Write( SourceQuery::SERVERDATA_AUTH, $Password ); + $Buffer = $this->Read( ); + + $RequestID = $Buffer->GetLong( ); + $Type = $Buffer->GetLong( ); + + // If we receive SERVERDATA_RESPONSE_VALUE, then we need to read again + // More info: https://developer.valvesoftware.com/wiki/Source_RCON_Protocol#Additional_Comments + + if( $Type === SourceQuery::SERVERDATA_RESPONSE_VALUE ) + { + $Buffer = $this->Read( ); + + $RequestID = $Buffer->GetLong( ); + $Type = $Buffer->GetLong( ); + } + + if( $RequestID === -1 || $Type !== SourceQuery::SERVERDATA_AUTH_RESPONSE ) + { + throw new AuthenticationException( 'RCON authorization failed.', AuthenticationException::BAD_PASSWORD ); + } + } + } diff --git a/hidden/SourceQuery/bootstrap.php b/hidden/SourceQuery/bootstrap.php new file mode 100644 index 0000000..585ddf2 --- /dev/null +++ b/hidden/SourceQuery/bootstrap.php @@ -0,0 +1,27 @@ + + * + * @link https://xpaw.me + * @link https://github.com/xPaw/PHP-Source-Query + * + * @license GNU Lesser General Public License, version 2.1 + */ + + require_once __DIR__ . '/Exception/SourceQueryException.php'; + require_once __DIR__ . '/Exception/AuthenticationException.php'; + require_once __DIR__ . '/Exception/InvalidArgumentException.php'; + require_once __DIR__ . '/Exception/SocketException.php'; + require_once __DIR__ . '/Exception/InvalidPacketException.php'; + + require_once __DIR__ . '/Buffer.php'; + require_once __DIR__ . '/BaseSocket.php'; + require_once __DIR__ . '/Socket.php'; + require_once __DIR__ . '/SourceRcon.php'; + require_once __DIR__ . '/GoldSourceRcon.php'; + require_once __DIR__ . '/SourceQuery.php'; diff --git a/hidden/TeamSpeak3/Adapter/Abstract.php b/hidden/TeamSpeak3/Adapter/Abstract.php new file mode 100644 index 0000000..943f011 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/Abstract.php @@ -0,0 +1,160 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Abstract + * @brief Provides low-level methods for concrete adapters to communicate with a TeamSpeak 3 Server. + */ +abstract class TeamSpeak3_Adapter_Abstract +{ + /** + * Stores user-provided options. + * + * @var array + */ + protected $options = null; + + /** + * Stores an TeamSpeak3_Transport_Abstract object. + * + * @var TeamSpeak3_Transport_Abstract + */ + protected $transport = null; + + /** + * The TeamSpeak3_Adapter_Abstract constructor. + * + * @param array $options + * @return TeamSpeak3_Adapter_Abstract + */ + public function __construct(array $options) + { + $this->options = $options; + + if($this->transport === null) + { + $this->syn(); + } + } + + /** + * The TeamSpeak3_Adapter_Abstract destructor. + * + * @return void + */ + abstract public function __destruct(); + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + abstract protected function syn(); + + /** + * Commit pending data. + * + * @return array + */ + public function __sleep() + { + return array("options"); + } + + /** + * Reconnects to the remote server. + * + * @return void + */ + public function __wakeup() + { + $this->syn(); + } + + /** + * Returns the profiler timer used for this connection adapter. + * + * @return TeamSpeak3_Helper_Profiler_Timer + */ + public function getProfiler() + { + return TeamSpeak3_Helper_Profiler::get(spl_object_hash($this)); + } + + /** + * Returns the transport object used for this connection adapter. + * + * @return TeamSpeak3_Transport_Abstract + */ + public function getTransport() + { + return $this->transport; + } + + /** + * Loads the transport object object used for the connection adapter and passes a given set + * of options. + * + * @param array $options + * @param string $transport + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + protected function initTransport($options, $transport = "TeamSpeak3_Transport_TCP") + { + if(!is_array($options)) + { + throw new TeamSpeak3_Adapter_Exception("transport parameters must provided in an array"); + } + + $this->transport = new $transport($options); + } + + /** + * Returns the hostname or IPv4 address the underlying TeamSpeak3_Transport_Abstract object + * is connected to. + * + * @return string + */ + public function getTransportHost() + { + return $this->getTransport()->getConfig("host", "0.0.0.0"); + } + + /** + * Returns the port number of the server the underlying TeamSpeak3_Transport_Abstract object + * is connected to. + * + * @return string + */ + public function getTransportPort() + { + return $this->getTransport()->getConfig("port", "0"); + } +} diff --git a/hidden/TeamSpeak3/Adapter/Blacklist.php b/hidden/TeamSpeak3/Adapter/Blacklist.php new file mode 100644 index 0000000..4054031 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/Blacklist.php @@ -0,0 +1,119 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Blacklist + * @brief Provides methods to check if an IP address is currently blacklisted. + */ +class TeamSpeak3_Adapter_Blacklist extends TeamSpeak3_Adapter_Abstract +{ + /** + * The IPv4 address or FQDN of the TeamSpeak Systems update server. + * + * @var string + */ + protected $default_host = "blacklist.teamspeak.com"; + + /** + * The UDP port number of the TeamSpeak Systems update server. + * + * @var integer + */ + protected $default_port = 17385; + + /** + * Stores an array containing the latest build numbers. + * + * @var array + */ + protected $build_numbers = null; + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @return void + */ + public function syn() + { + if(!isset($this->options["host"]) || empty($this->options["host"])) $this->options["host"] = $this->default_host; + if(!isset($this->options["port"]) || empty($this->options["port"])) $this->options["port"] = $this->default_port; + + $this->initTransport($this->options, "TeamSpeak3_Transport_UDP"); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("blacklistConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_Blacklist destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->getTransport()->isConnected()) + { + $this->getTransport()->disconnect(); + } + } + + /** + * Returns TRUE if a specified $host IP address is currently blacklisted. + * + * @param string $host + * @throws TeamSpeak3_Adapter_Blacklist_Exception + * @return boolean + */ + public function isBlacklisted($host) + { + if(ip2long($host) === FALSE) + { + $addr = gethostbyname($host); + + if($addr == $host) + { + throw new TeamSpeak3_Adapter_Blacklist_Exception("unable to resolve IPv4 address (" . $host . ")"); + } + + $host = $addr; + } + + $this->getTransport()->send("ip4:" . $host); + $repl = $this->getTransport()->read(1); + $this->getTransport()->disconnect(); + + if(!count($repl)) + { + return FALSE; + } + + return ($repl->toInt()) ? FALSE : TRUE; + } +} diff --git a/hidden/TeamSpeak3/Adapter/Blacklist/Exception.php b/hidden/TeamSpeak3/Adapter/Blacklist/Exception.php new file mode 100644 index 0000000..f9b9ef6 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/Blacklist/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Blacklist_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_Blacklist objects. + */ +class TeamSpeak3_Adapter_Blacklist_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/hidden/TeamSpeak3/Adapter/Exception.php b/hidden/TeamSpeak3/Adapter/Exception.php new file mode 100644 index 0000000..a6d4f46 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_Abstract objects. + */ +class TeamSpeak3_Adapter_Exception extends TeamSpeak3_Exception {} diff --git a/hidden/TeamSpeak3/Adapter/FileTransfer.php b/hidden/TeamSpeak3/Adapter/FileTransfer.php new file mode 100644 index 0000000..4c2a7a9 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/FileTransfer.php @@ -0,0 +1,190 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_FileTransfer + * @brief Provides low-level methods for file transfer communication with a TeamSpeak 3 Server. + */ +class TeamSpeak3_Adapter_FileTransfer extends TeamSpeak3_Adapter_Abstract +{ + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + public function syn() + { + $this->initTransport($this->options); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_FileTransfer destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->getTransport()->isConnected()) + { + $this->getTransport()->disconnect(); + } + } + + /** + * Sends a valid file transfer key to the server to initialize the file transfer. + * + * @param string $ftkey + * @throws TeamSpeak3_Adapter_FileTransfer_Exception + * @return void + */ + protected function init($ftkey) + { + if(strlen($ftkey) != 32) + { + throw new TeamSpeak3_Adapter_FileTransfer_Exception("invalid file transfer key format"); + } + + $this->getProfiler()->start(); + $this->getTransport()->send($ftkey); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferHandshake", $this); + } + + /** + * Sends the content of a file to the server. + * + * @param string $ftkey + * @param integer $seek + * @param string $data + * @throws TeamSpeak3_Adapter_FileTransfer_Exception + * @return void + */ + public function upload($ftkey, $seek, $data) + { + $this->init($ftkey); + + $size = strlen($data); + $seek = intval($seek); + $pack = 4096; + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferUploadStarted", $ftkey, $seek, $size); + + for(;$seek < $size;) + { + $rest = $size-$seek; + $pack = $rest < $pack ? $rest : $pack; + $buff = substr($data, $seek, $pack); + $seek = $seek+$pack; + + $this->getTransport()->send($buff); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferUploadProgress", $ftkey, $seek, $size); + } + + $this->getProfiler()->stop(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferUploadFinished", $ftkey, $seek, $size); + + if($seek < $size) + { + throw new TeamSpeak3_Adapter_FileTransfer_Exception("incomplete file upload (" . $seek . " of " . $size . " bytes)"); + } + } + + /** + * Returns the content of a downloaded file as a TeamSpeak3_Helper_String object. + * + * @param string $ftkey + * @param integer $size + * @param boolean $passthru + * @throws TeamSpeak3_Adapter_FileTransfer_Exception + * @return TeamSpeak3_Helper_String + */ + public function download($ftkey, $size, $passthru = FALSE) + { + $this->init($ftkey); + + if($passthru) + { + return $this->passthru($size); + } + + $buff = new TeamSpeak3_Helper_String(""); + $size = intval($size); + $pack = 4096; + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferDownloadStarted", $ftkey, count($buff), $size); + + for($seek = 0;$seek < $size;) + { + $rest = $size-$seek; + $pack = $rest < $pack ? $rest : $pack; + $data = $this->getTransport()->read($rest < $pack ? $rest : $pack); + $seek = $seek+$pack; + + $buff->append($data); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferDownloadProgress", $ftkey, count($buff), $size); + } + + $this->getProfiler()->stop(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferDownloadFinished", $ftkey, count($buff), $size); + + if(strlen($buff) != $size) + { + throw new TeamSpeak3_Adapter_FileTransfer_Exception("incomplete file download (" . count($buff) . " of " . $size . " bytes)"); + } + + return $buff; + } + + /** + * Outputs all remaining data on a TeamSpeak 3 file transfer stream using PHP's fpassthru() + * function. + * + * @param integer $size + * @throws TeamSpeak3_Adapter_FileTransfer_Exception + * @return void + */ + protected function passthru($size) + { + $buff_size = fpassthru($this->getTransport()->getStream()); + + if($buff_size != $size) + { + throw new TeamSpeak3_Adapter_FileTransfer_Exception("incomplete file download (" . intval($buff_size) . " of " . $size . " bytes)"); + } + } +} diff --git a/hidden/TeamSpeak3/Adapter/FileTransfer/Exception.php b/hidden/TeamSpeak3/Adapter/FileTransfer/Exception.php new file mode 100644 index 0000000..0ae9200 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/FileTransfer/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_FileTransfer_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_FileTransfer objects. + */ +class TeamSpeak3_Adapter_FileTransfer_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/hidden/TeamSpeak3/Adapter/ServerQuery.php b/hidden/TeamSpeak3/Adapter/ServerQuery.php new file mode 100644 index 0000000..2064281 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/ServerQuery.php @@ -0,0 +1,261 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_ServerQuery + * @brief Provides low-level methods for ServerQuery communication with a TeamSpeak 3 Server. + */ +class TeamSpeak3_Adapter_ServerQuery extends TeamSpeak3_Adapter_Abstract +{ + /** + * Stores a singleton instance of the active TeamSpeak3_Node_Host object. + * + * @var TeamSpeak3_Node_Host + */ + protected $host = null; + + /** + * Stores the timestamp of the last command. + * + * @var integer + */ + protected $timer = null; + + /** + * Number of queries executed on the server. + * + * @var integer + */ + protected $count = 0; + + /** + * Stores an array with unsupported commands. + * + * @var array + */ + protected $block = array("help"); + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + protected function syn() + { + $this->initTransport($this->options); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + if(!$this->getTransport()->readLine()->startsWith(TeamSpeak3::READY)) + { + throw new TeamSpeak3_Adapter_Exception("invalid reply from the server"); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("serverqueryConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_ServerQuery destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->transport->isConnected()) + { + try + { + $this->request("quit"); + } + catch(Exception $e) + { + return; + } + } + } + + /** + * Sends a prepared command to the server and returns the result. + * + * @param string $cmd + * @param boolean $throw + * @throws TeamSpeak3_Adapter_Exception + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function request($cmd, $throw = TRUE) + { + $query = TeamSpeak3_Helper_String::factory($cmd)->section(TeamSpeak3::SEPARATOR_CELL); + + if(strstr($cmd, "\r") || strstr($cmd, "\n")) + { + throw new TeamSpeak3_Adapter_Exception("illegal characters in command '" . $query . "'"); + } + elseif(in_array($query, $this->block)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("command not found", 0x100); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("serverqueryCommandStarted", $cmd); + + $this->getProfiler()->start(); + $this->getTransport()->sendLine($cmd); + $this->timer = time(); + $this->count++; + + $rpl = array(); + + do { + $str = $this->getTransport()->readLine(); + $rpl[] = $str; + } while($str instanceof TeamSpeak3_Helper_String && $str->section(TeamSpeak3::SEPARATOR_CELL) != TeamSpeak3::ERROR); + + $this->getProfiler()->stop(); + + $reply = new TeamSpeak3_Adapter_ServerQuery_Reply($rpl, $cmd, $this->getHost(), $throw); + + TeamSpeak3_Helper_Signal::getInstance()->emit("serverqueryCommandFinished", $cmd, $reply); + + return $reply; + } + + /** + * Waits for the server to send a notification message and returns the result. + * + * @throws TeamSpeak3_Adapter_Exception + * @return TeamSpeak3_Adapter_ServerQuery_Event + */ + public function wait() + { + if($this->getTransport()->getConfig("blocking")) + { + throw new TeamSpeak3_Adapter_Exception("only available in non-blocking mode"); + } + + do { + $evt = $this->getTransport()->readLine(); + } while($evt instanceof TeamSpeak3_Helper_String && !$evt->section(TeamSpeak3::SEPARATOR_CELL)->startsWith(TeamSpeak3::EVENT)); + + return new TeamSpeak3_Adapter_ServerQuery_Event($evt, $this->getHost()); + } + + /** + * Uses given parameters and returns a prepared ServerQuery command. + * + * @param string $cmd + * @param array $params + * @return string + */ + public function prepare($cmd, array $params = array()) + { + $args = array(); + $cells = array(); + + foreach($params as $ident => $value) + { + $ident = is_numeric($ident) ? "" : strtolower($ident) . TeamSpeak3::SEPARATOR_PAIR; + + if(is_array($value)) + { + $value = array_values($value); + + for($i = 0; $i < count($value); $i++) + { + if($value[$i] === null) continue; + elseif($value[$i] === FALSE) $value[$i] = 0x00; + elseif($value[$i] === TRUE) $value[$i] = 0x01; + elseif($value[$i] instanceof TeamSpeak3_Node_Abstract) $value[$i] = $value[$i]->getId(); + + $cells[$i][] = $ident . TeamSpeak3_Helper_String::factory($value[$i])->escape()->toUtf8(); + } + } + else + { + if($value === null) continue; + elseif($value === FALSE) $value = 0x00; + elseif($value === TRUE) $value = 0x01; + elseif($value instanceof TeamSpeak3_Node_Abstract) $value = $value->getId(); + + $args[] = $ident . TeamSpeak3_Helper_String::factory($value)->escape()->toUtf8(); + } + } + + foreach(array_keys($cells) as $ident) $cells[$ident] = implode(TeamSpeak3::SEPARATOR_CELL, $cells[$ident]); + + if(count($args)) $cmd .= " " . implode(TeamSpeak3::SEPARATOR_CELL, $args); + if(count($cells)) $cmd .= " " . implode(TeamSpeak3::SEPARATOR_LIST, $cells); + + return trim($cmd); + } + + /** + * Returns the timestamp of the last command. + * + * @return integer + */ + public function getQueryLastTimestamp() + { + return $this->timer; + } + + /** + * Returns the number of queries executed on the server. + * + * @return integer + */ + public function getQueryCount() + { + return $this->count; + } + + /** + * Returns the total runtime of all queries. + * + * @return mixed + */ + public function getQueryRuntime() + { + return $this->getProfiler()->getRuntime(); + } + + /** + * Returns the TeamSpeak3_Node_Host object of the current connection. + * + * @return TeamSpeak3_Node_Host + */ + public function getHost() + { + if($this->host === null) + { + $this->host = new TeamSpeak3_Node_Host($this); + } + + return $this->host; + } +} diff --git a/hidden/TeamSpeak3/Adapter/ServerQuery/Event.php b/hidden/TeamSpeak3/Adapter/ServerQuery/Event.php new file mode 100644 index 0000000..191b37c --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/ServerQuery/Event.php @@ -0,0 +1,170 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_ServerQuery_Event + * @brief Provides methods to analyze and format a ServerQuery event. + */ +class TeamSpeak3_Adapter_ServerQuery_Event implements ArrayAccess +{ + /** + * Stores the event type. + * + * @var TeamSpeak3_Helper_String + */ + protected $type = null; + + /** + * Stores the event data. + * + * @var array + */ + protected $data = null; + + /** + * Stores the event data as an unparsed string. + * + * @var TeamSpeak3_Helper_String + */ + protected $mesg = null; + + /** + * Creates a new TeamSpeak3_Adapter_ServerQuery_Event object. + * + * @param TeamSpeak3_Helper_String $evt + * @param TeamSpeak3_Node_Host $con + * @throws TeamSpeak3_Adapter_Exception + * @return TeamSpeak3_Adapter_ServerQuery_Event + */ + public function __construct(TeamSpeak3_Helper_String $evt, TeamSpeak3_Node_Host $con = null) + { + if(!$evt->startsWith(TeamSpeak3::EVENT)) + { + throw new TeamSpeak3_Adapter_Exception("invalid notification event format"); + } + + list($type, $data) = $evt->split(TeamSpeak3::SEPARATOR_CELL, 2); + + if(empty($data)) + { + throw new TeamSpeak3_Adapter_Exception("invalid notification event data"); + } + + $fake = new TeamSpeak3_Helper_String(TeamSpeak3::ERROR . TeamSpeak3::SEPARATOR_CELL . "id" . TeamSpeak3::SEPARATOR_PAIR . 0 . TeamSpeak3::SEPARATOR_CELL . "msg" . TeamSpeak3::SEPARATOR_PAIR . "ok"); + $repl = new TeamSpeak3_Adapter_ServerQuery_Reply(array($data, $fake), $type); + + $this->type = $type->substr(strlen(TeamSpeak3::EVENT)); + $this->data = $repl->toList(); + $this->mesg = $data; + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyEvent", $this, $con); + TeamSpeak3_Helper_Signal::getInstance()->emit("notify" . ucfirst($this->type), $this, $con); + } + + /** + * Returns the event type string. + * + * @return TeamSpeak3_Helper_String + */ + public function getType() + { + return $this->type; + } + + /** + * Returns the event data array. + * + * @return array + */ + public function getData() + { + return $this->data; + } + + /** + * Returns the event data as an unparsed string. + * + * @return TeamSpeak3_Helper_String + */ + public function getMessage() + { + return $this->mesg; + } + + /** + * @ignore + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->data) ? TRUE : FALSE; + } + + /** + * @ignore + */ + public function offsetGet($offset) + { + if(!$this->offsetExists($offset)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + return $this->data[$offset]; + } + + /** + * @ignore + */ + public function offsetSet($offset, $value) + { + throw new TeamSpeak3_Node_Exception("event '" . $this->getType() . "' is read only"); + } + + /** + * @ignore + */ + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } + + /** + * @ignore + */ + public function __get($offset) + { + return $this->offsetGet($offset); + } + + /** + * @ignore + */ + public function __set($offset, $value) + { + $this->offsetSet($offset, $value); + } +} diff --git a/hidden/TeamSpeak3/Adapter/ServerQuery/Exception.php b/hidden/TeamSpeak3/Adapter/ServerQuery/Exception.php new file mode 100644 index 0000000..5886f34 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/ServerQuery/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_ServerQuery_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_ServerQuery objects. + */ +class TeamSpeak3_Adapter_ServerQuery_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/hidden/TeamSpeak3/Adapter/ServerQuery/Reply.php b/hidden/TeamSpeak3/Adapter/ServerQuery/Reply.php new file mode 100644 index 0000000..cdcdea9 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/ServerQuery/Reply.php @@ -0,0 +1,346 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_ServerQuery_Reply + * @brief Provides methods to analyze and format a ServerQuery reply. + */ +class TeamSpeak3_Adapter_ServerQuery_Reply +{ + /** + * Stores the command used to get this reply. + * + * @var TeamSpeak3_Helper_String + */ + protected $cmd = null; + + /** + * Stores the servers reply (if available). + * + * @var TeamSpeak3_Helper_String + */ + protected $rpl = null; + + /** + * Stores connected TeamSpeak3_Node_Host object. + * + * @var TeamSpeak3_Node_Host + */ + protected $con = null; + + /** + * Stores an assoc array containing the error info for this reply. + * + * @var array + */ + protected $err = array(); + + /** + * Sotres an array of events that occured before or during this reply. + * + * @var array + */ + protected $evt = array(); + + /** + * Indicates whether exceptions should be thrown or not. + * + * @var boolean + */ + protected $exp = TRUE; + + /** + * Creates a new TeamSpeak3_Adapter_ServerQuery_Reply object. + * + * @param array $rpl + * @param string $cmd + * @param boolean $exp + * @param TeamSpeak3_Node_Host $con + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function __construct(array $rpl, $cmd = null, TeamSpeak3_Node_Host $con = null, $exp = TRUE) + { + $this->cmd = new TeamSpeak3_Helper_String($cmd); + $this->con = $con; + $this->exp = (bool) $exp; + + $this->fetchError(array_pop($rpl)); + $this->fetchReply($rpl); + } + + /** + * Returns the reply as an TeamSpeak3_Helper_String object. + * + * @return TeamSpeak3_Helper_String + */ + public function toString() + { + return (!func_num_args()) ? $this->rpl->unescape() : $this->rpl; + } + + /** + * Returns the reply as a standard PHP array where each element represents one item. + * + * @return array + */ + public function toLines() + { + if(!count($this->rpl)) return array(); + + $list = $this->toString(0)->split(TeamSpeak3::SEPARATOR_LIST); + + if(!func_num_args()) + { + for($i = 0; $i < count($list); $i++) $list[$i]->unescape(); + } + + return $list; + } + + /** + * Returns the reply as a standard PHP array where each element represents one item in table format. + * + * @return array + */ + public function toTable() + { + $table = array(); + + foreach($this->toLines(0) as $cells) + { + $pairs = $cells->split(TeamSpeak3::SEPARATOR_CELL); + + if(!func_num_args()) + { + for($i = 0; $i < count($pairs); $i++) $pairs[$i]->unescape(); + } + + $table[] = $pairs; + } + + return $table; + } + + /** + * Returns a multi-dimensional array containing the reply splitted in multiple rows and columns. + * + * @return array + */ + public function toArray() + { + $array = array(); + $table = $this->toTable(1); + + for($i = 0; $i < count($table); $i++) + { + foreach($table[$i] as $pair) + { + if(!count($pair)) + { + continue; + } + + if(!$pair->contains(TeamSpeak3::SEPARATOR_PAIR)) + { + $array[$i][$pair->toString()] = null; + } + else + { + list($ident, $value) = $pair->split(TeamSpeak3::SEPARATOR_PAIR, 2); + + $array[$i][$ident->toString()] = $value->isInt() ? $value->toInt() : (!func_num_args() ? $value->unescape() : $value); + } + } + } + + return $array; + } + + /** + * Returns a multi-dimensional assoc array containing the reply splitted in multiple rows and columns. + * The identifier specified by key will be used while indexing the array. + * + * @param $key + * @return array + */ + public function toAssocArray($ident) + { + $nodes = (func_num_args() > 1) ? $this->toArray(1) : $this->toArray(); + $array = array(); + + foreach($nodes as $node) + { + if(array_key_exists($ident, $node)) + { + $array[(is_object($node[$ident])) ? $node[$ident]->toString() : $node[$ident]] = $node; + } + else + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + } + + return $array; + } + + /** + * Returns an array containing the reply splitted in multiple rows and columns. + * + * @return array + */ + public function toList() + { + $array = func_num_args() ? $this->toArray(1) : $this->toArray(); + + if(count($array) == 1) + { + return array_shift($array); + } + + return $array; + } + + /** + * Returns an array containing stdClass objects. + * + * @return ArrayObject + */ + public function toObjectArray() + { + $array = (func_num_args() > 1) ? $this->toArray(1) : $this->toArray(); + + for($i = 0; $i < count($array); $i++) + { + $array[$i] = (object) $array[$i]; + } + + return $array; + } + + /** + * Returns the command used to get this reply. + * + * @return TeamSpeak3_Helper_String + */ + public function getCommandString() + { + return new TeamSpeak3_Helper_String($this->cmd); + } + + /** + * Returns an array of events that occured before or during this reply. + * + * @return array + */ + public function getNotifyEvents() + { + return $this->evt; + } + + /** + * Returns the value for a specified error property. + * + * @param string $ident + * @param mixed $default + * @return mixed + */ + public function getErrorProperty($ident, $default = null) + { + return (array_key_exists($ident, $this->err)) ? $this->err[$ident] : $default; + } + + /** + * Parses a ServerQuery error and throws a TeamSpeak3_Adapter_ServerQuery_Exception object if + * there's an error. + * + * @param string $err + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return void + */ + protected function fetchError($err) + { + $cells = $err->section(TeamSpeak3::SEPARATOR_CELL, 1, 3); + + foreach($cells->split(TeamSpeak3::SEPARATOR_CELL) as $pair) + { + list($ident, $value) = $pair->split(TeamSpeak3::SEPARATOR_PAIR); + + $this->err[$ident->toString()] = $value->isInt() ? $value->toInt() : $value->unescape(); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyError", $this); + + if($this->getErrorProperty("id", 0x00) != 0x00 && $this->exp) + { + if($permid = $this->getErrorProperty("failed_permid")) + { + if($permsid = key($this->con->request("permget permid=" . $permid, FALSE)->toAssocArray("permsid"))) + { + $suffix = " (failed on " . $permsid . ")"; + } + else + { + $suffix = " (failed on " . $this->cmd->section(TeamSpeak3::SEPARATOR_CELL) . " " . $permid . "/0x" . strtoupper(dechex($permid)) . ")"; + } + } + elseif($details = $this->getErrorProperty("extra_msg")) + { + $suffix = " (" . trim($details) . ")"; + } + else + { + $suffix = ""; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception($this->getErrorProperty("msg") . $suffix, $this->getErrorProperty("id")); + } + } + + /** + * Parses a ServerQuery reply and creates a TeamSpeak3_Helper_String object. + * + * @param string $rpl + * @return void + */ + protected function fetchReply($rpl) + { + foreach($rpl as $key => $val) + { + if($val->startsWith(TeamSpeak3::GREET)) + { + unset($rpl[$key]); + } + elseif($val->startsWith(TeamSpeak3::EVENT)) + { + $this->evt[] = new TeamSpeak3_Adapter_ServerQuery_Event($rpl[$key], $this->con); + unset($rpl[$key]); + } + } + + $this->rpl = new TeamSpeak3_Helper_String(implode(TeamSpeak3::SEPARATOR_LIST, $rpl)); + } +} diff --git a/hidden/TeamSpeak3/Adapter/TSDNS.php b/hidden/TeamSpeak3/Adapter/TSDNS.php new file mode 100644 index 0000000..bbef31b --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/TSDNS.php @@ -0,0 +1,95 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_TSDNS + * @brief Provides methods to query a TSDNS server. + */ +class TeamSpeak3_Adapter_TSDNS extends TeamSpeak3_Adapter_Abstract +{ + /** + * The TCP port number used by any TSDNS server. + * + * @var integer + */ + protected $default_port = 41144; + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Exception + * @return void + */ + public function syn() + { + if(!isset($this->options["port"]) || empty($this->options["port"])) $this->options["port"] = $this->default_port; + + $this->initTransport($this->options); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + TeamSpeak3_Helper_Signal::getInstance()->emit("tsdnsConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_FileTransfer destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->getTransport()->isConnected()) + { + $this->getTransport()->disconnect(); + } + } + + /** + * Queries the TSDNS server for a specified virtual hostname and returns the result. + * + * @param string $tsdns + * @throws TeamSpeak3_Adapter_TSDNS_Exception + * @return TeamSpeak3_Helper_String + */ + public function resolve($tsdns) + { + $this->getTransport()->sendLine($tsdns); + $repl = $this->getTransport()->readLine(); + $this->getTransport()->disconnect(); + + if($repl->section(":", 0)->toInt() == 404) + { + throw new TeamSpeak3_Adapter_TSDNS_Exception("unable to resolve TSDNS hostname (" . $tsdns . ")"); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("tsdnsResolved", $tsdns, $repl); + + return $repl; + } +} diff --git a/hidden/TeamSpeak3/Adapter/TSDNS/Exception.php b/hidden/TeamSpeak3/Adapter/TSDNS/Exception.php new file mode 100644 index 0000000..61ace62 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/TSDNS/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_TSDNS_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_TSDNS objects. + */ +class TeamSpeak3_Adapter_TSDNS_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/hidden/TeamSpeak3/Adapter/Update.php b/hidden/TeamSpeak3/Adapter/Update.php new file mode 100644 index 0000000..3c29937 --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/Update.php @@ -0,0 +1,217 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Update + * @brief Provides methods to query the latest TeamSpeak 3 build numbers from the master server. + */ +class TeamSpeak3_Adapter_Update extends TeamSpeak3_Adapter_Abstract +{ + /** + * The IPv4 address or FQDN of the TeamSpeak Systems update server. + * + * @var string + */ + protected $default_host = "update.teamspeak.com"; + + /** + * The UDP port number of the TeamSpeak Systems update server. + * + * @var integer + */ + protected $default_port = 17384; + + /** + * Stores an array containing the latest build numbers (integer timestamps). + * + * @var array + */ + protected $build_datetimes = null; + + /** + * Stores an array containing the latest version strings. + * + * @var array + */ + protected $version_strings = null; + + /** + * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote + * server. + * + * @throws TeamSpeak3_Adapter_Update_Exception + * @return void + */ + public function syn() + { + if(!isset($this->options["host"]) || empty($this->options["host"])) $this->options["host"] = $this->default_host; + if(!isset($this->options["port"]) || empty($this->options["port"])) $this->options["port"] = $this->default_port; + + $this->initTransport($this->options, "TeamSpeak3_Transport_UDP"); + $this->transport->setAdapter($this); + + TeamSpeak3_Helper_Profiler::init(spl_object_hash($this)); + + $this->getTransport()->send(TeamSpeak3_Helper_String::fromHex(33)); + + if(!preg_match_all("/,?(\d+)#([0-9a-zA-Z\._-]+),?/", $this->getTransport()->read(96), $matches) || !isset($matches[1]) || !isset($matches[2])) + { + throw new TeamSpeak3_Adapter_Update_Exception("invalid reply from the server"); + } + + $this->build_datetimes = $matches[1]; + $this->version_strings = $matches[2]; + + TeamSpeak3_Helper_Signal::getInstance()->emit("updateConnected", $this); + } + + /** + * The TeamSpeak3_Adapter_Update destructor. + * + * @return void + */ + public function __destruct() + { + if($this->getTransport() instanceof TeamSpeak3_Transport_Abstract && $this->getTransport()->isConnected()) + { + $this->getTransport()->disconnect(); + } + } + + /** + * Returns the current build number for a specified update channel. Note that since version + * 3.0.0, the build number represents an integer timestamp. $channel must be set to one of + * the following values: + * + * - stable + * - beta + * - alpha + * - server + * + * @param string $channel + * @throws TeamSpeak3_Adapter_Update_Exception + * @return integer + */ + public function getRev($channel = "stable") + { + switch($channel) + { + case "stable": + return isset($this->build_datetimes[0]) ? $this->build_datetimes[0] : null; + + case "beta": + return isset($this->build_datetimes[1]) ? $this->build_datetimes[1] : null; + + case "alpha": + return isset($this->build_datetimes[2]) ? $this->build_datetimes[2] : null; + + case "server": + return isset($this->build_datetimes[3]) ? $this->build_datetimes[3] : null; + + default: + throw new TeamSpeak3_Adapter_Update_Exception("invalid update channel identifier (" . $channel . ")"); + } + } + + /** + * Returns the current version string for a specified update channel. $channel must be set to + * one of the following values: + * + * - stable + * - beta + * - alpha + * - server + * + * @param string $channel + * @throws TeamSpeak3_Adapter_Update_Exception + * @return integer + */ + public function getVersion($channel = "stable") + { + switch($channel) + { + case "stable": + return isset($this->version_strings[0]) ? $this->version_strings[0] : null; + + case "beta": + return isset($this->version_strings[1]) ? $this->version_strings[1] : null; + + case "alpha": + return isset($this->version_strings[2]) ? $this->version_strings[2] : null; + + case "server": + return isset($this->version_strings[3]) ? $this->version_strings[3] : null; + + default: + throw new TeamSpeak3_Adapter_Update_Exception("invalid update channel identifier (" . $channel . ")"); + } + } + + /** + * Alias for getRev() using the 'stable' update channel. + * + * @param string $channel + * @return integer + */ + public function getClientRev() + { + return $this->getRev("stable"); + } + + /** + * Alias for getRev() using the 'server' update channel. + * + * @param string $channel + * @return integer + */ + public function getServerRev() + { + return $this->getRev("server"); + } + + /** + * Alias for getVersion() using the 'stable' update channel. + * + * @param string $channel + * @return integer + */ + public function getClientVersion() + { + return $this->getVersion("stable"); + } + + /** + * Alias for getVersion() using the 'server' update channel. + * + * @param string $channel + * @return integer + */ + public function getServerVersion() + { + return $this->getVersion("server"); + } +} diff --git a/hidden/TeamSpeak3/Adapter/Update/Exception.php b/hidden/TeamSpeak3/Adapter/Update/Exception.php new file mode 100644 index 0000000..ba239ad --- /dev/null +++ b/hidden/TeamSpeak3/Adapter/Update/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Adapter_Update_Exception + * @brief Enhanced exception class for TeamSpeak3_Adapter_Update objects. + */ +class TeamSpeak3_Adapter_Update_Exception extends TeamSpeak3_Adapter_Exception {} diff --git a/hidden/TeamSpeak3/Exception.php b/hidden/TeamSpeak3/Exception.php new file mode 100644 index 0000000..680faf8 --- /dev/null +++ b/hidden/TeamSpeak3/Exception.php @@ -0,0 +1,129 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Exception + * @brief Enhanced exception class for TeamSpeak3 objects. + */ +class TeamSpeak3_Exception extends Exception +{ + /** + * Stores custom error messages. + * + * @var array + */ + protected static $messages = array(); + + /** + * The TeamSpeak3_Exception constructor. + * + * @param string $mesg + * @param integer $code + * @return TeamSpeak3_Exception + */ + public function __construct($mesg, $code = 0x00) + { + parent::__construct($mesg, $code); + + if(array_key_exists((int) $code, self::$messages)) + { + $this->message = $this->prepareCustomMessage(self::$messages[intval($code)]); + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("errorException", $this); + } + + /** + * Prepares a custom error message by replacing pre-defined signs with given values. + * + * @param TeamSpeak3_Helper_String $mesg + * @return TeamSpeak3_Helper_String + */ + protected function prepareCustomMessage(TeamSpeak3_Helper_String $mesg) + { + $args = array( + "code" => $this->getCode(), + "mesg" => $this->getMessage(), + "line" => $this->getLine(), + "file" => $this->getFile(), + ); + + return $mesg->arg($args)->toString(); + } + + /** + * Registers a custom error message to $code. + * + * @param integer $code + * @param string $mesg + * @throws TeamSpeak3_Exception + * @return void + */ + public static function registerCustomMessage($code, $mesg) + { + if(array_key_exists((int) $code, self::$messages)) + { + throw new self("custom message for code 0x" . strtoupper(dechex($code)) . " is already registered"); + } + + if(!is_string($mesg)) + { + throw new self("custom message for code 0x" . strtoupper(dechex($code)) . " must be a string"); + } + + self::$messages[(int) $code] = new TeamSpeak3_Helper_String($mesg); + } + + /** + * Unregisters a custom error message from $code. + * + * @param integer $code + * @throws TeamSpeak3_Exception + * @return void + */ + public static function unregisterCustomMessage($code) + { + if(!array_key_exists((int) $code, self::$messages)) + { + throw new self("custom message for code 0x" . strtoupper(dechex($code)) . " is not registered"); + } + + unset(self::$messages[intval($code)]); + } + + /** + * Returns the class from which the exception was thrown. + * + * @return string + */ + public function getSender() + { + $trace = $this->getTrace(); + + return (isset($trace[0]["class"])) ? $trace[0]["class"] : "{main}"; + } +} diff --git a/hidden/TeamSpeak3/Helper/Char.php b/hidden/TeamSpeak3/Helper/Char.php new file mode 100644 index 0000000..1159a1a --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Char.php @@ -0,0 +1,269 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Char + * @brief Helper class for char handling. + */ +class TeamSpeak3_Helper_Char +{ + /** + * Stores the original character. + * + * @var string + */ + protected $char = null; + + /** + * The TeamSpeak3_Helper_Char constructor. + * + * @param string $var + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_Char + */ + public function __construct($char) + { + if(strlen($char) != 1) + { + throw new TeamSpeak3_Helper_Exception("char parameter may not contain more or less than one character"); + } + + $this->char = strval($char); + } + + /** + * Returns true if the character is a letter. + * + * @return boolean + */ + public function isLetter() + { + return ctype_alpha($this->char); + } + + /** + * Returns true if the character is a decimal digit. + * + * @return boolean + */ + public function isDigit() + { + return ctype_digit($this->char); + } + + /** + * Returns true if the character is a space. + * + * @return boolean + */ + public function isSpace() + { + return ctype_space($this->char); + } + + /** + * Returns true if the character is a mark. + * + * @return boolean + */ + public function isMark() + { + return ctype_punct($this->char); + } + + /** + * Returns true if the character is a control character (i.e. "\t"). + * + * @return boolean + */ + public function isControl() + { + return ctype_cntrl($this->char); + } + + /** + * Returns true if the character is a printable character. + * + * @return boolean + */ + public function isPrintable() + { + return ctype_print($this->char); + } + + /** + * Returns true if the character is the Unicode character 0x0000 ("\0"). + * + * @return boolean + */ + public function isNull() + { + return ($this->char === "\0") ? TRUE : FALSE; + } + + /** + * Returns true if the character is an uppercase letter. + * + * @return boolean + */ + public function isUpper() + { + return ($this->char === strtoupper($this->char)) ? TRUE : FALSE; + } + + /** + * Returns true if the character is a lowercase letter. + * + * @return boolean + */ + public function isLower() + { + return ($this->char === strtolower($this->char)) ? TRUE : FALSE; + } + + /** + * Returns the uppercase equivalent if the character is lowercase. + * + * @return TeamSpeak3_Helper_Char + */ + public function toUpper() + { + return ($this->isUpper()) ? $this : new self(strtoupper($this)); + } + + /** + * Returns the lowercase equivalent if the character is uppercase. + * + * @return TeamSpeak3_Helper_Char + */ + public function toLower() + { + return ($this->isLower()) ? $this : new self(strtolower($this)); + } + + /** + * Returns the ascii value of the character. + * + * @return integer + */ + public function toAscii() + { + return ord($this->char); + } + + /** + * Returns the Unicode value of the character. + * + * @return integer + */ + public function toUnicode() + { + $h = ord($this->char{0}); + + if($h <= 0x7F) + { + return $h; + } + else if($h < 0xC2) + { + return FALSE; + } + else if($h <= 0xDF) + { + return ($h & 0x1F) << 6 | (ord($this->char{1}) & 0x3F); + } + else if($h <= 0xEF) + { + return ($h & 0x0F) << 12 | (ord($this->char{1}) & 0x3F) << 6 | (ord($this->char{2}) & 0x3F); + } + else if($h <= 0xF4) + { + return ($h & 0x0F) << 18 | (ord($this->char{1}) & 0x3F) << 12 | (ord($this->char{2}) & 0x3F) << 6 | (ord($this->char{3}) & 0x3F); + } + else + { + return FALSE; + } + } + + /** + * Returns the hexadecimal value of the char. + * + * @return string + */ + public function toHex() + { + return strtoupper(dechex($this->toAscii())); + } + + /** + * Returns the TeamSpeak3_Helper_Char based on a given hex value. + * + * @param string $hex + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_Char + */ + public static function fromHex($hex) + { + if(strlen($hex) != 2) + { + throw new TeamSpeak3_Helper_Exception("given parameter '" . $hex . "' is not a valid hexadecimal number"); + } + + return new self(chr(hexdec($hex))); + } + + /** + * Returns the character as a standard string. + * + * @return string + */ + public function toString() + { + return $this->char; + } + + /** + * Returns the integer value of the character. + * + * @return integer + */ + public function toInt() + { + return intval($this->char); + } + + /** + * Returns the character as a standard string. + * + * @return string + */ + public function __toString() + { + return $this->char; + } +} diff --git a/hidden/TeamSpeak3/Helper/Convert.php b/hidden/TeamSpeak3/Helper/Convert.php new file mode 100644 index 0000000..d1fa21a --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Convert.php @@ -0,0 +1,349 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Convert + * @brief Helper class for data conversion. + */ +class TeamSpeak3_Helper_Convert +{ + /** + * Converts bytes to a human readable value. + * + * @param integer $bytes + * @return string + */ + public static function bytes($bytes) + { + $kbytes = sprintf("%.02f", $bytes/1024); + $mbytes = sprintf("%.02f", $kbytes/1024); + $gbytes = sprintf("%.02f", $mbytes/1024); + $tbytes = sprintf("%.02f", $gbytes/1024); + + if($tbytes >= 1) + return $tbytes . " TB"; + if($gbytes >= 1) + return $gbytes . " GB"; + if($mbytes >= 1) + return $mbytes . " MB"; + if($kbytes >= 1) + return $kbytes . " KB"; + + return $bytes . " B"; + } + + /** + * Converts seconds/milliseconds to a human readable value. + * + * @param integer $seconds + * @param boolean $is_ms + * @param string $format + * @return string + */ + public static function seconds($seconds, $is_ms = FALSE, $format = "%dD %02d:%02d:%02d") + { + if($is_ms) $seconds = $seconds/1000; + + return sprintf($format, $seconds/60/60/24, ($seconds/60/60)%24, ($seconds/60)%60, $seconds%60); + } + + /** + * Converts a given codec ID to a human readable name. + * + * @param integer $codec + * @return string + */ + public static function codec($codec) + { + if($codec == TeamSpeak3::CODEC_SPEEX_NARROWBAND) + return "Speex Narrowband"; + if($codec == TeamSpeak3::CODEC_SPEEX_WIDEBAND) + return "Speex Wideband"; + if($codec == TeamSpeak3::CODEC_SPEEX_ULTRAWIDEBAND) + return "Speex Ultra-Wideband"; + if($codec == TeamSpeak3::CODEC_CELT_MONO) + return "CELT Mono"; + if($codec == TeamSpeak3::CODEC_OPUS_VOICE) + return "Opus Voice"; + if($codec == TeamSpeak3::CODEC_OPUS_MUSIC) + return "Opus Music"; + + return "Unknown"; + } + + /** + * Converts a given group type ID to a human readable name. + * + * @param integer $type + * @return string + */ + public static function groupType($type) + { + if($type == TeamSpeak3::GROUP_DBTYPE_TEMPLATE) + return "Template"; + if($type == TeamSpeak3::GROUP_DBTYPE_REGULAR) + return "Regular"; + if($type == TeamSpeak3::GROUP_DBTYPE_SERVERQUERY) + return "ServerQuery"; + + return "Unknown"; + } + + /** + * Converts a given permission type ID to a human readable name. + * + * @param integer $type + * @return string + */ + public static function permissionType($type) + { + if($type == TeamSpeak3::PERM_TYPE_SERVERGROUP) + return "Server Group"; + if($type == TeamSpeak3::PERM_TYPE_CLIENT) + return "Client"; + if($type == TeamSpeak3::PERM_TYPE_CHANNEL) + return "Channel"; + if($type == TeamSpeak3::PERM_TYPE_CHANNELGROUP) + return "Channel Group"; + if($type == TeamSpeak3::PERM_TYPE_CHANNELCLIENT) + return "Channel Client"; + + return "Unknown"; + } + + /** + * Converts a given permission category value to a human readable name. + * + * @param integer $pcat + * @return string + */ + public static function permissionCategory($pcat) + { + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL) + return "Global"; + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL_INFORMATION) + return "Global / Information"; + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL_SERVER_MGMT) + return "Global / Virtual Server Management"; + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL_ADM_ACTIONS) + return "Global / Administration"; + if($pcat == TeamSpeak3::PERM_CAT_GLOBAL_SETTINGS) + return "Global / Settings"; + if($pcat == TeamSpeak3::PERM_CAT_SERVER) + return "Virtual Server"; + if($pcat == TeamSpeak3::PERM_CAT_SERVER_INFORMATION) + return "Virtual Server / Information"; + if($pcat == TeamSpeak3::PERM_CAT_SERVER_ADM_ACTIONS) + return "Virtual Server / Administration"; + if($pcat == TeamSpeak3::PERM_CAT_SERVER_SETTINGS) + return "Virtual Server / Settings"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL) + return "Channel"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_INFORMATION) + return "Channel / Information"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_CREATE) + return "Channel / Create"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_MODIFY) + return "Channel / Modify"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_DELETE) + return "Channel / Delete"; + if($pcat == TeamSpeak3::PERM_CAT_CHANNEL_ACCESS) + return "Channel / Access"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP) + return "Group"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP_INFORMATION) + return "Group / Information"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP_CREATE) + return "Group / Create"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP_MODIFY) + return "Group / Modify"; + if($pcat == TeamSpeak3::PERM_CAT_GROUP_DELETE) + return "Group / Delete"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT) + return "Client"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT_INFORMATION) + return "Client / Information"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT_ADM_ACTIONS) + return "Client / Admin"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT_BASICS) + return "Client / Basics"; + if($pcat == TeamSpeak3::PERM_CAT_CLIENT_MODIFY) + return "Client / Modify"; + if($pcat == TeamSpeak3::PERM_CAT_FILETRANSFER) + return "File Transfer"; + if($pcat == TeamSpeak3::PERM_CAT_NEEDED_MODIFY_POWER) + return "Grant"; + + return "Unknown"; + } + + /** + * Converts a given log level ID to a human readable name and vice versa. + * + * @param mixed $level + * @return string + */ + public static function logLevel($level) + { + if(is_numeric($level)) + { + if($level == TeamSpeak3::LOGLEVEL_CRITICAL) + return "CRITICAL"; + if($level == TeamSpeak3::LOGLEVEL_ERROR) + return "ERROR"; + if($level == TeamSpeak3::LOGLEVEL_DEBUG) + return "DEBUG"; + if($level == TeamSpeak3::LOGLEVEL_WARNING) + return "WARNING"; + if($level == TeamSpeak3::LOGLEVEL_INFO) + return "INFO"; + + return "DEVELOP"; + } + else + { + if(strtoupper($level) == "CRITICAL") + return TeamSpeak3::LOGLEVEL_CRITICAL; + if(strtoupper($level) == "ERROR") + return TeamSpeak3::LOGLEVEL_ERROR; + if(strtoupper($level) == "DEBUG") + return TeamSpeak3::LOGLEVEL_DEBUG; + if(strtoupper($level) == "WARNING") + return TeamSpeak3::LOGLEVEL_WARNING; + if(strtoupper($level) == "INFO") + return TeamSpeak3::LOGLEVEL_INFO; + + return TeamSpeak3::LOGLEVEL_DEVEL; + } + } + + /** + * Converts a specified log entry string into an array containing the data. + * + * @param string $entry + * @return array + */ + public static function logEntry($entry) + { + $parts = explode("|", $entry, 5); + $array = array(); + + if(count($parts) != 5) + { + $array["timestamp"] = 0; + $array["level"] = TeamSpeak3::LOGLEVEL_ERROR; + $array["channel"] = "ParamParser"; + $array["server_id"] = ""; + $array["msg"] = TeamSpeak3_Helper_String::factory("convert error (" . trim($entry) . ")"); + $array["msg_plain"] = $entry; + $array["malformed"] = TRUE; + } + else + { + $array["timestamp"] = strtotime(trim($parts[0])); + $array["level"] = self::logLevel(trim($parts[1])); + $array["channel"] = trim($parts[2]); + $array["server_id"] = trim($parts[3]); + $array["msg"] = TeamSpeak3_Helper_String::factory(trim($parts[4])); + $array["msg_plain"] = $entry; + $array["malformed"] = FALSE; + } + + return $array; + } + + /** + * Converts a given string to a ServerQuery password hash. + * + * @param string $plain + * @return string + */ + public static function password($plain) + { + return base64_encode(sha1($plain, TRUE)); + } + + /** + * Returns a client-like formatted version of the TeamSpeak 3 version string. + * + * @param string $version + * @param string $format + * @return string + */ + public static function version($version, $format = "Y-m-d h:i:s") + { + if(!$version instanceof TeamSpeak3_Helper_String) + { + $version = new TeamSpeak3_Helper_String($version); + } + + $buildno = $version->section("[", 1)->filterDigits()->toInt(); + + return ($buildno <= 15001) ? $version : $version->section("[")->append("(" . date($format, $buildno) . ")"); + } + + /** + * Returns a client-like short-formatted version of the TeamSpeak 3 version string. + * + * @param string $version + * @return string + */ + public static function versionShort($version) + { + if(!$version instanceof TeamSpeak3_Helper_String) + { + $version = new TeamSpeak3_Helper_String($version); + } + + return $version->section(" ", 0); + } + + /** + * Tries to detect the type of an image by a given string and returns it. + * + * @param string $binary + * @return string + */ + public static function imageMimeType($binary) + { + if(!preg_match('/\A(?:(\xff\xd8\xff)|(GIF8[79]a)|(\x89PNG\x0d\x0a)|(BM)|(\x49\x49(\x2a\x00|\x00\x4a))|(FORM.{4}ILBM))/', $binary, $matches)) + { + return "application/octet-stream"; + } + + $type = array( + 1 => "image/jpeg", + 2 => "image/gif", + 3 => "image/png", + 4 => "image/x-windows-bmp", + 5 => "image/tiff", + 6 => "image/x-ilbm", + ); + + return $type[count($matches)-1]; + } +} diff --git a/hidden/TeamSpeak3/Helper/Crypt.php b/hidden/TeamSpeak3/Helper/Crypt.php new file mode 100644 index 0000000..ad361fb --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Crypt.php @@ -0,0 +1,482 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Crypt + * @brief Helper class for data encryption. + */ +class TeamSpeak3_Helper_Crypt +{ + /** + * Stores the secret passphrase to encrypt or decrypt a given string. + * + * @var string + */ + protected $passphrase = null; + + /** + * Stores an array containing 18 32-bit entries. + * + * @var array + */ + protected $p = array(); + + /** + * Stores an array containing 4 sub-arrays with 256 32-bit entries. + * + * @var array + */ + protected $s = array(); + + /** + * The TeamSpeak3_Helper_Crypt constructor. + * + * @param string $secret + * @return TeamSpeak3_Helper_Crypt + */ + public function __construct($secret) + { + $this->setDefaultKeys(); + $this->setSecretKey($secret); + } + + /** + * Encrypts a given string. + * + * @param string $string + * @return string + */ + public function encrypt($string) + { + $string = trim($string); + $encryp = ""; + $length = strlen($string); + $string .= str_repeat(chr(0), (8-($length%8))%8); + + for($i = 0; $i < $length; $i += 8) + { + list(,$xl,$xr) = unpack("N2", substr($string, $i, 8)); + $this->encipher($xl, $xr); + $encryp .= pack("N2", $xl, $xr); + } + + return base64_encode($encryp); + } + + /** + * Decrypts a given string. + * + * @param string $string + * @return string + */ + public function decrypt($string) + { + $string = base64_decode($string); + $decryp = ""; + $length = strlen($string); + $string .= str_repeat(chr(0), (8-($length%8))%8); + + for($i = 0; $i < $length; $i += 8) + { + list(,$xl,$xr) = unpack("N2", substr($string, $i, 8)); + $this->decipher($xl, $xr); + $decryp .= pack("N2", $xl, $xr); + } + + return trim($decryp); + } + + /** + * Enciphers a single 64-bit block. + * + * @param integer $xl + * @param integer $xr + */ + protected function encipher(&$xl, &$xr) + { + for($i = 0; $i < 16; $i++) + { + $temp = $xl ^ $this->p[$i]; + $xl = ((($this->s[0][($temp>>24) & 255] + $this->s[1][($temp>>16) & 255]) ^ $this->s[2][($temp>>8) & 255]) + $this->s[3][$temp & 255]) ^ $xr; + $xr = $temp; + } + + $xr = $xl ^ $this->p[16]; + $xl = $temp ^ $this->p[17]; + } + + /** + * Deciphers a single 64-bit block + * + * @param integer $xl + * @param integer $xr + * @return void + */ + protected function decipher(&$xl, &$xr) + { + for($i = 17; $i > 1; $i--) + { + $temp = $xl ^ $this->p[$i]; + $xl = ((($this->s[0][($temp>>24) & 255] + $this->s[1][($temp>>16) & 255]) ^ $this->s[2][($temp>>8) & 255]) + $this->s[3][$temp & 255]) ^ $xr; + $xr = $temp; + } + + $xr = $xl ^ $this->p[1]; + $xl = $temp ^ $this->p[0]; + } + + /** + * Sets the secret key using the specified pasphrase. + * + * @param string $passphrase + * @throws Habitat_Exception + * @return void + */ + protected function setSecretKey($passphrase) + { + $length = strlen($passphrase); + + if(strlen($passphrase) < 1 || strlen($passphrase) > 56) + { + throw new TeamSpeak3_Helper_Exception("secret passphrase must contain at least one but less than 56 characters"); + } + + $k = 0; + $data = 0; + $datal = 0; + $datar = 0; + + for($i = 0; $i < 18; $i++) + { + $data = 0; + for($j = 4; $j > 0; $j--) + { + $data = $data << 8 | ord($passphrase{$k}); + $k = ($k+1) % $length; + } + $this->p[$i] ^= $data; + } + + + for($i = 0; $i <= 16; $i += 2) + { + $this->encipher($datal, $datar); + $this->p[$i] = $datal; + $this->p[$i+1] = $datar; + } + + foreach($this->s as $key => $val) + { + for ($i = 0; $i < 256; $i += 2) + { + $this->encipher($datal, $datar); + $this->s[$key][$i] = $datal; + $this->s[$key][$i+1] = $datar; + } + } + } + + /** + * Sets the defult p and s keys. + * + * @return void + */ + protected function setDefaultKeys() + { + $this->p = array( + 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0, + 0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, + 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B, + ); + $this->s = array( + array( + 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, + 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, + 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, + 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, + 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, + 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, + 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF, + 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, + 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60, + 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, + 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, + 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, + 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, + 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677, + 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, + 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032, + 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, + 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239, + 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, + 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, + 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3, + 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, + 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88, + 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, + 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6, + 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, + 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, + 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, + 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, + 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463, + 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, + 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09, + 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, + 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, + 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, + 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, + 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, + 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, + 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, + 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, + 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, + 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, + 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, + 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, + 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, + 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, + 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, + 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C, + 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, + 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, + 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, + 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, + 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, + 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, + 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, + 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, + 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, + 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, + 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, + 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, + 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, + 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, + 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664, + 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A + ), + array( + 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, + 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, + 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, + 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, + 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, + 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, + 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E, + 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, + 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737, + 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, + 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, + 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, + 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, + 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7, + 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, + 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331, + 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, + 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF, + 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, + 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, + 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, + 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, + 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16, + 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, + 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B, + 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, + 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, + 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, + 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, + 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A, + 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, + 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960, + 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, + 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28, + 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, + 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, + 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, + 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, + 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14, + 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, + 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50, + 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, + 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, + 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, + 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, + 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, + 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, + 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, + 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, + 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, + 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, + 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, + 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, + 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, + 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, + 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, + 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, + 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, + 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, + 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, + 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, + 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, + 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20, + 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7 + ), + array( + 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, + 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, + 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, + 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, + 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, + 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, + 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A, + 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, + 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE, + 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, + 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, + 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, + 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, + 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB, + 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, + 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B, + 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, + 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C, + 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, + 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, + 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17, + 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, + 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B, + 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, + 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922, + 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, + 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0, + 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, + 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, + 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, + 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, + 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B, + 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, + 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB, + 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, + 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, + 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, + 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, + 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, + 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, + 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D, + 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, + 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, + 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, + 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, + 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, + 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, + 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C, + 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, + 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, + 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, + 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, + 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, + 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, + 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, + 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, + 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, + 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, + 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, + 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, + 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, + 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, + 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837, + 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0 + ), + array( + 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, + 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, + 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, + 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, + 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, + 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, + 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304, + 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, + 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4, + 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, + 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, + 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, + 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, + 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51, + 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, + 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C, + 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, + 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28, + 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, + 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, + 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A, + 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, + 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB, + 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, + 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991, + 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, + 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680, + 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, + 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, + 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, + 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, + 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47, + 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, + 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D, + 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, + 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, + 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, + 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, + 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, + 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, + 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, + 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, + 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, + 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, + 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, + 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, + 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, + 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E, + 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, + 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, + 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, + 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, + 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, + 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, + 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, + 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, + 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, + 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, + 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, + 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, + 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, + 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, + 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F, + 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6 + ) + ); + } +} diff --git a/hidden/TeamSpeak3/Helper/Exception.php b/hidden/TeamSpeak3/Helper/Exception.php new file mode 100644 index 0000000..f0a1580 --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Exception + * @brief Enhanced exception class for TeamSpeak3_Helper_* objects. + */ +class TeamSpeak3_Helper_Exception extends TeamSpeak3_Exception {} diff --git a/hidden/TeamSpeak3/Helper/Profiler.php b/hidden/TeamSpeak3/Helper/Profiler.php new file mode 100644 index 0000000..cd936d8 --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Profiler.php @@ -0,0 +1,101 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Profiler + * @brief Helper class for profiler handling. + */ +class TeamSpeak3_Helper_Profiler +{ + /** + * Stores various timers for code profiling. + * + * @var array + */ + protected static $timers = array(); + + /** + * Inits a timer. + * + * @param string $name + * @return void + */ + public static function init($name = "default") + { + self::$timers[$name] = new TeamSpeak3_Helper_Profiler_Timer($name); + } + + /** + * Starts a timer. + * + * @param string $name + * @return void + */ + public static function start($name = "default") + { + if(array_key_exists($name, self::$timers)) + { + self::$timers[$name]->start(); + } + else + { + self::$timers[$name] = new TeamSpeak3_Helper_Profiler_Timer($name); + } + } + + /** + * Stops a timer. + * + * @param string $name + * @return void + */ + public static function stop($name = "default") + { + if(!array_key_exists($name, self::$timers)) + { + self::init($name); + } + + self::$timers[$name]->stop(); + } + + /** + * Returns a timer. + * + * @param string $name + * @return TeamSpeak3_Helper_Profiler_Timer + */ + public static function get($name = "default") + { + if(!array_key_exists($name, self::$timers)) + { + self::init($name); + } + + return self::$timers[$name]; + } +} diff --git a/hidden/TeamSpeak3/Helper/Profiler/Exception.php b/hidden/TeamSpeak3/Helper/Profiler/Exception.php new file mode 100644 index 0000000..67682c7 --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Profiler/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Profiler_Exception + * @brief Enhanced exception class for TeamSpeak3_Helper_Profiler objects. + */ +class TeamSpeak3_Helper_Profiler_Exception extends TeamSpeak3_Helper_Exception {} diff --git a/hidden/TeamSpeak3/Helper/Profiler/Timer.php b/hidden/TeamSpeak3/Helper/Profiler/Timer.php new file mode 100644 index 0000000..15a8dbb --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Profiler/Timer.php @@ -0,0 +1,154 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Profiler_Timer + * @brief Helper class providing profiler timers. + */ +class TeamSpeak3_Helper_Profiler_Timer +{ + /** + * Indicates wether the timer is running or not. + * + * @var boolean + */ + protected $running = FALSE; + + /** + * Stores the timestamp when the timer was last started. + * + * @var integer + */ + protected $started = 0; + + /** + * Stores the timer name. + * + * @var string + */ + protected $name = null; + + /** + * Stores various information about the server environment. + * + * @var array + */ + protected $data = array(); + + /** + * The TeamSpeak3_Helper_Profiler_Timer constructor. + * + * @param string $name + * @return TeamSpeak3_Helper_Profiler_Timer + */ + public function __construct($name) + { + $this->name = (string) $name; + + $this->data["runtime"] = 0; + $this->data["realmem"] = 0; + $this->data["emalloc"] = 0; + + $this->start(); + } + + /** + * Starts the timer. + * + * @return void + */ + public function start() + { + if($this->isRunning()) return; + + $this->data["realmem_start"] = memory_get_usage(TRUE); + $this->data["emalloc_start"] = memory_get_usage(); + + $this->started = microtime(TRUE); + $this->running = TRUE; + } + + /** + * Stops the timer. + * + * @return void + */ + public function stop() + { + if(!$this->isRunning()) return; + + $this->data["runtime"] += microtime(TRUE) - $this->started; + $this->data["realmem"] += memory_get_usage(TRUE) - $this->data["realmem_start"]; + $this->data["emalloc"] += memory_get_usage() - $this->data["emalloc_start"]; + + $this->started = 0; + $this->running = FALSE; + } + + /** + * Return the timer runtime. + * + * @return mixed + */ + public function getRuntime() + { + if($this->isRunning()) + { + $this->stop(); + $this->start(); + } + + return $this->data["runtime"]; + } + + /** + * Returns the amount of memory allocated to PHP in bytes. + * + * @param boolean $realmem + * @return integer + */ + public function getMemUsage($realmem = FALSE) + { + if($this->isRunning()) + { + $this->stop(); + $this->start(); + } + + return ($realmem !== FALSE) ? $this->data["realmem"] : $this->data["emalloc"]; + } + + /** + * Returns TRUE if the timer is running. + * + * @return boolean + */ + public function isRunning() + { + return $this->running; + } +} diff --git a/hidden/TeamSpeak3/Helper/Signal.php b/hidden/TeamSpeak3/Helper/Signal.php new file mode 100644 index 0000000..0ff372b --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Signal.php @@ -0,0 +1,213 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Signal + * @brief Helper class for signal slots. + */ +class TeamSpeak3_Helper_Signal +{ + /** + * Stores the TeamSpeak3_Helper_Signal object. + * + * @var TeamSpeak3_Helper_Signal + */ + protected static $instance = null; + + /** + * Stores subscribed signals and their slots. + * + * @var array + */ + protected $sigslots = array(); + + /** + * Emits a signal with a given set of parameters. + * + * @param string $signal + * @param mixed $params + * @return mixed + */ + public function emit($signal, $params = null) + { + if(!$this->hasHandlers($signal)) + { + return; + } + + if(!is_array($params)) + { + $params = func_get_args(); + $params = array_slice($params, 1); + } + + foreach($this->sigslots[$signal] as $slot) + { + $return = $slot->call($params); + } + + return $return; + } + + /** + * Generates a MD5 hash based on a given callback. + * + * @param mixed $callback + * @param string + * @return void + */ + public function getCallbackHash($callback) + { + if(!is_callable($callback, TRUE, $callable_name)) + { + throw new TeamSpeak3_Helper_Signal_Exception("invalid callback specified"); + } + + return md5($callable_name); + } + + /** + * Subscribes to a signal and returns the signal handler. + * + * @param string $signal + * @param mixed $callback + * @return TeamSpeak3_Helper_Signal_Handler + */ + public function subscribe($signal, $callback) + { + if(empty($this->sigslots[$signal])) + { + $this->sigslots[$signal] = array(); + } + + $index = $this->getCallbackHash($callback); + + if(!array_key_exists($index, $this->sigslots[$signal])) + { + $this->sigslots[$signal][$index] = new TeamSpeak3_Helper_Signal_Handler($signal, $callback); + } + + return $this->sigslots[$signal][$index]; + } + + /** + * Unsubscribes from a signal. + * + * @param string $signal + * @param mixed $callback + * @return void + */ + public function unsubscribe($signal, $callback = null) + { + if(!$this->hasHandlers($signal)) + { + return; + } + + if($callback !== null) + { + $index = $this->getCallbackHash($callback); + + if(!array_key_exists($index, $this->sigslots[$signal])) + { + return; + } + + unset($this->sigslots[$signal][$index]); + } + else + { + unset($this->sigslots[$signal]); + } + } + + /** + * Returns all registered signals. + * + * @return array + */ + public function getSignals() + { + return array_keys($this->sigslots); + } + + /** + * Returns TRUE there are slots subscribed for a specified signal. + * + * @param string $signal + * @return boolean + */ + public function hasHandlers($signal) + { + return empty($this->sigslots[$signal]) ? FALSE : TRUE; + } + + /** + * Returns all slots for a specified signal. + * + * @param string $signal + * @return array + */ + public function getHandlers($signal) + { + if(!$this->hasHandlers($signal)) + { + return $this->sigslots[$signal]; + } + + return array(); + } + + /** + * Clears all slots for a specified signal. + * + * @param string $signal + * @return void + */ + public function clearHandlers($signal) + { + if(!$this->hasHandlers($signal)) + { + unset($this->sigslots[$signal]); + } + } + + /** + * Returns a singleton instance of TeamSpeak3_Helper_Signal. + * + * @return TeamSpeak3_Helper_Signal + */ + public static function getInstance() + { + if(self::$instance === null) + { + self::$instance = new self(); + } + + return self::$instance; + } +} diff --git a/hidden/TeamSpeak3/Helper/Signal/Exception.php b/hidden/TeamSpeak3/Helper/Signal/Exception.php new file mode 100644 index 0000000..f9b49a9 --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Signal/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Signal_Exception + * @brief Enhanced exception class for TeamSpeak3_Helper_Signal objects. + */ +class TeamSpeak3_Helper_Signal_Exception extends TeamSpeak3_Helper_Exception {} diff --git a/hidden/TeamSpeak3/Helper/Signal/Handler.php b/hidden/TeamSpeak3/Helper/Signal/Handler.php new file mode 100644 index 0000000..8fd31ec --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Signal/Handler.php @@ -0,0 +1,78 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Signal_Handler + * @brief Helper class providing handler functions for signals. + */ +class TeamSpeak3_Helper_Signal_Handler +{ + /** + * Stores the name of the subscribed signal. + * + * @var string + */ + protected $signal = null; + + /** + * Stores the callback function for the subscribed signal. + * + * @var mixed + */ + protected $callback = null; + + /** + * The TeamSpeak3_Helper_Signal_Handler constructor. + * + * @param string $signal + * @param mixed $callback + * @throws TeamSpeak3_Helper_Signal_Exception + * @return TeamSpeak3_Helper_Signal_Handler + */ + public function __construct($signal, $callback) + { + $this->signal = (string) $signal; + + if(!is_callable($callback)) + { + throw new TeamSpeak3_Helper_Signal_Exception("invalid callback specified for signal '" . $signal . "'"); + } + + $this->callback = $callback; + } + + /** + * Invoke the signal handler. + * + * @param array $args + * @return mixed + */ + public function call(array $args = array()) + { + return call_user_func_array($this->callback, $args); + } +} diff --git a/hidden/TeamSpeak3/Helper/Signal/Interface.php b/hidden/TeamSpeak3/Helper/Signal/Interface.php new file mode 100644 index 0000000..11e3c88 --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Signal/Interface.php @@ -0,0 +1,353 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Signal_Interface + * @brief Interface class describing the layout for TeamSpeak3_Helper_Signal callbacks. + */ +interface TeamSpeak3_Helper_Signal_Interface +{ + /** + * Possible callback for 'Connected' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryConnected", array($object, "onConnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferConnected", array($object, "onConnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistConnected", array($object, "onConnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateConnected", array($object, "onConnect")); + * + * @param TeamSpeak3_Adapter_Abstract $adapter + * @return void + */ + public function onConnect(TeamSpeak3_Adapter_Abstract $adapter); + + /** + * Possible callback for 'Disconnected' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryDisconnected", array($object, "onDisconnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDisconnected", array($object, "onDisconnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistDisconnected", array($object, "onDisconnect")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateDisconnected", array($object, "onDisconnect")); + * + * @return void + */ + public function onDisconnect(); + + /** + * Possible callback for 'serverqueryCommandStarted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryCommandStarted", array($object, "onCommandStarted")); + * + * @param string $cmd + * @return void + */ + public function onCommandStarted($cmd); + + /** + * Possible callback for 'serverqueryCommandFinished' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryCommandFinished", array($object, "onCommandFinished")); + * + * @param string $cmd + * @param TeamSpeak3_Adapter_ServerQuery_Reply $reply + * @return void + */ + public function onCommandFinished($cmd, TeamSpeak3_Adapter_ServerQuery_Reply $reply); + + /** + * Possible callback for 'notifyEvent' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyEvent", array($object, "onEvent")); + * + * @param TeamSpeak3_Adapter_ServerQuery_Event $event + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onEvent(TeamSpeak3_Adapter_ServerQuery_Event $event, TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyError' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyError", array($object, "onError")); + * + * @param TeamSpeak3_Adapter_ServerQuery_Reply $reply + * @return void + */ + public function onError(TeamSpeak3_Adapter_ServerQuery_Reply $reply); + + /** + * Possible callback for 'notifyServerselected' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServerselected", array($object, "onServerselected")); + * + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onServerselected(TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyServercreated' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServercreated", array($object, "onServercreated")); + * + * @param TeamSpeak3_Node_Host $host + * @param integer $sid + * @return void + */ + public function onServercreated(TeamSpeak3_Node_Host $host, $sid); + + /** + * Possible callback for 'notifyServerdeleted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServerdeleted", array($object, "onServerdeleted")); + * + * @param TeamSpeak3_Node_Host $host + * @param integer $sid + * @return void + */ + public function onServerdeleted(TeamSpeak3_Node_Host $host, $sid); + + /** + * Possible callback for 'notifyServerstarted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServerstarted", array($object, "onServerstarted")); + * + * @param TeamSpeak3_Node_Host $host + * @param integer $sid + * @return void + */ + public function onServerstarted(TeamSpeak3_Node_Host $host, $sid); + + /** + * Possible callback for 'notifyServerstopped' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServerstopped", array($object, "onServerstopped")); + * + * @param TeamSpeak3_Node_Host $host + * @param integer $sid + * @return void + */ + public function onServerstopped(TeamSpeak3_Node_Host $host, $sid); + + /** + * Possible callback for 'notifyServershutdown' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyServershutdown", array($object, "onServershutdown")); + * + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onServershutdown(TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyLogin' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyLogin", array($object, "onLogin")); + * + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onLogin(TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyLogout' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyLogout", array($object, "onLogout")); + * + * @param TeamSpeak3_Node_Host $host + * @return void + */ + public function onLogout(TeamSpeak3_Node_Host $host); + + /** + * Possible callback for 'notifyTokencreated' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyTokencreated", array($object, "onTokencreated")); + * + * @param TeamSpeak3_Node_Server $server + * @param string $token + * @return void + */ + public function onTokencreated(TeamSpeak3_Node_Server $server, $token); + + /** + * Possible callback for 'filetransferHandshake' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferHandshake", array($object, "onFtHandshake")); + * + * @param TeamSpeak3_Adapter_FileTransfer $adapter + * @return void + */ + public function onFtHandshake(TeamSpeak3_Adapter_FileTransfer $adapter); + + /** + * Possible callback for 'filetransferUploadStarted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferUploadStarted", array($object, "onFtUploadStarted")); + * + * @param string $ftkey + * @param integer $seek + * @param integer $size + * @return void + */ + public function onFtUploadStarted($ftkey, $seek, $size); + + /** + * Possible callback for 'filetransferUploadProgress' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferUploadProgress", array($object, "onFtUploadProgress")); + * + * @param string $ftkey + * @param integer $seek + * @param integer $size + * @return void + */ + public function onFtUploadProgress($ftkey, $seek, $size); + + /** + * Possible callback for 'filetransferUploadFinished' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferUploadFinished", array($object, "onFtUploadFinished")); + * + * @param string $ftkey + * @param integer $seek + * @param integer $size + * @return void + */ + public function onFtUploadFinished($ftkey, $seek, $size); + + /** + * Possible callback for 'filetransferDownloadStarted' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDownloadStarted", array($object, "onFtDownloadStarted")); + * + * @param string $ftkey + * @param integer $buff + * @param integer $size + * @return void + */ + public function onFtDownloadStarted($ftkey, $buff, $size); + + /** + * Possible callback for 'filetransferDownloadProgress' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDownloadProgress", array($object, "onFtDownloadProgress")); + * + * @param string $ftkey + * @param integer $buff + * @param integer $size + * @return void + */ + public function onFtDownloadProgress($ftkey, $buff, $size); + + /** + * Possible callback for 'filetransferDownloadFinished' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDownloadFinished", array($object, "onFtDownloadFinished")); + * + * @param string $ftkey + * @param integer $buff + * @param integer $size + * @return void + */ + public function onFtDownloadFinished($ftkey, $buff, $size); + + /** + * Possible callback for 'DataRead' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryDataRead", array($object, "onDebugDataRead")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDataRead", array($object, "onDebugDataRead")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistDataRead", array($object, "onDebugDataRead")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateDataRead", array($object, "onDebugDataRead")); + * + * @param string $data + * @return void + */ + public function onDebugDataRead($data); + + /** + * Possible callback for 'DataSend' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryDataSend", array($object, "onDebugDataSend")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferDataSend", array($object, "onDebugDataSend")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistDataSend", array($object, "onDebugDataSend")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateDataSend", array($object, "onDebugDataSend")); + * + * @param string $data + * @return void + */ + public function onDebugDataSend($data); + + /** + * Possible callback for 'WaitTimeout' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("serverqueryWaitTimeout", array($object, "onWaitTimeout")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("filetransferWaitTimeout", array($object, "onWaitTimeout")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("blacklistWaitTimeout", array($object, "onWaitTimeout")); + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("updateWaitTimeout", array($object, "onWaitTimeout")); + * + * @param integer $time + * @param TeamSpeak3_Adapter_Abstract $adapter + * @return void + */ + public function onWaitTimeout($time, TeamSpeak3_Adapter_Abstract $adapter); + + /** + * Possible callback for 'errorException' signals. + * + * === Examples === + * - TeamSpeak3_Helper_Signal::getInstance()->subscribe("errorException", array($object, "onException")); + * + * @param TeamSpeak3_Exception $e + * @return void + */ + public function onException(TeamSpeak3_Exception $e); +} diff --git a/hidden/TeamSpeak3/Helper/String.php b/hidden/TeamSpeak3/Helper/String.php new file mode 100644 index 0000000..2164b4d --- /dev/null +++ b/hidden/TeamSpeak3/Helper/String.php @@ -0,0 +1,939 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_String + * @brief Helper class for string handling. + */ +class TeamSpeak3_Helper_String implements ArrayAccess, Iterator, Countable +{ + /** + * Stores the original string. + * + * @var string + */ + protected $string; + + /** + * @ignore + */ + protected $position = 0; + + /** + * The TeamSpeak3_Helper_String constructor. + * + * @param string $string + * @return TeamSpeak3_Helper_String + */ + public function __construct($string) + { + $this->string = strval($string); + } + + /** + * Returns a TeamSpeak3_Helper_String object for thegiven string. + * + * @param string $string + * @return TeamSpeak3_Helper_String + */ + public static function factory($string) + { + return new self($string); + } + + /** + * Replaces every occurrence of the string $search with the string $replace. + * + * @param string $search + * @param string $replace + * @param boolean $caseSensitivity + * @return TeamSpeak3_Helper_String + */ + public function replace($search, $replace, $caseSensitivity = TRUE) + { + if($caseSensitivity) + { + $this->string = str_replace($search, $replace, $this->string); + } + else + { + $this->string = str_ireplace($search, $replace, $this->string); + } + + return $this; + } + + /** + * This function replaces indexed or associative signs with given values. + * + * @param array $args + * @param string $char + * @return TeamSpeak3_Helper_String + */ + public function arg(array $args, $char = "%") + { + $args = array_reverse($args, TRUE); + + foreach($args as $key => $val) + { + $args[$char . $key] = $val; + unset($args[$key]); + } + + $this->string = strtr($this->string, $args); + + return $this; + } + + /** + * Returns true if the string starts with $pattern. + * + * @param string $pattern + * @return boolean + */ + public function startsWith($pattern) + { + return (substr($this->string, 0, strlen($pattern)) == $pattern) ? TRUE : FALSE; + } + + /** + * Returns true if the string ends with $pattern. + * + * @param string $pattern + * @return boolean + */ + public function endsWith($pattern) + { + return (substr($this->string, strlen($pattern)*-1) == $pattern) ? TRUE : FALSE; + } + + /** + * Returns the position of the first occurrence of a char in a string. + * + * @param string $needle + * @return integer + */ + public function findFirst($needle) + { + return strpos($this->string, $needle); + } + + /** + * Returns the position of the last occurrence of a char in a string. + * + * @param string $needle + * @return integer + */ + public function findLast($needle) + { + return strrpos($this->string, $needle); + } + + /** + * Returns the lowercased string. + * + * @return TeamSpeak3_Helper_String + */ + public function toLower() + { + return new self(strtolower($this->string)); + } + + /** + * Returns the uppercased string. + * + * @return TeamSpeak3_Helper_String + */ + public function toUpper() + { + return new self(strtoupper($this->string)); + } + + /** + * Returns true if the string contains $pattern. + * + * @param string $pattern + * @param booean $regexp + * @return boolean + */ + public function contains($pattern, $regexp = FALSE) + { + if(empty($pattern)) + { + return TRUE; + } + + if($regexp) + { + return (preg_match("/" . $pattern . "/i", $this->string)) ? TRUE : FALSE; + } + else + { + return (stristr($this->string, $pattern) !== FALSE) ? TRUE : FALSE; + } + } + + /** + * Returns part of a string. + * + * @param integer $start + * @param integer $length + * @return TeamSpeak3_Helper_String + */ + public function substr($start, $length = null) + { + $string = ($length !== null) ? substr($this->string, $start, $length) : substr($this->string, $start); + + return new self($string); + } + + /** + * Splits the string into substrings wherever $separator occurs. + * + * @param string $separator + * @param integer $limit + * @return array + */ + public function split($separator, $limit = 0) + { + $parts = explode($separator, $this->string, ($limit) ? intval($limit) : $this->count()); + + foreach($parts as $key => $val) + { + $parts[$key] = new self($val); + } + + return $parts; + } + + /** + * Appends $part to the string. + * + * @param string $part + * @return TeamSpeak3_Helper_String + */ + public function append($part) + { + $this->string = $this->string . strval($part); + + return $this; + } + + /** + * Prepends $part to the string. + * + * @param string $part + * @return TeamSpeak3_Helper_String + */ + public function prepend($part) + { + $this->string = strval($part) . $this->string; + + return $this; + } + + /** + * Returns a section of the string. + * + * @param string $separator + * @param integer $first + * @param integer $last + * @return TeamSpeak3_Helper_String + */ + public function section($separator, $first = 0, $last = 0) + { + $sections = explode($separator, $this->string); + + $total = count($sections); + $first = intval($first); + $last = intval($last); + + if($first > $total) return null; + if($first > $last) $last = $first; + + for($i = 0; $i < $total; $i++) + { + if($i < $first || $i > $last) + { + unset($sections[$i]); + } + } + + $string = implode($separator, $sections); + + return new self($string); + } + + /** + * Sets the size of the string to $size characters. + * + * @param integer $size + * @param string $char + * @return TeamSpeak3_Helper_String + */ + public function resize($size, $char = "\0") + { + $chars = ($size - $this->count()); + + if($chars < 0) + { + $this->string = substr($this->string, 0, $chars); + } + elseif($chars > 0) + { + $this->string = str_pad($this->string, $size, strval($char)); + } + + return $this; + } + + /** + * Strips whitespaces (or other characters) from the beginning and end of the string. + * + * @return TeamSpeak3_Helper_String + */ + public function trim() + { + $this->string = trim($this->string); + + return $this; + } + + /** + * Escapes a string using the TeamSpeak 3 escape patterns. + * + * @return TeamSpeak3_Helper_String + */ + public function escape() + { + foreach(TeamSpeak3::getEscapePatterns() as $search => $replace) + { + $this->string = str_replace($search, $replace, $this->string); + } + + return $this; + } + + /** + * Unescapes a string using the TeamSpeak 3 escape patterns. + * + * @return TeamSpeak3_Helper_String + */ + public function unescape() + { + $this->string = strtr($this->string, array_flip(TeamSpeak3::getEscapePatterns())); + + return $this; + } + + /** + * Removes any non alphanumeric characters from the string. + * + * @return TeamSpeak3_Helper_String + */ + public function filterAlnum() + { + $this->string = preg_replace("/[^[:alnum:]]/", "", $this->string); + + return $this; + } + + /** + * Removes any non alphabetic characters from the string. + * + * @return TeamSpeak3_Helper_String + */ + public function filterAlpha() + { + $this->string = preg_replace("/[^[:alpha:]]/", "", $this->string); + + return $this; + } + + /** + * Removes any non numeric characters from the string. + * + * @return TeamSpeak3_Helper_String + */ + public function filterDigits() + { + $this->string = preg_replace("/[^[:digit:]]/", "", $this->string); + + return $this; + } + + /** + * Returns TRUE if the string is a numeric value. + * + * @return boolean + */ + public function isInt() + { + return (is_numeric($this->string) && !$this->contains(".")) ? TRUE : FALSE; + } + + /** + * Returns the integer value of the string. + * + * @return float + * @return integer + */ + public function toInt() + { + if($this->string == pow(2, 63) || $this->string == pow(2, 64)) + { + return -1; + } + + return ($this->string > pow(2, 31)) ? floatval($this->string) : intval($this->string); + } + + /** + * Calculates and returns the crc32 polynomial of the string. + * + * @return string + */ + public function toCrc32() + { + return crc32($this->string); + } + + /** + * Calculates and returns the md5 checksum of the string. + * + * @return string + */ + public function toMd5() + { + return md5($this->string); + } + + /** + * Calculates and returns the sha1 checksum of the string. + * + * @return string + */ + public function toSha1() + { + return sha1($this->string); + } + + /** + * Returns TRUE if the string is UTF-8 encoded. This method searches for non-ascii multibyte + * sequences in the UTF-8 range. + * + * @return boolean + */ + public function isUtf8() + { + $pattern = array(); + + $pattern[] = "[\xC2-\xDF][\x80-\xBF]"; // non-overlong 2-byte + $pattern[] = "\xE0[\xA0-\xBF][\x80-\xBF]"; // excluding overlongs + $pattern[] = "[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}"; // straight 3-byte + $pattern[] = "\xED[\x80-\x9F][\x80-\xBF]"; // excluding surrogates + $pattern[] = "\xF0[\x90-\xBF][\x80-\xBF]{2}"; // planes 1-3 + $pattern[] = "[\xF1-\xF3][\x80-\xBF]{3}"; // planes 4-15 + $pattern[] = "\xF4[\x80-\x8F][\x80-\xBF]{2}"; // plane 16 + + return preg_match("%(?:" . implode("|", $pattern) . ")+%xs", $this->string); + } + + /** + * Converts the string to UTF-8. + * + * @return TeamSpeak3_Helper_String + */ + public function toUtf8() + { + if(!$this->isUtf8()) + { + $this->string = utf8_encode($this->string); + } + + return $this; + } + + /** + * Encodes the string with MIME base64 and returns the result. + * + * @return string + */ + public function toBase64() + { + return base64_encode($this->string); + } + + /** + * Decodes the string with MIME base64 and returns the result as an TeamSpeak3_Helper_String + * + * @param string + * @return TeamSpeak3_Helper_String + */ + public static function fromBase64($base64) + { + return new self(base64_decode($base64)); + } + + /** + * Returns the hexadecimal value of the string. + * + * @return string + */ + public function toHex() + { + $hex = ""; + + foreach($this as $char) + { + $hex .= $char->toHex(); + } + + return $hex; + } + + /** + * Returns the TeamSpeak3_Helper_String based on a given hex value. + * + * @param string + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_String + */ + public static function fromHex($hex) + { + $string = ""; + + if(strlen($hex)%2 == 1) + { + throw new TeamSpeak3_Helper_Exception("given parameter '" . $hex . "' is not a valid hexadecimal number"); + } + + foreach(str_split($hex, 2) as $chunk) + { + $string .= chr(hexdec($chunk)); + } + + return new self($string); + } + + /** + * Returns the string transliterated from UTF-8 to Latin. + * + * @return TeamSpeak3_Helper_String + */ + public function transliterate() + { + $utf8_accents = array( + "à" => "a", + "ô" => "o", + "Ä?" => "d", + "ḟ" => "f", + "ë" => "e", + "Å¡" => "s", + "Æ¡" => "o", + "ß" => "ss", + "ă" => "a", + "Å™" => "r", + "È›" => "t", + "ň" => "n", + "Ä?" => "a", + "Ä·" => "k", + "Å?" => "s", + "ỳ" => "y", + "ņ" => "n", + "ĺ" => "l", + "ħ" => "h", + "á¹—" => "p", + "ó" => "o", + "ú" => "u", + "Ä›" => "e", + "é" => "e", + "ç" => "c", + "áº?" => "w", + "Ä‹" => "c", + "õ" => "o", + "ṡ" => "s", + "ø" => "o", + "Ä£" => "g", + "ŧ" => "t", + "È™" => "s", + "Ä—" => "e", + "ĉ" => "c", + "Å›" => "s", + "î" => "i", + "ű" => "u", + "ć" => "c", + "Ä™" => "e", + "ŵ" => "w", + "ṫ" => "t", + "Å«" => "u", + "Ä?" => "c", + "ö" => "oe", + "è" => "e", + "Å·" => "y", + "Ä…" => "a", + "Å‚" => "l", + "ų" => "u", + "ů" => "u", + "ÅŸ" => "s", + "ÄŸ" => "g", + "ļ" => "l", + "Æ’" => "f", + "ž" => "z", + "ẃ" => "w", + "ḃ" => "b", + "Ã¥" => "a", + "ì" => "i", + "ï" => "i", + "ḋ" => "d", + "Å¥" => "t", + "Å—" => "r", + "ä" => "ae", + "í" => "i", + "Å•" => "r", + "ê" => "e", + "ü" => "ue", + "ò" => "o", + "Ä“" => "e", + "ñ" => "n", + "Å„" => "n", + "Ä¥" => "h", + "Ä?" => "g", + "Ä‘" => "d", + "ĵ" => "j", + "ÿ" => "y", + "Å©" => "u", + "Å­" => "u", + "Æ°" => "u", + "Å£" => "t", + "ý" => "y", + "Å‘" => "o", + "â" => "a", + "ľ" => "l", + "ẅ" => "w", + "ż" => "z", + "Ä«" => "i", + "ã" => "a", + "Ä¡" => "g", + "á¹?" => "m", + "Å?" => "o", + "Ä©" => "i", + "ù" => "u", + "į" => "i", + "ź" => "z", + "á" => "a", + "û" => "u", + "þ" => "th", + "ð" => "dh", + "æ" => "ae", + "µ" => "u", + "Ä•" => "e", + "Å“" => "oe", + "À" => "A", + "Ô" => "O", + "ÄŽ" => "D", + "Ḟ" => "F", + "Ë" => "E", + "Å " => "S", + "Æ " => "O", + "Ä‚" => "A", + "Ř" => "R", + "Èš" => "T", + "Ň" => "N", + "Ä€" => "A", + "Ķ" => "K", + "Åœ" => "S", + "Ỳ" => "Y", + "Å…" => "N", + "Ĺ" => "L", + "Ħ" => "H", + "á¹–" => "P", + "Ó" => "O", + "Ú" => "U", + "Äš" => "E", + "É" => "E", + "Ç" => "C", + "Ẁ" => "W", + "ÄŠ" => "C", + "Õ" => "O", + "á¹ " => "S", + "Ø" => "O", + "Ä¢" => "G", + "Ŧ" => "T", + "Ș" => "S", + "Ä–" => "E", + "Ĉ" => "C", + "Åš" => "S", + "ÃŽ" => "I", + "Å°" => "U", + "Ć" => "C", + "Ę" => "E", + "Å´" => "W", + "Ṫ" => "T", + "Ū" => "U", + "ÄŒ" => "C", + "Ö" => "Oe", + "È" => "E", + "Ŷ" => "Y", + "Ä„" => "A", + "Å?" => "L", + "Ų" => "U", + "Å®" => "U", + "Åž" => "S", + "Äž" => "G", + "Ä»" => "L", + "Æ‘" => "F", + "Ž" => "Z", + "Ẃ" => "W", + "Ḃ" => "B", + "Ã…" => "A", + "ÃŒ" => "I", + "Ã?" => "I", + "Ḋ" => "D", + "Ť" => "T", + "Å–" => "R", + "Ä" => "Ae", + "Ã?" => "I", + "Å”" => "R", + "Ê" => "E", + "Ãœ" => "Ue", + "Ã’" => "O", + "Ä’" => "E", + "Ñ" => "N", + "Ń" => "N", + "Ĥ" => "H", + "Äœ" => "G", + "Ä?" => "D", + "Ä´" => "J", + "Ÿ" => "Y", + "Ũ" => "U", + "Ŭ" => "U", + "Ư" => "U", + "Å¢" => "T", + "Ã?" => "Y", + "Å?" => "O", + "Â" => "A", + "Ľ" => "L", + "Ẅ" => "W", + "Å»" => "Z", + "Ī" => "I", + "Ã" => "A", + "Ä " => "G", + "á¹€" => "M", + "ÅŒ" => "O", + "Ĩ" => "I", + "Ù" => "U", + "Ä®" => "I", + "Ź" => "Z", + "Ã?" => "A", + "Û" => "U", + "Þ" => "Th", + "Ã?" => "Dh", + "Æ" => "Ae", + "Ä”" => "E", + "Å’" => "Oe", + ); + + return new self($this->toUtf8()->replace(array_keys($utf8_accents), array_values($utf8_accents))); + } + + /** + * Processes the string and replaces all accented UTF-8 characters by unaccented ASCII-7 "equivalents", + * whitespaces are replaced by a pre-defined spacer and the string is lowercase. + * + * @param string $spacer + * @return TeamSpeak3_Helper_String + */ + public function uriSafe($spacer = "-") + { + $this->string = str_replace($spacer, " ", $this->string); + $this->string = $this->transliterate(); + $this->string = preg_replace("/(\s|[^A-Za-z0-9\-])+/", $spacer, trim(strtolower($this->string))); + $this->string = trim($this->string, $spacer); + + return new self($this->string); + } + + /** + * Replaces space characters with percent encoded strings. + * + * @return string + */ + public function spaceToPercent() + { + return str_replace(" ", "%20", $this->string); + } + + /** + * Returns the string as a standard string + * + * @return string + */ + public function toString() + { + return $this->string; + } + + /** + * Magical function that allows you to call PHP's built-in string functions on the TeamSpeak3_Helper_String object. + * + * @param string $function + * @param array $args + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_String + */ + public function __call($function, $args) + { + if(!function_exists($function)) + { + throw new TeamSpeak3_Helper_Exception("cannot call undefined function '" . $function . "' on this object"); + } + + if(count($args)) + { + if(($key = array_search($this, $args, TRUE)) !== FALSE) + { + $args[$key] = $this->string; + } + else + { + throw new TeamSpeak3_Helper_Exception("cannot call undefined function '" . $function . "' without the " . __CLASS__ . " object parameter"); + } + + $return = call_user_func_array($function, $args); + } + else + { + $return = call_user_func($function, $this->string); + } + + if(is_string($return)) + { + $this->string = $return; + } + else + { + return $return; + } + + return $this; + } + + /** + * Returns the character as a standard string. + * + * @return string + */ + public function __toString() + { + return (string) $this->string; + } + + /** + * @ignore + */ + public function count() + { + return strlen($this->string); + } + + /** + * @ignore + */ + public function rewind() + { + $this->position = 0; + } + + /** + * @ignore + */ + public function valid() + { + return $this->position < $this->count(); + } + + /** + * @ignore + */ + public function key() + { + return $this->position; + } + + /** + * @ignore + */ + public function current() + { + return new TeamSpeak3_Helper_Char($this->string{$this->position}); + } + + /** + * @ignore + */ + public function next() + { + $this->position++; + } + + /** + * @ignore + */ + public function offsetExists($offset) + { + return ($offset < strlen($this->string)) ? TRUE : FALSE; + } + + /** + * @ignore + */ + public function offsetGet($offset) + { + return ($this->offsetExists($offset)) ? new TeamSpeak3_Helper_Char($this->string{$offset}) : null; + } + + /** + * @ignore + */ + public function offsetSet($offset, $value) + { + if(!$this->offsetExists($offset)) return; + + $this->string{$offset} = strval($value); + } + + /** + * @ignore + */ + public function offsetUnset($offset) + { + if(!$this->offsetExists($offset)) return; + + $this->string = substr_replace($this->string, "", $offset, 1); + } +} diff --git a/hidden/TeamSpeak3/Helper/Uri.php b/hidden/TeamSpeak3/Helper/Uri.php new file mode 100644 index 0000000..9abee01 --- /dev/null +++ b/hidden/TeamSpeak3/Helper/Uri.php @@ -0,0 +1,717 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Helper_Uri + * @brief Helper class for URI handling. + */ +class TeamSpeak3_Helper_Uri +{ + /** + * Stores the URI scheme. + * + * @var string + */ + protected $scheme = null; + + /** + * Stores the URI username + * + * @var string + */ + protected $user = null; + + /** + * Stores the URI password. + * + * @var string + */ + protected $pass = null; + + /** + * Stores the URI host. + * + * @var string + */ + protected $host = null; + + /** + * Stores the URI port. + * + * @var string + */ + protected $port = null; + + /** + * Stores the URI path. + * + * @var string + */ + protected $path = null; + + /** + * Stores the URI query string. + * + * @var string + */ + protected $query = null; + + /** + * Stores the URI fragment string. + * + * @var string + */ + protected $fragment = null; + + /** + * Stores grammar rules for validation via regex. + * + * @var array + */ + protected $regex = array(); + + /** + * The TeamSpeak3_Helper_Uri constructor. + * + * @param string $uri + * @throws TeamSpeak3_Helper_Exception + * @return TeamSpeak3_Helper_Uri + */ + public function __construct($uri) + { + $uri = explode(":", strval($uri), 2); + + $this->scheme = strtolower($uri[0]); + $uriString = isset($uri[1]) ? $uri[1] : ""; + + if(!ctype_alnum($this->scheme)) + { + throw new TeamSpeak3_Helper_Exception("invalid URI scheme '" . $this->scheme . "' supplied"); + } + + /* grammar rules for validation */ + $this->regex["alphanum"] = "[^\W_]"; + $this->regex["escaped"] = "(?:%[\da-fA-F]{2})"; + $this->regex["mark"] = "[-_.!~*'()\[\]]"; + $this->regex["reserved"] = "[;\/?:@&=+$,]"; + $this->regex["unreserved"] = "(?:" . $this->regex["alphanum"] . "|" . $this->regex["mark"] . ")"; + $this->regex["segment"] = "(?:(?:" . $this->regex["unreserved"] . "|" . $this->regex["escaped"] . "|[:@&=+$,;])*)"; + $this->regex["path"] = "(?:\/" . $this->regex["segment"] . "?)+"; + $this->regex["uric"] = "(?:" . $this->regex["reserved"] . "|" . $this->regex["unreserved"] . "|" . $this->regex["escaped"] . ")"; + + if(strlen($uriString) > 0) + { + $this->parseUri($uriString); + } + + if(!$this->isValid()) + { + throw new TeamSpeak3_Helper_Exception("invalid URI supplied"); + } + } + + /** + * Parses the scheme-specific portion of the URI and place its parts into instance variables. + * + * @throws TeamSpeak3_Helper_Exception + * @return void + */ + protected function parseUri($uriString = '') + { + $status = @preg_match("~^((//)([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?$~", $uriString, $matches); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI scheme-specific decomposition failed"); + } + + if(!$status) return; + + $this->path = (isset($matches[4])) ? $matches[4] : ''; + $this->query = (isset($matches[6])) ? $matches[6] : ''; + $this->fragment = (isset($matches[8])) ? $matches[8] : ''; + + $status = @preg_match("~^(([^:@]*)(:([^@]*))?@)?([^:]+)(:(.*))?$~", (isset($matches[3])) ? $matches[3] : "", $matches); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI scheme-specific authority decomposition failed"); + } + + if(!$status) return; + + $this->user = isset($matches[2]) ? $matches[2] : ""; + $this->pass = isset($matches[4]) ? $matches[4] : ""; + $this->host = isset($matches[5]) ? $matches[5] : ""; + $this->port = isset($matches[7]) ? $matches[7] : ""; + } + + /** + * Validate the current URI from the instance variables. + * + * @return boolean + */ + public function isValid() + { + return ($this->checkUser() && $this->checkPass() && $this->checkHost() && $this->checkPort() && $this->checkPath() && $this->checkQuery() && $this->checkFragment()); + } + + /** + * Returns TRUE if a given URI is valid. + * + * @param string $uri + * @return boolean + */ + public static function check($uri) + { + try + { + $uri = new self(strval($uri)); + } + catch(Exception $e) + { + return FALSE; + } + + return $uri->valid(); + } + + /** + * Returns TRUE if the URI has a scheme. + * + * @return boolean + */ + public function hasScheme() + { + return strlen($this->scheme) ? TRUE : FALSE; + } + + /** + * Returns the scheme. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getScheme($default = null) + { + return ($this->hasScheme()) ? new TeamSpeak3_Helper_String($this->scheme) : $default; + } + + /** + * Returns TRUE if the username is valid. + * + * @param string $username + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkUser($username = null) + { + if($username === null) + { + $username = $this->user; + } + + if(strlen($username) == 0) + { + return TRUE; + } + + $pattern = "/^(" . $this->regex["alphanum"] . "|" . $this->regex["mark"] . "|" . $this->regex["escaped"] . "|[;:&=+$,])+$/"; + $status = @preg_match($pattern, $username); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI username validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a username. + * + * @return boolean + */ + public function hasUser() + { + return strlen($this->user) ? TRUE : FALSE; + } + + /** + * Returns the username. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getUser($default = null) + { + return ($this->hasUser()) ? new TeamSpeak3_Helper_String($this->user) : $default; + } + + /** + * Returns TRUE if the password is valid. + * + * @param string $password + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkPass($password = null) + { + if($password === null) { + $password = $this->pass; + } + + if(strlen($password) == 0) + { + return TRUE; + } + + $pattern = "/^(" . $this->regex["alphanum"] . "|" . $this->regex["mark"] . "|" . $this->regex["escaped"] . "|[;:&=+$,])+$/"; + $status = @preg_match($pattern, $password); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI password validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a password. + * + * @return boolean + */ + public function hasPass() + { + return strlen($this->pass) ? TRUE : FALSE; + } + + /** + * Returns the password. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getPass($default = null) + { + return ($this->hasPass()) ? new TeamSpeak3_Helper_String($this->pass) : $default; + } + + /** + * Returns TRUE if the host is valid. + * + * @param string $host + * @return boolean + */ + public function checkHost($host = null) + { + if($host === null) + { + $host = $this->host; + } + + return TRUE; + } + + /** + * Returns TRUE if the URI has a host. + * + * @return boolean + */ + public function hasHost() + { + return strlen($this->host) ? TRUE : FALSE; + } + + /** + * Returns the host. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getHost($default = null) + { + return ($this->hasHost()) ? new TeamSpeak3_Helper_String($this->host) : $default; + } + + /** + * Returns TRUE if the port is valid. + * + * @param integer $port + * @return boolean + */ + public function checkPort($port = null) + { + if($port === null) + { + $port = $this->port; + } + + return TRUE; + } + + /** + * Returns TRUE if the URI has a port. + * + * @return boolean + */ + public function hasPort() + { + return strlen($this->port) ? TRUE : FALSE; + } + + /** + * Returns the port. + * + * @param mixed default + * @return integer + */ + public function getPort($default = null) + { + return ($this->hasPort()) ? intval($this->port) : $default; + } + + /** + * Returns TRUE if the path is valid. + * + * @param string $path + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkPath($path = null) + { + if($path === null) + { + $path = $this->path; + } + + if(strlen($path) == 0) + { + return TRUE; + } + + $pattern = "/^" . $this->regex["path"] . "$/"; + $status = @preg_match($pattern, $path); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI path validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a path. + * + * @return boolean + */ + public function hasPath() + { + return strlen($this->path) ? TRUE : FALSE; + } + + /** + * Returns the path. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getPath($default = null) + { + return ($this->hasPath()) ? new TeamSpeak3_Helper_String($this->path) : $default; + } + + /** + * Returns TRUE if the query string is valid. + * + * @param string $query + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkQuery($query = null) + { + if($query === null) + { + $query = $this->query; + } + + if(strlen($query) == 0) + { + return TRUE; + } + + $pattern = "/^" . $this->regex["uric"] . "*$/"; + $status = @preg_match($pattern, $query); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI query string validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a query string. + * + * @return boolean + */ + public function hasQuery() + { + return strlen($this->query) ? TRUE : FALSE; + } + + /** + * Returns an array containing the query string elements. + * + * @param mixed $default + * @return array + */ + public function getQuery($default = array()) + { + if(!$this->hasQuery()) + { + return $default; + } + + parse_str($this->query, $queryArray); + + return $queryArray; + } + + /** + * Returns TRUE if the URI has a query variable. + * + * @return boolean + */ + public function hasQueryVar($key) + { + if(!$this->hasQuery()) return FALSE; + + parse_str($this->query, $queryArray); + + return array_key_exists($key, $queryArray) ? TRUE : FALSE; + } + + /** + * Returns a single variable from the query string. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public function getQueryVar($key, $default = null) + { + if(!$this->hasQuery()) return $default; + + parse_str($this->query, $queryArray); + + if(array_key_exists($key, $queryArray)) + { + $val = $queryArray[$key]; + + if(ctype_digit($val)) + { + return intval($val); + } + elseif(is_string($val)) + { + return new TeamSpeak3_Helper_String($val); + } + else + { + return $val; + } + } + + return $default; + } + + /** + * Returns TRUE if the fragment string is valid. + * + * @param string $fragment + * @throws TeamSpeak3_Helper_Exception + * @return boolean + */ + public function checkFragment($fragment = null) + { + if($fragment === null) + { + $fragment = $this->fragment; + } + + if(strlen($fragment) == 0) + { + return TRUE; + } + + $pattern = "/^" . $this->regex["uric"] . "*$/"; + $status = @preg_match($pattern, $fragment); + + if($status === FALSE) + { + throw new TeamSpeak3_Helper_Exception("URI fragment validation failed"); + } + + return ($status == 1); + } + + /** + * Returns TRUE if the URI has a fragment string. + * + * @return boolean + */ + public function hasFragment() + { + return strlen($this->fragment) ? TRUE : FALSE; + } + + /** + * Returns the fragment. + * + * @param mixed default + * @return TeamSpeak3_Helper_String + */ + public function getFragment($default = null) + { + return ($this->hasFragment()) ? new TeamSpeak3_Helper_String($this->fragment) : $default; + } + + /** + * Returns a specified instance parameter from the $_REQUEST array. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function getUserParam($key, $default = null) + { + return (array_key_exists($key, $_REQUEST) && !empty($_REQUEST[$key])) ? self::stripslashesRecursive($_REQUEST[$key]) : $default; + } + + /** + * Returns a specified environment parameter from the $_SERVER array. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function getHostParam($key, $default = null) + { + return (array_key_exists($key, $_SERVER) && !empty($_SERVER[$key])) ? $_SERVER[$key] : $default; + } + + /** + * Returns a specified session parameter from the $_SESSION array. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + public static function getSessParam($key, $default = null) + { + return (array_key_exists($key, $_SESSION) && !empty($_SESSION[$key])) ? $_SESSION[$key] : $default; + } + + /** + * Returns an array containing the three main parts of a FQDN (Fully Qualified Domain Name), including the + * top-level domain, the second-level domains or hostname and the third-level domain. + * + * @param string $hostname + * @return array + */ + public static function getFQDNParts($hostname) + { + if(!preg_match("/^([a-z0-9][a-z0-9-]{0,62}\.)*([a-z0-9][a-z0-9-]{0,62}\.)+([a-z]{2,6})$/i", $hostname, $matches)) + { + return array(); + } + + $parts["tld"] = $matches[3]; + $parts["2nd"] = $matches[2]; + $parts["3rd"] = $matches[1]; + + return $parts; + } + + /** + * Returns the applications host address. + * + * @return TeamSpeak3_Helper_String + */ + public static function getHostUri() + { + $sheme = (self::getHostParam("HTTPS") == "on") ? "https" : "http"; + + $serverName = new TeamSpeak3_Helper_String(self::getHostParam("HTTP_HOST")); + $serverPort = self::getHostParam("SERVER_PORT"); + $serverPort = ($serverPort != 80 && $serverPort != 443) ? ":" . $serverPort : ""; + + if($serverName->endsWith($serverPort)) + { + $serverName = $serverName->replace($serverPort, ""); + } + + return new TeamSpeak3_Helper_String($sheme . "://" . $serverName . $serverPort); + } + + /** + * Returns the applications base address. + * + * @return string + */ + public static function getBaseUri() + { + $scriptPath = new TeamSpeak3_Helper_String(dirname(self::getHostParam("SCRIPT_NAME"))); + + return self::getHostUri()->append(($scriptPath == DIRECTORY_SEPARATOR ? "" : $scriptPath) . "/"); + } + + /** + * Strips slashes from each element of an array using stripslashes(). + * + * @param mixed $var + * @return mixed + */ + protected static function stripslashesRecursive($var) + { + if(!is_array($var)) + { + return stripslashes(strval($var)); + } + + foreach($var as $key => $val) + { + $var[$key] = (is_array($val)) ? stripslashesRecursive($val) : stripslashes(strval($val)); + } + + return $var; + } +} diff --git a/hidden/TeamSpeak3/Node/Abstract.php b/hidden/TeamSpeak3/Node/Abstract.php new file mode 100644 index 0000000..b2ab372 --- /dev/null +++ b/hidden/TeamSpeak3/Node/Abstract.php @@ -0,0 +1,625 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Abstract + * @brief Abstract class describing a TeamSpeak 3 node and all it's parameters. + */ +abstract class TeamSpeak3_Node_Abstract implements RecursiveIterator, ArrayAccess, Countable +{ + /** + * @ignore + */ + protected $parent = null; + + /** + * @ignore + */ + protected $server = null; + + /** + * @ignore + */ + protected $nodeId = 0x00; + + /** + * @ignore + */ + protected $nodeList = null; + + /** + * @ignore + */ + protected $nodeInfo = array(); + + /** + * @ignore + */ + protected $storage = array(); + + /** + * Sends a prepared command to the server and returns the result. + * + * @param string $cmd + * @param boolean $throw + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function request($cmd, $throw = TRUE) + { + return $this->getParent()->request($cmd, $throw); + } + + /** + * Uses given parameters and returns a prepared ServerQuery command. + * + * @param string $cmd + * @param array $params + * @return TeamSpeak3_Helper_String + */ + public function prepare($cmd, array $params = array()) + { + return $this->getParent()->prepare($cmd, $params); + } + + /** + * Prepares and executes a ServerQuery command and returns the result. + * + * @param string $cmd + * @param array $params + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function execute($cmd, array $params = array()) + { + return $this->request($this->prepare($cmd, $params)); + } + + /** + * Returns the parent object of the current node. + * + * @return TeamSpeak3_Adapter_ServerQuery + * @return TeamSpeak3_Node_Abstract + */ + public function getParent() + { + return $this->parent; + } + + /** + * Returns the primary ID of the current node. + * + * @return integer + */ + public function getId() + { + return $this->nodeId; + } + + /** + * Returns TRUE if the node icon has a local source. + * + * @param string $key + * @return boolean + */ + public function iconIsLocal($key) + { + return ($this[$key] > 0 && $this[$key] < 1000) ? TRUE : FALSE; + } + + /** + * Returns the internal path of the node icon. + * + * @param string $key + * @return TeamSpeak3_Helper_String + */ + public function iconGetName($key) + { + $iconid = ($this[$key] < 0) ? (pow(2, 32))-($this[$key]*-1) : $this[$key]; + + return new TeamSpeak3_Helper_String("/icon_" . $iconid); + } + + /** + * Returns a possible classname for the node which can be used as a HTML property. + * + * @param string $prefix + * @return string + */ + public function getClass($prefix = "ts3_") + { + if($this instanceof TeamSpeak3_Node_Channel && $this->isSpacer()) + { + return $prefix . "spacer"; + } + elseif($this instanceof TeamSpeak3_Node_Client && $this["client_type"]) + { + return $prefix . "query"; + } + + return $prefix . TeamSpeak3_Helper_String::factory(get_class($this))->section("_", 2)->toLower(); + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + abstract public function getUniqueId(); + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + abstract public function getIcon(); + + /** + * Returns a symbol representing the node. + * + * @return string + */ + abstract public function getSymbol(); + + /** + * Returns the HTML code to display a TeamSpeak 3 viewer. + * + * @param TeamSpeak3_Viewer_Interface $viewer + * @return string + */ + public function getViewer(TeamSpeak3_Viewer_Interface $viewer) + { + $html = $viewer->fetchObject($this); + + $iterator = new RecursiveIteratorIterator($this, RecursiveIteratorIterator::SELF_FIRST); + + foreach($iterator as $node) + { + $siblings = array(); + + for($level = 0; $level < $iterator->getDepth(); $level++) + { + $siblings[] = ($iterator->getSubIterator($level)->hasNext()) ? 1 : 0; + } + + $siblings[] = (!$iterator->getSubIterator($level)->hasNext()) ? 1 : 0; + + $html .= $viewer->fetchObject($node, $siblings); + } + + return $html; + } + + /** + * Filters given node list array using specified filter rules. + * + * @param array $nodes + * @param array $rules + * @return array + */ + protected function filterList(array $nodes = array(), array $rules = array()) + { + if(!empty($rules)) + { + foreach($nodes as $node) + { + if(!$node instanceof TeamSpeak3_Node_Abstract) continue; + + $props = $node->getInfo(FALSE); + $props = array_intersect_key($props, $rules); + $match = TRUE; + + foreach($props as $key => $val) + { + if($val instanceof TeamSpeak3_Helper_String) + { + $match = $val->contains($rules[$key], TRUE); + } + else + { + $match = $val == $rules[$key]; + } + + if($match === FALSE) + { + unset($nodes[$node->getId()]); + } + } + } + } + + return $nodes; + } + + /** + * Returns all information available on this node. If $convert is enabled, some property + * values will be converted to human-readable values. + * + * @param boolean $extend + * @param boolean $convert + * @return array + */ + public function getInfo($extend = TRUE, $convert = FALSE) + { + if($extend) + { + $this->fetchNodeInfo(); + } + + if($convert) + { + $info = $this->nodeInfo; + + foreach($info as $key => $val) + { + $key = TeamSpeak3_Helper_String::factory($key); + + if($key->contains("_bytes_")) + { + $info[$key->toString()] = TeamSpeak3_Helper_Convert::bytes($val); + } + elseif($key->contains("_bandwidth_")) + { + $info[$key->toString()] = TeamSpeak3_Helper_Convert::bytes($val) . "/s"; + } + elseif($key->contains("_packets_")) + { + $info[$key->toString()] = number_format($val, null, null, "."); + } + elseif($key->contains("_packetloss_")) + { + $info[$key->toString()] = sprintf("%01.2f", floatval($val->toString())*100) . "%"; + } + elseif($key->endsWith("_uptime")) + { + $info[$key->toString()] = TeamSpeak3_Helper_Convert::seconds($val); + } + elseif($key->endsWith("_version")) + { + $info[$key->toString()] = TeamSpeak3_Helper_Convert::version($val); + } + elseif($key->endsWith("_icon_id")) + { + $info[$key->toString()] = $this->iconGetName($key)->filterDigits(); + } + } + + return $info; + } + + return $this->nodeInfo; + } + + /** + * Returns the specified property or a pre-defined default value from the node info array. + * + * @param string $property + * @param mixed $default + * @return mixed + */ + public function getProperty($property, $default = null) + { + if(!$this->offsetExists($property)) + { + $this->fetchNodeInfo(); + } + + if(!$this->offsetExists($property)) + { + return $default; + } + + return $this->nodeInfo[(string) $property]; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return get_class($this); + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function toString() + { + return $this->__toString(); + } + + /** + * Returns an assoc array filled with current node info properties. + * + * @return array + */ + public function toArray() + { + return $this->nodeList; + } + + /** + * Called whenever we're using an unknown method. + * + * @param string $name + * @param array $args + * @throws TeamSpeak3_Node_Exception + * @return mixed + */ + public function __call($name, array $args) + { + if($this->getParent() instanceof TeamSpeak3_Node_Abstract) + { + return call_user_func_array(array($this->getParent(), $name), $args); + } + + throw new TeamSpeak3_Node_Exception("node method '" . $name . "()' does not exist"); + } + + /** + * Writes data to the internal storage array. + * + * @param string $key + * @param mixed $val + * @return void + */ + protected function setStorage($key, $val) + { + $this->storage[$key] = $val; + } + + /** + * Returns data from the internal storage array. + * + * @param string $key + * @param mixed $default + * @return mixed + */ + protected function getStorage($key, $default = null) + { + return (array_key_exists($key, $this->storage) && !empty($this->storage[$key])) ? $this->storage[$key] : $default; + } + + /** + * Deletes data from the internal storage array. + * + * @param string $key + * @return void + */ + protected function delStorage($key) + { + unset($this->storage[$key]); + } + + /** + * Commit pending data. + * + * @return array + */ + public function __sleep() + { + return array("parent", "storage", "nodeId"); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + } + + /** + * @ignore + */ + protected function fetchNodeInfo() + { + return; + } + + /** + * @ignore + */ + protected function resetNodeInfo() + { + $this->nodeInfo = array(); + } + + /** + * @ignore + */ + protected function verifyNodeList() + { + if($this->nodeList === null) + { + $this->fetchNodeList(); + } + } + + /** + * @ignore + */ + protected function resetNodeList() + { + $this->nodeList = null; + } + + /** + * @ignore + */ + public function count() + { + $this->verifyNodeList(); + + return count($this->nodeList); + } + + /** + * @ignore + */ + public function current() + { + $this->verifyNodeList(); + + return current($this->nodeList); + } + + /** + * @ignore + */ + public function getChildren() + { + $this->verifyNodeList(); + + return $this->current(); + } + + /** + * @ignore + */ + public function hasChildren() + { + $this->verifyNodeList(); + + return $this->current()->count() > 0; + } + + /** + * @ignore + */ + public function hasNext() + { + $this->verifyNodeList(); + + return $this->key()+1 < $this->count(); + } + + /** + * @ignore + */ + public function key() + { + $this->verifyNodeList(); + + return key($this->nodeList); + } + + /** + * @ignore + */ + public function valid() + { + $this->verifyNodeList(); + + return $this->key() !== null; + } + + /** + * @ignore + */ + public function next() + { + $this->verifyNodeList(); + + return next($this->nodeList); + } + + /** + * @ignore + */ + public function rewind() + { + $this->verifyNodeList(); + + return reset($this->nodeList); + } + + /** + * @ignore + */ + public function offsetExists($offset) + { + return array_key_exists((string) $offset, $this->nodeInfo) ? TRUE : FALSE; + } + + /** + * @ignore + */ + public function offsetGet($offset) + { + if(!$this->offsetExists($offset)) + { + $this->fetchNodeInfo(); + } + + if(!$this->offsetExists($offset)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + return $this->nodeInfo[(string) $offset]; + } + + /** + * @ignore + */ + public function offsetSet($offset, $value) + { + if(method_exists($this, "modify")) + { + return $this->modify(array((string) $offset => $value)); + } + + throw new TeamSpeak3_Node_Exception("node '" . get_class($this) . "' is read only"); + } + + /** + * @ignore + */ + public function offsetUnset($offset) + { + unset($this->nodeInfo[(string) $offset]); + } + + /** + * @ignore + */ + public function __get($offset) + { + return $this->offsetGet($offset); + } + + /** + * @ignore + */ + public function __set($offset, $value) + { + $this->offsetSet($offset, $value); + } +} diff --git a/hidden/TeamSpeak3/Node/Channel.php b/hidden/TeamSpeak3/Node/Channel.php new file mode 100644 index 0000000..9e47bf4 --- /dev/null +++ b/hidden/TeamSpeak3/Node/Channel.php @@ -0,0 +1,588 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Channel + * @brief Class describing a TeamSpeak 3 channel and all it's parameters. + */ +class TeamSpeak3_Node_Channel extends TeamSpeak3_Node_Abstract +{ + /** + * The TeamSpeak3_Node_Channel constructor. + * + * @param TeamSpeak3_Node_Server $server + * @param array $info + * @param string $index + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function __construct(TeamSpeak3_Node_Server $server, array $info, $index = "cid") + { + $this->parent = $server; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Returns an array filled with TeamSpeak3_Node_Channel objects. + * + * @param array $filter + * @return array + */ + public function subChannelList(array $filter = array()) + { + $channels = array(); + + foreach($this->getParent()->channelList() as $channel) + { + if($channel["pid"] == $this->getId()) + { + $channels[$channel->getId()] = $channel; + } + } + + return $this->filterList($channels, $filter); + } + + /** + * Returns the TeamSpeak3_Node_Channel object matching the given ID. + * + * @param integer $cid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function subChannelGetById($cid) + { + if(!array_key_exists((string) $cid, $this->subChannelList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + return $this->channelList[(string) $cid]; + } + + /** + * Returns the TeamSpeak3_Node_Channel object matching the given name. + * + * @param integer $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function subChannelGetByName($name) + { + foreach($this->subChannelList() as $channel) + { + if($channel["channel_name"] == $name) return $channel; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + /** + * Returns an array filled with TeamSpeak3_Node_Client objects. + * + * @param array $filter + * @return array + */ + public function clientList(array $filter = array()) + { + $clients = array(); + + foreach($this->getParent()->clientList() as $client) + { + if($client["cid"] == $this->getId()) + { + $clients[$client->getId()] = $client; + } + } + + return $this->filterList($clients, $filter); + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given ID. + * + * @param integer $clid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetById($clid) + { + if(!array_key_exists($clid, $this->clientList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + return $this->clientList[intval($clid)]; + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given name. + * + * @param integer $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetByName($name) + { + foreach($this->clientList() as $client) + { + if($client["client_nickname"] == $name) return $client; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + /** + * Returns a list of permissions defined for a client in the channel. + * + * @param integer $cldbid + * @param boolean $permsid + * @return void + */ + public function clientPermList($cldbid, $permsid = FALSE) + { + return $this->getParent()->channelClientPermList($this->getId(), $cldbid, $permsid); + } + + /** + * Adds a set of specified permissions to a client in a specific channel. Multiple permissions can be added by + * providing the two parameters of each permission. + * + * @param integer $cldbid + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function clientPermAssign($cldbid, $permid, $permvalue) + { + return $this->getParent()->channelClientPermAssign($this->getId(), $cldbid, $permid, $permvalue); + } + + /** + * Alias for clientPermAssign(). + * + * @deprecated + */ + public function clientPermAssignByName($cldbid, $permname, $permvalue) + { + return $this->clientPermAssign($cldbid, $permname, $permvalue); + } + + /** + * Removes a set of specified permissions from a client in the channel. Multiple permissions can be removed at once. + * + * @param integer $cldbid + * @param integer $permid + * @return void + */ + public function clientPermRemove($cldbid, $permid) + { + return $this->getParent()->channelClientPermRemove($this->getId(), $cldbid, $permid); + } + + /** + * Alias for clientPermRemove(). + * + * @deprecated + */ + public function clientPermRemoveByName($cldbid, $permname) + { + return $this->clientPermRemove($cldbid, $permname); + } + + /** + * Returns a list of permissions defined for the channel. + * + * @param boolean $permsid + * @return array + */ + public function permList($permsid = FALSE) + { + return $this->getParent()->channelPermList($this->getId(), $permsid); + } + + /** + * Adds a set of specified permissions to the channel. Multiple permissions can be added by + * providing the two parameters of each permission. + * + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function permAssign($permid, $permvalue) + { + return $this->getParent()->channelPermAssign($this->getId(), $permid, $permvalue); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permAssignByName($permname, $permvalue) + { + return $this->permAssign($permname, $permvalue); + } + + /** + * Removes a set of specified permissions from the channel. Multiple permissions can be removed at once. + * + * @param integer $permid + * @return void + */ + public function permRemove($permid) + { + return $this->getParent()->channelPermRemove($this->getId(), $permid); + } + + /** + * Alias for permRemove(). + * + * @deprecated + */ + public function permRemoveByName($permname) + { + return $this->permRemove($permname); + } + + /** + * Returns a list of files and directories stored in the channels file repository. + * + * @param string $cpw + * @param string $path + * @param boolean $recursive + * @return void + */ + public function fileList($cpw = "", $path = "/", $recursive = FALSE) + { + return $this->getParent()->channelFileList($this->getId(), $cpw, $path, $recursive); + } + + /** + * Returns detailed information about the specified file stored in the channels file repository. + * + * @param string $cpw + * @param string $name + * @return array + */ + public function fileInfo($cpw = "", $name = "/") + { + return $this->getParent()->channelFileInfo($this->getId(), $cpw, $name); + } + + /** + * Renames a file in the channels file repository. If the two parameters $tcid and $tcpw are specified, the file + * will be moved into another channels file repository. + * + * @param string $cpw + * @param string $oldname + * @param string $newname + * @param integer $tcid + * @param string $tcpw + * @return void + */ + public function fileRename($cpw = "", $oldname = "/", $newname = "/", $tcid = null, $tcpw = null) + { + return $this->getParent()->channelFileRename($this->getId(), $cpw, $oldname, $newname, $tcid, $tcpw); + } + + /** + * Deletes one or more files stored in the channels file repository. + * + * @param string $cpw + * @param string $path + * @return void + */ + public function fileDelete($cpw = "", $name = "/") + { + return $this->getParent()->channelFileDelete($this->getId(), $cpw, $name); + } + + /** + * Creates new directory in a channels file repository. + * + * @param string $cpw + * @param string $dirname + * @return void + */ + public function dirCreate($cpw = "", $dirname = "/") + { + return $this->getParent()->channelDirCreate($this->getId(), $cpw, $dirname); + } + + /** + * Returns the level of the channel. + * + * @return integer + */ + public function getLevel() + { + return $this->getParent()->channelGetLevel($this->getId()); + } + + /** + * Returns the pathway of the channel which can be used as a clients default channel. + * + * @return string + */ + public function getPathway() + { + return $this->getParent()->channelGetPathway($this->getId()); + } + + /** + * Returns the possible spacer type of the channel. + * + * @return integer + */ + public function spacerGetType() + { + return $this->getParent()->channelSpacerGetType($this->getId()); + } + + /** + * Returns the possible spacer alignment of the channel. + * + * @return integer + */ + public function spacerGetAlign() + { + return $this->getParent()->channelSpacerGetAlign($this->getId()); + } + + /** + * Returns TRUE if the channel is a spacer. + * + * @return boolean + */ + public function isSpacer() + { + return $this->getParent()->channelIsSpacer($this); + } + + /** + * Downloads and returns the channels icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("channel_icon_id") || $this["channel_icon_id"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("channel_icon_id")); + $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * Changes the channel configuration using given properties. + * + * @param array $properties + * @return void + */ + public function modify(array $properties) + { + $properties["cid"] = $this->getId(); + + $this->execute("channeledit", $properties); + $this->resetNodeInfo(); + } + + /** + * Sends a text message to all clients in the channel. + * + * @param string $msg + * @param string $cpw + * @return void + */ + public function message($msg, $cpw = null) + { + if($this->getId() != $this->getParent()->whoamiGet("client_channel_id")) + { + $this->getParent()->clientMove($this->getParent()->whoamiGet("client_id"), $this->getId(), $cpw); + } + + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $this->getId(), "targetmode" => TeamSpeak3::TEXTMSG_CHANNEL)); + } + + /** + * Deletes the channel. + * + * @param boolean $force + * @return void + */ + public function delete($force = FALSE) + { + $this->getParent()->channelDelete($this->getId(), $force); + + unset($this); + } + + /** + * Moves the channel to the parent channel specified with $pid. + * + * @param integer $pid + * @param integer $order + * @return void + */ + public function move($pid, $order = null) + { + $this->getParent()->channelMove($this->getId(), $pid, $order); + } + + /** + * Sends a plugin command to all clients in the channel. + * + * @param string $plugin + * @param string $data + * @param string $cpw + * @param boolean $subscribed + * @return void + */ + public function sendPluginCmd($plugin, $data, $cpw = null, $subscribed = FALSE) + { + if($this->getId() != $this->getParent()->whoamiGet("client_channel_id")) + { + $this->getParent()->clientMove($this->getParent()->whoamiGet("client_id"), $this->getId(), $cpw); + } + + $this->execute("plugincmd", array("name" => $plugin, "data" => $data, "targetmode" => $subscribed ? TeamSpeak3::PLUGINCMD_CHANNEL_SUBSCRIBED : TeamSpeak3::PLUGINCMD_CHANNEL)); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + + if($this->getParent()->getLoadClientlistFirst()) + { + foreach($this->clientList() as $client) + { + if($client["cid"] == $this->getId()) + { + $this->nodeList[] = $client; + } + } + + foreach($this->subChannelList() as $channel) + { + if($channel["pid"] == $this->getId()) + { + $this->nodeList[] = $channel; + } + } + } + else + { + foreach($this->subChannelList() as $channel) + { + if($channel["pid"] == $this->getId()) + { + $this->nodeList[] = $channel; + } + } + + foreach($this->clientList() as $client) + { + if($client["cid"] == $this->getId()) + { + $this->nodeList[] = $client; + } + } + } + } + + /** + * @ignore + */ + protected function fetchNodeInfo() + { + $this->nodeInfo = array_merge($this->nodeInfo, $this->execute("channelinfo", array("cid" => $this->getId()))->toList()); + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_ch" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + if($this["channel_maxclients"] != -1 && $this["channel_maxclients"] <= $this["total_clients"]) + { + return "channel_full"; + } + elseif($this["channel_flag_password"]) + { + return "channel_pass"; + } + else + { + return "channel_open"; + } + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "#"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["channel_name"]; + } +} + diff --git a/hidden/TeamSpeak3/Node/Channelgroup.php b/hidden/TeamSpeak3/Node/Channelgroup.php new file mode 100644 index 0000000..0cd4ca0 --- /dev/null +++ b/hidden/TeamSpeak3/Node/Channelgroup.php @@ -0,0 +1,276 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Channelgroup + * @brief Class describing a TeamSpeak 3 channel group and all it's parameters. + */ +class TeamSpeak3_Node_Channelgroup extends TeamSpeak3_Node_Abstract +{ + /** + * The TeamSpeak3_Node_Channelgroup constructor. + * + * @param TeamSpeak3_Node_Server $server + * @param array $info + * @param string $index + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channelgroup + */ + public function __construct(TeamSpeak3_Node_Server $server, array $info, $index = "cgid") + { + $this->parent = $server; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Renames the channel group specified. + * + * @param string $name + * @return void + */ + public function rename($name) + { + return $this->getParent()->channelGroupRename($this->getId(), $name); + } + + /** + * Deletes the channel group. If $force is set to TRUE, the channel group will be + * deleted even if there are clients within. + * + * @param boolean $force + * @return void + */ + public function delete($force = FALSE) + { + $this->getParent()->channelGroupDelete($this->getId(), $force); + + unset($this); + } + + /** + * Creates a copy of the channel group and returns the new groups ID. + * + * @param string $name + * @param integer $tcgid + * @param integer $type + * @return integer + */ + public function copy($name = null, $tcgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + return $this->getParent()->channelGroupCopy($this->getId(), $name, $tcgid, $type); + } + + /** + * Returns a list of permissions assigned to the channel group. + * + * @param boolean $permsid + * @return array + */ + public function permList($permsid = FALSE) + { + return $this->getParent()->channelGroupPermList($this->getId(), $permsid); + } + + /** + * Adds a set of specified permissions to the channel group. Multiple permissions + * can be added by providing the two parameters of each permission in separate arrays. + * + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function permAssign($permid, $permvalue) + { + return $this->getParent()->channelGroupPermAssign($this->getId(), $permid, $permvalue); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permAssignByName($permname, $permvalue) + { + return $this->permAssign($permname, $permvalue); + } + + /** + * Removes a set of specified permissions from the channel group. Multiple + * permissions can be removed at once. + * + * @param integer $permid + * @return void + */ + public function permRemove($permid) + { + return $this->getParent()->channelGroupPermRemove($this->getId(), $permid); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permRemoveByName($permname) + { + return $this->permRemove($permname); + } + + /** + * Returns a list of clients assigned to the server group specified. + * + * @return array + */ + public function clientList() + { + return $this->getParent()->channelGroupClientList($this->getId()); + } + + /** + * Alias for privilegeKeyCreate(). + * + * @deprecated + */ + public function tokenCreate($cid, $description = null, $customset = null) + { + return $this->privilegeKeyCreate($cid, $description, $customset); + } + + /** + * Creates a new privilege key (token) for the channel group and returns the key. + * + * @param integer $cid + * @param string $description + * @param string $customset + * @return TeamSpeak3_Helper_String + */ + public function privilegeKeyCreate($cid, $description = null, $customset = null) + { + return $this->getParent()->privilegeKeyCreate(TeamSpeak3::TOKEN_CHANNELGROUP, $this->getId(), $cid, $description, $customset); + } + + /** + * Sends a text message to all clients residing in the channel group on the virtual server. + * + * @param string $msg + * @return void + */ + public function message($msg) + { + foreach($this as $client) + { + try + { + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $client, "targetmode" => TeamSpeak3::TEXTMSG_CLIENT)); + } + catch(TeamSpeak3_Adapter_ServerQuery_Exception $e) + { + /* ERROR_client_invalid_id */ + if($e->getCode() != 0x0200) throw $e; + } + } + } + + /** + * Downloads and returns the channel groups icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("iconid") || $this["iconid"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("iconid")); + $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + + foreach($this->getParent()->clientList() as $client) + { + if($client["client_channel_group_id"] == $this->getId()) + { + $this->nodeList[] = $client; + } + } + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_cg" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + return "group_channel"; + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "%"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["name"]; + } +} + diff --git a/hidden/TeamSpeak3/Node/Client.php b/hidden/TeamSpeak3/Node/Client.php new file mode 100644 index 0000000..fa1b84a --- /dev/null +++ b/hidden/TeamSpeak3/Node/Client.php @@ -0,0 +1,441 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Client + * @brief Class describing a TeamSpeak 3 client and all it's parameters. + */ +class TeamSpeak3_Node_Client extends TeamSpeak3_Node_Abstract +{ + /** + * The TeamSpeak3_Node_Client constructor. + * + * @param TeamSpeak3_Node_Server $server + * @param array $info + * @param string $index + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function __construct(TeamSpeak3_Node_Server $server, array $info, $index = "clid") + { + $this->parent = $server; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Changes the clients properties using given properties. + * + * @param array $properties + * @return void + */ + public function modify(array $properties) + { + $properties["clid"] = $this->getId(); + + $this->execute("clientedit", $properties); + $this->resetNodeInfo(); + } + + /** + * Changes the clients properties using given properties. + * + * @param array $properties + * @return void + */ + public function modifyDb(array $properties) + { + return $this->getParent()->clientModifyDb($this["client_database_id"], $properties); + } + + /** + * Deletes the clients properties from the database. + * + * @return void + */ + public function deleteDb() + { + return $this->getParent()->clientDeleteDb($this["client_database_id"]); + } + + /** + * Returns a list of properties from the database for the client. + * + * @return array + */ + public function infoDb() + { + return $this->getParent()->clientInfoDb($this["client_database_id"]); + } + + /** + * Sends a text message to the client. + * + * @param string $msg + * @return void + */ + public function message($msg) + { + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $this->getId(), "targetmode" => TeamSpeak3::TEXTMSG_CLIENT)); + } + + /** + * Moves the client to another channel. + * + * @param integer $cid + * @param string $cpw + * @return void + */ + public function move($cid, $cpw = null) + { + return $this->getParent()->clientMove($this->getId(), $cid, $cpw); + } + + /** + * Kicks the client from his currently joined channel or from the server. + * + * @param integer $reasonid + * @param string $reasonmsg + * @return void + */ + public function kick($reasonid = TeamSpeak3::KICK_CHANNEL, $reasonmsg = null) + { + return $this->getParent()->clientKick($this->getId(), $reasonid, $reasonmsg); + } + + /** + * Sends a poke message to the client. + * + * @param string $msg + * @return void + */ + public function poke($msg) + { + return $this->getParent()->clientPoke($this->getId(), $msg); + } + + /** + * Bans the client from the server. Please note that this will create two separate + * ban rules for the targeted clients IP address and his unique identifier. + * + * @param integer $timeseconds + * @param string $reason + * @return array + */ + public function ban($timeseconds = null, $reason = null) + { + return $this->getParent()->clientBan($this->getId(), $timeseconds, $reason); + } + + /** + * Returns a list of custom properties for the client. + * + * @return array + */ + public function customInfo() + { + return $this->getParent()->customInfo($this["client_database_id"]); + } + + /** + * Returns an array containing the permission overview of the client. + * + * @param integer $cid + * @return array + */ + public function permOverview($cid) + { + return $this->execute("permoverview", array("cldbid" => $this["client_database_id"], "cid" => $cid, "permid" => 0))->toArray(); + } + + /** + * Returns a list of permissions defined for the client. + * + * @param boolean $permsid + * @return array + */ + public function permList($permsid = FALSE) + { + return $this->getParent()->clientPermList($this["client_database_id"], $permsid); + } + + /** + * Adds a set of specified permissions to the client. Multiple permissions can be added by providing + * the three parameters of each permission. + * + * @param integer $permid + * @param integer $permvalue + * @param integer $permskip + * @return void + */ + public function permAssign($permid, $permvalue, $permskip = FALSE) + { + return $this->getParent()->clientPermAssign($this["client_database_id"], $permid, $permvalue, $permskip); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permAssignByName($permname, $permvalue, $permskip = FALSE) + { + return $this->permAssign($permname, $permvalue, $permskip); + } + + /** + * Removes a set of specified permissions from a client. Multiple permissions can be removed at once. + * + * @param integer $permid + * @return void + */ + public function permRemove($permid) + { + return $this->getParent()->clientPermRemove($this["client_database_id"], $permid); + } + + /** + * Alias for permRemove(). + * + * @deprecated + */ + public function permRemoveByName($permname) + { + return $this->permRemove($permname); + } + + /** + * Sets the channel group of a client to the ID specified. + * + * @param integer $cid + * @param integer $cgid + * @return void + */ + public function setChannelGroup($cid, $cgid) + { + return $this->getParent()->clientSetChannelGroup($this["client_database_id"], $cid, $cgid); + } + + /** + * Adds the client to the server group specified with $sgid. + * + * @param integer $sgid + * @return void + */ + public function addServerGroup($sgid) + { + return $this->getParent()->serverGroupClientAdd($sgid, $this["client_database_id"]); + } + + /** + * Removes the client from the server group specified with $sgid. + * + * @param integer $sgid + * @return void + */ + public function remServerGroup($sgid) + { + return $this->getParent()->serverGroupClientDel($sgid, $this["client_database_id"]); + } + + /** + * Returns the possible name of the clients avatar. + * + * @return TeamSpeak3_Helper_String + */ + public function avatarGetName() + { + return new TeamSpeak3_Helper_String("/avatar_" . $this["client_base64HashClientUID"]); + } + + /** + * Downloads and returns the clients avatar file content. + * + * @return TeamSpeak3_Helper_String + */ + public function avatarDownload() + { + if($this["client_flag_avatar"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->avatarGetName()); + $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * Returns a list of client connections using the same identity as this client. + * + * @return array + */ + public function getClones() + { + return $this->execute("clientgetids", array("cluid" => $this["client_unique_identifier"]))->toAssocArray("clid"); + } + + /** + * Returns the revision/build number from the clients version string. + * + * @return integer + */ + public function getRev() + { + return $this["client_type"] ? null : $this["client_version"]->section("[", 1)->filterDigits(); + } + + /** + * Returns all server and channel groups the client is currently residing in. + * + * @return array + */ + public function memberOf() + { + $groups = array($this->getParent()->channelGroupGetById($this["client_channel_group_id"])); + + foreach(explode(",", $this["client_servergroups"]) as $sgid) + { + $groups[] = $this->getParent()->serverGroupGetById($sgid); + } + + return $groups; + } + + /** + * Downloads and returns the clients icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("client_icon_id") || $this["client_icon_id"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("client_icon_id")); + $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * Sends a plugin command to the client. + * + * @param string $plugin + * @param string $data + * @return void + */ + public function sendPluginCmd($plugin, $data) + { + $this->execute("plugincmd", array("name" => $plugin, "data" => $data, "targetmode" => TeamSpeak3::PLUGINCMD_CLIENT, "target" => $this->getId())); + } + + /** + * @ignore + */ + protected function fetchNodeInfo() + { + if($this["client_type"] == 1) return; + + $this->nodeInfo = array_merge($this->nodeInfo, $this->execute("clientinfo", array("clid" => $this->getId()))->toList()); + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_cl" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + if($this["client_type"]) + { + return "client_query"; + } + elseif($this["client_away"]) + { + return "client_away"; + } + elseif(!$this["client_output_hardware"]) + { + return "client_snd_disabled"; + } + elseif($this["client_output_muted"]) + { + return "client_snd_muted"; + } + elseif(!$this["client_input_hardware"]) + { + return "client_mic_disabled"; + } + elseif($this["client_input_muted"]) + { + return "client_mic_muted"; + } + elseif($this["client_is_channel_commander"]) + { + return $this["client_flag_talking"] ? "client_cc_talk" : "client_cc_idle"; + } + else + { + return $this["client_flag_talking"] ? "client_talk" : "client_idle"; + } + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "@"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["client_nickname"]; + } +} + diff --git a/hidden/TeamSpeak3/Node/Exception.php b/hidden/TeamSpeak3/Node/Exception.php new file mode 100644 index 0000000..a2a10d0 --- /dev/null +++ b/hidden/TeamSpeak3/Node/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Exception + * @brief Enhanced exception class for TeamSpeak3_Node_Abstract objects. + */ +class TeamSpeak3_Node_Exception extends TeamSpeak3_Exception {} diff --git a/hidden/TeamSpeak3/Node/Host.php b/hidden/TeamSpeak3/Node/Host.php new file mode 100644 index 0000000..c12f000 --- /dev/null +++ b/hidden/TeamSpeak3/Node/Host.php @@ -0,0 +1,1193 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @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 && array_key_exists($ident, $this->version)) ? $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() + { + return $this->request("bindinglist")->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)) ? intval($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); + + call_user_func_array(array($this, $func), $args); + } + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this->getAdapterHost(); + } +} + diff --git a/hidden/TeamSpeak3/Node/Server.php b/hidden/TeamSpeak3/Node/Server.php new file mode 100644 index 0000000..5dae154 --- /dev/null +++ b/hidden/TeamSpeak3/Node/Server.php @@ -0,0 +1,2536 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Server + * @brief Class describing a TeamSpeak 3 virtual server and all it's parameters. + */ +class TeamSpeak3_Node_Server extends TeamSpeak3_Node_Abstract +{ + /** + * @ignore + */ + protected $channelList = null; + + /** + * @ignore + */ + protected $clientList = null; + + /** + * @ignore + */ + protected $sgroupList = null; + + /** + * @ignore + */ + protected $cgroupList = null; + + /** + * The TeamSpeak3_Node_Server constructor. + * + * @param TeamSpeak3_Node_Host $host + * @param array $info + * @param string $index + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Server + */ + public function __construct(TeamSpeak3_Node_Host $host, array $info, $index = "virtualserver_id") + { + $this->parent = $host; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid serverID", 0x400); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Sends a prepared command to the server and returns the result. + * + * @param string $cmd + * @param boolean $throw + * @return TeamSpeak3_Adapter_ServerQuery_Reply + */ + public function request($cmd, $throw = TRUE) + { + if($this->getId() != $this->getParent()->serverSelectedId()) + { + $this->getParent()->serverSelect($this->getId()); + } + + return $this->getParent()->request($cmd, $throw); + } + + /** + * Returns an array filled with TeamSpeak3_Node_Channel objects. + * + * @param array $filter + * @return array + */ + public function channelList(array $filter = array()) + { + if($this->channelList === null) + { + $channels = $this->request("channellist -topic -flags -voice -limits -icon")->toAssocArray("cid"); + + $this->channelList = array(); + + foreach($channels as $cid => $channel) + { + $this->channelList[$cid] = new TeamSpeak3_Node_Channel($this, $channel); + } + + $this->resetNodeList(); + } + + return $this->filterList($this->channelList, $filter); + } + + /** + * Resets the list of channels online. + * + * @return void + */ + public function channelListReset() + { + $this->resetNodeList(); + $this->channelList = null; + } + + /** + * Creates a new channel using given properties and returns the new ID. + * + * @param array $properties + * @return integer + */ + public function channelCreate(array $properties) + { + $cid = $this->execute("channelcreate", $properties)->toList(); + $this->channelListReset(); + + if(!isset($properties["client_flag_permanent"]) && !isset($properties["client_flag_semi_permanent"])) + { + $this->getParent()->whoamiSet("client_channel_id", $cid["cid"]); + } + + return $cid["cid"]; + } + + /** + * Deletes the channel specified by $cid. + * + * @param integer $cid + * @param boolean $force + * @return void + */ + public function channelDelete($cid, $force = FALSE) + { + $this->execute("channeldelete", array("cid" => $cid, "force" => $force)); + $this->channelListReset(); + + if(($cid instanceof TeamSpeak3_Node_Abstract ? $cid->getId() : $cid) == $this->whoamiGet("client_channel_id")) + { + $this->getParent()->whoamiReset(); + } + } + + /** + * Moves the channel specified by $cid to the parent channel specified with $pid. + * + * @param integer $cid + * @param integer $pid + * @param integer $order + * @return void + */ + public function channelMove($cid, $pid, $order = null) + { + $this->execute("channelmove", array("cid" => $cid, "cpid" => $pid, "order" => $order)); + $this->channelListReset(); + } + + /** + * Returns TRUE if the given TeamSpeak3_Node_Channel object is a spacer. + * + * @param TeamSpeak3_Node_Channel $channel + * @return boolean + */ + public function channelIsSpacer(TeamSpeak3_Node_Channel $channel) + { + return (preg_match("/\[[^\]]*spacer[^\]]*\]/", $channel) && $channel["channel_flag_permanent"] && !$channel["pid"]) ? TRUE : FALSE; + } + + /** + * Creates a new channel spacer and returns the new ID. The first parameter $ident is used to create a + * unique spacer name on the virtual server. + * + * @param string $ident + * @param mixed $type + * @param integer $align + * @param integer $order + * @param integer $maxclients + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return integer + */ + public function channelSpacerCreate($ident, $type = TeamSpeak3::SPACER_SOLIDLINE, $align = TeamSpeak3::SPACER_ALIGN_REPEAT, $order = null, $maxclients = 0) + { + $properties = array( + "channel_name_phonetic" => "channel spacer", + "channel_codec" => TeamSpeak3::CODEC_OPUS_VOICE, + "channel_codec_quality" => 0x00, + "channel_flag_permanent" => TRUE, + "channel_flag_maxclients_unlimited" => FALSE, + "channel_flag_maxfamilyclients_unlimited" => FALSE, + "channel_flag_maxfamilyclients_inherited" => FALSE, + "channel_maxclients" => $maxclients, + "channel_order" => $order, + ); + + switch($align) + { + case TeamSpeak3::SPACER_ALIGN_REPEAT: + $properties["channel_name"] = "[*spacer" . strval($ident) . "]"; + break; + + case TeamSpeak3::SPACER_ALIGN_LEFT: + $properties["channel_name"] = "[lspacer" . strval($ident) . "]"; + break; + + case TeamSpeak3::SPACER_ALIGN_RIGHT: + $properties["channel_name"] = "[rspacer" . strval($ident) . "]"; + break; + + case TeamSpeak3::SPACER_ALIGN_CENTER: + $properties["channel_name"] = "[cspacer" . strval($ident) . "]"; + break; + + default: + throw new TeamSpeak3_Adapter_ServerQuery_Exception("missing required parameter", 0x606); + break; + } + + switch($type) + { + case (string) TeamSpeak3::SPACER_SOLIDLINE: + $properties["channel_name"] .= "___"; + break; + + case (string) TeamSpeak3::SPACER_DASHLINE: + $properties["channel_name"] .= "---"; + break; + + case (string) TeamSpeak3::SPACER_DOTLINE: + $properties["channel_name"] .= "..."; + break; + + case (string) TeamSpeak3::SPACER_DASHDOTLINE: + $properties["channel_name"] .= "-.-"; + break; + + case (string) TeamSpeak3::SPACER_DASHDOTDOTLINE: + $properties["channel_name"] .= "-.."; + break; + + default: + $properties["channel_name"] .= strval($type); + break; + } + + return $this->channelCreate($properties); + } + + /** + * Returns the possible type of a channel spacer. + * + * @param integer $cid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return integer + */ + public function channelSpacerGetType($cid) + { + $channel = $this->channelGetById($cid); + + if(!$this->channelIsSpacer($channel)) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channel flags", 0x307); + } + + switch($channel["channel_name"]->section("]", 1)) + { + case "___": + return TeamSpeak3::SPACER_SOLIDLINE; + + case "---": + return TeamSpeak3::SPACER_DASHLINE; + + case "...": + return TeamSpeak3::SPACER_DOTLINE; + + case "-.-": + return TeamSpeak3::SPACER_DASHDOTLINE; + + case "-..": + return TeamSpeak3::SPACER_DASHDOTDOTLINE; + + default: + return TeamSpeak3::SPACER_CUSTOM; + } + } + + /** + * Returns the possible alignment of a channel spacer. + * + * @param integer $cid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return integer + */ + public function channelSpacerGetAlign($cid) + { + $channel = $this->channelGetById($cid); + + if(!$this->channelIsSpacer($channel) || !preg_match("/\[(.*)spacer.*\]/", $channel, $matches) || !isset($matches[1])) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channel flags", 0x307); + } + + switch($matches[1]) + { + case "*": + return TeamSpeak3::SPACER_ALIGN_REPEAT; + + case "c": + return TeamSpeak3::SPACER_ALIGN_CENTER; + + case "r": + return TeamSpeak3::SPACER_ALIGN_RIGHT; + + default: + return TeamSpeak3::SPACER_ALIGN_LEFT; + } + } + + /** + * Returns a list of permissions defined for a specific channel. + * + * @param integer $cid + * @param boolean $permsid + * @return array + */ + public function channelPermList($cid, $permsid = FALSE) + { + return $this->execute("channelpermlist", array("cid" => $cid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to a channel. Multiple permissions can be added by + * providing the two parameters of each permission. + * + * @param integer $cid + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function channelPermAssign($cid, $permid, $permvalue) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channeladdperm", array("cid" => $cid, $permident => $permid, "permvalue" => $permvalue)); + } + + /** + * Removes a set of specified permissions from a channel. Multiple permissions can be removed at once. + * + * @param integer $cid + * @param integer $permid + * @return void + */ + public function channelPermRemove($cid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channeldelperm", array("cid" => $cid, $permident => $permid)); + } + + /** + * Returns a list of permissions defined for a client in a specific channel. + * + * @param integer $cid + * @param integer $cldbid + * @param boolean $permsid + * @return array + */ + public function channelClientPermList($cid, $cldbid, $permsid = FALSE) + { + return $this->execute("channelclientpermlist", array("cid" => $cid, "cldbid" => $cldbid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to a client in a specific channel. Multiple permissions can be added by + * providing the two parameters of each permission. + * + * @param integer $cid + * @param integer $cldbid + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function channelClientPermAssign($cid, $cldbid, $permid, $permvalue) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channelclientaddperm", array("cid" => $cid, "cldbid" => $cldbid, $permident => $permid, "permvalue" => $permvalue)); + } + + /** + * Removes a set of specified permissions from a client in a specific channel. Multiple permissions can be removed at once. + * + * @param integer $cid + * @param integer $cldbid + * @param integer $permid + * @return void + */ + public function channelClientPermRemove($cid, $cldbid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channelclientdelperm", array("cid" => $cid, "cldbid" => $cldbid, $permident => $permid)); + } + + /** + * Returns a list of files and directories stored in the specified channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $path + * @param boolean $recursive + * @return array + */ + public function channelFileList($cid, $cpw = "", $path = "/", $recursive = FALSE) + { + $files = $this->execute("ftgetfilelist", array("cid" => $cid, "cpw" => $cpw, "path" => $path))->toArray(); + $count = count($files); + + for($i = 0; $i < $count; $i++) + { + $files[$i]["sid"] = $this->getId(); + $files[$i]["cid"] = $files[0]["cid"]; + $files[$i]["path"] = $files[0]["path"]; + $files[$i]["src"] = new TeamSpeak3_Helper_String($cid ? $files[$i]["path"] : "/"); + + if(!$files[$i]["src"]->endsWith("/")) + { + $files[$i]["src"]->append("/"); + } + + $files[$i]["src"]->append($files[$i]["name"]); + + if($recursive && $files[$i]["type"] == TeamSpeak3::FILE_TYPE_DIRECTORY) + { + $files = array_merge($files, $this->channelFileList($cid, $cpw, $path . $files[$i]["name"], $recursive)); + } + } + + uasort($files, array(__CLASS__, "sortFileList")); + + return $files; + } + + /** + * Returns detailed information about the specified file stored in a channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $name + * @return array + */ + public function channelFileInfo($cid, $cpw = "", $name = "/") + { + return array_pop($this->execute("ftgetfileinfo", array("cid" => $cid, "cpw" => $cpw, "name" => $name))->toArray()); + } + + /** + * Renames a file in a channels file repository. If the two parameters $tcid and $tcpw are specified, the file + * will be moved into another channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $oldname + * @param string $newname + * @param integer $tcid + * @param string $tcpw + * @return void + */ + public function channelFileRename($cid, $cpw = "", $oldname = "/", $newname = "/", $tcid = null, $tcpw = null) + { + $this->execute("ftrenamefile", array("cid" => $cid, "cpw" => $cpw, "oldname" => $oldname, "newname" => $newname, "tcid" => $tcid, "tcpw" => $tcpw)); + } + + /** + * Deletes one or more files stored in a channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $name + * @return void + */ + public function channelFileDelete($cid, $cpw = "", $name = "/") + { + $this->execute("ftdeletefile", array("cid" => $cid, "cpw" => $cpw, "name" => $name)); + } + + /** + * Creates new directory in a channels file repository. + * + * @param integer $cid + * @param string $cpw + * @param string $dirname + * @return void + */ + public function channelDirCreate($cid, $cpw = "", $dirname = "/") + { + $this->execute("ftcreatedir", array("cid" => $cid, "cpw" => $cpw, "dirname" => $dirname)); + } + + /** + * Returns the level of a channel. + * + * @param integer $cid + * @return integer + */ + public function channelGetLevel($cid) + { + $channel = $this->channelGetById($cid); + $levelno = 0; + + if($channel["pid"]) + { + $levelno = $this->channelGetLevel($channel["pid"])+1; + } + + return $levelno; + } + + /** + * Returns the pathway of a channel which can be used as a clients default channel. + * + * @param integer $cid + * @return string + */ + public function channelGetPathway($cid) + { + $channel = $this->channelGetById($cid); + $pathway = $channel["channel_name"]; + + if($channel["pid"]) + { + $pathway = $this->channelGetPathway($channel["pid"]) . "/" . $channel["channel_name"]; + } + + return $pathway; + } + + /** + * Returns the TeamSpeak3_Node_Channel object matching the given ID. + * + * @param integer $cid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function channelGetById($cid) + { + if(!array_key_exists((string) $cid, $this->channelList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + return $this->channelList[intval((string) $cid)]; + } + + /** + * Returns the TeamSpeak3_Node_Channel object matching the given name. + * + * @param string $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channel + */ + public function channelGetByName($name) + { + foreach($this->channelList() as $channel) + { + if($channel["channel_name"] == $name) return $channel; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid channelID", 0x300); + } + + /** + * Returns an array filled with TeamSpeak3_Node_Client objects. + * + * @param array $filter + * @return array + */ + public function clientList(array $filter = array()) + { + if($this->clientList === null) + { + $clients = $this->request("clientlist -uid -away -badges -voice -info -times -groups -icon -country -ip")->toAssocArray("clid"); + + $this->clientList = array(); + + foreach($clients as $clid => $client) + { + if($this->getParent()->getExcludeQueryClients() && $client["client_type"]) continue; + + $this->clientList[$clid] = new TeamSpeak3_Node_Client($this, $client); + } + + uasort($this->clientList, array(__CLASS__, "sortClientList")); + + $this->resetNodeList(); + } + + return $this->filterList($this->clientList, $filter); + } + + /** + * Resets the list of clients online. + * + * @return void + */ + public function clientListReset() + { + $this->resetNodeList(); + $this->clientList = null; + } + + /** + * Returns a list of clients matching a given name pattern. + * + * @param string $pattern + * @return array + */ + public function clientFind($pattern) + { + return $this->execute("clientfind", array("pattern" => $pattern))->toAssocArray("clid"); + } + + /** + * Returns a list of client identities known by the virtual server. By default, the server spits out 25 entries + * at once. + * + * @param integer $offset + * @param integer $limit + * @return array + */ + public function clientListDb($offset = null, $limit = null) + { + return $this->execute("clientdblist -count", array("start" => $offset, "duration" => $limit))->toAssocArray("cldbid"); + } + + /** + * Returns the number of client identities known by the virtual server. + * + * @return integer + */ + public function clientCountDb() + { + return current($this->execute("clientdblist -count", array("duration" => 1))->toList("count")); + } + + /** + * Returns a list of properties from the database for the client specified by $cldbid. + * + * @param integer $cldbid + * @return array + */ + public function clientInfoDb($cldbid) + { + return $this->execute("clientdbinfo", array("cldbid" => $cldbid))->toList(); + } + + /** + * Returns a list of client database IDs matching a given pattern. You can either search for a clients + * last known nickname or his unique identity by using the $uid option. + * + * @param string $pattern + * @param boolean $uid + * @return array + */ + public function clientFindDb($pattern, $uid = FALSE) + { + return array_keys($this->execute("clientdbfind", array("pattern" => $pattern, ($uid) ? "-uid" : null))->toAssocArray("cldbid")); + } + + /** + * Returns the number of regular clients online. + * + * @return integer + */ + public function clientCount() + { + if($this->isOffline()) return 0; + + return $this["virtualserver_clientsonline"]-$this["virtualserver_queryclientsonline"]; + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given ID. + * + * @param integer $clid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetById($clid) + { + if(!array_key_exists((string) $clid, $this->clientList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + return $this->clientList[intval((string) $clid)]; + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given name. + * + * @param string $name + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetByName($name) + { + foreach($this->clientList() as $client) + { + if($client["client_nickname"] == $name) return $client; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given unique identifier. + * + * @param string $uid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetByUid($uid) + { + foreach($this->clientList() as $client) + { + if($client["client_unique_identifier"] == $uid) return $client; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + /** + * Returns the TeamSpeak3_Node_Client object matching the given database ID. + * + * @param integer $dbid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Client + */ + public function clientGetByDbid($dbid) + { + foreach($this->clientList() as $client) + { + if($client["client_database_id"] == $dbid) return $client; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid clientID", 0x200); + } + + /** + * Returns an array containing the last known nickname and the database ID of the client matching + * the unique identifier specified with $cluid. + * + * @param string $cluid + * @return array + */ + public function clientGetNameByUid($cluid) + { + return $this->execute("clientgetnamefromuid", array("cluid" => $cluid))->toList(); + } + + /** + * Returns an array containing a list of active client connections using the unique identifier + * specified with $cluid. + * + * @param string $cluid + * @return array + */ + public function clientGetIdsByUid($cluid) + { + return $this->execute("clientgetids", array("cluid" => $cluid))->toAssocArray("clid"); + } + + /** + * Returns an array containing the last known nickname and the unique identifier of the client + * matching the database ID specified with $cldbid. + * + * @param string $cldbid + * @return array + */ + public function clientGetNameByDbid($cldbid) + { + return $this->execute("clientgetnamefromdbid", array("cldbid" => $cldbid))->toList(); + } + + /** + * Returns an array containing the names and IDs of all server groups the client specified with + * $cldbid is is currently residing in. + * + * @param string $cldbid + * @return array + */ + public function clientGetServerGroupsByDbid($cldbid) + { + return $this->execute("servergroupsbyclientid", array("cldbid" => $cldbid))->toAssocArray("sgid"); + } + + /** + * Moves a client to another channel. + * + * @param integer $clid + * @param integer $cid + * @param string $cpw + * @return void + */ + public function clientMove($clid, $cid, $cpw = null) + { + $this->clientListReset(); + + $this->execute("clientmove", array("clid" => $clid, "cid" => $cid, "cpw" => $cpw)); + + if($clid instanceof TeamSpeak3_Node_Abstract) + { + $clid = $clid->getId(); + } + + if($cid instanceof TeamSpeak3_Node_Abstract) + { + $cid = $cid->getId(); + } + + if(!is_array($clid) && $clid == $this->whoamiGet("client_id")) + { + $this->getParent()->whoamiSet("client_channel_id", $cid); + } + } + + /** + * Kicks one or more clients from their currently joined channel or from the server. + * + * @param integer $clid + * @param integer $reasonid + * @param string $reasonmsg + * @return void + */ + public function clientKick($clid, $reasonid = TeamSpeak3::KICK_CHANNEL, $reasonmsg = null) + { + $this->clientListReset(); + + $this->execute("clientkick", array("clid" => $clid, "reasonid" => $reasonid, "reasonmsg" => $reasonmsg)); + } + + /** + * Sends a poke message to a client. + * + * @param integer $clid + * @param string $msg + * @return void + */ + public function clientPoke($clid, $msg) + { + $this->execute("clientpoke", array("clid" => $clid, "msg" => $msg)); + } + + /** + * Bans the client specified with ID $clid from the server. Please note that this will create two separate + * ban rules for the targeted clients IP address and his unique identifier. + * + * @param integer $clid + * @param integer $timeseconds + * @param string $reason + * @return array + */ + public function clientBan($clid, $timeseconds = null, $reason = null) + { + $this->clientListReset(); + + $bans = $this->execute("banclient", array("clid" => $clid, "time" => $timeseconds, "banreason" => $reason))->toAssocArray("banid"); + + return array_keys($bans); + } + + /** + * Changes the clients properties using given properties. + * + * @param string $cldbid + * @param array $properties + * @return void + */ + public function clientModifyDb($cldbid, array $properties) + { + $properties["cldbid"] = $cldbid; + + $this->execute("clientdbedit", $properties); + } + + /** + * Deletes a clients properties from the database. + * + * @param string $cldbid + * @return void + */ + public function clientDeleteDb($cldbid) + { + $this->execute("clientdbdelete", array("cldbid" => $cldbid)); + } + + /** + * Sets the channel group of a client to the ID specified. + * + * @param integer $cldbid + * @param integer $cid + * @param integer $cgid + * @return void + */ + public function clientSetChannelGroup($cldbid, $cid, $cgid) + { + $this->execute("setclientchannelgroup", array("cldbid" => $cldbid, "cid" => $cid, "cgid" => $cgid)); + } + + /** + * Returns a list of permissions defined for a client. + * + * @param integer $cldbid + * @param boolean $permsid + * @return array + */ + public function clientPermList($cldbid, $permsid = FALSE) + { + $this->clientListReset(); + + return $this->execute("clientpermlist", array("cldbid" => $cldbid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to a client. Multiple permissions can be added by providing + * the three parameters of each permission. + * + * @param integer $cldbid + * @param integer $permid + * @param integer $permvalue + * @param integer $permskip + * @return void + */ + public function clientPermAssign($cldbid, $permid, $permvalue, $permskip = FALSE) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("clientaddperm", array("cldbid" => $cldbid, $permident => $permid, "permvalue" => $permvalue, "permskip" => $permskip)); + } + + /** + * Removes a set of specified permissions from a client. Multiple permissions can be removed at once. + * + * @param integer $cldbid + * @param integer $permid + * @return void + */ + public function clientPermRemove($cldbid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("clientdelperm", array("cldbid" => $cldbid, $permident => $permid)); + } + + /** + * Returns a list of server groups available. + * + * @param filter $filter + * @return array + */ + public function serverGroupList(array $filter = array()) + { + if($this->sgroupList === null) + { + $this->sgroupList = $this->request("servergrouplist")->toAssocArray("sgid"); + + foreach($this->sgroupList as $sgid => $group) + { + $this->sgroupList[$sgid] = new TeamSpeak3_Node_Servergroup($this, $group); + } + + uasort($this->sgroupList, array(__CLASS__, "sortGroupList")); + } + + return $this->filterList($this->sgroupList, $filter); + } + + /** + * Resets the list of server groups. + * + * @return void + */ + public function serverGroupListReset() + { + $this->sgroupList = null; + } + + /** + * Creates a new server group using the name specified with $name and returns its ID. + * + * @param string $name + * @param integer $type + * @return integer + */ + public function serverGroupCreate($name, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + $this->serverGroupListReset(); + + $sgid = $this->execute("servergroupadd", array("name" => $name, "type" => $type))->toList(); + + return $sgid["sgid"]; + } + + /** + * Creates a copy of an existing server group specified by $ssgid and returns the new groups ID. + * + * @param integer $ssgid + * @param string $name + * @param integer $tsgid + * @param integer $type + * @return integer + */ + public function serverGroupCopy($ssgid, $name = null, $tsgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + $this->serverGroupListReset(); + + $sgid = $this->execute("servergroupcopy", array("ssgid" => $ssgid, "tsgid" => $tsgid, "name" => $name, "type" => $type))->toList(); + + if($tsgid && $name) + { + $this->serverGroupRename($tsgid, $name); + } + + return count($sgid) ? $sgid["sgid"] : intval($tsgid); + } + + /** + * Renames the server group specified with $sgid. + * + * @param integer $sgid + * @param string $name + * @return void + */ + public function serverGroupRename($sgid, $name) + { + $this->serverGroupListReset(); + + $this->execute("servergrouprename", array("sgid" => $sgid, "name" => $name)); + } + + /** + * Deletes the server group specified with $sgid. If $force is set to 1, the server group + * will be deleted even if there are clients within. + * + * @param integer $sgid + * @param boolean $force + * @return void + */ + public function serverGroupDelete($sgid, $force = FALSE) + { + $this->serverGroupListReset(); + + $this->execute("servergroupdel", array("sgid" => $sgid, "force" => $force)); + } + + /** + * Returns the TeamSpeak3_Node_Servergroup object matching the given ID. + * + * @param integer $sgid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Servergroup + */ + public function serverGroupGetById($sgid) + { + if(!array_key_exists((string) $sgid, $this->serverGroupList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + return $this->sgroupList[intval((string) $sgid)]; + } + + /** + * Returns the TeamSpeak3_Node_Servergroup object matching the given name. + * + * @param string $name + * @param integer $type + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Servergroup + */ + public function serverGroupGetByName($name, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + foreach($this->serverGroupList() as $group) + { + if($group["name"] == $name && $group["type"] == $type) return $group; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + /** + * Returns a list of permissions assigned to the server group specified. + * + * @param integer $sgid + * @param boolean $permsid + * @return array + */ + public function serverGroupPermList($sgid, $permsid = FALSE) + { + return $this->execute("servergrouppermlist", array("sgid" => $sgid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to the server group specified. Multiple permissions + * can be added by providing the four parameters of each permission in separate arrays. + * + * @param integer $sgid + * @param integer $permid + * @param integer $permvalue + * @param integer $permnegated + * @param integer $permskip + * @return void + */ + public function serverGroupPermAssign($sgid, $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("servergroupaddperm", array("sgid" => $sgid, $permident => $permid, "permvalue" => $permvalue, "permnegated" => $permnegated, "permskip" => $permskip)); + } + + /** + * Removes a set of specified permissions from the server group specified with $sgid. Multiple + * permissions can be removed at once. + * + * @param integer $sgid + * @param integer $permid + * @return void + */ + public function serverGroupPermRemove($sgid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("servergroupdelperm", array("sgid" => $sgid, $permident => $permid)); + } + + /** + * Returns a list of clients assigned to the server group specified. + * + * @param integer $sgid + * @return array + */ + public function serverGroupClientList($sgid) + { + if($this["virtualserver_default_server_group"] == $sgid) + { + return array(); + } + + return $this->execute("servergroupclientlist", array("sgid" => $sgid, "-names"))->toAssocArray("cldbid"); + } + + /** + * Adds a client to the server group specified. Please note that a client cannot be + * added to default groups or template groups. + * + * @param integer $sgid + * @param integer $cldbid + * @return void + */ + public function serverGroupClientAdd($sgid, $cldbid) + { + $this->clientListReset(); + + $this->execute("servergroupaddclient", array("sgid" => $sgid, "cldbid" => $cldbid)); + } + + /** + * Removes a client from the server group specified. + * + * @param integer $sgid + * @param integer $cldbid + * @return void + */ + public function serverGroupClientDel($sgid, $cldbid) + { + $this->execute("servergroupdelclient", array("sgid" => $sgid, "cldbid" => $cldbid)); + } + + /** + * Returns an ordered array of regular server groups available based on a pre-defined + * set of rules. + * + * @return array + */ + public function serverGroupGetProfiles() + { + $profiles = array(); + + foreach($this->serverGroupList() as $sgid => $sgroup) + { + if($sgroup["type"] != TeamSpeak3::GROUP_DBTYPE_REGULAR) continue; + + $profiles[$sgid] = array( + "b_permission_modify_power_ignore" => 0, + "i_group_needed_member_add_power" => 0, + "i_group_member_add_power" => 0, + "i_group_needed_member_remove_power" => 0, + "i_group_member_remove_power" => 0, + "i_needed_modify_power_count" => 0, + "i_needed_modify_power_total" => 0, + "i_permission_modify_power" => 0, + "i_group_needed_modify_power" => 0, + "i_group_modify_power" => 0, + "i_client_needed_modify_power" => 0, + "i_client_modify_power" => 0, + "b_virtualserver_servergroup_create" => 0, + "b_virtualserver_servergroup_delete" => 0, + "b_client_ignore_bans" => 0, + "b_client_ignore_antiflood" => 0, + "b_group_is_permanent" => 0, + "i_client_needed_ban_power" => 0, + "i_client_needed_kick_power" => 0, + "i_client_needed_move_power" => 0, + "i_client_talk_power" => 0, + "__sgid" => $sgid, + "__name" => $sgroup->toString(), + "__node" => $sgroup, + ); + + try + { + $perms = $this->serverGroupPermList($sgid, TRUE); + $grant = isset($perms["i_permission_modify_power"]) ? $perms["i_permission_modify_power"]["permvalue"] : null; + } + catch(TeamSpeak3_Adapter_ServerQuery_Exception $e) + { + /* ERROR_database_empty_result */ + if($e->getCode() != 0x501) throw $e; + + $perms = array(); + $grant = null; + } + + foreach($perms as $permsid => $perm) + { + if(in_array($permsid, array_keys($profiles[$sgid]))) + { + $profiles[$sgid][$permsid] = $perm["permvalue"]; + } + elseif(TeamSpeak3_Helper_String::factory($permsid)->startsWith("i_needed_modify_power_")) + { + if(!$grant || $perm["permvalue"] > $grant) continue; + + $profiles[$sgid]["i_needed_modify_power_total"] = $profiles[$sgid]["i_needed_modify_power_total"]+$perm["permvalue"]; + $profiles[$sgid]["i_needed_modify_power_count"]++; + } + } + } + + array_multisort($profiles, SORT_DESC); + + return $profiles; + } + + /** + * Tries to identify the post powerful/weakest server group on the virtual server and returns + * the ID. + * + * @param integer $mode + * @return TeamSpeak3_Node_Servergroup + */ + public function serverGroupIdentify($mode = TeamSpeak3::GROUP_IDENTIFIY_STRONGEST) + { + $profiles = $this->serverGroupGetProfiles(); + + $best_guess_profile = ($mode == TeamSpeak3::GROUP_IDENTIFIY_STRONGEST) ? array_shift($profiles) : array_pop($profiles); + + return $this->serverGroupGetById($best_guess_profile["__sgid"]); + } + + /** + * Returns a list of channel groups available. + * + * @param array $filter + * @return array + */ + public function channelGroupList(array $filter = array()) + { + if($this->cgroupList === null) + { + $this->cgroupList = $this->request("channelgrouplist")->toAssocArray("cgid"); + + foreach($this->cgroupList as $cgid => $group) + { + $this->cgroupList[$cgid] = new TeamSpeak3_Node_Channelgroup($this, $group); + } + + uasort($this->cgroupList, array(__CLASS__, "sortGroupList")); + } + + return $this->filterList($this->cgroupList, $filter); + } + + /** + * Resets the list of channel groups. + * + * @return void + */ + public function channelGroupListReset() + { + $this->cgroupList = null; + } + + /** + * Creates a new channel group using the name specified with $name and returns its ID. + * + * @param string $name + * @param integer $type + * @return integer + */ + public function channelGroupCreate($name, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + $this->channelGroupListReset(); + + $cgid = $this->execute("channelgroupadd", array("name" => $name, "type" => $type))->toList(); + + return $cgid["cgid"]; + } + + /** + * Creates a copy of an existing channel group specified by $scgid and returns the new groups ID. + * + * @param integer $scgid + * @param string $name + * @param integer $tcgid + * @param integer $type + * @return integer + */ + public function channelGroupCopy($scgid, $name = null, $tcgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + $this->channelGroupListReset(); + + $cgid = $this->execute("channelgroupcopy", array("scgid" => $scgid, "tcgid" => $tcgid, "name" => $name, "type" => $type))->toList(); + + if($tcgid && $name) + { + $this->channelGroupRename($tcgid, $name); + } + + return count($cgid) ? $cgid["cgid"] : intval($tcgid); + } + + /** + * Renames the channel group specified with $cgid. + * + * @param integer $cgid + * @param string $name + * @return void + */ + public function channelGroupRename($cgid, $name) + { + $this->channelGroupListReset(); + + $this->execute("channelgrouprename", array("cgid" => $cgid, "name" => $name)); + } + + /** + * Deletes the channel group specified with $cgid. If $force is set to 1, the channel group + * will be deleted even if there are clients within. + * + * @param integer $sgid + * @param boolean $force + * @return void + */ + public function channelGroupDelete($cgid, $force = FALSE) + { + $this->channelGroupListReset(); + + $this->execute("channelgroupdel", array("cgid" => $cgid, "force" => $force)); + } + + /** + * Returns the TeamSpeak3_Node_Channelgroup object matching the given ID. + * + * @param integer $cgid + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channelgroup + */ + public function channelGroupGetById($cgid) + { + if(!array_key_exists((string) $cgid, $this->channelGroupList())) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + return $this->cgroupList[intval((string) $cgid)]; + } + + /** + * Returns the TeamSpeak3_Node_Channelgroup object matching the given name. + * + * @param string $name + * @param integer $type + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return TeamSpeak3_Node_Channelgroup + */ + public function channelGroupGetByName($name, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + foreach($this->channelGroupList() as $group) + { + if($group["name"] == $name && $group["type"] == $type) return $group; + } + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid groupID", 0xA00); + } + + /** + * Returns a list of permissions assigned to the channel group specified. + * + * @param integer $cgid + * @param boolean $permsid + * @return array + */ + public function channelGroupPermList($cgid, $permsid = FALSE) + { + return $this->execute("channelgrouppermlist", array("cgid" => $cgid, $permsid ? "-permsid" : null))->toAssocArray($permsid ? "permsid" : "permid"); + } + + /** + * Adds a set of specified permissions to the channel group specified. Multiple permissions + * can be added by providing the two parameters of each permission in separate arrays. + * + * @param integer $cgid + * @param integer $permid + * @param integer $permvalue + * @return void + */ + public function channelGroupPermAssign($cgid, $permid, $permvalue) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channelgroupaddperm", array("cgid" => $cgid, $permident => $permid, "permvalue" => $permvalue)); + } + + /** + * Removes a set of specified permissions from the channel group specified with $cgid. Multiple + * permissions can be removed at once. + * + * @param integer $cgid + * @param integer $permid + * @return void + */ + public function channelGroupPermRemove($cgid, $permid) + { + if(!is_array($permid)) + { + $permident = (is_numeric($permid)) ? "permid" : "permsid"; + } + else + { + $permident = (is_numeric(current($permid))) ? "permid" : "permsid"; + } + + $this->execute("channelgroupdelperm", array("cgid" => $cgid, $permident => $permid)); + } + + /** + * Returns all the client and/or channel IDs currently assigned to channel groups. All three + * parameters are optional so you're free to choose the most suitable combination for your + * requirements. + * + * @param integer $cgid + * @param integer $cid + * @param integer $cldbid + * @return array + */ + public function channelGroupClientList($cgid = null, $cid = null, $cldbid = null) + { + if($this["virtualserver_default_channel_group"] == $cgid) + { + return array(); + } + + return $this->execute("channelgroupclientlist", array("cgid" => $cgid, "cid" => $cid, "cldbid" => $cldbid))->toArray(); + } + + /** + * Restores the default permission settings on the virtual server and returns a new initial + * administrator privilege key. + * + * @return TeamSpeak3_Helper_String + */ + public function permReset() + { + $token = $this->request("permreset")->toList(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyTokencreated", $this, $token["token"]); + + return $token["token"]; + } + + /** + * Removes any assignment of the permission specified with $permid on the selected virtual server + * and returns the number of removed assignments on success. + * + * @param integer $permid + * @return integer + */ + public function permRemoveAny($permid) + { + $assignments = $this->permissionFind($permid); + + foreach($assignments as $assignment) + { + switch($assignment["t"]) + { + case TeamSpeak3::PERM_TYPE_SERVERGROUP: + $this->serverGroupPermRemove($assignment["id1"], $assignment["p"]); + break; + + case TeamSpeak3::PERM_TYPE_CLIENT: + $this->clientPermRemove($assignment["id2"], $assignment["p"]); + break; + + case TeamSpeak3::PERM_TYPE_CHANNEL: + $this->channelPermRemove($assignment["id2"], $assignment["p"]); + break; + + case TeamSpeak3::PERM_TYPE_CHANNELGROUP: + $this->channelGroupPermRemove($assignment["id1"], $assignment["p"]); + break; + + case TeamSpeak3::PERM_TYPE_CHANNELCLIENT: + $this->channelClientPermRemove($assignment["id2"], $assignment["id1"], $assignment["p"]); + break; + + default: + throw new TeamSpeak3_Adapter_ServerQuery_Exception("convert error", 0x604); + } + } + + return count($assignments); + } + + /** + * Initializes a file transfer upload. $clientftfid is an arbitrary ID to identify the file transfer on client-side. + * + * @param integer $clientftfid + * @param integer $cid + * @param string $name + * @param integer $size + * @param string $cpw + * @param boolean $overwrite + * @param boolean $resume + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return array + */ + public function transferInitUpload($clientftfid, $cid, $name, $size, $cpw = "", $overwrite = FALSE, $resume = FALSE) + { + $upload = $this->execute("ftinitupload", array("clientftfid" => $clientftfid, "cid" => $cid, "name" => $name, "cpw" => $cpw, "size" => $size, "overwrite" => $overwrite, "resume" => $resume))->toList(); + + if(array_key_exists("status", $upload) && $upload["status"] != 0x00) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception($upload["msg"], $upload["status"]); + } + + $upload["cid"] = $cid; + $upload["file"] = $name; + + if(!array_key_exists("ip", $upload) || $upload["ip"]->startsWith("0.0.0.0")) + { + $upload["ip"] = $this->getParent()->getAdapterHost(); + $upload["host"] = $upload["ip"]; + } + else + { + $upload["ip"] = $upload["ip"]->section(","); + $upload["host"] = $upload["ip"]; + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferUploadInit", $upload["ftkey"], $upload); + + return $upload; + } + + /** + * Initializes a file transfer download. $clientftfid is an arbitrary ID to identify the file transfer on client-side. + * + * @param integer $clientftfid + * @param integer $cid + * @param string $name + * @param string $cpw + * @param integer $seekpos + * @throws TeamSpeak3_Adapter_ServerQuery_Exception + * @return array + */ + public function transferInitDownload($clientftfid, $cid, $name, $cpw = "", $seekpos = 0) + { + $download = $this->execute("ftinitdownload", array("clientftfid" => $clientftfid, "cid" => $cid, "name" => $name, "cpw" => $cpw, "seekpos" => $seekpos))->toList(); + + if(array_key_exists("status", $download) && $download["status"] != 0x00) + { + throw new TeamSpeak3_Adapter_ServerQuery_Exception($download["msg"], $download["status"]); + } + + $download["cid"] = $cid; + $download["file"] = $name; + + if(!array_key_exists("ip", $download) || $download["ip"]->startsWith("0.0.0.0")) + { + $download["ip"] = $this->getParent()->getAdapterHost(); + $download["host"] = $download["ip"]; + } + else + { + $download["ip"] = $download["ip"]->section(","); + $download["host"] = $download["ip"]; + } + + TeamSpeak3_Helper_Signal::getInstance()->emit("filetransferDownloadInit", $download["ftkey"], $download); + + return $download; + } + + /** + * Displays a list of running file transfers on the selected virtual server. The output contains the path to + * which a file is uploaded to, the current transfer rate in bytes per second, etc. + * + * @return array + */ + public function transferList() + { + return $this->request("ftlist")->toAssocArray("serverftfid"); + } + + /** + * Stops the running file transfer with server-side ID $serverftfid. + * + * @param integer $serverftfid + * @param boolean $delete + * @return void + */ + public function transferStop($serverftfid, $delete = FALSE) + { + $this->execute("ftstop", array("serverftfid" => $serverftfid, "delete" => $delete)); + } + + /** + * Downloads and returns the servers icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("virtualserver_icon_id") || $this["virtualserver_icon_id"] == 0) return; + + $download = $this->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("virtualserver_icon_id")); + $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * Uploads a given icon file content to the server and returns the ID of the icon. + * + * @param string $data + * @return integer + */ + public function iconUpload($data) + { + $crc = crc32($data); + $size = strlen($data); + + $upload = $this->transferInitUpload(rand(0x0000, 0xFFFF), 0, "/icon_" . $crc, $size); + $transfer = TeamSpeak3::factory("filetransfer://" . $upload["host"] . ":" . $upload["port"]); + + $transfer->upload($upload["ftkey"], $upload["seekpos"], $data); + + return $crc; + } + + /** + * Changes the virtual server configuration using given properties. + * + * @param array $properties + * @return void + */ + public function modify(array $properties) + { + $this->execute("serveredit", $properties); + $this->resetNodeInfo(); + } + + /** + * Sends a text message to all clients on the virtual server. + * + * @param string $msg + * @return void + */ + public function message($msg) + { + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $this->getId(), "targetmode" => TeamSpeak3::TEXTMSG_SERVER)); + } + + /** + * Returns a list of offline messages you've received. The output contains the senders unique identifier, + * the messages subject, etc. + * + * @return array + */ + public function messageList() + { + return $this->request("messagelist")->toAssocArray("msgid"); + } + + /** + * Sends an offline message to the client specified by $cluid. + * + * @param string $cluid + * @param string $subject + * @param string $message + * @return void + */ + public function messageCreate($cluid, $subject, $message) + { + $this->execute("messageadd", array("cluid" => $cluid, "subject" => $subject, "message" => $message)); + } + + /** + * Deletes an existing offline message with ID $msgid from your inbox. + * + * @param integer $msgid + * @return void + */ + public function messageDelete($msgid) + { + $this->execute("messagedel", array("msgid" => $msgid)); + } + + /** + * Returns an existing offline message with ID $msgid from your inbox. + * + * @param integer $msgid + * @param boolean $flag_read + * @return array + */ + public function messageRead($msgid, $flag_read = TRUE) + { + $msg = $this->execute("messageget", array("msgid" => $msgid))->toList(); + + if($flag_read) + { + $this->execute("messageget", array("msgid" => $msgid, "flag" => $flag_read)); + } + + return $msg; + } + + /** + * Creates and returns snapshot data for the selected virtual server. + * + * @param string $mode + * @return string + */ + public function snapshotCreate($mode = TeamSpeak3::SNAPSHOT_STRING) + { + $snapshot = $this->request("serversnapshotcreate")->toString(FALSE); + + switch($mode) + { + case TeamSpeak3::SNAPSHOT_BASE64: + return $snapshot->toBase64(); + break; + + case TeamSpeak3::SNAPSHOT_HEXDEC: + return $snapshot->toHex(); + break; + + default: + return (string) $snapshot; + break; + } + } + + /** + * Deploys snapshot data on the selected virtual server. If no virtual server is selected (ID 0), + * the data will be used to create a new virtual server from scratch. + * + * @param string $data + * @param string $mode + * @return array + */ + public function snapshotDeploy($data, $mode = TeamSpeak3::SNAPSHOT_STRING) + { + switch($mode) + { + case TeamSpeak3::SNAPSHOT_BASE64: + $data = TeamSpeak3_Helper_String::fromBase64($data); + break; + + case TeamSpeak3::SNAPSHOT_HEXDEC: + $data = TeamSpeak3_Helper_String::fromHex($data); + break; + + default: + $data = TeamSpeak3_Helper_String::factory($data); + break; + } + + $detail = $this->request("serversnapshotdeploy " . $data)->toList(); + + if(array_key_exists("sid", $detail)) + { + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyServercreated", $this->getParent(), $detail["sid"]); + } + + return $detail; + } + + /** + * Registers for a specified category of events on a virtual server to receive notification + * messages. Depending on the notifications you've registered for, the server will send you + * a message on every event. + * + * @param string $event + * @param integer $id + * @return void + */ + public function notifyRegister($event, $id = 0) + { + $this->execute("servernotifyregister", array("event" => $event, "id" => $id)); + } + + /** + * Unregisters all events previously registered with servernotifyregister so you will no + * longer receive notification messages. + * + * @return void + */ + public function notifyUnregister() + { + $this->request("servernotifyunregister"); + } + + /** + * Alias for privilegeKeyList(). + * + * @deprecated + */ + public function tokenList($translate = FALSE) + { + return $this->privilegeKeyList(); + } + + /** + * Returns a list of privilege keys (tokens) available. If $resolve is set to TRUE the values + * of token_id1 and token_id2 will be translated into the appropriate group and/or channel + * names. + * + * @param boolean $resolve + * @return array + */ + public function privilegeKeyList($resolve = FALSE) + { + $tokens = $this->request("privilegekeylist")->toAssocArray("token"); + + if($resolve) + { + foreach($tokens as $token => $array) + { + $func = $array["token_type"] ? "channelGroupGetById" : "serverGroupGetById"; + + try + { + $tokens[$token]["token_id1"] = $this->$func($array["token_id1"])->name; + } + catch(Exception $e) + { + /* ERROR_channel_invalid_id */ + if($e->getCode() != 0xA00) throw $e; + } + + try + { + if($array["token_type"]) $tokens[$token]["token_id2"] = $this->channelGetById($array["token_id2"])->getPathway(); + } + catch(Exception $e) + { + /* ERROR_permission_invalid_group_id */ + if($e->getCode() != 0x300) throw $e; + } + } + } + + return $tokens; + } + + /** + * Alias for privilegeKeyCreate(). + * + * @deprecated + */ + public function tokenCreate($type = TeamSpeak3::TOKEN_SERVERGROUP, $id1, $id2 = 0, $description = null, $customset = null) + { + return $this->privilegeKeyCreate($type, $id1, $id2, $description, $customset); + } + + /** + * Creates a new privilege key (token) and returns the key. + * + * @param integer $type + * @param integer $id1 + * @param integer $id2 + * @param string $description + * @param string $customset + * @return TeamSpeak3_Helper_String + */ + public function privilegeKeyCreate($type = TeamSpeak3::TOKEN_SERVERGROUP, $id1, $id2 = 0, $description = null, $customset = null) + { + $token = $this->execute("privilegekeyadd", array("tokentype" => $type, "tokenid1" => $id1, "tokenid2" => $id2, "tokendescription" => $description, "tokencustomset" => $customset))->toList(); + + TeamSpeak3_Helper_Signal::getInstance()->emit("notifyTokencreated", $this, $token["token"]); + + return $token["token"]; + } + + /** + * Alias for privilegeKeyDelete(). + * + * @deprecated + */ + public function tokenDelete($token) + { + $this->privilegeKeyDelete($token); + } + + /** + * Deletes a token specified by key $token. + * + * @param string $token + * @return void + */ + public function privilegeKeyDelete($token) + { + $this->execute("privilegekeydelete", array("token" => $token)); + } + + /** + * Alias for privilegeKeyUse(). + * + * @deprecated + */ + public function tokenUse($token) + { + $this->privilegeKeyUse($token); + } + + /** + * Use a token key gain access to a server or channel group. Please note that the server will + * automatically delete the token after it has been used. + * + * @param string $token + * @return void + */ + public function privilegeKeyUse($token) + { + $this->execute("privilegekeyuse", array("token" => $token)); + } + + /** + * Returns a list of custom client properties specified by $ident. + * + * @param string $ident + * @param string $pattern + * @return array + */ + public function customSearch($ident, $pattern = "%") + { + return $this->execute("customsearch", array("ident" => $ident, "pattern" => $pattern))->toArray(); + } + + /** + * Returns a list of custom properties for the client specified by $cldbid. + * + * @param integer $cldbid + * @return array + */ + public function customInfo($cldbid) + { + return $this->execute("custominfo", array("cldbid" => $cldbid))->toArray(); + } + + /** + * Returns a list of active bans on the selected virtual server. + * + * @return array + */ + public function banList() + { + return $this->request("banlist")->toAssocArray("banid"); + } + + /** + * Deletes all active ban rules from the server. + * + * @return void + */ + public function banListClear() + { + $this->request("bandelall"); + } + + /** + * Adds a new ban rule on the selected virtual server. All parameters are optional but at least one + * of the following rules must be set: ip, name, or uid. + * + * @param array $rules + * @param integer $timeseconds + * @param string $reason + * @return integer + */ + public function banCreate(array $rules, $timeseconds = null, $reason = null) + { + $rules["time"] = $timeseconds; + $rules["banreason"] = $reason; + + $banid = $this->execute("banadd", $rules)->toList(); + + return $banid["banid"]; + } + + /** + * Deletes the specified ban rule from the server. + * + * @param integer $banid + * @return void + */ + public function banDelete($banid) + { + $this->execute("bandel", array("banid" => $banid)); + } + + /** + * Returns a list of complaints on the selected virtual server. If $tcldbid is specified, only + * complaints about the targeted client will be shown. + * + * @param integer $tcldbid + * @return array + */ + public function complaintList($tcldbid = null) + { + return $this->execute("complainlist", array("tcldbid" => $tcldbid))->toArray(); + } + + /** + * Deletes all active complaints about the client with database ID $tcldbid from the server. + * + * @param integer $tcldbid + * @return void + */ + public function complaintListClear($tcldbid) + { + $this->execute("complaindelall", array("tcldbid" => $tcldbid)); + } + + /** + * Submits a complaint about the client with database ID $tcldbid to the server. + * + * @param integer $tcldbid + * @param string $message + * @return void + */ + public function complaintCreate($tcldbid, $message) + { + $this->execute("complainadd", array("tcldbid" => $tcldbid, "message" => $message)); + } + + /** + * Deletes the complaint about the client with ID $tcldbid submitted by the client with ID $fcldbid from the server. + * + * @param integer $tcldbid + * @param integer $fcldbid + * @return void + */ + public function complaintDelete($tcldbid, $fcldbid) + { + $this->execute("complaindel", array("tcldbid" => $tcldbid, "fcldbid" => $fcldbid)); + } + + /** + * Returns a list of temporary server passwords. + * + * @param boolean $resolve + * @return array + */ + public function tempPasswordList($resolve = FALSE) + { + $passwords = $this->request("servertemppasswordlist")->toAssocArray("pw_clear"); + + if($resolve) + { + foreach($passwords as $password => $array) + { + try + { + $channel = $this->channelGetById($array["tcid"]); + + $passwords[$password]["tcname"] = $channel->toString(); + $passwords[$password]["tcpath"] = $channel->getPathway(); + } + catch(Exception $e) + { + /* ERROR_channel_invalid_id */ + if($e->getCode() != 0xA00) throw $e; + } + } + } + + return $passwords; + } + + /** + * Sets a new temporary server password specified with $pw. The temporary password will be + * valid for the number of seconds specified with $duration. The client connecting with this + * password will automatically join the channel specified with $tcid. If tcid is set to 0, + * the client will join the default channel. + * + * @param string $pw + * @param integer $duration + * @param integer $tcid + * @param string $tcpw + * @param string $desc + * @return void + */ + public function tempPasswordCreate($pw, $duration, $tcid = 0, $tcpw = "", $desc = "") + { + $this->execute("servertemppasswordadd", array("pw" => $pw, "duration" => $duration, "tcid" => $tcid, "tcpw" => $tcpw, "desc" => $desc)); + } + + /** + * Deletes the temporary server password specified with $pw. + * + * @param string $pw + * @return void + */ + public function tempPasswordDelete($pw) + { + $this->execute("servertemppassworddel", array("pw" => $pw)); + } + + /** + * 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 = null) + { + return $this->execute("logview", array("lines" => $lines, "begin_pos" => $begin_pos, "instance" => $instance, "reverse" => $reverse))->toArray(); + } + + /** + * Writes a custom entry into the virtual server log. + * + * @param string $logmsg + * @param integer $loglevel + * @return void + */ + public function logAdd($logmsg, $loglevel = TeamSpeak3::LOGLEVEL_INFO) + { + $this->execute("logadd", array("logmsg" => $logmsg, "loglevel" => $loglevel)); + } + + /** + * Returns detailed connection information of the virtual server. + * + * @return array + */ + public function connectionInfo() + { + return $this->request("serverrequestconnectioninfo")->toList(); + } + + /** + * Deletes the virtual server. + * + * @return void + */ + public function delete() + { + $this->getParent()->serverDelete($this->getId()); + + unset($this); + } + + /** + * Starts the virtual server. + * + * @return void + */ + public function start() + { + $this->getParent()->serverStart($this->getId()); + } + + /** + * Stops the virtual server. + * + * @return void + */ + public function stop() + { + $this->getParent()->serverStop($this->getId()); + } + + /** + * Sends a plugin command to all clients connected to the server. + * + * @param string $plugin + * @param string $data + * @return void + */ + public function sendPluginCmd($plugin, $data) + { + $this->execute("plugincmd", array("name" => $plugin, "data" => $data, "targetmode" => TeamSpeak3::PLUGINCMD_SERVER)); + } + + /** + * Changes the properties of your own client connection. + * + * @param array $properties + * @return void + */ + public function selfUpdate(array $properties) + { + $this->execute("clientupdate", $properties); + + foreach($properties as $ident => $value) + { + $this->whoamiSet($ident, $value); + } + } + + /** + * Updates your own ServerQuery login credentials using a specified username. The password + * will be auto-generated. + * + * @param string $username + * @return TeamSpeak3_Helper_String + */ + public function selfUpdateLogin($username) + { + $password = $this->execute("clientsetserverquerylogin", array("client_login_name" => $username))->toList(); + + return $password["client_login_password"]; + } + + /** + * Returns an array containing the permission overview of your own client. + * + * @return array + */ + public function selfPermOverview() + { + return $this->execute("permoverview", array("cldbid" => $this->whoamiGet("client_database_id"), "cid" => $this->whoamiGet("client_channel_id"), "permid" => 0))->toArray(); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + + foreach($this->channelList() as $channel) + { + if($channel["pid"] == 0) + { + $this->nodeList[] = $channel; + } + } + } + + /** + * @ignore + */ + protected function fetchNodeInfo() + { + $this->nodeInfo = array_merge($this->nodeInfo, $this->request("serverinfo")->toList()); + } + + /** + * Internal callback funtion for sorting of client objects. + * + * @param TeamSpeak3_Node_Client $a + * @param TeamSpeak3_Node_Client $b + * @return integer + */ + protected static function sortClientList(TeamSpeak3_Node_Client $a, TeamSpeak3_Node_Client $b) + { + if(get_class($a) != get_class($b)) + { + return 0; + + /* workaround for PHP bug #50688 */ + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + if(!$a instanceof TeamSpeak3_Node_Client) + { + return 0; + + /* workaround for PHP bug #50688 */ + throw new TeamSpeak3_Adapter_ServerQuery_Exception("convert error", 0x604); + } + + if($a->getProperty("client_talk_power", 0) != $b->getProperty("client_talk_power", 0)) + { + return ($a->getProperty("client_talk_power", 0) > $b->getProperty("client_talk_power", 0)) ? -1 : 1; + } + + if($a->getProperty("client_is_talker", 0) != $b->getProperty("client_is_talker", 0)) + { + return ($a->getProperty("client_is_talker", 0) > $b->getProperty("client_is_talker", 0)) ? -1 : 1; + } + + return strcmp(strtolower($a["client_nickname"]), strtolower($b["client_nickname"])); + } + + /** + * Internal callback funtion for sorting of group objects. + * + * @param TeamSpeak3_Node_Abstract $a + * @param TeamSpeak3_Node_Abstract $b + * @return integer + */ + protected static function sortGroupList(TeamSpeak3_Node_Abstract $a, TeamSpeak3_Node_Abstract $b) + { + if(get_class($a) != get_class($b)) + { + return 0; + + /* workaround for PHP bug #50688 */ + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + if(!$a instanceof TeamSpeak3_Node_Servergroup && !$a instanceof TeamSpeak3_Node_Channelgroup) + { + return 0; + + /* workaround for PHP bug #50688 */ + throw new TeamSpeak3_Adapter_ServerQuery_Exception("convert error", 0x604); + } + + if($a->getProperty("sortid", 0) != $b->getProperty("sortid", 0) && $a->getProperty("sortid", 0) != 0 && $b->getProperty("sortid", 0) != 0) + { + return ($a->getProperty("sortid", 0) < $b->getProperty("sortid", 0)) ? -1 : 1; + } + + return ($a->getId() < $b->getId()) ? -1 : 1; + } + +/** + * Internal callback funtion for sorting of file list items. + * + * @param array $a + * @param array $b + * @return integer + */ + protected static function sortFileList(array $a, array $b) + { + if(!array_key_exists("src", $a) || !array_key_exists("src", $b) || !array_key_exists("type", $a) || !array_key_exists("type", $b)) + { + return 0; + + throw new TeamSpeak3_Adapter_ServerQuery_Exception("invalid parameter", 0x602); + } + + if($a["type"] != $b["type"]) + { + return ($a["type"] < $b["type"]) ? -1 : 1; + } + + return strcmp(strtolower($a["src"]), strtolower($b["src"])); + } + + /** + * Returns TRUE if the virtual server is online. + * + * @return boolean + */ + public function isOnline() + { + return ($this["virtualserver_status"] == "online") ? TRUE : FALSE; + } + + /** + * Returns TRUE if the virtual server is offline. + * + * @return boolean + */ + public function isOffline() + { + return ($this["virtualserver_status"] == "offline") ? TRUE : FALSE; + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_s" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + if($this["virtualserver_clientsonline"]-$this["virtualserver_queryclientsonline"] >= $this["virtualserver_maxclients"]) + { + return "server_full"; + } + elseif($this["virtualserver_flag_password"]) + { + return "server_pass"; + } + else + { + return "server_open"; + } + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "$"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["virtualserver_name"]; + } +} diff --git a/hidden/TeamSpeak3/Node/Servergroup.php b/hidden/TeamSpeak3/Node/Servergroup.php new file mode 100644 index 0000000..90e36a9 --- /dev/null +++ b/hidden/TeamSpeak3/Node/Servergroup.php @@ -0,0 +1,300 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Node_Servergroup + * @brief Class describing a TeamSpeak 3 server group and all it's parameters. + */ +class TeamSpeak3_Node_Servergroup extends TeamSpeak3_Node_Abstract +{ + /** + * The TeamSpeak3_Node_Servergroup constructor. + * + * @param TeamSpeak3_Node_Server $server + * @param array $info + * @param string $index + * @throws TeamSpeak3_Node_Exception + * @return TeamSpeak3_Node_Servergroup + */ + public function __construct(TeamSpeak3_Node_Server $server, array $info, $index = "sgid") + { + $this->parent = $server; + $this->nodeInfo = $info; + + if(!array_key_exists($index, $this->nodeInfo)) + { + throw new TeamSpeak3_Node_Exception("invalid groupID", 0xA00); + } + + $this->nodeId = $this->nodeInfo[$index]; + } + + /** + * Renames the server group specified. + * + * @param string $name + * @return void + */ + public function rename($name) + { + return $this->getParent()->serverGroupRename($this->getId(), $name); + } + + /** + * Deletes the server group. If $force is set to 1, the server group will be + * deleted even if there are clients within. + * + * @param boolean $force + * @return void + */ + public function delete($force = FALSE) + { + $this->getParent()->serverGroupDelete($this->getId(), $force); + + unset($this); + } + + /** + * Creates a copy of the server group and returns the new groups ID. + * + * @param string $name + * @param integer $tsgid + * @param integer $type + * @return integer + */ + public function copy($name = null, $tsgid = 0, $type = TeamSpeak3::GROUP_DBTYPE_REGULAR) + { + return $this->getParent()->serverGroupCopy($this->getId(), $name, $tsgid, $type); + } + + /** + * Returns a list of permissions assigned to the server group. + * + * @param boolean $permsid + * @return array + */ + public function permList($permsid = FALSE) + { + return $this->getParent()->serverGroupPermList($this->getId(), $permsid); + } + + /** + * Adds a set of specified permissions to the server group. Multiple permissions + * can be added by providing the four parameters of each permission in separate arrays. + * + * @param integer $permid + * @param integer $permvalue + * @param integer $permnegated + * @param integer $permskip + * @return void + */ + public function permAssign($permid, $permvalue, $permnegated = FALSE, $permskip = FALSE) + { + return $this->getParent()->serverGroupPermAssign($this->getId(), $permid, $permvalue, $permnegated, $permskip); + } + + /** + * Alias for permAssign(). + * + * @deprecated + */ + public function permAssignByName($permname, $permvalue, $permnegated = FALSE, $permskip = FALSE) + { + return $this->permAssign($permname, $permvalue, $permnegated, $permskip); + } + + /** + * Removes a set of specified permissions from the server group. Multiple + * permissions can be removed at once. + * + * @param integer $permid + * @return void + */ + public function permRemove($permid) + { + return $this->getParent()->serverGroupPermRemove($this->getId(), $permid); + } + + /** + * Alias for permRemove(). + * + * @deprecated + */ + public function permRemoveByName($permname) + { + return $this->permRemove($permname); + } + + /** + * Returns a list of clients assigned to the server group specified. + * + * @return array + */ + public function clientList() + { + return $this->getParent()->serverGroupClientList($this->getId()); + } + + /** + * Adds a client to the server group specified. Please note that a client cannot be + * added to default groups or template groups. + * + * @param integer $cldbid + * @return void + */ + public function clientAdd($cldbid) + { + return $this->getParent()->serverGroupClientAdd($this->getId(), $cldbid); + } + + /** + * Removes a client from the server group. + * + * @param integer $cldbid + * @return void + */ + public function clientDel($cldbid) + { + return $this->getParent()->serverGroupClientDel($this->getId(), $cldbid); + } + + /** + * Alias for privilegeKeyCreate(). + * + * @deprecated + */ + public function tokenCreate($description = null, $customset = null) + { + return $this->privilegeKeyCreate($description, $customset); + } + + /** + * Creates a new privilege key (token) for the server group and returns the key. + * + * @param string $description + * @param string $customset + * @return TeamSpeak3_Helper_String + */ + public function privilegeKeyCreate($description = null, $customset = null) + { + return $this->getParent()->privilegeKeyCreate(TeamSpeak3::TOKEN_SERVERGROUP, $this->getId(), 0, $description, $customset); + } + + /** + * Sends a text message to all clients residing in the server group on the virtual server. + * + * @param string $msg + * @return void + */ + public function message($msg) + { + foreach($this as $client) + { + try + { + $this->execute("sendtextmessage", array("msg" => $msg, "target" => $client, "targetmode" => TeamSpeak3::TEXTMSG_CLIENT)); + } + catch(TeamSpeak3_Adapter_ServerQuery_Exception $e) + { + /* ERROR_client_invalid_id */ + if($e->getCode() != 0x0200) throw $e; + } + } + } + + /** + * Downloads and returns the server groups icon file content. + * + * @return TeamSpeak3_Helper_String + */ + public function iconDownload() + { + if($this->iconIsLocal("iconid") || $this["iconid"] == 0) return; + + $download = $this->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->iconGetName("iconid")); + $transfer = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"]); + + return $transfer->download($download["ftkey"], $download["size"]); + } + + /** + * @ignore + */ + protected function fetchNodeList() + { + $this->nodeList = array(); + + foreach($this->getParent()->clientList() as $client) + { + if(in_array($this->getId(), explode(",", $client["client_servergroups"]))) + { + $this->nodeList[] = $client; + } + } + } + + /** + * Returns a unique identifier for the node which can be used as a HTML property. + * + * @return string + */ + public function getUniqueId() + { + return $this->getParent()->getUniqueId() . "_sg" . $this->getId(); + } + + /** + * Returns the name of a possible icon to display the node object. + * + * @return string + */ + public function getIcon() + { + return "group_server"; + } + + /** + * Returns a symbol representing the node. + * + * @return string + */ + public function getSymbol() + { + return "%"; + } + + /** + * Returns a string representation of this node. + * + * @return string + */ + public function __toString() + { + return (string) $this["name"]; + } +} + diff --git a/hidden/TeamSpeak3/TeamSpeak3.php b/hidden/TeamSpeak3/TeamSpeak3.php new file mode 100644 index 0000000..48a67fa --- /dev/null +++ b/hidden/TeamSpeak3/TeamSpeak3.php @@ -0,0 +1,981 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3 + * @brief Factory class all for TeamSpeak 3 PHP Framework objects. + */ +class TeamSpeak3 +{ + /** + * TeamSpeak 3 protocol welcome message. + */ + const READY = "TS3"; + + /** + * TeamSpeak 3 protocol greeting message prefix. + */ + const GREET = "Welcome"; + + /** + * TeamSpeak 3 protocol error message prefix. + */ + const ERROR = "error"; + + /** + * TeamSpeak 3 protocol event message prefix. + */ + const EVENT = "notify"; + + /** + * TeamSpeak 3 protocol server connection handler ID prefix. + */ + const SCHID = "selected"; + + /** + * TeamSpeak 3 PHP Framework version. + */ + const LIB_VERSION = "1.1.23"; + + /*@ + * TeamSpeak 3 protocol separators. + */ + const SEPARATOR_LINE = "\n"; //!< protocol line separator + const SEPARATOR_LIST = "|"; //!< protocol list separator + const SEPARATOR_CELL = " "; //!< protocol cell separator + const SEPARATOR_PAIR = "="; //!< protocol pair separator + + /*@ + * TeamSpeak 3 log levels. + */ + const LOGLEVEL_CRITICAL = 0x00; //!< 0: these messages stop the program + const LOGLEVEL_ERROR = 0x01; //!< 1: everything that is really bad + const LOGLEVEL_WARNING = 0x02; //!< 2: everything that might be bad + const LOGLEVEL_DEBUG = 0x03; //!< 3: output that might help find a problem + const LOGLEVEL_INFO = 0x04; //!< 4: informational output + const LOGLEVEL_DEVEL = 0x05; //!< 5: development output + + /*@ + * TeamSpeak 3 token types. + */ + const TOKEN_SERVERGROUP = 0x00; //!< 0: server group token (id1={groupID} id2=0) + const TOKEN_CHANNELGROUP = 0x01; //!< 1: channel group token (id1={groupID} id2={channelID}) + + /*@ + * TeamSpeak 3 codec identifiers. + */ + const CODEC_SPEEX_NARROWBAND = 0x00; //!< 0: speex narrowband (mono, 16bit, 8kHz) + const CODEC_SPEEX_WIDEBAND = 0x01; //!< 1: speex wideband (mono, 16bit, 16kHz) + const CODEC_SPEEX_ULTRAWIDEBAND = 0x02; //!< 2: speex ultra-wideband (mono, 16bit, 32kHz) + const CODEC_CELT_MONO = 0x03; //!< 3: celt mono (mono, 16bit, 48kHz) + const CODEC_OPUS_VOICE = 0x04; //!< 3: opus voice (interactive) + const CODEC_OPUS_MUSIC = 0x05; //!< 3: opus music (interactive) + + /*@ + * TeamSpeak 3 codec encryption modes. + */ + const CODEC_CRYPT_INDIVIDUAL = 0x00; //!< 0: configure per channel + const CODEC_CRYPT_DISABLED = 0x01; //!< 1: globally disabled + const CODEC_CRYPT_ENABLED = 0x02; //!< 2: globally enabled + + /*@ + * TeamSpeak 3 kick reason types. + */ + const KICK_CHANNEL = 0x04; //!< 4: kick client from channel + const KICK_SERVER = 0x05; //!< 5: kick client from server + + /*@ + * TeamSpeak 3 text message target modes. + */ + const TEXTMSG_CLIENT = 0x01; //!< 1: target is a client + const TEXTMSG_CHANNEL = 0x02; //!< 2: target is a channel + const TEXTMSG_SERVER = 0x03; //!< 3: target is a virtual server + + /*@ + * TeamSpeak 3 plugin command target modes. + */ + const PLUGINCMD_CHANNEL = 0x01; //!< 1: send plugincmd to all clients in current channel + const PLUGINCMD_SERVER = 0x02; //!< 2: send plugincmd to all clients on server + const PLUGINCMD_CLIENT = 0x03; //!< 3: send plugincmd to all given client ids + const PLUGINCMD_CHANNEL_SUBSCRIBED = 0x04; //!< 4: send plugincmd to all subscribed clients in current channel + + /*@ + * TeamSpeak 3 host message modes. + */ + const HOSTMSG_NONE = 0x00; //!< 0: display no message + const HOSTMSG_LOG = 0x01; //!< 1: display message in chatlog + const HOSTMSG_MODAL = 0x02; //!< 2: display message in modal dialog + const HOSTMSG_MODALQUIT = 0x03; //!< 3: display message in modal dialog and close connection + + /*@ + * TeamSpeak 3 host banner modes. + */ + const HOSTBANNER_NO_ADJUST = 0x00; //!< 0: do not adjust + const HOSTBANNER_IGNORE_ASPECT = 0x01; //!< 1: adjust but ignore aspect ratio + const HOSTBANNER_KEEP_ASPECT = 0x02; //!< 2: adjust and keep aspect ratio + + /*@ + * TeamSpeak 3 client identification types. + */ + const CLIENT_TYPE_REGULAR = 0x00; //!< 0: regular client + const CLIENT_TYPE_SERVERQUERY = 0x01; //!< 1: query client + + /*@ + * TeamSpeak 3 permission group database types. + */ + const GROUP_DBTYPE_TEMPLATE = 0x00; //!< 0: template group (used for new virtual servers) + const GROUP_DBTYPE_REGULAR = 0x01; //!< 1: regular group (used for regular clients) + const GROUP_DBTYPE_SERVERQUERY = 0x02; //!< 2: global query group (used for ServerQuery clients) + + /*@ + * TeamSpeak 3 permission group name modes. + */ + const GROUP_NAMEMODE_HIDDEN = 0x00; //!< 0: display no name + const GROUP_NAMEMODE_BEFORE = 0x01; //!< 1: display name before client nickname + const GROUP_NAMEMODE_BEHIND = 0x02; //!< 2: display name after client nickname + + /*@ + * TeamSpeak 3 permission group identification types. + */ + const GROUP_IDENTIFIY_STRONGEST = 0x01; //!< 1: identify most powerful group + const GROUP_IDENTIFIY_WEAKEST = 0x02; //!< 2: identify weakest group + + /*@ + * TeamSpeak 3 permission types. + */ + const PERM_TYPE_SERVERGROUP = 0x00; //!< 0: server group permission + const PERM_TYPE_CLIENT = 0x01; //!< 1: client specific permission + const PERM_TYPE_CHANNEL = 0x02; //!< 2: channel specific permission + const PERM_TYPE_CHANNELGROUP = 0x03; //!< 3: channel group permission + const PERM_TYPE_CHANNELCLIENT = 0x04; //!< 4: channel-client specific permission + + /*@ + * TeamSpeak 3 permission categories. + */ + const PERM_CAT_GLOBAL = 0x10; //!< 00010000: global permissions + const PERM_CAT_GLOBAL_INFORMATION = 0x11; //!< 00010001: global permissions -> global information + const PERM_CAT_GLOBAL_SERVER_MGMT = 0x12; //!< 00010010: global permissions -> virtual server management + const PERM_CAT_GLOBAL_ADM_ACTIONS = 0x13; //!< 00010011: global permissions -> global administrative actions + const PERM_CAT_GLOBAL_SETTINGS = 0x14; //!< 00010100: global permissions -> global settings + const PERM_CAT_SERVER = 0x20; //!< 00100000: virtual server permissions + const PERM_CAT_SERVER_INFORMATION = 0x21; //!< 00100001: virtual server permissions -> virtual server information + const PERM_CAT_SERVER_ADM_ACTIONS = 0x22; //!< 00100010: virtual server permissions -> virtual server administrative actions + const PERM_CAT_SERVER_SETTINGS = 0x23; //!< 00100011: virtual server permissions -> virtual server settings + const PERM_CAT_CHANNEL = 0x30; //!< 00110000: channel permissions + const PERM_CAT_CHANNEL_INFORMATION = 0x31; //!< 00110001: channel permissions -> channel information + const PERM_CAT_CHANNEL_CREATE = 0x32; //!< 00110010: channel permissions -> create channels + const PERM_CAT_CHANNEL_MODIFY = 0x33; //!< 00110011: channel permissions -> edit channels + const PERM_CAT_CHANNEL_DELETE = 0x34; //!< 00110100: channel permissions -> delete channels + const PERM_CAT_CHANNEL_ACCESS = 0x35; //!< 00110101: channel permissions -> access channels + const PERM_CAT_GROUP = 0x40; //!< 01000000: group permissions + const PERM_CAT_GROUP_INFORMATION = 0x41; //!< 01000001: group permissions -> group information + const PERM_CAT_GROUP_CREATE = 0x42; //!< 01000010: group permissions -> create groups + const PERM_CAT_GROUP_MODIFY = 0x43; //!< 01000011: group permissions -> edit groups + const PERM_CAT_GROUP_DELETE = 0x44; //!< 01000100: group permissions -> delete groups + const PERM_CAT_CLIENT = 0x50; //!< 01010000: client permissions + const PERM_CAT_CLIENT_INFORMATION = 0x51; //!< 01010001: client permissions -> client information + const PERM_CAT_CLIENT_ADM_ACTIONS = 0x52; //!< 01010010: client permissions -> client administrative actions + const PERM_CAT_CLIENT_BASICS = 0x53; //!< 01010011: client permissions -> client basic communication + const PERM_CAT_CLIENT_MODIFY = 0x54; //!< 01010100: client permissions -> edit clients + const PERM_CAT_FILETRANSFER = 0x60; //!< 01100000: file transfer permissions + const PERM_CAT_NEEDED_MODIFY_POWER = 0xFF; //!< 11111111: needed permission modify power (grant) permissions + + /*@ + * TeamSpeak 3 file types. + */ + const FILE_TYPE_DIRECTORY = 0x00; //!< 0: file is directory + const FILE_TYPE_REGULAR = 0x01; //!< 1: file is regular + + /*@ + * TeamSpeak 3 server snapshot types. + */ + const SNAPSHOT_STRING = 0x00; //!< 0: default string + const SNAPSHOT_BASE64 = 0x01; //!< 1: base64 string + const SNAPSHOT_HEXDEC = 0x02; //!< 2: hexadecimal string + + /*@ + * TeamSpeak 3 channel spacer types. + */ + const SPACER_SOLIDLINE = 0x00; //!< 0: solid line + const SPACER_DASHLINE = 0x01; //!< 1: dash line + const SPACER_DOTLINE = 0x02; //!< 2: dot line + const SPACER_DASHDOTLINE = 0x03; //!< 3: dash dot line + const SPACER_DASHDOTDOTLINE = 0x04; //!< 4: dash dot dot line + const SPACER_CUSTOM = 0x05; //!< 5: custom format + + /*@ + * TeamSpeak 3 channel spacer alignments. + */ + const SPACER_ALIGN_LEFT = 0x00; //!< 0: alignment left + const SPACER_ALIGN_RIGHT = 0x01; //!< 1: alignment right + const SPACER_ALIGN_CENTER = 0x02; //!< 2: alignment center + const SPACER_ALIGN_REPEAT = 0x03; //!< 3: repeat until the whole line is filled + + /*@ + * TeamSpeak 3 reason identifiers. + */ + const REASON_NONE = 0x00; //!< 0: no reason + const REASON_MOVE = 0x01; //!< 1: channel switched or moved + const REASON_SUBSCRIPTION = 0x02; //!< 2: subscription added or removed + const REASON_TIMEOUT = 0x03; //!< 3: client connection timed out + const REASON_CHANNEL_KICK = 0x04; //!< 4: client kicked from channel + const REASON_SERVER_KICK = 0x05; //!< 5: client kicked from server + const REASON_SERVER_BAN = 0x06; //!< 6: client banned from server + const REASON_SERVER_STOP = 0x07; //!< 7: server stopped + const REASON_DISCONNECT = 0x08; //!< 8: client disconnected + const REASON_CHANNEL_UPDATE = 0x09; //!< 9: channel information updated + const REASON_CHANNEL_EDIT = 0x0A; //!< 10: channel information edited + const REASON_DISCONNECT_SHUTDOWN = 0x0B; //!< 11: client disconnected on server shutdown + + /** + * Stores an array containing various chars which need to be escaped while communicating + * with a TeamSpeak 3 Server. + * + * @var array + */ + protected static $escape_patterns = array( + "\\" => "\\\\", // backslash + "/" => "\\/", // slash + " " => "\\s", // whitespace + "|" => "\\p", // pipe + ";" => "\\;", // semicolon + "\a" => "\\a", // bell + "\b" => "\\b", // backspace + "\f" => "\\f", // formfeed + "\n" => "\\n", // newline + "\r" => "\\r", // carriage return + "\t" => "\\t", // horizontal tab + "\v" => "\\v" // vertical tab + ); + + /** + * Factory for TeamSpeak3_Adapter_Abstract classes. $uri must be formatted as + * "://:@:/#". All parameters + * except adapter, host and port are optional. + * + * === Supported Options === + * - timeout + * - blocking + * - nickname + * - no_query_clients + * - use_offline_as_virtual + * - clients_before_channels + * - server_id|server_uid|server_port|server_name|server_tsdns + * - channel_id|channel_name + * - client_id|client_uid|client_name + * + * === Supported Flags (only one per $uri) === + * - no_query_clients + * - use_offline_as_virtual + * - clients_before_channels + * + * === URI Examples === + * - serverquery://127.0.0.1:10011/ + * - serverquery://127.0.0.1:10011/?server_port=9987&channel_id=1 + * - serverquery://127.0.0.1:10011/?server_port=9987&channel_id=1#no_query_clients + * - serverquery://127.0.0.1:10011/?server_port=9987&client_name=ScP + * - filetransfer://127.0.0.1:30011/ + * - blacklist + * - update + * + * @param string $uri + * @return TeamSpeak3_Adapter_Abstract + * @return TeamSpeak3_Node_Abstract + */ + public static function factory($uri) + { + self::init(); + + $uri = new TeamSpeak3_Helper_Uri($uri); + + $adapter = self::getAdapterName($uri->getScheme()); + $options = array("host" => $uri->getHost(), "port" => $uri->getPort(), "timeout" => intval($uri->getQueryVar("timeout", 10)), "blocking" => intval($uri->getQueryVar("blocking", 1))); + + self::loadClass($adapter); + + $object = new $adapter($options); + + if($object instanceof TeamSpeak3_Adapter_ServerQuery) + { + $node = $object->getHost(); + + if($uri->hasUser() && $uri->hasPass()) + { + $node->login($uri->getUser(), $uri->getPass()); + } + + /* option to pre-define nickname */ + if($uri->hasQueryVar("nickname")) + { + $node->setPredefinedQueryName($uri->getQueryVar("nickname")); + } + + /* flag to use offline servers in virtual mode */ + if($uri->getFragment() == "use_offline_as_virtual") + { + $node->setUseOfflineAsVirtual(TRUE); + } + elseif($uri->hasQueryVar("use_offline_as_virtual")) + { + $node->setUseOfflineAsVirtual($uri->getQueryVar("use_offline_as_virtual") ? TRUE : FALSE); + } + + /* flag to fetch clients before sub-channels */ + if($uri->getFragment() == "clients_before_channels") + { + $node->setLoadClientlistFirst(TRUE); + } + elseif($uri->hasQueryVar("clients_before_channels")) + { + $node->setLoadClientlistFirst($uri->getQueryVar("clients_before_channels") ? TRUE : FALSE); + } + + /* flag to hide ServerQuery clients */ + if($uri->getFragment() == "no_query_clients") + { + $node->setExcludeQueryClients(TRUE); + } + elseif($uri->hasQueryVar("no_query_clients")) + { + $node->setExcludeQueryClients($uri->getQueryVar("no_query_clients") ? TRUE : FALSE); + } + + /* access server node object */ + if($uri->hasQueryVar("server_id")) + { + $node = $node->serverGetById($uri->getQueryVar("server_id")); + } + elseif($uri->hasQueryVar("server_uid")) + { + $node = $node->serverGetByUid($uri->getQueryVar("server_uid")); + } + elseif($uri->hasQueryVar("server_port")) + { + $node = $node->serverGetByPort($uri->getQueryVar("server_port")); + } + elseif($uri->hasQueryVar("server_name")) + { + $node = $node->serverGetByName($uri->getQueryVar("server_name")); + } + elseif($uri->hasQueryVar("server_tsdns")) + { + $node = $node->serverGetByTSDNS($uri->getQueryVar("server_tsdns")); + } + + /* direct access to node objects */ + if($node instanceof TeamSpeak3_Node_Server) + { + /* access channel node object */ + if($uri->hasQueryVar("channel_id")) + { + $node = $node->channelGetById($uri->getQueryVar("channel_id")); + } + elseif($uri->hasQueryVar("channel_name")) + { + $node = $node->channelGetByName($uri->getQueryVar("channel_name")); + } + + /* access client node object */ + if($uri->hasQueryVar("client_id")) + { + $node = $node->clientGetById($uri->getQueryVar("client_id")); + } + if($uri->hasQueryVar("client_uid")) + { + $node = $node->clientGetByUid($uri->getQueryVar("client_uid")); + } + elseif($uri->hasQueryVar("client_name")) + { + $node = $node->clientGetByName($uri->getQueryVar("client_name")); + } + } + + return $node; + } + + return $object; + } + + /** + * Loads a class from a PHP file. The filename must be formatted as "$class.php". + * + * include() is not prefixed with the @ operator because if the file is loaded and + * contains a parse error, execution will halt silently and this is difficult to debug. + * + * @param string $class + * @throws LogicException + * @return boolean + */ + protected static function loadClass($class) + { + if(class_exists($class, FALSE) || interface_exists($class, FALSE)) + { + return; + } + + if(preg_match("/[^a-z0-9\\/\\\\_.-]/i", $class)) + { + throw new LogicException("illegal characters in classname '" . $class . "'"); + } + + $file = self::getFilePath($class) . ".php"; + + if(!file_exists($file) || !is_readable($file)) + { + throw new LogicException("file '" . $file . "' does not exist or is not readable"); + } + + if(class_exists($class, FALSE) || interface_exists($class, FALSE)) + { + throw new LogicException("class '" . $class . "' does not exist"); + } + + return include_once($file); + } + + /** + * Generates a possible file path for $name. + * + * @param string $name + * @return string + */ + protected static function getFilePath($name) + { + $path = str_replace("_", DIRECTORY_SEPARATOR, $name); + $path = str_replace(__CLASS__, dirname(__FILE__), $path); + + return $path; + } + + /** + * Returns the name of an adapter class by $name. + * + * @param string $name + * @param string $namespace + * @throws TeamSpeak3_Adapter_Exception + * @return string + */ + protected static function getAdapterName($name, $namespace = "TeamSpeak3_Adapter_") + { + $path = self::getFilePath($namespace); + $scan = scandir($path); + + foreach($scan as $node) + { + $file = TeamSpeak3_Helper_String::factory($node)->toLower(); + + if($file->startsWith($name) && $file->endsWith(".php")) + { + return $namespace . str_replace(".php", "", $node); + } + } + + throw new TeamSpeak3_Adapter_Exception("adapter '" . $name . "' does not exist"); + } + + /** + * spl_autoload() suitable implementation for supporting class autoloading. + * + * @param string $class + * @return boolean + */ + public static function autoload($class) + { + if(substr($class, 0, strlen(__CLASS__)) != __CLASS__) return; + + try + { + self::loadClass($class); + + return TRUE; + } + catch(Exception $e) + { + return FALSE; + } + } + + /** + * Checks for required PHP features, enables autoloading and starts a default profiler. + * + * @throws LogicException + * @return void + */ + public static function init() + { + if(version_compare(phpversion(), "5.2.1") == -1) + { + throw new LogicException("this particular software cannot be used with the installed version of PHP"); + } + + if(!function_exists("stream_socket_client")) + { + throw new LogicException("network functions are not available in this PHP installation"); + } + + if(!function_exists("spl_autoload_register")) + { + throw new LogicException("autoload functions are not available in this PHP installation"); + } + + if(!class_exists("TeamSpeak3_Helper_Profiler")) + { + spl_autoload_register(array(__CLASS__, "autoload")); + } + + TeamSpeak3_Helper_Profiler::start(); + } + + /** + * Returns an assoc array containing all escape patterns available on a TeamSpeak 3 + * Server. + * + * @return array + */ + public static function getEscapePatterns() + { + return self::$escape_patterns; + } + + /** + * Debug helper function. This is a wrapper for var_dump() that adds the pre-format tags, + * cleans up newlines and indents, and runs htmlentities() before output. + * + * @param mixed $var + * @param bool $echo + * @return string + */ + public static function dump($var, $echo = TRUE) + { + ob_start(); + var_dump($var); + + $output = ob_get_clean(); + $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output); + + if(PHP_SAPI == "cli") + { + $output = PHP_EOL . PHP_EOL . $output . PHP_EOL; + } + else + { + $output = "
" . htmlspecialchars($output, ENT_QUOTES) . "
"; + } + + if($echo) echo($output); + + return $output; + } +} + +/*! + * \mainpage API Documentation + * + * \section welcome_sec Introduction + * + * \subsection welcome1 What is the TS3 PHP Framework? + * Initially released in January 2010, the TS3 PHP Framework is a powerful, open source, object-oriented framework + * implemented in PHP 5 and licensed under the GNU General Public License. It's based on simplicity and a rigorously + * tested agile codebase. Extend the functionality of your servers with scripts or create powerful web applications + * to manage all features of your TeamSpeak 3 Server instances. + * + * Tested. Thoroughly. Enterprise-ready and built with agile methods, the TS3 PHP Framework has been unit-tested from + * the start to ensure that all code remains stable and easy for you to extend, re-test with your extensions, and + * further maintain. + * + * \subsection welcome2 Why should I use the TS3 PHP Framework rather than other PHP libraries? + * The TS3 PHP Framework is a is a modern use-at-will framework that provides individual components to communicate + * with the TeamSpeak 3 Server. + * + * There are lots of arguments for the TS3 PHP Framework in comparison with other PHP based libraries. It is the most + * dynamic and feature-rich piece of software in its class. In addition, it's always up-to-date and 100% compatible to + * almost any TeamSpeak 3 Server version available. + * + * \section sysreqs_sec Requirements + * The TS3 PHP Framework currently supports PHP 5.2.1 or later, but we strongly recommend the most current release of + * PHP for critical security and performance enhancements. If you want to create a web application using the TS3 PHP + * Framework, you need a PHP 5 interpreter with a web server configured to handle PHP scripts correctly. + * + * Note that the majority of TS3 PHP Framework development and deployment is done on nginx, so there is more community + * experience and testing performed on nginx than on other web servers. + * + * \section feature_sec Features + * Features of the TS3 PHP Framework include: + * + * - Fully object-oriented PHP 5 and E_STRICT compliant components + * - Access to all TeamSpeak 3 Server features via ServerQuery + * - Integrated full featured and customizable TSViewer interfaces + * - Full support for file transfers to up- and /or download custom icons and other stuff + * - Powerful error handling capablities using exceptions and customizable error messages + * - Query mechanisms for several official services such as the blacklist and auto-update servers + * - Dynamic signal slots for event based scripting + * - ... + * + * \section example_sec Usage Examples + * + * \subsection example1 1. Kick a single Client from a Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // kick the client with ID 123 from the server + * $ts3_VirtualServer->clientKick(123, TeamSpeak3::KICK_SERVER, "evil kick XD"); + * + * // spawn an object for the client by unique identifier and do the kick + * $ts3_VirtualServer->clientGetByUid("FPMPSC6MXqXq751dX7BKV0JniSo=")->kick(TeamSpeak3::KICK_SERVER, "evil kick XD"); + * + * // spawn an object for the client by current nickname and do the kick + * $ts3_VirtualServer->clientGetByName("ScP")->kick(TeamSpeak3::KICK_SERVER, "evil kick XD"); + * @endcode + * + * \subsection example2 2. Kick all Clients from a Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // query clientlist from virtual server + * $arr_ClientList = $ts3_VirtualServer->clientList(); + * + * // kick all clients online with a single command + * $ts3_VirtualServer->clientKick($arr_ClientList, TeamSpeak3::KICK_SERVER, "evil kick XD"); + * @endcode + * + * \subsection example3 3. Print the Nicknames of connected Android Clients + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // query clientlist from virtual server and filter by platform + * $arr_ClientList = $ts3_VirtualServer->clientList(array("client_platform" => "Android")); + * + * // walk through list of clients + * foreach($arr_ClientList as $ts3_Client) + * { + * echo $ts3_Client . " is using " . $ts3_Client["client_platform"] . "
\n"; + * } + * @endcode + * + * \subsection example4 4. Modify the Settings of each Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the server instance + * $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/"); + * + * // walk through list of virtual servers + * foreach($ts3_ServerInstance as $ts3_VirtualServer) + * { + * // modify the virtual servers hostbanner URL only using the ArrayAccess interface + * $ts3_VirtualServer["virtualserver_hostbanner_gfx_url"] = "http://www.example.com/banners/banner01_468x60.jpg"; + * + * // modify the virtual servers hostbanner URL only using property overloading + * $ts3_VirtualServer->virtualserver_hostbanner_gfx_url = "http://www.example.com/banners/banner01_468x60.jpg"; + * + * // modify multiple virtual server properties at once + * $ts3_VirtualServer->modify(array( + * "virtualserver_hostbutton_tooltip" => "My Company", + * "virtualserver_hostbutton_url" => "http://www.example.com", + * "virtualserver_hostbutton_gfx_url" => "http://www.example.com/buttons/button01_24x24.jpg", + * )); + * } + * @endcode + * + * \subsection example5 5. Create a Privilege Key for a Server Group + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // spawn an object for the group using a specified name + * $arr_ServerGroup = $ts3_VirtualServer->serverGroupGetByName("Admins"); + * + * // create the privilege key + * $ts3_PrivilegeKey = $arr_ServerGroup->privilegeKeyCreate(); + * @endcode + * + * \subsection example6 6. Modify the Permissions of Admins on each Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the server instance + * $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/"); + * + * // walk through list of virtual servers + * foreach($ts3_ServerInstance as $ts3_VirtualServer) + * { + * // identify the most powerful group on the virtual server + * $ts3_ServerGroup = $ts3_VirtualServer->serverGroupIdentify(); + * + * // assign a new permission + * $ts3_ServerGroup->permAssign("b_virtualserver_modify_hostbanner", TRUE); + * + * // revoke an existing permission + * $ts3_ServerGroup->permRemove("b_virtualserver_modify_maxclients"); + * } + * @endcode + * + * \subsection example7 7. Create a new Virtual Server + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the server instance + * $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/"); + * + * // create a virtual server and get its ID + * $new_sid = $ts3_ServerInstance->serverCreate(array( + * "virtualserver_name" => "My TeamSpeak 3 Server", + * "virtualserver_maxclients" => 64, + * "virtualserver_hostbutton_tooltip" => "My Company", + * "virtualserver_hostbutton_url" => "http://www.example.com", + * "virtualserver_hostbutton_gfx_url" => "http://www.example.com/buttons/button01_24x24.jpg", + * )); + * @endcode + * + * \subsection example8 8. Create a hierarchical Channel Stucture + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // create a top-level channel and get its ID + * $top_cid = $ts3_VirtualServer->channelCreate(array( + * "channel_name" => "My Channel", + * "channel_topic" => "This is a top-level channel", + * "channel_codec" => TeamSpeak3::CODEC_SPEEX_WIDEBAND, + * "channel_flag_permanent" => TRUE, + * )); + * + * // create a sub-level channel and get its ID + * $sub_cid = $ts3_VirtualServer->channelCreate(array( + * "channel_name" => "My Sub-Channel", + * "channel_topic" => "This is a sub-level channel", + * "channel_codec" => TeamSpeak3::CODEC_SPEEX_NARROWBAND, + * "channel_flag_permanent" => TRUE, + * "cpid" => $top_cid, + * )); + * @endcode + * + * \subsection example9 9. Send a Text Message to outdated Clients + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // connect to default update server + * $ts3_UpdateServer = TeamSpeak3::factory("update"); + * + * // walk through list of clients on virtual server + * foreach($ts3_VirtualServer->clientList() as $ts3_Client) + * { + * // skip query clients + * if($ts3_Client["client_type"]) continue; + * + * // send test message if client build is outdated + * if($ts3_Client->getRev() < $ts3_UpdateServer->getClientRev()) + * { + * $ts3_Client->message("[COLOR=red]your client is [B]outdated[/B]... update to [U]" . $ts3_UpdateServer->getClientVersion() . "[/U] now![/COLOR]"); + * } + * } + * @endcode + * + * \subsection example10 10. Check if the Server Instance is Outdated or Blacklisted + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the server instance + * $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/"); + * + * // connect to default update server + * $ts3_UpdateServer = TeamSpeak3::factory("update"); + * + * // send global text message if the server is outdated + * if($ts3_ServerInstance->version("build") < $ts3_UpdateServer->getServerRev()) + * { + * $ts3_ServerInstance->message("[COLOR=red]your server is [B]outdated[/B]... update to [U]" . $ts3_UpdateServer->getServerVersion() . "[/U] now![/COLOR]"); + * } + * + * // connect to default blacklist server + * $ts3_BlacklistServer = TeamSpeak3::factory("blacklist"); + * + * // send global text message if the server is blacklisted + * if($ts3_BlacklistServer->isBlacklisted($ts3_ServerInstance)) + * { + * $ts3_ServerInstance->message("[COLOR=red]your server is [B]blacklisted[/B]... disconnect now![/COLOR]"); + * } + * @endcode + * + * \subsection example11 11. Create a simple TSViewer for your Website + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // build and display HTML treeview using custom image paths (remote icons will be embedded using data URI sheme) + * echo $ts3_VirtualServer->getViewer(new TeamSpeak3_Viewer_Html("images/viewericons/", "images/countryflags/", "data:image")); + * @endcode + * + * \subsection example12 12. Update all outdated Audio Codecs to their Opus equivalent + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // walk through list of chanels + * foreach($ts3_VirtualServer->channelList() as $ts3_Channel) + * { + * if($ts3_Channel["channel_codec"] == TeamSpeak3::CODEC_CELT_MONO) + * { + * $ts3_Channel["channel_codec"] = TeamSpeak3::CODEC_OPUS_MUSIC; + * } + * elseif($ts3_Channel["channel_codec"] != TeamSpeak3::CODEC_OPUS_MUSIC) + * { + * $ts3_Channel["channel_codec"] = TeamSpeak3::CODEC_OPUS_VOICE; + * } + * } + * @endcode + * + * \subsection example13 13. Display the Avatar of a connected User + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // spawn an object for the client using a specified nickname + * $ts3_Client = $ts3_VirtualServer->clientGetByName("John Doe"); + * + * // download the clients avatar file + * $avatar = $ts3_Client->avatarDownload(); + * + * // send header and display image + * header("Content-Type: " . TeamSpeak3_Helper_Convert::imageMimeType($avatar)); + * echo $avatar; + * @endcode + * + * \subsection example14 14. Create a Simple Bot waiting for Events + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // connect to local server in non-blocking mode, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987&blocking=0"); + * + * // get notified on incoming private messages + * $ts3_VirtualServer->notifyRegister("textprivate"); + * + * // register a callback for notifyTextmessage events + * TeamSpeak3_Helper_Signal::getInstance()->subscribe("notifyTextmessage", "onTextmessage"); + * + * // wait for events + * while(1) $ts3_VirtualServer->getAdapter()->wait(); + * + * // define a callback function + * function onTextmessage(TeamSpeak3_Adapter_ServerQuery_Event $event, TeamSpeak3_Node_Host $host) + * { + * echo "Client " . $event["invokername"] . " sent textmessage: " . $event["msg"]; + * } + * @endcode + * + * \subsection example15 15. Handle Errors using Exceptions and Custom Error Messages + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // register custom error message (supported placeholders are: %file, %line, %code and %mesg) + * TeamSpeak3_Exception::registerCustomMessage(0x300, "The specified channel does not exist; server said: %mesg"); + * + * try + * { + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // spawn an object for the channel using a specified name + * $ts3_Channel = $ts3_VirtualServer->channelGetByName("I do not exist"); + * } + * catch(TeamSpeak3_Exception $e) + * { + * // print the error message returned by the server + * echo "Error " . $e->getCode() . ": " . $e->getMessage(); + * } + * @endcode + * + * \subsection example16 16. Save Connection State in Persistent Session Variable + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // start a PHP session + * session_start(); + * + * // connect to local server, authenticate and spawn an object for the virtual server on port 9987 + * $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987"); + * + * // save connection state (including login and selected virtual server) + * $_SESSION["_TS3"] = serialize($ts3_VirtualServer); + * @endcode + * + * \subsection example17 17. Restore Connection State from Persistent Session Variable + * @code + * // load framework files + * require_once("libraries/TeamSpeak3/TeamSpeak3.php"); + * + * // start a PHP session + * session_start(); + * + * // restore connection state + * $ts3_VirtualServer = unserialize($_SESSION["_TS3"]); + * + * // send a text message to the server + * $ts3_VirtualServer->message("Hello World!"); + * @endcode + * + * Speed up new development and reduce maintenance costs by using the TS3 PHP Framework! + */ diff --git a/hidden/TeamSpeak3/Transport/Abstract.php b/hidden/TeamSpeak3/Transport/Abstract.php new file mode 100644 index 0000000..77f13c5 --- /dev/null +++ b/hidden/TeamSpeak3/Transport/Abstract.php @@ -0,0 +1,268 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Transport_Abstract + * @brief Abstract class for connecting to a TeamSpeak 3 Server through different ways of transport. + */ +abstract class TeamSpeak3_Transport_Abstract +{ + /** + * Stores user-provided configuration settings. + * + * @var array + */ + protected $config = null; + + /** + * Stores the stream resource of the connection. + * + * @var resource + */ + protected $stream = null; + + /** + * Stores the TeamSpeak3_Adapter_Abstract object using this transport. + * + * @var TeamSpeak3_Adapter_Abstract + */ + protected $adapter = null; + + /** + * The TeamSpeak3_Transport_Abstract constructor. + * + * @param array $config + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Transport_Abstract + */ + public function __construct(array $config) + { + if(!array_key_exists("host", $config)) + { + throw new TeamSpeak3_Transport_Exception("config must have a key for 'host' which specifies the server host name"); + } + + if(!array_key_exists("port", $config)) + { + throw new TeamSpeak3_Transport_Exception("config must have a key for 'port' which specifies the server port number"); + } + + if(!array_key_exists("timeout", $config)) + { + $config["timeout"] = 10; + } + + if(!array_key_exists("blocking", $config)) + { + $config["blocking"] = 1; + } + + $this->config = $config; + } + + /** + * Commit pending data. + * + * @return array + */ + public function __sleep() + { + return array("config"); + } + + /** + * Reconnects to the remote server. + * + * @return void + */ + public function __wakeup() + { + $this->connect(); + } + + /** + * The TeamSpeak3_Transport_Abstract destructor. + * + * @return void + */ + public function __destruct() + { + if($this->adapter instanceof TeamSpeak3_Adapter_Abstract) + { + $this->adapter->__destruct(); + } + + $this->disconnect(); + } + + /** + * Connects to a remote server. + * + * @throws TeamSpeak3_Transport_Exception + * @return void + */ + abstract public function connect(); + + /** + * Disconnects from a remote server. + * + * @return void + */ + abstract public function disconnect(); + + /** + * Reads data from the stream. + * + * @param integer $length + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Helper_String + */ + abstract public function read($length = 4096); + + /** + * Writes data to the stream. + * + * @param string $data + * @return void + */ + abstract public function send($data); + + /** + * Returns the underlying stream resource. + * + * @return resource + */ + public function getStream() + { + return $this->stream; + } + + /** + * Returns the configuration variables in this adapter. + * + * @param string $key + * @param mixed $default + * @return array + */ + public function getConfig($key = null, $default = null) + { + if($key !== null) + { + return array_key_exists($key, $this->config) ? $this->config[$key] : $default; + } + + return $this->config; + } + + /** + * Sets the TeamSpeak3_Adapter_Abstract object using this transport. + * + * @param TeamSpeak3_Adapter_Abstract $adapter + * @return void + */ + public function setAdapter(TeamSpeak3_Adapter_Abstract $adapter) + { + $this->adapter = $adapter; + } + + /** + * Returns the TeamSpeak3_Adapter_Abstract object using this transport. + * + * @return TeamSpeak3_Adapter_Abstract + */ + public function getAdapter() + { + return $this->adapter; + } + + /** + * Returns the adapter type. + * + * @return string + */ + public function getAdapterType() + { + if($this->adapter instanceof TeamSpeak3_Adapter_Abstract) + { + $string = TeamSpeak3_Helper_String::factory(get_class($this->adapter)); + + return $string->substr($string->findLast("_"))->replace(array("_", " "), "")->toString(); + } + + return "Unknown"; + } + + /** + * Returns header/meta data from stream pointer. + * + * @throws TeamSpeak3_Transport_Exception + * @return array + */ + public function getMetaData() + { + if($this->stream === null) + { + throw new TeamSpeak3_Transport_Exception("unable to retrieve header/meta data from stream pointer"); + } + + return stream_get_meta_data($this->stream); + } + + /** + * Returns TRUE if the transport is connected. + * + * @return boolean + */ + public function isConnected() + { + return (is_resource($this->stream)) ? TRUE : FALSE; + } + + /** + * Blocks a stream until data is available for reading if the stream is connected + * in non-blocking mode. + * + * @param integer $time + * @return void + */ + protected function waitForReadyRead($time = 0) + { + if(!$this->isConnected() || $this->config["blocking"]) return; + + do { + $read = array($this->stream); + $null = null; + + if($time) + { + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "WaitTimeout", $time, $this->getAdapter()); + } + + $time = $time+$this->config["timeout"]; + } while(@stream_select($read, $null, $null, $this->config["timeout"]) == 0); + } +} diff --git a/hidden/TeamSpeak3/Transport/Exception.php b/hidden/TeamSpeak3/Transport/Exception.php new file mode 100644 index 0000000..09cbb1f --- /dev/null +++ b/hidden/TeamSpeak3/Transport/Exception.php @@ -0,0 +1,32 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Transport_Exception + * @brief Enhanced exception class for TeamSpeak3_Transport_Abstract objects. + */ +class TeamSpeak3_Transport_Exception extends TeamSpeak3_Exception {} diff --git a/hidden/TeamSpeak3/Transport/TCP.php b/hidden/TeamSpeak3/Transport/TCP.php new file mode 100644 index 0000000..c29e90e --- /dev/null +++ b/hidden/TeamSpeak3/Transport/TCP.php @@ -0,0 +1,179 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Transport_TCP + * @brief Class for connecting to a remote server through TCP. + */ +class TeamSpeak3_Transport_TCP extends TeamSpeak3_Transport_Abstract +{ + /** + * Connects to a remote server. + * + * @throws TeamSpeak3_Transport_Exception + * @return void + */ + public function connect() + { + if($this->stream !== null) return; + + $host = strval($this->config["host"]); + $port = strval($this->config["port"]); + + $address = "tcp://" . $host . ":" . $port; + $timeout = intval($this->config["timeout"]); + + $this->stream = @stream_socket_client($address, $errno, $errstr, $timeout); + + if($this->stream === FALSE) + { + throw new TeamSpeak3_Transport_Exception(TeamSpeak3_Helper_String::factory($errstr)->toUtf8()->toString(), $errno); + } + + @stream_set_timeout($this->stream, $timeout); + @stream_set_blocking($this->stream, $this->config["blocking"] ? 1 : 0); + } + + /** + * Disconnects from a remote server. + * + * @return void + */ + public function disconnect() + { + if($this->stream === null) return; + + $this->stream = null; + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "Disconnected"); + } + + /** + * Reads data from the stream. + * + * @param integer $length + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Helper_String + */ + public function read($length = 4096) + { + $this->connect(); + $this->waitForReadyRead(); + + $data = @stream_get_contents($this->stream, $length); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataRead", $data); + + if($data === FALSE) + { + throw new TeamSpeak3_Transport_Exception("connection to server '" . $this->config["host"] . ":" . $this->config["port"] . "' lost"); + } + + return new TeamSpeak3_Helper_String($data); + } + + /** + * Reads a single line of data from the stream. + * + * @param string $token + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Helper_String + */ + public function readLine($token = "\n") + { + $this->connect(); + + $line = TeamSpeak3_Helper_String::factory(""); + + while(!$line->endsWith($token)) + { + $this->waitForReadyRead(); + + $data = @fgets($this->stream, 4096); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataRead", $data); + + if($data === FALSE) + { + if($line->count()) + { + $line->append($token); + } + else + { + throw new TeamSpeak3_Transport_Exception("connection to server '" . $this->config["host"] . ":" . $this->config["port"] . "' lost"); + } + } + else + { + $line->append($data); + } + } + + return $line->trim(); + } + + /** + * Writes data to the stream. + * + * @param string $data + * @return void + */ + public function send($data) + { + $this->connect(); + + @stream_socket_sendto($this->stream, $data); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataSend", $data); + } + + /** + * Writes a line of data to the stream. + * + * @param string $data + * @param string $separator + * @return void + */ + public function sendLine($data, $separator = "\n") + { + $size = strlen($data); + $pack = 4096; + + for($seek = 0 ;$seek < $size;) + { + $rest = $size-$seek; + $pack = $rest < $pack ? $rest : $pack; + $buff = substr($data, $seek, $pack); + $seek = $seek+$pack; + + if($seek >= $size) $buff .= $separator; + + $this->send($buff); + } + } +} diff --git a/hidden/TeamSpeak3/Transport/UDP.php b/hidden/TeamSpeak3/Transport/UDP.php new file mode 100644 index 0000000..f496dd4 --- /dev/null +++ b/hidden/TeamSpeak3/Transport/UDP.php @@ -0,0 +1,113 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Transport_UDP + * @brief Class for connecting to a remote server through UDP. + */ +class TeamSpeak3_Transport_UDP extends TeamSpeak3_Transport_Abstract +{ + /** + * Connects to a remote server. + * + * @throws TeamSpeak3_Transport_Exception + * @return void + */ + public function connect() + { + if($this->stream !== null) return; + + $host = strval($this->config["host"]); + $port = strval($this->config["port"]); + + $address = "udp://" . $host . ":" . $port; + $timeout = intval($this->config["timeout"]); + + $this->stream = @stream_socket_client($address, $errno, $errstr, $timeout); + + if($this->stream === FALSE) + { + throw new TeamSpeak3_Transport_Exception(TeamSpeak3_Helper_String::factory($errstr)->toUtf8()->toString(), $errno); + } + + @stream_set_timeout($this->stream, $timeout); + @stream_set_blocking($this->stream, $this->config["blocking"] ? 1 : 0); + } + + /** + * Disconnects from a remote server. + * + * @return void + */ + public function disconnect() + { + if($this->stream === null) return; + + $this->stream = null; + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "Disconnected"); + } + + /** + * Reads data from the stream. + * + * @param integer $length + * @throws TeamSpeak3_Transport_Exception + * @return TeamSpeak3_Helper_String + */ + public function read($length = 4096) + { + $this->connect(); + $this->waitForReadyRead(); + + $data = @fread($this->stream, $length); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataRead", $data); + + if($data === FALSE) + { + throw new TeamSpeak3_Transport_Exception("connection to server '" . $this->config["host"] . ":" . $this->config["port"] . "' lost"); + } + + return new TeamSpeak3_Helper_String($data); + } + + /** + * Writes data to the stream. + * + * @param string $data + * @return void + */ + public function send($data) + { + $this->connect(); + + @stream_socket_sendto($this->stream, $data); + + TeamSpeak3_Helper_Signal::getInstance()->emit(strtolower($this->getAdapterType()) . "DataSend", $data); + } +} diff --git a/hidden/TeamSpeak3/Viewer/Html.php b/hidden/TeamSpeak3/Viewer/Html.php new file mode 100644 index 0000000..3469361 --- /dev/null +++ b/hidden/TeamSpeak3/Viewer/Html.php @@ -0,0 +1,670 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Viewer_Html + * @brief Renders nodes used in HTML-based TeamSpeak 3 viewers. + */ +class TeamSpeak3_Viewer_Html implements TeamSpeak3_Viewer_Interface +{ + /** + * A pre-defined pattern used to display a node in a TeamSpeak 3 viewer. + * + * @var string + */ + protected $pattern = "
%5%8 %9%11%12
\n"; + + /** + * The TeamSpeak3_Node_Abstract object which is currently processed. + * + * @var TeamSpeak3_Node_Abstract + */ + protected $currObj = null; + + /** + * An array filled with siblingsfor the TeamSpeak3_Node_Abstract object which is currently + * processed. + * + * @var array + */ + protected $currSib = null; + + /** + * An internal counter indicating the number of fetched TeamSpeak3_Node_Abstract objects. + * + * @var integer + */ + protected $currNum = 0; + + /** + * The relative URI path where the images used by the viewer can be found. + * + * @var string + */ + protected $iconpath = null; + + /** + * The relative URI path where the country flag icons used by the viewer can be found. + * + * @var string + */ + protected $flagpath = null; + + /** + * The relative path of the file transter client script on the server. + * + * @var string + */ + protected $ftclient = null; + + /** + * Stores an array of local icon IDs. + * + * @var array + */ + protected $cachedIcons = array(100, 200, 300, 400, 500, 600); + + /** + * Stores an array of remote icon IDs. + * + * @var array + */ + protected $remoteIcons = array(); + + /** + * The TeamSpeak3_Viewer_Html constructor. + * + * @param string $iconpath + * @param string $flagpath + * @param string $ftclient + * @param string $pattern + * @return void + */ + public function __construct($iconpath = "images/viewer/", $flagpath = null, $ftclient = null, $pattern = null) + { + $this->iconpath = $iconpath; + $this->flagpath = $flagpath; + $this->ftclient = $ftclient; + + if($pattern) + { + $this->pattern = $pattern; + } + } + + /** + * Returns the code needed to display a node in a TeamSpeak 3 viewer. + * + * @param TeamSpeak3_Node_Abstract $node + * @param array $siblings + * @return string + */ + public function fetchObject(TeamSpeak3_Node_Abstract $node, array $siblings = array()) + { + $this->currObj = $node; + $this->currSib = $siblings; + + $args = array( + $this->getContainerIdent(), + $this->getContainerClass(), + $this->getContainerSummary(), + $this->getRowClass(), + $this->getPrefixClass(), + $this->getPrefix(), + $this->getCorpusClass(), + $this->getCorpusTitle(), + $this->getCorpusIcon(), + $this->getCorpusName(), + $this->getSuffixClass(), + $this->getSuffixIcon(), + $this->getSuffixFlag(), + ); + + return TeamSpeak3_Helper_String::factory($this->pattern)->arg($args); + } + + /** + * Returns a unique identifier for the current node which can be used as a HTML id + * property. + * + * @return string + */ + protected function getContainerIdent() + { + return $this->currObj->getUniqueId(); + } + + /** + * Returns a dynamic string for the current container element which can be used as + * a HTML class property. + * + * @return string + */ + protected function getContainerClass() + { + return "ts3_viewer " . $this->currObj->getClass(null); + } + + /** + * Returns the ID of the current node which will be used as a summary element for + * the container element. + * + * @return integer + */ + protected function getContainerSummary() + { + return $this->currObj->getId(); + } + + /** + * Returns a dynamic string for the current row element which can be used as a HTML + * class property. + * + * @return string + */ + protected function getRowClass() + { + return ++$this->currNum%2 ? "row1" : "row2"; + } + + /** + * Returns a string for the current prefix element which can be used as a HTML class + * property. + * + * @return string + */ + protected function getPrefixClass() + { + return "prefix " . $this->currObj->getClass(null); + } + + /** + * Returns the HTML img tags to display the prefix of the current node. + * + * @return string + */ + protected function getPrefix() + { + $prefix = ""; + + if(count($this->currSib)) + { + $last = array_pop($this->currSib); + + foreach($this->currSib as $sibling) + { + $prefix .= ($sibling) ? $this->getImage("tree_line.gif") : $this->getImage("tree_blank.png"); + } + + $prefix .= ($last) ? $this->getImage("tree_end.gif") : $this->getImage("tree_mid.gif"); + } + + return $prefix; + } + + /** + * Returns a string for the current corpus element which can be used as a HTML class + * property. If the current node is a channel spacer the class string will contain + * additional class names to allow further customization of the content via CSS. + * + * @return string + */ + protected function getCorpusClass() + { + $extras = ""; + + if($this->currObj instanceof TeamSpeak3_Node_Channel && $this->currObj->isSpacer()) + { + switch($this->currObj->spacerGetType()) + { + case (string) TeamSpeak3::SPACER_SOLIDLINE: + $extras .= " solidline"; + break; + + case (string) TeamSpeak3::SPACER_DASHLINE: + $extras .= " dashline"; + break; + + case (string) TeamSpeak3::SPACER_DASHDOTLINE: + $extras .= " dashdotline"; + break; + + case (string) TeamSpeak3::SPACER_DASHDOTDOTLINE: + $extras .= " dashdotdotline"; + break; + + case (string) TeamSpeak3::SPACER_DOTLINE: + $extras .= " dotline"; + break; + } + + switch($this->currObj->spacerGetAlign()) + { + case TeamSpeak3::SPACER_ALIGN_CENTER: + $extras .= " center"; + break; + + case TeamSpeak3::SPACER_ALIGN_RIGHT: + $extras .= " right"; + break; + + case TeamSpeak3::SPACER_ALIGN_LEFT: + $extras .= " left"; + break; + } + } + + return "corpus " . $this->currObj->getClass(null) . $extras; + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusTitle() + { + if($this->currObj instanceof TeamSpeak3_Node_Server) + { + return "ID: " . $this->currObj->getId() . " | Clients: " . $this->currObj->clientCount() . "/" . $this->currObj["virtualserver_maxclients"] . " | Uptime: " . TeamSpeak3_Helper_Convert::seconds($this->currObj["virtualserver_uptime"]); + } + elseif($this->currObj instanceof TeamSpeak3_Node_Channel && !$this->currObj->isSpacer()) + { + return "ID: " . $this->currObj->getId() . " | Codec: " . TeamSpeak3_Helper_Convert::codec($this->currObj["channel_codec"]) . " | Quality: " . $this->currObj["channel_codec_quality"]; + } + elseif($this->currObj instanceof TeamSpeak3_Node_Client) + { + return "ID: " . $this->currObj->getId() . " | Version: " . TeamSpeak3_Helper_Convert::versionShort($this->currObj["client_version"]) . " | Platform: " . $this->currObj["client_platform"]; + } + elseif($this->currObj instanceof TeamSpeak3_Node_Servergroup || $this->currObj instanceof TeamSpeak3_Node_Channelgroup) + { + return "ID: " . $this->currObj->getId() . " | Type: " . TeamSpeak3_Helper_Convert::groupType($this->currObj["type"]) . " (" . ($this->currObj["savedb"] ? "Permanent" : "Temporary") . ")"; + } + } + + /** + * Returns a HTML img tag which can be used to display the status icon for a + * TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusIcon() + { + if($this->currObj instanceof TeamSpeak3_Node_Channel && $this->currObj->isSpacer()) return; + + return $this->getImage($this->currObj->getIcon() . ".png"); + } + + /** + * Returns a string for the current corpus element which contains the display name + * for the current TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusName() + { + if($this->currObj instanceof TeamSpeak3_Node_Channel && $this->currObj->isSpacer()) + { + if($this->currObj->spacerGetType() != TeamSpeak3::SPACER_CUSTOM) return; + + $string = $this->currObj["channel_name"]->section("]", 1, 99); + + if($this->currObj->spacerGetAlign() == TeamSpeak3::SPACER_ALIGN_REPEAT) + { + $string->resize(30, $string); + } + + return htmlspecialchars($string); + } + + if($this->currObj instanceof TeamSpeak3_Node_Client) + { + $before = array(); + $behind = array(); + + foreach($this->currObj->memberOf() as $group) + { + if($group->getProperty("namemode") == TeamSpeak3::GROUP_NAMEMODE_BEFORE) + { + $before[] = "[" . htmlspecialchars($group["name"]) . "]"; + } + elseif($group->getProperty("namemode") == TeamSpeak3::GROUP_NAMEMODE_BEHIND) + { + $behind[] = "[" . htmlspecialchars($group["name"]) . "]"; + } + } + + return implode("", $before) . " " . htmlspecialchars($this->currObj) . " " . implode("", $behind); + } + + return htmlspecialchars($this->currObj); + } + + /** + * Returns a string for the current suffix element which can be used as a HTML + * class property. + * + * @return string + */ + protected function getSuffixClass() + { + return "suffix " . $this->currObj->getClass(null); + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getSuffixIcon() + { + if($this->currObj instanceof TeamSpeak3_Node_Server) + { + return $this->getSuffixIconServer(); + } + elseif($this->currObj instanceof TeamSpeak3_Node_Channel) + { + return $this->getSuffixIconChannel(); + } + elseif($this->currObj instanceof TeamSpeak3_Node_Client) + { + return $this->getSuffixIconClient(); + } + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Server object. + * + * @return string + */ + protected function getSuffixIconServer() + { + $html = ""; + + if($this->currObj["virtualserver_icon_id"]) + { + if(!$this->currObj->iconIsLocal("virtualserver_icon_id") && $this->ftclient) + { + if(!isset($this->cacheIcon[$this->currObj["virtualserver_icon_id"]])) + { + $download = $this->currObj->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->currObj->iconGetName("virtualserver_icon_id")); + + if($this->ftclient == "data:image") + { + $download = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"])->download($download["ftkey"], $download["size"]); + } + + $this->cacheIcon[$this->currObj["virtualserver_icon_id"]] = $download; + } + else + { + $download = $this->cacheIcon[$this->currObj["virtualserver_icon_id"]]; + } + + if($this->ftclient == "data:image") + { + $html .= $this->getImage("data:" . TeamSpeak3_Helper_Convert::imageMimeType($download) . ";base64," . base64_encode($download), "Server Icon", null, FALSE); + } + else + { + $html .= $this->getImage($this->ftclient . "?ftdata=" . base64_encode(serialize($download)), "Server Icon", null, FALSE); + } + } + elseif(in_array($this->currObj["virtualserver_icon_id"], $this->cachedIcons)) + { + $html .= $this->getImage("group_icon_" . $this->currObj["virtualserver_icon_id"] . ".png", "Server Icon"); + } + } + + return $html; + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Channel object. + * + * @return string + */ + protected function getSuffixIconChannel() + { + if($this->currObj instanceof TeamSpeak3_Node_Channel && $this->currObj->isSpacer()) return; + + $html = ""; + + if($this->currObj["channel_flag_default"]) + { + $html .= $this->getImage("channel_flag_default.png", "Default Channel"); + } + + if($this->currObj["channel_flag_password"]) + { + $html .= $this->getImage("channel_flag_password.png", "Password-protected"); + } + + if($this->currObj["channel_codec"] == TeamSpeak3::CODEC_CELT_MONO || $this->currObj["channel_codec"] == TeamSpeak3::CODEC_OPUS_MUSIC) + { + $html .= $this->getImage("channel_flag_music.png", "Music Codec"); + } + + if($this->currObj["channel_needed_talk_power"]) + { + $html .= $this->getImage("channel_flag_moderated.png", "Moderated"); + } + + if($this->currObj["channel_icon_id"]) + { + if(!$this->currObj->iconIsLocal("channel_icon_id") && $this->ftclient) + { + if(!isset($this->cacheIcon[$this->currObj["channel_icon_id"]])) + { + $download = $this->currObj->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->currObj->iconGetName("channel_icon_id")); + + if($this->ftclient == "data:image") + { + $download = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"])->download($download["ftkey"], $download["size"]); + } + + $this->cacheIcon[$this->currObj["channel_icon_id"]] = $download; + } + else + { + $download = $this->cacheIcon[$this->currObj["channel_icon_id"]]; + } + + if($this->ftclient == "data:image") + { + $html .= $this->getImage("data:" . TeamSpeak3_Helper_Convert::imageMimeType($download) . ";base64," . base64_encode($download), "Channel Icon", null, FALSE); + } + else + { + $html .= $this->getImage($this->ftclient . "?ftdata=" . base64_encode(serialize($download)), "Channel Icon", null, FALSE); + } + } + elseif(in_array($this->currObj["channel_icon_id"], $this->cachedIcons)) + { + $html .= $this->getImage("group_icon_" . $this->currObj["channel_icon_id"] . ".png", "Channel Icon"); + } + } + + return $html; + } + + /** + * Returns the HTML img tags which can be used to display the various icons for a + * TeamSpeak_Node_Client object. + * + * @return string + */ + protected function getSuffixIconClient() + { + $html = ""; + + if($this->currObj["client_is_priority_speaker"]) + { + $html .= $this->getImage("client_priority.png", "Priority Speaker"); + } + + if($this->currObj["client_is_channel_commander"]) + { + $html .= $this->getImage("client_cc.png", "Channel Commander"); + } + + if($this->currObj["client_is_talker"]) + { + $html .= $this->getImage("client_talker.png", "Talk Power granted"); + } + elseif($cntp = $this->currObj->getParent()->channelGetById($this->currObj["cid"])->channel_needed_talk_power) + { + if($cntp > $this->currObj["client_talk_power"]) + { + $html .= $this->getImage("client_mic_muted.png", "Insufficient Talk Power"); + } + } + + foreach($this->currObj->memberOf() as $group) + { + if(!$group["iconid"]) continue; + + $type = ($group instanceof TeamSpeak3_Node_Servergroup) ? "Server Group" : "Channel Group"; + + if(!$group->iconIsLocal("iconid") && $this->ftclient) + { + if(!isset($this->cacheIcon[$group["iconid"]])) + { + $download = $group->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $group->iconGetName("iconid")); + + if($this->ftclient == "data:image") + { + $download = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"])->download($download["ftkey"], $download["size"]); + } + + $this->cacheIcon[$group["iconid"]] = $download; + } + else + { + $download = $this->cacheIcon[$group["iconid"]]; + } + + if($this->ftclient == "data:image") + { + $html .= $this->getImage("data:" . TeamSpeak3_Helper_Convert::imageMimeType($download) . ";base64," . base64_encode($download), $group . " [" . $type . "]", null, FALSE); + } + else + { + $html .= $this->getImage($this->ftclient . "?ftdata=" . base64_encode(serialize($download)), $group . " [" . $type . "]", null, FALSE); + } + } + elseif(in_array($group["iconid"], $this->cachedIcons)) + { + $html .= $this->getImage("group_icon_" . $group["iconid"] . ".png", $group . " [" . $type . "]"); + } + } + + if($this->currObj["client_icon_id"]) + { + if(!$this->currObj->iconIsLocal("client_icon_id") && $this->ftclient) + { + if(!isset($this->cacheIcon[$this->currObj["client_icon_id"]])) + { + $download = $this->currObj->getParent()->transferInitDownload(rand(0x0000, 0xFFFF), 0, $this->currObj->iconGetName("client_icon_id")); + + if($this->ftclient == "data:image") + { + $download = TeamSpeak3::factory("filetransfer://" . $download["host"] . ":" . $download["port"])->download($download["ftkey"], $download["size"]); + } + + $this->cacheIcon[$this->currObj["client_icon_id"]] = $download; + } + else + { + $download = $this->cacheIcon[$this->currObj["client_icon_id"]]; + } + + if($this->ftclient == "data:image") + { + $html .= $this->getImage("data:" . TeamSpeak3_Helper_Convert::imageMimeType($download) . ";base64," . base64_encode($download), "Client Icon", null, FALSE); + } + else + { + $html .= $this->getImage($this->ftclient . "?ftdata=" . base64_encode(serialize($download)), "Client Icon", null, FALSE); + } + } + elseif(in_array($this->currObj["client_icon_id"], $this->cachedIcons)) + { + $html .= $this->getImage("group_icon_" . $this->currObj["client_icon_id"] . ".png", "Client Icon"); + } + } + + return $html; + } + + /** + * Returns a HTML img tag which can be used to display the country flag for a + * TeamSpeak_Node_Client object. + * + * @return string + */ + protected function getSuffixFlag() + { + if(!$this->currObj instanceof TeamSpeak3_Node_Client) return; + + if($this->flagpath && $this->currObj["client_country"]) + { + return $this->getImage($this->currObj["client_country"]->toLower() . ".png", $this->currObj["client_country"], null, FALSE, TRUE); + } + } + + /** + * Returns the code to display a custom HTML img tag. + * + * @param string $name + * @param string $text + * @param string $class + * @param boolean $iconpath + * @param boolean $flagpath + * @return string + */ + protected function getImage($name, $text = "", $class = null, $iconpath = TRUE, $flagpath = FALSE) + { + $src = ""; + + if($iconpath) + { + $src = $this->iconpath; + } + + if($flagpath) + { + $src = $this->flagpath; + } + + return ""; + } +} diff --git a/hidden/TeamSpeak3/Viewer/Interface.php b/hidden/TeamSpeak3/Viewer/Interface.php new file mode 100644 index 0000000..df702f9 --- /dev/null +++ b/hidden/TeamSpeak3/Viewer/Interface.php @@ -0,0 +1,42 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Viewer_Interface + * @brief Interface class describing a TeamSpeak 3 viewer. + */ +interface TeamSpeak3_Viewer_Interface +{ + /** + * Returns the code needed to display a node in a TeamSpeak 3 viewer. + * + * @param TeamSpeak3_Node_Abstract $node + * @param array $siblings + * @return string + */ + public function fetchObject(TeamSpeak3_Node_Abstract $node, array $siblings = array()); +} diff --git a/hidden/TeamSpeak3/Viewer/Text.php b/hidden/TeamSpeak3/Viewer/Text.php new file mode 100644 index 0000000..c4d2532 --- /dev/null +++ b/hidden/TeamSpeak3/Viewer/Text.php @@ -0,0 +1,107 @@ +. + * + * @package TeamSpeak3 + * @version 1.1.23 + * @author Sven 'ScP' Paulsen + * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved. + */ + +/** + * @class TeamSpeak3_Viewer_Text + * @brief Renders nodes used in ASCII-based TeamSpeak 3 viewers. + */ +class TeamSpeak3_Viewer_Text implements TeamSpeak3_Viewer_Interface +{ + /** + * A pre-defined pattern used to display a node in a TeamSpeak 3 viewer. + * + * @var string + */ + protected $pattern = "%0%1 %2\n"; + + /** + * Returns the code needed to display a node in a TeamSpeak 3 viewer. + * + * @param TeamSpeak3_Node_Abstract $node + * @param array $siblings + * @return string + */ + public function fetchObject(TeamSpeak3_Node_Abstract $node, array $siblings = array()) + { + $this->currObj = $node; + $this->currSib = $siblings; + + $args = array( + $this->getPrefix(), + $this->getCorpusIcon(), + $this->getCorpusName(), + ); + + return TeamSpeak3_Helper_String::factory($this->pattern)->arg($args); + } + + /** + * Returns the ASCII string to display the prefix of the current node. + * + * @return string + */ + protected function getPrefix() + { + $prefix = ""; + + if(count($this->currSib)) + { + $last = array_pop($this->currSib); + + foreach($this->currSib as $sibling) + { + $prefix .= ($sibling) ? "| " : " "; + } + + $prefix .= ($last) ? "\\-" : "|-"; + } + + return $prefix; + } + + /** + * Returns an ASCII string which can be used to display the status icon for a + * TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusIcon() + { + return $this->currObj->getSymbol(); + } + + /** + * Returns a string for the current corpus element which contains the display name + * for the current TeamSpeak_Node_Abstract object. + * + * @return string + */ + protected function getCorpusName() + { + return $this->currObj; + } +} diff --git a/hidden/csgo_query.php b/hidden/csgo_query.php new file mode 100644 index 0000000..90eeb34 --- /dev/null +++ b/hidden/csgo_query.php @@ -0,0 +1,112 @@ +data = str_split($data); + $this->pointer = 0; + } + + public function ReadByte() + { + return ord($this->data[$this->pointer++]); + } + + public function ReadShort() + { + return (ord($this->data[$this->pointer++]) | (ord($this->data[$this->pointer++])<<8)); + } + + public function ReadInt() + { + return (ord($this->data[$this->pointer++]) | (ord($this->data[$this->pointer++])<<8) | (ord($this->data[$this->pointer++])<<16) | (ord($this->data[$this->pointer++])<<24)); + } + + public function ReadChar() + { + return $this->data[$this->pointer++]; + } + + public function ReadString() + { + $string = ''; + while ($this->data[$this->pointer] != "\0") + { + $string .= $this->data[$this->pointer]; + $this->pointer++; + } + $this->pointer++; + return $string; + } +} + + + +function source_query($ip) +{ +$cut = explode(":", $ip); +$HL2_address = $cut[0]; +$HL2_port = $cut[1]; + +$HL2_command = "\377\377\377\377TSource Engine Query\0"; +$HL2_socket = fsockopen("udp://".$HL2_address, $HL2_port, $errno, $errstr,3); +fwrite($HL2_socket, $HL2_command); $JunkHead = fread($HL2_socket,4); +$CheckStatus = socket_get_status($HL2_socket); + +if($CheckStatus["unread_bytes"] == 0) +{ + return 0; +} + +$do = 1; +while($do) +{ + $str = fread($HL2_socket,1); + $HL2_stats.= $str; + $status = socket_get_status($HL2_socket); + if($status["unread_bytes"] == 0) + { + $do = 0; + } +} +fclose($HL2_socket); + +$x = 0; +while ($x <= strlen($HL2_stats)) +{ + $x++; + $result.= substr($HL2_stats, $x, 1); +} +$result = urlencode($result); // the output +return $result; +} + + +/* FORMAT SOURCE ENGINE QUERY (assumes the query's results were urlencode()'ed!) */ +function format_source_query($string) +{ +$string = str_replace('%07','',$string); +$string = str_replace("%00","|||",$string); +$sinfo = urldecode($string); +$sinfo = explode('|||',$sinfo); +$info['hostname'] = $sinfo[0]; +$info['map'] = $sinfo[1]; +$info['game'] = $sinfo[2]; +if ($info['game'] == 'garrysmod') { $info['game'] = "Garry's Mod"; } +elseif ($info['game'] == 'cstrike') { $info['game'] = "Counter-Strike: Source"; } +elseif ($info['game'] == 'dod') { $info['game'] = "Day of Defeat: Source"; } +$info['gamemode'] = $sinfo[3]; +$buffer = new ByteBuffer($string); +$info['players'] = $buffer->ReadByte(); +$info['maxplayers'] = $buffer->ReadByte(); + +return $info; +} + +?> diff --git a/index.html b/index.html new file mode 100644 index 0000000..4917d24 --- /dev/null +++ b/index.html @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + Server-Status Test + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/loading.gif b/loading.gif new file mode 100644 index 0000000..ac3a3ef Binary files /dev/null and b/loading.gif differ diff --git a/query.php b/query.php new file mode 100644 index 0000000..6dd6844 --- /dev/null +++ b/query.php @@ -0,0 +1,137 @@ +Connect( $exploded_ip[0], $exploded_ip[1], 1, SourceQuery::SOURCE ); + $info = $Query->GetInfo(); + $response['status'] = 'online'; + $response['map'] = $info['Map']; + $response['players'] = $info['Players'] . '/' . $info['MaxPlayers']; + } + catch( Exception $e ) + { + //echo $e->getMessage( ); + $response['status'] = 'offline'; + } + finally + { + $Query->Disconnect( ); + } + + $response['container'] = $container; + $response['id'] = $id; + + return $response; + } + + function tsStatus($address,$container,$id) { + $response = ''; + try + { + $ts3 = TeamSpeak3::factory("serverquery://".$address); + //query_user:query_pass@host:10011/?server_port=9987 + + $response['status'] = 'online'; + $response['map'] = ''; + $response['players'] = $ts3->virtualserver_clientsonline-1 . " / " . $ts3->virtualserver_maxclients; + + } + catch(Exception $e) + { + $response['status'] = 'offline'; + } + + /*$c = file_get_contents($address); + $j = json_decode($c); + + if ($j->status == "Online") { + $response['status'] = 'online'; + $response['map'] = ''; + $response['players'] = $j->players . " / " . $j->slots; + } + else { + $response['status'] = 'offline'; + }*/ + + $response['container'] = $container; + $response['id'] = $id; + + return $response; + } + + function mcStatus($address,$container,$id) { + $response = ''; + + $address = explode(':',$address); + + Ini_Set('display_errors', true); + + $Query = new MinecraftQuery(); + try + { + $Query->Connect($address[0], $address[1], 1); + } + catch(MinecraftQueryException $e) + { + $Exception = $e; + } + + if (($Info = $Query->GetInfo()) !== false) { + $response['status'] = 'online'; + $response['map'] = $Info['Map']; + $response['players'] = $Info['Players'] . " / " . $Info['MaxPlayers']; + + $response['container'] = $container; + $response['id'] = $id; + } + else { + $response['status'] = 'offline'; + $response['container'] = $container; + $response['id'] = $id; + } + + return $response; + } + + ?> diff --git a/server-status-realsteel.js b/server-status-realsteel.js new file mode 100644 index 0000000..aff793a --- /dev/null +++ b/server-status-realsteel.js @@ -0,0 +1,62 @@ +String.prototype.trunc = String.prototype.trunc || + function(n){ + return (this.length > n) ? this.substr(0,n-1)+'…' : this; + }; + +var totalPlayersOnline = 0; + +function addServers() { + for (var i=0; i 0) { + for(l=0;l'+servers[i].links[l][0]+' | ';} + else {links += ''+servers[i].links[l][0]+'';} + } + } + + jQuery('#server-status-servers').append( + '
'+ + '
'+ + '
'+servers[i].title+'
'+ + '
'+servers[i].displayip+'
'+ + '
0/0
'+ + '
'+ + '
'+links+'
'+ + '
'+ + '
' + ); + } + } +} +function checkServersStatus() { + totalPlayersOnline = 0; + + jQuery('.server').each(function() { + if (jQuery(this).hasClass('ignore')) {} + else { + var i = jQuery(this).attr('id').split('server-').join(''); + jQuery('#server-'+i).find('.server-indicator').find('i').removeClass('fa-circle').addClass('fa-spinner').addClass('fa-pulse').removeClass('green').removeClass('red'); + jQuery.getJSON('https://vps.moow.info/scripts/server-status/query.php?type='+servers[i].type+'&ip=' + servers[i].ip, function(response) { + if (response["status"] == "offline") { + jQuery('#server-'+i).find('.server-indicator').find('i').removeClass('fa-spinner').removeClass('fa-pulse').addClass('fa-circle').removeClass('green').addClass('red'); + jQuery('#server-'+i).find('.server-players').html(' 0/0 '); + } + else { + jQuery('#server-'+i).find('.server-indicator').find('i').removeClass('fa-spinner').removeClass('fa-pulse').addClass('fa-circle').removeClass('red').addClass('green'); + jQuery('#server-'+i).find('.server-players').html(response["players"]); + jQuery('#server-'+i).find('.server-map').html(response["map"].trunc(15)); + totalPlayersOnline = totalPlayersOnline + parseInt(response["players"].split('\/')[0]); + jQuery('.server-status-total-num').html(totalPlayersOnline); + } + }); + } + }); +} + +jQuery(function() { + addServers(); + checkServersStatus(); + setInterval('checkServersStatus();',15000); +}); diff --git a/server-status.js b/server-status.js new file mode 100644 index 0000000..d5bae52 --- /dev/null +++ b/server-status.js @@ -0,0 +1,104 @@ +String.prototype.trunc = String.prototype.trunc || + function(n){ + return (this.length > n) ? this.substr(0,n-1)+'…' : this; + }; + +jQuery(function() { + jQuery.fn.extend({ + serverStatus: function(str, d, set, ref) { + new jQuery.serverStatus(this, str, d, set, ref); + } + }); + + jQuery.serverStatus = function(container, str, d, set, ref) { + + $serverStatus = this; + + //Structure + var structure = jQuery.extend([], str); //Structure + + //Data + var data = jQuery.extend([], d); //Data + + //Settings + var settings = jQuery.extend({ + type : "status" //Can also be: counter (counts total players online) + }, set); //Settings + + //Refresh time + var refresh = ref; //Refresh time + + $container = container; + $structure = structure; + $data = data; + $settings = settings; + $refresh = refresh; + + //Initialize server-status plugin + $serverStatus._init = function() { + + $container.html(''); + + //Add header bar + var content = '
'; + for (var y=0; y<$structure.length; y++) { + content += '
'+$structure[y].title+'
'; + } + content += '
\ +
\ +
'; + $container.append(content); + + //Add data + for (var i=0; i<$data.length; i++) { + if (!$data[i].hidden) { + var row = '
'; + for (var y=0; y<$structure.length; y++) { + if ($structure[y].type == "status") {row += '
';} + else if ($structure[y].type == "counter") {row += '
0/0
';} + else if ($structure[y].type == "map") {row += '
-
';} + else {row += '
'+$data[i][$structure[y].id]+'
';} + } + $container.find('.server-status-servers').append(row); + } + } + + } //Initialize + + //Update row + $serverStatus._updateRow = function(response) { + $this = jQuery('#' + response["container"] + ' .server-status-servers .server-status-row[data-id="'+response["id"]+'"]'); + if (response["status"] == "offline") { + $this.find('div[data-type="status"] i').removeClass('online').addClass('offline'); + $this.find('div[data-type="counter"]').html('0/0'); + $this.find('div[data-type="map"]').html(''); + } + else { + $this.find('div[data-type="status"] i').removeClass('offline').addClass('online'); + $this.find('div[data-type="counter"]').html(response["players"]); + $this.find('div[data-type="map"]').html(response["map"]); + + /*totalPlayersOnline = totalPlayersOnline + parseInt(response["players"].split('\/')[0]); + jQuery('.server-status-total-num').html(totalPlayersOnline);*/ + } + } //Update row + + //Update server-status + $serverStatus._updateStatus = function() { + $container.find('.server-status-servers .server-status-row').each(function() { + $this = jQuery(this); + $id = $this.data('id'); + $this.find('div[data-type="status"] i').removeClass('online').removeClass('offline'); + $this.find('div[data-type="counter"]').html('loading'); + + jQuery.getJSON('https://static.moow.info/server-status/query.php?type='+$data[$id].type+'&ip=' + $data[$id].ip + '&container=' + $container.attr('id') + '&id=' + $id, function(response) {$serverStatus._updateRow(response);}); + }); + } //Update status + + //Init after creation + $serverStatus._init(); + $serverStatus._updateStatus(); + if ($refresh > 0) {setInterval(function(){ $serverStatus._updateStatus(); }, $refresh);} + + }; +}); diff --git a/server-status.min.js b/server-status.min.js new file mode 100644 index 0000000..6b2c237 --- /dev/null +++ b/server-status.min.js @@ -0,0 +1,6 @@ +String.prototype.trunc=String.prototype.trunc||function(c){return this.length>c?this.substr(0,c-1)+"…":this}; +jQuery(function(){jQuery.fn.extend({serverStatus:function(c,d,e,f){new jQuery.serverStatus(this,c,d,e,f)}});jQuery.serverStatus=function(c,d,e,f,g){$serverStatus=this;d=jQuery.extend([],d);e=jQuery.extend([],e);f=jQuery.extend({type:"status"},f);$container=c;$structure=d;$data=e;$settings=f;$refresh=g;$serverStatus._init=function(){$container.html("");for(var b='
',a=0;a<$structure.length;a++)b+='
'+ +$structure[a].title+"
";$container.append(b+'
');for(b=0;b<$data.length;b++)if(!$data[b].hidden){for(var c='
',a=0;a<$structure.length;a++)c="status"==$structure[a].type?c+('
'):"counter"==$structure[a].type?c+('
0/0
'):"map"==$structure[a].type?c+('
-
'):c+('
'+$data[b][$structure[a].id]+"
");$container.find(".server-status-servers").append(c)}};$serverStatus._updateRow=function(b){$this=jQuery("#"+b.container+' .server-status-servers .server-status-row[data-id="'+b.id+'"]');"offline"==b.status?($this.find('div[data-type="status"] i').removeClass("online").addClass("offline"), +$this.find('div[data-type="counter"]').html("0/0"),$this.find('div[data-type="map"]').html("")):($this.find('div[data-type="status"] i').removeClass("offline").addClass("online"),$this.find('div[data-type="counter"]').html(b.players),$this.find('div[data-type="map"]').html(b.map))};$serverStatus._updateStatus=function(){$container.find(".server-status-servers .server-status-row").each(function(){$this=jQuery(this);$id=$this.data("id");$this.find('div[data-type="status"] i').removeClass("online").removeClass("offline"); +$this.find('div[data-type="counter"]').html('loading');jQuery.getJSON("https://static.moow.info/server-status/query.php?type="+$data[$id].type+"&ip="+$data[$id].ip+"&container="+$container.attr("id")+"&id="+$id,function(b){$serverStatus._updateRow(b)})})};$serverStatus._init();$serverStatus._updateStatus();0<$refresh&&setInterval(function(){$serverStatus._updateStatus()},$refresh)}}); \ No newline at end of file diff --git a/test.css b/test.css new file mode 100644 index 0000000..32b478c --- /dev/null +++ b/test.css @@ -0,0 +1,31 @@ +/* + Made by Dominik Dancs + Copyright © 2015 + http://dodancs.moow.info + ------------------------ + email: dodancs@moow.info +*/ + +.server-status {background:rgba(27,35,48,0.6);width:100%;padding:1em;box-sizing:border-box;} +.server-status-header {width:100%;padding:0.3em;color:white;} +.server-status-header .server-status-header-row {display:inline-block;text-transform:uppercase;font-size:1.2em;} +.server-status-row {width:100%;padding:0.3em;color:white;} +.server-status-row div[data-type="status"] i {color:white;} +.server-status-row div[data-type="status"] i.online {color:#1be51b;} +.server-status-row div[data-type="status"] i.offline {color:#e21b1b;} + +.server-status-status, .server-status-header-row[data-id="status"] {width:10%;text-align:left;display:inline-block;} +.server-status-title, .server-status-header-row[data-id="title"] {width:30%;text-align:left;display:inline-block;} +.server-status-visibleIP, .server-status-header-row[data-id="visibleIP"] {width:30%;text-align:left;display:inline-block;} +/*.server-status-map, .server-status-header-row[data-id="map"] {width:10%;text-align:left;display:inline-block;}*/ +.server-status-version, .server-status-header-row[data-id="version"] {width:10%;text-align:left;display:inline-block;} +.server-status-players, .server-status-header-row[data-id="players"] {width:10%;text-align:left;display:inline-block;} + +@media all and (max-width: 800px) { + .server-status-status, .server-status-header-row[data-id="status"] {width:20%;} + .server-status-title, .server-status-header-row[data-id="title"] {width:60%;} + .server-status-visibleIP, .server-status-header-row[data-id="visibleIP"] {display:none;} + /*.server-status-map, .server-status-header-row[data-id="map"] {display:none;}*/ + .server-status-version, .server-status-header-row[data-id="version"] {display:none;} + .server-status-players, .server-status-header-row[data-id="players"] {width:20%;} +} diff --git a/test.js b/test.js new file mode 100644 index 0000000..ea11081 --- /dev/null +++ b/test.js @@ -0,0 +1,62 @@ +var statusStructure = [ + { + "_comment" : "Server status", + id : "status", + type : "status", //type : "text","status","counter" + title : "Status" + }, + { + "_comment" : "Server title", + id : "title", + type : "text", + title : "Title" + }, + { + "_comment" : "Server address", + id : "visibleIP", + type : "text", + title : "Address" + }, + /*{ + "_comment" : "Server map", + id : "map", + type : "map", + title : "Map" + },*/ + { + "_comment" : "Server version", + id : "version", + type : "text", + title : "Version" + }, + { + "_comment" : "Players online", + id : "players", + type : "counter", + title : "Players Online" + } +]; +var statusServers = [ + { + type : "ts", + title : "FenixPortal TS", + ip : "tsquery:fyKItRok@ts.fenixportal.eu:10011/?server_port=9987", + visibleIP : "ts.fenixportal.eu", + version : "TS3", + hidden : false + }, + { + type : "csgo", + title : "CS:GO", + ip : "vps.moow.info:9987", + visibleIP : "vps.moow.info", + version : "", + hidden : false + } +]; + +jQuery(function() { + + jQuery('#status1').serverStatus(statusStructure,statusServers,{"type" : "status"},5000); + +});