2019-07-17 19:37:18 +02:00
# include <memory>
# include <iostream>
# include <bitset>
# include <algorithm>
# include <openssl/sha.h>
# include "../build.h"
# include "ConnectedClient.h"
# include "InternalClient.h"
# include "../server/file/FileServer.h"
# include "../server/VoiceServer.h"
# include "voice/VoiceClient.h"
# include "PermissionManager.h"
# include "../InstanceHandler.h"
# include "../server/QueryServer.h"
# include "file/FileClient.h"
# include "music/MusicClient.h"
# include "query/QueryClient.h"
# include "../weblist/WebListManager.h"
2019-07-19 22:55:03 +02:00
# include "../manager/ConversationManager.h"
2019-07-17 19:37:18 +02:00
# include <experimental/filesystem>
# include <cstdint>
# include <StringVariable.h>
# include <Properties.h>
# include <log/LogUtils.h>
# include <misc/sassert.h>
# include <misc/base64.h>
# include <misc/hex.h>
# include <misc/digest.h>
# include <misc/rnd.h>
# include <misc/timer.h>
# include <bbcode/bbcodes.h>
namespace fs = std : : experimental : : filesystem ;
using namespace std : : chrono ;
using namespace std ;
using namespace ts ;
using namespace ts : : server ;
using namespace ts : : token ;
extern ts : : server : : InstanceHandler * serverInstance ;
# define QUERY_PASSWORD_LENGTH 12
# define PARSE_PERMISSION(cmd) \
permission : : PermissionType permType = permission : : PermissionType : : unknown ; \
bool grant = false ; \
if ( cmd [ index ] . has ( " permid " ) ) { \
permType = cmd [ index ] [ " permid " ] . as < permission : : PermissionType > ( ) ; \
if ( ( permType & PERM_ID_GRANT ) ! = 0 ) { \
grant = true ; \
permType & = ~ PERM_ID_GRANT ; \
} \
} else if ( cmd [ index ] . has ( " permsid " ) ) { \
auto resv = permission : : resolvePermissionData ( cmd [ index ] [ " permsid " ] . as < string > ( ) ) ; \
permType = resv - > type ; \
if ( resv - > grantName ( ) = = cmd [ index ] [ " permsid " ] . as < string > ( ) ) grant = true ; \
} \
if ( permission : : resolvePermissionData ( permType ) - > type = = permission : : PermissionType : : unknown ) { \
if ( conOnError ) continue ; \
return { findError ( " parameter_invalid " ) , " could not resolve permission " + ( cmd [ index ] . has ( " permid " ) ? cmd [ index ] [ " permid " ] . as < string > ( ) : cmd [ index ] [ " permsid " ] . as < string > ( ) ) } ; \
}
# define CHANNEL_PERM_TEST_INIT \
auto current_channel = channel = = this - > getChannel ( )
# define CHANNEL_PERM_TEST(permission_type, required, enfore_required) \
do { \
if ( current_channel ) \
PERM_CHECK_CHANNELR ( permission_type , required , channel , enfore_required ) ; \
else \
PERM_CHECK_CHANNELR ( permission_type , required , channel , enfore_required ) ; \
} while ( 0 )
# define RESOLVE_CHANNEL_R(command, force) \
auto channel_tree = this - > server ? this - > server - > channelTree : serverInstance - > getChannelTree ( ) . get ( ) ; \
shared_lock channel_tree_read_lock ( this - > server ? this - > server - > channel_tree_lock : serverInstance - > getChannelTreeLock ( ) ) ; \
auto channel_id = command . as < ChannelId > ( ) ; \
auto l_channel = channel_id ? channel_tree - > findLinkedChannel ( command . as < ChannelId > ( ) ) : nullptr ; \
if ( ! l_channel & & ( channel_id ! = 0 | | force ) ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ; \
# define RESOLVE_CHANNEL_W(command, force) \
auto channel_tree = this - > server ? this - > server - > channelTree : serverInstance - > getChannelTree ( ) . get ( ) ; \
unique_lock channel_tree_write_lock ( this - > server ? this - > server - > channel_tree_lock : serverInstance - > getChannelTreeLock ( ) ) ; \
auto channel_id = command . as < ChannelId > ( ) ; \
auto l_channel = channel_id ? channel_tree - > findLinkedChannel ( command . as < ChannelId > ( ) ) : nullptr ; \
if ( ! l_channel & & ( channel_id ! = 0 | | force ) ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ; \
/* the "newest" channel permission access test */
# define CHANNEL_PERMISSION_TEST(permission_type, permission_needed_type, _channel, permission_required) \
do { \
auto permission_granted = this - > calculate_permission_value ( permission_type , _channel - > channelId ( ) ) ; \
if ( ! channel - > permission_granted ( permission_needed_type , permission_granted , permission_required ) ) \
return CommandResultPermissionError { permission_type } ; \
} while ( 0 )
/* the "newest" group permission access test */
# define GROUP_PERMISSION_TEST(permission_type, permission_needed_type, _group, permission_required) \
do { \
auto permission_granted = this - > calculate_permission_value ( permission_type , 0 ) ; \
if ( ! _group - > permission_granted ( permission_needed_type , permission_granted , permission_required ) ) \
return CommandResultPermissionError { permission_type } ; \
} while ( 0 )
inline bool permission_require_granted_value ( permission : : PermissionType type ) {
switch ( type ) {
case permission : : i_permission_modify_power :
case permission : : i_channel_group_member_add_power :
case permission : : i_channel_group_member_remove_power :
case permission : : i_channel_group_modify_power :
case permission : : i_server_group_member_add_power :
case permission : : i_server_group_member_remove_power :
case permission : : i_server_group_modify_power :
case permission : : i_displayed_group_member_add_power :
case permission : : i_displayed_group_member_remove_power :
case permission : : i_displayed_group_modify_power :
case permission : : i_channel_permission_modify_power :
case permission : : i_client_permission_modify_power :
case permission : : i_client_needed_kick_from_server_power :
case permission : : i_client_needed_kick_from_channel_power :
case permission : : i_client_kick_from_channel_power :
case permission : : i_client_kick_from_server_power :
return true ;
default :
return false ;
}
}
inline bool permission_is_group_property ( permission : : PermissionType type ) {
switch ( type ) {
case permission : : i_icon_id :
case permission : : i_group_show_name_in_tree :
case permission : : i_group_sort_id :
case permission : : b_group_is_permanent :
case permission : : i_displayed_group_needed_modify_power :
case permission : : i_displayed_group_needed_member_add_power :
case permission : : i_displayed_group_needed_member_remove_power :
return true ;
default :
return false ;
}
}
inline bool permission_is_client_property ( permission : : PermissionType type ) {
switch ( type ) {
case permission : : i_icon_id :
case permission : : i_client_talk_power :
case permission : : i_client_max_idletime :
case permission : : i_group_sort_id :
case permission : : i_channel_view_power :
case permission : : b_channel_ignore_view_power :
case permission : : b_client_is_priority_speaker :
return true ;
default :
return false ;
}
}
CommandResult ConnectedClient : : handleCommand ( Command & cmd ) {
threads : : MutexLock l2 ( this - > command_lock ) ;
auto command = cmd . command ( ) ;
if ( command = = " servergetvariables " ) return this - > handleCommandServerGetVariables ( cmd ) ;
else if ( command = = " serverrequestconnectioninfo " ) return this - > handleCommandServerRequestConnectionInfo ( cmd ) ;
else if ( command = = " getconnectioninfo " ) return this - > handleCommandGetConnectionInfo ( cmd ) ;
else if ( command = = " setconnectioninfo " ) return this - > handleCommandSetConnectionInfo ( cmd ) ;
else if ( command = = " clientgetvariables " ) return this - > handleCommandClientGetVariables ( cmd ) ;
else if ( command = = " serveredit " ) return this - > handleCommandServerEdit ( cmd ) ;
else if ( command = = " clientedit " ) return this - > handleCommandClientEdit ( cmd ) ;
else if ( command = = " channelgetdescription " ) return this - > handleCommandChannelGetDescription ( cmd ) ;
else if ( command = = " connectioninfoautoupdate " ) return this - > handleCommandConnectionInfoAutoUpdate ( cmd ) ;
else if ( command = = " permissionlist " ) return this - > handleCommandPermissionList ( cmd ) ;
else if ( command = = " propertylist " ) return this - > handleCommandPropertyList ( cmd ) ;
2019-07-19 22:55:03 +02:00
//Server group
2019-07-17 19:37:18 +02:00
else if ( command = = " servergrouplist " ) return this - > handleCommandServerGroupList ( cmd ) ;
else if ( command = = " servergroupadd " ) return this - > handleCommandServerGroupAdd ( cmd ) ;
else if ( command = = " servergroupcopy " ) return this - > handleCommandServerGroupCopy ( cmd ) ;
else if ( command = = " servergroupdel " ) return this - > handleCommandServerGroupDel ( cmd ) ;
else if ( command = = " servergrouprename " ) return this - > handleCommandServerGroupRename ( cmd ) ;
else if ( command = = " servergroupclientlist " ) return this - > handleCommandServerGroupClientList ( cmd ) ;
else if ( command = = " servergroupaddclient " ) return this - > handleCommandServerGroupAddClient ( cmd ) ;
else if ( command = = " servergroupdelclient " ) return this - > handleCommandServerGroupDelClient ( cmd ) ;
else if ( command = = " servergrouppermlist " ) return this - > handleCommandServerGroupPermList ( cmd ) ;
else if ( command = = " servergroupaddperm " ) return this - > handleCommandServerGroupAddPerm ( cmd ) ;
else if ( command = = " servergroupdelperm " ) return this - > handleCommandServerGroupDelPerm ( cmd ) ;
else if ( command = = " setclientchannelgroup " ) return this - > handleCommandSetClientChannelGroup ( cmd ) ;
2019-07-19 22:55:03 +02:00
//Channel basic actions
2019-07-17 19:37:18 +02:00
else if ( command = = " channelcreate " ) return this - > handleCommandChannelCreate ( cmd ) ;
else if ( command = = " channelmove " ) return this - > handleCommandChannelMove ( cmd ) ;
else if ( command = = " channeledit " ) return this - > handleCommandChannelEdit ( cmd ) ;
else if ( command = = " channeldelete " ) return this - > handleCommandChannelDelete ( cmd ) ;
2019-07-19 22:55:03 +02:00
//Find a channel and get informations
2019-07-17 19:37:18 +02:00
else if ( command = = " channelfind " ) return this - > handleCommandChannelFind ( cmd ) ;
else if ( command = = " channelinfo " ) return this - > handleCommandChannelInfo ( cmd ) ;
2019-07-19 22:55:03 +02:00
//Channel perm actions
2019-07-17 19:37:18 +02:00
else if ( command = = " channelpermlist " ) return this - > handleCommandChannelPermList ( cmd ) ;
else if ( command = = " channeladdperm " ) return this - > handleCommandChannelAddPerm ( cmd ) ;
else if ( command = = " channeldelperm " ) return this - > handleCommandChannelDelPerm ( cmd ) ;
2019-07-19 22:55:03 +02:00
//Channel group actions
2019-07-17 19:37:18 +02:00
else if ( command = = " channelgroupadd " ) return this - > handleCommandChannelGroupAdd ( cmd ) ;
else if ( command = = " channelgroupcopy " ) return this - > handleCommandChannelGroupCopy ( cmd ) ;
else if ( command = = " channelgrouprename " ) return this - > handleCommandChannelGroupRename ( cmd ) ;
else if ( command = = " channelgroupdel " ) return this - > handleCommandChannelGroupDel ( cmd ) ;
else if ( command = = " channelgrouplist " ) return this - > handleCommandChannelGroupList ( cmd ) ;
else if ( command = = " channelgroupclientlist " ) return this - > handleCommandChannelGroupClientList ( cmd ) ;
else if ( command = = " channelgrouppermlist " ) return this - > handleCommandChannelGroupPermList ( cmd ) ;
else if ( command = = " channelgroupaddperm " ) return this - > handleCommandChannelGroupAddPerm ( cmd ) ;
else if ( command = = " channelgroupdelperm " ) return this - > handleCommandChannelGroupDelPerm ( cmd ) ;
2019-07-19 22:55:03 +02:00
//Channel sub/unsubscribe
2019-07-17 19:37:18 +02:00
else if ( command = = " channelsubscribe " ) return this - > handleCommandChannelSubscribe ( cmd ) ;
else if ( command = = " channelsubscribeall " ) return this - > handleCommandChannelSubscribeAll ( cmd ) ;
else if ( command = = " channelunsubscribe " ) return this - > handleCommandChannelUnsubscribe ( cmd ) ;
else if ( command = = " channelunsubscribeall " ) return this - > handleCommandChannelUnsubscribeAll ( cmd ) ;
2019-07-19 22:55:03 +02:00
//manager channel permissions
2019-07-17 19:37:18 +02:00
else if ( command = = " channelclientpermlist " ) return this - > handleCommandChannelClientPermList ( cmd ) ;
else if ( command = = " channelclientaddperm " ) return this - > handleCommandChannelClientAddPerm ( cmd ) ;
else if ( command = = " channelclientdelperm " ) return this - > handleCommandChannelClientDelPerm ( cmd ) ;
2019-07-19 22:55:03 +02:00
//Client actions
2019-07-17 19:37:18 +02:00
else if ( command = = " clientupdate " ) return this - > handleCommandClientUpdate ( cmd ) ;
else if ( command = = " clientmove " ) return this - > handleCommandClientMove ( cmd ) ;
else if ( command = = " clientgetids " ) return this - > handleCommandClientGetIds ( cmd ) ;
else if ( command = = " clientkick " ) return this - > handleCommandClientKick ( cmd ) ;
else if ( command = = " clientpoke " ) return this - > handleCommandClientPoke ( cmd ) ;
else if ( command = = " sendtextmessage " ) return this - > handleCommandSendTextMessage ( cmd ) ;
else if ( command = = " clientchatcomposing " ) return this - > handleCommandClientChatComposing ( cmd ) ;
else if ( command = = " clientchatclosed " ) return this - > handleCommandClientChatClosed ( cmd ) ;
else if ( command = = " clientfind " ) return this - > handleCommandClientFind ( cmd ) ;
else if ( command = = " clientinfo " ) return this - > handleCommandClientInfo ( cmd ) ;
else if ( command = = " clientaddperm " ) return this - > handleCommandClientAddPerm ( cmd ) ;
else if ( command = = " clientdelperm " ) return this - > handleCommandClientDelPerm ( cmd ) ;
else if ( command = = " clientpermlist " ) return this - > handleCommandClientPermList ( cmd ) ;
2019-07-19 22:55:03 +02:00
//File transfare
2019-07-17 19:37:18 +02:00
else if ( command = = " ftgetfilelist " ) return this - > handleCommandFTGetFileList ( cmd ) ;
else if ( command = = " ftcreatedir " ) return this - > handleCommandFTCreateDir ( cmd ) ;
else if ( command = = " ftdeletefile " ) return this - > handleCommandFTDeleteFile ( cmd ) ;
else if ( command = = " ftinitupload " ) return this - > handleCommandFTInitUpload ( cmd ) ;
else if ( command = = " ftinitdownload " ) return this - > handleCommandFTInitDownload ( cmd ) ;
else if ( command = = " ftgetfileinfo " ) return this - > handleCommandFTGetFileInfo ( cmd ) ;
2019-07-19 22:55:03 +02:00
//Banlist
2019-07-17 19:37:18 +02:00
else if ( command = = " banlist " ) return this - > handleCommandBanList ( cmd ) ;
else if ( command = = " banadd " ) return this - > handleCommandBanAdd ( cmd ) ;
else if ( command = = " banedit " ) return this - > handleCommandBanEdit ( cmd ) ;
else if ( command = = " banclient " ) return this - > handleCommandBanClient ( cmd ) ;
else if ( command = = " bandel " ) return this - > handleCommandBanDel ( cmd ) ;
else if ( command = = " bandelall " ) return this - > handleCommandBanDelAll ( cmd ) ;
else if ( command = = " bantriggerlist " ) return this - > handleCommandBanTriggerList ( cmd ) ;
2019-07-19 22:55:03 +02:00
//Tokens
2019-07-17 19:37:18 +02:00
else if ( command = = " tokenlist " | | command = = " privilegekeylist " ) return this - > handleCommandTokenList ( cmd ) ;
else if ( command = = " tokenadd " | | command = = " privilegekeyadd " ) return this - > handleCommandTokenAdd ( cmd ) ;
else if ( command = = " tokenuse " | | command = = " privilegekeyuse " ) return this - > handleCommandTokenUse ( cmd ) ;
else if ( command = = " tokendelete " | | command = = " privilegekeydelete " ) return this - > handleCommandTokenDelete ( cmd ) ;
2019-07-19 22:55:03 +02:00
//DB stuff
2019-07-17 19:37:18 +02:00
else if ( command = = " clientdblist " ) return this - > handleCommandClientDbList ( cmd ) ;
else if ( command = = " clientdbinfo " ) return this - > handleCommandClientDbInfo ( cmd ) ;
else if ( command = = " clientdbedit " ) return this - > handleCommandClientDBEdit ( cmd ) ;
else if ( command = = " clientdbfind " ) return this - > handleCommandClientDBFind ( cmd ) ;
else if ( command = = " clientdbdelete " ) return this - > handleCommandClientDBDelete ( cmd ) ;
else if ( command = = " plugincmd " ) return this - > handleCommandPluginCmd ( cmd ) ;
else if ( command = = " clientmute " ) return this - > handleCommandClientMute ( cmd ) ;
else if ( command = = " clientunmute " ) return this - > handleCommandClientUnmute ( cmd ) ;
else if ( command = = " clientlist " ) return this - > handleCommandClientList ( cmd ) ;
else if ( command = = " whoami " ) return this - > handleCommandWhoAmI ( cmd ) ;
else if ( command = = " servergroupsbyclientid " ) return this - > handleCommandServerGroupsByClientId ( cmd ) ;
else if ( command = = " clientgetdbidfromuid " ) return this - > handleCommandClientGetDBIDfromUID ( cmd ) ;
else if ( command = = " clientgetnamefromdbid " ) return this - > handleCommandClientGetNameFromDBID ( cmd ) ;
else if ( command = = " clientgetnamefromuid " ) return this - > handleCommandClientGetNameFromUid ( cmd ) ;
else if ( command = = " clientgetuidfromclid " ) return this - > handleCommandClientGetUidFromClid ( cmd ) ;
else if ( command = = " complainadd " ) return this - > handleCommandComplainAdd ( cmd ) ;
else if ( command = = " complainlist " ) return this - > handleCommandComplainList ( cmd ) ;
else if ( command = = " complaindel " ) return this - > handleCommandComplainDel ( cmd ) ;
else if ( command = = " complaindelall " ) return this - > handleCommandComplainDelAll ( cmd ) ;
else if ( command = = " version " ) return this - > handleCommandVersion ( cmd ) ;
else if ( command = = " verifyserverpassword " ) return this - > handleCommandVerifyServerPassword ( cmd ) ;
else if ( command = = " verifychannelpassword " ) return this - > handleCommandVerifyChannelPassword ( cmd ) ;
else if ( command = = " messagelist " ) return this - > handleCommandMessageList ( cmd ) ;
else if ( command = = " messageadd " ) return this - > handleCommandMessageAdd ( cmd ) ;
else if ( command = = " messageget " ) return this - > handleCommandMessageGet ( cmd ) ;
else if ( command = = " messagedel " ) return this - > handleCommandMessageDel ( cmd ) ;
else if ( command = = " messageupdateflag " ) return this - > handleCommandMessageUpdateFlag ( cmd ) ;
else if ( command = = " permget " ) return this - > handleCommandPermGet ( cmd ) ;
else if ( command = = " permfind " ) return this - > handleCommandPermFind ( cmd ) ;
else if ( command = = " permidgetbyname " ) return this - > handleCommandPermIdGetByName ( cmd ) ;
else if ( command = = " permoverview " ) return this - > handleCommandPermOverview ( cmd ) ;
else if ( command = = " permreset " ) return this - > handleCommandPermReset ( cmd ) ;
else if ( command = = " clientsetserverquerylogin " ) return this - > handleCommandClientSetServerQueryLogin ( cmd ) ;
//Music stuff
else if ( command = = " musicbotcreate " ) return this - > handleCommandMusicBotCreate ( cmd ) ;
else if ( command = = " musicbotdelete " ) return this - > handleCommandMusicBotDelete ( cmd ) ;
else if ( command = = " musicbotsetsubscription " ) return this - > handleCommandMusicBotSetSubscription ( cmd ) ;
else if ( command = = " musicbotplayerinfo " ) return this - > handleCommandMusicBotPlayerInfo ( cmd ) ;
else if ( command = = " musicbotplayeraction " ) return this - > handleCommandMusicBotPlayerAction ( cmd ) ;
else if ( command = = " musicbotqueuelist " ) return this - > handleCommandMusicBotQueueList ( cmd ) ;
else if ( command = = " musicbotqueueadd " ) return this - > handleCommandMusicBotQueueAdd ( cmd ) ;
else if ( command = = " musicbotqueueremove " ) return this - > handleCommandMusicBotQueueRemove ( cmd ) ;
else if ( command = = " musicbotqueuereorder " ) return this - > handleCommandMusicBotQueueReorder ( cmd ) ;
else if ( command = = " musicbotplaylistassign " ) return this - > handleCommandMusicBotPlaylistAssign ( cmd ) ;
else if ( command = = " help " ) return this - > handleCommandHelp ( cmd ) ;
else if ( command = = " logview " ) return this - > handleCommandLogView ( cmd ) ;
else if ( command = = " servergroupautoaddperm " ) return this - > handleCommandServerGroupAutoAddPerm ( cmd ) ;
else if ( command = = " servergroupautodelperm " ) return this - > handleCommandServerGroupAutoDelPerm ( cmd ) ;
else if ( command = = " updatemytsid " ) return this - > handleCommandUpdateMyTsId ( cmd ) ;
else if ( command = = " updatemytsdata " ) return this - > handleCommandUpdateMyTsData ( cmd ) ;
else if ( command = = " querycreate " ) return this - > handleCommandQueryCreate ( cmd ) ;
else if ( command = = " querydelete " ) return this - > handleCommandQueryDelete ( cmd ) ;
else if ( command = = " querylist " ) return this - > handleCommandQueryList ( cmd ) ;
else if ( command = = " queryrename " ) return this - > handleCommandQueryRename ( cmd ) ;
else if ( command = = " querychangepassword " ) return this - > handleCommandQueryChangePassword ( cmd ) ;
else if ( command = = " playlistlist " ) return this - > handleCommandPlaylistList ( cmd ) ;
else if ( command = = " playlistcreate " ) return this - > handleCommandPlaylistCreate ( cmd ) ;
else if ( command = = " playlistdelete " ) return this - > handleCommandPlaylistDelete ( cmd ) ;
else if ( command = = " playlistpermlist " ) return this - > handleCommandPlaylistPermList ( cmd ) ;
else if ( command = = " playlistaddperm " ) return this - > handleCommandPlaylistAddPerm ( cmd ) ;
else if ( command = = " playlistdelperm " ) return this - > handleCommandPlaylistDelPerm ( cmd ) ;
else if ( command = = " playlistinfo " ) return this - > handleCommandPlaylistInfo ( cmd ) ;
else if ( command = = " playlistedit " ) return this - > handleCommandPlaylistEdit ( cmd ) ;
else if ( command = = " playlistsonglist " ) return this - > handleCommandPlaylistSongList ( cmd ) ;
else if ( command = = " playlistsongadd " ) return this - > handleCommandPlaylistSongAdd ( cmd ) ;
else if ( command = = " playlistsongreorder " | | command = = " playlistsongmove " ) return this - > handleCommandPlaylistSongReorder ( cmd ) ;
else if ( command = = " playlistsongremove " ) return this - > handleCommandPlaylistSongRemove ( cmd ) ;
else if ( command = = " dummy_ipchange " ) return this - > handleCommandDummy_IpChange ( cmd ) ;
2019-07-19 22:55:03 +02:00
else if ( command = = " conversationhistory " ) return this - > handleCommandConversationHistory ( cmd ) ;
else if ( command = = " conversationfetch " ) return this - > handleCommandConversationFetch ( cmd ) ;
2019-07-17 19:37:18 +02:00
if ( this - > getType ( ) = = ClientType : : CLIENT_QUERY ) return CommandResult : : NotImplemented ; //Dont log query invalid commands
if ( this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK )
if ( command . empty ( ) | | command . find_first_not_of ( ' ' ) = = - 1 ) {
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_allow_invalid_packet , 1 , this - > currentChannel ) )
( ( VoiceClient * ) this ) - > disconnect ( VREASON_SERVER_KICK , config : : messages : : kick_invalid_command , this - > server ? this - > server - > serverAdmin : static_pointer_cast < ConnectedClient > ( serverInstance - > getInitalServerAdmin ( ) ) , true ) ;
}
logError ( this - > getServerId ( ) , " Missing command '{}' " , command ) ;
return CommandResult : : NotImplemented ;
}
CommandResult ConnectedClient : : handleCommandServerGetVariables ( Command & cmd ) {
CMD_REQ_SERVER ;
this - > notifyServerUpdated ( _this . lock ( ) ) ;
return CommandResult : : Success ;
}
# define SERVEREDIT_CHK_PROP(name, perm, type)\
else if ( key = = name ) { \
if ( ! permissionGranted ( permission : : PERMTEST_HIGHEST , perm , 1 , nullptr , true , cache , target_server , true ) ) return CommandResultPermissionError ( perm ) ; \
if ( toApplay . count ( key ) = = 0 ) toApplay [ key ] = cmd [ key ] . as < std : : string > ( ) ; \
if ( ! cmd [ 0 ] [ key ] . castable < type > ( ) ) return { findError ( " parameter_invalid " ) , " Invalid type for " + key } ;
# define SERVEREDIT_CHK_PROP_CACHED(name, perm, type)\
else if ( key = = name ) { \
if ( ! this - > permission_granted ( this - > cached_permission_value ( perm ) , 1 ) ) return CommandResultPermissionError ( perm ) ; \
if ( toApplay . count ( key ) = = 0 ) toApplay [ key ] = cmd [ key ] . as < std : : string > ( ) ; \
if ( ! cmd [ 0 ] [ key ] . castable < type > ( ) ) return { findError ( " parameter_invalid " ) , " Invalid type for " + key } ;
# define SERVEREDIT_CHK_PROP2(name, perm, type_a, type_b)\
else if ( key = = name ) { \
if ( ! permissionGranted ( permission : : PERMTEST_HIGHEST , perm , 1 , nullptr , true , cache , target_server , true ) ) return CommandResultPermissionError ( perm ) ; \
if ( toApplay . count ( key ) = = 0 ) toApplay [ key ] = cmd [ key ] . as < std : : string > ( ) ; \
if ( ! cmd [ 0 ] [ key ] . castable < type_a > ( ) & & ! ! cmd [ 0 ] [ key ] . castable < type_b > ( ) ) return { findError ( " parameter_invalid " ) , " Invalid type for " + key } ;
CommandResult ConnectedClient : : handleCommandServerEdit ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
if ( cmd [ 0 ] . has ( " sid " ) & & this - > getServerId ( ) ! = cmd [ " sid " ] . as < ServerId > ( ) )
return { findError ( " server_invalid_id " ) , " Invalid server id! You can just edit the server where your're bound on " } ;
auto target_server = this - > server ;
if ( cmd [ 0 ] . has ( " sid " ) ) {
target_server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( cmd [ " sid " ] ) ;
if ( ! target_server & & cmd [ " sid " ] . as < ServerId > ( ) ! = 0 ) return { findError ( " server_invalid_id " ) } ;
}
auto cache = make_shared < CalculateCache > ( ) ;
map < string , string > toApplay ;
for ( auto & key : cmd [ 0 ] . keys ( ) ) {
if ( key = = " sid " ) continue ;
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_name " , permission : : b_virtualserver_modify_name , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_name_phonetic " , permission : : b_virtualserver_modify_name , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_maxclients " , permission : : b_virtualserver_modify_maxclients , size_t )
if ( cmd [ " virtualserver_maxclients " ] . as < size_t > ( ) > 1024 )
return { findError ( " accounting_slot_limit_reached " ) , " Do you really need more that 1024 slots? " } ;
} SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_reserved_slots " , permission : : b_virtualserver_modify_reserved_slots , size_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_icon_id " , permission : : b_virtualserver_modify_icon_id , int64_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_channel_temp_delete_delay_default " , permission : : b_virtualserver_modify_channel_temp_delete_delay_default , ChannelId ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_codec_encryption_mode " , permission : : b_virtualserver_modify_codec_encryption_mode , int ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_default_server_group " , permission : : b_virtualserver_modify_default_servergroup , GroupId )
if ( target_server ) {
auto group = target_server - > groups - > findGroup ( cmd [ " virtualserver_default_server_group " ] . as < GroupId > ( ) ) ;
if ( ! group | | group - > target ( ) ! = GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " Invalid default server group! " } ;
}
} SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_default_channel_group " , permission : : b_virtualserver_modify_default_channelgroup , GroupId )
if ( target_server ) {
auto group = target_server - > groups - > findGroup ( cmd [ " virtualserver_default_channel_group " ] . as < GroupId > ( ) ) ;
if ( ! group | | group - > target ( ) ! = GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " Invalid default channel group! " } ;
}
} SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_default_channel_admin_group " , permission : : b_virtualserver_modify_default_channeladmingroup , GroupId )
if ( target_server ) {
auto group = target_server - > groups - > findGroup ( cmd [ " virtualserver_default_channel_admin_group " ] . as < GroupId > ( ) ) ;
if ( ! group | | group - > target ( ) ! = GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " Invalid default channel admin group! " } ;
}
} SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_default_music_group " , permission : : b_virtualserver_modify_default_musicgroup , GroupId )
if ( target_server ) {
auto group = target_server - > groups - > findGroup ( cmd [ " virtualserver_default_music_group " ] . as < GroupId > ( ) ) ;
if ( ! group | | group - > target ( ) ! = GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " Invalid default music group! " } ;
}
}
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_priority_speaker_dimm_modificator " , permission : : b_virtualserver_modify_priority_speaker_dimm_modificator , float ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_port " , permission : : b_virtualserver_modify_port , uint16_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_host " , permission : : b_virtualserver_modify_host , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_web_host " , permission : : b_virtualserver_modify_port , uint16_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_web_port " , permission : : b_virtualserver_modify_host , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_hostbanner_url " , permission : : b_virtualserver_modify_hostbanner , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_hostbanner_gfx_url " , permission : : b_virtualserver_modify_hostbanner , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_hostbanner_gfx_interval " , permission : : b_virtualserver_modify_hostbanner , int ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_hostbanner_mode " , permission : : b_virtualserver_modify_hostbanner , int ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_hostbutton_tooltip " , permission : : b_virtualserver_modify_hostbutton , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_hostbutton_url " , permission : : b_virtualserver_modify_hostbutton , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_hostbutton_gfx_url " , permission : : b_virtualserver_modify_hostbutton , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_hostmessage " , permission : : b_virtualserver_modify_hostmessage , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_hostmessage_mode " , permission : : b_virtualserver_modify_hostmessage , int ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_welcomemessage " , permission : : b_virtualserver_modify_welcomemessage , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_weblist_enabled " , permission : : b_virtualserver_modify_weblist , bool )
if ( target_server & & target_server - > running ( ) ) {
if ( cmd [ " virtualserver_weblist_enabled " ] . as < bool > ( ) )
serverInstance - > getWebList ( ) - > enable_report ( target_server ) ;
else
serverInstance - > getWebList ( ) - > disable_report ( target_server ) ;
debugMessage ( string ( ) + " Changed weblist state to -> " + ( cmd [ " virtualserver_weblist_enabled " ] . as < bool > ( ) ? " activated " : " disabled " ) ) ;
}
} SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_needed_identity_security_level " , permission : : b_virtualserver_modify_needed_identity_security_level , int ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_antiflood_points_tick_reduce " , permission : : b_virtualserver_modify_antiflood , uint64_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_antiflood_points_needed_command_block " , permission : : b_virtualserver_modify_antiflood , uint64_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_antiflood_points_needed_ip_block " , permission : : b_virtualserver_modify_antiflood , uint64_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_complain_autoban_count " , permission : : b_virtualserver_modify_complain , uint64_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_complain_autoban_time " , permission : : b_virtualserver_modify_complain , uint64_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_complain_remove_time " , permission : : b_virtualserver_modify_complain , uint64_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_autostart " , permission : : b_virtualserver_modify_autostart , bool ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_min_clients_in_channel_before_forced_silence " , permission : : b_virtualserver_modify_channel_forced_silence , int ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_log_client " , permission : : b_virtualserver_modify_log_settings , bool ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_log_query " , permission : : b_virtualserver_modify_log_settings , bool ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_log_channel " , permission : : b_virtualserver_modify_log_settings , bool ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_log_permissions " , permission : : b_virtualserver_modify_log_settings , bool ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_log_server " , permission : : b_virtualserver_modify_log_settings , bool ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_log_filetransfer " , permission : : b_virtualserver_modify_log_settings , bool ) }
SERVEREDIT_CHK_PROP ( " virtualserver_min_client_version " , permission : : b_virtualserver_modify_min_client_version , uint64_t ) }
SERVEREDIT_CHK_PROP ( " virtualserver_min_android_version " , permission : : b_virtualserver_modify_min_client_version , uint64_t ) }
SERVEREDIT_CHK_PROP ( " virtualserver_min_ios_version " , permission : : b_virtualserver_modify_min_client_version , uint64_t ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_music_bot_limit " , permission : : b_virtualserver_modify_music_bot_limit , int ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_flag_password " , permission : : b_virtualserver_modify_password , bool )
if ( cmd [ " virtualserver_flag_password " ] . as < bool > ( ) & & ! cmd [ 0 ] . has ( " virtualserver_password " ) )
return { findError ( " parameter_invalid " ) , " Invalid password flag " } ;
} SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_password " , permission : : b_virtualserver_modify_password , string )
if ( cmd [ " virtualserver_password " ] . string ( ) . empty ( ) ) {
toApplay [ " virtualserver_flag_password " ] = " 0 " ;
} else {
toApplay [ " virtualserver_flag_password " ] = " 1 " ;
if ( this - > getType ( ) = = CLIENT_QUERY )
toApplay [ " virtualserver_password " ] = base64 : : encode ( digest : : sha1 ( cmd [ " virtualserver_password " ] . string ( ) ) ) ;
}
}
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_default_client_description " , permission : : b_virtualserver_modify_default_messages , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_default_channel_description " , permission : : b_virtualserver_modify_default_messages , string ) }
SERVEREDIT_CHK_PROP_CACHED ( " virtualserver_default_channel_topic " , permission : : b_virtualserver_modify_default_messages , string ) }
SERVEREDIT_CHK_PROP2 ( " virtualserver_max_download_total_bandwidth " , permission : : b_virtualserver_modify_ft_settings , uint64_t , int64_t )
if ( cmd [ " virtualserver_max_download_total_bandwidth " ] . string ( ) . find ( ' - ' ) = = string : : npos )
toApplay [ " virtualserver_max_download_total_bandwidth " ] = to_string ( ( int64_t ) cmd [ " virtualserver_max_download_total_bandwidth " ] . as < uint64_t > ( ) ) ;
else
toApplay [ " virtualserver_max_download_total_bandwidth " ] = to_string ( cmd [ " virtualserver_max_download_total_bandwidth " ] . as < int64_t > ( ) ) ;
}
SERVEREDIT_CHK_PROP2 ( " virtualserver_max_upload_total_bandwidth " , permission : : b_virtualserver_modify_ft_settings , uint64_t , int64_t )
if ( cmd [ " virtualserver_max_upload_total_bandwidth " ] . string ( ) . find ( ' - ' ) = = string : : npos )
toApplay [ " virtualserver_max_upload_total_bandwidth " ] = to_string ( ( int64_t ) cmd [ " virtualserver_max_upload_total_bandwidth " ] . as < uint64_t > ( ) ) ;
else
toApplay [ " virtualserver_max_upload_total_bandwidth " ] = to_string ( cmd [ " virtualserver_max_upload_total_bandwidth " ] . as < int64_t > ( ) ) ;
}
SERVEREDIT_CHK_PROP2 ( " virtualserver_download_quota " , permission : : b_virtualserver_modify_ft_quotas , uint64_t , int64_t )
if ( cmd [ " virtualserver_download_quota " ] . string ( ) . find ( ' - ' ) = = string : : npos )
toApplay [ " virtualserver_download_quota " ] = to_string ( ( int64_t ) cmd [ " virtualserver_download_quota " ] . as < uint64_t > ( ) ) ;
else
toApplay [ " virtualserver_download_quota " ] = to_string ( cmd [ " virtualserver_download_quota " ] . as < int64_t > ( ) ) ;
}
SERVEREDIT_CHK_PROP2 ( " virtualserver_upload_quota " , permission : : b_virtualserver_modify_ft_quotas , uint64_t , int64_t )
if ( cmd [ " virtualserver_upload_quota " ] . string ( ) . find ( ' - ' ) = = string : : npos )
toApplay [ " virtualserver_upload_quota " ] = to_string ( ( int64_t ) cmd [ " virtualserver_upload_quota " ] . as < uint64_t > ( ) ) ;
else
toApplay [ " virtualserver_upload_quota " ] = to_string ( cmd [ " virtualserver_upload_quota " ] . as < int64_t > ( ) ) ;
}
else {
logError ( target_server ? target_server - > getServerId ( ) : 0 , " Client " + this - > getDisplayName ( ) + " tried to change a not existing server properties. ( " + key + " ) " ) ;
//return CommandResult::NotImplemented;
}
}
std : : deque < std : : string > keys ;
bool group_update = false ;
for ( const auto & elm : toApplay ) {
auto info = property : : impl : : info < property : : VirtualServerProperties > ( elm . first ) ;
if ( * info = = property : : VIRTUALSERVER_UNDEFINED ) {
logCritical ( target_server ? target_server - > getServerId ( ) : 0 , " Missing server property " + elm . first ) ;
continue ;
}
if ( ! info - > validate_input ( elm . second ) ) {
logError ( target_server ? target_server - > getServerId ( ) : 0 , " Client " + this - > getDisplayName ( ) + " tried to change a property to an invalid value. (Value: ' " + elm . second + " ', Property: ' " + info - > name + " ') " ) ;
continue ;
}
if ( target_server )
target_server - > properties ( ) [ info ] = elm . second ;
else
( * serverInstance - > getDefaultServerProperties ( ) ) [ info ] = elm . second ;
keys . push_back ( elm . first ) ;
group_update | = * info = = property : : VIRTUALSERVER_DEFAULT_SERVER_GROUP | | * info = = property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP | | * info = = property : : VIRTUALSERVER_DEFAULT_MUSIC_GROUP ;
}
if ( target_server ) {
if ( group_update )
target_server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & client ) {
if ( target_server - > notifyClientPropertyUpdates ( client , target_server - > groups - > update_server_group_property ( client , true ) ) ) {
if ( client - > update_cached_permissions ( ) ) /* update cached calculated permissions */
client - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
}
} ) ;
if ( ! keys . empty ( ) )
target_server - > notifyServerEdited ( _this . lock ( ) , keys ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientGetVariables ( Command & cmd ) {
CMD_REQ_SERVER ;
auto client = this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) ;
shared_lock tree_lock ( this - > channel_lock ) ;
if ( ! client | | ( client ! = this & & ! this - > isClientVisible ( client , false ) ) )
return { findError ( " client_invalid_id " ) , " " } ;
deque < shared_ptr < 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 ( property : : info ( ( property : : ClientProperties ) prop . type ( ) . property_index ) ) ;
}
this - > notifyClientUpdated ( client , props , false ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientKick ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto client = this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) ;
if ( ! client ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
if ( client - > getType ( ) = = CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) , " You cant kick a music bot! " } ;
std : : shared_ptr < BasicChannel > targetChannel = nullptr ;
auto type = cmd [ " reasonid " ] . as < ViewReasonId > ( ) ;
if ( type = = ViewReasonId : : VREASON_CHANNEL_KICK ) {
auto channel = client - > currentChannel ;
PERM_CHECK_CHANNELR ( permission : : i_client_kick_from_channel_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_needed_kick_from_channel_power , channel ) , channel , true ) ;
targetChannel = this - > server - > channelTree - > getDefaultChannel ( ) ;
} else if ( type = = ViewReasonId : : VREASON_SERVER_KICK ) {
auto channel = client - > currentChannel ;
PERM_CHECK_CHANNELR ( permission : : i_client_kick_from_server_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_needed_kick_from_server_power , channel ) , channel , true ) ;
targetChannel = nullptr ;
} else return CommandResult : : NotImplemented ;
if ( targetChannel ) {
this - > server - > notify_client_kick ( client , this - > ref ( ) , cmd [ " reasonmsg " ] . as < std : : string > ( ) , targetChannel ) ;
} else {
this - > server - > notify_client_kick ( client , this - > ref ( ) , cmd [ " reasonmsg " ] . as < std : : string > ( ) , nullptr ) ;
client - > closeConnection ( system_clock : : now ( ) + seconds ( 1 ) ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelGetDescription ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 0 ) ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < BasicChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
if ( ! this - > permission_granted ( this - > permissionValue ( permission : : b_channel_ignore_description_view_power , channel ) , 1 , true ) ) {
CHANNEL_PERMISSION_TEST ( permission : : i_channel_description_view_power , permission : : i_channel_needed_description_view_power , channel , false ) ;
}
this - > sendChannelDescription ( channel , true ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandGetConnectionInfo ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto client = this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) ;
if ( ! client ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
auto info = client - > requestConnectionInfo ( _this . lock ( ) ) ;
if ( info )
this - > notifyConnectionInfo ( client , info ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandSetConnectionInfo ( Command & cmd ) {
auto info = std : : make_shared < ConnectionInfoData > ( ) ;
info - > timestamp = chrono : : system_clock : : now ( ) ;
for ( const auto & key : cmd [ 0 ] . keys ( ) )
info - > properties . insert ( { key , cmd [ key ] . string ( ) } ) ;
/*
CONNECTION_FILETRANSFER_BANDWIDTH_SENT , //how many bytes per second are currently being sent by file transfers
CONNECTION_FILETRANSFER_BANDWIDTH_RECEIVED , //how many bytes per second are currently being received by file transfers
CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL , //how many bytes we received in total through file transfers
CONNECTION_FILETRANSFER_BYTES_SENT_TOTAL , //how many bytes we sent in total through file transfers
*/
deque < shared_ptr < ConnectedClient > > receivers ;
{
lock_guard info_lock ( this - > connection_info . lock ) ;
for ( const auto & weak_receiver : this - > connection_info . receiver ) {
auto receiver = weak_receiver . lock ( ) ;
if ( ! receiver ) continue ;
receivers . push_back ( receiver ) ;
}
this - > connection_info . receiver . clear ( ) ;
this - > connection_info . data = info ;
this - > connection_info . data_age = system_clock : : now ( ) ;
}
for ( const auto & receiver : receivers )
receiver - > notifyConnectionInfo ( _this . lock ( ) , info ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerRequestConnectionInfo ( Command & ) {
CMD_REQ_SERVER ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_connectioninfo_view , 1 , true ) ;
Command notify ( " notifyserverconnectioninfo " ) ;
auto statistics = this - > server - > getServerStatistics ( ) - > statistics ( ) ;
auto report = this - > server - > getServerStatistics ( ) - > dataReport ( ) ;
notify [ 0 ] [ " connection_filetransfer_bandwidth_sent " ] = report . file_send ;
notify [ 0 ] [ " connection_filetransfer_bandwidth_received " ] = report . file_recv ;
notify [ 0 ] [ " connection_filetransfer_bytes_sent_total " ] = ( * statistics ) [ property : : CONNECTION_FILETRANSFER_BYTES_SENT_TOTAL ] . as < string > ( ) ;
notify [ 0 ] [ " connection_filetransfer_bytes_received_total " ] = ( * statistics ) [ property : : CONNECTION_FILETRANSFER_BYTES_RECEIVED_TOTAL ] . as < string > ( ) ;
notify [ 0 ] [ " connection_packets_sent_total " ] = ( * statistics ) [ property : : CONNECTION_PACKETS_SENT_TOTAL ] . as < string > ( ) ;
notify [ 0 ] [ " connection_bytes_sent_total " ] = ( * statistics ) [ property : : CONNECTION_BYTES_SENT_TOTAL ] . as < string > ( ) ;
notify [ 0 ] [ " connection_packets_received_total " ] = ( * statistics ) [ property : : CONNECTION_PACKETS_RECEIVED_TOTAL ] . as < string > ( ) ;
notify [ 0 ] [ " connection_bytes_received_total " ] = ( * statistics ) [ property : : CONNECTION_BYTES_RECEIVED_TOTAL ] . as < string > ( ) ;
notify [ 0 ] [ " connection_bandwidth_sent_last_second_total " ] = report . send_second ;
notify [ 0 ] [ " connection_bandwidth_sent_last_minute_total " ] = report . send_minute ;
notify [ 0 ] [ " connection_bandwidth_received_last_second_total " ] = report . recv_second ;
notify [ 0 ] [ " connection_bandwidth_received_last_minute_total " ] = report . recv_minute ;
notify [ 0 ] [ " connection_connected_time " ] = this - > server - > properties ( ) [ property : : VIRTUALSERVER_UPTIME ] . as < string > ( ) ;
notify [ 0 ] [ " connection_packetloss_total " ] = this - > server - > averagePacketLoss ( ) ;
notify [ 0 ] [ " connection_ping " ] = this - > server - > averagePing ( ) ;
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
//connectioninfoautoupdate connection_server2client_packetloss_speech=0.0000 connection_server2client_packetloss_keepalive=0.0010 connection_server2client_packetloss_control=0.0000 connection_server2client_packetloss_total=0.0009
CommandResult ConnectedClient : : handleCommandConnectionInfoAutoUpdate ( Command & cmd ) {
this - > properties ( ) [ property : : CONNECTION_SERVER2CLIENT_PACKETLOSS_KEEPALIVE ] = cmd [ " connection_server2client_packetloss_keepalive " ] . as < std : : string > ( ) ;
this - > properties ( ) [ property : : CONNECTION_SERVER2CLIENT_PACKETLOSS_CONTROL ] = cmd [ " connection_server2client_packetloss_control " ] . as < std : : string > ( ) ;
this - > properties ( ) [ property : : CONNECTION_SERVER2CLIENT_PACKETLOSS_SPEECH ] = cmd [ " connection_server2client_packetloss_speech " ] . as < std : : string > ( ) ;
this - > properties ( ) [ property : : CONNECTION_SERVER2CLIENT_PACKETLOSS_TOTAL ] = cmd [ " connection_server2client_packetloss_total " ] . as < std : : string > ( ) ;
return CommandResult : : Success ;
}
CommandResult 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 { findError ( " database_empty_result " ) , " empty! " } ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelSubscribe ( Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
bool flood_points = false ;
deque < shared_ptr < BasicChannel > > channels ;
{
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto local_channel = this - > channel_view ( ) - > find_channel ( cmd [ index ] [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! local_channel )
return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
auto channel = this - > server - > channelTree - > findChannel ( cmd [ index ] [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel )
return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
channels . push_back ( channel ) ;
if ( ! flood_points & & system_clock : : now ( ) - local_channel - > view_timestamp > seconds ( 5 ) ) {
flood_points = true ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 15 ) ;
}
}
if ( ! channels . empty ( ) )
this - > subscribeChannel ( channels , false , false ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelSubscribeAll ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 20 ) ;
{
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock ) ;
this - > subscribeChannel ( this - > server - > channelTree - > channels ( ) , false , false ) ;
this - > subscribeToAll = true ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelUnsubscribe ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
{
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock ) ;
deque < shared_ptr < BasicChannel > > channels ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) continue ;
channels . push_front ( channel ) ;
}
this - > unsubscribeChannel ( channels , false ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelUnsubscribeAll ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
{
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock ) ;
this - > unsubscribeChannel ( this - > server - > channelTree - > channels ( ) , false ) ;
this - > subscribeToAll = false ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPermissionList ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
static std : : string permission_list_string ;
static std : : mutex permission_list_string_lock ;
static auto build_permission_list = [ ] ( const std : : string & command ) {
Command list_builder ( command ) ;
int index = 0 ;
for ( auto group : permission : : availableGroups )
list_builder [ index + + ] [ " group_id_end " ] = group ;
auto avPerms = permission : : availablePermissions ;
std : : sort ( avPerms . begin ( ) , avPerms . end ( ) , [ ] ( const std : : shared_ptr < permission : : PermissionTypeEntry > & a , const std : : shared_ptr < permission : : PermissionTypeEntry > & b ) {
return a - > type < b - > type ;
} ) ;
for ( const auto & permission : avPerms ) {
if ( ! permission - > clientSupported ) continue ;
auto & blk = list_builder [ index + + ] ;
blk [ " permname " ] = permission - > name ;
blk [ " permdesc " ] = permission - > description ;
blk [ " permid " ] = permission - > type ;
}
return list_builder ;
} ;
if ( this - > getType ( ) = = CLIENT_TEASPEAK | | this - > getType ( ) = = CLIENT_TEAMSPEAK | | this - > getType ( ) = = CLIENT_QUERY ) {
Command response ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifypermissionlist " : " " ) ;
{
lock_guard lock ( permission_list_string_lock ) ;
if ( permission_list_string . empty ( ) )
permission_list_string = build_permission_list ( " " ) . build ( ) ;
response [ 0 ] [ " " ] = permission_list_string ;
}
this - > sendCommand ( response ) ;
} else {
this - > sendCommand ( build_permission_list ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifypermissionlist " : " " ) ) ;
}
return CommandResult : : Success ;
}
# define M(ptype) \
do { \
for ( const auto & prop : property : : impl : : list < ptype > ( ) ) { \
if ( ( prop - > flags & property : : FLAG_INTERNAL ) > 0 ) continue ; \
response [ index ] [ " name " ] = prop - > name ; \
response [ index ] [ " flags " ] = prop - > flags ; \
response [ index ] [ " type " ] = property : : PropertyType_Names [ prop - > type_property ] ; \
index + + ; \
} \
} while ( 0 )
CommandResult ConnectedClient : : handleCommandPropertyList ( ts : : Command & cmd ) {
Command response ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifypropertylist " : " " ) ;
{
string pattern ;
for ( auto flag_name : property : : flag_names )
pattern = flag_name + string ( " | " ) + pattern ;
pattern = pattern . substr ( 0 , pattern . length ( ) - 1 ) ;
response [ " flag_set " ] = pattern ;
}
int index = 0 ;
if ( cmd . hasParm ( " all " ) | | cmd . hasParm ( " server " ) )
M ( property : : VirtualServerProperties ) ;
if ( cmd . hasParm ( " all " ) | | cmd . hasParm ( " channel " ) )
M ( property : : ChannelProperties ) ;
if ( cmd . hasParm ( " all " ) | | cmd . hasParm ( " client " ) )
M ( property : : ClientProperties ) ;
if ( cmd . hasParm ( " all " ) | | cmd . hasParm ( " instance " ) )
M ( property : : InstanceProperties ) ;
if ( cmd . hasParm ( " all " ) | | cmd . hasParm ( " group " ) )
M ( property : : GroupProperties ) ;
if ( cmd . hasParm ( " all " ) | | cmd . hasParm ( " connection " ) )
M ( property : : ConnectionProperties ) ;
this - > sendCommand ( response ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerGroupList ( Command & ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_servergroup_list , 1 , true ) ;
this - > notifyServerGroupList ( ) ;
this - > command_times . servergrouplist = system_clock : : now ( ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelGroupAdd ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_channelgroup_create , 1 , true ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
if ( cmd [ " type " ] . as < GroupType > ( ) = = GroupType : : GROUP_TYPE_NORMAL & & ! this - > server ) return { findError ( " parameter_invalid " ) , " You cant create normal channel groups on the template server " } ;
if ( cmd [ " name " ] . string ( ) . empty ( ) ) return { findError ( " parameter_invalid " ) , " invalid group name " } ;
for ( const auto & gr : group_manager - > availableServerGroups ( true ) )
if ( gr - > name ( ) = = cmd [ " name " ] . string ( ) & & gr - > target ( ) = = GroupTarget : : GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " Group already exists " } ;
auto group = group_manager - > createGroup ( GroupTarget : : GROUPTARGET_CHANNEL , cmd [ " type " ] . as < GroupType > ( ) , cmd [ " name " ] . string ( ) ) ;
if ( group ) {
group - > permissions ( ) - > set_permission ( permission : : b_group_is_permanent , { 1 , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
if ( this - > server )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
} else return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
return CommandResult : : Success ;
}
//name=Channel\sAdmin scgid=5 tcgid=4 type=1
CommandResult ConnectedClient : : handleCommandChannelGroupCopy ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_channelgroup_create , 1 , true ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto src = group_manager - > findGroup ( cmd [ " scgid " ] . as < GroupId > ( ) ) ;
if ( ! src | | src - > target ( ) ! = GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " invalid channel group id " } ;
bool global = false ;
if ( cmd [ 0 ] . has ( " tcgid " ) & & cmd [ " tcgid " ] . as < GroupId > ( ) ! = 0 ) {
auto target = group_manager - > findGroup ( cmd [ " tcgid " ] . as < GroupId > ( ) ) ;
if ( ! target | | target - > target ( ) ! = GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " invalid target channel group id " } ;
auto result = group_manager - > copyGroupPermissions ( src , target ) ;
if ( ! result ) return { findError ( " vs_critical " ) , " could not copy group! " } ;
global = ! this - > server | | group_manager - > isLocalGroup ( target ) ;
} else {
auto type = cmd [ " type " ] . as < GroupType > ( ) ;
if ( type = = GroupType : : GROUP_TYPE_QUERY )
CACHED_PERM_CHECK ( permission : : b_serverinstance_modify_querygroup , 1 , true ) ;
if ( type = = GroupType : : GROUP_TYPE_TEMPLATE )
CACHED_PERM_CHECK ( permission : : b_serverinstance_modify_templates , 1 , true ) ;
if ( type = = GroupType : : GROUP_TYPE_NORMAL & & ! this - > server ) return { findError ( " parameter_invalid " ) , " You cant create normal channel groups on the template server " } ;
auto result = group_manager - > copyGroup ( src , cmd [ " type " ] , cmd [ " name " ] , type = = GROUP_TYPE_NORMAL ? this - > getServerId ( ) : 0 ) ; //TODO maybe check by name? No duplicated groups?
if ( ! result ) return { findError ( " vs_critical " ) , " could not copy group! " } ;
global = ! this - > server | | type ! = GroupType : : GROUP_TYPE_NORMAL ;
if ( this - > getType ( ) = = ClientType : : CLIENT_QUERY ) {
Command notify ( " " ) ;
notify [ " cgid " ] = group_manager - > availableChannelGroups ( false ) . back ( ) - > groupId ( ) ;
this - > sendCommand ( notify ) ;
}
}
for ( const auto & server : ( global ? serverInstance - > getVoiceServerManager ( ) - > serverInstances ( ) : deque < shared_ptr < TSServer > > { this - > server } ) )
if ( server )
server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelGroupRename ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto serverGroup = group_manager - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup | | serverGroup - > target ( ) ! = GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " invalid channel group id " } ;
GROUP_PERMISSION_TEST ( permission : : i_channel_group_modify_power , permission : : i_channel_group_needed_modify_power , serverGroup , true ) ;
group_manager - > renameGroup ( serverGroup , cmd [ " name " ] . string ( ) ) ;
if ( this - > server )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelGroupDel ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto channel_group = group_manager - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! channel_group | | channel_group - > target ( ) ! = GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " invalid channel group id " } ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_channelgroup_delete , 1 , true ) ;
if ( this - > server ) {
if ( this - > server - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] = = channel_group - > groupId ( ) )
return { findError ( " parameter_invalid " ) , " Could not delete default channel group! " } ;
if ( this - > server - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] = = channel_group - > groupId ( ) )
return { findError ( " parameter_invalid " ) , " Could not delete default channel admin group! " } ;
}
if ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP ] = = channel_group - > groupId ( ) )
return { findError ( " parameter_invalid " ) , " Could not delete instance default channel group! " } ;
if ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP ] = = channel_group - > groupId ( ) )
return { findError ( " parameter_invalid " ) , " Could not delete instance default channel admin group! " } ;
if ( ! cmd [ " force " ] . as < bool > ( ) )
if ( ! group_manager - > listGroupMembers ( channel_group , false ) . empty ( ) )
return { findError ( " database_empty_result " ) , " group not empty! " } ;
if ( group_manager - > deleteGroup ( channel_group ) & & this - > server ) {
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > cl ) {
if ( this - > server - > notifyClientPropertyUpdates ( cl , this - > server - > groups - > update_server_group_property ( cl , true ) ) ) {
if ( cl - > update_cached_permissions ( ) ) /* update cached calculated permissions */
cl - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
}
cl - > notifyChannelGroupList ( ) ;
} ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelGroupList ( Command & ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_channelgroup_list , 1 , true ) ;
this - > notifyChannelGroupList ( ) ;
this - > command_times . servergrouplist = system_clock : : now ( ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelGroupClientList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_channelgroup_client_list , 1 , true ) ;
Command result ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifychannelgroupclientlist " : " " ) ;
deque < variable > variables { variable { " :sid " , this - > getServerId ( ) } } ;
string query = " SELECT `groupId`, `cldbid`, `until`, `channelId` FROM `assignedGroups` WHERE `serverId` = :sid " ;
if ( cmd [ 0 ] . has ( " cgid " ) & & cmd [ " cgid " ] . as < GroupId > ( ) > 0 ) {
auto group = this - > server - > getGroupManager ( ) - > findGroup ( cmd [ " cgid " ] ) ;
if ( ! group | | group - > target ( ) ! = GroupTarget : : GROUPTARGET_CHANNEL )
return { findError ( " parameter_invalid " ) , " invalid channel group id " } ;
query + = " AND `groupId` = :groupId " ;
variables . push_back ( { " :groupId " , cmd [ " cgid " ] . as < GroupId > ( ) } ) ;
} else {
query + = " AND `groupId` IN (SELECT `groupId` FROM `groups` WHERE `serverId` = :sid AND `target` = :target) " ;
variables . push_back ( { " :target " , GroupTarget : : GROUPTARGET_CHANNEL } ) ;
}
if ( cmd [ 0 ] . has ( " cldbid " ) & & cmd [ " cldbid " ] . as < ClientDbId > ( ) > 0 ) {
query + = " AND `cldbid` = :cldbid " ;
variables . push_back ( { " :cldbid " , cmd [ " cldbid " ] . as < ClientDbId > ( ) } ) ;
}
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] . as < ChannelId > ( ) > 0 ) {
auto channel = this - > server - > getChannelTree ( ) - > findChannel ( cmd [ " cid " ] ) ;
if ( ! channel )
return { findError ( " parameter_invalid " ) , " invalid channel id " } ;
query + = " AND `channelId` = :cid " ;
variables . push_back ( { " :cid " , cmd [ " cid " ] . as < ChannelId > ( ) } ) ;
}
debugMessage ( this - > getServerId ( ) , " Command channelgroupclientlist sql: {} " , query ) ;
auto command = sql : : command ( this - > sql , query ) ;
for ( const auto & variable : variables )
command . value ( variable ) ;
int index = 0 ;
command . query ( [ & ] ( Command & command , int & index , int length , string * values , string * names ) {
GroupId group_id = 0 ;
ChannelId channel_id = 0 ;
ClientDbId cldbid = 0 ;
for ( int i = 0 ; i < length ; i + + ) {
try {
if ( names [ i ] = = " groupId " )
group_id = stoll ( values [ i ] ) ;
else if ( names [ i ] = = " cldbid " )
cldbid = stoll ( values [ i ] ) ;
else if ( names [ i ] = = " channelId " )
channel_id = stoll ( values [ i ] ) ;
} catch ( std : : exception & ex ) {
logError ( this - > getServerId ( ) , " Failed to parse db field {} " , names [ i ] ) ;
}
}
result [ index ] [ " cid " ] = channel_id ;
result [ index ] [ " cgid " ] = group_id ;
result [ index ] [ " cldbid " ] = cldbid ;
index + + ;
} , result , index ) ;
if ( index = = 0 ) return { findError ( " database_empty_result " ) , " empty " } ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelGroupPermList ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_channelgroup_permission_list , 1 , true ) ;
auto channelGroup = ( this - > server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ) - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! channelGroup | | channelGroup - > target ( ) ! = GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " invalid channel group id " } ;
if ( ! this - > notifyGroupPermList ( channelGroup , cmd . hasParm ( " permsid " ) ) ) return { findError ( " database_empty_result " ) , " empty " } ;
if ( this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK & & this - > command_times . last_notify + this - > command_times . notify_timeout < system_clock : : now ( ) ) {
this - > sendTSPermEditorWarning ( ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelGroupAddPerm ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto channelGroup = group_manager - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! channelGroup | | channelGroup - > target ( ) ! = GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " invalid channel group id " } ;
GROUP_PERMISSION_TEST ( permission : : i_channel_group_modify_power , permission : : i_channel_group_needed_modify_power , channelGroup , true ) ;
auto maxValue = this - > getPermissionGrantValue ( permission : : PERMTEST_ORDERED , permission : : i_permission_modify_power , this - > currentChannel ) ;
bool ignoreGrant = this - > permission_granted ( this - > cached_permission_value ( permission : : b_permission_modify_power_ignore ) , 1 ) ;
bool updateList = false ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto permission_manager = channelGroup - > permissions ( ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & val > maxValue )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( grant ) {
permission_manager - > set_permission ( permType , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : set_value ) ;
} else {
permission_manager - > set_permission (
permType ,
{ cmd [ index ] [ " permvalue " ] , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing ,
2019-07-19 22:55:03 +02:00
cmd [ index ] [ " permskip " ] . as < bool > ( ) ? 1 : 0 ,
cmd [ index ] [ " permnegated " ] . as < bool > ( ) ? 1 : 0
2019-07-17 19:37:18 +02:00
) ;
updateList | = permission_is_group_property ( permType ) ;
}
}
if ( updateList )
channelGroup - > apply_properties_from_permissions ( ) ;
if ( this - > server ) {
if ( updateList )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
this - > server - > forEachClient ( [ channelGroup ] ( shared_ptr < ConnectedClient > cl ) {
unique_lock client_channel_lock ( cl - > channel_lock ) ; /* while we're updating groups we dont want to change anything! */
if ( cl - > channelGroupAssigned ( channelGroup , cl - > getChannel ( ) ) ) {
if ( cl - > update_cached_permissions ( ) )
cl - > sendNeededPermissions ( false ) ; /* update the needed permissions */
2019-07-23 10:37:56 +02:00
cl - > updateChannelClientProperties ( false , true ) ;
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
2019-07-17 19:37:18 +02:00
}
} ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelGroupDelPerm ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto channelGroup = group_manager - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! channelGroup | | channelGroup - > target ( ) ! = GROUPTARGET_CHANNEL ) return { findError ( " parameter_invalid " ) , " invalid channel group id " } ;
GROUP_PERMISSION_TEST ( permission : : i_channel_group_modify_power , permission : : i_channel_group_needed_modify_power , channelGroup , true ) ;
bool ignoreGrant = this - > permission_granted ( this - > cached_permission_value ( permission : : b_permission_modify_power_ignore ) , 1 ) ;
bool updateList = false ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto permission_manager = channelGroup - > permissions ( ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd )
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( grant ) {
permission_manager - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : delete_value ) ;
} else {
permission_manager - > set_permission (
permType ,
permission : : v2 : : empty_permission_values ,
permission : : v2 : : PermissionUpdateType : : delete_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing
) ;
updateList | = permission_is_group_property ( permType ) ;
}
}
if ( updateList )
channelGroup - > apply_properties_from_permissions ( ) ;
if ( this - > server ) {
if ( updateList )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
this - > server - > forEachClient ( [ channelGroup ] ( shared_ptr < ConnectedClient > cl ) {
unique_lock client_channel_lock ( cl - > channel_lock ) ; /* while we're updating groups we dont want to change anything! */
if ( cl - > channelGroupAssigned ( channelGroup , cl - > getChannel ( ) ) ) {
if ( cl - > update_cached_permissions ( ) ) /* update cached calculated permissions */
cl - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
2019-07-23 10:37:56 +02:00
cl - > updateChannelClientProperties ( false , false ) ;
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
2019-07-17 19:37:18 +02:00
}
} ) ;
}
return CommandResult : : Success ;
}
using namespace std : : chrono ;
CommandResult 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 target_client_id = cmd [ " clid " ] . as < ClientId > ( ) ;
auto target_client = target_client_id = = 0 ? this - > ref ( ) : this - > server - > findClient ( target_client_id ) ;
if ( ! target_client ) {
return { findError ( " client_invalid_id " ) , " Invalid target clid " } ;
}
if ( ! target_client - > currentChannel ) {
if ( target_client ! = this )
return { findError ( " client_invalid_id " ) , " Invalid target clid " } ;
}
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) {
return { findError ( " channel_invalid_id " ) } ;
}
auto permission_cache = make_shared < CalculateCache > ( ) ;
if ( ! cmd [ 0 ] . has ( " cpw " ) )
cmd [ " cpw " ] = " " ;
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] , true ) )
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_channel_join_ignore_password , 1 , channel , true , permission_cache ) )
return { findError ( " channel_invalid_password " ) , " invalid password " } ;
switch ( channel - > channelType ( ) ) {
case ChannelType : : permanent :
PERM_CHECK_CHANNEL_CR ( permission : : b_channel_join_permanent , 1 , channel , true , permission_cache ) ;
break ;
case ChannelType : : semipermanent :
PERM_CHECK_CHANNEL_CR ( permission : : b_channel_join_semi_permanent , 1 , channel , true , permission_cache ) ;
break ;
case ChannelType : : temporary :
PERM_CHECK_CHANNEL_CR ( permission : : b_channel_join_temporary , 1 , channel , true , permission_cache ) ;
break ;
}
if ( ! channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ] . as < bool > ( ) | | ! channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED ] . as < bool > ( ) ) {
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_channel_join_ignore_maxclients , 1 , channel , true , permission_cache ) ) {
if ( ! channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ] . as < bool > ( ) ) {
auto maxClients = channel - > properties ( ) [ property : : CHANNEL_MAXCLIENTS ] . as < int32_t > ( ) ;
if ( maxClients > = 0 & & maxClients < = this - > server - > getClientsByChannel ( channel ) . size ( ) )
return { findError ( " channel_maxclients_reached " ) , " " } ;
}
if ( ! channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED ] . as < bool > ( ) ) {
shared_ptr < BasicChannel > family_root ;
if ( channel - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ] . as < bool > ( ) ) {
family_root = channel ;
while ( family_root & & family_root - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ] . as < bool > ( ) ) family_root = family_root - > parent ( ) ;
}
if ( family_root & & ! family_root - > properties ( ) [ property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED ] ) { //Could not be CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED
auto maxClients = family_root - > properties ( ) [ property : : CHANNEL_MAXFAMILYCLIENTS ] . as < int32_t > ( ) ;
auto clients = 0 ;
for ( const auto & entry : this - > server - > getClientsByChannelRoot ( channel , false ) ) if ( entry . get ( ) ! = this ) clients + + ; //Dont count the client itself
if ( maxClients > = 0 & & maxClients < = clients )
return { findError ( " channel_maxfamily_reached " ) , " " } ;
}
}
}
}
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_channel_ignore_join_power , 1 , channel , true , permission_cache ) ) {
CHANNEL_PERMISSION_TEST ( permission : : i_channel_join_power , permission : : i_channel_needed_join_power , channel , false ) ;
}
2019-07-23 10:37:56 +02:00
if ( target_client = = this ) {
auto permission_cache_current = make_shared < CalculateCache > ( ) ;
auto val = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : b_client_is_sticky , this - > currentChannel , permission_cache_current ) ;
if ( val ! = permNotGranted & & val > 0 ) {
auto st = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : b_client_ignore_sticky , this - > currentChannel , permission_cache_current ) ;
if ( st ! = 1 )
return CommandResultPermissionError { permission : : b_client_is_sticky } ;
}
}
2019-07-17 19:37:18 +02:00
if ( target_client ! = this ) {
PERM_CHECK_CHANNELR ( permission : : i_client_move_power , target_client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_needed_move_power , target_client - > getChannel ( ) ) , target_client - > getChannel ( ) , true ) ;
PERM_CHECK_CHANNEL_CR ( permission : : i_client_move_power , target_client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_needed_move_power , channel ) , channel , true , permission_cache ) ;
}
server_channel_r_lock . unlock ( ) ;
unique_lock server_channel_w_lock ( this - > server - > channel_tree_lock ) ;
auto oldChannel = target_client - > getChannel ( ) ;
this - > server - > client_move (
target_client ,
channel ,
target_client = = this ? nullptr : _this . lock ( ) ,
" " ,
target_client = = this ? ViewReasonId : : VREASON_USER_ACTION : ViewReasonId : : VREASON_MOVED ,
true ,
server_channel_w_lock
) ;
if ( oldChannel ) {
if ( ! server_channel_w_lock . owns_lock ( ) )
server_channel_w_lock . lock ( ) ;
if ( oldChannel - > channelType ( ) = = ChannelType : : temporary & & oldChannel - > properties ( ) [ property : : CHANNEL_DELETE_DELAY ] . as < int64_t > ( ) = = 0 )
if ( this - > server - > getClientsByChannelRoot ( oldChannel , false ) . empty ( ) )
this - > server - > delete_channel ( dynamic_pointer_cast < ServerChannel > ( oldChannel ) , this - > ref ( ) , " temporary auto delete " , server_channel_w_lock ) ;
if ( server_channel_w_lock . owns_lock ( ) )
server_channel_w_lock . unlock ( ) ;
}
return CommandResult : : Success ;
}
//TODO: Test if parent or previous is deleted!
CommandResult ConnectedClient : : handleCommandChannelCreate ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
CMD_CHK_PARM_COUNT ( 1 ) ;
auto permission_cache = make_shared < CalculateCache > ( ) ;
if ( cmd [ 0 ] . has ( " cpid " ) & & cmd [ " cpid " ] . as < uint64_t > ( ) ! = 0 ) CACHED_PERM_CHECK ( permission : : b_channel_create_child , 1 ) ;
if ( cmd [ 0 ] . has ( " channel_order " ) ) CACHED_PERM_CHECK ( permission : : b_channel_create_with_sortorder , 1 ) ;
if ( ! cmd [ 0 ] . has ( " channel_flag_permanent " ) ) cmd [ 0 ] [ " channel_flag_permanent " ] = false ;
if ( ! cmd [ 0 ] . has ( " channel_flag_semi_permanent " ) ) cmd [ 0 ] [ " channel_flag_semi_permanent " ] = false ;
if ( ! cmd [ 0 ] . has ( " channel_flag_default " ) ) cmd [ 0 ] [ " channel_flag_default " ] = false ;
if ( ! cmd [ 0 ] . has ( " channel_flag_password " ) ) cmd [ 0 ] [ " channel_flag_password " ] = false ;
if ( cmd [ 0 ] [ " channel_flag_permanent " ] . as < bool > ( ) ) CACHED_PERM_CHECK ( permission : : b_channel_create_permanent , 1 ) ;
else if ( cmd [ 0 ] [ " channel_flag_semi_permanent " ] . as < bool > ( ) ) CACHED_PERM_CHECK ( permission : : b_channel_create_semi_permanent , 1 ) ;
else CACHED_PERM_CHECK ( permission : : b_channel_create_temporary , 1 ) ;
if ( ! cmd [ 0 ] [ " channel_flag_permanent " ] . as < bool > ( ) & & ! this - > server ) return { findError ( " parameter_invalid " ) , " You can only create a permanent channel " } ;
if ( cmd [ 0 ] [ " channel_flag_default " ] . as < bool > ( ) ) CACHED_PERM_CHECK ( permission : : b_channel_create_with_default , 1 ) ;
if ( cmd [ 0 ] [ " channel_flag_password " ] . as < bool > ( ) ) CACHED_PERM_CHECK ( permission : : b_channel_create_with_password , 1 ) ;
else if ( this - > permission_granted ( this - > cached_permission_value ( permission : : b_channel_create_modify_with_force_password ) , 1 ) ) return CommandResultPermissionError { permission : : b_channel_create_modify_with_force_password } ;
if ( cmd [ 0 ] . has ( " channel_password " ) & & this - > getType ( ) = = ClientType : : CLIENT_QUERY )
cmd [ " channel_password " ] = base64 : : decode ( digest : : sha1 ( cmd [ " channel_password " ] . string ( ) ) ) ;
if ( cmd [ 0 ] . has ( " channel_description " ) ) CACHED_PERM_CHECK ( permission : : b_channel_create_with_description , 1 ) ;
if ( cmd [ 0 ] . has ( " channel_maxclients " ) | | ( cmd [ 0 ] . has ( " channel_flag_maxclients_unlimited " ) & & ! cmd [ " channel_flag_maxclients_unlimited " ] . as < bool > ( ) ) ) {
CACHED_PERM_CHECK ( permission : : b_channel_create_with_maxclients , 1 ) ;
if ( ! cmd [ 0 ] [ " channel_flag_permanent " ] . as < bool > ( ) & & ! cmd [ 0 ] [ " channel_flag_semi_permanent " ] . as < bool > ( ) ) {
cmd [ " channel_maxclients " ] = - 1 ;
cmd [ " channel_flag_maxclients_unlimited " ] = 1 ;
}
}
if ( cmd [ 0 ] . has ( " channel_maxfamilyclients " ) ) CACHED_PERM_CHECK ( permission : : b_channel_create_with_maxfamilyclients , 1 ) ;
if ( cmd [ 0 ] . has ( " channel_needed_talk_power " ) ) CACHED_PERM_CHECK ( permission : : b_channel_create_with_needed_talk_power , 1 ) ;
if ( cmd [ 0 ] . has ( " channel_topic " ) ) CACHED_PERM_CHECK ( permission : : b_channel_create_with_topic , 1 ) ;
auto target_tree = this - > server ? this - > server - > channelTree : serverInstance - > getChannelTree ( ) . get ( ) ;
auto & tree_lock = this - > server ? this - > server - > channel_tree_lock : serverInstance - > getChannelTreeLock ( ) ;
unique_lock tree_channel_lock ( tree_lock ) ;
2019-07-21 17:02:32 +02:00
if ( cmd [ 0 ] . has ( " channel_conversation_history_length " ) ) {
auto value = cmd [ " channel_conversation_history_length " ] . as < int64_t > ( ) ;
if ( value = = 0 ) {
CACHED_PERM_CHECK ( permission : : b_channel_create_modify_conversation_history_unlimited , 1 ) ;
} else {
CACHED_PERM_CHECK ( permission : : i_channel_create_modify_conversation_history_length , 1 ) ;
}
}
2019-07-17 19:37:18 +02:00
{
auto delete_delay = cmd [ 0 ] . has ( " channel_delete_delay " ) ? cmd [ " channel_delete_delay " ] . as < permission : : PermissionValue > ( ) : 0UL ;
if ( delete_delay = = 0 ) {
if ( this - > server )
cmd [ " channel_delete_delay " ] = this - > server - > properties ( ) [ property : : VIRTUALSERVER_CHANNEL_TEMP_DELETE_DELAY_DEFAULT ] . as < uint32_t > ( ) ;
else
cmd [ " channel_delete_delay " ] = 0 ;
} else {
CACHED_PERM_CHECK ( permission : : i_channel_create_modify_with_temp_delete_delay , cmd [ " channel_delete_delay " ] . as < permission : : PermissionValue > ( ) ) ;
}
}
{
size_t created_tmp = 0 , created_semi = 0 , created_perm = 0 ;
auto own_cldbid = this - > getClientDatabaseId ( ) ;
for ( const auto & channel : target_tree - > channels ( ) ) {
if ( channel - > properties ( ) [ property : : CHANNEL_CREATED_BY ] = = own_cldbid ) {
if ( channel - > properties ( ) [ property : : CHANNEL_FLAG_PERMANENT ] . as < bool > ( ) )
created_perm + + ;
else if ( channel - > properties ( ) [ property : : CHANNEL_FLAG_SEMI_PERMANENT ] . as < bool > ( ) )
created_semi + + ;
else
created_tmp + + ;
}
}
auto max_channels = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_max_channels , nullptr , permission_cache ) ;
if ( max_channels > = 0 ) {
if ( max_channels < = created_perm + created_semi + created_tmp )
return CommandResultPermissionError { permission : : i_client_max_channels } ;
}
if ( cmd [ 0 ] [ " channel_flag_permanent " ] . as < bool > ( ) ) {
max_channels = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_max_permanent_channels , nullptr , permission_cache ) ;
if ( max_channels > = 0 ) {
if ( max_channels < = created_perm )
return CommandResultPermissionError { permission : : i_client_max_permanent_channels } ;
}
}
else if ( cmd [ 0 ] [ " channel_flag_semi_permanent " ] . as < bool > ( ) ) {
max_channels = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_max_semi_channels , nullptr , permission_cache ) ;
if ( max_channels > = 0 ) {
if ( max_channels < = created_semi )
return CommandResultPermissionError { permission : : i_client_max_semi_channels } ;
}
}
else {
max_channels = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_max_temporary_channels , nullptr , permission_cache ) ;
if ( max_channels > = 0 ) {
if ( max_channels < = created_tmp )
return CommandResultPermissionError { permission : : i_client_max_temporary_channels } ;
}
}
}
//TODO check voice (opus etc)
std : : shared_ptr < TreeView : : LinkedTreeEntry > parent = nullptr ;
std : : shared_ptr < BasicChannel > created_channel = nullptr , old_default_channel ;
//bool enforce_permanent_parent = cmd[0]["channel_flag_default"].as<bool>(); //TODO check parents here
{ //Checkout the parent(s)
if ( cmd [ 0 ] . has ( " cpid " ) & & cmd [ " cpid " ] . as < ChannelId > ( ) ! = 0 & & cmd [ " cpid " ] . as < int > ( ) ! = - 1 ) {
parent = target_tree - > findLinkedChannel ( cmd [ " cpid " ] . as < ChannelId > ( ) ) ;
if ( ! parent ) return { findError ( " channel_invalid_id " ) , " Cant resolve parent channel " } ;
}
{
auto min_channel_deep = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_channel_min_depth , nullptr , permission_cache ) ;
auto max_channel_deep = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_channel_max_depth , nullptr , permission_cache ) ;
if ( min_channel_deep > = 0 | | max_channel_deep > = 0 ) {
auto channel_deep = 0 ;
auto local_parent = parent ;
while ( local_parent ) {
channel_deep + + ;
{
const auto typed_parent = dynamic_pointer_cast < ServerChannel > ( local_parent - > entry ) ;
if ( typed_parent - > deleted ) return { findError ( " channel_is_deleted " ) , " Oneof parent is deleted " } ;
}
local_parent = local_parent - > parent . lock ( ) ;
}
if ( min_channel_deep > = 0 & & channel_deep < min_channel_deep ) return CommandResultPermissionError { permission : : i_channel_min_depth } ;
if ( max_channel_deep > = 0 & & channel_deep > max_channel_deep ) return CommandResultPermissionError { permission : : i_channel_max_depth } ;
}
}
}
if ( ! cmd [ 0 ] . has ( " channel_order " ) ) {
auto last = parent ? parent - > child_head : target_tree - > tree_head ( ) ;
while ( last & & last - > next )
last = last - > next ;
if ( last )
cmd [ " channel_order " ] = last - > entry - > channelId ( ) ;
} else {
}
if ( cmd [ " channel_name " ] . string ( ) . length ( ) < 1 ) return { findError ( " channel_name_inuse " ) , " Invalid channel name " } ;
{
if ( target_tree - > findChannel ( cmd [ " channel_name " ] . as < std : : string > ( ) , parent ? dynamic_pointer_cast < BasicChannel > ( parent - > entry ) : nullptr ) ) return { findError ( " channel_name_inuse " ) , " Name already in use " } ;
created_channel = target_tree - > createChannel ( parent ? parent - > entry - > channelId ( ) : ( ChannelId ) 0 , cmd [ 0 ] . has ( " channel_order " ) ? cmd [ " channel_order " ] . as < ChannelId > ( ) : ( ChannelId ) 0 , cmd [ " channel_name " ] . as < std : : string > ( ) ) ;
}
if ( ! created_channel ) return { findError ( " channel_invalid_flags " ) , " Could not create channel " } ;
auto created_linked_channel = target_tree - > findLinkedChannel ( created_channel - > channelId ( ) ) ;
sassert ( created_linked_channel ) ;
if ( cmd [ 0 ] . has ( " channel_flag_default " ) & & cmd [ " channel_flag_default " ] . as < bool > ( ) ) {
old_default_channel = target_tree - > getDefaultChannel ( ) ;
target_tree - > setDefaultChannel ( created_channel ) ;
}
created_channel - > properties ( ) [ property : : CHANNEL_CREATED_BY ] = this - > getClientDatabaseId ( ) ;
{
auto permission_manager = created_channel - > permissions ( ) ;
permission_manager - > set_permission (
permission : : i_channel_needed_modify_power ,
{ this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_channel_modify_power , this - > currentChannel , permission_cache ) , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing
) ;
permission_manager - > set_permission (
permission : : i_channel_needed_delete_power ,
{ this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_channel_delete_power , this - > currentChannel , permission_cache ) , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing
) ;
}
for ( auto & prop : cmd [ 0 ] . keys ( ) ) {
if ( prop = = " channel_flag_default " ) continue ;
if ( prop = = " channel_order " ) continue ;
if ( prop = = " channel_name " ) continue ;
if ( prop = = " cpid " ) continue ;
if ( prop = = " cid " ) continue ;
const auto & property = property : : info < property : : ChannelProperties > ( prop ) ;
if ( * property = = property : : CHANNEL_UNDEFINED ) {
logError ( this - > getServerId ( ) , " Client " + this - > getDisplayName ( ) + " tried to change a not existing channel property " + prop ) ;
continue ;
}
if ( ! property - > validate_input ( cmd [ prop ] . as < string > ( ) ) ) {
logError ( this - > getServerId ( ) , " Client " + this - > getDisplayName ( ) + " tried to change a property to an invalid value. (Value: ' " + cmd [ prop ] . as < string > ( ) + " ', Property: ' " + property - > name + " ') " ) ;
continue ;
}
created_channel - > properties ( ) [ property ] = cmd [ prop ] . as < std : : string > ( ) ;
}
if ( created_channel - > parent ( ) ) {
if ( created_channel - > parent ( ) - > channelType ( ) > created_channel - > channelType ( ) )
created_channel - > setChannelType ( created_channel - > parent ( ) - > channelType ( ) ) ;
}
if ( this - > server ) {
const auto self_lock = _this . lock ( ) ;
this - > server - > forEachClient ( [ & , created_channel ] ( const shared_ptr < ConnectedClient > & client ) {
unique_lock client_channel_lock ( client - > channel_lock ) ;
auto result = client - > channels - > add_channel ( created_linked_channel ) ;
if ( ! result ) return ;
client - > notifyChannelCreate ( created_channel , result - > previous_channel , self_lock ) ;
if ( client = = self_lock & & this - > getType ( ) = = ClientType : : CLIENT_QUERY ) {
Command notify ( " " ) ;
notify [ " cid " ] = created_channel - > channelId ( ) ;
this - > sendCommand ( notify ) ;
}
client - > notifyChannelDescriptionChanged ( created_channel ) ;
if ( client - > subscribeToAll )
client - > subscribeChannel ( { created_channel } , false , true ) ;
if ( old_default_channel ) {
//TODO: Reminder: client channel tree must be at least read locked here!
client - > notifyChannelEdited ( old_default_channel , { " channel_flag_default " } , this ) ;
}
} ) ;
GroupId adminGroup = this - > server - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] ;
auto channel_admin_group = this - > server - > groups - > findGroup ( adminGroup ) ;
if ( ! channel_admin_group ) {
logError ( this - > getServerId ( ) , " Missing server's default channel admin group! Using default channel group! " ) ;
channel_admin_group = this - > server - > groups - > defaultGroup ( GroupTarget : : GROUPTARGET_CHANNEL ) ;
}
this - > server - > groups - > setChannelGroup ( this - > getClientDatabaseId ( ) , channel_admin_group , created_channel ) ;
if ( created_channel - > channelType ( ) = = ChannelType : : temporary & & ( this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK | | this - > getType ( ) = = ClientType : : CLIENT_WEB ) )
this - > server - > client_move (
this - > ref ( ) ,
created_channel ,
nullptr ,
" channel created " ,
ViewReasonId : : VREASON_USER_ACTION ,
true ,
tree_channel_lock
) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelDelete ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
RESOLVE_CHANNEL_W ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
if ( channel - > deleted ) /* channel gets already removed */
return CommandResult : : Success ;
CHANNEL_PERMISSION_TEST ( permission : : i_channel_delete_power , permission : : i_channel_needed_delete_power , channel , true ) ;
for ( const auto & ch : channel_tree - > channels ( channel ) ) {
if ( ch - > defaultChannel ( ) )
return { findError ( " channel_can_not_delete_default " ) , " The channel tree you're going to delete contains the default channel! " } ;
}
if ( this - > server ) {
auto clients = this - > server - > getClientsByChannelRoot ( channel , false ) ;
if ( ! clients . empty ( ) )
PERM_CHECK_CHANNELR ( permission : : b_channel_delete_flag_force , 1 , channel , true ) ;
this - > server - > delete_channel ( channel , this - > ref ( ) , " channel deleted " , channel_tree_write_lock ) ;
} else {
auto channel_ids = channel_tree - > deleteChannelRoot ( channel ) ;
this - > notifyChannelDeleted ( channel_ids , this - > ref ( ) ) ;
}
return CommandResult : : Success ;
}
inline ssize_t count_characters ( const std : : string & in ) {
size_t index = 0 ;
size_t count = 0 ;
while ( index < in . length ( ) ) {
count + + ;
auto current = ( uint8_t ) in [ index ] ;
if ( current > = 128 ) { //UTF8 check
if ( current > = 192 & & ( current < = 193 | | current > = 245 ) ) {
return - 1 ;
} else if ( current > = 194 & & current < = 223 ) {
if ( in . length ( ) - index < = 1 ) return - 1 ;
else if ( ( uint8_t ) in [ index + 1 ] > = 128 & & ( uint8_t ) in [ index + 1 ] < = 191 ) index + = 1 ; //Valid
else return - 1 ;
} else if ( current > = 224 & & current < = 239 ) {
if ( in . length ( ) - index < = 2 ) return - 1 ;
else if ( ( uint8_t ) in [ index + 1 ] > = 128 & & ( uint8_t ) in [ index + 1 ] < = 191 & &
( uint8_t ) in [ index + 2 ] > = 128 & & ( uint8_t ) in [ index + 2 ] < = 191 ) index + = 2 ; //Valid
else return - 1 ;
} else if ( current > = 240 & & current < = 244 ) {
if ( in . length ( ) - index < = 3 ) return - 1 ;
else if ( ( uint8_t ) in [ index + 1 ] > = 128 & & ( uint8_t ) in [ index + 1 ] < = 191 & &
( uint8_t ) in [ index + 2 ] > = 128 & & ( uint8_t ) in [ index + 2 ] < = 191 & &
( uint8_t ) in [ index + 3 ] > = 128 & & ( uint8_t ) in [ index + 3 ] < = 191 ) index + = 3 ; //Valid
else return - 1 ;
} else {
return - 1 ;
}
}
index + + ;
}
return count ;
}
/*
* 1. check for permission and basic requirements
* 2. Lock the channel tree in write mode if required
* 3. Apply changed , test for advanced requirements like channel name etc
* 4. notify everyone
*/
CommandResult ConnectedClient : : handleCommandChannelEdit ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
if ( channel - > deleted ) {
/* channel gets already removed */
return CommandResult : : Success ;
}
std : : deque < std : : shared_ptr < property : : PropertyDescription > > keys ;
bool require_write_lock = false ;
bool update_max_clients = false ;
bool update_max_family_clients = false ;
bool update_clients_in_channel = false ;
bool update_password = false ;
bool update_name = false ;
/* Step 1 */
bool target_channel_type_changed = false ;
ChannelType : : ChannelType target_channel_type = channel - > channelType ( ) ;
CHANNEL_PERM_TEST_INIT ;
2019-07-23 10:17:35 +02:00
CHANNEL_PERMISSION_TEST ( permission : : i_channel_modify_power , permission : : i_channel_needed_modify_power , channel , true ) ;
2019-07-17 19:37:18 +02:00
for ( const auto & key : cmd [ 0 ] . keys ( ) ) {
if ( key = = " cid " )
continue ;
2019-07-23 10:21:58 +02:00
if ( key = = " return_code " )
continue ;
2019-07-17 19:37:18 +02:00
const auto & property = property : : info < property : : ChannelProperties > ( key ) ;
if ( * property = = property : : CHANNEL_UNDEFINED ) {
logError ( this - > getServerId ( ) , R " ({} Tried to edit a not existing channel property " { } " to " { } " ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
if ( ( property - > flags & property : : FLAG_USER_EDITABLE ) = = 0 ) {
logError ( this - > getServerId ( ) , " {} Tried to change a channel property which is not changeable. (Key: {}, Value: \" {} \" ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
if ( ! property - > validate_input ( cmd [ key ] . as < string > ( ) ) ) {
logError ( this - > getServerId ( ) , " {} Tried to change a channel property to an invalid value. (Key: {}, Value: \" {} \" ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
2019-07-23 10:21:58 +02:00
if ( channel - > properties ( ) [ * property ] . as < string > ( ) = = cmd [ key ] . as < string > ( ) )
continue ; /* we dont need to update stuff which is the same */
2019-07-17 19:37:18 +02:00
if ( key = = " channel_icon_id " ) {
CHANNEL_PERMISSION_TEST ( permission : : i_channel_permission_modify_power , permission : : i_channel_needed_permission_modify_power , channel , true ) ;
} else if ( key = = " channel_order " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_sortorder , 1 , true ) ;
require_write_lock = true ;
} else if ( key = = " channel_flag_default " ) {
if ( ! cmd [ " channel_flag_default " ] . as < bool > ( ) )
return { findError ( " channel_invalid_flags " ) } ;
CHANNEL_PERM_TEST ( permission : : b_channel_modify_make_default , 1 , true ) ;
require_write_lock = true ;
} else if ( key = = " channel_name " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_name , 1 , true ) ;
if ( count_characters ( cmd [ " channel_name " ] ) < 1 )
return { findError ( " channel_name_inuse " ) , " Invalid channel name (too short) " } ;
if ( count_characters ( cmd [ " channel_name " ] ) > 40 )
return { findError ( " channel_name_inuse " ) , " Invalid channel name (too long) " } ;
require_write_lock = true ;
update_name = true ;
} else if ( key = = " channel_name_phonetic " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_name , 1 , true ) ;
} else if ( key = = " channel_topic " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_topic , 1 , true ) ;
} else if ( key = = " channel_description " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_description , 1 , true ) ;
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_use_bbcode_any , 1 , this - > currentChannel ) ) {
auto bbcode_image = bbcode : : sloppy : : has_image ( cmd [ key ] ) ;
auto bbcode_url = bbcode : : sloppy : : has_url ( cmd [ key ] ) ;
debugMessage ( this - > getServerId ( ) , " Channel description contains bb codes: Image: {} URL: {} " , bbcode_image , bbcode_url ) ;
if ( bbcode_image & & ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_use_bbcode_image , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : b_client_use_bbcode_image } ;
if ( bbcode_url & & ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_use_bbcode_url , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : b_client_use_bbcode_url } ;
}
} else if ( key = = " channel_codec " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_codec , 1 , true ) ;
} else if ( key = = " channel_codec_quality " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_codec_quality , 1 , true ) ;
} else if ( key = = " channel_codec_is_unencrypted " ) {
if ( cmd [ " channel_codec_is_unencrypted " ] . as < bool > ( ) )
CHANNEL_PERM_TEST ( permission : : b_channel_modify_make_codec_encrypted , 1 , true ) ;
} else if ( key = = " channel_needed_talk_power " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_needed_talk_power , 1 , true ) ;
update_clients_in_channel = true ;
} else if ( key = = " channel_maxclients " | | key = = " channel_flag_maxclients_unlimited " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_maxclients , 1 , true ) ;
require_write_lock = true ;
update_max_clients = true ;
} else if ( key = = " channel_maxfamilyclients " | | key = = " channel_flag_maxfamilyclients_unlimited " | | key = = " channel_flag_maxfamilyclients_inherited " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_maxfamilyclients , 1 , true ) ;
require_write_lock = true ;
update_max_family_clients = true ;
} else if ( key = = " channel_flag_permanent " | | key = = " channel_flag_semi_permanent " ) {
if ( cmd [ 0 ] . has ( " channel_flag_permanent " ) & & cmd [ " channel_flag_permanent " ] . as < bool > ( ) ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_make_permanent , 1 , true ) ;
target_channel_type = ChannelType : : permanent ;
} else if ( cmd [ 0 ] . has ( " channel_flag_semi_permanent " ) & & cmd [ " channel_flag_semi_permanent " ] . as < bool > ( ) ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_make_semi_permanent , 1 , true ) ;
target_channel_type = ChannelType : : semipermanent ;
} else {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_make_temporary , 1 , true ) ;
target_channel_type = ChannelType : : temporary ;
}
target_channel_type_changed = true ;
require_write_lock = true ;
} else if ( key = = " channel_delete_delay " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_temp_delete_delay , cmd [ " channel_delete_delay " ] . as < permission : : PermissionValue > ( ) , true ) ;
} else if ( key = = " channel_password " | | key = = " channel_flag_password " ) {
CHANNEL_PERM_TEST ( permission : : b_channel_modify_password , 1 , true ) ;
update_password = true ;
2019-07-21 17:02:32 +02:00
} else if ( key = = " channel_conversation_history_length " ) {
auto value = cmd [ " channel_conversation_history_length " ] . as < int64_t > ( ) ;
if ( value = = 0 ) {
CHANNEL_PERM_TEST ( permission : : b_channel_create_modify_conversation_history_unlimited , 1 , true ) ;
} else {
CHANNEL_PERM_TEST ( permission : : i_channel_create_modify_conversation_history_length , 1 , true ) ;
}
2019-07-17 19:37:18 +02:00
} else {
logCritical (
this - > getServerId ( ) ,
" The client " + this - > getDisplayName ( ) + " tried to change a editable channel property but we haven't found a permission. Please report this error. (Channel property: {}) " ,
key
) ;
continue ;
}
keys . push_back ( property ) ;
}
unique_lock server_channel_w_lock ( this - > server ? this - > server - > channel_tree_lock : serverInstance - > getChannelTreeLock ( ) , defer_lock ) ;
if ( require_write_lock ) {
channel_tree_read_lock . unlock ( ) ;
server_channel_w_lock . lock ( ) ;
/* not that while we're waiting to edit the server the channel got deleted... fuck my english */
if ( channel - > deleted )
return CommandResult : : Success ;
}
/* test the password parameters */
if ( update_password ) {
if ( ! cmd [ 0 ] . has ( " channel_password " ) ) {
if ( cmd [ 0 ] . has ( " channel_flag_password " ) & & cmd [ " channel_flag_password " ] . as < bool > ( ) )
return { findError ( " parameter_missing " ) , " " } ;
else
cmd [ " channel_password " ] = " " ; /* no password set */
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_PASSWORD ) ) ;
}
if ( ! cmd [ 0 ] . has ( " channel_flag_password " ) ) {
cmd [ " channel_flag_password " ] = ! cmd [ " channel_password " ] . string ( ) . empty ( ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_PASSWORD ) ) ;
}
if ( cmd [ " channel_flag_password " ] . as < bool > ( ) ) {
if ( cmd [ " channel_password " ] . string ( ) . empty ( ) )
return { findError ( " channel_invalid_flags " ) } ; /* we cant enable a password without a given password */
/* we've to "encode" the password */
if ( this - > getType ( ) = = ClientType : : CLIENT_QUERY )
cmd [ " channel_password " ] = base64 : : encode ( digest : : sha1 ( cmd [ " channel_password " ] . string ( ) ) ) ;
} else {
cmd [ " channel_password " ] = " " ; /* flag password if false so we set the password to empty */
}
}
/* test the default channel update */
if ( cmd [ 0 ] . has ( " channel_flag_default " ) | | channel - > defaultChannel ( ) ) {
if ( target_channel_type ! = ChannelType : : permanent )
return { findError ( " channel_default_require_permanent " ) } ; /* default channel is not allowed to be non permanent */
if ( ( cmd [ 0 ] . has ( " channel_flag_password " ) & & cmd [ " channel_flag_password " ] . as < bool > ( ) ) | | channel - > properties ( ) [ property : : CHANNEL_FLAG_PASSWORD ] ) {
cmd [ " channel_flag_password " ] = false ;
cmd [ " channel_password " ] = " " ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_PASSWORD ) ) ;
}
if ( cmd [ 0 ] . has ( " channel_flag_default " ) ) {
cmd [ " channel_maxclients " ] = - 1 ;
cmd [ " channel_flag_maxclients_unlimited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXCLIENTS ) ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ) ) ;
update_max_clients = true ;
cmd [ " channel_maxfamilyclients " ] = - 1 ;
cmd [ " channel_flag_maxfamilyclients_inherited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXFAMILYCLIENTS ) ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ) ) ;
update_max_family_clients = true ;
}
}
/* "fix" max client for temporary channels */
if ( target_channel_type_changed ) {
if ( target_channel_type = = ChannelType : : temporary ) {
if ( channel - > properties ( ) [ property : : CHANNEL_MAXCLIENTS ] . as < int > ( ) ! = - 1 ) {
cmd [ " channel_maxclients " ] = - 1 ;
cmd [ " channel_flag_maxclients_unlimited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXCLIENTS ) ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ) ) ;
update_max_clients = true ;
}
if ( channel - > properties ( ) [ property : : CHANNEL_MAXFAMILYCLIENTS ] . as < int > ( ) ! = - 1 ) {
cmd [ " channel_maxfamilyclients " ] = - 1 ;
cmd [ " channel_flag_maxfamilyclients_inherited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXFAMILYCLIENTS ) ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ) ) ;
update_max_family_clients = true ;
}
}
if ( target_channel_type ! = ChannelType : : permanent ) {
/* test if any child is the default channel */
for ( const auto & child : channel_tree - > channels ( channel ) )
if ( child - > defaultChannel ( ) )
return { findError ( " channel_default_require_permanent " ) } ; /* default channel is not allowed to be non permanent */
}
auto parent = channel - > parent ( ) ;
if ( parent & & parent - > channelType ( ) > target_channel_type )
return { findError ( " channel_parent_not_permanent " ) } ;
}
/* test the max clients parameters */
if ( update_max_clients ) {
if ( ! cmd [ 0 ] . has ( " channel_maxclients " ) ) {
if ( cmd [ 0 ] . has ( " channel_flag_maxclients_unlimited " ) & & cmd [ " channel_flag_maxclients_unlimited " ] . as < bool > ( ) )
cmd [ " channel_maxclients " ] = - 1 ;
else
return { findError ( " parameter_missing " ) , " channel_maxclients " } ; /* max clients must be specified */
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXCLIENTS ) ) ;
}
if ( ! cmd [ 0 ] . has ( " channel_flag_maxclients_unlimited " ) ) {
cmd [ " channel_flag_maxclients_unlimited " ] = cmd [ " channel_maxclients " ] . as < int > ( ) < 0 ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ) ) ;
}
if ( cmd [ " channel_flag_maxclients_unlimited " ] . as < bool > ( ) & & cmd [ " channel_maxclients " ] . as < int > ( ) ! = - 1 )
return { findError ( " channel_invalid_flags " ) } ; /* channel cant have a max client settings AND be unlimited as well */
if ( ! cmd [ " channel_flag_maxclients_unlimited " ] . as < bool > ( ) & & target_channel_type = = ChannelType : : temporary )
return { findError ( " channel_invalid_flags " ) } ; /* temporary channels cant have a limited user count */
}
/* test the max family clients parameters */
if ( update_max_family_clients ) {
if ( ! cmd [ 0 ] . has ( " channel_maxfamilyclients " ) ) {
if ( cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_unlimited " ) ) {
if ( cmd [ " channel_flag_maxfamilyclients_unlimited " ] . as < bool > ( ) )
cmd [ " channel_flag_maxfamilyclients_inherited " ] = false ;
else
cmd [ " channel_flag_maxfamilyclients_inherited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ) ) ;
} else if ( cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_inherited " ) ) {
if ( cmd [ " channel_flag_maxfamilyclients_inherited " ] . as < bool > ( ) )
cmd [ " channel_flag_maxfamilyclients_unlimited " ] = false ;
else
cmd [ " channel_flag_maxfamilyclients_unlimited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED ) ) ;
} else /* not really possible */
return { findError ( " parameter_missing " ) , " channel_maxfamilyclients " } ; /* family max clients must be */
cmd [ " channel_maxfamilyclients " ] = - 1 ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXFAMILYCLIENTS ) ) ;
}
//keep this order because this command: "channeledit cid=<x> channel_maxfamilyclients=-1" should set max family clients mode to inherited
if ( ! cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_inherited " ) ) {
auto flag_unlimited = cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_unlimited " ) & & cmd [ " channel_flag_maxfamilyclients_unlimited " ] . as < bool > ( ) ;
if ( flag_unlimited )
cmd [ " channel_flag_maxfamilyclients_inherited " ] = false ;
else
cmd [ " channel_flag_maxfamilyclients_inherited " ] = cmd [ " channel_maxfamilyclients " ] . as < int > ( ) < 0 ;
}
if ( ! cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_unlimited " ) ) {
auto flag_inherited = cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_inherited " ) & & cmd [ " channel_flag_maxfamilyclients_inherited " ] . as < bool > ( ) ;
if ( flag_inherited )
cmd [ " channel_flag_maxfamilyclients_unlimited " ] = false ;
else
cmd [ " channel_flag_maxfamilyclients_unlimited " ] = cmd [ " channel_maxfamilyclients " ] . as < int > ( ) < 0 ;
}
if ( cmd [ " channel_flag_maxfamilyclients_inherited " ] . as < bool > ( ) & & cmd [ " channel_flag_maxfamilyclients_unlimited " ] . as < bool > ( ) )
return { findError ( " channel_invalid_flags " ) } ; /* both at the same time are not possible */
if ( cmd [ " channel_flag_maxfamilyclients_inherited " ] . as < bool > ( ) & & cmd [ " channel_maxfamilyclients " ] . as < int > ( ) ! = - 1 )
return { findError ( " channel_invalid_flags " ) } ; /* flag inherited required max users to be -1 */
if ( cmd [ " channel_flag_maxfamilyclients_unlimited " ] . as < bool > ( ) & & cmd [ " channel_maxfamilyclients " ] . as < int > ( ) ! = - 1 )
return { findError ( " channel_invalid_flags " ) } ; /* flag unlimited required max users to be -1 */
if ( cmd [ " channel_maxfamilyclients " ] . as < int > ( ) ! = - 1 & & target_channel_type = = ChannelType : : temporary )
return { findError ( " channel_invalid_flags " ) } ; /* temporary channels cant have a limited user count */
}
/* test the channel name */
if ( update_name ) {
auto named_channel = channel_tree - > findChannel ( cmd [ " channel_name " ] . string ( ) , channel - > parent ( ) ) ;
if ( named_channel )
return { findError ( " channel_name_inuse " ) , to_string ( named_channel - > channelId ( ) ) } ;
}
shared_ptr < BasicChannel > old_default_channel ;
deque < shared_ptr < BasicChannel > > child_channel_updated ;
for ( const std : : shared_ptr < property : : PropertyDescription > & key : keys ) {
if ( * key = = property : : CHANNEL_ORDER ) {
/* TODO: May move that up because if it fails may some other props have already be applied */
if ( ! channel_tree - > change_order ( channel , cmd [ key - > name ] ) )
return { findError ( " channel_invalid_order " ) , " Can't change order id " } ;
if ( this - > server ) {
auto parent = channel - > hasParent ( ) ? channel_tree - > findLinkedChannel ( channel - > parent ( ) - > channelId ( ) ) : nullptr ;
auto previous = channel_tree - > findLinkedChannel ( channel - > previousChannelId ( ) ) ;
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & cl ) {
unique_lock client_channel_lock ( cl - > channel_lock ) ;
auto actions = cl - > channels - > change_order ( l_channel , parent , previous ) ;
std : : deque < ChannelId > deletions ;
for ( const auto & action : actions ) {
switch ( action . first ) {
case ClientChannelView : : NOTHING :
continue ;
case ClientChannelView : : ENTER_VIEW :
cl - > notifyChannelShow ( action . second - > channel ( ) , action . second - > previous_channel ) ;
break ;
case ClientChannelView : : DELETE_VIEW :
deletions . push_back ( action . second - > channelId ( ) ) ;
break ;
case ClientChannelView : : MOVE :
cl - > notifyChannelMoved ( action . second - > channel ( ) , action . second - > previous_channel , this - > ref ( ) ) ;
break ;
case ClientChannelView : : REORDER :
cl - > notifyChannelEdited ( action . second - > channel ( ) , { " channel_order " } , this ) ;
break ;
}
}
if ( ! deletions . empty ( ) ) {
cl - > notifyChannelHide ( deletions , false ) ;
return ; //Channel got deleted so we dont have to send the updates
}
} ) ;
}
} else if ( * key = = property : : CHANNEL_FLAG_DEFAULT ) {
old_default_channel = channel_tree - > getDefaultChannel ( ) ;
if ( old_default_channel = = channel ) {
old_default_channel = nullptr ;
continue ;
}
if ( ! cmd [ key - > name ] . as < bool > ( ) ) {
old_default_channel = nullptr ;
continue ;
}
channel_tree - > setDefaultChannel ( channel ) ;
deque < shared_ptr < BasicChannel > > updated_channels ;
shared_ptr < BasicChannel > current_channel = channel ;
do {
if ( current_channel - > channelType ( ) = = ChannelType : : permanent )
break ;
current_channel - > setChannelType ( ChannelType : : permanent ) ;
if ( current_channel ! = channel )
updated_channels . push_back ( channel ) ;
} while ( ( current_channel = current_channel - > parent ( ) ) ) ;
if ( this - > server & & ! updated_channels . empty ( ) ) {
std : : reverse ( updated_channels . begin ( ) , updated_channels . end ( ) ) ;
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & client ) {
unique_lock client_channel_lock ( client - > channel_lock ) ;
for ( const auto & channel : updated_channels ) {
client - > notifyChannelEdited ( channel , { " channel_flag_permanent " , " channel_flag_semi_permanent " } , this ) ;
}
} ) ;
}
} else if ( * key = = property : : CHANNEL_FLAG_PERMANENT | | * key = = property : : CHANNEL_FLAG_SEMI_PERMANENT ) {
if ( target_channel_type_changed ) { /* must be true else the key would not appere here */
target_channel_type_changed = false ; /* we only need to check all subchannels once! */
{ /* check channel children */
deque < shared_ptr < BasicChannel > > channel_to_test = { channel } ;
while ( ! channel_to_test . empty ( ) ) {
auto current_channel = channel_to_test . front ( ) ;
channel_to_test . pop_front ( ) ;
for ( const auto & child : channel_tree - > channels ( current_channel , 1 ) ) {
if ( child = = current_channel )
continue ;
if ( child - > channelType ( ) < target_channel_type ) {
child - > setChannelType ( target_channel_type ) ;
channel_to_test . push_back ( child ) ;
child_channel_updated . push_back ( child ) ;
}
}
}
}
}
2019-07-21 17:02:32 +02:00
} else if ( * key = = property : : CHANNEL_CONVERSATION_HISTORY_LENGTH ) {
//channel_conversation_history_length
auto conversation_manager = this - > server - > conversation_manager ( ) ;
if ( conversation_manager ) {
auto conversation = conversation_manager - > get ( channel - > channelId ( ) ) ;
if ( conversation )
conversation - > set_history_length ( cmd [ key - > name ] ) ;
}
2019-07-17 19:37:18 +02:00
}
channel - > properties ( ) [ key ] = cmd [ key - > name ] . string ( ) ;
}
if ( this - > server ) {
vector < string > key_vector ;
key_vector . reserve ( keys . size ( ) ) ;
for ( const auto & key : keys )
key_vector . push_back ( key - > name ) ;
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & client ) {
unique_lock client_channel_lock ( client - > channel_lock ) ;
for ( const auto & channel : child_channel_updated )
client - > notifyChannelEdited ( channel , { " channel_flag_permanent " , " channel_flag_semi_permanent " } , this ) ;
client - > notifyChannelEdited ( channel , key_vector , this ) ;
if ( old_default_channel ) /* clients need to have one or more defualt channels... */
client - > notifyChannelEdited ( old_default_channel , { " channel_flag_default " } , this ) ;
} ) ;
}
if ( server_channel_w_lock . owns_lock ( ) )
server_channel_w_lock . unlock ( ) ;
if ( ! channel_tree_read_lock . owns_lock ( ) )
channel_tree_read_lock . lock ( ) ;
if ( update_clients_in_channel & & this - > server ) {
for ( const auto & client : this - > server - > getClientsByChannel ( channel ) )
client - > updateChannelClientProperties ( true , true ) ; //TODO: May only update the talk power and not all?
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelMove ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
RESOLVE_CHANNEL_W ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
if ( channel - > deleted )
return { findError ( " channel_is_deleted " ) , " target channel has been deleted " } ;
if ( ! cmd [ 0 ] . has ( " order " ) )
cmd [ " order " ] = 0 ;
auto l_parent = channel_tree - > findLinkedChannel ( cmd [ " cpid " ] ) ;
shared_ptr < TreeView : : LinkedTreeEntry > l_order ;
if ( cmd [ 0 ] . has ( " order " ) ) {
l_order = channel_tree - > findLinkedChannel ( cmd [ " order " ] ) ;
if ( ! l_order & & cmd [ " order " ] . as < ChannelId > ( ) ! = 0 ) return { findError ( " channel_invalid_id " ) , " Cant resolve order channel " } ;
} else {
l_order = l_parent ? l_parent - > child_head : ( this - > server ? this - > server - > getChannelTree ( ) : serverInstance - > getChannelTree ( ) . get ( ) ) - > tree_head ( ) ;
while ( l_order & & l_order - > next )
l_order = l_order - > next ;
}
auto parent = l_parent ? dynamic_pointer_cast < ServerChannel > ( l_parent - > entry ) : nullptr ;
auto order = l_order ? dynamic_pointer_cast < ServerChannel > ( l_order - > entry ) : nullptr ;
if ( ( parent & & parent - > deleted ) | | ( order & & order - > deleted ) )
return { findError ( " channel_is_deleted " ) , " parent channel order previous channel has been deleted " } ;
if ( channel - > parent ( ) = = parent & & channel - > channelOrder ( ) = = ( order ? order - > channelId ( ) : 0 ) )
return CommandResult : : Success ;
if ( channel - > parent ( ) ! = parent )
PERM_CHECK_CHANNELR ( permission : : b_channel_modify_parent , 1 , channel , true ) ;
if ( ( order ? order - > channelId ( ) : 0 ) ! = channel - > channelOrder ( ) )
PERM_CHECK_CHANNELR ( permission : : b_channel_modify_sortorder , 1 , channel , true ) ;
{
auto min_channel_deep = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_channel_min_depth , nullptr , nullptr ) ;
auto max_channel_deep = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_channel_max_depth , nullptr , nullptr ) ;
if ( min_channel_deep > = 0 | | max_channel_deep > = 0 ) {
auto channel_deep = 0 ;
auto local_parent = l_parent ;
while ( local_parent ) {
channel_deep + + ;
local_parent = local_parent - > parent . lock ( ) ;
}
if ( min_channel_deep > = 0 & & channel_deep < min_channel_deep ) return CommandResultPermissionError { permission : : i_channel_min_depth } ;
if ( max_channel_deep > = 0 & & channel_deep > max_channel_deep ) return CommandResultPermissionError { permission : : i_channel_max_depth } ;
}
}
{
auto name = channel_tree - > findChannel ( channel - > name ( ) , parent ) ;
if ( name & & name ! = channel ) return { findError ( " channel_invalid_name " ) , " Channel with this name already exists " } ;
}
debugMessage ( this - > getServerId ( ) , " Moving channel {} from old [{} | {}] to [{} | {}] " , channel - > name ( ) , channel - > channelOrder ( ) , channel - > parent ( ) ? channel - > parent ( ) - > channelId ( ) : 0 , order ? order - > channelId ( ) : 0 , parent ? parent - > channelId ( ) : 0 ) ;
if ( ! channel_tree - > move_channel ( channel , parent , order ) ) return { findError ( " channel_invalid_order " ) , " Cant change order id " } ;
deque < shared_ptr < BasicChannel > > channel_type_updates ;
{
auto flag_default = channel - > defaultChannel ( ) ;
auto current_channel = channel ;
do {
if ( flag_default ) {
if ( current_channel - > channelType ( ) ! = ChannelType : : permanent ) {
current_channel - > setChannelType ( ChannelType : : permanent ) ;
channel_type_updates . push_front ( current_channel ) ;
}
} else if ( current_channel - > hasParent ( ) ) {
if ( current_channel - > channelType ( ) < current_channel - > parent ( ) - > channelType ( ) ) {
current_channel - > setChannelType ( current_channel - > parent ( ) - > channelType ( ) ) ;
channel_type_updates . push_front ( current_channel ) ;
}
}
} while ( ( current_channel = dynamic_pointer_cast < ServerChannel > ( current_channel - > parent ( ) ) ) ) ;
}
if ( this - > server ) {
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & client ) {
unique_lock channel_lock ( client - > channel_lock ) ;
for ( const auto & type_update : channel_type_updates )
client - > notifyChannelEdited ( type_update , { " channel_flag_permanent " , " channel_flag_semi_permanent " } , this ) ;
auto actions = client - > channels - > change_order ( l_channel , l_parent , l_order ) ;
std : : deque < ChannelId > deletions ;
for ( const auto & action : actions ) {
switch ( action . first ) {
case ClientChannelView : : NOTHING :
continue ;
case ClientChannelView : : ENTER_VIEW :
client - > notifyChannelShow ( action . second - > channel ( ) , action . second - > previous_channel ) ;
break ;
case ClientChannelView : : DELETE_VIEW :
deletions . push_back ( action . second - > channelId ( ) ) ;
break ;
case ClientChannelView : : MOVE :
client - > notifyChannelMoved ( action . second - > channel ( ) , action . second - > previous_channel , _this . lock ( ) ) ;
break ;
case ClientChannelView : : REORDER :
client - > notifyChannelEdited ( action . second - > channel ( ) , vector < string > { " channel_order " } , _this . lock ( ) . get ( ) ) ;
break ;
}
}
if ( ! deletions . empty ( ) )
client - > notifyChannelHide ( deletions , false ) ;
} ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientPoke ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto client = this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) ;
if ( ! client ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
if ( client - > getType ( ) = = CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) , " You cant poke a music bot! " } ;
2019-07-21 12:32:29 +02:00
CACHED_PERM_CHECK ( permission : : i_client_poke_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_needed_poke_power , client - > currentChannel ) , false ) ;
2019-07-17 19:37:18 +02:00
client - > notifyClientPoke ( _this . lock ( ) , cmd [ " msg " ] ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelPermList ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < BasicChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
CHANNEL_PERM_TEST_INIT ;
CHANNEL_PERM_TEST ( permission : : b_virtualserver_channel_permission_list , 1 , true ) ;
if ( this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK & & this - > command_times . last_notify + this - > command_times . notify_timeout < system_clock : : now ( ) ) {
this - > sendTSPermEditorWarning ( ) ;
}
auto sids = cmd . hasParm ( " permsid " ) ;
Command result ( this - > notify_response_command ( " notifychannelpermlist " ) ) ;
int index = 0 ;
result [ " cid " ] = channel - > channelId ( ) ;
auto permission_manager = channel - > permissions ( ) ;
for ( const auto & permission_data : permission_manager - > permissions ( ) ) {
auto & permission = std : : get < 1 > ( permission_data ) ;
if ( permission . flags . value_set ) {
if ( sids ) {
result [ index ] [ " permsid " ] = permission : : resolvePermissionData ( std : : get < 0 > ( permission_data ) ) - > name ;
} else {
result [ index ] [ " permid " ] = std : : get < 0 > ( permission_data ) ;
}
result [ index ] [ " permvalue " ] = permission . values . value ;
result [ index ] [ " permnegated " ] = permission . flags . negate ;
result [ index ] [ " permskip " ] = permission . flags . skip ;
index + + ;
}
if ( permission . flags . grant_set ) {
if ( sids ) {
result [ index ] [ " permsid " ] = permission : : resolvePermissionData ( std : : get < 0 > ( permission_data ) ) - > grant_name ;
} else {
result [ index ] [ " permid " ] = ( uint16_t ) ( std : : get < 0 > ( permission_data ) | PERM_ID_GRANT ) ;
}
result [ index ] [ " permvalue " ] = permission . values . grant ;
result [ index ] [ " permnegated " ] = 0 ;
result [ index ] [ " permskip " ] = 0 ;
index + + ;
}
}
if ( index = = 0 )
return { ErrorType : : DBEmpty } ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
//
//channel_icon_id=18446744073297259750
//channel_name
//channel_topic
//Desctiption has no extra parm
CommandResult ConnectedClient : : handleCommandChannelAddPerm ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < BasicChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
CHANNEL_PERMISSION_TEST ( permission : : i_channel_permission_modify_power , permission : : i_channel_needed_permission_modify_power , channel , true ) ;
auto maxValue = this - > getPermissionGrantValue ( permission : : PERMTEST_ORDERED , permission : : i_permission_modify_power , channel ) ;
bool ignoreGrant = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_permission_modify_power_ignore , 1 , channel ) ;
auto updateClients = false , update_view = false , update_channel_properties = false ;
CommandResult command_result = CommandResult : : Success ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto permission_manager = channel - > permissions ( ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & val > maxValue ) {
command_result = CommandResultPermissionError { permission : : i_permission_modify_power } ;
break ;
}
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , channel ) ) {
command_result = CommandResultPermissionError { permission : : i_permission_modify_power } ;
break ;
}
if ( grant ) {
permission_manager - > set_permission ( permType , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : set_value ) ;
} else {
permission_manager - > set_permission (
permType ,
{ cmd [ index ] [ " permvalue " ] , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing ,
2019-07-19 22:55:03 +02:00
cmd [ index ] [ " permskip " ] . as < bool > ( ) ? 1 : 0 ,
cmd [ index ] [ " permnegated " ] . as < bool > ( ) ? 1 : 0
2019-07-17 19:37:18 +02:00
) ;
updateClients | = permission_is_client_property ( permType ) ;
update_view | = permType = = permission : : i_channel_needed_view_power ;
update_channel_properties | = channel - > permission_require_property_update ( permType ) ;
if ( permType = = permission : : i_icon_id ) {
if ( this - > server )
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
shared_lock client_channel_lock ( cl - > channel_lock ) ;
cl - > notifyChannelEdited ( channel , { " channel_icon_id " } , this ) ;
} ) ;
continue ;
}
}
}
/* broadcast the updated channel properties */
if ( update_channel_properties ) {
auto updates = channel - > update_properties_from_permissions ( ) ;
if ( ! updates . empty ( ) & & this - > server ) {
vector < string > keys ;
keys . reserve ( updates . size ( ) ) ;
for ( auto & property : updates )
keys . push_back ( property : : info ( property ) - > name ) ;
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
shared_lock client_channel_lock ( cl - > channel_lock ) ;
cl - > notifyChannelEdited ( channel , keys , this ) ;
} ) ;
}
}
if ( updateClients & & this - > server )
for ( const auto & client : this - > server - > getClientsByChannel ( channel ) ) {
/* let them lock the server channel tree as well (read lock so does not matter) */
client - > updateChannelClientProperties ( true , true ) ;
2019-07-23 10:37:56 +02:00
client - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
2019-07-17 19:37:18 +02:00
}
2019-07-23 10:37:56 +02:00
if ( update_view & & this - > server ) {
auto l_source = this - > server - > channelTree - > findLinkedChannel ( channel - > channelId ( ) ) ;
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & cl ) {
/* server tree read lock still active */
auto l_target = ! cl - > currentChannel ? nullptr : cl - > server - > channelTree - > findLinkedChannel ( cl - > currentChannel - > channelId ( ) ) ;
sassert ( l_source ) ;
if ( cl - > currentChannel ) sassert ( l_target ) ;
{
unique_lock client_channel_lock ( cl - > channel_lock ) ;
deque < ChannelId > deleted ;
for ( const auto & update_entry : cl - > channels - > update_channel ( l_source , l_target ) ) {
if ( update_entry . first )
cl - > notifyChannelShow ( update_entry . second - > channel ( ) , update_entry . second - > previous_channel ) ;
else deleted . push_back ( update_entry . second - > channelId ( ) ) ;
}
if ( ! deleted . empty ( ) )
cl - > notifyChannelHide ( deleted , false ) ;
}
} ) ;
}
2019-07-17 19:37:18 +02:00
return command_result ;
}
CommandResult ConnectedClient : : handleCommandChannelDelPerm ( Command & cmd ) {
CMD_RESET_IDLE ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true )
auto channel = dynamic_pointer_cast < BasicChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
CHANNEL_PERMISSION_TEST ( permission : : i_channel_permission_modify_power , permission : : i_channel_needed_permission_modify_power , channel , true ) ;
bool ignoreGrant = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_permission_modify_power_ignore , 1 , channel ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto updateClients = false , update_view = false , update_channel_properties = false ;
auto permission_manager = channel - > permissions ( ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , channel ) )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( grant ) {
permission_manager - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : delete_value ) ;
} else {
permission_manager - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : PermissionUpdateType : : delete_value , permission : : v2 : : PermissionUpdateType : : do_nothing ) ;
updateClients | = permission_is_client_property ( permType ) ;
update_view | = permType = = permission : : i_channel_needed_view_power ;
update_channel_properties | = channel - > permission_require_property_update ( permType ) ;
}
}
/* broadcast the updated channel properties */
if ( update_channel_properties ) {
auto updates = channel - > update_properties_from_permissions ( ) ;
if ( ! updates . empty ( ) & & this - > server ) {
vector < string > keys ;
keys . reserve ( updates . size ( ) ) ;
for ( auto & property : updates )
keys . push_back ( property : : info ( property ) - > name ) ;
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
shared_lock client_channel_lock ( cl - > channel_lock ) ;
cl - > notifyChannelEdited ( channel , keys , this ) ;
} ) ;
}
}
if ( updateClients & & this - > server )
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
2019-07-23 10:37:56 +02:00
if ( cl - > currentChannel = = channel ) {
2019-07-17 19:37:18 +02:00
cl - > updateChannelClientProperties ( true , true ) ;
2019-07-23 10:37:56 +02:00
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
2019-07-17 19:37:18 +02:00
} ) ;
if ( update_view & & this - > server ) {
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
/* server tree read lock still active */
auto l_source = cl - > server - > channelTree - > findLinkedChannel ( channel - > channelId ( ) ) ;
auto l_target = ! cl - > currentChannel ? nullptr : cl - > server - > channelTree - > findLinkedChannel ( cl - > currentChannel - > channelId ( ) ) ;
sassert ( l_source ) ;
if ( cl - > currentChannel ) sassert ( l_target ) ;
{
unique_lock client_channel_lock ( cl - > channel_lock ) ;
deque < ChannelId > deleted ;
for ( const auto & update_entry : cl - > channels - > update_channel ( l_source , l_target ) ) {
if ( update_entry . first )
cl - > notifyChannelShow ( update_entry . second - > channel ( ) , update_entry . second - > previous_channel ) ;
else deleted . push_back ( update_entry . second - > channelId ( ) ) ;
}
if ( ! deleted . empty ( ) )
cl - > notifyChannelHide ( deleted , false ) ;
}
} ) ;
}
return CommandResult : : Success ;
}
//servergroupadd name=TestGroup type=1
CommandResult ConnectedClient : : handleCommandServerGroupAdd ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_servergroup_create , 1 , true ) ;
if ( cmd [ " name " ] . string ( ) . empty ( ) ) return { findError ( " parameter_invalid " ) , " invalid group name " } ;
if ( cmd [ " type " ] . as < GroupType > ( ) = = GroupType : : GROUP_TYPE_QUERY ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_querygroup ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_querygroup } ;
} else if ( cmd [ " type " ] . as < GroupType > ( ) = = GroupType : : GROUP_TYPE_TEMPLATE ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_templates ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_templates } ;
} else if ( ! this - > server ) return { findError ( " parameter_invalid " ) , " you cant create normal groups on the template server! " } ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
for ( const auto & gr : group_manager - > availableServerGroups ( true ) )
if ( gr - > name ( ) = = cmd [ " name " ] . string ( ) & & gr - > target ( ) = = GroupTarget : : GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " Group already exists " } ;
auto group = group_manager - > createGroup ( GroupTarget : : GROUPTARGET_SERVER , cmd [ " type " ] . as < GroupType > ( ) , cmd [ " name " ] . string ( ) ) ;
if ( group ) {
group - > permissions ( ) - > set_permission ( permission : : b_group_is_permanent , { 1 , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
if ( this - > server )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyServerGroupList ( ) ;
} ) ;
} else return { ErrorType : : VSError , " Could not create group " } ;
return CommandResult : : Success ;
}
//name=Server\sAdmin\s(Copy) ssgid=1 tsgid=0 type=1
CommandResult ConnectedClient : : handleCommandServerGroupCopy ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_servergroup_create , 1 , true ) ;
auto group_manager = this - > server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ;
bool global = false ;
auto src = group_manager - > findGroup ( cmd [ " ssgid " ] . as < GroupId > ( ) ) ;
if ( ! src | | src - > target ( ) ! = GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
if ( cmd [ 0 ] . has ( " tsgid " ) & & cmd [ " tsgid " ] . as < GroupId > ( ) ! = 0 ) {
auto target = group_manager - > findGroup ( cmd [ " tsgid " ] . as < GroupId > ( ) ) ;
if ( ! target | | target - > target ( ) ! = GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " invalid target server group id " } ;
auto result = group_manager - > copyGroupPermissions ( src , target ) ;
if ( ! result ) return { findError ( " vs_critical " ) , " could not copy group! " } ;
global = ! this - > server | | group_manager - > isLocalGroup ( target ) ;
} else {
//GroupType
auto type = cmd [ " type " ] . as < GroupType > ( ) ;
if ( type = = GroupType : : GROUP_TYPE_NORMAL & & ! this - > server ) return { findError ( " parameter_invalid " ) , " You cant create normal groups on the template server! " } ;
if ( type = = GroupType : : GROUP_TYPE_QUERY ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_querygroup ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_querygroup } ;
} else if ( type = = GroupType : : GROUP_TYPE_TEMPLATE ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_templates ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_templates } ;
}
auto result = group_manager - > copyGroup ( src , type , cmd [ " name " ] , type ! = GroupType : : GROUP_TYPE_NORMAL ? 0 : this - > getServerId ( ) ) ; //TODO maybe check by name? No duplicated groups?
if ( ! result ) return { findError ( " vs_critical " ) , " could not copy group! " } ;
global = ! this - > server | | type ! = GroupType : : GROUP_TYPE_NORMAL ;
if ( this - > getType ( ) = = ClientType : : CLIENT_QUERY ) {
Command notify ( " " ) ;
notify [ " sgid " ] = group_manager - > availableServerGroups ( false ) . back ( ) - > groupId ( ) ;
this - > sendCommand ( notify ) ;
}
}
for ( const auto & server : ( global ? serverInstance - > getVoiceServerManager ( ) - > serverInstances ( ) : deque < shared_ptr < TSServer > > { this - > server } ) )
if ( server )
server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyServerGroupList ( ) ;
} ) ;
return CommandResult : : Success ;
}
//servergrouprename sgid=2 name=Operators
CommandResult ConnectedClient : : handleCommandServerGroupRename ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto serverGroup = group_manager - > findGroup ( cmd [ " sgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup | | serverGroup - > target ( ) ! = GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
GROUP_PERMISSION_TEST ( permission : : i_server_group_modify_power , permission : : i_server_group_needed_modify_power , serverGroup , true ) ;
auto type = serverGroup - > type ( ) ;
if ( type = = GroupType : : GROUP_TYPE_QUERY ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_querygroup ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_querygroup } ;
} else if ( type = = GroupType : : GROUP_TYPE_TEMPLATE ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_templates ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_templates } ;
}
group_manager - > renameGroup ( serverGroup , cmd [ " name " ] . string ( ) ) ;
if ( this - > server )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyServerGroupList ( ) ;
} ) ;
return CommandResult : : Success ;
}
//servergroupdel sgid=2 force=0
CommandResult ConnectedClient : : handleCommandServerGroupDel ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_servergroup_delete , 1 , true ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto serverGroup = group_manager - > findGroup ( cmd [ " sgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup | | serverGroup - > target ( ) ! = GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
if ( this - > server & & this - > server - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_SERVER_GROUP ] = = serverGroup - > groupId ( ) )
return { findError ( " parameter_invalid " ) , " Could not delete default server group! " } ;
if ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_SERVERADMIN_GROUP ] = = serverGroup - > groupId ( ) )
return { findError ( " parameter_invalid " ) , " Could not delete instance default server admin group! " } ;
if ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_SERVERDEFAULT_GROUP ] = = serverGroup - > groupId ( ) )
return { findError ( " parameter_invalid " ) , " Could not delete instance default server group! " } ;
if ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_GUEST_SERVERQUERY_GROUP ] = = serverGroup - > groupId ( ) )
return { findError ( " parameter_invalid " ) , " Could not delete instance default guest server query group! " } ;
auto type = serverGroup - > type ( ) ;
if ( type = = GroupType : : GROUP_TYPE_QUERY ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_querygroup ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_querygroup } ;
} else if ( type = = GroupType : : GROUP_TYPE_TEMPLATE ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_templates ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_templates } ;
}
if ( ! cmd [ " force " ] . as < bool > ( ) )
if ( ! group_manager - > listGroupMembers ( serverGroup , false ) . empty ( ) )
return { findError ( " database_empty_result " ) , " group not empty! " } ;
if ( group_manager - > deleteGroup ( serverGroup ) ) {
if ( this - > server )
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > cl ) {
if ( this - > server - > notifyClientPropertyUpdates ( cl , this - > server - > groups - > update_server_group_property ( cl , true ) ) ) {
if ( cl - > update_cached_permissions ( ) ) /* update cached calculated permissions */
cl - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
}
cl - > notifyServerGroupList ( ) ;
} ) ;
}
return CommandResult : : Success ;
}
//servergroupclientlist sgid=2
//notifyservergroupclientlist sgid=6 cldbid=2 client_nickname=WolverinDEV client_unique_identifier=xxjnc14LmvTk+Lyrm8OOeo4tOqw=
CommandResult ConnectedClient : : handleCommandServerGroupClientList ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_servergroup_client_list , 1 , true ) ;
auto server = cmd [ 0 ] . has ( " sid " ) & & cmd [ " sid " ] = = 0 ? nullptr : this - > server ;
auto groupManager = server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ;
auto serverGroup = groupManager - > findGroup ( cmd [ " sgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup | | serverGroup - > target ( ) ! = GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
Command notify ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyservergroupclientlist " : " " ) ;
notify [ " sgid " ] = cmd [ " sgid " ] . as < GroupId > ( ) ;
int index = 0 ;
for ( const auto & clientEntry : groupManager - > listGroupMembers ( serverGroup ) ) {
notify [ index ] [ " cldbid " ] = clientEntry - > cldbId ;
notify [ index ] [ " client_nickname " ] = clientEntry - > displayName ;
notify [ index ] [ " client_unique_identifier " ] = clientEntry - > uid ;
index + + ;
}
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerGroupAddClient ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto server = cmd [ 0 ] . has ( " sid " ) & & cmd [ " sid " ] = = 0 ? nullptr : this - > server ;
auto groupManager = server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ;
auto serverGroup = groupManager - > findGroup ( cmd [ " sgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
if ( ( server ! = this - > server | | ! this - > server ) & & serverGroup - > target ( ) ! = GroupTarget : : GROUPTARGET_SERVER & & serverGroup - > type ( ) ! = GroupType : : GROUP_TYPE_QUERY ) return { findError ( " parameter_invalid " ) , " invalid group type " } ;
auto target_cldbid = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
{
if ( ! serverGroup - > permission_granted ( permission : : i_server_group_needed_member_add_power , this - > calculate_permission_value ( permission : : i_server_group_member_add_power , - 1 ) , true ) ) {
if ( target_cldbid ! = this - > getClientDatabaseId ( ) )
return CommandResultPermissionError { permission : : i_server_group_member_add_power } ;
if ( ! serverGroup - > permission_granted ( permission : : i_server_group_needed_member_add_power , this - > calculate_permission_value ( permission : : i_server_group_self_add_power , - 1 ) , true ) )
return CommandResultPermissionError { permission : : i_server_group_self_add_power } ;
}
auto needed_client_permission = this - > server - > calculatePermission ( permission : : PERMTEST_ORDERED , target_cldbid , permission : : i_client_needed_permission_modify_power , ClientType : : CLIENT_TEAMSPEAK , nullptr ) ;
if ( needed_client_permission ! = permNotGranted ) {
if ( ! this - > permission_granted ( this - > permissionValue ( permission : : i_client_permission_modify_power ) , needed_client_permission ) )
return CommandResultPermissionError { permission : : i_client_needed_permission_modify_power } ;
}
}
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( server , cmd [ " cldbid " ] ) ) return { findError ( " client_invalid_id " ) , " invalid cldbid " } ;
if ( groupManager - > hasServerGroupAssigned ( cmd [ " cldbid " ] , serverGroup ) ) return { findError ( " parameter_invalid " ) , " Client is already member of this group " } ;
groupManager - > addServerGroup ( target_cldbid , serverGroup ) ;
for ( const auto & _server : server ? std : : deque < shared_ptr < TSServer > > { server } : serverInstance - > getVoiceServerManager ( ) - > serverInstances ( ) ) {
for ( const auto & targetClient : _server - > findClientsByCldbId ( target_cldbid ) ) {
if ( _server - > notifyClientPropertyUpdates ( targetClient , _server - > groups - > update_server_group_property ( targetClient , true ) ) ) {
for ( const auto & client : _server - > getClients ( ) ) {
if ( client - > isClientVisible ( targetClient , true ) | | client = = targetClient )
client - > notifyServerGroupClientAdd ( _this . lock ( ) , targetClient , serverGroup ) ;
}
if ( targetClient - > update_cached_permissions ( ) ) /* update cached calculated permissions */
targetClient - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
targetClient - > updateChannelClientProperties ( true , true ) ;
}
}
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerGroupDelClient ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto server = cmd [ 0 ] . has ( " sid " ) & & cmd [ " sid " ] = = 0 ? nullptr : this - > server ;
auto groupManager = server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ;
auto serverGroup = groupManager - > findGroup ( cmd [ " sgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
if ( ( server ! = this - > server | | ! this - > server ) & & serverGroup - > target ( ) ! = GroupTarget : : GROUPTARGET_SERVER & & serverGroup - > type ( ) ! = GroupType : : GROUP_TYPE_QUERY ) return { findError ( " parameter_invalid " ) , " invalid group type " } ;
auto target_cldbid = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
{
if ( ! serverGroup - > permission_granted ( permission : : i_server_group_needed_member_remove_power , this - > calculate_permission_value ( permission : : i_server_group_member_remove_power , - 1 ) , true ) ) {
if ( target_cldbid ! = this - > getClientDatabaseId ( ) )
return CommandResultPermissionError { permission : : i_server_group_member_remove_power } ;
if ( ! serverGroup - > permission_granted ( permission : : i_server_group_needed_member_remove_power , this - > calculate_permission_value ( permission : : i_server_group_self_remove_power , - 1 ) , true ) )
return CommandResultPermissionError { permission : : i_server_group_self_remove_power } ;
}
auto needed_client_permission = this - > server - > calculatePermission ( permission : : PERMTEST_ORDERED , target_cldbid , permission : : i_client_needed_permission_modify_power , ClientType : : CLIENT_TEAMSPEAK , nullptr ) ;
if ( needed_client_permission ! = permNotGranted ) {
if ( ! this - > permission_granted ( this - > permissionValue ( permission : : i_client_permission_modify_power ) , needed_client_permission ) )
return CommandResultPermissionError { permission : : i_client_needed_permission_modify_power } ;
}
}
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( server , cmd [ " cldbid " ] ) ) return { findError ( " client_invalid_id " ) , " invalid cldbid " } ;
if ( ! groupManager - > hasServerGroupAssigned ( cmd [ " cldbid " ] , serverGroup ) ) return { findError ( " parameter_invalid " ) , " Client isn't a member of this group " } ;
for ( const auto & assignment : groupManager - > listGroupAssignments ( cmd [ " cldbid " ] ) )
if ( assignment - > group = = serverGroup & & assignment - > server ! = this - > getServerId ( ) ) return { findError ( " parameter_invalid " ) , " Group wasn't assigned over this server (Assigned server: " + to_string ( assignment - > server ) + " ) " } ;
groupManager - > removeServerGroup ( target_cldbid , serverGroup ) ;
for ( const auto & _server : server ? std : : deque < shared_ptr < TSServer > > { server } : serverInstance - > getVoiceServerManager ( ) - > serverInstances ( ) ) {
for ( const auto & targetClient : _server - > findClientsByCldbId ( target_cldbid ) ) {
if ( _server - > notifyClientPropertyUpdates ( targetClient , _server - > groups - > update_server_group_property ( targetClient , true ) ) ) {
for ( const auto & client : _server - > getClients ( ) ) {
if ( client - > isClientVisible ( targetClient , true ) | | client = = targetClient )
client - > notifyServerGroupClientRemove ( _this . lock ( ) , targetClient , serverGroup ) ;
}
if ( targetClient - > update_cached_permissions ( ) ) /* update cached calculated permissions */
targetClient - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
targetClient - > updateChannelClientProperties ( true , true ) ;
}
}
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerGroupPermList ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_servergroup_permission_list , 1 , true ) ;
auto serverGroup = ( this - > server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ) - > findGroup ( cmd [ " sgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
if ( this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK & & this - > command_times . last_notify + this - > command_times . notify_timeout < system_clock : : now ( ) ) {
this - > sendTSPermEditorWarning ( ) ;
}
if ( ! this - > notifyGroupPermList ( serverGroup , cmd . hasParm ( " permsid " ) ) ) return { findError ( " database_empty_result " ) , " empty " } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerGroupAddPerm ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto serverGroup = ( this - > server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ) - > findGroup ( cmd [ " sgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
if ( serverGroup - > target ( ) ! = GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " invalid group type " } ;
GROUP_PERMISSION_TEST ( permission : : i_server_group_modify_power , permission : : i_server_group_needed_modify_power , serverGroup , true ) ;
auto type = serverGroup - > type ( ) ;
if ( type = = GroupType : : GROUP_TYPE_QUERY ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_querygroup ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_querygroup } ;
} else if ( type = = GroupType : : GROUP_TYPE_TEMPLATE ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_templates ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_templates } ;
}
auto maxValue = this - > getPermissionGrantValue ( permission : : PERMTEST_ORDERED , permission : : i_permission_modify_power , this - > currentChannel ) ;
bool ignoreGrant = this - > permission_granted ( this - > cached_permission_value ( permission : : b_permission_modify_power_ignore ) , 1 ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
bool checkTp = false ;
bool sgroupUpdate = false ;
auto permissions = serverGroup - > permissions ( ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
//permvalue='1' permnegated='0' permskip='0'
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & val > maxValue ) {
if ( conOnError ) continue ;
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
}
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) ) {
if ( conOnError ) continue ;
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
}
if ( grant ) {
permissions - > set_permission ( permType , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : set_value ) ;
} else {
permissions - > set_permission (
permType ,
{ cmd [ index ] [ " permvalue " ] , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing ,
2019-07-19 22:55:03 +02:00
cmd [ index ] [ " permskip " ] . as < bool > ( ) ? 1 : 0 ,
cmd [ index ] [ " permnegated " ] . as < bool > ( ) ? 1 : 0
2019-07-17 19:37:18 +02:00
) ;
sgroupUpdate | = permission_is_group_property ( permType ) ;
checkTp | = permission_is_client_property ( permType ) ;
}
}
if ( sgroupUpdate )
serverGroup - > apply_properties_from_permissions ( ) ;
//TODO may update for every server?
if ( this - > server ) {
auto lock = this - > _this . lock ( ) ;
auto server = this - > server ;
threads : : Thread ( [ checkTp , sgroupUpdate , serverGroup , lock , server ] ( ) {
if ( sgroupUpdate )
server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyServerGroupList ( ) ;
} ) ;
server - > forEachClient ( [ serverGroup , checkTp ] ( shared_ptr < ConnectedClient > cl ) {
if ( cl - > serverGroupAssigned ( serverGroup ) ) {
if ( cl - > update_cached_permissions ( ) ) /* update cached calculated permissions */
cl - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
if ( checkTp )
cl - > updateChannelClientProperties ( true , true ) ;
2019-07-23 10:37:56 +02:00
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
2019-07-17 19:37:18 +02:00
}
} ) ;
} ) . detach ( ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerGroupDelPerm ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto serverGroup = ( this - > server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ) - > findGroup ( cmd [ " sgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
if ( serverGroup - > target ( ) ! = GROUPTARGET_SERVER ) return { findError ( " parameter_invalid " ) , " invalid group type " } ;
GROUP_PERMISSION_TEST ( permission : : i_server_group_modify_power , permission : : i_server_group_needed_modify_power , serverGroup , true ) ;
auto type = serverGroup - > type ( ) ;
if ( type = = GroupType : : GROUP_TYPE_QUERY ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_querygroup ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_querygroup } ;
} else if ( type = = GroupType : : GROUP_TYPE_TEMPLATE ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_templates ) , 1 , true ) )
return CommandResultPermissionError { permission : : b_serverinstance_modify_templates } ;
}
bool ignoreGrant = this - > permission_granted ( this - > cached_permission_value ( permission : : b_permission_modify_power_ignore ) , 1 ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
bool checkTp = false ;
auto sgroupUpdate = false ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) ) {
if ( conOnError ) continue ;
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
}
if ( grant ) {
serverGroup - > permissions ( ) - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : delete_value ) ;
} else {
serverGroup - > permissions ( ) - > set_permission (
permType ,
permission : : v2 : : empty_permission_values ,
permission : : v2 : : PermissionUpdateType : : delete_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing
) ;
sgroupUpdate | = permission_is_group_property ( permType ) ;
checkTp | = permission_is_client_property ( permType ) ;
}
}
if ( sgroupUpdate )
serverGroup - > apply_properties_from_permissions ( ) ;
if ( this - > server ) {
auto lock = this - > _this . lock ( ) ;
auto server = this - > server ;
threads : : Thread ( [ checkTp , sgroupUpdate , serverGroup , lock , server ] ( ) {
if ( sgroupUpdate )
server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyServerGroupList ( ) ;
} ) ;
server - > forEachClient ( [ serverGroup , checkTp ] ( shared_ptr < ConnectedClient > cl ) {
if ( cl - > serverGroupAssigned ( serverGroup ) ) {
if ( cl - > update_cached_permissions ( ) ) /* update cached calculated permissions */
cl - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
if ( checkTp )
cl - > updateChannelClientProperties ( true , true ) ;
2019-07-23 10:37:56 +02:00
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
2019-07-17 19:37:18 +02:00
}
} ) ;
} ) . detach ( ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerGroupAutoAddPerm ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
deque < shared_ptr < Group > > groups ;
for ( const auto & group : this - > server - > groups - > availableGroups ( false ) ) {
if ( group - > updateType ( ) = = cmd [ " sgtype " ] . as < permission : : PermissionValue > ( ) & & group - > target ( ) = = GROUPTARGET_SERVER ) {
if ( group - > permission_granted ( permission : : i_server_group_needed_modify_power , this - > calculate_permission_value ( permission : : i_server_group_modify_power , 0 ) , true ) ) {
auto type = group - > type ( ) ;
if ( type = = GroupType : : GROUP_TYPE_QUERY ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_querygroup ) , 1 , true ) )
continue ;
} else if ( type = = GroupType : : GROUP_TYPE_TEMPLATE ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_templates ) , 1 , true ) )
continue ;
}
groups . push_back ( group ) ; //sgtype
}
}
}
if ( groups . empty ( ) )
return CommandResult : : Success ;
auto maxValue = this - > getPermissionGrantValue ( permission : : PERMTEST_ORDERED , permission : : i_permission_modify_power , this - > currentChannel ) ;
bool ignoreGrant = this - > permission_granted ( this - > cached_permission_value ( permission : : b_permission_modify_power_ignore ) , 1 ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
bool checkTp = false ;
bool sgroupUpdate = false ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
//permvalue='1' permnegated='0' permskip='0'end
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & val > maxValue ) {
if ( conOnError ) continue ;
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
}
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) ) {
if ( conOnError ) continue ;
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
}
for ( const auto & serverGroup : groups ) {
if ( grant ) {
serverGroup - > permissions ( ) - > set_permission ( permType , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : set_value ) ;
} else {
serverGroup - > permissions ( ) - > set_permission (
permType ,
{ cmd [ index ] [ " permvalue " ] , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing ,
cmd [ index ] [ " permnegated " ] . as < bool > ( ) ? 1 : 0 ,
cmd [ index ] [ " permskip " ] . as < bool > ( ) ? 1 : 0
) ;
}
}
sgroupUpdate | = permission_is_group_property ( permType ) ;
checkTp | = permission_is_client_property ( permType ) ;
}
if ( sgroupUpdate )
for ( auto & group : groups )
group - > apply_properties_from_permissions ( ) ;
auto lock = this - > _this . lock ( ) ;
auto server = this - > server ;
threads : : Thread ( [ checkTp , sgroupUpdate , groups , lock , server ] ( ) {
if ( sgroupUpdate )
server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyServerGroupList ( ) ;
} ) ;
server - > forEachClient ( [ groups , checkTp ] ( shared_ptr < ConnectedClient > cl ) {
for ( const auto & serverGroup : groups ) {
if ( cl - > serverGroupAssigned ( serverGroup ) ) {
2019-07-23 10:37:56 +02:00
if ( cl - > update_cached_permissions ( ) ) { /* update cached calculated permissions */
2019-07-17 19:37:18 +02:00
cl - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
2019-07-23 10:37:56 +02:00
}
if ( checkTp ) {
cl - > updateChannelClientProperties ( true , true ) ;
}
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate if needed */
2019-07-17 19:37:18 +02:00
break ;
}
}
} ) ;
} ) . detach ( ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerGroupAutoDelPerm ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
deque < shared_ptr < Group > > groups ;
for ( const auto & group : this - > server - > groups - > availableGroups ( false ) ) {
if ( group - > updateType ( ) = = cmd [ " sgtype " ] . as < permission : : PermissionValue > ( ) & & group - > target ( ) = = GROUPTARGET_SERVER ) {
if ( group - > permission_granted ( permission : : i_server_group_needed_modify_power , this - > calculate_permission_value ( permission : : i_server_group_modify_power , 0 ) , true ) ) {
auto type = group - > type ( ) ;
if ( type = = GroupType : : GROUP_TYPE_QUERY ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_querygroup ) , 1 , true ) )
continue ;
} else if ( type = = GroupType : : GROUP_TYPE_TEMPLATE ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_serverinstance_modify_templates ) , 1 , true ) )
continue ;
}
groups . push_back ( group ) ; //sgtype
}
}
}
if ( groups . empty ( ) ) return CommandResult : : Success ;
bool ignoreGrant = this - > permission_granted ( this - > cached_permission_value ( permission : : b_permission_modify_power_ignore ) , 1 ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
bool checkTp = false ;
auto sgroupUpdate = false ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) ) {
if ( conOnError ) continue ;
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
}
for ( const auto & serverGroup : groups ) {
if ( grant ) {
serverGroup - > permissions ( ) - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : delete_value ) ;
} else {
serverGroup - > permissions ( ) - > set_permission (
permType ,
permission : : v2 : : empty_permission_values ,
permission : : v2 : : PermissionUpdateType : : delete_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing
) ;
sgroupUpdate | = permission_is_group_property ( permType ) ;
}
}
checkTp | = permission_is_client_property ( permType ) ;
}
if ( sgroupUpdate )
for ( auto & group : groups )
group - > apply_properties_from_permissions ( ) ;
auto lock = this - > _this . lock ( ) ;
auto server = this - > server ;
threads : : Thread ( [ checkTp , sgroupUpdate , groups , lock , server ] ( ) {
if ( sgroupUpdate )
server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyServerGroupList ( ) ;
} ) ;
server - > forEachClient ( [ groups , checkTp ] ( shared_ptr < ConnectedClient > cl ) {
for ( const auto & serverGroup : groups ) {
if ( cl - > serverGroupAssigned ( serverGroup ) ) {
if ( cl - > update_cached_permissions ( ) ) /* update cached calculated permissions */
cl - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
if ( checkTp )
cl - > updateChannelClientProperties ( true , true ) ;
2019-07-23 10:37:56 +02:00
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
2019-07-17 19:37:18 +02:00
break ;
}
}
} ) ;
} ) . detach ( ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandSetClientChannelGroup ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto serverGroup = this - > server - > groups - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! serverGroup & & cmd [ " gcid " ] . as < GroupId > ( ) = = 0 )
serverGroup = this - > server - > groups - > defaultGroup ( GroupTarget : : GROUPTARGET_CHANNEL ) ;
if ( ! serverGroup | | serverGroup - > target ( ) ! = GROUPTARGET_CHANNEL )
return { findError ( " parameter_invalid " ) , " invalid channel group id " } ;
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ; /* ensure we dont get moved or somebody could move us */
std : : shared_ptr < BasicChannel > channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
auto target_cldbid = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
{
if ( ! serverGroup - > permission_granted ( permission : : i_channel_group_member_add_power , this - > calculate_permission_value ( permission : : i_channel_group_member_add_power , - 1 ) , true ) ) {
if ( target_cldbid ! = this - > getClientDatabaseId ( ) )
return CommandResultPermissionError { permission : : i_channel_group_member_add_power } ;
if ( ! serverGroup - > permission_granted ( permission : : i_channel_group_member_add_power , this - > calculate_permission_value ( permission : : i_channel_group_self_add_power , - 1 ) , true ) )
return CommandResultPermissionError { permission : : i_channel_group_self_add_power } ;
}
auto needed_client_permission = this - > server - > calculatePermission ( permission : : PERMTEST_ORDERED , target_cldbid , permission : : i_client_needed_permission_modify_power , ClientType : : CLIENT_TEAMSPEAK , nullptr ) ;
if ( needed_client_permission ! = permNotGranted ) {
if ( ! this - > permission_granted ( this - > permissionValue ( permission : : i_client_permission_modify_power ) , needed_client_permission ) )
return CommandResultPermissionError { permission : : i_client_needed_permission_modify_power } ;
}
}
auto oldGroup = this - > server - > groups - > getChannelGroupExact ( target_cldbid , channel , false ) ;
if ( oldGroup ) {
if ( ! serverGroup - > permission_granted ( permission : : i_channel_group_member_remove_power , this - > calculate_permission_value ( permission : : i_channel_group_member_remove_power , - 1 ) , true ) ) {
if ( target_cldbid ! = this - > getClientDatabaseId ( ) )
return CommandResultPermissionError { permission : : i_channel_group_member_remove_power } ;
if ( ! serverGroup - > permission_granted ( permission : : i_channel_group_member_remove_power , this - > calculate_permission_value ( permission : : i_channel_group_self_remove_power , - 1 ) , true ) )
return CommandResultPermissionError { permission : : i_channel_group_self_remove_power } ;
}
}
this - > server - > groups - > setChannelGroup ( target_cldbid , serverGroup , channel ) ;
for ( const auto & targetClient : this - > server - > findClientsByCldbId ( target_cldbid ) ) {
unique_lock client_channel_lock_w ( targetClient - > channel_lock ) ;
auto updates = this - > server - > groups - > update_server_group_property ( targetClient , false ) ; /* needs a write lock */
client_channel_lock_w . unlock ( ) ;
shared_lock client_channel_lock_r ( targetClient - > channel_lock ) ;
auto result = this - > server - > notifyClientPropertyUpdates ( targetClient , updates ) ;
if ( result ) {
if ( targetClient - > update_cached_permissions ( ) ) /* update cached calculated permissions */
targetClient - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
if ( targetClient - > properties ( ) [ property : : CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID ] = = channel - > channelId ( ) ) { //Only if group assigned over the channel
for ( const auto & viewer : this - > server - > getClients ( ) ) {
/* if in view will be tested within that method */
shared_lock viewer_channel_lock ( viewer - > channel_lock , defer_lock ) ;
if ( viewer ! = targetClient )
viewer_channel_lock . lock ( ) ;
viewer - > notifyClientChannelGroupChanged ( _this . lock ( ) , targetClient , targetClient - > getChannel ( ) , channel , serverGroup , false ) ;
}
}
}
targetClient - > updateChannelClientProperties ( false , true ) ;
}
return CommandResult : : Success ;
}
//sendtextmessage targetmode=1 <1 = direct | 2 = channel | 3 = server> msg=asd target=1 <clid>
CommandResult ConnectedClient : : handleCommandSendTextMessage ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
if ( cmd [ " targetmode " ] . as < ChatMessageMode > ( ) = = ChatMessageMode : : TEXTMODE_PRIVATE ) {
auto target = this - > server - > findClient ( cmd [ " target " ] . as < ClientId > ( ) ) ;
if ( ! target ) return { findError ( " client_invalid_id " ) , " invalid target clid " } ;
bool chat_open = false ;
{
shared_lock channel_lock ( this - > channel_lock ) ;
this - > openChats . erase ( remove_if ( this - > openChats . begin ( ) , this - > openChats . end ( ) , [ ] ( const weak_ptr < ConnectedClient > & weak ) { return ! weak . lock ( ) ; } ) , this - > openChats . end ( ) ) ;
for ( const auto & entry : this - > openChats ) {
if ( entry . lock ( ) = = target ) {
chat_open = true ;
break ;
}
}
}
if ( ! chat_open ) {
if ( target = = this ) {
PERM_CHECK_CHANNELR ( permission : : b_client_even_textmessage_send , 1 , this - > currentChannel , true ) ;
}
PERM_CHECK_CHANNELR ( permission : : i_client_private_textmessage_power , target - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_needed_private_textmessage_power , target - > currentChannel ) , this - > currentChannel , false ) ;
{
unique_lock channel_lock ( target - > channel_lock ) ;
target - > openChats . push_back ( _this ) ;
}
{
unique_lock channel_lock ( this - > channel_lock ) ;
this - > openChats . push_back ( target ) ;
}
}
if ( this - > handleTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , cmd [ " msg " ] , target ) ) return CommandResult : : Success ;
2019-07-23 10:37:56 +02:00
target - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , _this . lock ( ) , target - > getClientId ( ) , 0 , cmd [ " msg " ] . string ( ) ) ;
this - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , _this . lock ( ) , target - > getClientId ( ) , 0 , cmd [ " msg " ] . string ( ) ) ;
2019-07-17 19:37:18 +02:00
} else if ( cmd [ " targetmode " ] = = ChatMessageMode : : TEXTMODE_CHANNEL ) {
CACHED_PERM_CHECK ( permission : : b_client_channel_textmessage_send , 1 , false ) ;
2019-07-23 10:37:56 +02:00
if ( ! cmd [ 0 ] . has ( " cid " ) )
cmd [ " cid " ] = 0 ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , false ) ;
auto channel = l_channel ? dynamic_pointer_cast < BasicChannel > ( l_channel - > entry ) : nullptr ;
if ( ! channel ) {
CMD_REQ_CHANNEL ;
channel = this - > currentChannel ;
channel_id = this - > currentChannel - > channelId ( ) ;
if ( this - > handleTextMessage ( ChatMessageMode : : TEXTMODE_CHANNEL , cmd [ " msg " ] , nullptr ) )
return CommandResult : : Success ;
}
2019-07-17 19:37:18 +02:00
2019-07-23 10:37:56 +02:00
auto message = cmd [ " msg " ] . string ( ) ;
auto _this = this - > _this . lock ( ) ;
auto client_id = this - > getClientId ( ) ;
auto flag_password = channel - > properties ( ) [ property : : CHANNEL_FLAG_PASSWORD ] . as < bool > ( ) ;
for ( const auto & client : this - > server - > getClients ( ) ) {
if ( client - > connectionState ( ) ! = ConnectionState : : CONNECTED )
continue ;
auto type = client - > getType ( ) ;
if ( type = = ClientType : : CLIENT_INTERNAL | | type = = ClientType : : CLIENT_MUSIC )
continue ;
auto own_channel = client - > currentChannel = = this - > currentChannel ;
if ( type ! = ClientType : : CLIENT_TEAMSPEAK | | own_channel ) {
if ( ! own_channel & & & * client ! = this ) {
if ( flag_password )
continue ; /* TODO: Send notification about new message. The client then could request messages via message history */
if ( ! client - > calculate_and_get_join_state ( channel ) )
continue ;
}
client - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_CHANNEL , _this , client_id , channel_id , message ) ;
}
}
2019-07-19 22:55:03 +02:00
auto conversations = this - > server - > conversation_manager ( ) ;
2019-07-23 10:37:56 +02:00
auto conversation = conversations - > get_or_create ( channel - > channelId ( ) ) ;
2019-07-19 22:55:03 +02:00
conversation - > register_message ( this - > getClientDatabaseId ( ) , this - > getUid ( ) , this - > getDisplayName ( ) , cmd [ " msg " ] . string ( ) ) ;
2019-07-17 19:37:18 +02:00
} else if ( cmd [ " targetmode " ] = = ChatMessageMode : : TEXTMODE_SERVER ) {
CACHED_PERM_CHECK ( permission : : b_client_server_textmessage_send , 1 ) ;
if ( this - > handleTextMessage ( ChatMessageMode : : TEXTMODE_SERVER , cmd [ " msg " ] , nullptr ) ) return CommandResult : : Success ;
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > client ) {
2019-07-23 10:37:56 +02:00
client - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_SERVER , _this . lock ( ) , this - > getClientId ( ) , 0 , cmd [ " msg " ] . string ( ) ) ;
2019-07-17 19:37:18 +02:00
} ) ;
} else return { findError ( " parameter_invalid " ) , " invalid target mode " } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientChatComposing ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 0 ) ;
auto client = this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) ;
if ( ! client ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
client - > notifyClientChatComposing ( _this . lock ( ) ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientChatClosed ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto client = this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) ;
if ( ! client ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
{
unique_lock channel_lock ( this - > channel_lock ) ;
this - > openChats . erase ( remove_if ( this - > openChats . begin ( ) , this - > openChats . end ( ) , [ client ] ( const weak_ptr < ConnectedClient > & weak ) {
return weak . lock ( ) = = client ;
} ) , this - > openChats . end ( ) ) ;
}
{
unique_lock channel_lock ( client - > channel_lock ) ;
client - > openChats . erase ( remove_if ( client - > openChats . begin ( ) , client - > openChats . end ( ) , [ & ] ( const weak_ptr < ConnectedClient > & weak ) {
return weak . lock ( ) . get ( ) = = this ;
} ) , client - > openChats . end ( ) ) ;
}
client - > notifyClientChatClosed ( _this . lock ( ) ) ;
return CommandResult : : Success ;
}
//ftgetfilelist cid=1 cpw path=\/ return_code=1:x
//Answer:
//1 .. n
// notifyfilelist cid=1 path=\/ return_code=1:x name=testFile size=35256 datetime=1509459767 type=1|name=testDir size=0 datetime=1509459741 type=0|name=testDir_2 size=0 datetime=1509459763 type=0
//notifyfilelistfinished cid=1 path=\/
inline void appendFileList ( Command & fileList , vector < std : : shared_ptr < file : : FileEntry > > files ) {
int index = 0 ;
for ( const auto & fileEntry : files ) {
debugMessage ( lstream < < " Having file " < < fileEntry - > path < < " / " < < fileEntry - > name < < " (Name: " < < fileEntry - > name < < " ) " < < endl ) ;
fileList [ index ] [ " name " ] = fileEntry - > name ;
fileList [ index ] [ " datetime " ] = std : : chrono : : duration_cast < std : : chrono : : seconds > ( fileEntry - > lastChanged . time_since_epoch ( ) ) . count ( ) ;
fileList [ index ] [ " type " ] = fileEntry - > type ;
if ( fileEntry - > type = = file : : FileType : : FILE )
fileList [ index ] [ " size " ] = static_pointer_cast < file : : File > ( fileEntry ) - > fileSize ;
else
fileList [ index ] [ " size " ] = 0 ;
index + + ;
}
}
# define CMD_REQ_FSERVER if(!serverInstance->getFileServer()) return {findError("vs_critical"), "file server not started yet!"}
CommandResult ConnectedClient : : handleCommandFTGetFileList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_REQ_FSERVER ;
std : : string code = cmd [ " return_code " ] . size ( ) > 0 ? cmd [ " return_code " ] . string ( ) : " " ;
Command fileList ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyfilelist " : " " ) ;
Command fileListFinished ( " notifyfilelistfinished " ) ;
fileList [ " path " ] = cmd [ " path " ] . as < std : : string > ( ) ;
fileList [ " return_code " ] = code ;
fileListFinished [ " path " ] = cmd [ " path " ] . as < std : : string > ( ) ;
fileList [ " cid " ] = cmd [ " cid " ] . as < size_t > ( ) ;
fileListFinished [ " cid " ] = cmd [ " cid " ] . as < size_t > ( ) ;
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] ! = 0 ) { //Channel
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_ft_ignore_password , 1 , channel , true ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? CommandResultPermissionError { permission : : b_ft_ignore_password } : CommandResult { findError ( " channel_invalid_password " ) } ;
CHANNEL_PERMISSION_TEST ( permission : : i_ft_file_browse_power , permission : : i_ft_needed_file_browse_power , channel , true ) ;
appendFileList ( fileList , serverInstance - > getFileServer ( ) - > listFiles ( serverInstance - > getFileServer ( ) - > resolveDirectory ( this - > server , channel , cmd [ " path " ] . as < std : : string > ( ) ) ) ) ;
} else {
if ( cmd [ " path " ] . as < string > ( ) = = " /icons " | | cmd [ " path " ] . as < string > ( ) = = " /icons/ " ) {
appendFileList ( fileList , serverInstance - > getFileServer ( ) - > listFiles ( serverInstance - > getFileServer ( ) - > iconDirectory ( this - > server ) ) ) ;
PERM_CHECKR ( permission : : b_icon_manage , 1 , true ) ;
} else if ( cmd [ " path " ] . as < string > ( ) = = " / " ) {
appendFileList ( fileList , serverInstance - > getFileServer ( ) - > listFiles ( serverInstance - > getFileServer ( ) - > avatarDirectory ( this - > server ) ) ) ;
PERM_CHECKR ( permission : : b_icon_manage , 1 , true ) ;
} else {
cerr < < " Unknown requested directory: ' " < < cmd [ " path " ] . as < std : : string > ( ) < < " ' " < < endl ;
return CommandResult : : NotImplemented ;
}
}
if ( fileList [ 0 ] . has ( " name " ) ) {
2019-07-21 14:56:53 +02:00
if ( dynamic_cast < VoiceClient * > ( this ) ) {
dynamic_cast < VoiceClient * > ( this ) - > sendCommand0 ( fileList , false , true ) ; /* We need to process this directly else the order could get shuffeled up! */
this - > sendCommand ( fileListFinished ) ;
} else {
this - > sendCommand ( fileList ) ;
}
2019-07-17 19:37:18 +02:00
return CommandResult : : Success ;
} else {
return { findError ( " database_empty_result " ) , " empty " } ;
}
}
//ftcreatedir cid=4 cpw dirname=\/TestDir return_code=1:17
CommandResult ConnectedClient : : handleCommandFTCreateDir ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CMD_REQ_FSERVER ;
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_ft_ignore_password , 1 , channel , true ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? CommandResultPermissionError { permission : : b_ft_ignore_password } : CommandResult { findError ( " channel_invalid_password " ) } ;
CHANNEL_PERMISSION_TEST ( permission : : i_ft_directory_create_power , permission : : i_ft_needed_directory_create_power , channel , true ) ;
auto dir = serverInstance - > getFileServer ( ) - > createDirectory ( cmd [ " dirname " ] , serverInstance - > getFileServer ( ) - > resolveDirectory ( this - > server , channel , cmd [ " path " ] . as < std : : string > ( ) ) ) ;
if ( ! dir ) return { findError ( " file_invalid_path " ) , " could not create dir " } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandFTDeleteFile ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CMD_REQ_FSERVER ;
std : : vector < std : : shared_ptr < file : : FileEntry > > files ;
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] ! = 0 ) { //Channel
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_ft_ignore_password , 1 , channel , true ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? CommandResultPermissionError { permission : : b_ft_ignore_password } : CommandResult { findError ( " channel_invalid_password " ) } ;
CHANNEL_PERMISSION_TEST ( permission : : i_ft_file_delete_power , permission : : i_ft_needed_file_delete_power , channel , true ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + )
files . push_back ( serverInstance - > getFileServer ( ) - > findFile ( cmd [ index ] [ " name " ] . as < std : : string > ( ) , serverInstance - > getFileServer ( ) - > resolveDirectory ( this - > server , channel ) ) ) ;
} else {
if ( cmd [ " name " ] . string ( ) . find ( " /icon_ " ) = = 0 & & cmd [ " path " ] . string ( ) . empty ( ) ) {
PERM_CHECKR ( permission : : b_icon_manage , 1 , true ) ;
files . push_back ( serverInstance - > getFileServer ( ) - > findFile ( cmd [ " name " ] . string ( ) , serverInstance - > getFileServer ( ) - > iconDirectory ( this - > server ) ) ) ;
} else if ( cmd [ " name " ] . string ( ) . find ( " /avatar_ " ) = = 0 & & cmd [ " path " ] . string ( ) . empty ( ) ) {
if ( cmd [ " name " ] . string ( ) ! = " /avatar_ " ) {
PERM_CHECKR ( permission : : b_client_avatar_delete_other , 1 , true ) ;
auto uid = cmd [ " name " ] . string ( ) . substr ( strlen ( " /avatar_ " ) ) ;
auto avId = hex : : hex ( base64 : : decode ( uid ) , ' a ' , ' q ' ) ;
auto cls = this - > server - > findClientsByUid ( uid ) ;
for ( const auto & cl : cls ) {
cl - > properties ( ) [ property : : CLIENT_FLAG_AVATAR ] = " " ;
this - > server - > notifyClientPropertyUpdates ( cl , deque < property : : ClientProperties > { property : : CLIENT_FLAG_AVATAR } ) ;
}
cmd [ " name " ] = " /avatar_ " + avId ;
} else {
cmd [ " name " ] = " /avatar_ " + this - > getAvatarId ( ) ;
this - > properties ( ) [ property : : CLIENT_FLAG_AVATAR ] = " " ;
this - > server - > notifyClientPropertyUpdates ( _this . lock ( ) , deque < property : : ClientProperties > { property : : CLIENT_FLAG_AVATAR } ) ;
}
files . push_back ( serverInstance - > getFileServer ( ) - > findFile ( cmd [ " name " ] . string ( ) , serverInstance - > getFileServer ( ) - > avatarDirectory ( this - > server ) ) ) ;
} else {
cerr < < " Unknown requested file to delete: " < < cmd [ " path " ] . as < std : : string > ( ) < < endl ;
return CommandResult : : NotImplemented ;
}
}
for ( const auto & file : files ) {
if ( ! file ) continue ;
if ( ! serverInstance - > getFileServer ( ) - > deleteFile ( file ) ) {
logCritical ( this - > getServerId ( ) , lstream < < " Cound not delete file " < < file - > path < < " / " < < file - > name ) ;
}
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandFTInitUpload ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_REQ_FSERVER ;
std : : shared_ptr < file : : Directory > directory = nullptr ;
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] ! = 0 ) { //Channel
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_ft_ignore_password , 1 , channel , true ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? CommandResultPermissionError { permission : : b_ft_ignore_password } : CommandResult { findError ( " channel_invalid_password " ) } ;
CHANNEL_PERMISSION_TEST ( permission : : i_ft_file_upload_power , permission : : i_ft_needed_file_upload_power , channel , true ) ;
directory = serverInstance - > getFileServer ( ) - > resolveDirectory ( this - > server , channel ) ;
} else {
if ( cmd [ " path " ] . as < std : : string > ( ) . empty ( ) & & cmd [ " name " ] . as < std : : string > ( ) . find ( " /icon_ " ) = = 0 ) {
auto max_size = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_max_icon_filesize , this - > currentChannel ) ;
if ( max_size ! = - 1 & & max_size < ( ssize_t ) cmd [ " size " ] . as < size_t > ( ) ) return CommandResultPermissionError { permission : : i_max_icon_filesize } ;
directory = serverInstance - > getFileServer ( ) - > iconDirectory ( this - > server ) ;
} else if ( cmd [ " path " ] . as < std : : string > ( ) . empty ( ) & & cmd [ " name " ] . string ( ) = = " /avatar " ) {
auto max_size = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_max_avatar_filesize , this - > currentChannel ) ;
if ( max_size ! = - 1 & & max_size < ( ssize_t ) cmd [ " size " ] . as < size_t > ( ) ) return CommandResultPermissionError { permission : : i_client_max_avatar_filesize } ;
directory = serverInstance - > getFileServer ( ) - > avatarDirectory ( this - > server ) ;
cmd [ " name " ] = " /avatar_ " + this - > getAvatarId ( ) ;
} else {
cerr < < " Unknown requested directory: " < < cmd [ " path " ] . as < std : : string > ( ) < < endl ;
return CommandResult : : NotImplemented ;
}
}
if ( ! directory | | directory - > type ! = file : : FileType : : DIRECTORY ) { //Should not happen
cerr < < " Invalid upload file path! " < < endl ;
return { findError ( " file_invalid_path " ) , " could not resolve directory " } ;
}
{
auto server_quota = this - > server - > properties ( ) [ property : : VIRTUALSERVER_UPLOAD_QUOTA ] . as < ssize_t > ( ) ;
auto server_used_quota = this - > server - > properties ( ) [ property : : VIRTUALSERVER_MONTH_BYTES_UPLOADED ] . as < size_t > ( ) ;
server_used_quota + = cmd [ " size " ] . as < uint64_t > ( ) ;
for ( const auto & trans : serverInstance - > getFileServer ( ) - > pending_file_transfers ( ) )
server_used_quota + = trans - > size ;
for ( const auto & trans : serverInstance - > getFileServer ( ) - > running_file_transfers ( ) )
server_used_quota + = trans - > remaining_bytes ( ) ;
if ( server_quota > = 0 & & server_quota * 1024 * 1024 < ( int64_t ) server_used_quota ) return { findError ( " file_transfer_server_quota_exceeded " ) } ;
auto client_quota = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_ft_quota_mb_upload_per_client , this - > currentChannel ) ;
auto client_used_quota = this - > properties ( ) [ property : : CLIENT_MONTH_BYTES_UPLOADED ] . as < size_t > ( ) ;
client_used_quota + = cmd [ " size " ] . as < uint64_t > ( ) ;
for ( const auto & trans : serverInstance - > getFileServer ( ) - > pending_file_transfers ( _this . lock ( ) ) )
client_used_quota + = trans - > size ;
for ( const auto & trans : serverInstance - > getFileServer ( ) - > running_file_transfers ( _this . lock ( ) ) )
client_used_quota + = trans - > remaining_bytes ( ) ;
if ( client_quota > = 0 & & client_quota * 1024 * 1024 < ( int64_t ) client_used_quota ) return { findError ( " file_transfer_client_quota_exceeded " ) } ;
}
if ( cmd [ " overwrite " ] . as < bool > ( ) & & cmd [ " resume " ] . as < bool > ( ) ) return { findError ( " file_overwrite_excludes_resume " ) , " funny " } ;
if ( serverInstance - > getFileServer ( ) - > findFile ( cmd [ " name " ] . as < std : : string > ( ) , directory ) & & ! ( cmd [ " overwrite " ] . as < bool > ( ) | | cmd [ " resume " ] . as < bool > ( ) ) )
return { findError ( " file_already_exists " ) , " file already exists " } ;
//Request: clientftfid=1 serverftfid=6 ftkey=itRNdsIOvcBiBg\/Xj4Ge51ZSrsShHuid port=30033 seekpos=0
//Reqpose: notifystartupload clientftfid=4079 serverftfid=1 ftkey=aX9CFQbfaddHpOYxhQiSLu\/BumfVtPyP port=30033 seekpos=0 proto=1
string error = " success " ;
auto key = serverInstance - > getFileServer ( ) - > generateUploadTransferKey ( error , directory - > path + " / " + directory - > name + cmd [ " name " ] . string ( ) , cmd [ " size " ] . as < uint64_t > ( ) , 0 , _this . lock ( ) ) ; //TODO implement resume!
if ( ! key ) return { findError ( " " ) , " cant generate key " } ; //TODO insert error!
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifystartupload " : " " ) ;
result [ " clientftfid " ] = cmd [ " clientftfid " ] . as < uint64_t > ( ) ;
result [ " ftkey " ] = key - > key ;
2019-07-21 10:43:26 +02:00
auto bindings = serverInstance - > getFileServer ( ) - > list_bindings ( ) ;
if ( ! bindings . empty ( ) ) {
result [ " port " ] = net : : port ( bindings [ 0 ] - > address ) ;
string ip = " " ;
for ( auto & entry : bindings ) {
if ( net : : is_anybind ( entry - > address ) ) {
ip = " " ;
break ;
}
ip + = net : : to_string ( entry - > address , false ) + " , " ;
}
if ( ! ip . empty ( ) )
result [ " ip " ] = ip ;
} else {
return { findError ( " server_is_not_running " ) , " file server is not bound to any address " } ;
}
2019-07-17 19:37:18 +02:00
result [ " seekpos " ] = 0 ;
result [ " proto " ] = 1 ;
result [ " serverftfid " ] = key - > key_id ; //TODO generate!
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandFTInitDownload ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_REQ_FSERVER ;
std : : shared_ptr < file : : Directory > directory = nullptr ;
if ( ! cmd [ 0 ] . has ( " path " ) ) cmd [ " path " ] = " " ;
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] ! = ( ChannelId ) 0 ) { //Channel
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
CHANNEL_PERMISSION_TEST ( permission : : i_ft_file_download_power , permission : : i_ft_needed_file_download_power , channel , true ) ;
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_ft_ignore_password , 1 , channel , true ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? CommandResultPermissionError { permission : : b_ft_ignore_password } : CommandResult { findError ( " channel_invalid_password " ) } ;
directory = serverInstance - > getFileServer ( ) - > resolveDirectory ( this - > server , channel ) ;
} else {
if ( cmd [ " path " ] . as < std : : string > ( ) . empty ( ) & & cmd [ " name " ] . as < std : : string > ( ) . find ( " /icon_ " ) = = 0 ) {
directory = serverInstance - > getFileServer ( ) - > iconDirectory ( this - > server ) ;
} else if ( cmd [ " path " ] . as < std : : string > ( ) . empty ( ) & & cmd [ " name " ] . as < std : : string > ( ) . find ( " /avatar_ " ) = = 0 ) { //TODO fix avatar download not working
directory = serverInstance - > getFileServer ( ) - > avatarDirectory ( this - > server ) ;
} else {
cerr < < " Unknown requested directory: " < < cmd [ " path " ] . as < std : : string > ( ) < < endl ;
return CommandResult : : NotImplemented ;
}
}
if ( ! directory | | directory - > type ! = file : : FileType : : DIRECTORY ) { //Should not happen
cerr < < " Invalid download file path! " < < endl ;
return { findError ( " file_invalid_path " ) , " could not resolve directory " } ;
}
if ( ! serverInstance - > getFileServer ( ) - > findFile ( cmd [ " name " ] . as < std : : string > ( ) , directory ) )
return { findError ( " file_not_found " ) , " file not exists " } ;
string error = " success " ;
auto key = serverInstance - > getFileServer ( ) - > generateDownloadTransferKey ( error , directory - > path + " / " + directory - > name + cmd [ " name " ] . as < std : : string > ( ) , 0 , _this . lock ( ) ) ; //TODO implement resume!
if ( ! key ) return { findError ( " vs_critical " ) , " cant generate key ( " + error + " ) " } ;
{
auto server_quota = this - > server - > properties ( ) [ property : : VIRTUALSERVER_DOWNLOAD_QUOTA ] . as < ssize_t > ( ) ;
auto server_used_quota = this - > server - > properties ( ) [ property : : VIRTUALSERVER_MONTH_BYTES_DOWNLOADED ] . as < size_t > ( ) ;
server_used_quota + = key - > size ;
for ( const auto & trans : serverInstance - > getFileServer ( ) - > pending_file_transfers ( ) )
server_used_quota + = trans - > size ;
for ( const auto & trans : serverInstance - > getFileServer ( ) - > running_file_transfers ( ) )
server_used_quota + = trans - > remaining_bytes ( ) ;
if ( server_quota > = 0 & & server_quota * 1024 * 1024 < ( int64_t ) server_used_quota ) return { findError ( " file_transfer_server_quota_exceeded " ) } ;
auto client_quota = this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_ft_quota_mb_download_per_client , this - > currentChannel ) ;
auto client_used_quota = this - > properties ( ) [ property : : CLIENT_MONTH_BYTES_DOWNLOADED ] . as < size_t > ( ) ;
client_used_quota + = key - > size ;
for ( const auto & trans : serverInstance - > getFileServer ( ) - > pending_file_transfers ( _this . lock ( ) ) )
client_used_quota + = trans - > size ;
for ( const auto & trans : serverInstance - > getFileServer ( ) - > running_file_transfers ( _this . lock ( ) ) )
client_used_quota + = trans - > remaining_bytes ( ) ;
if ( client_quota > = 0 & & client_quota * 1024 * 1024 < ( int64_t ) client_used_quota ) return { findError ( " file_transfer_client_quota_exceeded " ) } ;
}
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifystartdownload " : " " ) ;
result [ " clientftfid " ] = cmd [ " clientftfid " ] . as < uint64_t > ( ) ;
result [ " proto " ] = 1 ;
result [ " serverftfid " ] = key - > key_id ;
result [ " ftkey " ] = key - > key ;
2019-07-21 10:43:26 +02:00
auto bindings = serverInstance - > getFileServer ( ) - > list_bindings ( ) ;
if ( ! bindings . empty ( ) ) {
result [ " port " ] = net : : port ( bindings [ 0 ] - > address ) ;
string ip = " " ;
for ( auto & entry : bindings ) {
if ( net : : is_anybind ( entry - > address ) ) {
ip = " " ;
break ;
}
ip + = net : : to_string ( entry - > address , false ) + " , " ;
}
if ( ! ip . empty ( ) )
result [ " ip " ] = ip ;
} else {
return { findError ( " server_is_not_running " ) , " file server is not bound to any address " } ;
}
2019-07-17 19:37:18 +02:00
result [ " size " ] = key - > size ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
/*
* Usage : ftgetfileinfo cid = { channelID } cpw = { channelPassword } name = { filePath } . . .
Permissions :
i_ft_file_browse_power
i_ft_needed_file_browse_power
Description :
Displays detailed information about one or more specified files stored in a
channels file repository .
Example :
ftgetfileinfo cid = 2 cpw = path = \ / Pic1 . PNG | cid = 2 cpw = path = \ / Pic2 . PNG
cid = 2 path = \ / name = Stuff size = 0 datetime = 1259415210 type = 0 | name = Pic1 . PNG size = 563783 datetime = 1259425462 type = 1 | name = Pic2 . PNG . . .
error id = 0 msg = ok
*/
CommandResult ConnectedClient : : handleCommandFTGetFileInfo ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
CMD_REQ_FSERVER ;
CMD_RESET_IDLE ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyfileinfo " : " " ) ;
int result_index = 0 ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto & request = cmd [ index ] ;
std : : shared_ptr < file : : FileEntry > file ;
if ( request . has ( " cid " ) & & request [ " cid " ] . as < ChannelId > ( ) ! = 0 ) { //Channel
auto channel = this - > server - > channelTree - > findChannel ( request [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_ft_ignore_password , 1 , channel , true ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? CommandResultPermissionError { permission : : b_ft_ignore_password } : CommandResult { findError ( " channel_invalid_password " ) , " " } ;
CHANNEL_PERMISSION_TEST ( permission : : i_ft_file_browse_power , permission : : i_ft_needed_file_browse_power , channel , true ) ;
file = serverInstance - > getFileServer ( ) - > findFile ( request [ " name " ] , serverInstance - > getFileServer ( ) - > resolveDirectory ( this - > server , channel , request [ " path " ] ) ) ;
} else {
std : : shared_ptr < file : : Directory > directory ;
if ( ! request . has ( " path " ) | | request [ " path " ] . as < string > ( ) = = " / " ) {
directory = serverInstance - > getFileServer ( ) - > avatarDirectory ( this - > server ) ;
} else if ( request [ " path " ] . as < string > ( ) = = " /icons " | | request [ " path " ] . as < string > ( ) = = " /icons/ " ) {
directory = serverInstance - > getFileServer ( ) - > iconDirectory ( this - > server ) ;
} else {
cerr < < " Unknown requested directory: ' " < < request [ " path " ] . as < std : : string > ( ) < < " ' " < < endl ;
return CommandResult : : NotImplemented ;
}
if ( ! directory ) continue ;
file = serverInstance - > getFileServer ( ) - > findFile ( cmd [ " name " ] . as < std : : string > ( ) , directory ) ;
}
if ( ! file ) continue ;
result [ result_index ] [ " cid " ] = request [ " cid " ] . as < ChannelId > ( ) ;
result [ result_index ] [ " name " ] = request [ " name " ] ;
result [ result_index ] [ " path " ] = request [ " path " ] ;
result [ result_index ] [ " type " ] = file - > type ;
result [ result_index ] [ " datetime " ] = duration_cast < seconds > ( file - > lastChanged . time_since_epoch ( ) ) . count ( ) ;
if ( file - > type = = file : : FileType : : FILE )
result [ result_index ] [ " size " ] = static_pointer_cast < file : : File > ( file ) - > fileSize ;
else
result [ result_index ] [ " size " ] = 0 ;
result_index + + ;
}
if ( result_index = = 0 )
return { findError ( " database_empty_result " ) } ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
//notifybanlist banid=3 ip name uid=zbex8X3bFRTIKLI7mzeyJGZsh64= lastnickname=Wolf\sC++\sXXXX created=1510357269 duration=3600 invokername=WolverinDEV invokercldbid=5 invokeruid=xxjnc14LmvTk+Lyrm8OOeo4tOqw= reason=Prefix\sFake\s\p\sName enforcements=3
CommandResult ConnectedClient : : handleCommandBanList ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ServerId sid = this - > getServerId ( ) ;
if ( cmd [ 0 ] . has ( " sid " ) )
sid = cmd [ " sid " ] ;
if ( sid = = 0 ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_ban_list_global ) , 1 ) )
return CommandResultPermissionError { permission : : b_client_ban_list_global } ;
} else {
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( sid ) ;
if ( ! server ) return { findError ( " parameter_invalid " ) , " " } ;
if ( server - > calculatePermission ( permission : : PERMTEST_ORDERED , this - > getClientDatabaseId ( ) , permission : : b_client_ban_list , this - > getType ( ) , nullptr ) ! = 1 )
return CommandResultPermissionError { permission : : b_client_ban_list } ;
}
//When empty: return {findError("database_empty_result"), "empty"};
auto banList = serverInstance - > banManager ( ) - > listBans ( sid ) ;
if ( banList . empty ( ) ) return { findError ( " database_empty_result " ) } ;
auto allow_ip = this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_remoteaddress_view ) , 1 ) ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifybanlist " : " " ) ;
int index = 0 ;
for ( const auto & elm : banList ) {
notify [ index ] [ " sid " ] = elm - > serverId ;
notify [ index ] [ " banid " ] = elm - > banId ;
if ( allow_ip )
notify [ index ] [ " ip " ] = elm - > ip ;
else
notify [ index ] [ " ip " ] = " hidden " ;
notify [ index ] [ " name " ] = elm - > name ;
notify [ index ] [ " uid " ] = elm - > uid ;
notify [ index ] [ " hwid " ] = elm - > hwid ;
notify [ index ] [ " lastnickname " ] = elm - > name ; //Maybe update?
notify [ index ] [ " created " ] = chrono : : duration_cast < chrono : : seconds > ( elm - > created . time_since_epoch ( ) ) . count ( ) ;
if ( elm - > until . time_since_epoch ( ) . count ( ) ! = 0 )
notify [ index ] [ " duration " ] = chrono : : duration_cast < chrono : : seconds > ( elm - > until - elm - > created ) . count ( ) ;
else
notify [ index ] [ " duration " ] = 0 ;
notify [ index ] [ " reason " ] = elm - > reason ;
notify [ index ] [ " enforcements " ] = elm - > triggered ;
notify [ index ] [ " invokername " ] = elm - > invokerName ;
notify [ index ] [ " invokercldbid " ] = elm - > invokerDbId ;
notify [ index ] [ " invokeruid " ] = elm - > invokerUid ;
index + + ;
}
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandBanAdd ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
string ip = cmd [ 0 ] . has ( " ip " ) ? cmd [ " ip " ] . string ( ) : " " ;
string name = cmd [ 0 ] . has ( " name " ) ? cmd [ " name " ] . string ( ) : " " ;
string uid = cmd [ 0 ] . has ( " uid " ) ? cmd [ " uid " ] . string ( ) : " " ;
string hwid = cmd [ 0 ] . has ( " hwid " ) ? cmd [ " hwid " ] . string ( ) : " " ;
string banreason = cmd [ 0 ] . has ( " banreason " ) ? cmd [ " banreason " ] . string ( ) : " No reason set " ;
auto time = cmd [ 0 ] . has ( " time " ) ? cmd [ " time " ] . as < int64_t > ( ) : 0L ;
ServerId sid = this - > getServerId ( ) ;
if ( cmd [ 0 ] . has ( " sid " ) )
sid = cmd [ " sid " ] ;
if ( sid = = 0 ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_ban_create_global ) , 1 ) )
return CommandResultPermissionError { permission : : b_client_ban_create_global } ;
} else {
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( sid ) ;
if ( ! server ) return { findError ( " parameter_invalid " ) , " " } ;
if ( server - > calculatePermission ( permission : : PERMTEST_ORDERED , this - > getClientDatabaseId ( ) , permission : : b_client_ban_create , this - > getType ( ) , nullptr ) ! = 1 )
return CommandResultPermissionError { permission : : b_client_ban_create_global } ;
}
auto max_ban_time = this - > cached_permission_value ( permission : : i_client_ban_max_bantime ) ;
if ( max_ban_time ! = permNotGranted ) {
if ( max_ban_time ! = - 1 & & max_ban_time < time )
return CommandResultPermissionError ( permission : : i_client_ban_max_bantime ) ;
}
chrono : : time_point < chrono : : system_clock > until = time > 0 ? chrono : : system_clock : : now ( ) + chrono : : seconds ( time ) : chrono : : time_point < chrono : : system_clock > ( ) ;
auto existing = serverInstance - > banManager ( ) - > findBanExact ( sid , banreason , uid , ip , name , hwid ) ;
bool banned = false ;
if ( existing ) {
if ( existing - > invokerDbId = = this - > getClientDatabaseId ( ) ) {
if ( existing - > until = = until ) return { findError ( " database_duplicate_entry " ) } ;
else {
existing - > until = until ;
serverInstance - > banManager ( ) - > updateBan ( existing ) ;
banned = true ;
}
} else if ( ! banned ) {
serverInstance - > banManager ( ) - > unban ( existing ) ;
}
}
if ( ! banned ) serverInstance - > banManager ( ) - > registerBan ( sid , this - > getClientDatabaseId ( ) , banreason , uid , ip , name , hwid , until ) ;
for ( auto server : ( this - > server ? std : : deque < shared_ptr < TSServer > > { this - > server } : serverInstance - > getVoiceServerManager ( ) - > serverInstances ( ) ) )
server - > testBanStateChange ( _this . lock ( ) ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandBanEdit ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ServerId sid = this - > getServerId ( ) ;
if ( cmd [ 0 ] . has ( " sid " ) )
sid = cmd [ " sid " ] ;
auto ban = serverInstance - > banManager ( ) - > findBanById ( sid , cmd [ " banid " ] . as < uint64_t > ( ) ) ;
if ( ! ban ) return { findError ( " database_empty_result " ) , " empty " } ;
if ( sid = = 0 ) {
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_ban_edit_global ) , 1 ) )
return CommandResultPermissionError { permission : : b_client_ban_edit_global } ;
} else {
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( sid ) ;
if ( ! server ) return { findError ( " parameter_invalid " ) , " " } ;
if ( server - > calculatePermission ( permission : : PERMTEST_ORDERED , this - > getClientDatabaseId ( ) , permission : : b_client_ban_edit , this - > getType ( ) , nullptr ) ! = 1 ) return CommandResultPermissionError { permission : : b_client_ban_edit } ;
}
/* ip name uid reason time hwid */
bool changed = false ;
if ( cmd [ 0 ] . has ( " ip " ) ) {
ban - > ip = cmd [ " ip " ] . as < string > ( ) ;
changed | = true ;
}
if ( cmd [ 0 ] . has ( " name " ) ) {
ban - > name = cmd [ " name " ] . as < string > ( ) ;
changed | = true ;
}
if ( cmd [ 0 ] . has ( " uid " ) ) {
ban - > uid = cmd [ " uid " ] . as < string > ( ) ;
changed | = true ;
}
if ( cmd [ 0 ] . has ( " reason " ) ) {
ban - > reason = cmd [ " reason " ] . as < string > ( ) ;
changed | = true ;
}
if ( cmd [ 0 ] . has ( " banreason " ) ) {
ban - > reason = cmd [ " banreason " ] . as < string > ( ) ;
changed | = true ;
}
if ( cmd [ 0 ] . has ( " time " ) ) {
ban - > until = ban - > created + seconds ( cmd [ " time " ] . as < size_t > ( ) ) ;
changed | = true ;
}
if ( cmd [ 0 ] . has ( " hwid " ) ) {
ban - > hwid = cmd [ " hwid " ] . as < string > ( ) ;
changed | = true ;
}
if ( changed )
serverInstance - > banManager ( ) - > updateBan ( ban ) ;
else return { findError ( " parameter_invalid " ) , " " } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandBanClient ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
PERM_CHECKR ( permission : : i_client_ban_power , 1 , true ) ; //Require a little ban power
string uid ;
string reason = cmd [ 0 ] . has ( " banreason " ) ? cmd [ " banreason " ] . string ( ) : " " ;
auto time = cmd [ 0 ] . has ( " time " ) ? cmd [ " time " ] . as < uint64_t > ( ) : 0UL ;
chrono : : time_point < chrono : : system_clock > until = time > 0 ? chrono : : system_clock : : now ( ) + chrono : : seconds ( time ) : chrono : : time_point < chrono : : system_clock > ( ) ;
const auto no_nickname = cmd . hasParm ( " no-nickname " ) ;
const auto no_hwid = cmd . hasParm ( " no-hardware-id " ) ;
const auto no_ip = cmd . hasParm ( " no-ip " ) ;
deque < shared_ptr < ConnectedClient > > target_clients ;
if ( cmd [ 0 ] . has ( " uid " ) ) {
target_clients = this - > server - > findClientsByUid ( uid = cmd [ " uid " ] . string ( ) ) ;
for ( const auto & client : target_clients )
if ( client - > getType ( ) = = ClientType : : CLIENT_MUSIC )
return { findError ( " client_invalid_id " ) , " You cant ban a music bot! " } ;
} else {
target_clients = { this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) } ;
if ( ! target_clients [ 0 ] ) {
return { findError ( " client_invalid_id " ) , " Could not find target client " } ;
}
if ( target_clients [ 0 ] - > getType ( ) = = ClientType : : CLIENT_MUSIC ) {
return { findError ( " client_invalid_id " ) , " You cant ban a music bot! " } ;
}
uid = target_clients [ 0 ] - > getUid ( ) ;
}
ClientDbId target_dbid = 0 ;
if ( ! target_clients . empty ( ) ) target_dbid = target_clients [ 0 ] - > getClientDatabaseId ( ) ;
else {
auto info = serverInstance - > databaseHelper ( ) - > queryDatabaseInfoByUid ( this - > getServer ( ) , { uid } ) ;
if ( ! info . empty ( ) )
target_dbid = info [ 0 ] - > cldbid ;
else
return { findError ( " client_unknown " ) } ;
}
if ( target_dbid ! = 0 ) {
if ( this - > server - > calculatePermission ( permission : : PERMTEST_ORDERED , target_dbid , permission : : i_client_needed_ban_power , ClientType : : CLIENT_TEAMSPEAK , nullptr ) > this - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_ban_power ) )
return CommandResultPermissionError ( permission : : i_client_ban_power ) ;
if ( this - > server - > calculatePermission ( permission : : PERMTEST_ORDERED , target_dbid , permission : : b_client_ignore_bans , ClientType : : CLIENT_TEAMSPEAK , nullptr ) > = 1 ) return CommandResultPermissionError ( permission : : b_client_ignore_bans ) ;
}
deque < BanId > ban_ids ;
auto _id = serverInstance - > banManager ( ) - > registerBan ( this - > getServer ( ) - > getServerId ( ) , this - > getClientDatabaseId ( ) , reason , uid , " " , " " , " " , until ) ;
ban_ids . push_back ( _id ) ;
auto b_ban_name = this - > cached_permission_value ( permission : : b_client_ban_name ) = = permNotGranted | | this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_ban_name ) , 1 , false ) ;
auto b_ban_ip = this - > cached_permission_value ( permission : : b_client_ban_ip ) = = permNotGranted | | this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_ban_ip ) , 1 , false ) ;
auto b_ban_hwid = this - > cached_permission_value ( permission : : b_client_ban_hwid ) = = permNotGranted | | this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_ban_hwid ) , 1 , false ) ;
auto max_value = this - > cached_permission_value ( permission : : i_client_ban_max_bantime ) ;
if ( max_value ! = permNotGranted & & max_value ! = - 1 ) {
if ( time > max_value ) return CommandResultPermissionError { permission : : i_client_ban_max_bantime } ;
if ( time = = 0 ) return CommandResultPermissionError { permission : : i_client_ban_max_bantime } ;
}
for ( const auto & client : target_clients ) {
if ( client - > getType ( ) ! = CLIENT_TEAMSPEAK & & client - > getType ( ) ! = CLIENT_QUERY ) continue ; //Remember if you add new type you have to change stuff here
this - > server - > notify_client_ban ( client , this - > ref ( ) , reason , time ) ;
client - > closeConnection ( system_clock : : now ( ) + seconds ( 2 ) ) ;
string entry_name , entry_ip , entry_hardware_id ;
if ( b_ban_name & & ! no_nickname ) {
entry_name = client - > getDisplayName ( ) ;
}
if ( b_ban_ip & & ! no_ip & & ! config : : server : : disable_ip_saving ) {
entry_ip = client - > getPeerIp ( ) ;
}
if ( b_ban_hwid & & ! no_hwid ) {
entry_hardware_id = client - > getHardwareId ( ) ;
}
auto exact = serverInstance - > banManager ( ) - > findBanExact ( this - > getServer ( ) - > getServerId ( ) , reason , " " , entry_ip , entry_name , entry_hardware_id ) ;
if ( exact ) {
exact - > until = until ;
exact - > invokerDbId = this - > getClientDatabaseId ( ) ;
serverInstance - > banManager ( ) - > updateBan ( exact ) ;
ban_ids . push_back ( exact - > banId ) ;
} else {
auto id = serverInstance - > banManager ( ) - > registerBan ( this - > getServer ( ) - > getServerId ( ) , this - > getClientDatabaseId ( ) , reason , " " , entry_ip , entry_name , entry_hardware_id , until ) ;
ban_ids . push_back ( id ) ;
}
}
this - > server - > testBanStateChange ( _this . lock ( ) ) ;
if ( this - > getType ( ) = = CLIENT_QUERY ) {
Command notify ( " " ) ;
int index = 0 ;
for ( const auto & ban_id : ban_ids )
notify [ index + + ] [ " banid " ] = ban_id ;
this - > sendCommand ( notify ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandBanDel ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ServerId sid = this - > getServerId ( ) ;
if ( cmd [ 0 ] . has ( " sid " ) )
sid = cmd [ " sid " ] ;
auto ban = serverInstance - > banManager ( ) - > findBanById ( sid , cmd [ " banid " ] . as < uint64_t > ( ) ) ;
if ( ! ban ) return { findError ( " database_empty_result " ) , " empty " } ;
if ( sid = = 0 ) {
const auto permission = ban - > invokerDbId = = this - > getClientDatabaseId ( ) ? permission : : b_client_ban_delete_own_global : permission : : b_client_ban_delete_global ;
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission ) , 1 ) )
return CommandResultPermissionError { permission } ;
} else {
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( sid ) ;
if ( ! server ) return { findError ( " parameter_invalid " ) , " " } ;
auto perm = ban - > invokerDbId = = this - > getClientDatabaseId ( ) ? permission : : b_client_ban_delete_own : permission : : b_client_ban_delete ;
if ( server - > calculatePermission ( permission : : PERMTEST_ORDERED , this - > getClientDatabaseId ( ) , perm , this - > getType ( ) , nullptr ) ! = 1 ) return CommandResultPermissionError { perm } ;
}
serverInstance - > banManager ( ) - > unban ( ban ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandBanDelAll ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
CACHED_PERM_CHECK ( permission : : b_client_ban_delete , 1 , true ) ;
serverInstance - > banManager ( ) - > deleteAllBans ( server - > getServerId ( ) ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandBanTriggerList ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
CACHED_PERM_CHECK ( permission : : b_client_ban_trigger_list , 1 , true ) ;
CMD_REQ_PARM ( " banid " ) ;
auto record = serverInstance - > banManager ( ) - > findBanById ( this - > getServerId ( ) , cmd [ " banid " ] ) ;
if ( ! record ) return { findError ( " parameter_invalid " ) , " Invalid ban id " } ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifybantriggerlist " : " " ) ;
notify [ " banid " ] = record - > banId ;
notify [ " serverid " ] = record - > serverId ;
auto allow_ip = this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_remoteaddress_view ) , 1 ) ;
int index = 0 ;
for ( auto & entry : serverInstance - > banManager ( ) - > trigger_list ( record , this - > getServerId ( ) , cmd [ 0 ] . has ( " offset " ) ? cmd [ " offset " ] . as < int64_t > ( ) : 0 , cmd [ 0 ] . has ( " limit " ) ? cmd [ " limit " ] . as < int64_t > ( ) : - 1 ) ) {
notify [ index ] [ " client_unique_identifier " ] = entry - > unique_id ;
notify [ index ] [ " client_hardware_identifier " ] = entry - > hardware_id ;
notify [ index ] [ " client_nickname " ] = entry - > name ;
if ( allow_ip )
notify [ index ] [ " connection_client_ip " ] = entry - > ip ;
else
notify [ index ] [ " connection_client_ip " ] = " hidden " ;
notify [ index ] [ " timestamp " ] = duration_cast < milliseconds > ( entry - > timestamp . time_since_epoch ( ) ) . count ( ) ;
index + + ;
}
if ( index = = 0 ) return { findError ( " database_empty_result " ) } ;
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandTokenList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_token_list , 1 , true ) ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifytokenlist " : " " ) ;
int index = 0 ;
for ( auto & token : this - > server - > tokenManager - > avariableTokes ( ) ) {
notify [ index ] [ " token " ] = token - > token ;
notify [ index ] [ " token_type " ] = token - > type ;
notify [ index ] [ " token_id1 " ] = token - > groupId ;
notify [ index ] [ " token_id2 " ] = token - > channelId ;
notify [ index ] [ " token_created " ] = chrono : : duration_cast < chrono : : seconds > ( token - > created . time_since_epoch ( ) ) . count ( ) ;
notify [ index ] [ " token_description " ] = token - > description ;
index + + ;
}
if ( index = = 0 ) return { findError ( " database_empty_result " ) , " empty! " } ;
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandTokenAdd ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_token_add , 1 , true ) ;
TokenType ttype = static_cast < TokenType > ( cmd [ " tokentype " ] . as < uint32_t > ( ) ) ;
auto gId = cmd [ " tokenid1 " ] . as < GroupId > ( ) ;
auto cId = cmd [ " tokenid2 " ] . as < ChannelId > ( ) ;
string description = cmd [ " tokendescription " ] . string ( ) ;
{
auto group = this - > server - > groups - > findGroup ( gId ) ;
if ( ! group ) return { findError ( " parameter_invalid " ) , " invalid server group id " } ;
if ( group - > type ( ) = = GroupType : : GROUP_TYPE_TEMPLATE ) return { findError ( " parameter_invalid " ) , " invalid server group type " } ;
if ( group - > target ( ) = = GroupTarget : : GROUPTARGET_SERVER )
GROUP_PERMISSION_TEST ( permission : : i_server_group_member_add_power , permission : : i_server_group_needed_member_add_power , group , true ) ;
else
GROUP_PERMISSION_TEST ( permission : : i_channel_group_member_add_power , permission : : i_channel_group_needed_member_add_power , group , true ) ;
}
if ( ttype = = TokenType : : TOKEN_CHANNEL ) {
if ( ! this - > server - > channelTree - > findChannel ( cId ) ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
} else if ( ttype = = TokenType : : TOKEN_SERVER ) ;
else return { findError ( " parameter_invalid " ) , " invalid token target type " } ;
auto result = this - > server - > tokenManager - > createToken ( ttype , gId , description , cId , cmd [ " token " ] ) ;
if ( ! result ) return { ErrorType : : Success , " internal error " } ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifytokenadd " : " " ) ;
notify [ " token " ] = result - > token ;
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandTokenUse ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_token_use , 1 , true ) ;
auto strToken = cmd [ " token " ] . string ( ) ;
auto token = this - > server - > tokenManager - > findToken ( strToken ) ;
if ( ! token ) return { findError ( " token_invalid_id " ) , " Invalid token. (Token not registered) " } ;
this - > server - > tokenManager - > deleteToke ( token - > token ) ;
auto serverGroup = this - > server - > groups - > findGroup ( token - > groupId ) ;
if ( ! serverGroup ) return { findError ( " token_invalid_id " ) , " Token invalid groupId " } ;
this - > server - > properties ( ) [ property : : VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY ] = false ; //TODO test if its the default token
std : : shared_ptr < BasicChannel > channel = nullptr ;
if ( token - > channelId ! = 0 ) {
channel = this - > server - > channelTree - > findChannel ( token - > channelId ) ;
if ( ! channel ) return { findError ( " token_invalid_id " ) , " Token invalid channelId " } ;
this - > server - > groups - > setChannelGroup ( this - > getClientDatabaseId ( ) , serverGroup , channel ) ;
} else {
if ( ! this - > server - > groups - > hasServerGroupAssigned ( this - > getClientDatabaseId ( ) , serverGroup ) )
this - > server - > groups - > addServerGroup ( this - > getClientDatabaseId ( ) , serverGroup ) ;
else {
return CommandResult : : Success ;
}
}
if ( this - > server - > notifyClientPropertyUpdates ( _this . lock ( ) , this - > server - > groups - > update_server_group_property ( _this . lock ( ) , true ) ) ) {
if ( this - > update_cached_permissions ( ) ) /* update cached calculated permissions */
this - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
{
for ( auto & viewer : this - > server - > getClients ( ) ) {
if ( viewer - > isClientVisible ( _this . lock ( ) , true ) )
viewer - > notifyServerGroupClientAdd ( this - > server - > serverRoot , _this . lock ( ) , serverGroup ) ;
}
}
this - > notifyServerGroupClientAdd ( this - > server - > serverRoot , _this . lock ( ) , serverGroup ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandTokenDelete ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_token_delete , 1 , true ) ;
auto strToken = cmd [ " token " ] . string ( ) ;
auto token = this - > server - > tokenManager - > findToken ( strToken ) ;
if ( ! token ) return { findError ( " token_invalid_id " ) , " Invalid token. (Token not registered) " } ;
this - > server - > tokenManager - > deleteToke ( token - > token ) ;
if ( token - > token = = this - > server - > properties ( ) [ property : : VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY ] . as < string > ( ) ) {
this - > server - > properties ( ) [ property : : VIRTUALSERVER_AUTOGENERATED_PRIVILEGEKEY ] = " " ;
this - > server - > properties ( ) [ property : : VIRTUALSERVER_ASK_FOR_PRIVILEGEKEY ] = false ;
logMessage ( this - > getServerId ( ) , " {} Deleting the default server token. Don't ask anymore for this a token! " , CLIENT_STR_LOG_PREFIX ) ;
}
return CommandResult : : Success ;
}
//start=0 duration=10
//pattern=%asd%
struct ClientDbArgs {
shared_ptr < TSServer > server ;
int index = 0 ;
int offset = 0 ;
int resultIndex = 0 ;
bool showIp = false ;
bool largeInfo = false ;
Command * result = nullptr ;
} ;
CommandResult ConnectedClient : : handleCommandClientDbList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
CACHED_PERM_CHECK ( permission : : b_virtualserver_client_dblist , 1 , true ) ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientdblist " : " " ) ;
if ( ! cmd [ 0 ] . has ( " start " ) )
cmd [ " start " ] = 0 ;
if ( ! cmd [ 0 ] . has ( " duration " ) )
cmd [ " duration " ] = 20 ;
if ( cmd [ 0 ] [ " duration " ] . as < int > ( ) > 2000 ) cmd [ " duration " ] = 2000 ;
if ( cmd [ 0 ] [ " duration " ] . as < int > ( ) < 1 ) cmd [ " duration " ] = 1 ;
auto maxIndex = cmd [ " start " ] . as < uint32_t > ( ) + cmd [ " duration " ] . as < uint32_t > ( ) ;
ClientDbArgs args ;
args . server = this - > server ;
args . offset = cmd [ " start " ] . as < uint32_t > ( ) ;
args . result = & notify ;
args . resultIndex = 0 ;
args . index = 0 ;
args . showIp = this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_remoteaddress_view ) , 1 ) ;
args . largeInfo = cmd . hasParm ( " details " ) ;
( LOG_SQL_CMD ) ( sql : : command ( this - > server - > getSql ( ) , " SELECT * FROM `clients` WHERE `serverId` = :sid ORDER BY `cldbid` ASC " + ( maxIndex > 0 ? " LIMIT " + to_string ( maxIndex ) : " " ) , variable { " :sid " , this - > server - > getServerId ( ) } ) . query (
[ ] ( ClientDbArgs * pArgs , int length , char * * values , char * * column ) {
pArgs - > index + + ;
if ( pArgs - > offset < pArgs - > index ) {
ClientDbId id = 0 ;
string uid , name , ip ;
string created = " 0 " , lastConnected = " 0 " , connections = " 0 " ;
for ( int index = 0 ; index < length ; index + + ) {
string key = column [ index ] ;
if ( key = = " cldbid " )
id = stoll ( values [ index ] ) ;
else if ( key = = " clientUid " )
uid = values [ index ] ;
else if ( key = = " firstConnect " )
created = values [ index ] ;
else if ( key = = " lastConnect " )
lastConnected = values [ index ] ;
else if ( key = = " connections " )
connections = values [ index ] ;
else if ( key = = " lastName " )
name = values [ index ] ;
}
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " cldbid " ] = id ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_unique_identifier " ] = uid ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_nickname " ] = name ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_created " ] = created ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_lastconnected " ] = lastConnected ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_totalconnections " ] = connections ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_description " ] = " " ;
auto props = serverInstance - > databaseHelper ( ) - > loadClientProperties ( pArgs - > server , id , ClientType : : CLIENT_TEAMSPEAK ) ;
if ( props ) {
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_lastip " ] = ( * props ) [ property : : CONNECTION_CLIENT_IP ] . as < string > ( ) ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_description " ] = ( * props ) [ property : : CLIENT_DESCRIPTION ] . as < string > ( ) ;
if ( pArgs - > largeInfo ) {
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_badges " ] = ( * props ) [ property : : CLIENT_BADGES ] . as < string > ( ) ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_version " ] = ( * props ) [ property : : CLIENT_VERSION ] . as < string > ( ) ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_platform " ] = ( * props ) [ property : : CLIENT_PLATFORM ] . as < string > ( ) ;
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_hwid " ] = ( * props ) [ property : : CLIENT_HARDWARE_ID ] . as < string > ( ) ;
}
}
if ( ! pArgs - > showIp )
pArgs - > result - > operator [ ] ( pArgs - > resultIndex ) [ " client_lastip " ] = " hidden " ;
pArgs - > resultIndex + + ;
}
return 0 ;
} , & args ) ) ;
if ( args . resultIndex = = 0 ) return { findError ( " database_empty_result " ) , " empty! " } ;
if ( cmd . hasParm ( " count " ) ) {
size_t result = 0 ;
sql : : command ( this - > server - > getSql ( ) , " SELECT COUNT(*) AS `count` FROM `clients` WHERE `serverId` = :sid " , variable { " :sid " , this - > server - > getServerId ( ) } ) . query ( [ ] ( size_t * ptr , int , char * * v , char * * ) {
* ptr = static_cast < size_t > ( stoll ( v [ 0 ] ) ) ;
return 0 ;
} , & result ) ;
notify [ 0 ] [ " count " ] = result ;
}
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientDBEdit ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
PERM_CHECKR ( permission : : b_client_modify_dbproperties , 1 , true ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return { findError ( " 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 ;
auto info = property : : info < property : : ClientProperties > ( elm ) ;
if ( * info = = property : : CLIENT_UNDEFINED ) {
logError ( this - > getServerId ( ) , " Client " + this - > getDisplayName ( ) + " tried to change someone's db entry, but the entry in unknown: " + elm ) ;
continue ;
}
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: ' " + info - > name + " ') " ) ;
continue ;
}
( * props ) [ info ] = cmd [ elm ] . string ( ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPluginCmd ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto mode = cmd [ " targetmode " ] . as < PluginTargetMode > ( ) ;
if ( mode = = PluginTargetMode : : PLUGINCMD_CURRENT_CHANNEL ) {
CMD_REQ_CHANNEL ;
for ( auto & cl : this - > server - > getClientsByChannel ( this - > currentChannel ) )
cl - > notifyPluginCmd ( cmd [ " name " ] , cmd [ " data " ] , _this . lock ( ) ) ;
} else if ( mode = = PluginTargetMode : : PLUGINCMD_SUBSCRIBED_CLIENTS ) {
for ( auto & cl : this - > server - > getClients ( ) )
if ( cl - > isClientVisible ( _this . lock ( ) , true ) )
cl - > notifyPluginCmd ( cmd [ " name " ] , cmd [ " data " ] , _this . lock ( ) ) ;
} else if ( mode = = PluginTargetMode : : PLUGINCMD_SERVER ) {
for ( auto & cl : this - > server - > getClients ( ) )
cl - > notifyPluginCmd ( cmd [ " name " ] , cmd [ " data " ] , _this . lock ( ) ) ;
} else if ( mode = = PluginTargetMode : : PLUGINCMD_CLIENT ) {
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto target = cmd [ index ] [ " target " ] . as < ClientId > ( ) ;
auto cl = this - > server - > findClient ( target ) ;
if ( ! cl ) return { findError ( " client_invalid_id " ) , " invalid target id " } ;
cl - > notifyPluginCmd ( cmd [ " name " ] , cmd [ " data " ] , _this . lock ( ) ) ;
}
}
/*
else if ( mode = = PluginTargetMode : : PLUGINCMD_SEND_COMMAND ) {
auto target = _this . lock ( ) ;
if ( cmd [ 0 ] . has ( " target " ) )
target = this - > server - > findClient ( cmd [ " target " ] . as < ClientId > ( ) ) ;
if ( ! target ) return { findError ( " client_invalid_id " ) , " invalid target id " } ;
target - > sendCommand ( Command ( cmd [ " command " ] . string ( ) ) , cmd [ 0 ] . has ( " low " ) ? cmd [ " low " ] : false ) ;
}
*/
else return CommandResult : : NotImplemented ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientEdit ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
auto client = this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) ;
if ( ! client ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
return this - > handleCommandClientEdit ( cmd , client ) ;
}
CommandResult 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 ;
deque < pair < property : : ClientProperties , string > > keys ;
for ( const auto & key : cmd [ 0 ] . keys ( ) ) {
if ( key = = " return_code " ) continue ;
if ( key = = " clid " ) continue ;
const auto & info = property : : info < property : : ClientProperties > ( key ) ;
if ( * info = = property : : CLIENT_UNDEFINED ) {
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 ;
}
if ( ( info - > flags & property : : FLAG_USER_EDITABLE ) = = 0 ) {
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 ;
}
if ( ! info - > validate_input ( cmd [ key ] . as < string > ( ) ) ) {
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 ;
}
if ( client - > properties ( ) [ info ] . as < string > ( ) = = cmd [ key ] . as < string > ( ) ) continue ;
if ( * info = = property : : CLIENT_DESCRIPTION ) {
if ( self )
PERM_CHECKR ( permission : : b_client_modify_own_description , 1 , true ) ;
else if ( client - > getType ( ) = = ClientType : : CLIENT_MUSIC ) {
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_modify_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_modify_power , client - > currentChannel ) , true ) ;
}
} else {
PERM_CHECKR ( permission : : b_client_modify_description , 1 , true ) ;
}
string value = cmd [ " client_description " ] . string ( ) ;
if ( count_characters ( value ) > 200 ) return { findError ( " parameter_invalid " ) , " Invalid description length. A maximum of 200 characters is allowed! " } ;
} else if ( * info = = property : : CLIENT_IS_TALKER ) {
PERM_CHECK_CHANNELR ( permission : : b_client_set_flag_talker , 1 , client - > getChannel ( ) , true ) ;
cmd [ " client_is_talker " ] = cmd [ " client_is_talker " ] . as < bool > ( ) ;
cmd [ " client_talk_request " ] = 0 ;
update_talk_rights = true ;
keys . emplace_back ( property : : CLIENT_IS_TALKER , " client_is_talker " ) ;
keys . emplace_back ( property : : CLIENT_TALK_REQUEST , " client_talk_request " ) ;
continue ;
} else if ( * info = = property : : CLIENT_NICKNAME ) {
if ( ! self ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_rename_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_rename_power , client - > currentChannel ) , true ) ;
}
}
string name = cmd [ " client_nickname " ] . string ( ) ;
if ( count_characters ( name ) < 3 ) return { findError ( " parameter_invalid " ) , " Invalid name length. A minimum of 3 characters is required! " } ;
if ( count_characters ( name ) > 30 ) return { findError ( " parameter_invalid " ) , " Invalid name length. A maximum of 30 characters is allowed! " } ;
auto banIgnore = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_ignore_bans , 1 , this - > currentChannel ) ;
if ( ! banIgnore ) {
auto banRecord = serverInstance - > banManager ( ) - > findBanByName ( this - > getServerId ( ) , name ) ;
if ( banRecord ) return { findError ( " 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 { findError ( " client_nickname_inuse " ) , " This nickname is already in use " } ;
}
}
if ( self ) {
nickname_lock . reset ( ) ;
continue ;
}
}
} else if ( * info = = property : : CLIENT_PLAYER_VOLUME ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_modify_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_modify_power , client - > currentChannel ) , true ) ;
}
auto bot = dynamic_pointer_cast < MusicClient > ( client ) ;
assert ( bot ) ;
auto volume = cmd [ " player_volume " ] . as < float > ( ) ;
auto max_volume = this - > cached_permission_value ( permission : : i_client_music_create_modify_max_volume ) ;
if ( max_volume ! = permNotGranted & & ! this - > permission_granted ( max_volume , volume * 100 ) ) return CommandResultPermissionError { permission : : i_client_music_create_modify_max_volume } ;
bot - > volume_modifier ( cmd [ " player_volume " ] ) ;
} else if ( * info = = property : : CLIENT_IS_CHANNEL_COMMANDER ) {
if ( ! self ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_modify_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_modify_power , client - > currentChannel ) , true ) ;
}
}
if ( cmd [ " client_is_channel_commander " ] . as < bool > ( ) ) {
CACHED_PERM_CHECK ( permission : : b_client_use_channel_commander , 1 ) ;
}
} else if ( * info = = property : : CLIENT_IS_PRIORITY_SPEAKER ) {
//FIXME allow other to remove this thing
if ( ! self ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC )
return { findError ( " client_invalid_type " ) } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_modify_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_modify_power , client - > currentChannel ) , true ) ;
}
}
if ( cmd [ " client_is_priority_speaker " ] . as < bool > ( ) ) {
PERM_CHECK_CHANNELR ( permission : : b_client_use_priority_speaker , 1 , this - > currentChannel , true ) ;
}
} else if ( self & & key = = " client_talk_request " ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 20 ) ;
CACHED_PERM_CHECK ( permission : : b_client_request_talker , 1 , true ) ;
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 ;
keys . emplace_back ( property : : CLIENT_TALK_REQUEST , " client_talk_request " ) ;
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 ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_allow_invalid_badges , 1 , this - > currentChannel ) )
( ( VoiceClient * ) this ) - > disconnect ( VREASON_SERVER_KICK , config : : messages : : kick_invalid_badges , this - > server ? this - > server - > serverAdmin : dynamic_pointer_cast < ConnectedClient > ( serverInstance - > getInitalServerAdmin ( ) ) , true ) ;
return { findError ( " parameter_invalid " ) , " Invalid badges " } ;
}
//FIXME stuff here
} else if ( ! self & & key = = " client_version " ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_modify_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_modify_power , client - > currentChannel ) , true ) ;
}
} else if ( ! self & & key = = " client_platform " ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_modify_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_modify_power , client - > currentChannel ) , true ) ;
}
} else if ( ! self & & key = = " client_country " ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_modify_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_modify_power , client - > currentChannel ) , true ) ;
}
} else if ( ! self & & ( * info = = property : : CLIENT_FLAG_NOTIFY_SONG_CHANGE /* || *info == property::CLIENT_NOTIFY_SONG_MESSAGE*/ ) ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_modify_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_modify_power , client - > currentChannel ) , true ) ;
}
} else if ( ! self & & key = = " client_uptime_mode " ) {
if ( client - > getType ( ) ! = ClientType : : CLIENT_MUSIC ) return { findError ( " client_invalid_type " ) } ;
if ( client - > properties ( ) [ property : : CLIENT_OWNER ] ! = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : i_client_music_modify_power , client - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_modify_power , client - > currentChannel ) , true ) ;
}
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 ;
}
keys . emplace_back ( property : : CLIENT_LASTCONNECTED , " client_lastconnected " ) ;
} else if ( ! self & & * info = = property : : CLIENT_BOT_TYPE ) {
auto type = cmd [ " client_bot_type " ] . as < MusicClient : : Type : : value > ( ) ;
if ( type = = MusicClient : : Type : : TEMPORARY ) {
CACHED_PERM_CHECK ( permission : : b_client_music_modify_temporary , 1 , true ) ;
} else if ( type = = MusicClient : : Type : : SEMI_PERMANENT ) {
CACHED_PERM_CHECK ( permission : : b_client_music_modify_semi_permanent , 1 , true ) ;
} else if ( type = = MusicClient : : Type : : PERMANENT ) {
CACHED_PERM_CHECK ( permission : : b_client_music_modify_permanent , 1 , true ) ;
} else
return { findError ( " parameter_invalid " ) } ;
} else if ( ! self ) { /* dont edit random properties of other clients. For us self its allowed to edit the rest without permissions */
continue ;
}
keys . emplace_back ( ( property : : ClientProperties ) info - > property_index , key ) ;
}
deque < property : : ClientProperties > updates ;
for ( const auto & key : keys ) {
if ( key . first = = property : : CLIENT_IS_PRIORITY_SPEAKER ) {
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 ) ;
}
client - > properties ( ) [ key . first ] = cmd [ 0 ] [ key . second ] . value ( ) ;
updates . push_back ( key . first ) ;
}
if ( update_talk_rights )
client - > updateTalkRights ( client - > properties ( ) [ property : : CLIENT_TALK_POWER ] ) ;
if ( this - > server )
this - > server - > notifyClientPropertyUpdates ( client , updates ) ;
nickname_lock . reset ( ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientUpdate ( Command & cmd ) {
return this - > handleCommandClientEdit ( cmd , _this . lock ( ) ) ;
}
CommandResult ConnectedClient : : handleCommandClientMute ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
auto client = this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) ;
if ( ! client | | client - > getClientId ( ) = = this - > getClientId ( ) ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
{
unique_lock channel_lock ( this - > channel_lock ) ;
for ( const auto & weak : this - > mutedClients )
if ( weak . lock ( ) = = client ) return CommandResult : : Success ;
this - > mutedClients . push_back ( client ) ;
}
if ( config : : voice : : notifyMuted )
2019-07-23 10:37:56 +02:00
client - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , _this . lock ( ) , client - > getClientId ( ) , 0 , config : : messages : : mute_notify_message ) ;
2019-07-17 19:37:18 +02:00
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientUnmute ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
auto client = this - > server - > findClient ( cmd [ " clid " ] . as < ClientId > ( ) ) ;
if ( ! client | | client - > getClientId ( ) = = this - > getClientId ( ) ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
{
unique_lock channel_lock ( this - > channel_lock ) ;
this - > mutedClients . erase ( std : : remove_if ( this - > mutedClients . begin ( ) , this - > mutedClients . end ( ) , [ client ] ( const weak_ptr < ConnectedClient > & weak ) {
auto c = weak . lock ( ) ;
return ! c | | c = = client ;
} ) , this - > mutedClients . end ( ) ) ;
}
if ( config : : voice : : notifyMuted )
2019-07-23 10:37:56 +02:00
client - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , _this . lock ( ) , client - > getClientId ( ) , 0 , config : : messages : : unmute_notify_message ) ;
2019-07-17 19:37:18 +02:00
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
bool allow_ip = false ;
if ( cmd . hasParm ( " ip " ) )
allow_ip = this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_remoteaddress_view ) , 1 ) ;
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 " ) ) {
result [ index ] [ " client_away " ] = client - > properties ( ) [ property : : CLIENT_AWAY ] . as < string > ( ) ;
result [ index ] [ " client_away_message " ] = client - > properties ( ) [ property : : CLIENT_AWAY_MESSAGE ] . as < string > ( ) ;
}
if ( cmd . hasParm ( " groups " ) ) {
result [ index ] [ " client_channel_group_id " ] = client - > properties ( ) [ property : : CLIENT_CHANNEL_GROUP_ID ] . as < string > ( ) ;
result [ index ] [ " client_servergroups " ] = client - > properties ( ) [ property : : CLIENT_SERVERGROUPS ] . as < string > ( ) ;
result [ index ] [ " client_channel_group_inherited_channel_id " ] = client - > properties ( ) [ property : : CLIENT_CHANNEL_GROUP_INHERITED_CHANNEL_ID ] . as < string > ( ) ;
}
if ( cmd . hasParm ( " times " ) ) {
result [ index ] [ " client_idle_time " ] = duration_cast < milliseconds > ( system_clock : : now ( ) - client - > idleTimestamp ) . count ( ) ;
result [ index ] [ " client_total_online_time " ] = client - > properties ( ) [ property : : CLIENT_TOTAL_ONLINE_TIME ] . as < 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 < int64_t > ( ) + duration_cast < seconds > ( system_clock : : now ( ) - client - > lastOnlineTimestamp ) . count ( ) ;
result [ index ] [ " client_idle_time " ] = duration_cast < milliseconds > ( system_clock : : now ( ) - client - > idleTimestamp ) . count ( ) ;
result [ index ] [ " client_created " ] = client - > properties ( ) [ property : : CLIENT_CREATED ] . as < string > ( ) ;
result [ index ] [ " client_lastconnected " ] = client - > properties ( ) [ property : : CLIENT_LASTCONNECTED ] . as < string > ( ) ;
}
if ( cmd . hasParm ( " info " ) ) {
result [ index ] [ " client_version " ] = client - > properties ( ) [ property : : CLIENT_VERSION ] . as < string > ( ) ;
result [ index ] [ " client_platform " ] = client - > properties ( ) [ property : : CLIENT_PLATFORM ] . as < string > ( ) ;
}
if ( cmd . hasParm ( " badges " ) )
result [ index ] [ " client_badges " ] = client - > properties ( ) [ property : : CLIENT_BADGES ] . as < string > ( ) ;
if ( cmd . hasParm ( " country " ) )
result [ index ] [ " client_country " ] = client - > properties ( ) [ property : : CLIENT_COUNTRY ] . as < string > ( ) ;
if ( cmd . hasParm ( " ip " ) )
result [ index ] [ " connection_client_ip " ] = allow_ip ? client - > properties ( ) [ property : : CONNECTION_CLIENT_IP ] . as < string > ( ) : " hidden " ;
if ( cmd . hasParm ( " icon " ) )
result [ index ] [ " client_icon_id " ] = client - > properties ( ) [ property : : CLIENT_ICON_ID ] . as < string > ( ) ;
if ( cmd . hasParm ( " voice " ) ) {
result [ index ] [ " client_talk_power " ] = client - > properties ( ) [ property : : CLIENT_TALK_POWER ] . as < string > ( ) ;
result [ index ] [ " client_flag_talking " ] = client - > properties ( ) [ property : : CLIENT_FLAG_TALKING ] . as < string > ( ) ;
result [ index ] [ " client_input_muted " ] = client - > properties ( ) [ property : : CLIENT_INPUT_MUTED ] . as < string > ( ) ;
result [ index ] [ " client_output_muted " ] = client - > properties ( ) [ property : : CLIENT_OUTPUT_MUTED ] . as < string > ( ) ;
result [ index ] [ " client_input_hardware " ] = client - > properties ( ) [ property : : CLIENT_INPUT_HARDWARE ] . as < string > ( ) ;
result [ index ] [ " client_output_hardware " ] = client - > properties ( ) [ property : : CLIENT_OUTPUT_HARDWARE ] . as < string > ( ) ;
result [ index ] [ " client_is_talker " ] = client - > properties ( ) [ property : : CLIENT_IS_TALKER ] . as < string > ( ) ;
result [ index ] [ " client_is_priority_speaker " ] = client - > properties ( ) [ property : : CLIENT_IS_PRIORITY_SPEAKER ] . as < string > ( ) ;
result [ index ] [ " client_is_recording " ] = client - > properties ( ) [ property : : CLIENT_IS_RECORDING ] . as < string > ( ) ;
result [ index ] [ " client_is_channel_commander " ] = client - > properties ( ) [ property : : CLIENT_IS_CHANNEL_COMMANDER ] . as < string > ( ) ;
}
index + + ;
} ) ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandWhoAmI ( Command & cmd ) {
CMD_RESET_IDLE ;
Command result ( " " ) ;
if ( this - > server ) {
result [ " virtualserver_status " ] = ServerState : : string ( this - > getServer ( ) - > state ) ;
result [ " virtualserver_id " ] = this - > server - > getServerId ( ) ;
result [ " virtualserver_unique_identifier " ] = this - > server - > properties ( ) [ property : : VIRTUALSERVER_UNIQUE_IDENTIFIER ] . as < string > ( ) ;
result [ " virtualserver_port " ] = 0 ;
if ( this - > server - > udpVoiceServer ) {
result [ " virtualserver_port " ] = this - > server - > properties ( ) [ property : : VIRTUALSERVER_PORT ] . as_save < uint16_t > ( ) ;
}
} else {
result [ " virtualserver_status " ] = " template " ;
result [ " virtualserver_id " ] = " 0 " ;
result [ " virtualserver_unique_identifier " ] = " " ; //TODO generate uid
result [ " virtualserver_port " ] = " 0 " ;
}
result [ " client_id " ] = this - > getClientId ( ) ;
result [ " client_channel_id " ] = this - > currentChannel ? this - > currentChannel - > channelId ( ) : 0 ;
result [ " client_nickname " ] = this - > getDisplayName ( ) ;
result [ " client_database_id " ] = this - > getClientDatabaseId ( ) ;
result [ " client_login_name " ] = this - > properties ( ) [ property : : CLIENT_LOGIN_NAME ] . as < string > ( ) ;
result [ " client_unique_identifier " ] = this - > getUid ( ) ;
{
auto query = dynamic_cast < QueryClient * > ( this ) ;
if ( query ) {
auto account = query - > getQueryAccount ( ) ;
result [ " client_origin_server_id " ] = account ? account - > bound_server : 0 ;
} else
result [ " client_origin_server_id " ] = 0 ;
}
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandServerGroupsByClientId ( Command & cmd ) {
CMD_RESET_IDLE ;
ClientDbId cldbid = cmd [ " cldbid " ] ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cldbid ) ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyservergroupsbyclientid " : " " ) ;
int index = 0 ;
if ( this - > server ) {
for ( const auto & group : this - > server - > groups - > getAssignedServerGroups ( cldbid ) ) {
result [ index ] [ " name " ] = group - > group - > name ( ) ;
result [ index ] [ " sgid " ] = group - > group - > groupId ( ) ;
result [ index ] [ " cldbid " ] = cldbid ;
index + + ;
}
} else {
for ( const auto & group : serverInstance - > getGroupManager ( ) - > getAssignedServerGroups ( cldbid ) ) {
result [ index ] [ " name " ] = group - > group - > name ( ) ;
result [ index ] [ " sgid " ] = group - > group - > groupId ( ) ;
result [ index ] [ " cldbid " ] = cldbid ;
index + + ;
}
}
if ( index = = 0 ) return { findError ( " database_empty_result " ) , " empty! " } ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientGetDBIDfromUID ( 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 { findError ( " database_empty_result " ) , " empty! " } ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientdbidfromuid " : " " ) ;
int result_index = 0 ;
for ( auto & info : res ) {
result [ result_index ] [ " cluid " ] = info - > uniqueId ;
result [ result_index ] [ " cldbid " ] = info - > cldbid ;
result_index + + ;
}
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult 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 { findError ( " database_empty_result " ) , " empty! " } ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientgetnamefromdbid " : " " ) ;
int result_index = 0 ;
for ( auto & info : res ) {
result [ result_index ] [ " cluid " ] = info - > uniqueId ;
result [ result_index ] [ " cldbid " ] = info - > cldbid ;
result [ result_index ] [ " name " ] = info - > lastName ;
result [ result_index ] [ " clname " ] = info - > lastName ;
result_index + + ;
}
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult 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 { findError ( " database_empty_result " ) , " empty! " } ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientnamefromuid " : " " ) ;
int result_index = 0 ;
for ( auto & info : res ) {
result [ result_index ] [ " cluid " ] = info - > uniqueId ;
result [ result_index ] [ " cldbid " ] = info - > cldbid ;
result [ result_index ] [ " name " ] = info - > lastName ;
result [ result_index ] [ " clname " ] = info - > lastName ;
result_index + + ;
}
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientGetUidFromClid ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
bool error = false ;
bool found = false ;
auto client_list = this - > server - > getClients ( ) ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientgetuidfromclid " : " " ) ;
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 { findError ( " database_empty_result " ) , " empty! " } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientAddPerm ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > server , cmd [ " cldbid " ] ) ;
PERM_CHECKR ( permission : : i_client_permission_modify_power , this - > server - > calculatePermission ( permission : : PERMTEST_ORDERED , cmd [ " cldbid " ] , permission : : i_client_needed_permission_modify_power , ClientType : : CLIENT_TEAMSPEAK , nullptr ) , true ) ;
auto maxValue = this - > getPermissionGrantValue ( permission : : PERMTEST_ORDERED , permission : : i_permission_modify_power , this - > currentChannel ) ;
bool ignoreGrant = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_permission_modify_power_ignore , 1 , this - > currentChannel ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto update_channels = false ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & val > maxValue )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( grant ) {
mgr - > set_permission ( permType , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : do_nothing , permission : : v2 : : set_value ) ;
} else {
mgr - > set_permission ( permType , { cmd [ index ] [ " permvalue " ] , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing , cmd [ index ] [ " permskip " ] ? 1 : 0 , cmd [ index ] [ " permnegated " ] ? 1 : 0 ) ;
update_channels | = permission_is_client_property ( permType ) ;
}
}
auto onlineClients = this - > server - > findClientsByCldbId ( cmd [ " cldbid " ] ) ;
if ( ! onlineClients . empty ( ) )
for ( const auto & elm : onlineClients ) {
if ( elm - > update_cached_permissions ( ) ) /* update cached calculated permissions */
elm - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
if ( update_channels )
elm - > updateChannelClientProperties ( true , true ) ;
2019-07-23 10:37:56 +02:00
elm - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
2019-07-17 19:37:18 +02:00
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientDelPerm ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > server , cmd [ " cldbid " ] ) ;
PERM_CHECKR ( permission : : i_client_permission_modify_power , this - > server - > calculatePermission ( permission : : PERMTEST_ORDERED , cmd [ " cldbid " ] , permission : : i_client_needed_permission_modify_power , ClientType : : CLIENT_TEAMSPEAK , nullptr ) , true ) ;
bool ignoreGrant = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_permission_modify_power_ignore , 1 , this - > currentChannel ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto onlineClients = this - > server - > findClientsByCldbId ( cmd [ " cldbid " ] ) ;
auto update_channel = false ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd )
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( grant ) {
mgr - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : do_nothing , permission : : v2 : : delete_value ) ;
} else {
mgr - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : delete_value , permission : : v2 : : do_nothing ) ;
update_channel | = permission_is_client_property ( permType ) ;
}
}
if ( ! onlineClients . empty ( ) )
for ( const auto & elm : onlineClients ) {
if ( elm - > update_cached_permissions ( ) ) /* update cached calculated permissions */
elm - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
if ( update_channel )
elm - > updateChannelClientProperties ( true , true ) ;
2019-07-23 10:37:56 +02:00
elm - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
2019-07-17 19:37:18 +02:00
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientPermList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
PERM_CHECKR ( permission : : b_virtualserver_client_permission_list , 1 , true ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > server , cmd [ " cldbid " ] ) ;
if ( ! this - > notifyClientPermList ( cmd [ " cldbid " ] , mgr , cmd . hasParm ( " permsid " ) ) ) return { findError ( " database_empty_result " ) , " empty! " } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelClientPermList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
PERM_CHECKR ( permission : : b_virtualserver_channelclient_permission_list , 1 , true ) ;
2019-07-23 10:37:56 +02:00
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
if ( ! channel ) return { ErrorType : : VSError } ;
2019-07-17 19:37:18 +02:00
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > server , cmd [ " cldbid " ] . as < ClientDbId > ( ) ) ;
Command res ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifychannelclientpermlist " : " " ) ;
auto permissions = mgr - > channel_permissions ( channel - > channelId ( ) ) ;
if ( permissions . empty ( ) )
return { ErrorType : : DBEmpty } ;
int index = 0 ;
res [ index ] [ " cid " ] = channel - > channelId ( ) ;
res [ index ] [ " cldbid " ] = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
auto sids = cmd . hasParm ( " permsid " ) ;
for ( const auto & permission_data : permissions ) {
auto & permission = std : : get < 1 > ( permission_data ) ;
if ( permission . flags . value_set ) {
if ( sids )
res [ index ] [ " permsid " ] = permission : : resolvePermissionData ( get < 0 > ( permission_data ) ) - > name ;
else
res [ index ] [ " permid " ] = get < 0 > ( permission_data ) ;
res [ index ] [ " permvalue " ] = permission . values . value ;
res [ index ] [ " permnegated " ] = permission . flags . negate ;
res [ index ] [ " permskip " ] = permission . flags . skip ;
index + + ;
}
if ( permission . flags . grant_set ) {
if ( sids )
res [ index ] [ " permsid " ] = permission : : resolvePermissionData ( get < 0 > ( permission_data ) ) - > grant_name ;
else
res [ index ] [ " permid " ] = ( get < 0 > ( permission_data ) | PERM_ID_GRANT ) ;
res [ index ] [ " permvalue " ] = permission . values . grant ;
res [ index ] [ " permnegated " ] = 0 ;
res [ index ] [ " permskip " ] = 0 ;
index + + ;
}
}
this - > sendCommand ( res ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelClientDelPerm ( Command & cmd ) {
2019-07-23 10:37:56 +02:00
CMD_REF_SERVER ( server_ref ) ;
2019-07-17 19:37:18 +02:00
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return { findError ( " parameter_invalid " ) , " Invalid manager db id " } ;
2019-07-23 10:37:56 +02:00
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > server , cmd [ " cldbid " ] ) ;
PERM_CHECKR ( permission : : i_client_permission_modify_power , this - > server - > calculatePermission ( permission : : PERMTEST_ORDERED , cmd [ " cldbid " ] , permission : : i_client_needed_permission_modify_power , ClientType : : CLIENT_TEAMSPEAK , nullptr ) , true ) ;
2019-07-17 19:37:18 +02:00
2019-07-23 10:37:56 +02:00
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
if ( ! channel ) return { ErrorType : : VSError } ;
2019-07-17 19:37:18 +02:00
bool ignoreGrant = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_permission_modify_power_ignore , 1 , this - > currentChannel ) ;
2019-07-23 10:37:56 +02:00
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) , update_view = false ;
2019-07-17 19:37:18 +02:00
auto cll = this - > server - > findClientsByCldbId ( cmd [ " cldbid " ] ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( grant ) {
mgr - > set_channel_permission ( permType , channel - > channelId ( ) , permission : : v2 : : empty_permission_values , permission : : v2 : : do_nothing , permission : : v2 : : delete_value ) ;
} else {
mgr - > set_channel_permission ( permType , channel - > channelId ( ) , permission : : v2 : : empty_permission_values , permission : : v2 : : delete_value , permission : : v2 : : do_nothing ) ;
2019-07-23 10:37:56 +02:00
update_view = permType = = permission : : b_channel_ignore_view_power | | permType = = permission : : i_channel_view_power ;
2019-07-17 19:37:18 +02:00
}
}
if ( ! cll . empty ( ) ) {
2019-07-23 10:37:56 +02:00
for ( const auto & elm : cll ) {
if ( elm - > update_cached_permissions ( ) ) /* update cached calculated permissions */
elm - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
2019-07-17 19:37:18 +02:00
2019-07-23 10:37:56 +02:00
if ( elm - > currentChannel = = channel ) {
2019-07-17 19:37:18 +02:00
elm - > updateChannelClientProperties ( true , true ) ;
2019-07-23 10:37:56 +02:00
} else if ( update_view ) {
unique_lock client_channel_lock ( this - > channel_lock ) ;
auto elm_channel = elm - > currentChannel ;
if ( elm_channel ) {
deque < ChannelId > deleted ;
for ( const auto & update_entry : elm - > channels - > update_channel_path ( l_channel , this - > server - > channelTree - > findLinkedChannel ( elm - > currentChannel - > channelId ( ) ) ) ) {
if ( update_entry . first )
elm - > notifyChannelShow ( update_entry . second - > channel ( ) , update_entry . second - > previous_channel ) ;
else deleted . push_back ( update_entry . second - > channelId ( ) ) ;
}
if ( ! deleted . empty ( ) )
elm - > notifyChannelHide ( deleted , false ) ; /* we've locked the tree before */
}
2019-07-17 19:37:18 +02:00
}
2019-07-23 10:37:56 +02:00
elm - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
2019-07-17 19:37:18 +02:00
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelClientAddPerm ( Command & cmd ) {
2019-07-23 10:37:56 +02:00
CMD_REF_SERVER ( server_ref ) ;
2019-07-17 19:37:18 +02:00
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return { findError ( " parameter_invalid " ) , " Invalid manager db id " } ;
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > server , cmd [ " cldbid " ] ) ;
PERM_CHECKR ( permission : : i_client_permission_modify_power , this - > server - > calculatePermission ( permission : : PERMTEST_ORDERED , cmd [ " cldbid " ] , permission : : i_client_needed_permission_modify_power , ClientType : : CLIENT_TEAMSPEAK , nullptr ) , true ) ;
2019-07-23 10:37:56 +02:00
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
if ( ! channel ) return { ErrorType : : VSError } ;
2019-07-17 19:37:18 +02:00
auto maxValue = this - > getPermissionGrantValue ( permission : : PERMTEST_ORDERED , permission : : i_permission_modify_power , this - > currentChannel ) ;
bool ignoreGrant = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_permission_modify_power_ignore , 1 , this - > currentChannel ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto onlineClientInstances = this - > server - > findClientsByCldbId ( cmd [ " cldbid " ] ) ;
2019-07-23 10:37:56 +02:00
bool update_view = false ;
2019-07-17 19:37:18 +02:00
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & val > maxValue )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( grant ) {
mgr - > set_channel_permission ( permType , channel - > channelId ( ) , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : do_nothing , permission : : v2 : : set_value ) ;
} else {
mgr - > set_channel_permission ( permType , channel - > channelId ( ) , { cmd [ index ] [ " permvalue " ] , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing , cmd [ index ] [ " permskip " ] ? 1 : 0 , cmd [ index ] [ " permnegated " ] ? 1 : 0 ) ;
2019-07-23 10:37:56 +02:00
update_view = permType = = permission : : b_channel_ignore_view_power | | permType = = permission : : i_channel_view_power ;
2019-07-17 19:37:18 +02:00
}
}
if ( ! onlineClientInstances . empty ( ) )
for ( const auto & elm : onlineClientInstances ) {
if ( elm - > update_cached_permissions ( ) ) /* update cached calculated permissions */
elm - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
2019-07-23 10:37:56 +02:00
if ( elm - > currentChannel = = channel ) {
2019-07-17 19:37:18 +02:00
elm - > updateChannelClientProperties ( true , true ) ;
2019-07-23 10:37:56 +02:00
} else if ( update_view ) {
unique_lock client_channel_lock ( this - > channel_lock ) ;
auto elm_channel = elm - > currentChannel ;
if ( elm_channel ) {
deque < ChannelId > deleted ;
for ( const auto & update_entry : elm - > channels - > update_channel_path ( l_channel , this - > server - > channelTree - > findLinkedChannel ( elm - > currentChannel - > channelId ( ) ) ) ) {
if ( update_entry . first )
elm - > notifyChannelShow ( update_entry . second - > channel ( ) , update_entry . second - > previous_channel ) ;
else deleted . push_back ( update_entry . second - > channelId ( ) ) ;
}
if ( ! deleted . empty ( ) )
elm - > notifyChannelHide ( deleted , false ) ; /* we've locked the tree before */
}
2019-07-17 19:37:18 +02:00
}
2019-07-23 10:37:56 +02:00
elm - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
2019-07-17 19:37:18 +02:00
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientDbInfo ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
PERM_CHECKR ( permission : : b_virtualserver_client_dbinfo , 1 , true ) ;
deque < ClientDbId > cldbids ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + )
cldbids . push_back ( cmd [ index ] [ " cldbid " ] ) ;
auto basic = serverInstance - > databaseHelper ( ) - > queryDatabaseInfo ( this - > server , cldbids ) ;
if ( basic . empty ( ) ) return { findError ( " database_empty_result " ) , " empty! " } ;
auto allow_ip = this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_remoteaddress_view ) , 1 ) ;
Command res ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyclientdbinfo " : " " ) ;
size_t index = 0 ;
for ( const auto & info : basic ) {
res [ index ] [ " client_base64HashClientUID " ] = hex : : hex ( base64 : : validate ( info - > uniqueId ) ? base64 : : decode ( info - > uniqueId ) : info - > uniqueId , ' a ' , ' q ' ) ;
res [ index ] [ " client_unique_identifier " ] = info - > uniqueId ;
res [ index ] [ " client_nickname " ] = info - > lastName ;
res [ index ] [ " client_database_id " ] = info - > cldbid ;
res [ index ] [ " client_created " ] = chrono : : duration_cast < chrono : : seconds > ( info - > created . time_since_epoch ( ) ) . count ( ) ;
res [ index ] [ " client_lastconnected " ] = chrono : : duration_cast < chrono : : seconds > ( info - > lastjoin . time_since_epoch ( ) ) . count ( ) ;
res [ index ] [ " client_totalconnections " ] = info - > connections ;
res [ index ] [ " client_database_id " ] = info - > cldbid ;
auto props = serverInstance - > databaseHelper ( ) - > loadClientProperties ( this - > server , info - > cldbid , ClientType : : CLIENT_TEAMSPEAK ) ;
if ( allow_ip )
res [ index ] [ " client_lastip " ] = ( * props ) [ property : : CONNECTION_CLIENT_IP ] . as < string > ( ) ;
else
res [ index ] [ " client_lastip " ] = " hidden " ;
res [ index ] [ " client_icon_id " ] = ( * props ) [ property : : CLIENT_ICON_ID ] . as < string > ( ) ;
res [ index ] [ " client_badges " ] = ( * props ) [ property : : CLIENT_BADGES ] . as < string > ( ) ;
res [ index ] [ " client_version " ] = ( * props ) [ property : : CLIENT_VERSION ] . as < string > ( ) ;
res [ index ] [ " client_platform " ] = ( * props ) [ property : : CLIENT_PLATFORM ] . as < string > ( ) ;
res [ index ] [ " client_hwid " ] = ( * props ) [ property : : CLIENT_HARDWARE_ID ] . as < string > ( ) ;
res [ index ] [ " client_total_bytes_downloaded " ] = ( * props ) [ property : : CLIENT_TOTAL_BYTES_DOWNLOADED ] . as < string > ( ) ;
res [ index ] [ " client_total_bytes_uploaded " ] = ( * props ) [ property : : CLIENT_TOTAL_BYTES_UPLOADED ] . as < string > ( ) ;
res [ index ] [ " client_month_bytes_downloaded " ] = ( * props ) [ property : : CLIENT_MONTH_BYTES_DOWNLOADED ] . as < string > ( ) ;
res [ index ] [ " client_month_bytes_uploaded " ] = ( * props ) [ property : : CLIENT_MONTH_BYTES_DOWNLOADED ] . as < string > ( ) ;
res [ index ] [ " client_description " ] = ( * props ) [ property : : CLIENT_DESCRIPTION ] . as < string > ( ) ;
res [ index ] [ " client_flag_avatar " ] = ( * props ) [ property : : CLIENT_FLAG_AVATAR ] . as < string > ( ) ;
res [ index ] [ " client_month_online_time " ] = ( * props ) [ property : : CLIENT_MONTH_ONLINE_TIME ] . as < string > ( ) ;
res [ index ] [ " client_total_online_time " ] = ( * props ) [ property : : CLIENT_TOTAL_ONLINE_TIME ] . as < string > ( ) ;
index + + ;
}
this - > sendCommand ( res ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientDBDelete ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
PERM_CHECKR ( permission : : b_client_delete_dbproperties , 1 , true ) ;
ClientDbId id = cmd [ " cldbid " ] ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , id ) ) return { findError ( " database_empty_result " ) , " " } ;
serverInstance - > databaseHelper ( ) - > deleteClient ( this - > server , id ) ;
return CommandResult : : Success ;
}
struct DBFindArgs {
int index = 0 ;
bool full = false ;
bool ip = false ;
Command cmd { " " } ;
} ;
CommandResult ConnectedClient : : handleCommandClientDBFind ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
PERM_CHECKR ( permission : : b_virtualserver_client_dbsearch , 1 , true ) ;
bool uid = cmd . hasParm ( " uid " ) ;
string pattern = cmd [ " pattern " ] ;
DBFindArgs args { } ;
args . cmd = Command ( this - > getType ( ) = = CLIENT_QUERY ? " " : " notifyclientdbfind " ) ;
args . full = cmd . hasParm ( " details " ) ;
args . ip = this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_remoteaddress_view ) , 1 ) ;
auto res = sql : : command ( this - > sql , string ( ) + " SELECT * FROM `clients` WHERE `serverId` = :sid AND ` " + ( uid ? " clientUid " : " lastName " ) + " ` LIKE ' " + pattern + " ' LIMIT 50 " , variable { " :sid " , this - > server - > getServerId ( ) } ) . query (
[ & ] ( DBFindArgs * ptr , int len , char * * values , char * * names ) {
for ( int index = 0 ; index < len ; index + + )
if ( strcmp ( names [ index ] , " cldbid " ) = = 0 )
ptr - > cmd [ ptr - > index ] [ " cldbid " ] = values [ index ] ;
else if ( strcmp ( names [ index ] , " clientUid " ) = = 0 & & ptr - > full )
ptr - > cmd [ ptr - > index ] [ " client_unique_identifier " ] = values [ index ] ;
else if ( strcmp ( names [ index ] , " lastConnect " ) = = 0 & & ptr - > full )
ptr - > cmd [ ptr - > index ] [ " client_lastconnected " ] = values [ index ] ;
else if ( strcmp ( names [ index ] , " connections " ) = = 0 & & ptr - > full )
ptr - > cmd [ ptr - > index ] [ " client_totalconnections " ] = values [ index ] ;
else if ( strcmp ( names [ index ] , " lastName " ) = = 0 & & ptr - > full )
ptr - > cmd [ ptr - > index ] [ " client_nickname " ] = values [ index ] ;
if ( ptr - > full ) {
auto props = serverInstance - > databaseHelper ( ) - > loadClientProperties ( this - > server , ptr - > cmd [ ptr - > index ] [ " cldbid " ] , ClientType : : CLIENT_TEAMSPEAK ) ;
if ( props ) {
if ( ptr - > ip ) {
ptr - > cmd [ ptr - > index ] [ " client_lastip " ] = ( * props ) [ property : : CONNECTION_CLIENT_IP ] . as < string > ( ) ;
} else {
ptr - > cmd [ ptr - > index ] [ " client_lastip " ] = " hidden " ;
}
ptr - > cmd [ ptr - > index ] [ " client_badges " ] = ( * props ) [ property : : CLIENT_BADGES ] . as < string > ( ) ;
ptr - > cmd [ ptr - > index ] [ " client_version " ] = ( * props ) [ property : : CLIENT_VERSION ] . as < string > ( ) ;
ptr - > cmd [ ptr - > index ] [ " client_platform " ] = ( * props ) [ property : : CLIENT_PLATFORM ] . as < string > ( ) ;
ptr - > cmd [ ptr - > index ] [ " client_hwid " ] = ( * props ) [ property : : CLIENT_HARDWARE_ID ] . as < string > ( ) ;
}
}
ptr - > index + + ;
return 0 ;
} , & args ) ;
auto pf = LOG_SQL_CMD ;
pf ( res ) ;
if ( args . index = = 0 ) return { findError ( " database_empty_result " ) , " " } ;
this - > sendCommand ( args . cmd ) ;
return CommandResult : : Success ;
}
CommandResult 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 = this - > permission_granted ( this - > cached_permission_value ( permission : : b_client_remoteaddress_view ) , 1 ) ;
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 ;
auto client = this - > server - > findClient ( client_id ) ;
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 ) )
res [ result_index ] [ key . type ( ) . name ] = key . value ( ) ;
if ( view_remote )
res [ result_index ] [ " connection_client_ip " ] = client - > properties ( ) [ property : : CONNECTION_CLIENT_IP ] . as < string > ( ) ;
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 { findError ( " client_invalid_id " ) , " invalid client id " } ;
else
return CommandResult : : Success ;
}
CommandResult 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 { findError ( " database_empty_result " ) , " " } ;
this - > sendCommand ( res ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandVersion ( Command & ) {
CMD_RESET_IDLE ;
Command res ( " " ) ;
res [ " version " ] = build : : version ( ) - > string ( false ) ;
res [ " build_count " ] = build : : buildCount ( ) ;
res [ " build " ] = duration_cast < seconds > ( build : : version ( ) - > timestamp . time_since_epoch ( ) ) . count ( ) ;
# ifdef WINDOWS
res [ " platform " ] = " Windows " ;
# else
res [ " platform " ] = " Linux " ;
# endif
this - > sendCommand ( res ) ;
return CommandResult : : Success ;
}
//cid=%d password=%s
CommandResult ConnectedClient : : handleCommandVerifyChannelPassword ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
std : : shared_ptr < BasicChannel > channel = ( this - > server ? this - > server - > channelTree : serverInstance - > getChannelTree ( ) . get ( ) ) - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
std : : string password = cmd [ " password " ] ;
if ( ! channel - > passwordMatch ( password , false ) ) return { findError ( " server_invalid_password " ) , " " } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandVerifyServerPassword ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
std : : string password = cmd [ " password " ] ;
if ( ! this - > server - > verifyServerPassword ( password , false ) ) return { findError ( " server_invalid_password " ) , " " } ;
return CommandResult : : Success ;
}
//msgid=2 cluid=IkBXingb46\/z1Q3hhMvJEweb3lw= subject=The\sSubject timestamp=1512224138 flag_read=0
//notifymessagelist msgid=2 cluid=IkBXingb46\/z1Q3hhMvJEweb3lw= subject=The\sSubject timestamp=1512224138 flag_read=0
CommandResult ConnectedClient : : handleCommandMessageList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto msgList = this - > server - > letters - > avariableLetters ( this - > getUid ( ) ) ;
if ( msgList . empty ( ) ) return { findError ( " database_empty_result " ) , " no letters avaraible " } ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifymessagelist " : " " ) ;
int index = 0 ;
for ( const auto & elm : msgList ) {
notify [ index ] [ " msgid " ] = elm - > id ;
notify [ index ] [ " cluid " ] = elm - > sender ;
notify [ index ] [ " subject " ] = elm - > subject ;
notify [ index ] [ " timestamp " ] = duration_cast < seconds > ( elm - > created . time_since_epoch ( ) ) . count ( ) ;
notify [ index ] [ " flag_read " ] = elm - > read ;
index + + ;
}
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
//messageadd cluid=ePHuXhcai9nk\/4Fd\/xkxrokvnNk= subject=Test message=Message
CommandResult ConnectedClient : : handleCommandMessageAdd ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
CACHED_PERM_CHECK ( permission : : b_client_offline_textmessage_send , 1 , true ) ;
this - > server - > letters - > createLetter ( this - > getUid ( ) , cmd [ " cluid " ] , cmd [ " subject " ] , cmd [ " message " ] ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandMessageGet ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 10 ) ;
auto letter = this - > server - > letters - > getFullLetter ( cmd [ " msgid " ] ) ;
//msgid=2 cluid=IkBXingb46\/z1Q3hhMvJEweb3lw= subject=The\sSubject message=The\sbody timestamp=1512224138
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifymessage " : " " ) ;
notify [ " msgid " ] = cmd [ " msgid " ] ;
notify [ " cluid " ] = letter - > sender ;
notify [ " subject " ] = letter - > subject ;
notify [ " message " ] = letter - > message ;
notify [ " timestamp " ] = duration_cast < seconds > ( letter - > created . time_since_epoch ( ) ) . count ( ) ;
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandMessageUpdateFlag ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
this - > server - > letters - > updateReadFlag ( cmd [ " msgid " ] , cmd [ " flag " ] ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandMessageDel ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
this - > server - > letters - > deleteLetter ( cmd [ " msgid " ] ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPermGet ( Command & cmd ) {
CMD_RESET_IDLE ;
CACHED_PERM_CHECK ( permission : : b_client_permissionoverview_own , 1 , true ) ;
Command res ( " " ) ;
deque < permission : : PermissionType > requrested ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
permission : : PermissionType permType = permission : : unknown ;
if ( cmd [ index ] . has ( " permid " ) )
permType = cmd [ index ] [ " permid " ] . as < permission : : PermissionType > ( ) ;
else if ( cmd [ index ] . has ( " permsid " ) )
permType = permission : : resolvePermissionData ( cmd [ index ] [ " permsid " ] . as < string > ( ) ) - > type ;
if ( permission : : resolvePermissionData ( permType ) - > type = = permission : : PermissionType : : unknown ) return { findError ( " parameter_invalid " ) , " could not resolve permission " } ;
requrested . push_back ( permType ) ;
}
int index = 0 ;
for ( const auto & entry : this - > permissionValues ( permission : : PERMTEST_ORDERED , requrested , this - > currentChannel ) ) {
res [ index ] [ " permsid " ] = permission : : resolvePermissionData ( entry . first ) - > name ;
res [ index ] [ " permid " ] = entry . first ;
res [ index + + ] [ " permvalue " ] = entry . second ;
}
this - > sendCommand ( res ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPermIdGetByName ( Command & cmd ) {
auto found = permission : : resolvePermissionData ( cmd [ " permsid " ] . as < string > ( ) ) ;
Command res ( " " ) ;
res [ " permid " ] = found - > type ;
this - > sendCommand ( res ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPermFind ( Command & cmd ) {
struct PermissionEntry {
permission : : PermissionType permission_type ;
permission : : PermissionValue permission_value ;
permission : : PermissionSqlType type ;
GroupId group_id ;
ChannelId channel_id ;
ClientDbId client_id ;
bool negate ;
bool skip ;
} ;
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
PERM_CHECKR ( permission : : b_virtualserver_permission_find , 1 , true ) ;
deque < pair < pair < string , permission : : PermissionType > , bool > > permissions ;
std : : shared_ptr < permission : : PermissionTypeEntry > permission ;
for ( size_t index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
bool granted = false ;
if ( cmd [ index ] . has ( " permid " ) ) {
permission = permission : : resolvePermissionData ( ( permission : : PermissionType ) ( cmd [ index ] [ " permid " ] . as < permission : : PermissionType > ( ) & ( ~ PERM_ID_GRANT ) ) ) ;
granted = ( cmd [ index ] [ " permid " ] . as < permission : : PermissionType > ( ) & PERM_ID_GRANT ) > 0 ;
if ( permission - > type = = permission : : PermissionType : : unknown )
return { findError ( " parameter_invalid " ) , " could not resolve permission (id= " + cmd [ index ] [ " permid " ] . string ( ) + " ) " } ;
} else if ( cmd [ index ] . has ( " permsid " ) ) {
permission = permission : : resolvePermissionData ( cmd [ index ] [ " permsid " ] . as < string > ( ) ) ;
granted = permission - > grant_name = = cmd [ index ] [ " permsid " ] . as < string > ( ) ;
if ( permission - > type = = permission : : PermissionType : : unknown )
return { findError ( " parameter_invalid " ) , " could not resolve permission (id= " + cmd [ index ] [ " permid " ] . string ( ) + " ) " } ;
} else {
continue ;
}
permissions . emplace_back ( pair < pair < string , permission : : PermissionType > , bool > { { permission - > name , permission - > type } , granted } ) ;
}
if ( permissions . empty ( ) )
return { findError ( " database_empty_result " ) } ;
map < string , uint8_t > flags ;
map < string , permission : : PermissionType > quick_mapping ;
string query_string ;
for ( const auto & entry : permissions ) {
if ( flags [ entry . first . first ] = = 0 ) {
quick_mapping [ entry . first . first ] = entry . first . second ;
query_string + = string ( query_string . empty ( ) ? " " : " OR " ) + " `permId` = ' " + entry . first . first + " ' " ;
}
flags [ entry . first . first ] | = entry . second ? 2 : 1 ;
}
deque < unique_ptr < PermissionEntry > > entries ;
//`serverId` INT NOT NULL, `type` INT, `id` INT, `channelId` INT, `permId` VARCHAR(" UNKNOWN_KEY_LENGTH "), `value` INT, `grant` INT
sql : : command ( this - > sql , " SELECT `permId`, `type`, `id`, `channelId`, `value`, `grant`, `flag_skip`, `flag_negate` FROM `permissions` WHERE `serverId` = :sid AND ( " + query_string + " ) AND `type` != :playlist " ,
variable { " :sid " , this - > server - > getServerId ( ) } ,
variable { " :playlist " , permission : : SQL_PERM_PLAYLIST }
) . query ( [ & ] ( int length , string * values , string * columns ) {
permission : : PermissionSqlType type = permission : : SQL_PERM_GROUP ;
uint64_t id = 0 ;
ChannelId channel_id = 0 ;
permission : : PermissionValue value = 0 ,
granted_value = 0 ;
string permission_name ;
bool negate = false , skip = false ;
for ( int index = 0 ; index < length ; index + + ) {
try {
if ( columns [ index ] = = " type " )
type = static_cast < permission : : PermissionSqlType > ( stoll ( values [ index ] ) ) ;
else if ( columns [ index ] = = " permId " )
permission_name = values [ index ] ;
else if ( columns [ index ] = = " id " )
id = static_cast < uint64_t > ( stoll ( values [ index ] ) ) ;
else if ( columns [ index ] = = " channelId " )
channel_id = static_cast < ChannelId > ( stoll ( values [ index ] ) ) ;
else if ( columns [ index ] = = " value " )
value = static_cast < permission : : PermissionValue > ( stoll ( values [ index ] ) ) ;
else if ( columns [ index ] = = " grant " )
granted_value = static_cast < permission : : PermissionValue > ( stoll ( values [ index ] ) ) ;
else if ( columns [ index ] = = " flag_negate " )
negate = ! values [ index ] . empty ( ) & & stol ( values [ index ] ) = = 1 ;
else if ( columns [ index ] = = " flag_skip " )
skip = ! values [ index ] . empty ( ) & & stol ( values [ index ] ) = = 1 ;
} catch ( std : : exception & ex ) {
debugMessage ( this - > getServerId ( ) , " [{}] 'permfind' iterates over invalid permission entry. Key: {}, Value: {}, Error: {} " , CLIENT_STR_LOG_PREFIX , columns [ index ] , values [ index ] , ex . what ( ) ) ;
return 0 ;
}
}
/* value */
if ( ( flags [ permission_name ] & 0x1 ) > 0 & & value > 0 ) {
auto result = make_unique < PermissionEntry > ( ) ;
result - > permission_type = quick_mapping [ permission_name ] ;
result - > permission_value = value ;
result - > type = type ;
result - > channel_id = channel_id ;
result - > negate = negate ;
result - > skip = skip ;
if ( type = = permission : : SQL_PERM_GROUP ) {
auto gr = this - > server - > groups - > findGroup ( id ) ;
if ( ! gr ) return 0 ;
result - > group_id = id ;
if ( gr - > target ( ) = = GROUPTARGET_CHANNEL )
result - > channel_id = 1 ;
} else if ( type = = permission : : SQL_PERM_USER ) {
result - > client_id = id ;
}
if ( result )
entries . push_back ( std : : move ( result ) ) ;
}
/* granted */
if ( ( flags [ permission_name ] & 0x2 ) > 0 & & granted_value > 0 ) {
auto result = make_unique < PermissionEntry > ( ) ;
result - > permission_type = ( permission : : PermissionType ) ( quick_mapping [ permission_name ] | PERM_ID_GRANT ) ;
result - > permission_value = granted_value ;
result - > type = type ;
result - > channel_id = channel_id ;
result - > negate = negate ;
result - > skip = skip ;
if ( type = = permission : : SQL_PERM_GROUP ) {
auto gr = this - > server - > groups - > findGroup ( id ) ;
if ( ! gr ) return 0 ;
result - > group_id = id ;
if ( gr - > target ( ) = = GROUPTARGET_CHANNEL )
result - > channel_id = 1 ;
} else if ( type = = permission : : SQL_PERM_USER ) {
result - > client_id = id ;
}
if ( result )
entries . push_back ( std : : move ( result ) ) ;
}
return 0 ;
} ) ;
struct CommandPerm {
permission : : PermissionType p ;
permission : : PermissionValue v ;
int64_t id1 ;
int64_t id2 ;
uint8_t t ;
} ;
std : : deque < CommandPerm > perms ;
perms . resize ( entries . size ( ) ) ;
size_t index = 0 ;
for ( const auto & entry : entries ) {
auto & perm = perms [ index + + ] ;
perm . p = entry - > permission_type ;
perm . v = entry - > permission_value ;
if ( entry - > type = = permission : : SQL_PERM_USER ) {
if ( entry - > channel_id > 0 ) {
perm . id1 = entry - > client_id ;
perm . id2 = entry - > channel_id ;
perm . t = 4 ; /* client channel */
} else {
perm . id1 = 0 ;
perm . id2 = entry - > client_id ;
perm . t = 1 ; /* client server */
}
} else if ( entry - > type = = permission : : SQL_PERM_CHANNEL ) {
perm . id1 = 0 ;
perm . id2 = entry - > channel_id ;
perm . t = 2 ; /* channel permission */
} else if ( entry - > type = = permission : : SQL_PERM_GROUP ) {
if ( entry - > channel_id > 0 ) {
perm . id1 = entry - > group_id ;
perm . id2 = 0 ;
perm . t = 3 ; /* channel group */
} else {
perm . id1 = entry - > group_id ;
perm . id2 = 0 ;
perm . t = 0 ; /* server group */
}
}
}
sort ( perms . begin ( ) , perms . end ( ) , [ ] ( const CommandPerm & a , const CommandPerm & b ) {
if ( a . t < b . t ) return true ;
else if ( b . t < a . t ) return false ;
if ( a . id1 < b . id1 ) return true ;
else if ( b . id1 < a . id1 ) return false ;
if ( a . id2 < b . id2 ) return true ;
else if ( b . id2 < a . id2 ) return false ;
if ( a . p < b . p ) return true ;
else if ( b . p < a . p ) return false ;
return & a > & b ;
} ) ;
Command result ( " " ) ;
index = 0 ;
// http://yat.qa/ressourcen/server-query-kommentare/#permfind
for ( const auto & e : perms ) {
result [ index ] [ " p " ] = e . p ;
result [ index ] [ " v " ] = e . v ;
result [ index ] [ " id1 " ] = e . id1 ;
result [ index ] [ " id2 " ] = e . id2 ;
result [ index ] [ " t " ] = e . t ;
index + + ;
}
if ( index = = 0 ) return { findError ( " database_empty_result " ) } ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
/*
* - Alle rechte der aktuellen server gruppen vom client
* - Alle client rechte | channel cleint rechte
* - Alle rechte des channels
*/
CommandResult ConnectedClient : : handleCommandPermOverview ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto client_dbid = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > getServer ( ) , client_dbid ) ) return { findError ( " client_invalid_id " ) } ;
if ( client_dbid = = this - > getClientDatabaseId ( ) ) {
CACHED_PERM_CHECK ( permission : : b_client_permissionoverview_own , 1 , true ) ;
} else {
CACHED_PERM_CHECK ( permission : : b_client_permissionoverview_view , 1 , true ) ;
}
string channel_query , perm_query ;
auto channel = this - > server ? this - > server - > channelTree - > findChannel ( cmd [ " cid " ] ) : serverInstance - > getChannelTree ( ) - > findChannel ( cmd [ " cid " ] ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) } ;
auto server_groups = this - > server - > getGroupManager ( ) - > getServerGroups ( client_dbid , ClientType : : CLIENT_TEAMSPEAK ) ;
auto channel_group = this - > server - > getGroupManager ( ) - > getChannelGroup ( client_dbid , channel , true ) ;
auto permission_manager = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > getServer ( ) , client_dbid ) ;
Command result ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifypermoverview " : " " ) ;
size_t index = 0 ;
result [ " cldbid " ] = client_dbid ;
result [ " cid " ] = channel - > channelId ( ) ;
if ( cmd [ " return_code " ] . size ( ) > 0 )
result [ " return_code " ] = cmd [ " return_code " ] . string ( ) ;
for ( const auto & server_group : server_groups ) {
auto permission_manager = server_group - > group - > permissions ( ) ;
for ( const auto & permission_data : permission_manager - > permissions ( ) ) {
auto & permission = std : : get < 1 > ( permission_data ) ;
if ( permission . flags . value_set ) {
result [ index ] [ " t " ] = 0 ; /* server group */
result [ index ] [ " id1 " ] = server_group - > group - > groupId ( ) ;
result [ index ] [ " id2 " ] = 0 ;
result [ index ] [ " p " ] = std : : get < 0 > ( permission_data ) ;
result [ index ] [ " v " ] = permission . values . value ;
result [ index ] [ " n " ] = permission . flags . negate ;
result [ index ] [ " s " ] = permission . flags . skip ;
index + + ;
}
if ( permission . flags . skip ) {
result [ index ] [ " t " ] = 0 ; /* server group */
result [ index ] [ " id1 " ] = server_group - > group - > groupId ( ) ;
result [ index ] [ " id2 " ] = 0 ;
result [ index ] [ " p " ] = ( std : : get < 0 > ( permission_data ) | PERM_ID_GRANT ) ;
result [ index ] [ " v " ] = permission . values . grant ;
result [ index ] [ " n " ] = false ;
result [ index ] [ " s " ] = false ;
index + + ;
}
}
}
{
for ( const auto & permission_data : permission_manager - > permissions ( ) ) {
auto & permission = std : : get < 1 > ( permission_data ) ;
if ( permission . flags . value_set ) {
result [ index ] [ " t " ] = 1 ; /* client */
result [ index ] [ " id1 " ] = client_dbid ;
result [ index ] [ " id2 " ] = 0 ;
result [ index ] [ " p " ] = std : : get < 0 > ( permission_data ) ;
result [ index ] [ " v " ] = permission . values . value ;
result [ index ] [ " n " ] = permission . flags . negate ;
result [ index ] [ " s " ] = permission . flags . skip ;
index + + ;
}
if ( permission . flags . skip ) {
result [ index ] [ " t " ] = 1 ; /* client */
result [ index ] [ " id1 " ] = client_dbid ;
result [ index ] [ " id2 " ] = 0 ;
result [ index ] [ " p " ] = ( std : : get < 0 > ( permission_data ) | PERM_ID_GRANT ) ;
result [ index ] [ " v " ] = permission . values . grant ;
result [ index ] [ " n " ] = false ;
result [ index ] [ " s " ] = false ;
index + + ;
}
}
}
{
auto permission_manager = channel - > permissions ( ) ;
for ( const auto & permission_data : permission_manager - > permissions ( ) ) {
auto & permission = std : : get < 1 > ( permission_data ) ;
if ( permission . flags . value_set ) {
result [ index ] [ " t " ] = 2 ; /* server channel */
result [ index ] [ " id1 " ] = channel - > channelId ( ) ;
result [ index ] [ " id2 " ] = 0 ;
result [ index ] [ " p " ] = std : : get < 0 > ( permission_data ) ;
result [ index ] [ " v " ] = permission . values . value ;
result [ index ] [ " n " ] = permission . flags . negate ;
result [ index ] [ " s " ] = permission . flags . skip ;
index + + ;
}
if ( permission . flags . skip ) {
result [ index ] [ " t " ] = 2 ; /* server channel */
result [ index ] [ " id1 " ] = channel - > channelId ( ) ;
result [ index ] [ " id2 " ] = 0 ;
result [ index ] [ " p " ] = ( std : : get < 0 > ( permission_data ) | PERM_ID_GRANT ) ;
result [ index ] [ " v " ] = permission . values . grant ;
result [ index ] [ " n " ] = false ;
result [ index ] [ " s " ] = false ;
index + + ;
}
}
}
{
auto permission_manager = channel_group - > group - > permissions ( ) ;
for ( const auto & permission_data : permission_manager - > permissions ( ) ) {
auto & permission = std : : get < 1 > ( permission_data ) ;
if ( permission . flags . value_set ) {
result [ index ] [ " t " ] = 3 ; /* channel group */
result [ index ] [ " id1 " ] = channel_group - > channelId ;
result [ index ] [ " id2 " ] = channel_group - > group - > groupId ( ) ;
result [ index ] [ " p " ] = std : : get < 0 > ( permission_data ) ;
result [ index ] [ " v " ] = permission . values . value ;
result [ index ] [ " n " ] = permission . flags . negate ;
result [ index ] [ " s " ] = permission . flags . skip ;
index + + ;
}
if ( permission . flags . skip ) {
result [ index ] [ " t " ] = 3 ; /* channel group */
result [ index ] [ " id1 " ] = channel_group - > channelId ;
result [ index ] [ " id2 " ] = channel_group - > group - > groupId ( ) ;
result [ index ] [ " p " ] = ( std : : get < 0 > ( permission_data ) | PERM_ID_GRANT ) ;
result [ index ] [ " v " ] = permission . values . grant ;
result [ index ] [ " n " ] = false ;
result [ index ] [ " s " ] = false ;
index + + ;
}
}
}
{
for ( const auto & permission_data : permission_manager - > channel_permissions ( ) ) {
auto & permission = std : : get < 2 > ( permission_data ) ;
if ( permission . flags . value_set ) {
result [ index ] [ " t " ] = 4 ; /* client channel */
result [ index ] [ " id1 " ] = std : : get < 1 > ( permission_data ) ;
result [ index ] [ " id2 " ] = client_dbid ;
result [ index ] [ " p " ] = std : : get < 0 > ( permission_data ) ;
result [ index ] [ " v " ] = permission . values . value ;
result [ index ] [ " n " ] = permission . flags . negate ;
result [ index ] [ " s " ] = permission . flags . skip ;
index + + ;
}
if ( permission . flags . skip ) {
result [ index ] [ " t " ] = 1 ; /* client */
result [ index ] [ " id1 " ] = std : : get < 1 > ( permission_data ) ;
result [ index ] [ " id2 " ] = client_dbid ;
result [ index ] [ " p " ] = ( std : : get < 0 > ( permission_data ) | PERM_ID_GRANT ) ;
result [ index ] [ " v " ] = permission . values . grant ;
result [ index ] [ " n " ] = false ;
result [ index ] [ " s " ] = false ;
index + + ;
}
}
}
if ( index = = 0 ) return { findError ( " database_empty_result " ) , " " } ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelFind ( Command & cmd ) {
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 ? this - > server - > channelTree : serverInstance - > getChannelTree ( ) . get ( ) ) - > channels ( ) ) {
string name = cl - > name ( ) ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , : : tolower ) ;
if ( name . find ( pattern ) ! = std : : string : : npos ) {
res [ index ] [ " cid " ] = cl - > channelId ( ) ;
res [ index ] [ " channel_name " ] = cl - > name ( ) ;
index + + ;
}
}
if ( index = = 0 ) return { findError ( " database_empty_result " ) , " " } ;
this - > sendCommand ( res ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandChannelInfo ( Command & cmd ) {
std : : shared_ptr < BasicChannel > channel = ( this - > server ? this - > server - > channelTree : serverInstance - > getChannelTree ( ) . get ( ) ) - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return { findError ( " channel_invalid_id " ) , " Cant resolve channel " } ;
Command res ( " " ) ;
for ( const auto & prop : channel - > properties ( ) . list_properties ( property : : FLAG_CHANNEL_VIEW | property : : FLAG_CHANNEL_VARIABLE , this - > getType ( ) = = CLIENT_TEAMSPEAK ? property : : FLAG_NEW : ( uint16_t ) 0 ) )
res [ prop . type ( ) . name ] = prop . value ( ) ;
res [ " seconds_empty " ] = channel - > emptySince ( ) ;
res [ " pid " ] = res [ " cpid " ] . string ( ) ;
this - > sendCommand ( res ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandClientSetServerQueryLogin ( Command & cmd ) {
PERM_CHECKR ( permission : : b_client_create_modify_serverquery_login , 1 , true ) ;
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 { findError ( " client_not_logged_in " ) } ;
}
} else {
serverInstance - > getQueryServer ( ) - > create_query_account ( cmd [ " client_login_name " ] , this - > getServerId ( ) , this - > getUid ( ) , password ) ;
}
Command res ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifyclientserverqueryloginpassword " : " " ) ;
res [ " client_login_password " ] = password ;
this - > sendCommand ( res ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandComplainAdd ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ClientDbId target = cmd [ " tcldbid " ] ;
std : : string msg = cmd [ " message " ] ;
auto cl = this - > server - > findClientsByCldbId ( target ) ;
if ( cl . empty ( ) ) return { findError ( " client_invalid_id " ) , " invalid client id " } ;
PERM_CHECKR ( permission : : i_client_complain_power , cl [ 0 ] - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_needed_complain_power ) , true ) ;
/*
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( target ) )
return { findError ( " client_invalid_id " ) , " invalid database id " } ;
*/
for ( const auto & elm : this - > server - > complains - > findComplainsFromTarget ( target ) )
if ( elm - > invoker = = this - > getClientDatabaseId ( ) )
return { findError ( " database_duplicate_entry " ) , " you already send a complain " } ;
if ( ! this - > server - > complains - > createComplain ( target , this - > getClientDatabaseId ( ) , msg ) ) return { findError ( " vs_critical " ) , " could not create complains " } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandComplainList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
CACHED_PERM_CHECK ( permission : : b_client_complain_list , 1 , true ) ;
ClientDbId id = cmd [ 0 ] . has ( " tcldbid " ) ? cmd [ " tcldbid " ] . as < ClientDbId > ( ) : 0 ;
auto list = id = = 0 ? this - > server - > complains - > complains ( ) : this - > server - > complains - > findComplainsFromTarget ( id ) ;
if ( list . empty ( ) ) return { findError ( " database_empty_result " ) , " empty! " } ;
deque < ClientDbId > nameQuery ;
for ( const auto & elm : list ) {
if ( std : : find ( nameQuery . begin ( ) , nameQuery . end ( ) , elm - > invoker ) = = nameQuery . end ( ) )
nameQuery . push_back ( elm - > invoker ) ;
if ( std : : find ( nameQuery . begin ( ) , nameQuery . end ( ) , elm - > target ) = = nameQuery . end ( ) )
nameQuery . push_back ( elm - > target ) ;
}
auto dbInfo = serverInstance - > databaseHelper ( ) - > queryDatabaseInfo ( this - > server , nameQuery ) ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifycomplainlist " : " " ) ;
int index = 0 ;
for ( const auto & elm : list ) {
result [ index ] [ " tcldbid " ] = elm - > target ;
result [ index ] [ " tname " ] = " unknown " ;
result [ index ] [ " fcldbid " ] = elm - > invoker ;
result [ index ] [ " fname " ] = " unknown " ;
result [ index ] [ " message " ] = elm - > reason ;
result [ index ] [ " timestamp " ] = chrono : : duration_cast < chrono : : seconds > ( elm - > created . time_since_epoch ( ) ) . count ( ) ;
for ( const auto & e : dbInfo ) {
if ( e - > cldbid = = elm - > target )
result [ index ] [ " tname " ] = e - > lastName ;
if ( e - > cldbid = = elm - > invoker )
result [ index ] [ " fname " ] = e - > lastName ;
}
index + + ;
}
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandComplainDel ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ClientDbId tid = cmd [ " tcldbid " ] ;
ClientDbId fid = cmd [ " fcldbid " ] ;
shared_ptr < ComplainEntry > entry ;
for ( const auto & elm : this - > server - > complains - > findComplainsFromTarget ( tid ) )
if ( elm - > invoker = = fid ) {
entry = elm ;
break ;
}
if ( ! entry ) return { findError ( " database_empty_result " ) , " empty! " } ;
if ( entry - > invoker = = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : b_client_complain_delete_own , 1 , true ) ;
else
CACHED_PERM_CHECK ( permission : : b_client_complain_delete , 1 , true ) ;
this - > server - > complains - > deleteComplain ( entry ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandComplainDelAll ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
CACHED_PERM_CHECK ( permission : : b_client_complain_delete , 1 , true ) ;
ClientDbId tid = cmd [ " tcldbid " ] ;
if ( ! this - > server - > complains - > deleteComplainsFromTarget ( tid ) ) return { findError ( " database_empty_result " ) , " empty! " } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandMusicBotCreate ( Command & cmd ) {
if ( ! config : : music : : enabled ) return { findError ( " music_disabled " ) } ;
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
if ( this - > server - > musicManager - > max_bots ( ) ! = - 1 & & this - > server - > musicManager - > max_bots ( ) < = this - > server - > musicManager - > current_bot_count ( ) ) {
if ( config : : license - > isPremium ( ) )
return { findError ( " music_limit_reached " ) , " " } ;
else
return { findError ( " music_limit_reached " ) , " You reached the server music bot limit. You could increase this limit by extend your server with a premium license. " } ;
}
auto permissions_list = this - > permissionValues ( permission : : PERMTEST_ORDERED , {
permission : : i_client_music_limit ,
permission : : b_client_music_create_permanent ,
permission : : b_client_music_create_semi_permanent ,
permission : : b_client_music_create_temporary ,
permission : : i_channel_join_power ,
permission : : i_client_music_delete_power ,
permission : : i_client_music_create_modify_max_volume
} , this - > currentChannel ) ;
auto permissions = map < permission : : PermissionType , permission : : PermissionValue > ( permissions_list . begin ( ) , permissions_list . end ( ) ) ;
auto max_bots = permissions [ permission : : i_client_music_limit ] ;
if ( max_bots > = 0 ) {
auto ownBots = this - > server - > musicManager - > listBots ( this - > getClientDatabaseId ( ) ) ;
if ( ownBots . size ( ) > max_bots )
return { findError ( " music_client_limit_reached " ) , " " } ;
}
MusicClient : : Type : : value create_type ;
if ( cmd [ 0 ] . has ( " type " ) ) {
create_type = cmd [ " type " ] . as < MusicClient : : Type : : value > ( ) ;
switch ( create_type ) {
case MusicClient : : Type : : PERMANENT :
if ( permissions [ permission : : b_client_music_create_permanent ] ! = 1 )
return CommandResultPermissionError { permission : : b_client_music_create_permanent } ;
break ;
case MusicClient : : Type : : SEMI_PERMANENT :
if ( permissions [ permission : : b_client_music_create_semi_permanent ] ! = 1 )
return CommandResultPermissionError { permission : : b_client_music_create_semi_permanent } ;
break ;
case MusicClient : : Type : : TEMPORARY :
if ( permissions [ permission : : b_client_music_create_temporary ] ! = 1 )
return CommandResultPermissionError { permission : : b_client_music_create_temporary } ;
break ;
default :
return { ErrorType : : VSError } ;
}
} else {
if ( permissions [ permission : : b_client_music_create_permanent ] = = 1 )
create_type = MusicClient : : Type : : PERMANENT ;
else if ( permissions [ permission : : b_client_music_create_semi_permanent ] = = 1 )
create_type = MusicClient : : Type : : SEMI_PERMANENT ;
else if ( permissions [ permission : : b_client_music_create_temporary ] = = 1 )
create_type = MusicClient : : Type : : TEMPORARY ;
else
return CommandResultPermissionError { permission : : b_client_music_create_temporary } ;
}
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
auto channel = cmd [ 0 ] . has ( " cid " ) ? this - > server - > channelTree - > findChannel ( cmd [ " cid " ] ) : this - > currentChannel ;
if ( ! channel ) {
if ( cmd [ 0 ] . has ( " cid " ) ) return { findError ( " client_invalid_id " ) } ;
} else {
CHANNEL_PERMISSION_TEST ( permission : : i_channel_description_view_power , permission : : i_channel_needed_description_view_power , channel , false ) ;
auto permission_granted = this - > calculate_permission_value ( permission : : i_channel_join_power , channel - > channelId ( ) ) ;
if ( ! channel - > permission_granted ( permission : : i_channel_needed_join_power , permission_granted , false ) )
channel = nullptr ;
}
if ( ! channel ) {
channel = this - > server - > channelTree - > getDefaultChannel ( ) ;
}
auto bot = this - > server - > musicManager - > createBot ( this - > getClientDatabaseId ( ) ) ;
if ( ! bot ) return { ErrorType : : VSError , " " } ;
bot - > set_bot_type ( create_type ) ;
{
if ( permissions [ permission : : i_client_music_create_modify_max_volume ] > 0 ) {
auto max_volume = min ( 100 , max ( 0 , permissions [ permission : : i_client_music_create_modify_max_volume ] ) ) ;
if ( max_volume > = 0 )
bot - > volume_modifier ( max_volume / 100.f ) ;
}
}
this - > selectedBot = bot ;
{
server_channel_lock . unlock ( ) ;
unique_lock server_channel_w_lock ( this - > server - > channel_tree_lock ) ;
this - > server - > client_move (
bot ,
channel ,
nullptr ,
" music bot created " ,
ViewReasonId : : VREASON_USER_ACTION ,
false ,
server_channel_w_lock
) ;
}
if ( permissions [ permission : : i_client_music_delete_power ] > 0 ) {
bot - > clientPermissions - > set_permission ( permission : : i_client_music_needed_delete_power , { permissions [ permission : : i_client_music_delete_power ] , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
}
Command notify ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifymusiccreated " : " " ) ;
notify [ " bot_id " ] = bot - > getClientDatabaseId ( ) ;
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandMusicBotDelete ( Command & cmd ) {
if ( ! config : : music : : enabled ) return { findError ( " music_disabled " ) } ;
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return { findError ( " music_invalid_id " ) } ;
bool permPower = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : i_client_music_delete_power , bot - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_delete_power ) ) ;
if ( bot - > getOwner ( ) ! = this - > getClientDatabaseId ( ) ) {
if ( ! permPower ) return CommandResultPermissionError { permission : : i_client_music_delete_power } ;
}
this - > server - > musicManager - > deleteBot ( bot ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandMusicBotSetSubscription ( ts : : Command & cmd ) {
if ( ! config : : music : : enabled ) return { findError ( " music_disabled " ) } ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot & & cmd [ " bot_id " ] . as < ClientDbId > ( ) ! = 0 ) return { findError ( " music_invalid_id " ) } ;
{
auto old_bot = this - > subscribed_bot . lock ( ) ;
if ( old_bot )
old_bot - > remove_subscriber ( _this . lock ( ) ) ;
}
if ( bot ) {
bot - > add_subscriber ( _this . lock ( ) ) ;
this - > subscribed_bot = bot ;
}
return CommandResult : : Success ;
}
void apply_song ( Command & command , const std : : shared_ptr < ts : : music : : SongInfo > & element , int index = 0 ) {
if ( ! element ) return ;
command [ index ] [ " song_id " ] = element ? element - > getSongId ( ) : 0 ;
command [ index ] [ " song_url " ] = element ? element - > getUrl ( ) : " " ;
command [ index ] [ " song_invoker " ] = element ? element - > getInvoker ( ) : 0 ;
command [ index ] [ " song_loaded " ] = false ;
auto entry = dynamic_pointer_cast < ts : : music : : PlayableSong > ( element ) ;
if ( entry ) {
auto data = entry - > song_loaded_data ( ) ;
command [ index ] [ " song_loaded " ] = entry - > song_loaded ( ) & & data ;
if ( entry - > song_loaded ( ) & & data ) {
command [ index ] [ " song_title " ] = data - > title ;
command [ index ] [ " song_description " ] = data - > description ;
command [ index ] [ " song_thumbnail " ] = data - > thumbnail ;
command [ index ] [ " song_length " ] = data - > length . count ( ) ;
}
}
}
CommandResult ConnectedClient : : handleCommandMusicBotPlayerInfo ( Command & cmd ) {
if ( ! config : : music : : enabled ) return { findError ( " music_disabled " ) } ;
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return { findError ( " music_invalid_id " ) } ;
Command result ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifymusicplayerinfo " : " " ) ;
result [ " bot_id " ] = bot - > getClientDatabaseId ( ) ;
result [ " player_state " ] = ( int ) bot - > player_state ( ) ;
if ( bot - > current_player ( ) ) {
result [ " player_buffered_index " ] = bot - > current_player ( ) - > bufferedUntil ( ) . count ( ) ;
result [ " player_replay_index " ] = bot - > current_player ( ) - > currentIndex ( ) . count ( ) ;
result [ " player_max_index " ] = bot - > current_player ( ) - > length ( ) . count ( ) ;
result [ " player_seekable " ] = bot - > current_player ( ) - > seek_supported ( ) ;
result [ " player_title " ] = bot - > current_player ( ) - > songTitle ( ) ;
result [ " player_description " ] = bot - > current_player ( ) - > songDescription ( ) ;
} else {
result [ " player_buffered_index " ] = 0 ;
result [ " player_replay_index " ] = 0 ;
result [ " player_max_index " ] = 0 ;
result [ " player_seekable " ] = 0 ;
result [ " player_title " ] = " " ;
result [ " player_description " ] = " " ;
}
apply_song ( result , bot - > current_song ( ) ) ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandMusicBotPlayerAction ( Command & cmd ) {
if ( ! config : : music : : enabled ) return { findError ( " music_disabled " ) } ;
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return { findError ( " music_invalid_id " ) } ;
PERM_CHECK_CHANNELR ( permission : : i_client_music_play_power , bot - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_play_power , bot - > currentChannel ) , this - > currentChannel , true ) ;
if ( cmd [ " action " ] = = 0 ) {
bot - > stopMusic ( ) ;
} else if ( cmd [ " action " ] = = 1 ) {
bot - > playMusic ( ) ;
} else if ( cmd [ " action " ] = = 2 ) {
bot - > player_pause ( ) ;
} else if ( cmd [ " action " ] = = 3 ) {
bot - > forwardSong ( ) ;
} else if ( cmd [ " action " ] = = 4 ) {
bot - > rewindSong ( ) ;
} else if ( cmd [ " action " ] = = 5 ) {
if ( ! bot - > current_player ( ) ) return { findError ( " music_no_player " ) } ;
bot - > current_player ( ) - > forward ( : : music : : PlayerUnits ( cmd [ " units " ] . as < int64_t > ( ) ) ) ;
} else if ( cmd [ " action " ] = = 6 ) {
if ( ! bot - > current_player ( ) ) return { findError ( " music_no_player " ) } ;
bot - > current_player ( ) - > rewind ( : : music : : PlayerUnits ( cmd [ " units " ] . as < int64_t > ( ) ) ) ;
} else return { findError ( " music_invalid_action " ) } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistList ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto self_dbid = this - > getClientDatabaseId ( ) ;
auto playlist_view_power = this - > cached_permission_value ( permission : : i_playlist_view_power ) ;
auto playlists = this - > server - > musicManager - > playlists ( ) ;
playlists . erase ( find_if ( playlists . begin ( ) , playlists . end ( ) , [ & ] ( const shared_ptr < music : : PlayablePlaylist > & playlist ) {
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] = = self_dbid )
return false ;
auto needed_view_power = playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_view_power ) ;
return ! this - > permission_granted ( playlist_view_power , needed_view_power , false ) ;
} ) , playlists . end ( ) ) ;
if ( playlists . empty ( ) )
return { ErrorType : : DBEmpty } ;
Command notify ( this - > notify_response_command ( " notifyplaylistlist " ) ) ;
size_t index = 0 ;
for ( const auto & entry : playlists ) {
notify [ index ] [ " playlist_id " ] = entry - > playlist_id ( ) ;
auto bot = entry - > current_bot ( ) ;
notify [ index ] [ " playlist_bot_id " ] = bot ? bot - > getClientDatabaseId ( ) : 0 ;
notify [ index ] [ " playlist_title " ] = entry - > properties ( ) [ property : : PLAYLIST_TITLE ] . value ( ) ;
notify [ index ] [ " playlist_type " ] = entry - > properties ( ) [ property : : PLAYLIST_TYPE ] . value ( ) ;
notify [ index ] [ " playlist_owner_dbid " ] = entry - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] . value ( ) ;
notify [ index ] [ " playlist_owner_name " ] = entry - > properties ( ) [ property : : PLAYLIST_OWNER_NAME ] . value ( ) ;
notify [ index ] [ " needed_power_modify " ] = entry - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_modify_power ) ;
notify [ index ] [ " needed_power_permission_modify " ] = entry - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_permission_modify_power ) ;
notify [ index ] [ " needed_power_delete " ] = entry - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_delete_power ) ;
notify [ index ] [ " needed_power_song_add " ] = entry - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_song_needed_add_power ) ;
notify [ index ] [ " needed_power_song_move " ] = entry - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_song_needed_move_power ) ;
notify [ index ] [ " needed_power_song_remove " ] = entry - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_song_needed_remove_power ) ;
index + + ;
}
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistCreate ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
CACHED_PERM_CHECK ( permission : : b_playlist_create , 1 , true ) ;
{
auto max_playlists = this - > cached_permission_value ( permission : : i_max_playlists ) ;
if ( max_playlists ! = permNotGranted ) {
auto playlists = ref_server - > musicManager - > find_playlists_by_client ( this - > getClientDatabaseId ( ) ) ;
if ( ! this - > permission_granted ( this - > cached_permission_value ( permission : : i_max_playlists ) , playlists . size ( ) , false ) )
return CommandResultPermissionError { permission : : i_max_playlists } ;
}
}
auto playlist = ref_server - > musicManager - > create_playlist ( this - > getClientDatabaseId ( ) , this - > getDisplayName ( ) ) ;
if ( ! playlist ) return { ErrorType : : VSError } ;
playlist - > properties ( ) [ property : : PLAYLIST_TYPE ] = music : : Playlist : : Type : : GENERAL ;
{
auto max_songs = this - > cached_permission_value ( permission : : i_max_playlist_size ) ;
if ( max_songs ! = permNotGranted )
playlist - > properties ( ) [ property : : PLAYLIST_MAX_SONGS ] = max_songs ;
}
playlist - > permissions ( ) - > setPermission ( permission : : i_playlist_song_needed_remove_power , this - > cached_permission_value ( permission : : i_playlist_song_remove_power ) , nullptr ) ;
playlist - > permissions ( ) - > setPermission ( permission : : i_playlist_needed_delete_power , this - > cached_permission_value ( permission : : i_playlist_delete_power ) , nullptr ) ;
playlist - > permissions ( ) - > setPermission ( permission : : i_playlist_needed_modify_power , this - > cached_permission_value ( permission : : i_playlist_modify_power ) , nullptr ) ;
playlist - > permissions ( ) - > setPermission ( permission : : i_playlist_needed_permission_modify_power , this - > cached_permission_value ( permission : : i_playlist_permission_modify_power ) , nullptr ) ;
Command notify ( this - > notify_response_command ( " notifyplaylistcreated " ) ) ;
notify [ " playlist_id " ] = playlist - > playlist_id ( ) ;
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistDelete ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_delete_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_delete_power ) ) ;
string error ;
if ( ! ref_server - > musicManager - > delete_playlist ( playlist - > playlist_id ( ) , error ) ) {
logError ( this - > getServerId ( ) , " Failed to delete playlist with id {}. Error: {} " , playlist - > playlist_id ( ) , error ) ;
return { ErrorType : : VSError , error } ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistInfo ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_view_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_view_power ) ) ;
Command notify ( this - > notify_response_command ( " notifyplaylistinfo " ) ) ;
for ( const auto & property : playlist - > properties ( ) . list_properties ( property : : FLAG_PLAYLIST_VARIABLE ) ) {
notify [ property . type ( ) . name ] = property . value ( ) ;
}
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistEdit ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_modify_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_modify_power ) ) ;
deque < pair < shared_ptr < property : : PropertyDescription > , string > > properties ;
for ( const auto & key : cmd [ 0 ] . keys ( ) ) {
if ( key = = " playlist_id " ) continue ;
if ( key = = " return_code " ) continue ;
auto property = property : : info < property : : PlaylistProperties > ( key ) ;
if ( * property = = property : : PLAYLIST_UNDEFINED ) {
logError ( this - > getServerId ( ) , R " ([{}] Tried to edit a not existing playlist property " { } " to " { } " ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
if ( ( property - > flags & property : : FLAG_USER_EDITABLE ) = = 0 ) {
logError ( this - > getServerId ( ) , " [{}] Tried to change a playlist property which is not changeable. (Key: {}, Value: \" {} \" ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
if ( ! property - > validate_input ( cmd [ key ] . as < string > ( ) ) ) {
logError ( this - > getServerId ( ) , " [{}] Tried to change a playlist property to an invalid value. (Key: {}, Value: \" {} \" ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
if ( * property = = property : : PLAYLIST_CURRENT_SONG_ID ) {
auto song_id = cmd [ key ] . as < SongId > ( ) ;
auto song = song_id > 0 ? playlist - > find_song ( song_id ) : nullptr ;
if ( song_id ! = 0 & & ! song )
return { findError ( " playlist_invalid_song_id " ) } ;
} else if ( * property = = property : : PLAYLIST_MAX_SONGS ) {
auto value = cmd [ key ] . as < int32_t > ( ) ;
auto max_value = this - > cached_permission_value ( permission : : i_max_playlist_size ) ;
if ( ! this - > permission_granted ( max_value , value , false ) )
return CommandResultPermissionError { permission : : i_max_playlist_size } ;
}
properties . emplace_back ( property , key ) ;
}
for ( const auto & property : properties ) {
if ( * property . first = = property : : PLAYLIST_CURRENT_SONG_ID ) {
playlist - > set_current_song ( cmd [ property . second ] ) ;
continue ;
}
playlist - > properties ( ) [ property . first ] = cmd [ property . second ] . string ( ) ;
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistPermList ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : b_virtualserver_playlist_permission_list , 1 , true ) ;
auto permissions = playlist - > permissions ( ) - > listPermissions ( PERM_FLAG_PUBLIC ) ;
if ( permissions . empty ( ) )
return { ErrorType : : VSError } ;
Command result ( this - > notify_response_command ( " notifyplaylistpermlist " ) ) ;
int index = 0 ;
result [ " playlist_id " ] = playlist - > playlist_id ( ) ;
for ( const auto & elm : permissions ) {
if ( elm - > hasValue ( ) ) {
result [ index ] [ " permid " ] = elm - > type - > type ;
result [ index ] [ " permvalue " ] = elm - > value ;
result [ index ] [ " permnegated " ] = elm - > flag_negate ;
result [ index ] [ " permskip " ] = elm - > flag_skip ;
index + + ;
}
if ( elm - > hasGrant ( ) ) {
result [ index ] [ " permid " ] = ( uint16_t ) ( elm - > type - > type | PERM_ID_GRANT ) ;
result [ index ] [ " permvalue " ] = elm - > granted ;
result [ index ] [ " permnegated " ] = 0 ;
result [ index ] [ " permskip " ] = 0 ;
index + + ;
}
}
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistAddPerm ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_permission_modify_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_permission_modify_power ) , true ) ;
auto maxValue = this - > getPermissionGrantValue ( permission : : i_permission_modify_power , this - > currentChannel ) ;
bool ignoreGrant = this - > permission_granted ( this - > cached_permission_value ( permission : : b_permission_modify_power_ignore ) , 1 , true ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & val > maxValue )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( grant ) {
playlist - > permissions ( ) - > setPermissionGranted ( permType , cmd [ index ] [ " permvalue " ] , nullptr ) ;
} else {
playlist - > permissions ( ) - > setPermission ( permType , cmd [ index ] [ " permvalue " ] , nullptr , cmd [ index ] [ " permnegated " ] , cmd [ index ] [ " permskip " ] ) ;
}
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistDelPerm ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_permission_modify_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_permission_modify_power ) , true ) ;
bool ignoreGrant = this - > permission_granted ( this - > cached_permission_value ( permission : : b_permission_modify_power_ignore ) , 1 , true ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
if ( ! ignoreGrant & & ! this - > permissionGrantGranted ( permission : : PERMTEST_ORDERED , permType , 1 , this - > currentChannel ) )
return CommandResultPermissionError { permission : : i_permission_modify_power } ;
if ( grant ) {
playlist - > permissions ( ) - > setPermissionGranted ( permType , permNotGranted , nullptr ) ;
} else {
playlist - > permissions ( ) - > deletePermission ( permType , nullptr ) ;
}
}
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistSongList ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_view_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_view_power ) ) ;
auto songs = playlist - > list_songs ( ) ;
if ( songs . empty ( ) )
return { ErrorType : : DBEmpty } ;
Command notify ( this - > notify_response_command ( " notifyplaylistsonglist " ) ) ;
notify [ " playlist_id " ] = playlist - > playlist_id ( ) ;
size_t index = 0 ;
for ( const auto & song : songs ) {
notify [ index ] [ " song_id " ] = song - > id ;
notify [ index ] [ " song_invoker " ] = song - > invoker ;
notify [ index ] [ " song_previous_song_id " ] = song - > previous_song_id ;
notify [ index ] [ " song_url " ] = song - > url ;
notify [ index ] [ " song_url_loader " ] = song - > url_loader ;
notify [ index ] [ " song_loaded " ] = song - > loaded ;
notify [ index ] [ " song_metadata " ] = song - > metadata ;
index + + ;
}
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistSongAdd ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_song_add_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_song_needed_add_power ) ) ;
if ( ! cmd [ 0 ] . has ( " invoker " ) )
cmd [ " invoker " ] = " " ;
if ( ! cmd [ 0 ] . has ( " previous " ) ) {
auto songs = playlist - > list_songs ( ) ;
if ( songs . empty ( ) )
cmd [ " previous " ] = " 0 " ;
else
cmd [ " previous " ] = songs . back ( ) - > id ;
}
auto song = playlist - > add_song ( _this . lock ( ) , cmd [ " url " ] , cmd [ " invoker " ] , cmd [ " previous " ] ) ;
if ( ! song ) return { ErrorType : : VSError } ;
Command notify ( this - > notify_response_command ( " notifyplaylistsongadd " ) ) ;
notify [ " song_id " ] = song - > id ;
this - > sendCommand ( notify ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistSongReorder ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_song_move_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_song_needed_move_power ) ) ;
SongId song_id = cmd [ " song_id " ] ;
SongId previous_id = cmd [ " song_previous_song_id " ] ;
auto song = playlist - > find_song ( song_id ) ;
if ( ! song ) return { findError ( " playlist_invalid_song_id " ) } ;
if ( ! playlist - > reorder_song ( song_id , previous_id ) )
return { ErrorType : : VSError } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPlaylistSongRemove ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist ) return { findError ( " playlist_invalid_id " ) } ;
if ( playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_song_remove_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_song_needed_remove_power ) ) ;
SongId song_id = cmd [ " song_id " ] ;
auto song = playlist - > find_song ( song_id ) ;
if ( ! song ) return { findError ( " playlist_invalid_song_id " ) } ;
if ( ! playlist - > delete_song ( song_id ) )
return { ErrorType : : VSError } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandMusicBotQueueList ( Command & cmd ) {
return CommandResult : : NotImplemented ; //FIXME
/*
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return { findError ( " music_invalid_id " ) } ;
PERM_CHECK_CHANNELR ( permission : : i_client_music_info , bot - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_info , bot - > currentChannel ) , this - > currentChannel , true ) ;
bool bulked = cmd . hasParm ( " bulk " ) | | cmd . hasParm ( " balk " ) | | cmd . hasParm ( " pipe " ) | | cmd . hasParm ( " bar " ) | | cmd . hasParm ( " paypal " ) ;
int command_index = 0 ;
Command notify ( this - > getExternalType ( ) = = CLIENT_VOICE ? " notifymusicqueueentry " : " " ) ;
{
auto history = bot - > queue ( ) - > history ( ) ;
for ( int index = history . size ( ) ; index > 0 ; index - - ) {
if ( ! bulked )
notify = Command ( this - > getExternalType ( ) = = CLIENT_VOICE ? " notifymusicqueueentry " : " " ) ;
apply_song ( notify , history [ index - 1 ] , command_index ) ;
notify [ command_index ] [ " queue_index " ] = - index ;
if ( ! bulked )
this - > sendCommand ( notify ) ;
else
command_index + + ;
}
}
{
if ( ! bulked )
notify = Command ( this - > getExternalType ( ) = = CLIENT_VOICE ? " notifymusicqueueentry " : " " ) ;
auto song = bot - > queue ( ) - > currentSong ( ) ;
apply_song ( notify , song , command_index ) ;
notify [ command_index ] [ " queue_index " ] = 0 ;
if ( ! bulked )
this - > sendCommand ( notify ) ;
else if ( song )
command_index + + ;
}
{
auto queue = bot - > queue ( ) - > queueEntries ( ) ;
for ( int index = 0 ; index < queue . size ( ) ; index + + ) {
if ( ! bulked )
notify = Command ( this - > getExternalType ( ) = = CLIENT_VOICE ? " notifymusicqueueentry " : " " ) ;
apply_song ( notify , queue [ index ] , command_index ) ;
notify [ command_index ] [ " queue_index " ] = index + 1 ;
if ( ! bulked )
this - > sendCommand ( notify ) ;
else
command_index + + ;
}
}
debugMessage ( this - > getServerId ( ) , " Send: {} " , notify . build ( ) ) ;
if ( bulked ) {
if ( command_index > 0 ) {
this - > sendCommand ( notify ) ;
} else return { ErrorType : : DBEmpty } ;
}
if ( this - > getExternalType ( ) = = CLIENT_VOICE ) {
Command notify ( " notifymusicqueuefinish " ) ;
notify [ " bot_id " ] = bot - > getClientDatabaseId ( ) ;
this - > sendCommand ( notify ) ;
}
return CommandResult : : Success ;
*/
}
CommandResult ConnectedClient : : handleCommandMusicBotQueueAdd ( Command & cmd ) {
return CommandResult : : NotImplemented ; //FIXME
/*
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return { findError ( " music_invalid_id " ) } ;
PERM_CHECK_CHANNELR ( permission : : i_client_music_play_power , bot - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_play_power , bot - > currentChannel ) , this - > currentChannel , true ) ;
MusicClient : : loader_t loader ;
auto & type = cmd [ 0 ] [ " type " ] ;
if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = 0 ) | | type . as < string > ( ) = = " yt " ) {
loader = bot - > ytLoader ( this - > getServer ( ) ) ;
} else if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = 1 ) | | type . as < string > ( ) = = " ffmpeg " ) {
loader = bot - > ffmpegLoader ( this - > getServer ( ) ) ;
} else if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = 2 ) | | type . as < string > ( ) = = " channel " ) {
loader = bot - > channelLoader ( this - > getServer ( ) ) ;
} else if ( ( type . castable < int > ( ) & & type . as < int > ( ) = = - 1 ) | | type . as < string > ( ) = = " any " ) {
loader = bot - > providerLoader ( this - > getServer ( ) , " " ) ;
}
if ( ! loader ) return { findError ( " music_invalid_action " ) } ;
auto entry = bot - > queue ( ) - > insertEntry ( cmd [ " url " ] , _this . lock ( ) , loader ) ;
if ( ! entry ) return { ErrorType : : VSError } ;
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > client ) {
client - > notifyMusicQueueAdd ( bot , entry , bot - > queue ( ) - > queueEntries ( ) . size ( ) - 1 , _this . lock ( ) ) ;
} ) ;
return CommandResult : : Success ;
*/
}
CommandResult ConnectedClient : : handleCommandMusicBotQueueRemove ( Command & cmd ) {
return CommandResult : : NotImplemented ; //FIXME
/*
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return { findError ( " music_invalid_id " ) } ;
PERM_CHECK_CHANNELR ( permission : : i_client_music_play_power , bot - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_play_power , bot - > currentChannel ) , this - > currentChannel , true ) ;
std : : deque < std : : shared_ptr < music : : SongInfo > > songs ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto entry = bot - > queue ( ) - > find_queue ( cmd [ " song_id " ] ) ;
if ( ! entry ) {
if ( cmd . hasParm ( " skip_error " ) ) continue ;
return { ErrorType : : DBEmpty } ;
}
songs . push_back ( move ( entry ) ) ;
}
for ( const auto & entry : songs )
bot - > queue ( ) - > deleteEntry ( dynamic_pointer_cast < music : : PlayableSong > ( entry ) ) ;
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > client ) {
client - > notifyMusicQueueRemove ( bot , songs , _this . lock ( ) ) ;
} ) ;
return CommandResult : : Success ;
*/
}
CommandResult ConnectedClient : : handleCommandMusicBotQueueReorder ( Command & cmd ) {
return CommandResult : : NotImplemented ; //FIXME
/*
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = this - > server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return { findError ( " music_invalid_id " ) } ;
PERM_CHECK_CHANNELR ( permission : : i_client_music_play_power , bot - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_play_power , bot - > currentChannel ) , this - > currentChannel , true ) ;
auto entry = bot - > queue ( ) - > find_queue ( cmd [ " song_id " ] ) ;
if ( ! entry ) return { ErrorType : : DBEmpty } ;
auto order = bot - > queue ( ) - > changeOrder ( entry , cmd [ " index " ] ) ;
if ( order < 0 ) return { ErrorType : : VSError } ;
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > client ) {
client - > notifyMusicQueueOrderChange ( bot , entry , order , _this . lock ( ) ) ;
} ) ;
return CommandResult : : Success ;
*/
}
CommandResult ConnectedClient : : handleCommandMusicBotPlaylistAssign ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto bot = ref_server - > musicManager - > findBotById ( cmd [ " bot_id " ] ) ;
if ( ! bot ) return { findError ( " music_invalid_id " ) } ;
if ( bot - > getOwner ( ) ! = this - > getClientDatabaseId ( ) )
PERM_CHECK_CHANNELR ( permission : : i_client_music_play_power , bot - > permissionValue ( permission : : PERMTEST_ORDERED , permission : : i_client_music_needed_play_power , bot - > currentChannel ) , this - > currentChannel , true ) ;
auto playlist = ref_server - > musicManager - > find_playlist ( cmd [ " playlist_id " ] ) ;
if ( ! playlist & & cmd [ " playlist_id " ] ! = 0 ) return { findError ( " playlist_invalid_id " ) } ;
if ( ref_server - > musicManager - > find_bot_by_playlist ( playlist ) )
return { findError ( " playlist_already_in_use " ) } ;
if ( playlist & & playlist - > properties ( ) [ property : : PLAYLIST_OWNER_DBID ] ! = this - > getClientDatabaseId ( ) )
CACHED_PERM_CHECK ( permission : : i_playlist_view_power , playlist - > permissions ( ) - > getPermissionValue ( permission : : i_playlist_needed_view_power ) ) ;
if ( ! ref_server - > musicManager - > assign_playlist ( bot , playlist ) )
return { ErrorType : : VSError } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandHelp ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
PERM_CHECKR ( permission : : b_serverinstance_help_view , 1 , false ) ;
string command = cmd [ 0 ] . has ( " command " ) ? cmd [ " command " ] . as < string > ( ) : " " ;
if ( command . empty ( ) )
for ( const auto & key : cmd [ 0 ] . keys ( ) ) {
command = key ;
break ;
}
if ( command . empty ( ) )
command = " help " ;
std : : transform ( command . begin ( ) , command . end ( ) , command . begin ( ) , : : tolower ) ;
auto file = fs : : u8path ( " commanddocs/ " + command + " .txt " ) ;
if ( ! fs : : exists ( file ) ) return { findError ( " file_not_found " ) , " Could not resolve file " + file . string ( ) } ;
string line ;
ifstream stream ( file ) ;
if ( ! stream ) return { findError ( " file_io_error " ) , " Could not read documentation file " + file . string ( ) } ;
while ( getline ( stream , line ) )
this - > sendCommand ( Command ( line ) ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandPermReset ( ts : : Command & cmd ) {
CMD_REQ_FSERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 50 ) ;
PERM_CHECKR ( permission : : b_virtualserver_permission_reset , 1 , true ) ;
string token ;
if ( ! this - > server - > resetPermissions ( token ) )
return { ErrorType : : VSError , " Could not reset permissions! " } ;
Command result ( " " ) ;
result [ " token " ] = token ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandLogView ( ts : : Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 50 ) ;
auto lagacy = this - > getType ( ) = = CLIENT_TEAMSPEAK | | cmd . hasParm ( " lagacy " ) | | cmd . hasParm ( " legacy " ) ;
string log_path ;
ServerId target_server = cmd [ 0 ] . has ( " instance " ) & & cmd [ " instance " ] . as < bool > ( ) ? ( ServerId ) 0 : this - > getServerId ( ) ;
string server_identifier ;
if ( target_server > 0 )
server_identifier = to_string ( target_server ) ;
else server_identifier = " [A-Z]{0,7} " ;
if ( target_server = = 0 )
PERM_CHECKR ( permission : : b_serverinstance_log_view , 1 , true ) ;
else
PERM_CHECKR ( permission : : b_virtualserver_log_view , 1 , true ) ;
for ( const auto & sink : logger : : logger ( target_server ) - > sinks ( ) ) {
if ( dynamic_pointer_cast < logger : : ColoredFileSink > ( sink ) ) {
log_path = dynamic_pointer_cast < logger : : ColoredFileSink > ( sink ) - > _file_helper . filename ( ) ;
}
}
if ( log_path . empty ( ) )
return { findError ( " file_not_found " ) , " Cant find log file (May log disabled?) " } ;
{ //Replace " within the log path
size_t index = 0 ;
while ( ( index = log_path . find ( ' " ' , index ) ) ! = string : : npos ) {
log_path . replace ( index , 1 , " \\ \" " ) ;
index + = 2 ;
}
}
string command = " cat \" " + log_path + " \" " ;
command + = " | grep -E " ;
command + = " \" \\ ] \\ [.* \\ ]( ){0,6}? " + server_identifier + " \\ | \" " ;
size_t beginpos = cmd [ 0 ] . has ( " begin_pos " ) ? cmd [ " begin_pos " ] . as < size_t > ( ) : 0ULL ; //TODO test it?
size_t file_index = 0 ;
size_t max_lines = cmd [ 0 ] . has ( " lines " ) ? cmd [ " lines " ] . as < size_t > ( ) : 100ULL ; //TODO bounds?
deque < pair < uintptr_t , string > > lines ;
{
debugMessage ( target_server , " Logview command: \" {} \" " , command ) ;
array < char , 1024 > buffer { } ;
string line_buffer ;
std : : shared_ptr < FILE > pipe ( popen ( command . c_str ( ) , " r " ) , pclose ) ;
if ( ! pipe ) return { findError ( " file_io_error " ) , " Could not execute command " } ;
while ( ! feof ( pipe . get ( ) ) ) {
auto read = fread ( buffer . data ( ) , 1 , buffer . size ( ) , pipe . get ( ) ) ;
if ( read > 0 ) {
if ( beginpos = = 0 | | file_index < beginpos ) {
if ( beginpos ! = 0 & & file_index + read > beginpos ) { //We're done we just want to get the size later
line_buffer + = string ( buffer . data ( ) , beginpos - file_index ) ;
lines . push_back ( { file_index , line_buffer } ) ;
if ( lines . size ( ) > max_lines ) lines . pop_front ( ) ;
//debugMessage(LOG_GENERAL, "Final line {}", line_buffer);
line_buffer = " " ;
} else {
line_buffer + = string ( buffer . data ( ) , read ) ;
size_t index ;
size_t length ;
size_t cut_offset = 0 ;
while ( ( index = line_buffer . find ( " \n " ) ) ! = string : : npos | | ( index = line_buffer . find ( " \r " ) ) ! = string : : npos ) {
length = 0 ;
if ( index > 0 ) {
if ( line_buffer [ index - 1 ] = = ' \r ' | | line_buffer [ index - 1 ] = = ' \n ' ) {
length = 2 ;
index - - ;
}
}
if ( length = = 0 ) {
if ( index + 1 < line_buffer . length ( ) ) {
if ( line_buffer [ index + 1 ] = = ' \r ' | | line_buffer [ index + 1 ] = = ' \n ' ) {
length = 2 ;
}
}
}
if ( length = = 0 ) length = 1 ;
//debugMessage(LOG_GENERAL, "Got line {}", line_buffer.substr(0, index));
lines . push_back ( { file_index + cut_offset , line_buffer . substr ( 0 , index ) } ) ;
if ( lines . size ( ) > max_lines ) lines . pop_front ( ) ;
cut_offset + = index + length ;
line_buffer = line_buffer . substr ( index + length ) ;
}
}
}
file_index + = read ;
} else if ( read < 0 ) return { findError ( " file_io_error " ) , " fread(...) returned " + to_string ( read ) + " ( " + to_string ( errno ) + " ) " } ;
}
if ( ! line_buffer . empty ( ) ) {
lines . push_back ( { file_index - line_buffer . length ( ) , line_buffer } ) ;
if ( lines . size ( ) > max_lines ) lines . pop_front ( ) ;
}
}
//last_pos=1558 file_size=1764 l
if ( lines . empty ( ) ) return { ErrorType : : DBEmpty } ;
Command result ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyserverlog " : " " ) ;
result [ " last_pos " ] = lines . front ( ) . first ;
result [ " file_size " ] = file_index ;
if ( ! ( cmd . hasParm ( " reverse " ) & & cmd [ " revers " ] . as < bool > ( ) ) )
std : : reverse ( lines . begin ( ) , lines . end ( ) ) ;
int index = 0 ;
for ( const auto & index_line : lines ) {
auto line = index_line . second ;
//2018-07-15 21:01:46.488639
//TeamSpeak format:
//YYYY-MM-DD hh:mm:ss.millis|{:<8}|{:<14}|{:<3}|....
//2018-07-15 21:01:47.066367|INFO |VirtualServer |1 |listening on 0.0.0.0:9989, [::]:9989
//TeaSpeak:
//[2018-07-15 23:21:47] [ERROR] Timer sql_test tick needs more than 9437 microseconds. Max allowed was 5000 microseconds.
if ( lagacy ) {
string ts = line . substr ( 1 , 19 ) + " .000000| " ;
{
string type = " unknown " ;
auto idx = line . find_first_of ( ' [ ' , 2 ) ;
if ( idx ! = string : : npos ) {
type = line . substr ( idx + 1 , line . find ( ' ] ' , idx + 1 ) - idx - 1 ) ;
}
ts + = type + " | | | " + line . substr ( line . find ( ' | ' ) + 1 ) ;
}
result [ index + + ] [ " l " ] = ts ;
} else {
result [ index + + ] [ " l " ] = line ;
}
}
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandUpdateMyTsId ( ts : : Command & ) {
if ( config : : voice : : suppress_myts_warnings ) return CommandResult : : Success ;
return CommandResult : : NotImplemented ;
}
CommandResult ConnectedClient : : handleCommandUpdateMyTsData ( ts : : Command & ) {
if ( config : : voice : : suppress_myts_warnings ) return CommandResult : : Success ;
return CommandResult : : NotImplemented ;
}
CommandResult ConnectedClient : : handleCommandQueryList ( ts : : Command & cmd ) {
OptionalServerId server_id = EmptyServerId ;
if ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK )
server_id = this - > getServerId ( ) ;
if ( cmd [ 0 ] . has ( " server_id " ) )
server_id = cmd [ " server_id " ] ;
if ( cmd [ 0 ] . has ( " sid " ) )
server_id = cmd [ " sid " ] ;
auto server = server_id = = EmptyServerId ? nullptr : serverInstance - > getVoiceServerManager ( ) - > findServerById ( server_id ) ;
if ( ! server & & server_id ! = EmptyServerId & & server_id ! = 0 )
return { findError ( " server_invalid_id " ) } ;
auto global_list = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_query_list , 1 , nullptr , true , nullptr , server , true ) ;
auto own_list = global_list | | this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_query_list_own , 1 , nullptr , true , nullptr , server , true ) ;
if ( ! own_list & & ! global_list )
return CommandResultPermissionError { permission : : b_client_query_list } ;
auto accounts = serverInstance - > getQueryServer ( ) - > list_query_accounts ( server_id ) ;
if ( ! global_list ) {
accounts . erase ( remove_if ( accounts . begin ( ) , accounts . end ( ) , [ & ] ( const std : : shared_ptr < QueryAccount > & account ) {
return account - > unique_id ! = this - > getUid ( ) ;
} ) , accounts . end ( ) ) ;
}
if ( accounts . empty ( ) )
return { ErrorType : : DBEmpty } ;
Command result ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyquerylist " : " " ) ;
result [ " server_id " ] = server_id ;
result [ " flag_own " ] = own_list ;
result [ " flag_all " ] = global_list ;
size_t index = 0 ;
for ( const auto & account : accounts ) {
result [ index ] [ " client_unique_identifier " ] = account - > unique_id ;
result [ index ] [ " client_login_name " ] = account - > username ;
result [ index ] [ " client_bound_server " ] = account - > bound_server ;
index + + ;
}
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandQueryCreate ( ts : : Command & cmd ) {
OptionalServerId server_id = this - > getServerId ( ) ;
if ( cmd [ 0 ] . has ( " server_id " ) )
server_id = cmd [ " server_id " ] ;
if ( cmd [ 0 ] . has ( " sid " ) )
server_id = cmd [ " sid " ] ;
auto server = server_id = = EmptyServerId ? nullptr : serverInstance - > getVoiceServerManager ( ) - > findServerById ( server_id ) ;
if ( ! server & & server_id ! = EmptyServerId & & server_id ! = 0 )
return { findError ( " server_invalid_id " ) } ;
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_query_create , 1 , nullptr , true , nullptr , server , true ) )
return CommandResultPermissionError { permission : : b_client_query_create } ;
auto username = cmd [ " client_login_name " ] . as < string > ( ) ;
auto password = cmd [ 0 ] . has ( " client_login_password " ) ? cmd [ " client_login_password " ] . as < string > ( ) : " " ;
if ( password . empty ( ) )
password = rnd_string ( QUERY_PASSWORD_LENGTH ) ;
auto account = serverInstance - > getQueryServer ( ) - > find_query_account_by_name ( username ) ;
if ( account ) return { findError ( " query_already_exists " ) } ;
account = serverInstance - > getQueryServer ( ) - > create_query_account ( username , server_id , this - > getUid ( ) , password ) ;
if ( ! account )
return { ErrorType : : VSError } ;
Command result ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyquerycreated " : " " ) ;
result [ " client_unique_identifier " ] = account - > unique_id ;
result [ " client_login_name " ] = account - > username ;
result [ " client_login_password " ] = password ;
result [ " client_bound_server " ] = account - > bound_server ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandQueryDelete ( ts : : Command & cmd ) {
auto username = cmd [ " client_login_name " ] . as < string > ( ) ;
auto account = serverInstance - > getQueryServer ( ) - > find_query_account_by_name ( username ) ;
if ( ! account )
return { findError ( " query_not_exists " ) } ;
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( account - > bound_server ) ;
/* If the server is not existing anymore, we're asking for global permissions
if ( ! server & & account - > bounded_server ! = 0 )
return { findError ( " server_invalid_id " ) } ;
*/
auto delete_all = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_query_delete , 1 , nullptr , true , nullptr , server , true ) ;
auto delete_own = delete_all | | this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_query_delete_own , 1 , nullptr , true , nullptr , server , true ) ;
if ( account - > unique_id = = this - > getUid ( ) ) {
if ( ! delete_own )
return CommandResultPermissionError { permission : : b_client_query_delete_own } ;
} else {
if ( ! delete_all )
return CommandResultPermissionError { permission : : b_client_query_delete } ;
}
if ( account - > unique_id = = " serveradmin " & & account - > username = = " serveradmin " )
return ErrorType : : VSError ;
serverInstance - > getQueryServer ( ) - > delete_query_account ( account ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandQueryRename ( ts : : Command & cmd ) {
auto username = cmd [ " client_login_name " ] . as < string > ( ) ;
auto new_username = cmd [ " client_new_login_name " ] . as < string > ( ) ;
auto account = serverInstance - > getQueryServer ( ) - > find_query_account_by_name ( username ) ;
if ( ! account )
return { findError ( " query_not_exists " ) } ;
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( account - > bound_server ) ;
if ( ! server & & account - > bound_server ! = 0 )
return { findError ( " server_invalid_id " ) } ;
auto rename_all = this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_query_rename , 1 , nullptr , true , nullptr , server , true ) ;
auto rename_own = rename_all | | this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_query_rename_own , 1 , nullptr , true , nullptr , server , true ) ;
if ( account - > unique_id = = this - > getUid ( ) ) {
if ( ! rename_own )
return CommandResultPermissionError { permission : : b_client_query_rename_own } ;
} else {
if ( ! rename_all )
return CommandResultPermissionError { permission : : b_client_query_rename } ;
}
auto target_account = serverInstance - > getQueryServer ( ) - > find_query_account_by_name ( new_username ) ;
if ( target_account ) return { findError ( " query_already_exists " ) } ;
if ( account - > unique_id = = " serveradmin " & & account - > username = = " serveradmin " )
return ErrorType : : VSError ;
if ( ! serverInstance - > getQueryServer ( ) - > rename_query_account ( account , new_username ) )
return { ErrorType : : VSError } ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandQueryChangePassword ( ts : : Command & cmd ) {
auto username = cmd [ " client_login_name " ] . as < string > ( ) ;
auto account = serverInstance - > getQueryServer ( ) - > find_query_account_by_name ( username ) ;
if ( ! account )
return { findError ( " query_not_exists " ) } ;
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( account - > bound_server ) ;
if ( ! server & & account - > bound_server ! = 0 )
return { findError ( " server_invalid_id " ) } ;
auto change_all = this - > permissionGranted ( permission : : PERMTEST_ORDERED , server ? permission : : b_client_query_change_password : permission : : b_client_query_change_password_global , 1 , nullptr , true , nullptr , server , true ) ;
auto change_own = change_all | | this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_query_change_own_password , 1 , nullptr , true , nullptr , server , true ) ;
auto password = cmd [ 0 ] . has ( " client_login_password " ) ? cmd [ " client_login_password " ] . as < string > ( ) : " " ;
if ( password . empty ( ) )
password = rnd_string ( QUERY_PASSWORD_LENGTH ) ;
if ( account - > unique_id = = this - > getUid ( ) ) {
if ( ! change_own )
return CommandResultPermissionError { permission : : b_client_query_change_own_password } ;
} else {
if ( ! change_all )
return CommandResultPermissionError { server ? permission : : b_client_query_change_password : permission : : b_client_query_change_password_global } ;
}
if ( ! serverInstance - > getQueryServer ( ) - > change_query_password ( account , password ) )
return { ErrorType : : VSError } ;
Command result ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyquerypasswordchanges " : " " ) ;
result [ " client_login_name " ] = account - > username ;
result [ " client_login_password " ] = password ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
CommandResult ConnectedClient : : handleCommandDummy_IpChange ( ts : : Command & cmd ) {
CMD_REF_SERVER ( server ) ;
logMessage ( this - > getServerId ( ) , " [{}] Address changed from {} to {} " , CLIENT_STR_LOG_PREFIX , cmd [ " old_ip " ] . string ( ) , cmd [ " new_ip " ] . string ( ) ) ;
if ( geoloc : : provider_vpn & & ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_client_ignore_vpn , 1 ) ) {
auto provider = this - > isAddressV4 ( ) ? geoloc : : provider_vpn - > resolveInfoV4 ( this - > getPeerIp ( ) , true ) : geoloc : : provider_vpn - > resolveInfoV6 ( this - > getPeerIp ( ) , true ) ;
if ( provider ) {
this - > disconnect ( strvar : : transform ( ts : : config : : messages : : kick_vpn , strvar : : StringValue { " provider.name " , provider - > name } , strvar : : StringValue { " provider.website " , provider - > side } ) ) ;
return CommandResult : : Success ;
}
}
string new_country = config : : geo : : countryFlag ;
if ( geoloc : : provider ) {
auto loc = this - > isAddressV4 ( ) ? geoloc : : provider - > resolveInfoV4 ( this - > getPeerIp ( ) , false ) : geoloc : : provider - > resolveInfoV6 ( this - > getPeerIp ( ) , false ) ;
if ( loc ) {
logError ( this - > getServerId ( ) , " [{}] Received new ip location. IP {} traced to {} ({}). " , CLIENT_STR_LOG_PREFIX , this - > getLoggingPeerIp ( ) , loc - > name , loc - > identifier ) ;
this - > properties ( ) [ property : : CLIENT_COUNTRY ] = loc - > identifier ;
server - > notifyClientPropertyUpdates ( _this . lock ( ) , deque < property : : ClientProperties > { property : : CLIENT_COUNTRY } ) ;
new_country = loc - > identifier ;
} else {
logError ( this - > getServerId ( ) , " [{}] Failed to resolve ip location for IP {}. " , CLIENT_STR_LOG_PREFIX , this - > getLoggingPeerIp ( ) ) ;
}
}
return CommandResult : : Success ;
}
2019-07-19 22:55:03 +02:00
//conversationhistory cid=1 [cpw=xxx] [timestamp_begin] [timestamp_end (0 := no end)] [message_count (default 25| max 100)] [-merge]
CommandResult ConnectedClient : : handleCommandConversationHistory ( ts : : Command & command ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
if ( ! command [ 0 ] . has ( " cid " ) | | ! command [ 0 ] [ " cid " ] . castable < ChannelId > ( ) )
return { findError ( " conversation_invalid_id " ) } ;
auto conversation_id = command [ 0 ] [ " cid " ] . as < ChannelId > ( ) ;
/* test if we have access to the conversation */
{
/* test if we're able to see the channel */
{
shared_lock channel_view_lock ( this - > channel_lock ) ;
auto channel = this - > channel_view ( ) - > find_channel ( conversation_id ) ;
if ( ! channel )
return { findError ( " conversation_invalid_id " ) } ;
}
/* test if there is a channel password or join power which denies that we see the conversation */
{
shared_lock channel_view_lock ( ref_server - > channel_tree_lock ) ;
auto channel = ref_server - > getChannelTree ( ) - > findChannel ( conversation_id ) ;
if ( ! channel ) /* should never happen! */
return { findError ( " conversation_invalid_id " ) } ;
if ( ! command [ 0 ] . has ( " cpw " ) )
command [ 0 ] [ " cpw " ] = " " ;
if ( ! channel - > passwordMatch ( command [ " cpw " ] , true ) )
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_channel_join_ignore_password , 1 , channel , true ) )
return { findError ( " channel_invalid_password " ) , " invalid password " } ;
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_channel_ignore_join_power , 1 , channel , true ) ) {
CHANNEL_PERMISSION_TEST ( permission : : i_channel_join_power , permission : : i_channel_needed_join_power , channel , false ) ;
}
}
}
auto conversation_manager = ref_server - > conversation_manager ( ) ;
auto conversation = conversation_manager - > get ( conversation_id ) ;
if ( ! conversation )
return { ErrorType : : DBEmpty } ;
system_clock : : time_point timestamp_begin = system_clock : : now ( ) ;
system_clock : : time_point timestamp_end ;
size_t message_count = 25 ;
if ( command [ 0 ] . has ( " timestamp_begin " ) )
timestamp_begin = system_clock : : time_point { } + milliseconds ( command [ 0 ] [ " timestamp_begin " ] . as < uint64_t > ( ) ) ;
if ( command [ 0 ] . has ( " timestamp_end " ) )
timestamp_end = system_clock : : time_point { } + milliseconds ( command [ 0 ] [ " timestamp_end " ] . as < uint64_t > ( ) ) ;
if ( command [ 0 ] . has ( " message_count " ) )
message_count = command [ 0 ] [ " message_count " ] . as < uint64_t > ( ) ;
if ( timestamp_begin < timestamp_end )
return { findError ( " parameter_invalid " ) } ;
if ( message_count > 100 )
message_count = 100 ;
auto messages = conversation - > message_history ( timestamp_begin , message_count + 1 , timestamp_end ) ; /* query one more to test for more data */
if ( messages . empty ( ) )
return { ErrorType : : DBEmpty } ;
bool more_data = messages . size ( ) > message_count ;
if ( more_data )
messages . pop_back ( ) ;
Command notify ( this - > notify_response_command ( " notifyconversationhistory " ) ) ;
size_t index = 0 ;
size_t length = 0 ;
bool merge = command . hasParm ( " merge " ) ;
2019-07-23 10:37:56 +02:00
for ( auto it = messages . rbegin ( ) ; it ! = messages . rend ( ) ; it + + ) {
2019-07-21 17:02:32 +02:00
if ( index = = 0 ) {
2019-07-19 22:55:03 +02:00
notify [ index ] [ " cid " ] = conversation_id ;
2019-07-21 17:02:32 +02:00
notify [ index ] [ " flag_volatile " ] = conversation - > volatile_only ( ) ;
}
2019-07-19 22:55:03 +02:00
2019-07-23 10:37:56 +02:00
auto & message = * it ;
2019-07-19 22:55:03 +02:00
notify [ index ] [ " timestamp " ] = duration_cast < milliseconds > ( message - > message_timestamp . time_since_epoch ( ) ) . count ( ) ;
notify [ index ] [ " sender_database_id " ] = message - > sender_database_id ;
notify [ index ] [ " sender_unique_id " ] = message - > sender_unique_id ;
notify [ index ] [ " sender_name " ] = message - > sender_name ;
notify [ index ] [ " msg " ] = message - > message ;
length + = message - > message . size ( ) ;
length + = message - > sender_name . size ( ) ;
length + = message - > sender_unique_id . size ( ) ;
if ( length > 1024 * 8 | | ! merge ) {
index = 0 ;
this - > sendCommand ( notify ) ;
notify = Command { this - > notify_response_command ( " notifyconversationhistory " ) } ;
} else
index + + ;
}
if ( index > 0 )
this - > sendCommand ( notify ) ;
if ( more_data )
return { findError ( " conversation_more_data " ) } ;
return CommandResult : : Success ;
}
2019-07-17 19:37:18 +02:00
2019-07-19 22:55:03 +02:00
CommandResult ConnectedClient : : handleCommandConversationFetch ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
Command result ( this - > notify_response_command ( " notifyconversationindex " ) ) ;
size_t result_index = 0 ;
auto conversation_manager = ref_server - > conversation_manager ( ) ;
for ( size_t index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto & bulk = cmd [ index ] ;
if ( ! bulk . has ( " cid " ) | | ! bulk [ " cid " ] . castable < ChannelId > ( ) )
continue ;
auto conversation_id = bulk [ " cid " ] . as < ChannelId > ( ) ;
auto & result_bulk = result [ result_index + + ] ;
result_bulk [ " cid " ] = conversation_id ;
/* test if we have access to the conversation */
{
/* test if we're able to see the channel */
{
shared_lock channel_view_lock ( this - > channel_lock ) ;
auto channel = this - > channel_view ( ) - > find_channel ( conversation_id ) ;
if ( ! channel ) {
auto error = findError ( " conversation_invalid_id " ) ;
result_bulk [ " error_id " ] = error . errorId ;
result_bulk [ " error_msg " ] = error . message ;
continue ;
}
}
/* test if there is a channel password or join power which denies that we see the conversation */
{
shared_lock channel_view_lock ( ref_server - > channel_tree_lock ) ;
auto channel = ref_server - > getChannelTree ( ) - > findChannel ( conversation_id ) ;
if ( ! channel ) { /* should never happen! */
auto error = findError ( " conversation_invalid_id " ) ;
result_bulk [ " error_id " ] = error . errorId ;
result_bulk [ " error_msg " ] = error . message ;
continue ;
}
if ( ! bulk . has ( " cpw " ) )
bulk [ " cpw " ] = " " ;
if ( ! channel - > passwordMatch ( bulk [ " cpw " ] , true ) )
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_channel_join_ignore_password , 1 , channel , true ) ) {
auto error = findError ( " channel_invalid_password " ) ;
result_bulk [ " error_id " ] = error . errorId ;
result_bulk [ " error_msg " ] = error . message ;
continue ;
}
if ( ! this - > permissionGranted ( permission : : PERMTEST_ORDERED , permission : : b_channel_ignore_join_power , 1 , channel , true ) ) {
auto permission_granted = this - > calculate_permission_value ( permission : : i_channel_join_power , channel - > channelId ( ) ) ;
if ( ! channel - > permission_granted ( permission : : i_channel_needed_join_power , permission_granted , false ) ) {
auto error = findError ( " server_insufficeient_permissions " ) ;
result_bulk [ " error_id " ] = error . errorId ;
result_bulk [ " error_msg " ] = error . message ;
result_bulk [ " failed_permid " ] = permission : : i_channel_join_power ;
continue ;
}
}
}
}
auto conversation = conversation_manager - > get ( conversation_id ) ;
if ( conversation )
result_bulk [ " timestamp " ] = duration_cast < milliseconds > ( conversation - > last_message ( ) . time_since_epoch ( ) ) . count ( ) ;
else
result_bulk [ " timestamp " ] = 0 ;
2019-07-21 17:02:32 +02:00
result_bulk [ " flag_volatile " ] = conversation - > volatile_only ( ) ;
2019-07-19 22:55:03 +02:00
}
if ( result_index = = 0 )
return { ErrorType : : DBEmpty } ;
this - > sendCommand ( result ) ;
return CommandResult : : Success ;
}
2019-07-17 19:37:18 +02:00