Skip to content
Merged
1 change: 1 addition & 0 deletions .env.testing.example
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ DEV_LIVE_SERVER_UNIT_TEST_SIGNALS=false
DEV_LIVE_SERVER_UNIT_TEST_USER_EXTEND=UnitTestUser2
DEV_LIVE_SERVER_UNIT_TEST_SERVER_PORT=9987
DEV_LIVE_SERVER_UNIT_TEST_SERVER_QUERY_LOGIN_NAME=ts3-bot-dev
DEV_LIVE_SERVER_UNIT_TEST_SERVER_HOST_KEY=yourServerFingerPrintFromHostKey
2 changes: 1 addition & 1 deletion doc/coverage/coverage-badge.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions src/Adapter/MockServerQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use PlanetTeamSpeak\TeamSpeak3Framework\Exception\TransportException;
use PlanetTeamSpeak\TeamSpeak3Framework\Helper\Profiler;
use PlanetTeamSpeak\TeamSpeak3Framework\Helper\Signal;
use PlanetTeamSpeak\TeamSpeak3Framework\Helper\StringHelper;
use PlanetTeamSpeak\TeamSpeak3Framework\TeamSpeak3;
use PlanetTeamSpeak\TeamSpeak3Framework\Transport\MockTCP;

Expand All @@ -27,11 +28,77 @@ protected function syn(): void
Profiler::init(spl_object_hash($this));

$rdy = $this->getTransport()->readLine();
$rdy = StringHelper::factory($rdy ?? '');

if (! $rdy->startsWith(TeamSpeak3::TS3_PROTO_IDENT) && ! $rdy->startsWith(TeamSpeak3::TEA_PROTO_IDENT)) {
throw new AdapterException('invalid reply from the server ('.$rdy.')');
}

Signal::getInstance()->emit('serverqueryConnected', $this);
}

/**
* Return the underlying MockTCP transport.
*/
public function getMockTransport(): MockTCP
{
/** @var MockTCP $transport */
$transport = $this->getTransport();

return $transport;
}

/**
* Register a custom response on the mock transport.
*/
public function registerResponse(string $cmd, string $reply): self
{
$this->getMockTransport()->registerResponse($cmd, $reply);

return $this;
}

/**
* Queue a response on the mock transport.
*/
public function queueResponse(string $reply): self
{
$this->getMockTransport()->queueResponse($reply);

return $this;
}

/**
* Set a custom dynamic command handler.
*/
public function setCommandHandler(callable $handler): self
{
$this->getMockTransport()->setCommandHandler($handler);

return $this;
}

/**
* Get sent commands.
*/
public function getSentCommands(): array
{
return $this->getMockTransport()->getSentCommands();
}

/**
* Get the last sent command.
*/
public function getLastCommand(): ?string
{
return $this->getMockTransport()->getLastCommand();
}

/**
* Check if a command was sent.
*/
public function hasSentCommand(string $command): bool
{
return $this->getMockTransport()->hasSentCommand($command);
}
}
36 changes: 34 additions & 2 deletions src/Helper/Char.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,23 +162,55 @@ public function toAscii(): int
*/
public function toUnicode(): int
{
$length = strlen($this->char);
$h = ord($this->char[0]);

if ($h <= 0x7F) {
return $h;
return $length === 1 ? $h : -1;
} elseif ($h < 0xC2) {
return -1;
} elseif ($h <= 0xDF) {
if ($length !== 2 || ! $this->isContinuationByte(1)) {
return -1;
}

return ($h & 0x1F) << 6 | (ord($this->char[1]) & 0x3F);
} elseif ($h <= 0xEF) {
if ($length !== 3 || ! $this->isContinuationByte(1) || ! $this->isContinuationByte(2)) {
return -1;
}

return ($h & 0x0F) << 12 | (ord($this->char[1]) & 0x3F) << 6 | (ord($this->char[2]) & 0x3F);
} elseif ($h <= 0xF4) {
return ($h & 0x0F) << 18 | (ord($this->char[1]) & 0x3F) << 12 | (ord($this->char[2]) & 0x3F) << 6 | (ord($this->char[3]) & 0x3F);
if (
$length !== 4
|| ! $this->isContinuationByte(1)
|| ! $this->isContinuationByte(2)
|| ! $this->isContinuationByte(3)
) {
return -1;
}

return ($h & 0x07) << 18
| (ord($this->char[1]) & 0x3F) << 12
| (ord($this->char[2]) & 0x3F) << 6
| (ord($this->char[3]) & 0x3F);
} else {
return -1;
}
}

private function isContinuationByte(int $offset): bool
{
if (! isset($this->char[$offset])) {
return false;
}

$byte = ord($this->char[$offset]);

return $byte >= 0x80 && $byte <= 0xBF;
}

/**
* Returns the hexadecimal value of the char.
*
Expand Down
4 changes: 4 additions & 0 deletions src/Helper/Signal.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ public function emit(string $signal, mixed $params = null): mixed
*/
public function getCallbackHash(mixed $callback): string
{
if ($callback instanceof \Closure) {
return spl_object_hash($callback);
}

if (! is_callable($callback, true, $callable_name)) {
throw new SignalException('invalid callback specified');
}
Expand Down
4 changes: 2 additions & 2 deletions src/Helper/Uri.php
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ public function getQuery(array $default = []): array
return $default;
}

parse_str(rawurldecode($this->query), $queryArray);
parse_str($this->query, $queryArray);

return $queryArray;
}
Expand Down Expand Up @@ -514,7 +514,7 @@ public function getQueryVar(string $key, mixed $default = null): mixed
return $default;
}

parse_str(rawurldecode($this->query), $queryArray);
parse_str($this->query, $queryArray);

if (array_key_exists($key, $queryArray)) {
$val = $queryArray[$key];
Expand Down
2 changes: 1 addition & 1 deletion src/Node/ChannelGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public function clientList(int $cid = null, int $cldbid = null, bool $resolve =
*/
public function privilegeKeyCreate(int $cid, string $description = null, string $customset = null): StringHelper
{
return $this->getParent()->privilegeKeyCreate($this->getId(), TeamSpeak3::TOKEN_CHANNELGROUP, $cid, $description, $customset);
return $this->getParent()->privilegeKeyCreate($this->getId(), $cid, TeamSpeak3::TOKEN_CHANNELGROUP, $description, $customset);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/Node/Group.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ abstract class Group extends Node
public function message(string $msg): void
{
// get all clients in this group
$clients = $this->getParent()->channelGroupClientList($this->getId());
$clients = $this->clientList();

// get client id from dbid and send a textmessage
foreach ($clients as $client) {
try {
$targetClientID = $this->getParent()->clientgetbydbid($client['cldbid'])->getId();
$targetClientID = $this->getParent()->clientGetByDbid($client['cldbid'])->getId();
$this->execute('sendtextmessage', ['msg' => $msg, 'target' => $targetClientID, 'targetmode' => TeamSpeak3::TEXTMSG_CLIENT]);
} catch (ServerQueryException $e) {
/* ERROR_client_invalid_id */
Expand Down
47 changes: 36 additions & 11 deletions src/Node/Host.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,15 @@ public function version(): array
if ($this->version === null) {
$raw = $this->request('version')->toList();

// Find the first array that contains real data
foreach ($raw as $item) {
if (is_array($item) && isset($item['version'])) {
$this->version = $item;
break;
if (isset($raw['version'])) {
$this->version = $raw;
} elseif (is_array($raw)) {
// Find the first array that contains real data
foreach ($raw as $item) {
if (is_array($item) && isset($item['version'])) {
$this->version = $item;
break;
}
}
}

Expand Down Expand Up @@ -189,7 +193,19 @@ public function serverIdGetByPort(int $port): int
{
$sid = $this->execute('serveridgetbyport', ['virtualserver_port' => $port])->toList();

return $sid[1]['server_id'];
if (isset($sid['server_id'])) {
return (int) $sid['server_id'];
}

if (isset($sid[0]['server_id'])) {
return (int) $sid[0]['server_id'];
}

if (isset($sid[1]['server_id'])) {
return (int) $sid[1]['server_id'];
}

return 0;
}

/**
Expand Down Expand Up @@ -757,9 +773,10 @@ public function login(string $username, string $password): void

if ($this->predefined_query_name) {
$clients = $this->request('clientlist -uid')->toList();
$clientRows = isset($clients['clid']) ? [$clients] : (is_array($clients) ? $clients : []);

foreach ($clients as $client) {
if ($client['client_nickname'] === $this->predefined_query_name) {
foreach ($clientRows as $client) {
if (is_array($client) && isset($client['client_nickname']) && $client['client_nickname'] === $this->predefined_query_name) {
// Kick old query with same nickname
$this->execute('clientkick', [
'clid' => $client['clid'],
Expand All @@ -775,7 +792,11 @@ public function login(string $username, string $password): void
]);
}

$crypt = new Crypt($username);
$cryptKey = substr($username, 0, 56);
if ($cryptKey === '') {
$cryptKey = 'serveradmin';
}
$crypt = new Crypt($cryptKey);
$this->setStorage('_login_user', $username);
$this->setStorage('_login_pass', $crypt->encrypt($password));

Expand Down Expand Up @@ -889,8 +910,12 @@ public function whoami(): array
// Execute server request
$response = $this->request('whoami')->toList();

// response[1] contains the actual data
$data = $response[1] ?? [];
// Check if single-row associative array or nested list
if (isset($response['client_id']) || isset($response['virtualserver_id']) || isset($response['client_nickname'])) {
$data = $response;
} else {
$data = $response[1] ?? ($response[0] ?? []);
}

// Automatically convert StringHelper to strings
foreach ($data as $key => $val) {
Expand Down
2 changes: 1 addition & 1 deletion src/Node/Node.php
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ public function getInfo(bool $extend = true, bool $convert = false): array

// Now include all standard commands
if ($this instanceof Server) {
$standardCommands = ['whoami', 'serverinfo', 'serverinfoserver info'];
$standardCommands = ['whoami', 'serverinfo'];
foreach ($standardCommands as $cmd) {
try {
$result = $this->{$cmd}(); // Calls the respective function
Expand Down
Loading
Loading