2020-01-26 08:21:34 -05:00
//
// Created by wolverindev on 26.01.20.
//
# include <memory>
# include <iostream>
# include <bitset>
# include <algorithm>
# include <openssl/sha.h>
# include "../../build.h"
# include "../ConnectedClient.h"
# include "../InternalClient.h"
# include "../../server/VoiceServer.h"
# include "../voice/VoiceClient.h"
# include "../../InstanceHandler.h"
# include "../../server/QueryServer.h"
# include "../music/MusicClient.h"
# include "../query/QueryClient.h"
# include "../../weblist/WebListManager.h"
# include "../../manager/ConversationManager.h"
# include "../../manager/PermissionNameMapper.h"
2020-06-28 08:01:14 -04:00
# include "../../manager/ActionLogger.h"
2020-01-26 08:21:34 -05:00
# include <experimental/filesystem>
# include <cstdint>
# include <StringVariable.h>
# include "helpers.h"
# include <log/LogUtils.h>
# include <misc/sassert.h>
# include <misc/rnd.h>
# include <misc/strobf.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 ;
# define QUERY_PASSWORD_LENGTH 12
command_result 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 ) ;
//Server group
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 " | | command = = " clientaddservergroup " ) return this - > handleCommandServerGroupAddClient ( cmd ) ;
else if ( command = = " servergroupdelclient " | | command = = " clientdelservergroup " ) 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 ) ;
//Channel basic actions
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 ) ;
//Find a channel and get informations
else if ( command = = " channelfind " ) return this - > handleCommandChannelFind ( cmd ) ;
else if ( command = = " channelinfo " ) return this - > handleCommandChannelInfo ( cmd ) ;
//Channel perm actions
else if ( command = = " channelpermlist " ) return this - > handleCommandChannelPermList ( cmd ) ;
else if ( command = = " channeladdperm " ) return this - > handleCommandChannelAddPerm ( cmd ) ;
else if ( command = = " channeldelperm " ) return this - > handleCommandChannelDelPerm ( cmd ) ;
//Channel group actions
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 ) ;
//Channel sub/unsubscribe
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 ) ;
//manager channel permissions
else if ( command = = " channelclientpermlist " ) return this - > handleCommandChannelClientPermList ( cmd ) ;
else if ( command = = " channelclientaddperm " ) return this - > handleCommandChannelClientAddPerm ( cmd ) ;
else if ( command = = " channelclientdelperm " ) return this - > handleCommandChannelClientDelPerm ( cmd ) ;
//Client actions
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 ) ;
//File transfare
else if ( command = = " ftgetfilelist " ) return this - > handleCommandFTGetFileList ( cmd ) ;
else if ( command = = " ftcreatedir " ) return this - > handleCommandFTCreateDir ( cmd ) ;
else if ( command = = " ftdeletefile " ) return this - > handleCommandFTDeleteFile ( cmd ) ;
2020-07-13 05:13:09 -04:00
else if ( command = = " ftinitupload " ) {
auto result = this - > handleCommandFTInitUpload ( cmd ) ;
if ( result . has_error ( ) & & this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK ) {
ts : : command_builder notify { " notifystatusfiletransfer " } ;
notify . put_unchecked ( 0 , " clientftfid " , cmd [ " clientftfid " ] . string ( ) ) ;
notify . put ( 0 , " size " , 0 ) ;
this - > writeCommandResult ( notify , result , " status " ) ;
this - > sendCommand ( notify ) ;
result . release_data ( ) ;
return command_result { error : : ok } ;
}
return result ;
}
else if ( command = = " ftinitdownload " ) {
auto result = this - > handleCommandFTInitDownload ( cmd ) ;
if ( result . has_error ( ) & & this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK ) {
ts : : command_builder notify { " notifystatusfiletransfer " } ;
notify . put_unchecked ( 0 , " clientftfid " , cmd [ " clientftfid " ] . string ( ) ) ;
notify . put ( 0 , " size " , 0 ) ;
this - > writeCommandResult ( notify , result , " status " ) ;
this - > sendCommand ( notify ) ;
result . release_data ( ) ;
return command_result { error : : ok } ;
}
return result ;
}
2020-01-26 08:21:34 -05:00
else if ( command = = " ftgetfileinfo " ) return this - > handleCommandFTGetFileInfo ( cmd ) ;
2020-05-13 05:32:08 -04:00
else if ( command = = " ftrenamefile " ) return this - > handleCommandFTRenameFile ( cmd ) ;
else if ( command = = " ftlist " ) return this - > handleCommandFTList ( cmd ) ;
else if ( command = = " ftstop " ) return this - > handleCommandFTStop ( cmd ) ;
2020-01-26 08:21:34 -05:00
//Banlist
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 ) ;
//Tokens
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 ) ;
//DB stuff
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 ) ;
2020-06-28 08:01:14 -04:00
else if ( command = = " logquery " ) return this - > handleCommandLogQuery ( cmd ) ;
else if ( command = = " logadd " ) return this - > handleCommandLogAdd ( cmd ) ;
2020-01-26 08:21:34 -05:00
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 ) ;
2020-02-02 08:58:46 -05:00
else if ( command = = " playlistsetsubscription " ) return this - > handleCommandPlaylistSetSubscription ( cmd ) ;
2020-01-26 08:21:34 -05:00
else if ( command = = " playlistpermlist " ) return this - > handleCommandPlaylistPermList ( cmd ) ;
else if ( command = = " playlistaddperm " ) return this - > handleCommandPlaylistAddPerm ( cmd ) ;
else if ( command = = " playlistdelperm " ) return this - > handleCommandPlaylistDelPerm ( cmd ) ;
2020-02-21 14:32:25 -05:00
else if ( command = = " playlistclientlist " ) return this - > handleCommandPlaylistClientList ( cmd ) ;
2020-02-01 08:32:16 -05:00
else if ( command = = " playlistclientpermlist " ) return this - > handleCommandPlaylistClientPermList ( cmd ) ;
else if ( command = = " playlistclientaddperm " ) return this - > handleCommandPlaylistClientAddPerm ( cmd ) ;
else if ( command = = " playlistclientdelperm " ) return this - > handleCommandPlaylistClientDelPerm ( cmd ) ;
2020-01-26 08:21:34 -05:00
else if ( command = = " playlistinfo " ) return this - > handleCommandPlaylistInfo ( cmd ) ;
else if ( command = = " playlistedit " ) return this - > handleCommandPlaylistEdit ( cmd ) ;
else if ( command = = " playlistsonglist " ) return this - > handleCommandPlaylistSongList ( cmd ) ;
2020-02-02 08:58:46 -05:00
else if ( command = = " playlistsongsetcurrent " ) return this - > handleCommandPlaylistSongSetCurrent ( cmd ) ;
2020-01-26 08:21:34 -05:00
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 ) ;
else if ( command = = " conversationhistory " ) return this - > handleCommandConversationHistory ( cmd ) ;
else if ( command = = " conversationfetch " ) return this - > handleCommandConversationFetch ( cmd ) ;
else if ( command = = " conversationmessagedelete " ) return this - > handleCommandConversationMessageDelete ( cmd ) ;
2020-06-16 06:57:20 -04:00
else if ( command = = " listfeaturesupport " ) return this - > handleCommandListFeatureSupport ( cmd ) ;
2020-07-29 13:05:38 -04:00
if ( this - > getType ( ) = = ClientType : : CLIENT_QUERY )
return command_result { error : : command_not_found } ; //Dont log query invalid commands
2020-01-26 08:21:34 -05:00
if ( this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK )
if ( command . empty ( ) | | command . find_first_not_of ( ' ' ) = = - 1 ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_allow_invalid_packet , this - > getChannelId ( ) ) ) )
( ( VoiceClient * ) this ) - > disconnect ( VREASON_SERVER_KICK , config : : messages : : kick_invalid_command , this - > server ? this - > server - > serverAdmin : static_pointer_cast < ConnectedClient > ( serverInstance - > getInitialServerAdmin ( ) ) , true ) ;
}
logError ( this - > getServerId ( ) , " Missing command '{}' " , command ) ;
return command_result { error : : command_not_found } ;
} ;
command_result ConnectedClient : : handleCommandGetConnectionInfo ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
2020-02-01 08:32:16 -05:00
ConnectedLockedClient client { this - > server - > find_client_by_id ( cmd [ " clid " ] . as < ClientId > ( ) ) } ;
2020-01-26 08:21:34 -05:00
if ( ! client ) return command_result { error : : client_invalid_id } ;
2020-02-01 16:40:23 -05:00
bool send_temp { false } ;
2020-01-26 08:21:34 -05:00
auto info = client - > request_connection_info ( _this . lock ( ) , send_temp ) ;
2020-02-01 16:40:23 -05:00
if ( info | | send_temp ) {
2020-02-01 08:32:16 -05:00
this - > notifyConnectionInfo ( client . client , info ) ;
2020-02-02 09:08:42 -05:00
} else if ( this - > getType ( ) ! = ClientType : : CLIENT_TEAMSPEAK )
2020-01-26 08:21:34 -05:00
return command_result { error : : no_cached_connection_info } ;
return command_result { error : : ok } ;
}
command_result 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 command_result { error : : ok } ;
}
//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
command_result 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 command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPermissionList ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
static std : : string permission_list_string [ ClientType : : MAX ] ;
static std : : mutex permission_list_string_lock ;
static auto build_permission_list = [ ] ( const std : : string & command , const ClientType & type ) {
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 ;
} ) ;
auto mapper = serverInstance - > getPermissionMapper ( ) ;
for ( const auto & permission : avPerms ) {
if ( ! permission - > clientSupported ) continue ;
auto & blk = list_builder [ index + + ] ;
blk [ " permname " ] = permission - > name ;
blk [ " permname " ] = mapper - > permission_name ( type , permission - > type ) ;
blk [ " permdesc " ] = permission - > description ;
blk [ " permid " ] = permission - > type ;
}
return list_builder ;
} ;
auto type = this - > getType ( ) ;
if ( type = = CLIENT_TEASPEAK | | type = = CLIENT_TEAMSPEAK | | type = = CLIENT_QUERY ) {
Command response ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifypermissionlist " : " " ) ;
{
lock_guard lock ( permission_list_string_lock ) ;
if ( permission_list_string [ type ] . empty ( ) )
permission_list_string [ type ] = build_permission_list ( " " , type ) . build ( ) ;
response [ 0 ] [ " " ] = permission_list_string [ type ] ;
}
this - > sendCommand ( response ) ;
} else {
this - > sendCommand ( build_permission_list ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifypermissionlist " : " " , type ) ) ;
}
return command_result { error : : ok } ;
}
# define M(ptype) \
do { \
2020-04-08 07:01:41 -04:00
for ( const auto & prop : property : : list < ptype > ( ) ) { \
2020-01-26 08:21:34 -05:00
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 ] ; \
2020-10-04 09:04:25 -04:00
response [ index ] [ " value " ] = prop - > default_value ; \
response [ index ] [ " value_type " ] = property : : ValueType_Names [ ( int ) prop - > type_value ] ; \
2020-01-26 08:21:34 -05:00
index + + ; \
} \
} while ( 0 )
command_result ConnectedClient : : handleCommandPropertyList ( ts : : Command & cmd ) {
Command response ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifypropertylist " : " " ) ;
{
string pattern ;
2020-10-04 09:04:25 -04:00
for ( auto flag_name : property : : flag_names ) {
if ( flag_name ) {
pattern = flag_name + string ( " | " ) + pattern ;
}
}
2020-01-26 08:21:34 -05:00
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 ) ;
2020-10-04 09:04:25 -04:00
if ( cmd . hasParm ( " all " ) | | cmd . hasParm ( " playlist " ) )
M ( property : : PlaylistProperties ) ;
2020-01-26 08:21:34 -05:00
this - > sendCommand ( response ) ;
return command_result { error : : ok } ;
}
command_result 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 [ " cgid " ] . as < GroupId > ( ) = = 0 )
serverGroup = this - > server - > groups - > defaultGroup ( GroupTarget : : GROUPTARGET_CHANNEL ) ;
if ( ! serverGroup | | serverGroup - > target ( ) ! = GROUPTARGET_CHANNEL )
return command_result { error : : group_invalid_id } ;
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ; /* ensure we dont get moved or somebody could move us */
auto channel_id = cmd [ " cid " ] . as < ChannelId > ( ) ;
auto channel = this - > server - > channelTree - > findChannel ( channel_id ) ;
if ( ! channel ) return command_result { error : : channel_invalid_id } ;
auto target_cldbid = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
{
auto channel_group_member_add_power = this - > calculate_permission ( permission : : i_channel_group_member_add_power , channel_id ) ;
if ( ! serverGroup - > permission_granted ( permission : : i_channel_group_needed_member_add_power , channel_group_member_add_power , true ) ) {
if ( target_cldbid ! = this - > getClientDatabaseId ( ) )
return command_result { permission : : i_channel_group_member_add_power } ;
auto channel_group_self_add_power = this - > calculate_permission ( permission : : i_channel_group_self_add_power , channel_id ) ;
if ( ! serverGroup - > permission_granted ( permission : : i_channel_group_needed_member_add_power , channel_group_self_add_power , true ) )
return command_result { permission : : i_channel_group_self_add_power } ;
}
auto client_permission_modify_power = this - > calculate_permission ( permission : : i_client_permission_modify_power , channel_id ) ;
auto client_needed_permission_modify_power = this - > server - > calculate_permission (
permission : : i_client_needed_permission_modify_power , target_cldbid , ClientType : : CLIENT_TEAMSPEAK , channel_id ) ;
if ( client_needed_permission_modify_power . has_value ) {
if ( ! permission : : v2 : : permission_granted ( client_needed_permission_modify_power , client_permission_modify_power ) )
return command_result { permission : : i_client_permission_modify_power } ;
}
}
2020-06-28 08:01:14 -04:00
std : : shared_ptr < GroupAssignment > old_group ;
2020-01-26 08:21:34 -05:00
{
2020-06-28 08:01:14 -04:00
old_group = this - > server - > groups - > getChannelGroupExact ( target_cldbid , channel , false ) ;
2020-01-26 08:21:34 -05:00
if ( old_group ) {
auto channel_group_member_remove_power = this - > calculate_permission ( permission : : i_channel_group_member_remove_power , channel_id ) ;
2020-06-28 08:01:14 -04:00
if ( ! old_group - > group - > permission_granted ( permission : : i_channel_group_needed_member_remove_power , channel_group_member_remove_power , true ) ) {
2020-01-26 08:21:34 -05:00
if ( target_cldbid ! = this - > getClientDatabaseId ( ) )
return command_result { permission : : i_channel_group_member_remove_power } ;
auto channel_group_self_remove_power = this - > calculate_permission ( permission : : i_channel_group_self_remove_power , channel_id ) ;
2020-06-28 08:01:14 -04:00
if ( ! old_group - > group - > permission_granted ( permission : : i_channel_group_needed_member_remove_power , channel_group_self_remove_power , true ) )
2020-01-26 08:21:34 -05:00
return command_result { permission : : i_channel_group_self_remove_power } ;
}
}
}
this - > server - > groups - > setChannelGroup ( target_cldbid , serverGroup , channel ) ;
2020-06-28 08:01:14 -04:00
std : : shared_ptr < ConnectedClient > connected_client { } ;
2020-01-26 08:21:34 -05:00
for ( const auto & targetClient : this - > server - > findClientsByCldbId ( target_cldbid ) ) {
2020-06-28 08:01:14 -04:00
connected_client = targetClient ;
2020-01-26 08:21:34 -05:00
unique_lock client_channel_lock_w ( targetClient - > channel_lock ) ;
auto updates = this - > server - > groups - > update_server_group_property ( targetClient , false , targetClient - > getChannel ( ) ) ; /* 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 ) ;
}
2020-06-28 08:01:14 -04:00
if ( old_group ) {
serverInstance - > action_logger ( ) - > group_assignment_logger . log_group_assignment_remove ( this - > getServerId ( ) ,
this - > ref ( ) , log : : GroupTarget : : CHANNEL ,
old_group - > group - > groupId ( ) , old_group - > group - > name ( ) ,
target_cldbid , connected_client ? connected_client - > getDisplayName ( ) : " "
) ;
}
if ( serverGroup ! = this - > server - > groups - > defaultGroup ( GroupTarget : : GROUPTARGET_CHANNEL ) ) {
serverInstance - > action_logger ( ) - > group_assignment_logger . log_group_assignment_add ( this - > getServerId ( ) ,
this - > ref ( ) , log : : GroupTarget : : CHANNEL ,
serverGroup - > groupId ( ) , serverGroup - > name ( ) ,
target_cldbid , connected_client ? connected_client - > getDisplayName ( ) : " "
) ;
}
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
//sendtextmessage targetmode=1 <1 = direct | 2 = channel | 3 = server> msg=asd target=1 <clid>
command_result ConnectedClient : : handleCommandSendTextMessage ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto timestamp = system_clock : : now ( ) ;
if ( cmd [ " targetmode " ] . as < ChatMessageMode > ( ) = = ChatMessageMode : : TEXTMODE_PRIVATE ) {
2020-02-01 08:32:16 -05:00
ConnectedLockedClient target { this - > server - > find_client_by_id ( cmd [ " target " ] . as < ClientId > ( ) ) } ;
2020-01-26 08:21:34 -05:00
if ( ! target ) return command_result { error : : client_invalid_id } ;
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 ) {
2020-02-01 08:32:16 -05:00
if ( target . client = = this )
2020-01-26 08:21:34 -05:00
ACTION_REQUIRES_PERMISSION ( permission : : b_client_even_textmessage_send , 1 , this - > getChannelId ( ) ) ;
if ( ! permission : : v2 : : permission_granted ( target - > calculate_permission ( permission : : i_client_needed_private_textmessage_power , target - > getClientId ( ) ) , this - > calculate_permission ( permission : : i_client_private_textmessage_power , this - > getClientId ( ) ) , false ) )
return command_result { permission : : i_client_private_textmessage_power } ;
{
2020-02-01 08:32:16 -05:00
unique_lock channel_lock ( target - > get_channel_lock ( ) ) ;
2020-01-26 08:21:34 -05:00
target - > openChats . push_back ( _this ) ;
}
{
unique_lock channel_lock ( this - > channel_lock ) ;
2020-02-01 08:32:16 -05:00
this - > openChats . push_back ( target . client ) ;
2020-01-26 08:21:34 -05:00
}
}
2020-02-01 08:32:16 -05:00
if ( this - > handleTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , cmd [ " msg " ] , target . client ) ) return command_result { error : : ok } ;
2020-01-26 08:21:34 -05:00
target - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , _this . lock ( ) , target - > getClientId ( ) , 0 , timestamp , cmd [ " msg " ] . string ( ) ) ;
this - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_PRIVATE , _this . lock ( ) , target - > getClientId ( ) , 0 , timestamp , cmd [ " msg " ] . string ( ) ) ;
} else if ( cmd [ " targetmode " ] = = ChatMessageMode : : TEXTMODE_CHANNEL ) {
2020-10-04 09:04:25 -04:00
if ( ! cmd [ 0 ] . has ( " cid " ) ) {
2020-01-26 08:21:34 -05:00
cmd [ " cid " ] = 0 ;
2020-10-04 09:04:25 -04:00
}
2020-01-26 08:21:34 -05:00
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 ( ) ;
}
2020-02-16 13:02:06 -05:00
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_channel_textmessage_send , channel_id ) , false ) ) \
return command_result { permission : : b_client_channel_textmessage_send } ;
2020-01-26 08:21:34 -05:00
if ( channel = = this - > currentChannel ) {
channel_tree_read_lock . unlock ( ) ; //Method may creates a music bot which modifies the channel tree
2020-10-04 09:04:25 -04:00
if ( this - > handleTextMessage ( ChatMessageMode : : TEXTMODE_CHANNEL , cmd [ " msg " ] , nullptr ) ) {
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
2020-10-04 09:04:25 -04:00
}
2020-01-26 08:21:34 -05:00
channel_tree_read_lock . lock ( ) ;
}
2020-10-04 09:04:25 -04:00
auto conversation_mode = channel - > properties ( ) [ property : : CHANNEL_CONVERSATION_MODE ] . as < ChannelConversationMode > ( ) ;
if ( conversation_mode = = ChannelConversationMode : : CHANNELCONVERSATIONMODE_NONE ) {
return command_result { error : : conversation_not_exists } ;
} else if ( channel ! = this - > currentChannel ) {
if ( conversation_mode = = ChannelConversationMode : : CHANNELCONVERSATIONMODE_PRIVATE ) {
2020-01-26 08:21:34 -05:00
return command_result { error : : conversation_is_private } ;
2020-10-04 09:04:25 -04:00
}
2020-01-26 08:21:34 -05:00
2020-10-04 09:04:25 -04:00
if ( auto fail_perm { this - > calculate_and_get_join_state ( channel ) } ; fail_perm ! = permission : : ok ) {
2020-02-16 13:02:06 -05:00
return command_result { fail_perm } ; /* You're not allowed to send messages :) */
2020-10-04 09:04:25 -04:00
}
2020-01-26 08:21:34 -05:00
}
2020-02-02 08:58:46 -05:00
this - > server - > send_text_message ( channel , this - > ref ( ) , cmd [ " msg " ] . string ( ) ) ;
2020-01-26 08:21:34 -05:00
} else if ( cmd [ " targetmode " ] = = ChatMessageMode : : TEXTMODE_SERVER ) {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_server_textmessage_send , 1 ) ;
if ( this - > handleTextMessage ( ChatMessageMode : : TEXTMODE_SERVER , cmd [ " msg " ] , nullptr ) ) return command_result { error : : ok } ;
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 ;
client - > notifyTextMessage ( ChatMessageMode : : TEXTMODE_SERVER , _this . lock ( ) , this - > getClientId ( ) , 0 , timestamp , cmd [ " msg " ] . string ( ) ) ;
}
{
auto conversations = this - > server - > conversation_manager ( ) ;
auto conversation = conversations - > get_or_create ( 0 ) ;
conversation - > register_message ( this - > getClientDatabaseId ( ) , this - > getUid ( ) , this - > getDisplayName ( ) , timestamp , cmd [ " msg " ] . string ( ) ) ;
}
} else return command_result { error : : parameter_invalid , " invalid target mode " } ;
return command_result { error : : ok } ;
}
//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
command_result 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 ) {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_ban_list_global , 1 ) ;
} else {
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( sid ) ;
if ( ! server ) return command_result { error : : parameter_invalid } ;
if ( ! permission : : v2 : : permission_granted ( 1 , server - > calculate_permission ( permission : : b_client_ban_list , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) ) )
return command_result { permission : : b_client_ban_list } ;
}
//When empty: return command_result{error::database_empty_result};
auto banList = serverInstance - > banManager ( ) - > listBans ( sid ) ;
if ( banList . empty ( ) ) return command_result { error : : database_empty_result } ;
auto allow_ip = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_remoteaddress_view , 0 ) ) ;
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 command_result { error : : ok } ;
}
command_result 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 ) {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_ban_create_global , 1 ) ;
} else {
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( sid ) ;
if ( ! server ) return command_result { error : : parameter_invalid } ;
if ( ! permission : : v2 : : permission_granted ( 1 , server - > calculate_permission ( permission : : b_client_ban_create , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) ) )
return command_result { permission : : b_client_ban_create } ;
}
2020-08-07 15:05:19 -04:00
auto max_ban_time = this - > calculate_permission ( permission : : i_client_ban_max_bantime , this - > getClientDatabaseId ( ) ) ;
if ( ! max_ban_time . has_value )
return command_result { permission : : i_client_ban_max_bantime } ;
2020-01-30 06:06:39 -05:00
if ( ! max_ban_time . has_infinite_power ( ) ) {
2020-01-26 08:21:34 -05:00
if ( max_ban_time . value < time )
return command_result { 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 ( ) ) {
2020-06-28 08:01:14 -04:00
if ( existing - > until = = until ) {
return command_result { error : : database_duplicate_entry } ;
} else {
2020-01-26 08:21:34 -05:00
existing - > until = until ;
serverInstance - > banManager ( ) - > updateBan ( existing ) ;
banned = true ;
}
} else if ( ! banned ) {
serverInstance - > banManager ( ) - > unban ( existing ) ;
}
}
2020-06-28 08:01:14 -04:00
if ( ! banned ) {
serverInstance - > banManager ( ) - > registerBan ( sid , this - > getClientDatabaseId ( ) , banreason , uid , ip , name , hwid , until ) ;
}
2020-01-26 08:21:34 -05:00
2020-01-26 12:04:38 -05:00
for ( auto server : ( this - > server ? std : : deque < shared_ptr < VirtualServer > > { this - > server } : serverInstance - > getVoiceServerManager ( ) - > serverInstances ( ) ) )
2020-01-26 08:21:34 -05:00
server - > testBanStateChange ( _this . lock ( ) ) ;
return command_result { error : : ok } ;
}
command_result 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 command_result { error : : database_empty_result } ;
if ( sid = = 0 ) {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_ban_edit_global , 1 ) ;
} else {
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( sid ) ;
if ( ! server ) return command_result { error : : parameter_invalid } ;
if ( ! permission : : v2 : : permission_granted ( 1 , server - > calculate_permission ( permission : : b_client_ban_edit , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) ) )
return command_result { 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 command_result { error : : parameter_invalid } ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandBanClient ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
2020-04-04 06:22:20 -04:00
std : : string target_unique_id { } ;
ClientDbId target_database_id { 0 } ;
2020-01-26 08:21:34 -05:00
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 " ) ;
2020-04-04 06:22:20 -04:00
std : : deque < std : : shared_ptr < ConnectedClient > > target_clients ;
2020-01-26 08:21:34 -05:00
if ( cmd [ 0 ] . has ( " uid " ) ) {
2020-04-04 06:22:20 -04:00
target_clients = this - > server - > findClientsByUid ( target_unique_id = cmd [ " uid " ] . string ( ) ) ;
} else if ( cmd [ 0 ] . has ( " cldbid " ) ) {
target_clients = this - > server - > findClientsByCldbId ( target_database_id = cmd [ " cldbid " ] . as < ClientDbId > ( ) ) ;
2020-01-26 08:21:34 -05:00
} else {
2020-02-01 08:32:16 -05:00
target_clients = { this - > server - > find_client_by_id ( cmd [ " clid " ] . as < ClientId > ( ) ) } ;
2020-01-26 08:21:34 -05:00
if ( ! target_clients [ 0 ] ) {
return command_result { error : : client_invalid_id , " Could not find target client " } ;
}
}
2020-04-04 06:22:20 -04:00
for ( const auto & client : target_clients )
if ( client - > getType ( ) = = ClientType : : CLIENT_MUSIC )
return command_result { error : : client_invalid_id , " You cant ban a music bot! " } ;
if ( ! target_clients . empty ( ) ) {
if ( target_unique_id . empty ( ) )
target_unique_id = target_clients . back ( ) - > getUid ( ) ;
2020-01-26 08:21:34 -05:00
2020-04-04 06:22:20 -04:00
if ( ! target_database_id )
target_database_id = target_clients . back ( ) - > getClientDatabaseId ( ) ;
}
if ( ! permission : : v2 : : permission_granted ( this - > server - > calculate_permission ( permission : : i_client_needed_ban_power , target_database_id , ClientType : : CLIENT_TEAMSPEAK , 0 ) , this - > calculate_permission ( permission : : i_client_ban_power , 0 ) ) )
2020-01-26 08:21:34 -05:00
return command_result { permission : : i_client_ban_power } ;
2020-04-04 06:22:20 -04:00
if ( permission : : v2 : : permission_granted ( 1 , this - > server - > calculate_permission ( permission : : b_client_ignore_bans , target_database_id , ClientType : : CLIENT_TEAMSPEAK , 0 ) ) )
2020-01-26 08:21:34 -05:00
return command_result { permission : : b_client_ignore_bans } ;
deque < BanId > ban_ids ;
2020-04-04 06:22:20 -04:00
if ( ! target_unique_id . empty ( ) ) {
auto _id = serverInstance - > banManager ( ) - > registerBan ( this - > getServer ( ) - > getServerId ( ) , this - > getClientDatabaseId ( ) , reason , target_unique_id , " " , " " , " " , until ) ;
ban_ids . push_back ( _id ) ;
}
2020-01-26 08:21:34 -05:00
auto b_ban_name = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_ban_name , 0 ) , false ) ;
auto b_ban_ip = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_ban_ip , 0 ) , false ) ;
auto b_ban_hwid = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_ban_hwid , 0 ) , false ) ;
auto max_ban_time = this - > calculate_permission ( permission : : i_client_ban_max_bantime , 0 ) ;
2020-01-30 06:06:39 -05:00
if ( ! max_ban_time . has_value ) return command_result { permission : : i_client_ban_max_bantime } ;
if ( ! max_ban_time . has_infinite_power ( ) ) {
2020-01-26 08:21:34 -05:00
if ( max_ban_time . value < time )
return command_result { 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 ) ;
2020-02-01 08:32:16 -05:00
client - > close_connection ( system_clock : : now ( ) + seconds ( 2 ) ) ;
2020-01-26 08:21:34 -05:00
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 command_result { error : : ok } ;
}
command_result 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 command_result { error : : database_empty_result } ;
if ( sid = = 0 ) {
const auto permission = ban - > invokerDbId = = this - > getClientDatabaseId ( ) ? permission : : b_client_ban_delete_own_global : permission : : b_client_ban_delete_global ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission , 1 ) ;
} else {
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( sid ) ;
if ( ! server ) return command_result { error : : parameter_invalid } ;
auto perm = ban - > invokerDbId = = this - > getClientDatabaseId ( ) ? permission : : b_client_ban_delete_own : permission : : b_client_ban_delete ;
if ( ! permission : : v2 : : permission_granted ( 1 , server - > calculate_permission ( perm , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) ) )
return command_result { perm } ;
}
serverInstance - > banManager ( ) - > unban ( ban ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandBanDelAll ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_ban_delete , 1 ) ;
serverInstance - > banManager ( ) - > deleteAllBans ( server - > getServerId ( ) ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandBanTriggerList ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_ban_trigger_list , 1 ) ;
CMD_REQ_PARM ( " banid " ) ;
auto record = serverInstance - > banManager ( ) - > findBanById ( this - > getServerId ( ) , cmd [ " banid " ] ) ;
if ( ! record ) return command_result { error : : parameter_invalid , " Invalid ban id " } ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifybantriggerlist " : " " ) ;
notify [ " banid " ] = record - > banId ;
notify [ " serverid " ] = record - > serverId ;
auto allow_ip = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_remoteaddress_view , 0 ) ) ;
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 command_result { error : : database_empty_result } ;
this - > sendCommand ( notify ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandTokenList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_token_list , 1 ) ;
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 command_result { error : : database_empty_result } ;
this - > sendCommand ( notify ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandTokenAdd ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_token_add , 1 ) ;
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 command_result { error : : group_invalid_id } ;
if ( group - > type ( ) = = GroupType : : GROUP_TYPE_TEMPLATE ) return command_result { error : : parameter_invalid , " invalid server group type " } ;
if ( group - > target ( ) = = GroupTarget : : GROUPTARGET_SERVER )
ACTION_REQUIRES_GROUP_PERMISSION ( group , permission : : i_server_group_needed_member_add_power , permission : : i_server_group_member_add_power , true ) ;
else
ACTION_REQUIRES_GROUP_PERMISSION ( group , permission : : i_channel_group_needed_member_add_power , permission : : i_channel_group_member_add_power , true ) ;
}
if ( ttype = = TokenType : : TOKEN_CHANNEL ) {
if ( ! this - > server - > channelTree - > findChannel ( cId ) ) return command_result { error : : channel_invalid_id , " Cant resolve channel " } ;
} else if ( ttype = = TokenType : : TOKEN_SERVER ) ;
else return command_result { error : : parameter_invalid , " invalid token target type " } ;
auto result = this - > server - > tokenManager - > createToken ( ttype , gId , description , cId , cmd [ " token " ] ) ;
if ( ! result ) return command_result { error : : vs_critical } ;
Command notify ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifytokenadd " : " " ) ;
notify [ " token " ] = result - > token ;
this - > sendCommand ( notify ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandTokenUse ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_token_use , 1 ) ;
auto strToken = cmd [ " token " ] . string ( ) ;
auto token = this - > server - > tokenManager - > findToken ( strToken ) ;
if ( ! token ) return command_result { error : : 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 command_result { error : : 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 command_result { error : : 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 command_result { error : : ok } ;
}
}
if ( this - > server - > notifyClientPropertyUpdates ( _this . lock ( ) , this - > server - > groups - > update_server_group_property ( _this . lock ( ) , true , this - > getChannel ( ) ) ) ) {
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 command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandTokenDelete ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_token_delete , 1 ) ;
auto strToken = cmd [ " token " ] . string ( ) ;
auto token = this - > server - > tokenManager - > findToken ( strToken ) ;
if ( ! token ) return command_result { error : : 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 command_result { error : : ok } ;
}
//start=0 duration=10
//pattern=%asd%
command_result 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 > ( ) ;
2020-02-01 08:32:16 -05:00
ConnectedLockedClient cl { this - > server - > find_client_by_id ( target ) } ;
if ( ! cl ) return command_result { error : : client_invalid_id } ;
2020-01-26 08:21:34 -05:00
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 command_result { error : : client_invalid_id , " invalid target id " } ;
target - > sendCommand ( Command ( cmd [ " command " ] . string ( ) ) , cmd [ 0 ] . has ( " low " ) ? cmd [ " low " ] : false ) ;
}
*/
else return command_result { error : : not_implemented } ;
return command_result { error : : ok } ;
}
command_result 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 command_result { error : : ok } ;
}
struct DBFindArgs {
int index = 0 ;
bool full = false ;
bool ip = false ;
Command cmd { " " } ;
} ;
command_result 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 WIN32
res [ " platform " ] = " Windows " ;
# else
res [ " platform " ] = " Linux " ;
# endif
this - > sendCommand ( res ) ;
return command_result { error : : ok } ;
}
//cid=%d password=%s
command_result 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 command_result { error : : channel_invalid_id , " Cant resolve channel " } ;
std : : string password = cmd [ " password " ] ;
if ( ! channel - > passwordMatch ( password , false ) ) return command_result { error : : server_invalid_password } ;
return command_result { error : : ok } ;
}
command_result 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 command_result { error : : server_invalid_password } ;
return command_result { error : : ok } ;
}
//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
command_result 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 command_result { error : : database_empty_result , " no letters available " } ;
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 command_result { error : : ok } ;
}
//messageadd cluid=ePHuXhcai9nk\/4Fd\/xkxrokvnNk= subject=Test message=Message
command_result ConnectedClient : : handleCommandMessageAdd ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_offline_textmessage_send , 1 ) ;
this - > server - > letters - > createLetter ( this - > getUid ( ) , cmd [ " cluid " ] , cmd [ " subject " ] , cmd [ " message " ] ) ;
return command_result { error : : ok } ;
}
command_result 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 command_result { error : : ok } ;
}
command_result 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 command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandMessageDel ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
this - > server - > letters - > deleteLetter ( cmd [ " msgid " ] ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPermGet ( Command & cmd ) {
CMD_RESET_IDLE ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_permissionoverview_own , 1 ) ;
Command res ( " " ) ;
deque < permission : : PermissionType > requrested ;
auto permission_mapper = serverInstance - > getPermissionMapper ( ) ;
auto type = this - > getType ( ) ;
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 ; //TODO: Map the other way around!
if ( permission : : resolvePermissionData ( permType ) - > type = = permission : : PermissionType : : unknown ) return command_result { error : : parameter_invalid , " could not resolve permission " } ;
requrested . push_back ( permType ) ;
}
int index = 0 ;
for ( const auto & entry : this - > calculate_permissions ( requrested , this - > getChannelId ( ) ) ) {
if ( ! entry . second . has_value ) continue ;
res [ index ] [ " permsid " ] = permission_mapper - > permission_name ( type , entry . first ) ; ;
res [ index ] [ " permid " ] = entry . first ;
res [ index + + ] [ " permvalue " ] = entry . second . value ;
}
if ( index = = 0 )
return command_result { error : : database_empty_result } ;
this - > sendCommand ( res ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPermIdGetByName ( Command & cmd ) {
auto found = permission : : resolvePermissionData ( cmd [ " permsid " ] . as < string > ( ) ) ; //TODO: Map the other way around
Command res ( " " ) ;
res [ " permid " ] = found - > type ;
this - > sendCommand ( res ) ;
return command_result { error : : ok } ;
}
command_result 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 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_permission_find , 1 ) ;
2020-04-02 08:10:33 -04:00
std : : vector < std : : tuple < std : : string , permission : : PermissionType , bool > > requested_permissions { } ;
requested_permissions . reserve ( cmd . bulkCount ( ) ) ;
2020-01-26 08:21:34 -05:00
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 command_result { error : : 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 > ( ) ) ; //TODO: Map the other way around
granted = permission - > grant_name = = cmd [ index ] [ " permsid " ] . as < string > ( ) ;
if ( permission - > type = = permission : : PermissionType : : unknown )
return command_result { error : : parameter_invalid , " could not resolve permission (id= " + cmd [ index ] [ " permid " ] . string ( ) + " ) " } ;
} else {
continue ;
}
2020-04-02 08:10:33 -04:00
requested_permissions . emplace_back ( permission - > name , permission - > type , granted ) ;
2020-01-26 08:21:34 -05:00
}
2020-04-02 08:10:33 -04:00
if ( requested_permissions . empty ( ) )
2020-01-26 08:21:34 -05:00
return command_result { error : : database_empty_result } ;
2020-04-02 08:10:33 -04:00
std : : map < std : : string , std : : tuple < permission : : PermissionType , uint8_t > > db_lookup_mapping { } ;
std : : string query_string { } ;
for ( const auto & [ name , id , as_granted ] : requested_permissions ) {
auto & mapping = db_lookup_mapping [ name ] ;
if ( std : : get < 0 > ( mapping ) = = 0 ) {
std : : get < 0 > ( mapping ) = id ;
query_string + = std : : string { query_string . empty ( ) ? " " : " OR " } + " `permId` = ' " + name + " ' " ;
2020-01-26 08:21:34 -05:00
}
2020-04-02 08:10:33 -04:00
std : : get < 1 > ( mapping ) | = ( 1U < < as_granted ) ;
2020-01-26 08:21:34 -05:00
}
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 ) {
2020-04-02 08:10:33 -04:00
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 { } ;
2020-01-26 08:21:34 -05:00
bool negate = false , skip = false ;
2020-04-02 08:10:33 -04:00
#if 0
2020-01-26 08:21:34 -05:00
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 ;
}
}
2020-04-02 08:10:33 -04:00
# else
assert ( length = = 8 ) ;
try {
type = static_cast < permission : : PermissionSqlType > ( stoll ( values [ 1 ] ) ) ;
permission_name = values [ 0 ] ;
id = static_cast < uint64_t > ( stoll ( values [ 2 ] ) ) ;
channel_id = static_cast < ChannelId > ( stoll ( values [ 3 ] ) ) ;
value = static_cast < permission : : PermissionValue > ( stoll ( values [ 4 ] ) ) ;
granted_value = static_cast < permission : : PermissionValue > ( stoll ( values [ 5 ] ) ) ;
negate = values [ 7 ] = = " 1 " ;
skip = values [ 6 ] = = " 1 " ;
} catch ( std : : exception & ex ) {
return 0 ;
}
# endif
2020-01-26 08:21:34 -05:00
2020-04-02 08:10:33 -04:00
auto request = db_lookup_mapping . find ( permission_name ) ;
if ( request = = db_lookup_mapping . end ( ) ) return 0 ; /* shall not happen */
auto flags = std : : get < 1 > ( request - > second ) ;
2020-01-26 08:21:34 -05:00
/* value */
2020-04-02 08:10:33 -04:00
if ( ( flags & 0x1U ) > 0 & & value > 0 ) {
2020-01-26 08:21:34 -05:00
auto result = make_unique < PermissionEntry > ( ) ;
2020-04-02 08:10:33 -04:00
result - > permission_type = std : : get < 0 > ( request - > second ) ;
2020-01-26 08:21:34 -05:00
result - > permission_value = value ;
result - > type = type ;
result - > channel_id = channel_id ;
result - > negate = negate ;
result - > skip = skip ;
if ( type = = permission : : SQL_PERM_GROUP ) {
result - > group_id = id ;
} else if ( type = = permission : : SQL_PERM_USER ) {
result - > client_id = id ;
}
2020-04-02 08:10:33 -04:00
entries . push_back ( std : : move ( result ) ) ;
2020-01-26 08:21:34 -05:00
}
/* granted */
2020-04-02 08:10:33 -04:00
if ( ( flags & 0x2U ) > 0 & & granted_value > 0 ) {
2020-01-26 08:21:34 -05:00
auto result = make_unique < PermissionEntry > ( ) ;
2020-04-02 08:10:33 -04:00
result - > permission_type = ( permission : : PermissionType ) ( std : : get < 0 > ( request - > second ) | PERM_ID_GRANT ) ;
2020-01-26 08:21:34 -05:00
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 ) {
result - > group_id = id ;
} else if ( type = = permission : : SQL_PERM_USER ) {
result - > client_id = id ;
}
2020-04-02 08:10:33 -04:00
entries . push_back ( std : : move ( result ) ) ;
2020-01-26 08:21:34 -05:00
}
return 0 ;
} ) ;
2020-04-02 08:10:33 -04:00
if ( entries . empty ( ) )
return command_result { error : : database_empty_result } ;
2020-01-26 08:21:34 -05:00
struct CommandPerm {
permission : : PermissionType p ;
permission : : PermissionValue v ;
int64_t id1 ;
int64_t id2 ;
uint8_t t ;
} ;
2020-02-21 14:32:25 -05:00
std : : vector < CommandPerm > perms ;
2020-01-26 08:21:34 -05:00
perms . resize ( entries . size ( ) ) ;
2020-04-02 08:10:33 -04:00
size_t index { 0 } ;
auto all_groups = this - > server - > groups - > availableGroups ( true ) ;
2020-01-26 08:21:34 -05:00
for ( const auto & entry : entries ) {
auto & perm = perms [ index + + ] ;
2020-04-02 08:10:33 -04:00
#if 0 /* TS3 switched the oder and YatQa as well, to keep compatibility we do it as well */
2020-01-26 08:21:34 -05:00
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 */
}
}
2020-04-02 08:10:33 -04:00
# else
if ( entry - > type = = permission : : SQL_PERM_USER ) {
if ( entry - > channel_id > 0 ) {
perm . id1 = entry - > channel_id ;
perm . id2 = entry - > client_id ;
perm . t = 4 ; /* client channel */
} else {
perm . id1 = entry - > client_id ;
perm . id2 = 0 ;
perm . t = 1 ; /* client server */
}
} else if ( entry - > type = = permission : : SQL_PERM_CHANNEL ) {
perm . id1 = entry - > channel_id ;
perm . id2 = 0 ;
perm . t = 2 ; /* channel permission */
} else if ( entry - > type = = permission : : SQL_PERM_GROUP ) {
auto group = std : : find_if ( all_groups . begin ( ) , all_groups . end ( ) , [ & ] ( const auto & group ) { return group - > groupId ( ) = = entry - > group_id ; } ) ;
if ( group = = all_groups . end ( ) ) {
index - - ; /* unknown group */
continue ;
}
if ( ( * group ) - > target ( ) = = GroupTarget : : GROUPTARGET_CHANNEL ) {
perm . id1 = 0 ;
perm . id2 = entry - > group_id ;
perm . t = 3 ; /* channel group */
} else {
perm . id1 = entry - > group_id ;
perm . id2 = 0 ;
perm . t = 0 ; /* server group */
}
}
# endif
perm . p = entry - > permission_type ;
perm . v = entry - > permission_value ;
2020-01-26 08:21:34 -05:00
}
2020-04-02 08:10:33 -04:00
perms . erase ( perms . begin ( ) + index , perms . end ( ) ) ;
2020-01-26 08:21:34 -05:00
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 ;
} ) ;
2020-04-02 08:10:33 -04:00
#if 0
2020-02-21 14:32:25 -05:00
Command result ( this - > notify_response_command ( " notifypermfind " ) ) ;
2020-01-26 08:21:34 -05:00
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 + + ;
}
2020-04-02 08:10:33 -04:00
this - > sendCommand ( result ) ;
# else
command_builder result { this - > notify_response_command ( " notifypermfind " ) , 64 , perms . size ( ) } ;
index = 0 ;
2020-01-26 08:21:34 -05:00
2020-04-02 08:10:33 -04:00
for ( const auto & e : perms ) {
auto bulk = result . bulk ( index + + ) ;
bulk . put ( " t " , e . t ) ;
bulk . put ( " p " , ( uint16_t ) e . p ) ;
bulk . put ( " v " , e . v ) ;
bulk . put ( " id1 " , e . id1 ) ;
bulk . put ( " id2 " , e . id2 ) ;
}
2020-01-26 08:21:34 -05:00
this - > sendCommand ( result ) ;
2020-04-02 08:10:33 -04:00
# endif
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
/*
* - Alle rechte der aktuellen server gruppen vom client
* - Alle client rechte | channel cleint rechte
* - Alle rechte des channels
*/
command_result 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 command_result { error : : client_invalid_id } ;
if ( client_dbid = = this - > getClientDatabaseId ( ) ) {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_permissionoverview_own , 1 ) ;
} else {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_permissionoverview_view , 1 ) ;
}
string channel_query , perm_query ;
auto channel = this - > server ? this - > server - > channelTree - > findChannel ( cmd [ " cid " ] ) : serverInstance - > getChannelTree ( ) - > findChannel ( cmd [ " cid " ] ) ;
if ( ! channel ) return command_result { error : : 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 . grant_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 ) | 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 . grant_set ) {
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 . grant_set ) {
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 . grant_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 ) | 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 . grant_set ) {
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 command_result { error : : database_empty_result } ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result 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 command_result { error : : client_invalid_id } ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : i_client_complain_power , cl [ 0 ] - > calculate_permission ( permission : : i_client_needed_complain_power , 0 ) ) ;
/*
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( target ) )
return command_result { error : : client_invalid_id , " invalid database id " } ;
*/
for ( const auto & elm : this - > server - > complains - > findComplainsFromTarget ( target ) )
if ( elm - > invoker = = this - > getClientDatabaseId ( ) )
return command_result { error : : database_duplicate_entry , " you already send a complain " } ;
if ( ! this - > server - > complains - > createComplain ( target , this - > getClientDatabaseId ( ) , msg ) ) return command_result { error : : vs_critical , " could not create complains " } ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandComplainList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_complain_list , 1 ) ;
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 command_result { error : : database_empty_result } ;
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 ) {
2020-07-30 14:25:45 -04:00
if ( e - > client_database_id = = elm - > target )
result [ index ] [ " tname " ] = e - > client_nickname ;
if ( e - > client_database_id = = elm - > invoker )
result [ index ] [ " fname " ] = e - > client_nickname ;
2020-01-26 08:21:34 -05:00
}
index + + ;
}
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result 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 command_result { error : : database_empty_result } ;
if ( entry - > invoker = = this - > getClientDatabaseId ( ) )
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_complain_delete_own , 1 ) ;
else
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_complain_delete , 1 ) ;
this - > server - > complains - > deleteComplain ( entry ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandComplainDelAll ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_client_complain_delete , 1 ) ;
ClientDbId tid = cmd [ " tcldbid " ] ;
if ( ! this - > server - > complains - > deleteComplainsFromTarget ( tid ) ) return command_result { error : : database_empty_result } ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandHelp ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_serverinstance_help_view , 1 ) ;
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 command_result { error : : file_not_found } ;
string line ;
ifstream stream ( file ) ;
if ( ! stream ) return command_result { error : : file_io_error } ;
while ( getline ( stream , line ) )
this - > sendCommand ( Command { line } ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandPermReset ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 50 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_permission_reset , 1 ) ;
string token ;
if ( ! this - > server - > resetPermissions ( token ) )
return command_result { error : : vs_critical } ;
Command result ( " " ) ;
result [ " token " ] = token ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandLogView ( ts : : Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 50 ) ;
2020-06-28 08:01:14 -04:00
ServerId target_server = cmd [ 0 ] . has ( " instance " ) & & cmd [ " instance " ] . as < bool > ( ) ? ( ServerId ) 0 : this - > getServerId ( ) ;
if ( target_server = = 0 )
ACTION_REQUIRES_INSTANCE_PERMISSION ( permission : : b_serverinstance_log_view , 1 ) ;
else
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_log_view , 1 ) ;
2020-01-26 08:21:34 -05:00
auto lagacy = this - > getType ( ) = = CLIENT_TEAMSPEAK | | cmd . hasParm ( " lagacy " ) | | cmd . hasParm ( " legacy " ) ;
2020-06-28 08:01:14 -04:00
#if 0
2020-01-26 08:21:34 -05:00
string log_path ;
string server_identifier ;
if ( target_server > 0 )
server_identifier = to_string ( target_server ) ;
else
2020-06-28 08:01:14 -04:00
server_identifier = " [A-Z]{0,7} " ;
2020-01-26 08:21:34 -05:00
for ( const auto & sink : logger : : logger ( target_server ) - > sinks ( ) ) {
if ( dynamic_pointer_cast < spdlog : : sinks : : rotating_file_sink_mt > ( sink ) ) {
log_path = dynamic_pointer_cast < spdlog : : sinks : : rotating_file_sink_mt > ( sink ) - > filename ( ) ;
break ;
} else if ( dynamic_pointer_cast < spdlog : : sinks : : rotating_file_sink_st > ( sink ) ) {
log_path = dynamic_pointer_cast < spdlog : : sinks : : rotating_file_sink_st > ( sink ) - > filename ( ) ;
break ;
}
}
if ( log_path . empty ( ) )
return command_result { error : : 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 ;
}
}
2020-03-03 14:57:35 -05:00
string command = " cat \" " + log_path + " \" " ;
2020-01-26 08:21:34 -05:00
command + = " | grep -E " ;
2020-03-03 14:57:35 -05:00
command + = R " ( " \ ] \ [ . * \ ] ( ) { 0 , 6 } ? ) " + server_identifier + " \ \ | \ " " ;
2020-01-26 08:21:34 -05:00
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 command_result { error : : 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 ) ;
2020-02-28 05:24:07 -05:00
lines . emplace_back ( file_index , line_buffer ) ;
2020-01-26 08:21:34 -05:00
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));
2020-02-28 05:24:07 -05:00
lines . emplace_back ( file_index + cut_offset , line_buffer . substr ( 0 , index ) ) ;
2020-01-26 08:21:34 -05:00
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 command_result { error : : file_io_error , " fread(...) returned " + to_string ( read ) + " ( " + to_string ( errno ) + " ) " } ;
}
if ( ! line_buffer . empty ( ) ) {
2020-02-28 05:24:07 -05:00
lines . emplace_back ( file_index - line_buffer . length ( ) , line_buffer ) ;
2020-01-26 08:21:34 -05:00
if ( lines . size ( ) > max_lines ) lines . pop_front ( ) ;
}
}
//last_pos=1558 file_size=1764 l
if ( lines . empty ( ) ) return command_result { error : : database_empty_result } ;
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 ) ;
}
2020-02-28 05:24:07 -05:00
if ( ts . length ( ) > 1024 )
ts = ts . substr ( 0 , 1024 ) + " ... " ;
2020-01-26 08:21:34 -05:00
result [ index + + ] [ " l " ] = ts ;
} else {
2020-02-28 05:24:07 -05:00
if ( line . length ( ) > 1024 )
line = line . substr ( 0 , 1024 ) + " ... " ;
2020-01-26 08:21:34 -05:00
result [ index + + ] [ " l " ] = line ;
}
}
this - > sendCommand ( result ) ;
2020-06-28 08:01:14 -04:00
# else
constexpr static std : : array < std : : string_view , 5 > log_output {
2020-07-30 05:40:03 -04:00
" located at your TeaSpeak installation folder. All logs could be found there. " ,
2020-06-28 08:01:14 -04:00
" If you need to lookup the TeaSpeak - Server logs, please visit the 'logs/' folder, " ,
2020-07-30 05:40:03 -04:00
" " ,
" In order to lookup the server actions use 'logquery'. " ,
" The command 'logview' is not supported anymore. "
2020-06-28 08:01:14 -04:00
} ;
command_builder result { this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyserverlog " : " " } ;
2020-07-29 16:53:40 -04:00
result . put_unchecked ( 0 , " last_pos " , 0 ) ;
result . put_unchecked ( 0 , " file_size " , 0 ) ;
2020-06-28 08:01:14 -04:00
size_t index { 0 } ;
if ( lagacy ) {
for ( const auto & message : log_output ) {
2020-07-30 05:40:03 -04:00
std : : string line { " 2020-06-27 00:00.000 " + std : : to_string ( index ) + " |CRITICAL|Server Instance | | " } ;
2020-06-28 08:01:14 -04:00
line + = message ;
result . put_unchecked ( index + + , " l " , line ) ;
}
} else {
for ( const auto & message : log_output ) {
2020-07-30 05:40:03 -04:00
std : : string line { " [2020-06-27 00:00:0 " + std : : to_string ( index ) + " ][ERROR] " } ;
2020-06-28 08:01:14 -04:00
line + = message ;
result . put_unchecked ( index + + , " l " , line ) ;
}
}
this - > sendCommand ( result ) ;
# endif
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandLogQuery ( ts : : Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 50 ) ;
uint64_t target_server = ( cmd [ 0 ] . has ( " instance " ) & & cmd [ " instance " ] . as < bool > ( ) ) | | cmd . hasParm ( " instance " ) ? ( ServerId ) 0 : this - > getServerId ( ) ;
if ( target_server = = 0 ) {
ACTION_REQUIRES_INSTANCE_PERMISSION ( permission : : b_serverinstance_log_view , 1 ) ;
} else {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_log_view , 1 ) ;
}
std : : chrono : : system_clock : : time_point timestamp_begin { } , timestamp_end { } ;
if ( cmd [ 0 ] . has ( " begin " ) )
timestamp_begin + = std : : chrono : : milliseconds { cmd [ " begin " ] . as < uint64_t > ( ) } ;
if ( cmd [ 0 ] . has ( " end " ) )
timestamp_end + = std : : chrono : : milliseconds { cmd [ " end " ] . as < uint64_t > ( ) } ;
if ( timestamp_begin < = timestamp_end & & timestamp_begin . time_since_epoch ( ) . count ( ) ! = 0 )
return command_result { error : : parameter_constraint_violation , " begin > end " } ;
size_t limit { 100 } ;
if ( cmd [ 0 ] . has ( " limit " ) )
limit = std : : min ( ( size_t ) 2000 , cmd [ " limit " ] . as < size_t > ( ) ) ;
std : : vector < log : : LoggerGroup > groups { } ;
if ( cmd [ 0 ] . has ( " groups " ) ) {
auto groups_string = cmd [ " groups " ] . string ( ) ;
size_t offset { 0 } , findex ;
do {
findex = groups_string . find ( ' , ' , offset ) ;
auto group_name = groups_string . substr ( offset , findex - offset ) ;
offset = findex + 1 ;
size_t index { 0 } ;
for ( ; index < ( size_t ) log : : LoggerGroup : : MAX ; index + + ) {
auto group = static_cast < log : : LoggerGroup > ( index ) ;
if ( log : : kLoggerGroupName [ ( int ) group ] = = group_name ) {
if ( std : : find ( groups . begin ( ) , groups . end ( ) , group ) ! = groups . end ( ) )
return command_result { error : : parameter_invalid , " groups " } ;
groups . push_back ( group ) ;
}
}
if ( index = = ( size_t ) log : : LoggerGroup : : MAX )
return command_result { error : : parameter_invalid , " groups " } ;
} while ( offset ! = 0 ) ;
}
auto result = serverInstance - > action_logger ( ) - > query ( groups , target_server , timestamp_begin , timestamp_end , limit ) ;
if ( result . empty ( ) )
return command_result { error : : database_empty_result } ;
command_builder notify { this - > notify_response_command ( " notifylogquery " ) } ;
size_t index { 0 } ;
size_t threshold = this - > getType ( ) = = ClientType : : CLIENT_QUERY ? ( size_t ) - 1 : 4096 ; /* limit each command to 4096 bytes */
for ( log : : LogEntryInfo & entry : result ) {
notify . set_bulk ( index , std : : move ( entry . info ) ) ;
if ( index = = 0 )
notify . put_unchecked ( 0 , " sid " , this - > getServerId ( ) ) ;
if ( notify . current_size ( ) > threshold ) {
this - > sendCommand ( notify ) ;
notify . reset ( ) ;
index = 0 ;
}
index + + ;
}
if ( index > 0 )
this - > sendCommand ( notify ) ;
if ( this - > getType ( ) ! = ClientType : : CLIENT_QUERY )
this - > sendCommand ( command_builder { " notifylogqueryfinished " } ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandLogAdd ( ts : : Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 50 ) ;
uint64_t target_server = cmd [ 0 ] . has ( " instance " ) & & cmd [ " instance " ] . as < bool > ( ) ? ( ServerId ) 0 : this - > getServerId ( ) ;
if ( target_server = = 0 ) {
ACTION_REQUIRES_INSTANCE_PERMISSION ( permission : : b_serverinstance_log_add , 1 ) ;
} else {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_log_add , 1 ) ;
}
2020-01-26 08:21:34 -05:00
2020-06-28 08:01:14 -04:00
serverInstance - > action_logger ( ) - > custom_logger . add_log_message ( target_server , this - > ref ( ) , cmd [ " msg " ] ) ;
2020-01-26 08:21:34 -05:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandUpdateMyTsId ( ts : : Command & ) {
if ( config : : voice : : suppress_myts_warnings ) return command_result { error : : ok } ;
return command_result { error : : not_implemented } ;
}
command_result ConnectedClient : : handleCommandUpdateMyTsData ( ts : : Command & ) {
if ( config : : voice : : suppress_myts_warnings ) return command_result { error : : ok } ;
return command_result { error : : not_implemented } ;
}
command_result 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 command_result { error : : server_invalid_id } ;
auto global_list = permission : : v2 : : permission_granted ( 1 ,
server ? server - > calculate_permission ( permission : : b_client_query_list , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) :
serverInstance - > calculate_permission ( permission : : b_client_query_list , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 )
) ;
auto own_list = global_list | | permission : : v2 : : permission_granted ( 1 ,
server ? server - > calculate_permission ( permission : : b_client_query_list_own , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) :
serverInstance - > calculate_permission ( permission : : b_client_query_list_own , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 )
) ;
if ( ! own_list & & ! global_list )
return command_result { 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 command_result { error : : database_empty_result } ;
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 command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandQueryCreate ( ts : : Command & cmd ) {
OptionalServerId server_id = this - > getServerId ( ) ;
if ( cmd [ 0 ] . has ( " server_id " ) )
server_id = cmd [ " server_id " ] ;
2020-03-30 16:53:15 -04:00
2020-01-26 08:21:34 -05:00
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 command_result { error : : server_invalid_id } ;
auto username = cmd [ " client_login_name " ] . as < string > ( ) ;
auto password = cmd [ 0 ] . has ( " client_login_password " ) ? cmd [ " client_login_password " ] . as < string > ( ) : " " ;
auto account = serverInstance - > getQueryServer ( ) - > find_query_account_by_name ( username ) ;
if ( account ) return command_result { error : : query_already_exists } ;
2020-03-30 16:53:15 -04:00
std : : string uid = this - > getUid ( ) ;
if ( cmd [ 0 ] . has ( " cldbid " ) ) {
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( server , cmd [ " cldbid " ] . as < ClientDbId > ( ) ) )
return command_result { error : : database_empty_result } ;
if ( server ) {
if ( ! permission : : v2 : : permission_granted ( 1 , server - > calculate_permission ( permission : : b_client_query_create , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) ) )
return command_result { permission : : b_client_query_create } ;
} else {
if ( ! permission : : v2 : : permission_granted ( 1 , serverInstance - > calculate_permission ( permission : : b_client_query_create , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) ) )
return command_result { permission : : b_client_query_create } ;
}
auto info = serverInstance - > databaseHelper ( ) - > queryDatabaseInfo ( server , { cmd [ " cldbid " ] . as < ClientDbId > ( ) } ) ;
if ( info . empty ( ) )
return command_result { error : : database_empty_result } ;
2020-07-30 14:25:45 -04:00
uid = info [ 0 ] - > client_unique_id ;
2020-03-30 16:53:15 -04:00
} else {
if ( server ) {
if ( ! permission : : v2 : : permission_granted ( 1 , server - > calculate_permission ( permission : : b_client_query_create_own , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) ) )
return command_result { permission : : b_client_query_create_own } ;
} else {
if ( ! permission : : v2 : : permission_granted ( 1 , serverInstance - > calculate_permission ( permission : : b_client_query_create_own , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) ) )
return command_result { permission : : b_client_query_create_own } ;
}
}
if ( password . empty ( ) )
password = rnd_string ( QUERY_PASSWORD_LENGTH ) ;
account = serverInstance - > getQueryServer ( ) - > create_query_account ( username , server_id , uid , password ) ;
2020-01-26 08:21:34 -05:00
if ( ! account )
return command_result { error : : vs_critical } ;
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 command_result { error : : ok } ;
}
command_result 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 command_result { error : : 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 command_result { error : : server_invalid_id } ;
*/
auto delete_all = permission : : v2 : : permission_granted ( 1 ,
server ? server - > calculate_permission ( permission : : b_client_query_delete , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) :
serverInstance - > calculate_permission ( permission : : b_client_query_delete , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 )
) ;
auto delete_own = delete_all | | permission : : v2 : : permission_granted ( 1 ,
server ? server - > calculate_permission ( permission : : b_client_query_delete_own , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) :
serverInstance - > calculate_permission ( permission : : b_client_query_delete_own , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 )
) ;
if ( account - > unique_id = = this - > getUid ( ) ) {
if ( ! delete_own )
return command_result { permission : : b_client_query_delete_own } ;
} else {
if ( ! delete_all )
return command_result { permission : : b_client_query_delete } ;
}
if ( account - > unique_id = = " serveradmin " & & account - > username = = " serveradmin " )
return command_result { error : : vs_critical } ;
serverInstance - > getQueryServer ( ) - > delete_query_account ( account ) ;
return command_result { error : : ok } ;
}
command_result 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 command_result { error : : query_not_exists } ;
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( account - > bound_server ) ;
if ( ! server & & account - > bound_server ! = 0 )
return command_result { error : : server_invalid_id } ;
auto rename_all = permission : : v2 : : permission_granted ( 1 ,
server ? server - > calculate_permission ( permission : : b_client_query_rename , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) :
serverInstance - > calculate_permission ( permission : : b_client_query_rename , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 )
) ;
auto rename_own = rename_all | | permission : : v2 : : permission_granted ( 1 ,
server ? server - > calculate_permission ( permission : : b_client_query_rename_own , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) :
serverInstance - > calculate_permission ( permission : : b_client_query_rename_own , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 )
) ;
if ( account - > unique_id = = this - > getUid ( ) ) {
if ( ! rename_own )
return command_result { permission : : b_client_query_rename_own } ;
} else {
if ( ! rename_all )
return command_result { permission : : b_client_query_rename } ;
}
auto target_account = serverInstance - > getQueryServer ( ) - > find_query_account_by_name ( new_username ) ;
if ( target_account ) return command_result { error : : query_already_exists } ;
if ( account - > unique_id = = " serveradmin " & & account - > username = = " serveradmin " )
return command_result { error : : parameter_invalid } ;
if ( ! serverInstance - > getQueryServer ( ) - > rename_query_account ( account , new_username ) )
return command_result { error : : vs_critical } ;
return command_result { error : : ok } ;
}
command_result 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 command_result { error : : query_not_exists } ;
auto server = serverInstance - > getVoiceServerManager ( ) - > findServerById ( account - > bound_server ) ;
if ( ! server & & account - > bound_server ! = 0 )
return command_result { error : : server_invalid_id } ;
auto change_all = permission : : v2 : : permission_granted ( 1 ,
server ? server - > calculate_permission ( permission : : b_client_query_change_password , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) :
serverInstance - > calculate_permission ( permission : : b_client_query_change_password_global , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 )
) ;
auto change_own = change_all | | permission : : v2 : : permission_granted ( 1 ,
server ? server - > calculate_permission ( permission : : b_client_query_change_own_password , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 ) :
serverInstance - > calculate_permission ( permission : : b_client_query_change_own_password , this - > getClientDatabaseId ( ) , this - > getType ( ) , 0 )
) ;
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 command_result { permission : : b_client_query_change_own_password } ;
} else {
if ( ! change_all )
return command_result { server ? permission : : b_client_query_change_password : permission : : b_client_query_change_password_global } ;
}
if ( ! serverInstance - > getQueryServer ( ) - > change_query_password ( account , password ) )
return command_result { error : : vs_critical } ;
Command result ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifyquerypasswordchanges " : " " ) ;
result [ " client_login_name " ] = account - > username ;
result [ " client_login_password " ] = password ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result 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 & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_ignore_vpn , 0 ) ) ) {
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 command_result { error : : ok } ;
}
}
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 ) {
2020-04-03 19:38:37 -04:00
logMessage ( this - > getServerId ( ) , " [{}] Received new ip location. IP {} traced to {} ({}). " , CLIENT_STR_LOG_PREFIX , this - > getLoggingPeerIp ( ) , loc - > name , loc - > identifier ) ;
2020-01-26 08:21:34 -05:00
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 ( ) ) ;
}
}
this - > properties ( ) [ property : : CONNECTION_CLIENT_IP ] = this - > getLoggingPeerIp ( ) ;
return command_result { error : : ok } ;
}
//conversationhistory cid=1 [cpw=xxx] [timestamp_begin] [timestamp_end (0 := no end)] [message_count (default 25| max 100)] [-merge]
command_result 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 command_result { error : : conversation_invalid_id } ;
auto conversation_id = command [ 0 ] [ " cid " ] . as < ChannelId > ( ) ;
/* test if we have access to the conversation */
2020-07-23 14:28:43 -04:00
if ( conversation_id > 0 ) {
2020-01-26 08:21:34 -05:00
/* 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 command_result { error : : conversation_invalid_id } ;
2020-07-13 05:13:09 -04:00
2020-10-04 09:04:25 -04:00
auto conversation_mode = channel - > channel ( ) - > properties ( ) [ property : : CHANNEL_CONVERSATION_MODE ] . as < ChannelConversationMode > ( ) ;
switch ( conversation_mode ) {
case ChannelConversationMode : : CHANNELCONVERSATIONMODE_PRIVATE :
return command_result { error : : conversation_is_private } ;
case ChannelConversationMode : : CHANNELCONVERSATIONMODE_NONE :
return command_result { error : : conversation_not_exists } ;
case ChannelConversationMode : : CHANNELCONVERSATIONMODE_PUBLIC :
break ;
}
2020-01-26 08:21:34 -05:00
}
/* 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 command_result { error : : conversation_invalid_id } ;
if ( ! command [ 0 ] . has ( " cpw " ) )
command [ 0 ] [ " cpw " ] = " " ;
if ( ! channel - > passwordMatch ( command [ " cpw " ] , true ) )
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_join_ignore_password , 1 , channel - > channelId ( ) ) ;
auto error = this - > calculate_and_get_join_state ( channel ) ;
if ( error ) return command_result { error } ;
}
}
auto conversation_manager = ref_server - > conversation_manager ( ) ;
auto conversation = conversation_manager - > get ( conversation_id ) ;
if ( ! conversation )
return command_result { error : : database_empty_result } ;
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 command_result { error : : 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 command_result { error : : database_empty_result } ;
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 " ) ;
for ( auto it = messages . rbegin ( ) ; it ! = messages . rend ( ) ; it + + ) {
if ( index = = 0 ) {
notify [ index ] [ " cid " ] = conversation_id ;
notify [ index ] [ " flag_volatile " ] = conversation - > volatile_only ( ) ;
}
auto & message = * it ;
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 command_result { error : : conversation_more_data } ;
return command_result { error : : ok } ;
}
command_result 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 */
2020-07-23 14:28:43 -04:00
if ( conversation_id > 0 ) {
2020-01-26 08:21:34 -05:00
/* 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 ;
}
2020-10-04 09:04:25 -04:00
auto conversation_mode = channel - > channel ( ) - > properties ( ) [ property : : CHANNEL_CONVERSATION_MODE ] . as < ChannelConversationMode > ( ) ;
switch ( conversation_mode ) {
case ChannelConversationMode : : CHANNELCONVERSATIONMODE_PRIVATE : {
auto error = findError ( " conversation_is_private " ) ;
result_bulk [ " error_id " ] = error . errorId ;
result_bulk [ " error_msg " ] = error . message ;
continue ;
}
case ChannelConversationMode : : CHANNELCONVERSATIONMODE_NONE : {
auto error = findError ( " conversation_not_exists " ) ;
result_bulk [ " error_id " ] = error . errorId ;
result_bulk [ " error_msg " ] = error . message ;
continue ;
}
case ChannelConversationMode : : CHANNELCONVERSATIONMODE_PUBLIC :
break ;
2020-01-26 08:21:34 -05:00
}
}
/* 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 ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_join_ignore_password , 1 , channel - > channelId ( ) ) ) ) {
auto error = findError ( " channel_invalid_password " ) ;
result_bulk [ " error_id " ] = error . errorId ;
result_bulk [ " error_msg " ] = error . message ;
continue ;
}
if ( auto error_perm = this - > calculate_and_get_join_state ( channel ) ; error_perm ) {
auto error = findError ( " server_insufficeient_permissions " ) ;
result_bulk [ " error_id " ] = error . errorId ;
result_bulk [ " error_msg " ] = error . message ;
result_bulk [ " failed_permid " ] = ( int ) error_perm ;
continue ;
}
}
}
auto conversation = conversation_manager - > get ( conversation_id ) ;
2020-07-13 05:13:09 -04:00
if ( conversation ) {
2020-01-26 08:21:34 -05:00
result_bulk [ " timestamp " ] = duration_cast < milliseconds > ( conversation - > last_message ( ) . time_since_epoch ( ) ) . count ( ) ;
2020-07-13 05:13:09 -04:00
result_bulk [ " flag_volatile " ] = conversation - > volatile_only ( ) ;
} else {
2020-01-26 08:21:34 -05:00
result_bulk [ " timestamp " ] = 0 ;
2020-07-13 05:13:09 -04:00
result_bulk [ " flag_volatile " ] = false ;
}
2020-01-26 08:21:34 -05:00
}
if ( result_index = = 0 )
return command_result { error : : database_empty_result } ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandConversationMessageDelete ( ts : : Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto conversation_manager = ref_server - > conversation_manager ( ) ;
std : : shared_ptr < conversation : : Conversation > current_conversation ;
ChannelId current_conversation_id = 0 ;
for ( size_t index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto & bulk = cmd [ index ] ;
if ( ! bulk . has ( " cid " ) | | ! bulk [ " cid " ] . castable < ChannelId > ( ) )
continue ;
/* test if we have access to the conversation */
if ( current_conversation_id ! = bulk [ " cid " ] . as < ChannelId > ( ) ) {
current_conversation_id = bulk [ " cid " ] . as < ChannelId > ( ) ;
/* test if we're able to see the channel */
{
shared_lock channel_view_lock ( this - > channel_lock ) ;
auto channel = this - > channel_view ( ) - > find_channel ( current_conversation_id ) ;
if ( ! channel )
return command_result { error : : 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 ( current_conversation_id ) ;
if ( ! channel )
return command_result { error : : conversation_invalid_id } ;
if ( ! bulk . has ( " cpw " ) )
bulk [ " cpw " ] = " " ;
if ( ! channel - > passwordMatch ( bulk [ " cpw " ] , true ) )
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_join_ignore_password , 1 , channel - > channelId ( ) ) ;
2020-07-13 05:13:09 -04:00
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_conversation_message_delete , channel - > channelId ( ) ) ) )
2020-01-26 08:21:34 -05:00
return command_result { permission : : b_channel_conversation_message_delete } ;
2020-02-18 05:53:33 -05:00
if ( auto error_perm = this - > calculate_and_get_join_state ( channel ) ; error_perm ! = permission : : ok & & error_perm ! = permission : : b_client_is_sticky )
2020-01-26 08:21:34 -05:00
return command_result { error_perm } ;
}
}
current_conversation = conversation_manager - > get ( current_conversation_id ) ;
if ( ! current_conversation ) continue ;
auto timestamp_begin = system_clock : : time_point { } + milliseconds { bulk [ " timestamp_begin " ] } ;
auto timestamp_end = system_clock : : time_point { } + milliseconds { bulk . has ( " timestamp_end " ) ? bulk [ " timestamp_end " ] . as < uint64_t > ( ) : 0 } ;
auto limit = bulk . has ( " limit " ) ? bulk [ " limit " ] . as < uint64_t > ( ) : 1 ;
if ( limit > 100 )
limit = 100 ;
2020-07-13 05:13:09 -04:00
2020-01-26 08:21:34 -05:00
auto delete_count = current_conversation - > delete_messages ( timestamp_end , limit , timestamp_begin , bulk [ " cldbid " ] ) ;
if ( delete_count > 0 ) {
for ( const auto & client : ref_server - > getClients ( ) ) {
if ( client - > connectionState ( ) ! = ConnectionState : : CONNECTED )
continue ;
auto type = client - > getType ( ) ;
if ( type = = ClientType : : CLIENT_INTERNAL | | type = = ClientType : : CLIENT_MUSIC )
continue ;
client - > notifyConversationMessageDelete ( current_conversation_id , timestamp_begin , timestamp_end , bulk [ " cldbid " ] , delete_count ) ;
}
}
}
return command_result { error : : ok } ;
}
2020-06-16 06:57:20 -04:00
enum struct FeatureSupportMode {
NONE ,
FULL ,
EXPERIMENTAL ,
DEPRECATED
} ;
# define REGISTER_FEATURE(name, support, version) \
notify . put_unchecked ( index , " name " , name ) ; \
notify . put_unchecked ( index , " support " , ( int ) support ) ; \
notify . put_unchecked ( index , " version " , version ) ; \
index + +
command_result ConnectedClient : : handleCommandListFeatureSupport ( ts : : Command & cmd ) {
ts : : command_builder notify { this - > notify_response_command ( " notifyfeaturesupport " ) } ;
int index { 0 } ;
2020-01-26 08:21:34 -05:00
2020-06-16 06:57:20 -04:00
REGISTER_FEATURE ( " error-bulks " , FeatureSupportMode : : FULL , 1 ) ;
REGISTER_FEATURE ( " advanced-channel-chat " , FeatureSupportMode : : FULL , 1 ) ;
2020-06-28 08:07:07 -04:00
REGISTER_FEATURE ( " log-query " , FeatureSupportMode : : FULL , 1 ) ;
2020-09-06 15:00:27 -04:00
REGISTER_FEATURE ( " whisper-echo " , FeatureSupportMode : : FULL , 1 ) ;
2020-11-07 07:17:51 -05:00
REGISTER_FEATURE ( " video " , FeatureSupportMode : : EXPERIMENTAL , 1 ) ;
2020-06-16 06:57:20 -04:00
this - > sendCommand ( notify ) ;
return command_result { error : : ok } ;
}
2020-01-26 08:21:34 -05:00