2020-01-26 08:21:34 -05:00
# include <memory>
2020-04-23 09:36:58 -04:00
# include <vector>
2020-01-26 08:21:34 -05:00
# include <bitset>
# include <algorithm>
# include "../../build.h"
# include "../ConnectedClient.h"
# include "../InternalClient.h"
# include "../voice/VoiceClient.h"
# include "PermissionManager.h"
# include "../../InstanceHandler.h"
# include "../../server/QueryServer.h"
# include "../music/MusicClient.h"
# include "../query/QueryClient.h"
# include "../../manager/ConversationManager.h"
# include "../../manager/PermissionNameMapper.h"
2020-06-28 08:01:14 -04:00
# include "../../manager/ActionLogger.h"
2020-01-26 08:21:34 -05:00
# include <cstdint>
# include "helpers.h"
2020-05-07 15:28:15 -04:00
# include "./bulk_parsers.h"
2020-01-26 08:21:34 -05:00
# include <Properties.h>
# include <log/LogUtils.h>
# include <misc/sassert.h>
# include <misc/base64.h>
# include <misc/hex.h>
# include <misc/rnd.h>
# include <bbcode/bbcodes.h>
using namespace std : : chrono ;
using namespace std ;
using namespace ts ;
using namespace ts : : server ;
# define QUERY_PASSWORD_LENGTH 12
command_result ConnectedClient : : handleCommandClientGetVariables ( Command & cmd ) {
CMD_REQ_SERVER ;
2020-02-01 08:32:16 -05:00
ConnectedLockedClient client { this - > server - > find_client_by_id ( cmd [ " clid " ] . as < ClientId > ( ) ) } ;
2020-04-10 17:29:51 -04:00
{
shared_lock tree_lock ( this - > channel_lock ) ;
2020-01-26 08:21:34 -05:00
2020-04-10 17:29:51 -04:00
if ( ! client | | ( client . client ! = this & & ! this - > isClientVisible ( client . client , false ) ) )
return command_result { error : : client_invalid_id , " " } ;
2020-01-26 08:21:34 -05:00
2020-04-10 17:29:51 -04:00
deque < const property : : PropertyDescription * > props ;
for ( auto & prop : client - > properties ( ) - > list_properties ( property : : FLAG_CLIENT_VARIABLE , this - > getType ( ) = = CLIENT_TEAMSPEAK ? property : : FLAG_NEW : ( uint16_t ) 0 ) ) {
props . push_back ( & prop . type ( ) ) ;
}
2020-01-26 08:21:34 -05:00
2020-04-10 17:29:51 -04:00
this - > notifyClientUpdated ( client . client , props , false ) ;
}
if ( client . client = = this & & this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK )
this - > subscribeChannel ( { this - > currentChannel } , true , true ) ; /* lets show the clients in the current channel because we've not done that while joining (speed improvement ;))*/
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientKick ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
2020-04-28 12:27:49 -04:00
command_result_bulk result { } ;
result . reserve ( cmd . bulkCount ( ) ) ;
2020-04-23 09:36:58 -04:00
std : : vector < ConnectedLockedClient < ConnectedClient > > clients { } ;
clients . reserve ( cmd . bulkCount ( ) ) ;
2020-01-26 08:21:34 -05:00
auto type = cmd [ " reasonid " ] . as < ViewReasonId > ( ) ;
2020-04-23 09:36:58 -04:00
auto target_channel = type = = ViewReasonId : : VREASON_CHANNEL_KICK ? this - > server - > channelTree - > getDefaultChannel ( ) : nullptr ;
for ( size_t index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
ConnectedLockedClient < ConnectedClient > client { this - > server - > find_client_by_id ( cmd [ index ] [ " clid " ] . as < ClientId > ( ) ) } ;
if ( ! client ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( error : : client_invalid_id ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
2020-06-28 08:01:14 -04:00
2020-04-23 09:36:58 -04:00
if ( client - > getType ( ) = = CLIENT_MUSIC ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( error : : client_invalid_type ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
if ( type = = ViewReasonId : : VREASON_CHANNEL_KICK ) {
2020-06-25 12:15:15 -04:00
auto kick_power = this - > calculate_permission ( permission : : i_client_kick_from_channel_power , client - > getChannelId ( ) ) ;
2020-04-23 09:36:58 -04:00
if ( ! permission : : v2 : : permission_granted ( client - > calculate_permission ( permission : : i_client_needed_kick_from_channel_power , client - > getChannelId ( ) ) , kick_power ) ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( permission : : i_client_needed_kick_from_channel_power ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
} else {
2020-06-25 12:15:15 -04:00
auto kick_power = this - > calculate_permission ( permission : : i_client_kick_from_server_power , client - > getChannelId ( ) ) ;
2020-04-23 09:36:58 -04:00
if ( ! permission : : v2 : : permission_granted ( client - > calculate_permission ( permission : : i_client_needed_kick_from_server_power , client - > getChannelId ( ) ) , kick_power ) ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( permission : : i_client_needed_kick_from_server_power ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
}
clients . emplace_back ( std : : move ( client ) ) ;
2020-04-28 12:27:49 -04:00
result . emplace_result ( error : : ok ) ;
2020-04-23 09:36:58 -04:00
}
for ( auto & client : clients ) {
2020-06-28 08:01:14 -04:00
auto old_channel = client - > getChannel ( ) ;
if ( ! old_channel ) continue ;
2020-04-23 09:36:58 -04:00
if ( target_channel ) {
this - > server - > notify_client_kick ( client . client , this - > ref ( ) , cmd [ " reasonmsg " ] . as < std : : string > ( ) , target_channel ) ;
2020-06-28 08:01:14 -04:00
serverInstance - > action_logger ( ) - > client_channel_logger . log_client_kick ( this - > getServerId ( ) , this - > ref ( ) , client - > ref ( ) , target_channel - > channelId ( ) , target_channel - > name ( ) , old_channel - > channelId ( ) , old_channel - > name ( ) ) ;
2020-04-23 09:36:58 -04:00
} else {
this - > server - > notify_client_kick ( client . client , this - > ref ( ) , cmd [ " reasonmsg " ] . as < std : : string > ( ) , nullptr ) ;
client - > close_connection ( system_clock : : now ( ) + seconds ( 1 ) ) ;
2020-06-28 08:01:14 -04:00
serverInstance - > action_logger ( ) - > client_channel_logger . log_client_kick ( this - > getServerId ( ) , this - > ref ( ) , client - > ref ( ) , 0 , " " , old_channel - > channelId ( ) , old_channel - > name ( ) ) ;
2020-04-23 09:36:58 -04:00
}
2020-01-26 08:21:34 -05:00
}
2020-04-28 12:27:49 -04:00
return command_result { std : : forward < command_result_bulk > ( result ) } ;
2020-01-26 08:21:34 -05:00
}
command_result ConnectedClient : : handleCommandClientGetIds ( Command & cmd ) {
CMD_REQ_SERVER ;
bool error = false ;
bool found = false ;
auto client_list = this - > server - > getClients ( ) ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientids " : " " ) ;
int result_index = 0 ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto unique_id = cmd [ index ] [ " cluid " ] . as < string > ( ) ;
for ( const auto & entry : client_list ) {
if ( entry - > getUid ( ) = = unique_id ) {
if ( ! config : : server : : show_invisible_clients_as_online & & ! this - > channels - > channel_visible ( entry - > currentChannel , nullptr ) )
continue ;
notify [ result_index ] [ " name " ] = entry - > getDisplayName ( ) ;
notify [ result_index ] [ " clid " ] = entry - > getClientId ( ) ;
notify [ result_index ] [ " cluid " ] = entry - > getUid ( ) ;
result_index + + ;
found = true ;
}
}
if ( found ) found = false ;
else error = false ;
}
string uid = cmd [ " cluid " ] ;
if ( result_index > 0 ) {
this - > sendCommand ( notify ) ;
}
if ( error ) {
return command_result { error : : database_empty_result } ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientMove ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 10 ) ;
shared_lock server_channel_r_lock ( this - > server - > channel_tree_lock ) ;
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) {
return command_result { error : : channel_invalid_id } ;
}
auto permission_cache = make_shared < CalculateCache > ( ) ;
2020-05-13 05:51:01 -04:00
2021-02-25 05:13:30 -05:00
auto & channel_whitelist = this - > join_whitelisted_channel ;
auto whitelist_entry = std : : find_if ( channel_whitelist . begin ( ) , channel_whitelist . end ( ) , [ & ] ( const auto & entry ) { return entry . first = = channel - > channelId ( ) ; } ) ;
if ( whitelist_entry ! = channel_whitelist . end ( ) ) {
debugMessage ( this - > getServerId ( ) , " {} Allowing client to join channel {} because the token he used earlier explicitly allowed it. " , this - > getLoggingPrefix ( ) , channel - > channelId ( ) ) ;
if ( whitelist_entry - > second ! = " ignore " ) {
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] , true ) ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_join_ignore_password , channel - > channelId ( ) ) ) ) {
return command_result { error : : channel_invalid_password } ;
}
}
}
} else {
if ( ! cmd [ 0 ] . has ( " cpw " ) ) {
cmd [ " cpw " ] = " " ;
}
2020-01-26 08:21:34 -05:00
2021-02-25 05:13:30 -05:00
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] , true ) ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_join_ignore_password , channel - > channelId ( ) ) ) ) {
return command_result { error : : channel_invalid_password } ;
}
}
auto permission_error = this - > calculate_and_get_join_state ( channel ) ;
if ( permission_error ! = permission : : unknown ) {
return command_result { permission_error } ;
}
}
channel_whitelist . clear ( ) ;
2020-01-26 08:21:34 -05:00
2020-04-28 12:27:49 -04:00
command_result_bulk result { } ;
result . reserve ( cmd . bulkCount ( ) ) ;
2020-04-23 09:36:58 -04:00
std : : vector < ConnectedLockedClient < ConnectedClient > > clients { } ;
for ( size_t index { 0 } ; index < cmd . bulkCount ( ) ; index + + ) {
auto target_client_id = cmd [ index ] [ " clid " ] . as < ClientId > ( ) ;
ConnectedLockedClient target_client { target_client_id = = 0 ? this - > ref ( ) : this - > server - > find_client_by_id ( target_client_id ) } ;
if ( ! target_client ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( error : : client_invalid_id ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
if ( ! target_client - > getChannel ( ) ) {
if ( target_client . client ! = this ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( error : : client_invalid_id ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
}
2020-05-13 05:51:01 -04:00
if ( target_client - > getChannel ( ) = = channel ) {
result . emplace_result ( error : : ok ) ;
continue ;
}
2020-04-23 09:36:58 -04:00
if ( target_client . client ! = this ) {
2020-05-13 05:51:01 -04:00
if ( ! permission : : v2 : : permission_granted ( target_client - > calculate_permission ( permission : : i_client_needed_move_power , target_client - > getChannelId ( ) ) , this - > calculate_permission ( permission : : i_client_move_power , target_client - > getChannelId ( ) ) ) ) {
result . emplace_result ( permission : : i_client_move_power ) ;
continue ;
}
if ( ! permission : : v2 : : permission_granted ( target_client - > calculate_permission ( permission : : i_client_needed_move_power , channel - > channelId ( ) ) , this - > calculate_permission ( permission : : i_client_move_power , channel - > channelId ( ) ) ) ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( permission : : i_client_move_power ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
}
clients . emplace_back ( std : : move ( target_client ) ) ;
2020-04-29 04:34:22 -04:00
result . emplace_result ( error : : ok ) ;
2020-04-23 09:36:58 -04:00
}
2021-02-25 05:13:30 -05:00
/* FIXME: Some kind of invite key frags to prevent limit checking! */
2021-03-01 08:16:44 -05:00
if ( ! channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ] . as_unchecked < bool > ( ) | | ! channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED ] . as_unchecked < bool > ( ) ) {
2020-01-26 08:21:34 -05:00
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_join_ignore_maxclients , channel - > channelId ( ) ) ) ) {
2021-03-01 08:16:44 -05:00
if ( ! channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ] . as_unchecked < bool > ( ) ) {
auto maxClients = channel - > properties ( ) [ property : : CHANNEL_MAXCLIENTS ] . as_unchecked < int32_t > ( ) ;
2021-02-25 05:13:30 -05:00
if ( maxClients > = 0 & & maxClients < this - > server - > getClientsByChannel ( channel ) . size ( ) + clients . size ( ) ) {
2020-01-26 08:21:34 -05:00
return command_result { error : : channel_maxclients_reached } ;
2021-02-25 05:13:30 -05:00
}
2020-01-26 08:21:34 -05:00
}
2021-03-01 08:16:44 -05:00
if ( ! channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED ] . as_unchecked < bool > ( ) ) {
2020-01-26 08:21:34 -05:00
shared_ptr < BasicChannel > family_root ;
2021-03-01 08:16:44 -05:00
if ( channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ] . as_unchecked < bool > ( ) ) {
2020-01-26 08:21:34 -05:00
family_root = channel ;
2021-03-01 08:16:44 -05:00
while ( family_root & &
family_root - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ] . as_unchecked < bool > ( ) ) {
2020-04-23 09:36:58 -04:00
family_root = family_root - > parent ( ) ;
2021-02-25 05:13:30 -05:00
}
2020-01-26 08:21:34 -05:00
}
if ( family_root & & ! family_root - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED ] ) { //Could not be CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED
2021-03-01 08:16:44 -05:00
auto maxClients = family_root - > properties ( ) [ property : : CHANNEL_MAXFAMILYCLIENTS ] . as_unchecked < int32_t > ( ) ;
2020-04-23 09:36:58 -04:00
auto client_count = 0 ;
2021-02-25 05:13:30 -05:00
for ( const auto & entry : this - > server - > getClientsByChannelRoot ( channel , false ) ) {
if ( entry . get ( ) ! = this ) {
client_count + + ; //Dont count the client itself
}
}
2020-04-23 09:36:58 -04:00
2021-02-25 05:13:30 -05:00
if ( maxClients > = 0 & & maxClients < client_count + clients . size ( ) ) {
2020-01-26 08:21:34 -05:00
return command_result { error : : channel_maxfamily_reached } ;
2021-02-25 05:13:30 -05:00
}
2020-01-26 08:21:34 -05:00
}
}
}
}
server_channel_r_lock . unlock ( ) ;
unique_lock server_channel_w_lock ( this - > server - > channel_tree_lock ) ;
2020-04-23 09:36:58 -04:00
std : : vector < std : : shared_ptr < BasicChannel > > channels { } ;
channels . reserve ( clients . size ( ) ) ;
for ( auto & client : clients ) {
auto oldChannel = client - > getChannel ( ) ;
2021-02-25 05:13:30 -05:00
if ( ! oldChannel ) {
continue ;
}
2020-05-07 15:28:15 -04:00
2020-04-23 09:36:58 -04:00
this - > server - > client_move (
client . client ,
channel ,
2021-02-21 14:28:59 -05:00
client . client = = this ? nullptr : this - > ref ( ) ,
2020-04-23 09:36:58 -04:00
" " ,
client . client = = this ? ViewReasonId : : VREASON_USER_ACTION : ViewReasonId : : VREASON_MOVED ,
true ,
server_channel_w_lock
) ;
2020-06-28 08:01:14 -04:00
serverInstance - > action_logger ( ) - > client_channel_logger . log_client_move ( this - > getServerId ( ) , this - > ref ( ) , client - > ref ( ) , channel - > channelId ( ) , channel - > name ( ) , oldChannel - > channelId ( ) , oldChannel - > name ( ) ) ;
2021-02-25 05:13:30 -05:00
if ( std : : find_if ( channels . begin ( ) , channels . end ( ) , [ & ] ( const std : : shared_ptr < BasicChannel > & channel ) { return & * channel = = & * oldChannel ; } ) = = channels . end ( ) ) {
2020-04-23 09:36:58 -04:00
channels . push_back ( oldChannel ) ;
2021-02-25 05:13:30 -05:00
}
2020-04-23 09:36:58 -04:00
}
2020-04-28 12:27:49 -04:00
for ( const auto & oldChannel : channels ) {
2020-12-04 06:23:12 -05:00
if ( ! server_channel_w_lock . owns_lock ( ) ) {
2020-01-26 08:21:34 -05:00
server_channel_w_lock . lock ( ) ;
2020-12-04 06:23:12 -05:00
}
2021-03-01 08:16:44 -05:00
if ( oldChannel - > channelType ( ) = = ChannelType : : temporary & &
oldChannel - > properties ( ) [ property : : CHANNEL_DELETE_DELAY ] . as_unchecked < int64_t > ( ) = = 0 ) {
2020-12-04 06:23:12 -05:00
if ( this - > server - > getClientsByChannelRoot ( oldChannel , false ) . empty ( ) ) {
2020-06-28 08:01:14 -04:00
this - > server - > delete_channel ( dynamic_pointer_cast < ServerChannel > ( oldChannel ) , this - > ref ( ) , " temporary auto delete " , server_channel_w_lock , true ) ;
2020-12-04 06:23:12 -05:00
}
}
if ( server_channel_w_lock . owns_lock ( ) ) {
2020-01-26 08:21:34 -05:00
server_channel_w_lock . unlock ( ) ;
2020-12-04 06:23:12 -05:00
}
2020-01-26 08:21:34 -05:00
}
2020-04-28 12:27:49 -04:00
return command_result { std : : forward < command_result_bulk > ( result ) } ;
2020-01-26 08:21:34 -05:00
}
command_result ConnectedClient : : handleCommandClientPoke ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
2020-04-28 12:27:49 -04:00
command_result_bulk result { } ;
result . reserve ( cmd . bulkCount ( ) ) ;
2020-04-23 09:36:58 -04:00
std : : vector < ConnectedLockedClient < ConnectedClient > > clients { } ;
2020-04-24 16:04:07 -04:00
clients . reserve ( cmd . bulkCount ( ) ) ;
2020-01-26 08:21:34 -05:00
2020-04-23 09:36:58 -04:00
for ( size_t index { 0 } ; index < cmd . bulkCount ( ) ; index + + ) {
2020-04-28 12:27:49 -04:00
ConnectedLockedClient client { this - > server - > find_client_by_id ( cmd [ index ] [ " clid " ] . as < ClientId > ( ) ) } ;
2020-04-23 09:36:58 -04:00
if ( ! client ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( error : : client_invalid_id ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
if ( client - > getType ( ) = = CLIENT_MUSIC ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( error : : client_invalid_type ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
auto own_permission = this - > calculate_permission ( permission : : i_client_poke_power , client - > getChannelId ( ) ) ;
if ( ! permission : : v2 : : permission_granted ( client - > calculate_permission ( permission : : i_client_needed_poke_power , client - > getChannelId ( ) ) , own_permission ) ) {
2020-04-28 12:27:49 -04:00
result . emplace_result ( permission : : i_client_poke_power ) ;
2020-04-23 09:36:58 -04:00
continue ;
}
clients . push_back ( std : : move ( client ) ) ;
2020-04-28 12:27:49 -04:00
result . emplace_result ( error : : ok ) ;
2020-04-23 09:36:58 -04:00
}
2020-04-28 12:27:49 -04:00
/* clients might be empty ;) */
if ( clients . size ( ) > 1 ) {
2020-04-23 09:36:58 -04:00
auto max_clients = this - > calculate_permission ( permission : : i_client_poke_max_clients , 0 ) ;
if ( ! permission : : v2 : : permission_granted ( clients . size ( ) , max_clients ) )
return command_result { permission : : i_client_poke_max_clients } ;
}
2020-04-28 12:27:49 -04:00
2020-07-30 05:50:31 -04:00
auto message = cmd [ " msg " ] . string ( ) ;
2020-08-18 16:03:07 -04:00
if ( count_characters ( message ) > ts : : config : : server : : limits : : poke_message_length )
2020-07-30 05:50:31 -04:00
return command_result { error : : parameter_invalid_size , " msg " } ;
2020-04-23 09:36:58 -04:00
for ( auto & client : clients )
2021-02-21 14:28:59 -05:00
client - > notifyClientPoke ( this - > ref ( ) , message ) ;
2020-04-28 12:27:49 -04:00
return command_result { std : : forward < command_result_bulk > ( result ) } ;
2020-01-26 08:21:34 -05:00
}
command_result ConnectedClient : : handleCommandClientChatComposing ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 0 ) ;
2020-02-01 08:32:16 -05:00
ConnectedLockedClient client { this - > server - > find_client_by_id ( cmd [ " clid " ] . as < ClientId > ( ) ) } ;
2020-01-26 08:21:34 -05:00
if ( ! client ) return command_result { error : : client_invalid_id } ;
2021-02-21 14:28:59 -05:00
client - > notifyClientChatComposing ( this - > ref ( ) ) ;
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientChatClosed ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
2020-02-01 08:32:16 -05:00
ConnectedLockedClient < ConnectedClient > client { this - > server - > find_client_by_id ( cmd [ " clid " ] . as < ClientId > ( ) ) } ;
2020-01-26 08:21:34 -05:00
if ( ! client ) return command_result { error : : client_invalid_id } ;
{
unique_lock channel_lock ( this - > channel_lock ) ;
2020-12-05 04:26:12 -05:00
this - > open_private_conversations . erase ( remove_if ( this - > open_private_conversations . begin ( ) , this - > open_private_conversations . end ( ) , [ & ] ( const weak_ptr < ConnectedClient > & weak ) {
2020-01-26 08:21:34 -05:00
return weak . lock ( ) = = client ;
2020-12-05 04:26:12 -05:00
} ) , this - > open_private_conversations . end ( ) ) ;
2020-01-26 08:21:34 -05:00
}
{
2020-02-01 08:32:16 -05:00
unique_lock channel_lock ( client - > get_channel_lock ( ) ) ;
2020-12-05 04:26:12 -05:00
client - > open_private_conversations . erase ( remove_if ( client - > open_private_conversations . begin ( ) , client - > open_private_conversations . end ( ) , [ & ] ( const weak_ptr < ConnectedClient > & weak ) {
2020-01-26 08:21:34 -05:00
return weak . lock ( ) . get ( ) = = this ;
2020-12-05 04:26:12 -05:00
} ) , client - > open_private_conversations . end ( ) ) ;
2020-01-26 08:21:34 -05:00
}
2021-02-21 14:28:59 -05:00
client - > notifyClientChatClosed ( this - > ref ( ) ) ;
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientDbList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_client_dblist , 1 ) ;
2020-07-30 14:25:45 -04:00
size_t offset = cmd [ 0 ] . has ( " start " ) ? cmd [ " start " ] . as < size_t > ( ) : 0 ;
size_t limit = cmd [ 0 ] . has ( " duration " ) ? cmd [ " duration " ] . as < int > ( ) : 0 ;
if ( limit > 2000 | | limit < 1 )
limit = 2000 ;
2020-01-26 08:21:34 -05:00
2020-07-30 14:25:45 -04:00
ts : : command_builder result { this - > notify_response_command ( " notifyclientdblist " ) } ;
result . reserve_bulks ( limit ) ;
2020-07-31 11:35:14 -04:00
struct CallbackArgument {
ts : : command_builder & result ;
bool show_ip { false } ;
size_t command_index { 0 } ;
} ;
CallbackArgument callback_argument { result } ;
callback_argument . show_ip = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_remoteaddress_view , 0 ) ) ;
serverInstance - > databaseHelper ( ) - > listDatabaseClients ( this - > getServerId ( ) , { offset } , { limit } , [ ] ( void * ptr_data , const DatabaseClient & client ) {
auto argument = ( CallbackArgument * ) ptr_data ;
auto bulk = argument - > result . bulk ( argument - > command_index + + ) ;
bulk . reserve ( 300 ) ;
bulk . put_unchecked ( " cldbid " , client . client_database_id ) ;
bulk . put_unchecked ( " client_unique_identifier " , client . client_unique_id ) ;
bulk . put_unchecked ( " client_nickname " , client . client_nickname ) ;
bulk . put_unchecked ( " client_lastip " , argument - > show_ip ? client . client_ip : " hidden " ) ;
bulk . put_unchecked ( " client_lastconnected " , client . client_last_connected ) ;
bulk . put_unchecked ( " client_created " , client . client_created ) ;
bulk . put_unchecked ( " client_totalconnections " , client . client_total_connections ) ;
bulk . put_unchecked ( " client_login_name " , client . client_login_name ) ;
bulk . put_unchecked ( " client_description " , client . client_description ) ;
} , & callback_argument ) ;
if ( callback_argument . command_index = = 0 )
2020-07-30 14:25:45 -04:00
return command_result { error : : database_empty_result } ;
2020-01-26 08:21:34 -05:00
if ( cmd . hasParm ( " count " ) ) {
2020-07-30 14:25:45 -04:00
size_t count { 0 } ;
sql : : command ( this - > server - > getSql ( ) , " SELECT COUNT(`client_database_id`) AS `count` FROM `clients_server` WHERE `server_id` = :sid " , variable { " :sid " , this - > server - > getServerId ( ) } )
. query ( [ & ] ( int , std : : string * v , std : : string * ) {
count = stoll ( v [ 0 ] ) ;
} ) ;
result . put_unchecked ( 0 , " count " , count ) ;
2020-01-26 08:21:34 -05:00
}
2020-07-30 14:25:45 -04:00
this - > sendCommand ( result ) ;
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientDBEdit ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_modify_dbproperties , 1 ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return command_result { error : : database_empty_result , " invalid cldbid " } ;
auto props = serverInstance - > databaseHelper ( ) - > loadClientProperties ( this - > server , cmd [ " cldbid " ] , ClientType : : CLIENT_TEAMSPEAK ) ;
for ( auto & elm : cmd [ 0 ] . keys ( ) ) {
if ( elm = = " cldbid " ) continue ;
2020-04-08 07:01:41 -04:00
const auto & info = property : : find < property : : ClientProperties > ( elm ) ;
if ( info = = property : : CLIENT_UNDEFINED ) {
2020-01-26 08:21:34 -05:00
logError ( this - > getServerId ( ) , " Client " + this - > getDisplayName ( ) + " tried to change someone's db entry, but the entry in unknown: " + elm ) ;
continue ;
}
2020-04-08 07:01:41 -04:00
if ( ! info . validate_input ( cmd [ elm ] . as < string > ( ) ) ) {
logError ( this - > getServerId ( ) , " Client " + this - > getDisplayName ( ) + " tried to change a property to an invalid value. (Value: ' " + cmd [ elm ] . as < string > ( ) + " ', Property: ' " + std : : string { info . name } + " ') " ) ;
2020-01-26 08:21:34 -05:00
continue ;
}
( * props ) [ info ] = cmd [ elm ] . string ( ) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientEdit ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
2020-02-01 08:32:16 -05:00
ConnectedLockedClient client { this - > server - > find_client_by_id ( cmd [ " clid " ] . as < ClientId > ( ) ) } ;
2020-01-26 08:21:34 -05:00
if ( ! client ) return command_result { error : : client_invalid_id } ;
2020-02-01 08:32:16 -05:00
return this - > handleCommandClientEdit ( cmd , client . client ) ;
2020-01-26 08:21:34 -05:00
}
command_result ConnectedClient : : handleCommandClientEdit ( Command & cmd , const std : : shared_ptr < ConnectedClient > & client ) {
assert ( client ) ;
auto self = client = = this ;
CMD_CHK_AND_INC_FLOOD_POINTS ( self ? 15 : 25 ) ;
CMD_RESET_IDLE ;
bool update_talk_rights = false ;
unique_ptr < lock_guard < std : : recursive_mutex > > nickname_lock ;
2020-04-08 07:01:41 -04:00
std : : deque < std : : pair < const property : : PropertyDescription * , std : : string > > keys ;
2020-01-26 08:21:34 -05:00
for ( const auto & key : cmd [ 0 ] . keys ( ) ) {
if ( key = = " return_code " ) continue ;
if ( key = = " clid " ) continue ;
2020-04-08 07:01:41 -04:00
const auto & info = property : : find < property : : ClientProperties > ( key ) ;
if ( info = = property : : CLIENT_UNDEFINED ) {
2020-01-26 08:21:34 -05:00
logError ( this - > getServerId ( ) , R " ([{}] Tried to change a not existing client property for {}. (Key: " { } " , Value: " { } " )) " , CLIENT_STR_LOG_PREFIX , CLIENT_STR_LOG_PREFIX_ ( client ) , key , cmd [ key ] . string ( ) ) ;
continue ;
}
2020-04-08 07:01:41 -04:00
if ( ( info . flags & property : : FLAG_USER_EDITABLE ) = = 0 ) {
2020-01-26 08:21:34 -05:00
logError ( this - > getServerId ( ) , R " ([{}] Tried to change a not user editable client property for {}. (Key: " { } " , Value: " { } " )) " , CLIENT_STR_LOG_PREFIX , CLIENT_STR_LOG_PREFIX_ ( client ) , key , cmd [ key ] . string ( ) ) ;
continue ;
}
2020-04-08 07:01:41 -04:00
if ( ! info . validate_input ( cmd [ key ] . as < string > ( ) ) ) {
2020-01-26 08:21:34 -05:00
logError ( this - > getServerId ( ) , R " ([{}] Tried to change a client property to an invalid value for {}. (Key: " { } " , Value: " { } " )) " , CLIENT_STR_LOG_PREFIX , CLIENT_STR_LOG_PREFIX_ ( client ) , key , cmd [ key ] . string ( ) ) ;
continue ;
}
2021-03-01 08:16:44 -05:00
if ( client - > properties ( ) [ & info ] . as_unchecked < string > ( ) = = cmd [ key ] . as < string > ( ) ) continue ;
2020-01-26 08:21:34 -05:00
2020-04-08 07:01:41 -04:00
if ( info = = property : : CLIENT_DESCRIPTION ) {
2020-01-26 08:21:34 -05:00
if ( self ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_client_modify_own_description , 1 , client - > getChannelId ( ) ) ;
} else if ( client - > getType ( ) = = ClientType : : CLIENT_MUSIC ) {
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
} else {
ACTION_REQUIRES_PERMISSION ( permission : : b_client_modify_description , 1 , client - > getChannelId ( ) ) ;
}
string value = cmd [ " client_description " ] . string ( ) ;
if ( count_characters ( value ) > 200 ) return command_result { error : : parameter_invalid , " Invalid description length. A maximum of 200 characters is allowed! " } ;
2020-04-08 07:01:41 -04:00
} else if ( info = = property : : CLIENT_IS_TALKER ) {
2020-01-26 08:21:34 -05:00
ACTION_REQUIRES_PERMISSION ( permission : : b_client_set_flag_talker , 1 , client - > getChannelId ( ) ) ;
cmd [ " client_is_talker " ] = cmd [ " client_is_talker " ] . as < bool > ( ) ;
cmd [ " client_talk_request " ] = 0 ;
update_talk_rights = true ;
2020-04-08 07:01:41 -04:00
keys . emplace_back ( & property : : describe ( property : : CLIENT_IS_TALKER ) , " client_is_talker " ) ;
keys . emplace_back ( & property : : describe ( property : : CLIENT_TALK_REQUEST ) , " client_talk_request " ) ;
2020-01-26 08:21:34 -05:00
continue ;
2020-04-08 07:01:41 -04:00
} else if ( info = = property : : CLIENT_NICKNAME ) {
2020-01-26 08:21:34 -05:00
if ( ! self ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_rename_power , client - > calculate_permission ( permission : : i_client_music_needed_rename_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
}
string name = cmd [ " client_nickname " ] . string ( ) ;
if ( count_characters ( name ) < 3 ) return command_result { error : : parameter_invalid , " Invalid name length. A minimum of 3 characters is required! " } ;
if ( count_characters ( name ) > 30 ) return command_result { error : : parameter_invalid , " Invalid name length. A maximum of 30 characters is allowed! " } ;
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_ignore_bans , client - > getClientId ( ) ) ) ) {
auto banRecord = serverInstance - > banManager ( ) - > findBanByName ( this - > getServerId ( ) , name ) ;
if ( banRecord )
return command_result { error : : client_nickname_inuse , string ( ) + " This nickname is " + ( banRecord - > serverId = = 0 ? " globally " : " " ) + " banned for the reason: " + banRecord - > reason } ;
}
if ( this - > server ) {
nickname_lock = std : : make_unique < lock_guard < recursive_mutex > > ( this - > server - > client_nickname_lock ) ;
bool self = false ;
for ( const auto & cl : this - > server - > getClients ( ) ) {
if ( cl - > getDisplayName ( ) = = cmd [ " client_nickname " ] . string ( ) ) {
if ( cl = = this )
self = true ;
else
return command_result { error : : client_nickname_inuse , " This nickname is already in use " } ;
}
}
if ( self ) {
nickname_lock . reset ( ) ;
continue ;
}
}
2020-09-24 16:57:10 -04:00
} else if ( info = = property : : CLIENT_NICKNAME_PHONETIC ) {
if ( ! self ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_rename_power , client - > calculate_permission ( permission : : i_client_music_needed_rename_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
}
string name = cmd [ " client_nickname_phonetic " ] . string ( ) ;
if ( count_characters ( name ) > 30 ) return command_result { error : : parameter_invalid , " Invalid name length. A maximum of 30 characters is allowed! " } ;
2020-04-08 07:01:41 -04:00
} else if ( info = = property : : CLIENT_PLAYER_VOLUME ) {
2020-01-26 08:21:34 -05:00
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
auto bot = dynamic_pointer_cast < MusicClient > ( client ) ;
assert ( bot ) ;
auto volume = cmd [ " player_volume " ] . as < float > ( ) ;
auto max_volume = this - > calculate_permission ( permission : : i_client_music_create_modify_max_volume , client - > getClientId ( ) ) ;
if ( max_volume . has_value & & ! permission : : v2 : : permission_granted ( volume * 100 , max_volume ) )
return command_result { permission : : i_client_music_create_modify_max_volume } ;
bot - > volume_modifier ( cmd [ " player_volume " ] ) ;
2020-04-08 07:01:41 -04:00
} else if ( info = = property : : CLIENT_IS_CHANNEL_COMMANDER ) {
2020-01-26 08:21:34 -05:00
if ( ! self ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
}
if ( cmd [ " client_is_channel_commander " ] . as < bool > ( ) )
ACTION_REQUIRES_PERMISSION ( permission : : b_client_use_channel_commander , 1 , client - > getChannelId ( ) ) ;
2020-04-08 07:01:41 -04:00
} else if ( info = = property : : CLIENT_IS_PRIORITY_SPEAKER ) {
2020-01-26 08:21:34 -05:00
//FIXME allow other to remove this thing
if ( ! self ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC )
return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) )
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getClientId ( ) ) , client - > getClientId ( ) ) ;
}
if ( cmd [ " client_is_priority_speaker " ] . as < bool > ( ) )
ACTION_REQUIRES_PERMISSION ( permission : : b_client_use_priority_speaker , 1 , client - > getChannelId ( ) ) ;
} else if ( self & & key = = " client_talk_request " ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 20 ) ;
ACTION_REQUIRES_PERMISSION ( permission : : b_client_request_talker , 1 , client - > getChannelId ( ) ) ;
if ( cmd [ " client_talk_request " ] . as < bool > ( ) )
cmd [ " client_talk_request " ] = duration_cast < seconds > ( system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
else
cmd [ " client_talk_request " ] = 0 ;
2020-04-08 07:01:41 -04:00
keys . emplace_back ( & property : : describe ( property : : CLIENT_TALK_REQUEST ) , " client_talk_request " ) ;
2020-01-26 08:21:34 -05:00
continue ;
} else if ( self & & key = = " client_badges " ) {
std : : string str = cmd [ key ] ;
size_t index = 0 ;
int badgesTags = 0 ;
do {
index = str . find ( " badges " , index ) ;
if ( index < str . length ( ) ) badgesTags + + ;
index + + ;
} while ( index < str . length ( ) & & index ! = 0 ) ;
if ( badgesTags > = 2 ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_allow_invalid_badges , client - > getClientId ( ) ) ) )
( ( VoiceClient * ) this ) - > disconnect ( VREASON_SERVER_KICK , config : : messages : : kick_invalid_badges , this - > server ? this - > server - > serverAdmin : dynamic_pointer_cast < ConnectedClient > ( serverInstance - > getInitialServerAdmin ( ) ) , true ) ;
return command_result { error : : parameter_invalid , " Invalid badges " } ;
}
//FIXME stuff here
} else if ( ! self & & key = = " client_version " ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
} else if ( ! self & & key = = " client_platform " ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
} else if ( ! self & & key = = " client_country " ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
2020-04-08 07:01:41 -04:00
} else if ( ! self & & ( info = = property : : CLIENT_FLAG_NOTIFY_SONG_CHANGE /* || info == property::CLIENT_NOTIFY_SONG_MESSAGE*/ ) ) {
2020-01-26 08:21:34 -05:00
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
} else if ( ! self & & key = = " client_uptime_mode " ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return command_result { error : : client_invalid_type } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
}
if ( cmd [ key ] . as < MusicClient : : UptimeMode : : value > ( ) = = MusicClient : : UptimeMode : : TIME_SINCE_SERVER_START ) {
cmd [ " client_lastconnected " ] = duration_cast < seconds > ( this - > server - > startTimestamp . time_since_epoch ( ) ) . count ( ) ;
} else {
string value = client - > properties ( ) [ property : : CLIENT_CREATED ] ;
if ( value . empty ( ) )
value = " 0 " ;
cmd [ " client_lastconnected " ] = value ;
}
2020-04-08 07:01:41 -04:00
keys . emplace_back ( & property : : describe ( property : : CLIENT_LASTCONNECTED ) , " client_lastconnected " ) ;
} else if ( ! self & & info = = property : : CLIENT_BOT_TYPE ) {
2020-01-26 08:21:34 -05:00
ACTION_REQUIRES_PERMISSION ( permission : : i_client_music_modify_power , client - > calculate_permission ( permission : : i_client_music_needed_modify_power , client - > getChannelId ( ) ) , client - > getChannelId ( ) ) ;
auto type = cmd [ " client_bot_type " ] . as < MusicClient : : Type : : value > ( ) ;
if ( type = = MusicClient : : Type : : TEMPORARY ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_client_music_modify_temporary , 1 , client - > getChannelId ( ) ) ;
} else if ( type = = MusicClient : : Type : : SEMI_PERMANENT ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_client_music_modify_semi_permanent , 1 , client - > getChannelId ( ) ) ;
} else if ( type = = MusicClient : : Type : : PERMANENT ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_client_music_modify_permanent , 1 , client - > getChannelId ( ) ) ;
} else
return command_result { error : : parameter_invalid } ;
2020-04-08 07:01:41 -04:00
} else if ( info = = property : : CLIENT_AWAY_MESSAGE ) {
2020-01-26 08:21:34 -05:00
if ( ! self ) continue ;
2020-08-18 16:03:07 -04:00
if ( cmd [ " client_away_message " ] . string ( ) . length ( ) > ts : : config : : server : : limits : : afk_message_length )
2020-01-26 08:21:34 -05:00
return command_result { error : : parameter_invalid } ;
} else if ( ! self ) { /* dont edit random properties of other clients. For us self its allowed to edit the rest without permissions */
continue ;
2020-07-30 05:50:31 -04:00
} else if ( info = = property : : CLIENT_TALK_REQUEST_MSG ) {
2020-08-18 16:03:07 -04:00
if ( cmd [ " client_talk_request_msg " ] . string ( ) . length ( ) > ts : : config : : server : : limits : : talk_power_request_message_length )
2020-07-30 05:50:31 -04:00
return command_result { error : : parameter_invalid } ;
2020-01-26 08:21:34 -05:00
}
2020-04-08 07:01:41 -04:00
keys . emplace_back ( & info , key ) ;
2020-01-26 08:21:34 -05:00
}
2020-04-08 07:01:41 -04:00
deque < const property : : PropertyDescription * > updates ;
2020-01-26 08:21:34 -05:00
for ( const auto & key : keys ) {
2020-04-08 07:01:41 -04:00
if ( * key . first = = property : : CLIENT_IS_PRIORITY_SPEAKER ) {
2020-01-26 08:21:34 -05:00
client - > clientPermissions - > set_permission ( permission : : b_client_is_priority_speaker , { 1 , 0 } , cmd [ " client_is_priority_speaker " ] . as < bool > ( ) ? permission : : v2 : : PermissionUpdateType : : set_value : permission : : v2 : : PermissionUpdateType : : delete_value , permission : : v2 : : PermissionUpdateType : : do_nothing ) ;
}
2020-06-28 08:01:14 -04:00
auto property = client - > properties ( ) [ key . first ] ;
auto old_value = property . value ( ) ;
auto new_value = cmd [ 0 ] [ key . second ] . value ( ) ;
if ( old_value = = new_value )
continue ;
property = new_value ;
2020-01-26 08:21:34 -05:00
updates . push_back ( key . first ) ;
2020-06-28 08:01:14 -04:00
serverInstance - > action_logger ( ) - > client_edit_logger . log_client_edit (
this - > getServerId ( ) ,
this - > ref ( ) ,
client ,
* key . first ,
old_value ,
new_value
) ;
2020-01-26 08:21:34 -05:00
}
2020-12-04 06:23:12 -05:00
if ( update_talk_rights ) {
2020-07-28 12:36:32 -04:00
client - > updateTalkRights ( client - > calculate_permission ( permission : : i_client_talk_power , client - > getChannelId ( ) ) ) ;
2020-12-04 06:23:12 -05:00
}
2020-01-26 08:21:34 -05:00
2020-12-04 06:23:12 -05:00
if ( this - > server ) {
2020-01-26 08:21:34 -05:00
this - > server - > notifyClientPropertyUpdates ( client , updates ) ;
2020-12-04 06:23:12 -05:00
}
2020-01-26 08:21:34 -05:00
nickname_lock . reset ( ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientUpdate ( Command & cmd ) {
2021-02-21 14:28:59 -05:00
return this - > handleCommandClientEdit ( cmd , this - > ref ( ) ) ;
2020-01-26 08:21:34 -05:00
}
command_result ConnectedClient : : handleCommandClientMute ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
2020-02-01 08:32:16 -05:00
ConnectedLockedClient client { this - > server - > find_client_by_id ( cmd [ " clid " ] . as < ClientId > ( ) ) } ;
2020-01-26 08:21:34 -05:00
if ( ! client | | client - > getClientId ( ) = = this - > getClientId ( ) ) return command_result { error : : client_invalid_id } ;
{
unique_lock channel_lock ( this - > channel_lock ) ;
for ( const auto & weak : this - > mutedClients )
if ( weak . lock ( ) = = client ) return command_result { error : : ok } ;
2020-02-01 08:32:16 -05:00
this - > mutedClients . push_back ( client . client ) ;
2020-01-26 08:21:34 -05:00
}
if ( config : : voice : : notifyMuted )
2021-02-21 14:28:59 -05:00
client - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , this - > ref ( ) , client - > getClientId ( ) , 0 , system_clock : : now ( ) , config : : messages : : mute_notify_message ) ;
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientUnmute ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
2020-02-01 08:32:16 -05:00
ConnectedLockedClient client { this - > server - > find_client_by_id ( cmd [ " clid " ] . as < ClientId > ( ) ) } ;
2020-01-26 08:21:34 -05:00
if ( ! client | | client - > getClientId ( ) = = this - > getClientId ( ) ) return command_result { error : : client_invalid_id } ;
{
unique_lock channel_lock ( this - > channel_lock ) ;
2020-02-01 08:32:16 -05:00
this - > mutedClients . erase ( std : : remove_if ( this - > mutedClients . begin ( ) , this - > mutedClients . end ( ) , [ & ] ( const weak_ptr < ConnectedClient > & weak ) {
2020-01-26 08:21:34 -05:00
auto c = weak . lock ( ) ;
return ! c | | c = = client ;
} ) , this - > mutedClients . end ( ) ) ;
}
if ( config : : voice : : notifyMuted )
2021-02-21 14:28:59 -05:00
client - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , this - > ref ( ) , client - > getClientId ( ) , 0 , system_clock : : now ( ) , config : : messages : : unmute_notify_message ) ;
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
bool allow_ip = false ;
if ( cmd . hasParm ( " ip " ) )
allow_ip = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_remoteaddress_view , 0 ) ) ;
Command result ( " " ) ;
int index = 0 ;
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > client ) {
if ( client - > getType ( ) = = ClientType : : CLIENT_INTERNAL ) return ;
result [ index ] [ " clid " ] = client - > getClientId ( ) ;
if ( client - > getChannel ( ) )
result [ index ] [ " cid " ] = client - > getChannel ( ) - > channelId ( ) ;
else result [ index ] [ " cid " ] = 0 ;
result [ index ] [ " client_database_id " ] = client - > getClientDatabaseId ( ) ;
result [ index ] [ " client_nickname " ] = client - > getDisplayName ( ) ;
result [ index ] [ " client_type " ] = client - > getType ( ) ;
if ( cmd . hasParm ( " uid " ) )
result [ index ] [ " client_unique_identifier " ] = client - > getUid ( ) ;
if ( cmd . hasParm ( " away " ) ) {
2021-03-01 08:16:44 -05:00
result [ index ] [ " client_away " ] = client - > properties ( ) [ property : : CLIENT_AWAY ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_away_message " ] = client - > properties ( ) [ property : : CLIENT_AWAY_MESSAGE ] . as_unchecked < string > ( ) ;
2020-01-26 08:21:34 -05:00
}
if ( cmd . hasParm ( " groups " ) ) {
2021-03-01 08:16:44 -05:00
result [ index ] [ " client_channel_group_id " ] = client - > properties ( ) [ property : : CLIENT_CHANNEL_GROUP_ID ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_servergroups " ] = client - > properties ( ) [ property : : CLIENT_SERVERGROUPS ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_channel_group_inherited_channel_id " ] = client - > properties ( ) [ property : : CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID ] . as_unchecked < string > ( ) ;
2020-01-26 08:21:34 -05:00
}
if ( cmd . hasParm ( " times " ) ) {
result [ index ] [ " client_idle_time " ] = duration_cast < milliseconds > ( system_clock : : now ( ) - client - > idleTimestamp ) . count ( ) ;
2021-03-01 08:16:44 -05:00
result [ index ] [ " client_total_online_time " ] =
client - > properties ( ) [ property : : CLIENT_TOTAL_ONLINE_TIME ] . as_unchecked < int64_t > ( ) + duration_cast < seconds > ( system_clock : : now ( ) - client - > lastOnlineTimestamp ) . count ( ) ;
result [ index ] [ " client_month_online_time " ] =
client - > properties ( ) [ property : : CLIENT_MONTH_ONLINE_TIME ] . as_unchecked < int64_t > ( ) + duration_cast < seconds > ( system_clock : : now ( ) - client - > lastOnlineTimestamp ) . count ( ) ;
2020-01-26 08:21:34 -05:00
result [ index ] [ " client_idle_time " ] = duration_cast < milliseconds > ( system_clock : : now ( ) - client - > idleTimestamp ) . count ( ) ;
2021-03-01 08:16:44 -05:00
result [ index ] [ " client_created " ] = client - > properties ( ) [ property : : CLIENT_CREATED ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_lastconnected " ] = client - > properties ( ) [ property : : CLIENT_LASTCONNECTED ] . as_unchecked < string > ( ) ;
2020-01-26 08:21:34 -05:00
}
if ( cmd . hasParm ( " info " ) ) {
2021-03-01 08:16:44 -05:00
result [ index ] [ " client_version " ] = client - > properties ( ) [ property : : CLIENT_VERSION ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_platform " ] = client - > properties ( ) [ property : : CLIENT_PLATFORM ] . as_unchecked < string > ( ) ;
2020-01-26 08:21:34 -05:00
}
if ( cmd . hasParm ( " badges " ) )
2021-03-01 08:16:44 -05:00
result [ index ] [ " client_badges " ] = client - > properties ( ) [ property : : CLIENT_BADGES ] . as_unchecked < string > ( ) ;
2020-01-26 08:21:34 -05:00
if ( cmd . hasParm ( " country " ) )
2021-03-01 08:16:44 -05:00
result [ index ] [ " client_country " ] = client - > properties ( ) [ property : : CLIENT_COUNTRY ] . as_unchecked < string > ( ) ;
2020-01-26 08:21:34 -05:00
if ( cmd . hasParm ( " ip " ) )
2021-03-01 08:16:44 -05:00
result [ index ] [ " connection_client_ip " ] = allow_ip ? client - > properties ( ) [ property : : CONNECTION_CLIENT_IP ] . as_unchecked < string > ( ) : " hidden " ;
2020-01-26 08:21:34 -05:00
if ( cmd . hasParm ( " icon " ) )
2021-03-01 08:16:44 -05:00
result [ index ] [ " client_icon_id " ] = client - > properties ( ) [ property : : CLIENT_ICON_ID ] . as_unchecked < string > ( ) ;
2020-01-26 08:21:34 -05:00
if ( cmd . hasParm ( " voice " ) ) {
2021-03-01 08:16:44 -05:00
result [ index ] [ " client_talk_power " ] = client - > properties ( ) [ property : : CLIENT_TALK_POWER ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_flag_talking " ] = client - > properties ( ) [ property : : CLIENT_FLAG_TALKING ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_input_muted " ] = client - > properties ( ) [ property : : CLIENT_INPUT_MUTED ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_output_muted " ] = client - > properties ( ) [ property : : CLIENT_OUTPUT_MUTED ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_input_hardware " ] = client - > properties ( ) [ property : : CLIENT_INPUT_HARDWARE ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_output_hardware " ] = client - > properties ( ) [ property : : CLIENT_OUTPUT_HARDWARE ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_is_talker " ] = client - > properties ( ) [ property : : CLIENT_IS_TALKER ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_is_priority_speaker " ] = client - > properties ( ) [ property : : CLIENT_IS_PRIORITY_SPEAKER ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_is_recording " ] = client - > properties ( ) [ property : : CLIENT_IS_RECORDING ] . as_unchecked < string > ( ) ;
result [ index ] [ " client_is_channel_commander " ] = client - > properties ( ) [ property : : CLIENT_IS_CHANNEL_COMMANDER ] . as_unchecked < string > ( ) ;
2020-01-26 08:21:34 -05:00
}
index + + ;
} ) ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientGetDBIDfromUID ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
deque < string > unique_ids ;
2020-07-30 14:25:45 -04:00
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
unique_ids . push_back ( cmd [ index ] [ " cluid " ] ) ;
}
2020-01-26 08:21:34 -05:00
auto res = serverInstance - > databaseHelper ( ) - > queryDatabaseInfoByUid ( this - > server , unique_ids ) ;
if ( res . empty ( ) ) return command_result { error : : database_empty_result } ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientdbidfromuid " : " " ) ;
int result_index = 0 ;
for ( auto & info : res ) {
2020-07-30 14:25:45 -04:00
result [ result_index ] [ " cluid " ] = info - > client_unique_id ;
result [ result_index ] [ " cldbid " ] = info - > client_database_id ;
2020-01-26 08:21:34 -05:00
result_index + + ;
}
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientGetNameFromDBID ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
deque < ClientDbId > dbids ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + )
dbids . push_back ( cmd [ index ] [ " cldbid " ] . as < ClientDbId > ( ) ) ;
auto res = serverInstance - > databaseHelper ( ) - > queryDatabaseInfo ( this - > server , dbids ) ;
if ( res . empty ( ) ) return command_result { error : : database_empty_result } ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientgetnamefromdbid " : " " ) ;
int result_index = 0 ;
for ( auto & info : res ) {
2020-07-30 14:25:45 -04:00
result [ result_index ] [ " cluid " ] = info - > client_unique_id ;
result [ result_index ] [ " cldbid " ] = info - > client_database_id ;
result [ result_index ] [ " name " ] = info - > client_nickname ;
result [ result_index ] [ " clname " ] = info - > client_nickname ;
2020-01-26 08:21:34 -05:00
result_index + + ;
}
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientGetNameFromUid ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
deque < string > unique_ids ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + )
unique_ids . push_back ( cmd [ index ] [ " cluid " ] . as < string > ( ) ) ;
auto res = serverInstance - > databaseHelper ( ) - > queryDatabaseInfoByUid ( this - > server , unique_ids ) ;
if ( res . empty ( ) ) return command_result { error : : database_empty_result } ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientnamefromuid " : " " ) ;
int result_index = 0 ;
for ( auto & info : res ) {
2020-07-30 14:25:45 -04:00
result [ result_index ] [ " cluid " ] = info - > client_unique_id ;
result [ result_index ] [ " cldbid " ] = info - > client_database_id ;
result [ result_index ] [ " name " ] = info - > client_nickname ;
result [ result_index ] [ " clname " ] = info - > client_nickname ;
2020-01-26 08:21:34 -05:00
result_index + + ;
}
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientGetUidFromClid ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
bool error = false ;
bool found = false ;
auto client_list = this - > server - > getClients ( ) ;
2020-09-06 15:00:27 -04:00
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientuidfromclid " : " " ) ;
2020-01-26 08:21:34 -05:00
int result_index = 0 ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto client_id = cmd [ index ] [ " clid " ] . as < ClientId > ( ) ;
for ( const auto & entry : client_list ) {
if ( entry - > getClientId ( ) = = client_id ) {
notify [ result_index ] [ " clname " ] = entry - > getDisplayName ( ) ;
notify [ result_index ] [ " clid " ] = entry - > getClientId ( ) ;
notify [ result_index ] [ " cluid " ] = entry - > getUid ( ) ;
notify [ result_index ] [ " cldbid " ] = entry - > getClientDatabaseId ( ) ;
result_index + + ;
found = true ;
}
}
if ( found ) found = false ;
else error = false ;
}
if ( result_index > 0 )
this - > sendCommand ( notify ) ;
if ( error )
return command_result { error : : database_empty_result } ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientAddPerm ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto cldbid = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cldbid ) )
return command_result { error : : client_invalid_id } ;
2021-02-28 13:03:41 -05:00
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > getServerId ( ) , cldbid ) ;
2020-01-26 08:21:34 -05:00
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : i_client_permission_modify_power , this - > server - > calculate_permission ( permission : : i_client_needed_permission_modify_power , cldbid , ClientType : : CLIENT_TEAMSPEAK , 0 ) ) ;
2021-03-11 08:12:12 -05:00
ts : : command : : bulk_parser : : PermissionBulksParser pparser { cmd , true } ;
2020-05-07 15:28:15 -04:00
if ( ! pparser . validate ( this - > ref ( ) , 0 ) )
return pparser . build_command_result ( ) ;
2020-01-26 08:21:34 -05:00
2020-05-07 15:28:15 -04:00
bool update_channels { false } ;
for ( const auto & ppermission : pparser . iterate_valid_permissions ( ) ) {
ppermission . apply_to ( mgr , permission : : v2 : : PermissionUpdateType : : set_value ) ;
2020-06-28 08:01:14 -04:00
ppermission . log_update ( serverInstance - > action_logger ( ) - > permission_logger ,
this - > getServerId ( ) ,
this - > ref ( ) ,
log : : PermissionTarget : : CLIENT ,
permission : : v2 : : PermissionUpdateType : : set_value ,
cldbid , " " ,
0 , " "
) ;
2020-05-07 15:28:15 -04:00
update_channels | = ppermission . is_client_view_property ( ) ;
2020-01-26 08:21:34 -05:00
}
2020-05-07 15:28:15 -04:00
2020-01-26 08:21:34 -05:00
serverInstance - > databaseHelper ( ) - > saveClientPermissions ( this - > server , cldbid , mgr ) ;
auto onlineClients = this - > server - > findClientsByCldbId ( cldbid ) ;
if ( ! onlineClients . empty ( ) )
for ( const auto & elm : onlineClients ) {
2021-02-21 15:56:52 -05:00
elm - > task_update_needed_permissions . enqueue ( ) ;
2020-01-26 08:21:34 -05:00
if ( update_channels )
2021-02-21 15:56:52 -05:00
elm - > task_update_channel_client_properties . enqueue ( ) ;
2020-01-26 08:21:34 -05:00
elm - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
2020-05-07 15:28:15 -04:00
return pparser . build_command_result ( ) ;
2020-01-26 08:21:34 -05:00
}
command_result ConnectedClient : : handleCommandClientDelPerm ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto cldbid = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cldbid ) )
return command_result { error : : client_invalid_id } ;
2021-02-28 13:03:41 -05:00
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > getServerId ( ) , cldbid ) ;
2020-01-26 08:21:34 -05:00
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : i_client_permission_modify_power , this - > server - > calculate_permission ( permission : : i_client_needed_permission_modify_power , cldbid , ClientType : : CLIENT_TEAMSPEAK , 0 ) ) ;
2021-03-11 08:12:12 -05:00
ts : : command : : bulk_parser : : PermissionBulksParser pparser { cmd , false } ;
2020-05-07 15:28:15 -04:00
if ( ! pparser . validate ( this - > ref ( ) , 0 ) )
return pparser . build_command_result ( ) ;
2020-01-26 08:21:34 -05:00
2020-05-07 15:28:15 -04:00
bool update_channels { false } ;
for ( const auto & ppermission : pparser . iterate_valid_permissions ( ) ) {
ppermission . apply_to ( mgr , permission : : v2 : : PermissionUpdateType : : delete_value ) ;
2020-06-28 08:01:14 -04:00
ppermission . log_update ( serverInstance - > action_logger ( ) - > permission_logger ,
this - > getServerId ( ) ,
this - > ref ( ) ,
log : : PermissionTarget : : CLIENT ,
permission : : v2 : : PermissionUpdateType : : delete_value ,
cldbid , " " ,
0 , " "
) ;
2020-05-07 15:28:15 -04:00
update_channels | = ppermission . is_client_view_property ( ) ;
2020-01-26 08:21:34 -05:00
}
serverInstance - > databaseHelper ( ) - > saveClientPermissions ( this - > server , cldbid , mgr ) ;
2020-05-07 15:28:15 -04:00
auto onlineClients = this - > server - > findClientsByCldbId ( cldbid ) ;
2020-01-26 08:21:34 -05:00
if ( ! onlineClients . empty ( ) )
for ( const auto & elm : onlineClients ) {
2021-02-21 15:56:52 -05:00
elm - > task_update_needed_permissions . enqueue ( ) ;
2020-05-07 15:28:15 -04:00
if ( update_channels )
2021-02-21 15:56:52 -05:00
elm - > task_update_channel_client_properties . enqueue ( ) ;
2020-01-26 08:21:34 -05:00
elm - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
2020-05-07 15:28:15 -04:00
return pparser . build_command_result ( ) ;
2020-01-26 08:21:34 -05:00
}
command_result ConnectedClient : : handleCommandClientPermList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_client_permission_list , 1 ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return command_result { error : : client_invalid_id } ;
2021-02-28 13:03:41 -05:00
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > getServerId ( ) , cmd [ " cldbid " ] ) ;
2020-01-26 08:21:34 -05:00
if ( ! this - > notifyClientPermList ( cmd [ " cldbid " ] , mgr , cmd . hasParm ( " permsid " ) ) ) return command_result { error : : database_empty_result } ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientDbInfo ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_client_dbinfo , 1 ) ;
2020-12-05 04:26:12 -05:00
std : : deque < ClientDbId > cldbids ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
2020-01-26 08:21:34 -05:00
cldbids . push_back ( cmd [ index ] [ " cldbid " ] ) ;
2020-12-05 04:26:12 -05:00
}
2020-01-26 08:21:34 -05:00
auto basic = serverInstance - > databaseHelper ( ) - > queryDatabaseInfo ( this - > server , cldbids ) ;
2020-12-05 04:26:12 -05:00
if ( basic . empty ( ) ) {
return command_result { error : : database_empty_result } ;
}
2020-01-26 08:21:34 -05:00
auto allow_ip = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_remoteaddress_view , 0 ) ) ;
2020-12-05 04:26:12 -05:00
ts : : command_builder result { this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyclientdbinfo " : " " } ;
result . reserve_bulks ( basic . size ( ) ) ;
2020-01-26 08:21:34 -05:00
size_t index = 0 ;
for ( const auto & info : basic ) {
2020-12-05 04:26:12 -05:00
auto bulk = result . bulk ( index + + ) ;
bulk . reserve ( 800 ) ;
bulk . put_unchecked ( " client_base64HashClientUID " , hex : : hex ( base64 : : validate ( info - > client_unique_id ) ? base64 : : decode ( info - > client_unique_id ) : info - > client_unique_id , ' a ' , ' q ' ) ) ;
bulk . put_unchecked ( property : : CLIENT_UNIQUE_IDENTIFIER , info - > client_unique_id ) ;
bulk . put_unchecked ( property : : CLIENT_NICKNAME , info - > client_nickname ) ;
bulk . put_unchecked ( property : : CLIENT_DATABASE_ID , info - > client_database_id ) ;
bulk . put_unchecked ( property : : CLIENT_CREATED , chrono : : duration_cast < chrono : : seconds > ( info - > client_created . time_since_epoch ( ) ) . count ( ) ) ;
bulk . put_unchecked ( property : : CLIENT_LASTCONNECTED , chrono : : duration_cast < chrono : : seconds > ( info - > client_last_connected . time_since_epoch ( ) ) . count ( ) ) ;
bulk . put_unchecked ( property : : CLIENT_TOTALCONNECTIONS , info - > client_total_connections ) ;
bulk . put_unchecked ( property : : CLIENT_DATABASE_ID , info - > client_database_id ) ;
2020-07-30 14:25:45 -04:00
auto props = serverInstance - > databaseHelper ( ) - > loadClientProperties ( this - > server , info - > client_database_id , ClientType : : CLIENT_TEAMSPEAK ) ;
2020-12-05 04:26:12 -05:00
if ( allow_ip ) {
2021-03-01 08:16:44 -05:00
bulk . put_unchecked ( " client_lastip " , ( * props ) [ property : : CONNECTION_CLIENT_IP ] . as_unchecked < string > ( ) ) ;
2020-12-05 04:26:12 -05:00
} else {
bulk . put_unchecked ( " client_lastip " , " hidden " ) ;
}
# define ASSIGN_PROPERTY(property) \
2021-03-01 08:16:44 -05:00
bulk . put_unchecked ( property , ( * props ) [ property ] . value ( ) ) ;
2020-12-05 04:26:12 -05:00
ASSIGN_PROPERTY ( property : : CLIENT_ICON_ID ) ;
ASSIGN_PROPERTY ( property : : CLIENT_BADGES ) ;
ASSIGN_PROPERTY ( property : : CLIENT_VERSION ) ;
ASSIGN_PROPERTY ( property : : CLIENT_PLATFORM ) ;
ASSIGN_PROPERTY ( property : : CLIENT_HARDWARE_ID ) ;
ASSIGN_PROPERTY ( property : : CLIENT_TOTAL_BYTES_DOWNLOADED ) ;
ASSIGN_PROPERTY ( property : : CLIENT_TOTAL_BYTES_UPLOADED ) ;
ASSIGN_PROPERTY ( property : : CLIENT_MONTH_BYTES_DOWNLOADED ) ;
ASSIGN_PROPERTY ( property : : CLIENT_MONTH_BYTES_DOWNLOADED ) ;
ASSIGN_PROPERTY ( property : : CLIENT_DESCRIPTION ) ;
ASSIGN_PROPERTY ( property : : CLIENT_FLAG_AVATAR ) ;
ASSIGN_PROPERTY ( property : : CLIENT_MONTH_ONLINE_TIME ) ;
ASSIGN_PROPERTY ( property : : CLIENT_TOTAL_ONLINE_TIME ) ;
# undef ASSIGN_PROPERTY
2020-01-26 08:21:34 -05:00
index + + ;
}
2020-12-05 04:26:12 -05:00
this - > sendCommand ( result ) ;
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientDBDelete ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_delete_dbproperties , 1 ) ;
ClientDbId id = cmd [ " cldbid " ] ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , id ) ) return command_result { error : : database_empty_result } ;
serverInstance - > databaseHelper ( ) - > deleteClient ( this - > server , id ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientDBFind ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_client_dbsearch , 1 ) ;
bool uid = cmd . hasParm ( " uid " ) ;
string pattern = cmd [ " pattern " ] ;
2020-07-30 14:25:45 -04:00
const auto detailed = cmd . hasParm ( " details " ) ;
const auto show_ip = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_remoteaddress_view , 0 ) ) ;
size_t command_index { 0 } ;
ts : : command_builder result { this - > notify_response_command ( " notifyclientdbfind " ) } ;
result . reserve_bulks ( 50 ) ;
constexpr static auto kBaseCommand { " SELECT `client_database_id`, `client_unique_id`, `client_nickname`, `client_ip`, `client_last_connected`, `client_total_connections` FROM `clients_server` WHERE " } ;
auto sql_result = sql : : command { this - > sql , std : : string { kBaseCommand } + " `server_id` = :sid AND " + ( uid ? " `client_unique_id` " : " `client_nickname` " ) + " LIKE :pattern LIMIT 50 " , variable { " :sid " , this - > getServerId ( ) } , variable { " :pattern " , pattern } }
. query ( [ & ] ( int length , std : : string * values , std : : string * names ) {
auto bulk = result . bulk ( command_index + + ) ;
bulk . reserve ( 300 ) ;
auto index { 0 } ;
ClientDbId client_database_id ;
try {
assert ( names [ index ] = = " client_database_id " ) ;
client_database_id = std : : stoull ( values [ index ] ) ;
bulk . put_unchecked ( " cldbid " , values [ index + + ] ) ;
assert ( names [ index ] = = " client_unique_id " ) ;
bulk . put_unchecked ( " client_unique_identifier " , values [ index + + ] ) ;
assert ( names [ index ] = = " client_nickname " ) ;
bulk . put_unchecked ( " client_nickname " , values [ index + + ] ) ;
assert ( names [ index ] = = " client_ip " ) ;
if ( detailed ) {
bulk . put_unchecked ( " client_lastip " , show_ip ? values [ index + + ] : " hidden " ) ;
} else {
index + + ;
2020-01-26 08:21:34 -05:00
}
2020-07-30 14:25:45 -04:00
assert ( names [ index ] = = " client_last_connected " ) ;
bulk . put_unchecked ( " client_lastconnected " , values [ index + + ] ) ;
assert ( names [ index ] = = " client_total_connections " ) ;
bulk . put_unchecked ( " client_totalconnections " , values [ index + + ] ) ;
assert ( index = = length ) ;
} catch ( std : : exception & ex ) {
command_index - - ;
logError ( this - > getServerId ( ) , " Failed to parse client base properties at index {}: {}. Search pattern: {} " ,
index - 1 ,
ex . what ( ) ,
pattern
) ;
return ;
}
2020-01-26 08:21:34 -05:00
2020-07-30 14:25:45 -04:00
if ( detailed ) {
auto props = serverInstance - > databaseHelper ( ) - > loadClientProperties ( this - > server , client_database_id , ClientType : : CLIENT_TEAMSPEAK ) ;
if ( props ) {
auto & properties = * props ;
2021-03-01 08:16:44 -05:00
bulk . put_unchecked ( " client_badges " , properties [ property : : CLIENT_BADGES ] . as_unchecked < std : : string > ( ) ) ;
bulk . put_unchecked ( " client_version " ,
properties [ property : : CLIENT_VERSION ] . as_unchecked < std : : string > ( ) ) ;
bulk . put_unchecked ( " client_platform " ,
properties [ property : : CLIENT_PLATFORM ] . as_unchecked < std : : string > ( ) ) ;
bulk . put_unchecked ( " client_hwid " ,
properties [ property : : CLIENT_HARDWARE_ID ] . as_unchecked < std : : string > ( ) ) ;
2020-07-30 14:25:45 -04:00
}
}
} ) ;
if ( command_index = = 0 )
return command_result { error : : database_empty_result } ;
this - > sendCommand ( result ) ;
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientInfo ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
Command res ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyclientinfo " : " " ) ;
bool trigger_error = false ;
bool view_remote = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_remoteaddress_view , 0 ) ) ;
int result_index = 0 ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto client_id = cmd [ index ] [ " clid " ] . as < ClientId > ( ) ;
if ( client_id = = 0 ) continue ;
2020-02-01 08:32:16 -05:00
ConnectedLockedClient client { this - > server - > find_client_by_id ( client_id ) } ;
2020-01-26 08:21:34 -05:00
if ( ! client ) {
trigger_error = true ;
continue ;
}
for ( const auto & key : client - > properties ( ) - > list_properties ( property : : FLAG_CLIENT_VIEW | property : : FLAG_CLIENT_VARIABLE | property : : FLAG_CLIENT_INFO , this - > getType ( ) = = CLIENT_TEAMSPEAK ? property : : FLAG_NEW : ( uint16_t ) 0 ) )
2020-04-08 07:01:41 -04:00
res [ result_index ] [ std : : string { key . type ( ) . name } ] = key . value ( ) ;
2020-01-26 08:21:34 -05:00
if ( view_remote )
2021-03-01 08:16:44 -05:00
res [ result_index ] [ " connection_client_ip " ] = client - > properties ( ) [ property : : CONNECTION_CLIENT_IP ] . value ( ) ;
2020-01-26 08:21:34 -05:00
else
res [ result_index ] [ " connection_client_ip " ] = " hidden " ;
res [ result_index ] [ " client_idle_time " ] = duration_cast < milliseconds > ( system_clock : : now ( ) - client - > idleTimestamp ) . count ( ) ;
res [ result_index ] [ " connection_connected_time " ] = duration_cast < milliseconds > ( system_clock : : now ( ) - client - > connectTimestamp ) . count ( ) ;
{
auto channel = client - > currentChannel ;
if ( channel )
res [ result_index ] [ " cid " ] = channel - > channelId ( ) ;
else
res [ result_index ] [ " cid " ] = 0 ;
}
result_index + + ;
}
if ( result_index > 0 ) {
this - > sendCommand ( res ) ;
}
if ( trigger_error | | result_index = = 0 )
return command_result { error : : client_invalid_id } ;
else
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientFind ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
string pattern = cmd [ " pattern " ] ;
std : : transform ( pattern . begin ( ) , pattern . end ( ) , pattern . begin ( ) , : : tolower ) ;
Command res ( " " ) ;
int index = 0 ;
for ( const auto & cl : this - > server - > getClients ( ) ) {
string name = cl - > getDisplayName ( ) ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , : : tolower ) ;
if ( name . find ( pattern ) ! = std : : string : : npos ) {
res [ index ] [ " clid " ] = cl - > getClientId ( ) ;
res [ index ] [ " client_nickname " ] = cl - > getDisplayName ( ) ;
index + + ;
}
}
if ( index = = 0 ) return command_result { error : : database_empty_result } ;
this - > sendCommand ( res ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandClientSetServerQueryLogin ( Command & cmd ) {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_create_modify_serverquery_login , 1 ) ;
if ( ! cmd [ 0 ] . has ( " client_login_password " ) ) cmd [ " client_login_password " ] = " " ;
std : : string password = cmd [ " client_login_password " ] ;
if ( password . empty ( ) )
password = rnd_string ( QUERY_PASSWORD_LENGTH ) ;
auto old = serverInstance - > getQueryServer ( ) - > find_query_account_by_name ( cmd [ " client_login_name " ] ) ;
if ( old ) {
if ( old - > unique_id = = this - > getUid ( ) ) {
serverInstance - > getQueryServer ( ) - > change_query_password ( old , password ) ;
} else {
return command_result { error : : client_not_logged_in } ;
}
} else {
serverInstance - > getQueryServer ( ) - > create_query_account ( cmd [ " client_login_name " ] , this - > getServerId ( ) , this - > getUid ( ) , password ) ;
}
Command res ( this - > notify_response_command ( " notifyclientserverqueryloginpassword " ) ) ;
res [ " client_login_password " ] = password ;
this - > sendCommand ( res ) ;
return command_result { error : : ok } ;
}