2020-01-26 14:21:34 +01:00
# include <memory>
# include <bitset>
# include <algorithm>
# include "../../build.h"
# include "../ConnectedClient.h"
# include "../InternalClient.h"
# include "../../server/file/FileServer.h"
# include "../../server/VoiceServer.h"
# include "../voice/VoiceClient.h"
# include "PermissionManager.h"
# include "../../InstanceHandler.h"
# include "../../server/QueryServer.h"
# include "../file/FileClient.h"
# include "../music/MusicClient.h"
# include "../query/QueryClient.h"
# include "../../weblist/WebListManager.h"
# include "../../manager/ConversationManager.h"
# include "../../manager/PermissionNameMapper.h"
# include <cstdint>
# include "helpers.h"
# include <Properties.h>
# include <log/LogUtils.h>
# include <misc/sassert.h>
# include <misc/base64.h>
# include <misc/digest.h>
# include <bbcode/bbcodes.h>
using namespace std : : chrono ;
using namespace std ;
using namespace ts ;
using namespace ts : : server ;
using namespace ts : : token ;
/ / { findError ( " parameter_invalid " ) , " could not resolve permission " + ( cmd [ index ] . has ( " permid " ) ? cmd [ index ] [ " permid " ] . as < string > ( ) : cmd [ index ] [ " permsid " ] . as < string > ( ) ) } ; \
//TODO: Log missing permissions?
command_result ConnectedClient : : handleCommandChannelGetDescription ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 0 ) ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < BasicChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_ignore_description_view_power , channel - > channelId ( ) ) ) ) {
2020-02-15 14:03:46 +01:00
auto view_power = this - > calculate_permission ( permission : : i_channel_description_view_power , channel - > channelId ( ) ) ;
if ( ! channel - > permission_granted ( permission : : i_channel_needed_description_view_power , view_power , false ) )
return command_result { permission : : i_channel_description_view_power } ;
2020-01-26 14:21:34 +01:00
}
this - > sendChannelDescription ( channel , true ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelSubscribe ( Command & cmd ) {
CMD_REF_SERVER ( ref_server ) ;
CMD_RESET_IDLE ;
bool flood_points = false ;
deque < shared_ptr < BasicChannel > > channels ;
{
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto local_channel = this - > channel_view ( ) - > find_channel ( cmd [ index ] [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! local_channel )
return command_result { error : : channel_invalid_id , " Cant resolve channel " } ;
auto channel = this - > server - > channelTree - > findChannel ( cmd [ index ] [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel )
return command_result { error : : channel_invalid_id , " Cant resolve channel " } ;
channels . push_back ( channel ) ;
if ( ! flood_points & & system_clock : : now ( ) - local_channel - > view_timestamp > seconds ( 5 ) ) {
flood_points = true ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 15 ) ;
}
}
if ( ! channels . empty ( ) )
this - > subscribeChannel ( channels , false , false ) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelSubscribeAll ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 20 ) ;
{
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock ) ;
this - > subscribeChannel ( this - > server - > channelTree - > channels ( ) , false , false ) ;
this - > subscribeToAll = true ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelUnsubscribe ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
{
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock ) ;
deque < shared_ptr < BasicChannel > > channels ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) continue ;
channels . push_front ( channel ) ;
}
this - > unsubscribeChannel ( channels , false ) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelUnsubscribeAll ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
{
shared_lock server_channel_lock ( this - > server - > channel_tree_lock ) ;
unique_lock client_channel_lock ( this - > channel_lock ) ;
this - > unsubscribeChannel ( this - > server - > channelTree - > channels ( ) , false ) ;
this - > subscribeToAll = false ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelGroupAdd ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_channelgroup_create , 1 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
if ( cmd [ " type " ] . as < GroupType > ( ) = = GroupType : : GROUP_TYPE_NORMAL & & ! this - > server ) return command_result { error : : parameter_invalid , " You cant create normal channel groups on the template server " } ;
if ( cmd [ " name " ] . string ( ) . empty ( ) ) return command_result { error : : parameter_invalid , " invalid group name " } ;
for ( const auto & gr : group_manager - > availableServerGroups ( true ) )
if ( gr - > name ( ) = = cmd [ " name " ] . string ( ) & & gr - > target ( ) = = GroupTarget : : GROUPTARGET_CHANNEL ) return command_result { error : : parameter_invalid , " Group already exists " } ;
auto group = group_manager - > createGroup ( GroupTarget : : GROUPTARGET_CHANNEL , cmd [ " type " ] . as < GroupType > ( ) , cmd [ " name " ] . string ( ) ) ;
if ( group ) {
group - > permissions ( ) - > set_permission ( permission : : b_group_is_permanent , { 1 , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
if ( this - > server )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
} else return command_result { error : : group_invalid_id } ;
return command_result { error : : ok } ;
}
//name=Channel\sAdmin scgid=5 tcgid=4 type=1
command_result ConnectedClient : : handleCommandChannelGroupCopy ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_channelgroup_create , 1 ) ;
auto ref_server = this - > server ;
auto group_manager = this - > server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ;
auto source_group_id = cmd [ " scgid " ] . as < GroupId > ( ) ;
auto source_group = group_manager - > findGroup ( source_group_id ) ;
if ( ! source_group | | source_group - > target ( ) ! = GROUPTARGET_CHANNEL )
return command_result { error : : group_invalid_id , " invalid source group " } ;
const auto group_type_modificable = [ & ] ( GroupType type ) {
switch ( type ) {
case GroupType : : GROUP_TYPE_TEMPLATE :
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_serverinstance_modify_templates , 0 ) ) )
return permission : : b_serverinstance_modify_templates ;
break ;
case GroupType : : GROUP_TYPE_QUERY :
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_serverinstance_modify_querygroup , 0 ) ) )
return permission : : b_serverinstance_modify_querygroup ;
break ;
default :
break ;
}
return permission : : undefined ;
} ;
{
auto result = group_type_modificable ( source_group - > type ( ) ) ;
if ( result ! = permission : : undefined )
return command_result { result } ;
}
auto global_update = false ;
if ( cmd [ 0 ] . has ( " tcgid " ) & & cmd [ " tcgid " ] . as < GroupId > ( ) ! = 0 ) {
//Copy an existing group
auto target_group = group_manager - > findGroup ( cmd [ " tcgid " ] ) ;
if ( ! target_group | | target_group - > target ( ) ! = GROUPTARGET_CHANNEL )
return command_result { error : : group_invalid_id , " invalid target group " } ;
{
auto result = group_type_modificable ( target_group - > type ( ) ) ;
if ( result ! = permission : : undefined )
return command_result { result } ;
}
if ( ! target_group - > permission_granted ( permission : : i_channel_group_needed_modify_power , this - > calculate_permission ( permission : : i_channel_group_modify_power , 0 ) , true ) )
return command_result { permission : : i_channel_group_modify_power } ;
if ( ! group_manager - > copyGroupPermissions ( source_group , target_group ) )
return command_result { error : : vs_critical , " failed to copy group permissions " } ;
global_update = ! this - > server | | ! group_manager - > isLocalGroup ( target_group ) ;
} else {
//Copy a new group
auto target_type = cmd [ " type " ] . as < GroupType > ( ) ;
{
auto result = group_type_modificable ( target_type ) ;
if ( result ! = permission : : undefined )
return command_result { result } ;
}
if ( ! ref_server & & target_type = = GroupType : : GROUP_TYPE_NORMAL )
return command_result { error : : parameter_invalid , " You cant create normal groups on the template server! " } ;
if ( ! group_manager - > findGroup ( GroupTarget : : GROUPTARGET_CHANNEL , cmd [ " name " ] . string ( ) ) . empty ( ) )
return command_result { error : : group_name_inuse , " You cant create normal groups on the template server! " } ;
auto target_group_id = group_manager - > copyGroup ( source_group , target_type , cmd [ " name " ] , target_type ! = GroupType : : GROUP_TYPE_NORMAL ? 0 : this - > getServerId ( ) ) ;
if ( target_group_id = = 0 )
return command_result { error : : vs_critical , " failed to copy group " } ;
if ( this - > getType ( ) = = ClientType : : CLIENT_QUERY ) {
Command notify ( " " ) ;
notify [ " cgid " ] = target_group_id ;
this - > sendCommand ( notify ) ;
}
global_update = ! this - > server | | ! group_manager - > isLocalGroup ( group_manager - > findGroup ( target_group_id ) ) ;
}
2020-01-26 18:04:38 +01:00
for ( const auto & server : ( global_update ? serverInstance - > getVoiceServerManager ( ) - > serverInstances ( ) : deque < shared_ptr < VirtualServer > > { this - > server } ) )
2020-01-26 14:21:34 +01:00
if ( server )
server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelGroupRename ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto channel_group = group_manager - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! channel_group | | channel_group - > target ( ) ! = GROUPTARGET_CHANNEL ) return command_result { error : : parameter_invalid , " invalid channel group id " } ;
ACTION_REQUIRES_GROUP_PERMISSION ( channel_group , permission : : i_channel_group_needed_modify_power , permission : : i_channel_group_modify_power , true ) ;
group_manager - > renameGroup ( channel_group , cmd [ " name " ] . string ( ) ) ;
if ( this - > server )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelGroupDel ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_channelgroup_delete , 1 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto channel_group = group_manager - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! channel_group | | channel_group - > target ( ) ! = GROUPTARGET_CHANNEL ) return command_result { error : : parameter_invalid , " invalid channel group id " } ;
if ( this - > server ) {
if ( this - > server - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_GROUP ] = = channel_group - > groupId ( ) )
return command_result { error : : parameter_invalid , " Could not delete default channel group! " } ;
if ( this - > server - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] = = channel_group - > groupId ( ) )
return command_result { error : : parameter_invalid , " Could not delete default channel admin group! " } ;
}
if ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_CHANNELDEFAULT_GROUP ] = = channel_group - > groupId ( ) )
return command_result { error : : parameter_invalid , " Could not delete instance default channel group! " } ;
if ( serverInstance - > properties ( ) [ property : : SERVERINSTANCE_TEMPLATE_CHANNELADMIN_GROUP ] = = channel_group - > groupId ( ) )
return command_result { error : : parameter_invalid , " Could not delete instance default channel admin group! " } ;
if ( ! cmd [ " force " ] . as < bool > ( ) )
if ( ! group_manager - > listGroupMembers ( channel_group , false ) . empty ( ) )
return command_result { error : : database_empty_result , " group not empty! " } ;
if ( group_manager - > deleteGroup ( channel_group ) & & this - > server ) {
this - > server - > forEachClient ( [ & ] ( shared_ptr < ConnectedClient > cl ) {
if ( this - > server - > notifyClientPropertyUpdates ( cl , this - > server - > groups - > update_server_group_property ( cl , true , cl - > getChannel ( ) ) ) ) {
if ( cl - > update_cached_permissions ( ) ) /* update cached calculated permissions */
cl - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
}
cl - > notifyChannelGroupList ( ) ;
} ) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelGroupList ( Command & ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_channelgroup_list , 1 ) ;
this - > notifyChannelGroupList ( ) ;
this - > command_times . servergrouplist = system_clock : : now ( ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelGroupClientList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto target_channel_id = cmd [ 0 ] . has ( " cid " ) ? cmd [ " cid " ] . as < ChannelId > ( ) : 0 ;
if ( target_channel_id > 0 ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_virtualserver_channelgroup_client_list , 1 , target_channel_id ) ;
} else {
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_channelgroup_client_list , 1 ) ;
}
Command result ( this - > getExternalType ( ) = = ClientType : : CLIENT_TEAMSPEAK ? " notifychannelgroupclientlist " : " " ) ;
deque < variable > variables { variable { " :sid " , this - > getServerId ( ) } } ;
string query = " SELECT `groupId`, `cldbid`, `until`, `channelId` FROM `assignedGroups` WHERE `serverId` = :sid " ;
if ( cmd [ 0 ] . has ( " cgid " ) & & cmd [ " cgid " ] . as < GroupId > ( ) > 0 ) {
auto group = this - > server - > getGroupManager ( ) - > findGroup ( cmd [ " cgid " ] ) ;
if ( ! group | | group - > target ( ) ! = GroupTarget : : GROUPTARGET_CHANNEL )
return command_result { error : : parameter_invalid , " invalid channel group id " } ;
query + = " AND `groupId` = :groupId " ;
variables . push_back ( { " :groupId " , cmd [ " cgid " ] . as < GroupId > ( ) } ) ;
} else {
query + = " AND `groupId` IN (SELECT `groupId` FROM `groups` WHERE `serverId` = :sid AND `target` = :target) " ;
variables . push_back ( { " :target " , GroupTarget : : GROUPTARGET_CHANNEL } ) ;
}
if ( cmd [ 0 ] . has ( " cldbid " ) & & cmd [ " cldbid " ] . as < ClientDbId > ( ) > 0 ) {
query + = " AND `cldbid` = :cldbid " ;
variables . push_back ( { " :cldbid " , cmd [ " cldbid " ] . as < ClientDbId > ( ) } ) ;
}
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] . as < ChannelId > ( ) > 0 ) {
auto channel = this - > server - > getChannelTree ( ) - > findChannel ( cmd [ " cid " ] ) ;
if ( ! channel )
return command_result { error : : parameter_invalid , " invalid channel id " } ;
query + = " AND `channelId` = :cid " ;
variables . push_back ( { " :cid " , cmd [ " cid " ] . as < ChannelId > ( ) } ) ;
}
debugMessage ( this - > getServerId ( ) , " Command channelgroupclientlist sql: {} " , query ) ;
auto command = sql : : command ( this - > sql , query ) ;
for ( const auto & variable : variables )
command . value ( variable ) ;
int index = 0 ;
command . query ( [ & ] ( Command & command , int & index , int length , string * values , string * names ) {
GroupId group_id = 0 ;
ChannelId channel_id = 0 ;
ClientDbId cldbid = 0 ;
for ( int i = 0 ; i < length ; i + + ) {
try {
if ( names [ i ] = = " groupId " )
group_id = stoll ( values [ i ] ) ;
else if ( names [ i ] = = " cldbid " )
cldbid = stoll ( values [ i ] ) ;
else if ( names [ i ] = = " channelId " )
channel_id = stoll ( values [ i ] ) ;
} catch ( std : : exception & ex ) {
logError ( this - > getServerId ( ) , " Failed to parse db field {} " , names [ i ] ) ;
}
}
result [ index ] [ " cid " ] = channel_id ;
result [ index ] [ " cgid " ] = group_id ;
result [ index ] [ " cldbid " ] = cldbid ;
index + + ;
} , result , index ) ;
if ( index = = 0 ) return command_result { error : : database_empty_result } ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelGroupPermList ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_virtualserver_channelgroup_permission_list , 1 ) ;
auto channelGroup = ( this - > server ? this - > server - > groups : serverInstance - > getGroupManager ( ) . get ( ) ) - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! channelGroup | | channelGroup - > target ( ) ! = GROUPTARGET_CHANNEL ) return command_result { error : : parameter_invalid , " invalid channel group id " } ;
if ( ! this - > notifyGroupPermList ( channelGroup , cmd . hasParm ( " permsid " ) ) ) return command_result { error : : database_empty_result } ;
if ( this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK & & this - > command_times . last_notify + this - > command_times . notify_timeout < system_clock : : now ( ) ) {
this - > sendTSPermEditorWarning ( ) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelGroupAddPerm ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto channelGroup = group_manager - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! channelGroup | | channelGroup - > target ( ) ! = GROUPTARGET_CHANNEL ) return command_result { error : : parameter_invalid , " invalid channel group id " } ;
ACTION_REQUIRES_GROUP_PERMISSION ( channelGroup , permission : : i_channel_group_needed_modify_power , permission : : i_channel_group_modify_power , true ) ;
auto max_value = this - > calculate_permission ( permission : : i_permission_modify_power , 0 , true ) ;
if ( ! max_value . has_value ) return command_result { permission : : i_permission_modify_power } ;
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , 0 ) ) ;
auto conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
bool updateList = false ;
auto permission_manager = channelGroup - > permissions ( ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & ! permission : : v2 : : permission_granted ( val , max_value ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
2020-02-03 19:41:18 +01:00
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permType , 0 , true ) ) ) {
2020-01-26 14:21:34 +01:00
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
if ( grant ) {
permission_manager - > set_permission ( permType , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : set_value ) ;
} else {
permission_manager - > set_permission (
permType ,
{ cmd [ index ] [ " permvalue " ] , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing ,
cmd [ index ] [ " permskip " ] . as < bool > ( ) ? 1 : 0 ,
cmd [ index ] [ " permnegated " ] . as < bool > ( ) ? 1 : 0
) ;
updateList | = permission_is_group_property ( permType ) ;
}
}
if ( updateList )
channelGroup - > apply_properties_from_permissions ( ) ;
if ( this - > server ) {
if ( updateList )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
this - > server - > forEachClient ( [ channelGroup ] ( shared_ptr < ConnectedClient > cl ) {
unique_lock client_channel_lock ( cl - > channel_lock ) ; /* while we're updating groups we dont want to change anything! */
if ( cl - > channelGroupAssigned ( channelGroup , cl - > getChannel ( ) ) ) {
if ( cl - > update_cached_permissions ( ) )
cl - > sendNeededPermissions ( false ) ; /* update the needed permissions */
cl - > updateChannelClientProperties ( false , true ) ;
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
} ) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelGroupDelPerm ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto group_manager = this - > server ? this - > server - > getGroupManager ( ) : serverInstance - > getGroupManager ( ) . get ( ) ;
auto channelGroup = group_manager - > findGroup ( cmd [ " cgid " ] . as < GroupId > ( ) ) ;
if ( ! channelGroup | | channelGroup - > target ( ) ! = GROUPTARGET_CHANNEL ) return command_result { error : : parameter_invalid , " invalid channel group id " } ;
ACTION_REQUIRES_GROUP_PERMISSION ( channelGroup , permission : : i_channel_group_needed_modify_power , permission : : i_channel_group_modify_power , true ) ;
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , 0 ) ) ;
bool updateList = false ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto permission_manager = channelGroup - > permissions ( ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd )
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 0 , this - > calculate_permission ( permType , 0 , true ) ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
if ( grant ) {
permission_manager - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : delete_value ) ;
} else {
permission_manager - > set_permission (
permType ,
permission : : v2 : : empty_permission_values ,
permission : : v2 : : PermissionUpdateType : : delete_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing
) ;
updateList | = permission_is_group_property ( permType ) ;
}
}
if ( updateList )
channelGroup - > apply_properties_from_permissions ( ) ;
if ( this - > server ) {
if ( updateList )
this - > server - > forEachClient ( [ ] ( shared_ptr < ConnectedClient > cl ) {
cl - > notifyChannelGroupList ( ) ;
} ) ;
this - > server - > forEachClient ( [ channelGroup ] ( shared_ptr < ConnectedClient > cl ) {
unique_lock client_channel_lock ( cl - > channel_lock ) ; /* while we're updating groups we dont want to change anything! */
if ( cl - > channelGroupAssigned ( channelGroup , cl - > getChannel ( ) ) ) {
if ( cl - > update_cached_permissions ( ) ) /* update cached calculated permissions */
cl - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
cl - > updateChannelClientProperties ( false , false ) ;
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
} ) ;
}
return command_result { error : : ok } ;
}
//TODO: Test if parent or previous is deleted!
command_result ConnectedClient : : handleCommandChannelCreate ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
CMD_CHK_PARM_COUNT ( 1 ) ;
//TODO: Use for this here the cache as well!
auto permission_cache = make_shared < CalculateCache > ( ) ;
if ( cmd [ 0 ] . has ( " cpid " ) & & cmd [ " cpid " ] . as < uint64_t > ( ) ! = 0 ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_child , 1 , permission_cache ) ;
if ( cmd [ 0 ] . has ( " channel_order " ) ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_with_sortorder , 1 , permission_cache ) ;
if ( ! cmd [ 0 ] . has ( " channel_flag_permanent " ) ) cmd [ 0 ] [ " channel_flag_permanent " ] = false ;
if ( ! cmd [ 0 ] . has ( " channel_flag_semi_permanent " ) ) cmd [ 0 ] [ " channel_flag_semi_permanent " ] = false ;
if ( ! cmd [ 0 ] . has ( " channel_flag_default " ) ) cmd [ 0 ] [ " channel_flag_default " ] = false ;
if ( ! cmd [ 0 ] . has ( " channel_flag_password " ) ) cmd [ 0 ] [ " channel_flag_password " ] = false ;
if ( cmd [ 0 ] [ " channel_flag_permanent " ] . as < bool > ( ) ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_permanent , 1 , permission_cache ) ;
else if ( cmd [ 0 ] [ " channel_flag_semi_permanent " ] . as < bool > ( ) ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_semi_permanent , 1 , permission_cache ) ;
else ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_temporary , 1 , permission_cache ) ;
if ( ! cmd [ 0 ] [ " channel_flag_permanent " ] . as < bool > ( ) & & ! this - > server ) return command_result { error : : parameter_invalid , " You can only create a permanent channel " } ;
if ( cmd [ 0 ] [ " channel_flag_default " ] . as < bool > ( ) ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_with_default , 1 , permission_cache ) ;
if ( cmd [ 0 ] [ " channel_flag_password " ] . as < bool > ( ) ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_with_password , 1 , permission_cache ) ;
else if ( permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_channel_create_modify_with_force_password , 0 , false , permission_cache ) ) )
return command_result { permission : : b_channel_create_modify_with_force_password } ;
if ( cmd [ 0 ] . has ( " channel_password " ) & & this - > getType ( ) = = ClientType : : CLIENT_QUERY )
cmd [ " channel_password " ] = base64 : : decode ( digest : : sha1 ( cmd [ " channel_password " ] . string ( ) ) ) ;
if ( cmd [ 0 ] . has ( " channel_description " ) ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_with_description , 1 , permission_cache ) ;
if ( cmd [ 0 ] . has ( " channel_maxclients " ) | | ( cmd [ 0 ] . has ( " channel_flag_maxclients_unlimited " ) & & ! cmd [ " channel_flag_maxclients_unlimited " ] . as < bool > ( ) ) ) {
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_with_maxclients , 1 , permission_cache ) ;
if ( ! cmd [ 0 ] [ " channel_flag_permanent " ] . as < bool > ( ) & & ! cmd [ 0 ] [ " channel_flag_semi_permanent " ] . as < bool > ( ) ) {
cmd [ " channel_maxclients " ] = - 1 ;
cmd [ " channel_flag_maxclients_unlimited " ] = 1 ;
}
}
if ( cmd [ 0 ] . has ( " channel_maxfamilyclients " ) ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_with_maxfamilyclients , 1 , permission_cache ) ;
if ( cmd [ 0 ] . has ( " channel_needed_talk_power " ) ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_with_needed_talk_power , 1 , permission_cache ) ;
if ( cmd [ 0 ] . has ( " channel_topic " ) ) ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_with_topic , 1 , permission_cache ) ;
auto target_tree = this - > server ? this - > server - > channelTree : serverInstance - > getChannelTree ( ) . get ( ) ;
auto & tree_lock = this - > server ? this - > server - > channel_tree_lock : serverInstance - > getChannelTreeLock ( ) ;
unique_lock tree_channel_lock ( tree_lock ) ;
if ( cmd [ 0 ] . has ( " channel_conversation_history_length " ) ) {
auto value = cmd [ " channel_conversation_history_length " ] . as < int64_t > ( ) ;
if ( value = = 0 ) {
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : b_channel_create_modify_conversation_history_unlimited , 1 , permission_cache ) ;
} else {
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : i_channel_create_modify_conversation_history_length , 1 , permission_cache ) ;
}
}
{
auto delete_delay = cmd [ 0 ] . has ( " channel_delete_delay " ) ? cmd [ " channel_delete_delay " ] . as < permission : : PermissionValue > ( ) : 0UL ;
if ( delete_delay = = 0 ) {
if ( this - > server )
cmd [ " channel_delete_delay " ] = this - > server - > properties ( ) [ property : : VIRTUALSERVER_CHANNEL_TEMP_DELETE_DELAY_DEFAULT ] . as < uint32_t > ( ) ;
else
cmd [ " channel_delete_delay " ] = 0 ;
} else {
ACTION_REQUIRES_GLOBAL_PERMISSION_CACHED ( permission : : i_channel_create_modify_with_temp_delete_delay , cmd [ " channel_delete_delay " ] . as < permission : : PermissionValue > ( ) , permission_cache ) ;
}
}
{
2020-01-26 16:33:48 +01:00
size_t created_total = 0 , created_tmp = 0 , created_semi = 0 , created_perm = 0 ;
2020-01-26 14:21:34 +01:00
auto own_cldbid = this - > getClientDatabaseId ( ) ;
for ( const auto & channel : target_tree - > channels ( ) ) {
2020-01-26 16:33:48 +01:00
created_total + + ;
2020-01-26 14:21:34 +01:00
if ( channel - > properties ( ) [ property : : CHANNEL_CREATED_BY ] = = own_cldbid ) {
if ( channel - > properties ( ) [ property : : CHANNEL_FLAG_PERMANENT ] . as < bool > ( ) )
created_perm + + ;
else if ( channel - > properties ( ) [ property : : CHANNEL_FLAG_SEMI_PERMANENT ] . as < bool > ( ) )
created_semi + + ;
else
created_tmp + + ;
}
}
2020-02-15 14:03:46 +01:00
if ( this - > server & & created_total > = this - > server - > properties ( ) [ property : : VIRTUALSERVER_MAX_CHANNELS ] . as < uint64_t > ( ) )
2020-01-26 16:33:48 +01:00
return command_result { error : : channel_limit_reached } ;
2020-01-26 14:21:34 +01:00
auto max_channels = this - > calculate_permission ( permission : : i_client_max_channels , 0 , false , permission_cache ) ;
if ( max_channels . has_value ) {
if ( ! permission : : v2 : : permission_granted ( created_perm + created_semi + created_tmp + 1 , max_channels ) )
return command_result { permission : : i_client_max_channels } ;
}
if ( cmd [ 0 ] [ " channel_flag_permanent " ] . as < bool > ( ) ) {
max_channels = this - > calculate_permission ( permission : : i_client_max_permanent_channels , 0 , false , permission_cache ) ;
if ( max_channels . has_value ) {
if ( ! permission : : v2 : : permission_granted ( created_perm + 1 , max_channels ) )
return command_result { permission : : i_client_max_permanent_channels } ;
}
}
else if ( cmd [ 0 ] [ " channel_flag_semi_permanent " ] . as < bool > ( ) ) {
max_channels = this - > calculate_permission ( permission : : i_client_max_semi_channels , 0 , false , permission_cache ) ;
if ( max_channels . has_value ) {
if ( ! permission : : v2 : : permission_granted ( created_semi + 1 , max_channels ) )
return command_result { permission : : i_client_max_semi_channels } ;
}
}
else {
max_channels = this - > calculate_permission ( permission : : i_client_max_temporary_channels , 0 , false , permission_cache ) ;
if ( max_channels . has_value ) {
if ( ! permission : : v2 : : permission_granted ( created_tmp + 1 , max_channels ) )
return command_result { permission : : i_client_max_temporary_channels } ;
}
}
}
//TODO check voice (opus etc)
std : : shared_ptr < TreeView : : LinkedTreeEntry > parent = nullptr ;
std : : shared_ptr < BasicChannel > created_channel = nullptr , old_default_channel ;
//bool enforce_permanent_parent = cmd[0]["channel_flag_default"].as<bool>(); //TODO check parents here
{ //Checkout the parent(s)
if ( cmd [ 0 ] . has ( " cpid " ) & & cmd [ " cpid " ] . as < ChannelId > ( ) ! = 0 & & cmd [ " cpid " ] . as < int > ( ) ! = - 1 ) {
parent = target_tree - > findLinkedChannel ( cmd [ " cpid " ] . as < ChannelId > ( ) ) ;
if ( ! parent ) return command_result { error : : channel_invalid_id , " Cant resolve parent channel " } ;
}
{
auto min_channel_deep = this - > calculate_permission ( permission : : i_channel_min_depth , 0 , false , permission_cache ) ;
auto max_channel_deep = this - > calculate_permission ( permission : : i_channel_max_depth , 0 , false , permission_cache ) ;
if ( min_channel_deep . has_value | | max_channel_deep . has_value ) {
auto channel_deep = 0 ;
auto local_parent = parent ;
while ( local_parent ) {
channel_deep + + ;
{
const auto typed_parent = dynamic_pointer_cast < ServerChannel > ( local_parent - > entry ) ;
if ( typed_parent - > deleted ) return command_result { error : : channel_is_deleted , " One of the parents has been deleted " } ;
}
local_parent = local_parent - > parent . lock ( ) ;
}
if ( min_channel_deep . has_value & & ( channel_deep < min_channel_deep . value & & ! min_channel_deep . has_infinite_power ( ) ) ) return command_result { permission : : i_channel_min_depth } ;
if ( max_channel_deep . has_value & & ! permission : : v2 : : permission_granted ( channel_deep , max_channel_deep ) ) return command_result { permission : : i_channel_max_depth } ;
}
}
}
if ( ! cmd [ 0 ] . has ( " channel_order " ) ) {
auto last = parent ? parent - > child_head : target_tree - > tree_head ( ) ;
while ( last & & last - > next )
last = last - > next ;
if ( last )
cmd [ " channel_order " ] = last - > entry - > channelId ( ) ;
} else {
}
if ( cmd [ " channel_name " ] . string ( ) . length ( ) < 1 ) return command_result { error : : channel_name_inuse , " Invalid channel name " } ;
{
if ( target_tree - > findChannel ( cmd [ " channel_name " ] . as < std : : string > ( ) , parent ? dynamic_pointer_cast < BasicChannel > ( parent - > entry ) : nullptr ) ) return command_result { error : : channel_name_inuse , " Name already in use " } ;
created_channel = target_tree - > createChannel ( parent ? parent - > entry - > channelId ( ) : ( ChannelId ) 0 , cmd [ 0 ] . has ( " channel_order " ) ? cmd [ " channel_order " ] . as < ChannelId > ( ) : ( ChannelId ) 0 , cmd [ " channel_name " ] . as < std : : string > ( ) ) ;
}
if ( ! created_channel ) return command_result { error : : channel_invalid_flags , " Could not create channel " } ;
auto created_linked_channel = target_tree - > findLinkedChannel ( created_channel - > channelId ( ) ) ;
sassert ( created_linked_channel ) ;
if ( cmd [ 0 ] . has ( " channel_flag_default " ) & & cmd [ " channel_flag_default " ] . as < bool > ( ) ) {
old_default_channel = target_tree - > getDefaultChannel ( ) ;
target_tree - > setDefaultChannel ( created_channel ) ;
}
created_channel - > properties ( ) [ property : : CHANNEL_CREATED_BY ] = this - > getClientDatabaseId ( ) ;
{
auto default_modify_power = this - > calculate_permission ( permission : : i_channel_modify_power , 0 , false , permission_cache ) ;
auto default_delete_power = this - > calculate_permission ( permission : : i_channel_delete_power , 0 , false , permission_cache ) ;
auto permission_manager = created_channel - > permissions ( ) ;
permission_manager - > set_permission (
permission : : i_channel_needed_modify_power ,
{ default_modify_power . has_value ? default_modify_power . value : 0 , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing
) ;
permission_manager - > set_permission (
permission : : i_channel_needed_delete_power ,
{ default_delete_power . has_value ? default_delete_power . value : 0 , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing
) ;
}
for ( auto & prop : cmd [ 0 ] . keys ( ) ) {
if ( prop = = " channel_flag_default " ) continue ;
if ( prop = = " channel_order " ) continue ;
if ( prop = = " channel_name " ) continue ;
if ( prop = = " cpid " ) continue ;
if ( prop = = " cid " ) continue ;
const auto & property = property : : info < property : : ChannelProperties > ( prop ) ;
if ( * property = = property : : CHANNEL_UNDEFINED ) {
logError ( this - > getServerId ( ) , " Client " + this - > getDisplayName ( ) + " tried to change a not existing channel property " + prop ) ;
continue ;
}
if ( ! property - > validate_input ( cmd [ prop ] . as < string > ( ) ) ) {
logError ( this - > getServerId ( ) , " Client " + this - > getDisplayName ( ) + " tried to change a property to an invalid value. (Value: ' " + cmd [ prop ] . as < string > ( ) + " ', Property: ' " + property - > name + " ') " ) ;
continue ;
}
created_channel - > properties ( ) [ property ] = cmd [ prop ] . as < std : : string > ( ) ;
}
if ( created_channel - > parent ( ) ) {
if ( created_channel - > parent ( ) - > channelType ( ) > created_channel - > channelType ( ) )
created_channel - > setChannelType ( created_channel - > parent ( ) - > channelType ( ) ) ;
}
if ( this - > server ) {
const auto self_lock = _this . lock ( ) ;
this - > server - > forEachClient ( [ & , created_channel ] ( const shared_ptr < ConnectedClient > & client ) {
unique_lock client_channel_lock ( client - > channel_lock ) ;
auto result = client - > channels - > add_channel ( created_linked_channel ) ;
if ( ! result ) return ;
client - > notifyChannelCreate ( created_channel , result - > previous_channel , self_lock ) ;
if ( client = = self_lock & & this - > getType ( ) = = ClientType : : CLIENT_QUERY ) {
Command notify ( " " ) ;
notify [ " cid " ] = created_channel - > channelId ( ) ;
this - > sendCommand ( notify ) ;
}
client - > notifyChannelDescriptionChanged ( created_channel ) ;
if ( client - > subscribeToAll )
client - > subscribeChannel ( { created_channel } , false , true ) ;
if ( old_default_channel ) {
//TODO: Reminder: client channel tree must be at least read locked here!
client - > notifyChannelEdited ( old_default_channel , { property : : CHANNEL_FLAG_DEFAULT } , self_lock , false ) ;
}
} ) ;
GroupId adminGroup = this - > server - > properties ( ) [ property : : VIRTUALSERVER_DEFAULT_CHANNEL_ADMIN_GROUP ] ;
auto channel_admin_group = this - > server - > groups - > findGroup ( adminGroup ) ;
if ( ! channel_admin_group ) {
logError ( this - > getServerId ( ) , " Missing server's default channel admin group! Using default channel group! " ) ;
channel_admin_group = this - > server - > groups - > defaultGroup ( GroupTarget : : GROUPTARGET_CHANNEL ) ;
}
this - > server - > groups - > setChannelGroup ( this - > getClientDatabaseId ( ) , channel_admin_group , created_channel ) ;
if ( created_channel - > channelType ( ) = = ChannelType : : temporary & & ( this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK | | this - > getType ( ) = = ClientType : : CLIENT_WEB ) )
this - > server - > client_move (
this - > ref ( ) ,
created_channel ,
nullptr ,
" channel created " ,
ViewReasonId : : VREASON_USER_ACTION ,
true ,
tree_channel_lock
) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelDelete ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
RESOLVE_CHANNEL_W ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
if ( channel - > deleted ) /* channel gets already removed */
return command_result { error : : ok } ;
ACTION_REQUIRES_CHANNEL_PERMISSION ( channel , permission : : i_channel_needed_delete_power , permission : : i_channel_delete_power , true ) ;
for ( const auto & ch : channel_tree - > channels ( channel ) ) {
if ( ch - > defaultChannel ( ) )
return command_result { error : : channel_can_not_delete_default } ;
}
if ( this - > server ) {
auto clients = this - > server - > getClientsByChannelRoot ( channel , false ) ;
if ( ! clients . empty ( ) )
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_delete_flag_force , 1 , channel - > channelId ( ) ) ;
this - > server - > delete_channel ( channel , this - > ref ( ) , " channel deleted " , channel_tree_write_lock ) ;
} else {
auto channel_ids = channel_tree - > deleteChannelRoot ( channel ) ;
this - > notifyChannelDeleted ( channel_ids , this - > ref ( ) ) ;
}
return command_result { error : : ok } ;
}
/*
* 1. check for permission and basic requirements
* 2. Lock the channel tree in write mode if required
* 3. Apply changed , test for advanced requirements like channel name etc
* 4. notify everyone
*/
command_result ConnectedClient : : handleCommandChannelEdit ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
if ( channel - > deleted ) {
/* channel gets already removed */
return command_result { error : : ok } ;
}
std : : deque < std : : shared_ptr < property : : PropertyDescription > > keys ;
bool require_write_lock = false ;
bool update_max_clients = false ;
bool update_max_family_clients = false ;
bool update_clients_in_channel = false ;
bool update_password = false ;
bool update_name = false ;
/* Step 1 */
bool target_channel_type_changed = false ;
ChannelType : : ChannelType target_channel_type = channel - > channelType ( ) ;
ACTION_REQUIRES_CHANNEL_PERMISSION ( channel , permission : : i_channel_needed_modify_power , permission : : i_channel_modify_power , true ) ;
for ( const auto & key : cmd [ 0 ] . keys ( ) ) {
if ( key = = " cid " )
continue ;
if ( key = = " return_code " )
continue ;
const auto & property = property : : info < property : : ChannelProperties > ( key ) ;
if ( * property = = property : : CHANNEL_UNDEFINED ) {
logError ( this - > getServerId ( ) , R " ({} Tried to edit a not existing channel property " { } " to " { } " ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
if ( ( property - > flags & property : : FLAG_USER_EDITABLE ) = = 0 ) {
logError ( this - > getServerId ( ) , " {} Tried to change a channel property which is not changeable. (Key: {}, Value: \" {} \" ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
if ( ! property - > validate_input ( cmd [ key ] . as < string > ( ) ) ) {
logError ( this - > getServerId ( ) , " {} Tried to change a channel property to an invalid value. (Key: {}, Value: \" {} \" ) " , CLIENT_STR_LOG_PREFIX , key , cmd [ key ] . string ( ) ) ;
continue ;
}
if ( channel - > properties ( ) [ * property ] . as < string > ( ) = = cmd [ key ] . as < string > ( ) )
continue ; /* we dont need to update stuff which is the same */
if ( key = = " channel_icon_id " ) {
ACTION_REQUIRES_CHANNEL_PERMISSION ( channel , permission : : i_channel_needed_permission_modify_power , permission : : i_channel_permission_modify_power , true ) ;
} else if ( key = = " channel_order " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_sortorder , 1 , channel_id ) ;
require_write_lock = true ;
} else if ( key = = " channel_flag_default " ) {
if ( ! cmd [ " channel_flag_default " ] . as < bool > ( ) )
return command_result { error : : channel_invalid_flags } ;
ACTION_REQUIRES_GLOBAL_PERMISSION ( permission : : b_channel_modify_make_default , 1 ) ;
require_write_lock = true ;
} else if ( key = = " channel_name " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_name , 1 , channel_id ) ;
if ( count_characters ( cmd [ " channel_name " ] ) < 1 )
return command_result { error : : channel_name_invalid } ;
if ( count_characters ( cmd [ " channel_name " ] ) > 40 )
return command_result { error : : channel_name_invalid } ;
require_write_lock = true ;
update_name = true ;
} else if ( key = = " channel_name_phonetic " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_name , 1 , channel_id ) ;
} else if ( key = = " channel_topic " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_topic , 1 , channel_id ) ;
} else if ( key = = " channel_description " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_description , 1 , channel_id ) ;
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_use_bbcode_any , channel_id ) ) ) {
auto bbcode_image = bbcode : : sloppy : : has_image ( cmd [ key ] ) ;
auto bbcode_url = bbcode : : sloppy : : has_url ( cmd [ key ] ) ;
debugMessage ( this - > getServerId ( ) , " Channel description contains bb codes: Image: {} URL: {} " , bbcode_image , bbcode_url ) ;
if ( bbcode_image & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_use_bbcode_image , channel_id ) ) )
return command_result { permission : : b_client_use_bbcode_image } ;
if ( bbcode_url & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_use_bbcode_url , channel_id ) ) )
return command_result { permission : : b_client_use_bbcode_url } ;
}
} else if ( key = = " channel_codec " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_codec , 1 , channel_id ) ;
} else if ( key = = " channel_codec_quality " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_codec_quality , 1 , channel_id ) ;
} else if ( key = = " channel_codec_is_unencrypted " ) {
if ( cmd [ " channel_codec_is_unencrypted " ] . as < bool > ( ) )
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_make_codec_encrypted , 1 , channel_id ) ;
} else if ( key = = " channel_needed_talk_power " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_needed_talk_power , 1 , channel_id ) ;
update_clients_in_channel = true ;
} else if ( key = = " channel_maxclients " | | key = = " channel_flag_maxclients_unlimited " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_maxclients , 1 , channel_id ) ;
require_write_lock = true ;
update_max_clients = true ;
} else if ( key = = " channel_maxfamilyclients " | | key = = " channel_flag_maxfamilyclients_unlimited " | | key = = " channel_flag_maxfamilyclients_inherited " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_maxfamilyclients , 1 , channel_id ) ;
require_write_lock = true ;
update_max_family_clients = true ;
} else if ( key = = " channel_flag_permanent " | | key = = " channel_flag_semi_permanent " ) {
if ( cmd [ 0 ] . has ( " channel_flag_permanent " ) & & cmd [ " channel_flag_permanent " ] . as < bool > ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_make_permanent , 1 , channel_id ) ;
target_channel_type = ChannelType : : permanent ;
} else if ( cmd [ 0 ] . has ( " channel_flag_semi_permanent " ) & & cmd [ " channel_flag_semi_permanent " ] . as < bool > ( ) ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_make_semi_permanent , 1 , channel_id ) ;
target_channel_type = ChannelType : : semipermanent ;
} else {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_make_temporary , 1 , channel_id ) ;
target_channel_type = ChannelType : : temporary ;
}
target_channel_type_changed = true ;
require_write_lock = true ;
} else if ( key = = " channel_delete_delay " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_temp_delete_delay , cmd [ " channel_delete_delay " ] . as < permission : : PermissionValue > ( ) , channel_id ) ;
} else if ( key = = " channel_password " | | key = = " channel_flag_password " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_password , 1 , channel_id ) ;
update_password = true ;
} else if ( key = = " channel_conversation_history_length " ) {
auto value = cmd [ " channel_conversation_history_length " ] . as < int64_t > ( ) ;
if ( value = = 0 ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_create_modify_conversation_history_unlimited , 1 , channel_id ) ;
} else {
ACTION_REQUIRES_PERMISSION ( permission : : i_channel_create_modify_conversation_history_length , 1 , channel_id ) ;
}
} else if ( key = = " channel_flag_conversation_private " ) {
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_create_modify_conversation_private , 1 , channel_id ) ;
} else {
logCritical (
this - > getServerId ( ) ,
" The client " + this - > getDisplayName ( ) + " tried to change a editable channel property but we haven't found a permission. Please report this error. (Channel property: {}) " ,
key
) ;
continue ;
}
keys . push_back ( property ) ;
}
unique_lock server_channel_w_lock ( this - > server ? this - > server - > channel_tree_lock : serverInstance - > getChannelTreeLock ( ) , defer_lock ) ;
if ( require_write_lock ) {
channel_tree_read_lock . unlock ( ) ;
server_channel_w_lock . lock ( ) ;
/* not that while we're waiting to edit the server the channel got deleted... fuck my english */
if ( channel - > deleted )
return command_result { error : : ok } ;
}
/* test the password parameters */
if ( update_password ) {
if ( ! cmd [ 0 ] . has ( " channel_password " ) ) {
if ( cmd [ 0 ] . has ( " channel_flag_password " ) & & cmd [ " channel_flag_password " ] . as < bool > ( ) )
return command_result { error : : parameter_missing } ;
else
cmd [ " channel_password " ] = " " ; /* no password set */
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_PASSWORD ) ) ;
}
if ( ! cmd [ 0 ] . has ( " channel_flag_password " ) ) {
cmd [ " channel_flag_password " ] = ! cmd [ " channel_password " ] . string ( ) . empty ( ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_PASSWORD ) ) ;
}
if ( cmd [ " channel_flag_password " ] . as < bool > ( ) ) {
if ( cmd [ " channel_password " ] . string ( ) . empty ( ) )
return command_result { error : : channel_invalid_flags } ; /* we cant enable a password without a given password */
/* we've to "encode" the password */
if ( this - > getType ( ) = = ClientType : : CLIENT_QUERY )
cmd [ " channel_password " ] = base64 : : encode ( digest : : sha1 ( cmd [ " channel_password " ] . string ( ) ) ) ;
} else {
cmd [ " channel_password " ] = " " ; /* flag password if false so we set the password to empty */
}
}
/* test the default channel update */
if ( cmd [ 0 ] . has ( " channel_flag_default " ) | | channel - > defaultChannel ( ) ) {
if ( target_channel_type ! = ChannelType : : permanent )
return command_result { error : : channel_default_require_permanent } ; /* default channel is not allowed to be non permanent */
if ( ( cmd [ 0 ] . has ( " channel_flag_password " ) & & cmd [ " channel_flag_password " ] . as < bool > ( ) ) | | channel - > properties ( ) [ property : : CHANNEL_FLAG_PASSWORD ] ) {
cmd [ " channel_flag_password " ] = false ;
cmd [ " channel_password " ] = " " ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_PASSWORD ) ) ;
}
if ( cmd [ 0 ] . has ( " channel_flag_default " ) ) {
cmd [ " channel_maxclients " ] = - 1 ;
cmd [ " channel_flag_maxclients_unlimited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXCLIENTS ) ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ) ) ;
update_max_clients = true ;
cmd [ " channel_maxfamilyclients " ] = - 1 ;
cmd [ " channel_flag_maxfamilyclients_inherited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXFAMILYCLIENTS ) ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ) ) ;
update_max_family_clients = true ;
}
}
/* "fix" max client for temporary channels */
if ( target_channel_type_changed ) {
if ( target_channel_type = = ChannelType : : temporary ) {
if ( channel - > properties ( ) [ property : : CHANNEL_MAXCLIENTS ] . as < int > ( ) ! = - 1 ) {
cmd [ " channel_maxclients " ] = - 1 ;
cmd [ " channel_flag_maxclients_unlimited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXCLIENTS ) ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ) ) ;
update_max_clients = true ;
}
if ( channel - > properties ( ) [ property : : CHANNEL_MAXFAMILYCLIENTS ] . as < int > ( ) ! = - 1 ) {
cmd [ " channel_maxfamilyclients " ] = - 1 ;
cmd [ " channel_flag_maxfamilyclients_inherited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXFAMILYCLIENTS ) ) ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ) ) ;
update_max_family_clients = true ;
}
}
if ( target_channel_type ! = ChannelType : : permanent ) {
/* test if any child is the default channel */
for ( const auto & child : channel_tree - > channels ( channel ) )
if ( child - > defaultChannel ( ) )
return command_result { error : : channel_default_require_permanent } ; /* default channel is not allowed to be non permanent */
}
auto parent = channel - > parent ( ) ;
if ( parent & & parent - > channelType ( ) > target_channel_type )
return command_result { error : : channel_parent_not_permanent } ;
}
/* test the max clients parameters */
if ( update_max_clients ) {
if ( ! cmd [ 0 ] . has ( " channel_maxclients " ) ) {
if ( cmd [ 0 ] . has ( " channel_flag_maxclients_unlimited " ) & & cmd [ " channel_flag_maxclients_unlimited " ] . as < bool > ( ) )
cmd [ " channel_maxclients " ] = - 1 ;
else
return command_result { error : : parameter_missing , " channel_maxclients " } ; /* max clients must be specified */
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXCLIENTS ) ) ;
}
if ( ! cmd [ 0 ] . has ( " channel_flag_maxclients_unlimited " ) ) {
cmd [ " channel_flag_maxclients_unlimited " ] = cmd [ " channel_maxclients " ] . as < int > ( ) < 0 ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXCLIENTS_UNLIMITED ) ) ;
}
if ( cmd [ " channel_flag_maxclients_unlimited " ] . as < bool > ( ) & & cmd [ " channel_maxclients " ] . as < int > ( ) ! = - 1 )
return command_result { error : : channel_invalid_flags } ; /* channel cant have a max client settings AND be unlimited as well */
if ( ! cmd [ " channel_flag_maxclients_unlimited " ] . as < bool > ( ) & & target_channel_type = = ChannelType : : temporary )
return command_result { error : : channel_invalid_flags } ; /* temporary channels cant have a limited user count */
}
/* test the max family clients parameters */
if ( update_max_family_clients ) {
if ( ! cmd [ 0 ] . has ( " channel_maxfamilyclients " ) ) {
if ( cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_unlimited " ) ) {
if ( cmd [ " channel_flag_maxfamilyclients_unlimited " ] . as < bool > ( ) )
cmd [ " channel_flag_maxfamilyclients_inherited " ] = false ;
else
cmd [ " channel_flag_maxfamilyclients_inherited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_INHERITED ) ) ;
} else if ( cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_inherited " ) ) {
if ( cmd [ " channel_flag_maxfamilyclients_inherited " ] . as < bool > ( ) )
cmd [ " channel_flag_maxfamilyclients_unlimited " ] = false ;
else
cmd [ " channel_flag_maxfamilyclients_unlimited " ] = true ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_FLAG_MAXFAMILYCLIENTS_UNLIMITED ) ) ;
} else /* not really possible */
return command_result { error : : parameter_missing , " channel_maxfamilyclients " } ; /* family max clients must be */
cmd [ " channel_maxfamilyclients " ] = - 1 ;
keys . push_back ( property : : info < property : : ChannelProperties > ( property : : CHANNEL_MAXFAMILYCLIENTS ) ) ;
}
//keep this order because this command: "channeledit cid=<x> channel_maxfamilyclients=-1" should set max family clients mode to inherited
if ( ! cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_inherited " ) ) {
auto flag_unlimited = cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_unlimited " ) & & cmd [ " channel_flag_maxfamilyclients_unlimited " ] . as < bool > ( ) ;
if ( flag_unlimited )
cmd [ " channel_flag_maxfamilyclients_inherited " ] = false ;
else
cmd [ " channel_flag_maxfamilyclients_inherited " ] = cmd [ " channel_maxfamilyclients " ] . as < int > ( ) < 0 ;
}
if ( ! cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_unlimited " ) ) {
auto flag_inherited = cmd [ 0 ] . has ( " channel_flag_maxfamilyclients_inherited " ) & & cmd [ " channel_flag_maxfamilyclients_inherited " ] . as < bool > ( ) ;
if ( flag_inherited )
cmd [ " channel_flag_maxfamilyclients_unlimited " ] = false ;
else
cmd [ " channel_flag_maxfamilyclients_unlimited " ] = cmd [ " channel_maxfamilyclients " ] . as < int > ( ) < 0 ;
}
if ( cmd [ " channel_flag_maxfamilyclients_inherited " ] . as < bool > ( ) & & cmd [ " channel_flag_maxfamilyclients_unlimited " ] . as < bool > ( ) )
return command_result { error : : channel_invalid_flags } ; /* both at the same time are not possible */
if ( cmd [ " channel_flag_maxfamilyclients_inherited " ] . as < bool > ( ) & & cmd [ " channel_maxfamilyclients " ] . as < int > ( ) ! = - 1 )
return command_result { error : : channel_invalid_flags } ; /* flag inherited required max users to be -1 */
if ( cmd [ " channel_flag_maxfamilyclients_unlimited " ] . as < bool > ( ) & & cmd [ " channel_maxfamilyclients " ] . as < int > ( ) ! = - 1 )
return command_result { error : : channel_invalid_flags } ; /* flag unlimited required max users to be -1 */
if ( cmd [ " channel_maxfamilyclients " ] . as < int > ( ) ! = - 1 & & target_channel_type = = ChannelType : : temporary )
return command_result { error : : channel_invalid_flags } ; /* temporary channels cant have a limited user count */
}
/* test the channel name */
if ( update_name ) {
auto named_channel = channel_tree - > findChannel ( cmd [ " channel_name " ] . string ( ) , channel - > parent ( ) ) ;
if ( named_channel )
return command_result { error : : channel_name_inuse } ;
}
auto self_ref = this - > ref ( ) ;
shared_ptr < BasicChannel > old_default_channel ;
deque < shared_ptr < BasicChannel > > child_channel_updated ;
for ( const std : : shared_ptr < property : : PropertyDescription > & key : keys ) {
if ( * key = = property : : CHANNEL_ORDER ) {
/* TODO: May move that up because if it fails may some other props have already be applied */
if ( ! channel_tree - > change_order ( channel , cmd [ key - > name ] ) )
return command_result { error : : channel_invalid_order , " Can't change order id " } ;
if ( this - > server ) {
auto parent = channel - > hasParent ( ) ? channel_tree - > findLinkedChannel ( channel - > parent ( ) - > channelId ( ) ) : nullptr ;
auto previous = channel_tree - > findLinkedChannel ( channel - > previousChannelId ( ) ) ;
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & cl ) {
unique_lock client_channel_lock ( cl - > channel_lock ) ;
auto actions = cl - > channels - > change_order ( l_channel , parent , previous ) ;
std : : deque < ChannelId > deletions ;
for ( const auto & action : actions ) {
switch ( action . first ) {
case ClientChannelView : : NOTHING :
continue ;
case ClientChannelView : : ENTER_VIEW :
cl - > notifyChannelShow ( action . second - > channel ( ) , action . second - > previous_channel ) ;
break ;
case ClientChannelView : : DELETE_VIEW :
deletions . push_back ( action . second - > channelId ( ) ) ;
break ;
case ClientChannelView : : MOVE :
cl - > notifyChannelMoved ( action . second - > channel ( ) , action . second - > previous_channel , this - > ref ( ) ) ;
break ;
case ClientChannelView : : REORDER :
cl - > notifyChannelEdited ( action . second - > channel ( ) , { property : : CHANNEL_ORDER } , self_ref , false ) ;
break ;
}
}
if ( ! deletions . empty ( ) ) {
cl - > notifyChannelHide ( deletions , false ) ;
return ; //Channel got deleted so we dont have to send the updates
}
} ) ;
}
} else if ( * key = = property : : CHANNEL_FLAG_DEFAULT ) {
old_default_channel = channel_tree - > getDefaultChannel ( ) ;
if ( old_default_channel = = channel ) {
old_default_channel = nullptr ;
continue ;
}
if ( ! cmd [ key - > name ] . as < bool > ( ) ) {
old_default_channel = nullptr ;
continue ;
}
channel_tree - > setDefaultChannel ( channel ) ;
deque < shared_ptr < BasicChannel > > updated_channels ;
shared_ptr < BasicChannel > current_channel = channel ;
do {
if ( current_channel - > channelType ( ) = = ChannelType : : permanent )
break ;
current_channel - > setChannelType ( ChannelType : : permanent ) ;
if ( current_channel ! = channel )
updated_channels . push_back ( channel ) ;
} while ( ( current_channel = current_channel - > parent ( ) ) ) ;
if ( this - > server & & ! updated_channels . empty ( ) ) {
std : : reverse ( updated_channels . begin ( ) , updated_channels . end ( ) ) ;
auto this_ref = this - > ref ( ) ;
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & client ) {
unique_lock client_channel_lock ( client - > channel_lock ) ;
for ( const auto & channel : updated_channels ) {
client - > notifyChannelEdited ( channel , { property : : CHANNEL_FLAG_PERMANENT , property : : CHANNEL_FLAG_SEMI_PERMANENT } , this_ref , false ) ;
}
} ) ;
}
} else if ( * key = = property : : CHANNEL_FLAG_PERMANENT | | * key = = property : : CHANNEL_FLAG_SEMI_PERMANENT ) {
if ( target_channel_type_changed ) { /* must be true else the key would not appere here */
target_channel_type_changed = false ; /* we only need to check all subchannels once! */
{ /* check channel children */
deque < shared_ptr < BasicChannel > > channel_to_test = { channel } ;
while ( ! channel_to_test . empty ( ) ) {
auto current_channel = channel_to_test . front ( ) ;
channel_to_test . pop_front ( ) ;
for ( const auto & child : channel_tree - > channels ( current_channel , 1 ) ) {
if ( child = = current_channel )
continue ;
if ( child - > channelType ( ) < target_channel_type ) {
child - > setChannelType ( target_channel_type ) ;
channel_to_test . push_back ( child ) ;
child_channel_updated . push_back ( child ) ;
}
}
}
}
}
} else if ( * key = = property : : CHANNEL_CONVERSATION_HISTORY_LENGTH ) {
//channel_conversation_history_length
auto conversation_manager = this - > server - > conversation_manager ( ) ;
if ( conversation_manager ) {
auto conversation = conversation_manager - > get ( channel - > channelId ( ) ) ;
if ( conversation )
conversation - > set_history_length ( cmd [ key - > name ] ) ;
}
2020-02-28 11:24:07 +01:00
} else if ( * key = = property : : CHANNEL_NEEDED_TALK_POWER ) {
channel - > permissions ( ) - > set_permission ( permission : : i_client_needed_talk_power , { cmd [ key - > name ] . as < int > ( ) , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing ) ;
2020-01-26 14:21:34 +01:00
}
channel - > properties ( ) [ key ] = cmd [ key - > name ] . string ( ) ;
}
if ( this - > server ) {
vector < property : : ChannelProperties > key_vector ;
key_vector . reserve ( keys . size ( ) ) ;
for ( const auto & key : keys )
key_vector . push_back ( ( property : : ChannelProperties ) key - > property_index ) ;
auto self_rev = this - > ref ( ) ;
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & client ) {
unique_lock client_channel_lock ( client - > channel_lock ) ;
for ( const auto & channel : child_channel_updated )
client - > notifyChannelEdited ( channel , { property : : CHANNEL_FLAG_PERMANENT , property : : CHANNEL_FLAG_SEMI_PERMANENT } , self_rev , false ) ;
client - > notifyChannelEdited ( channel , key_vector , self_rev , false ) ;
if ( old_default_channel ) /* clients need to have one or more defualt channels... */
client - > notifyChannelEdited ( old_default_channel , { property : : CHANNEL_FLAG_DEFAULT } , self_rev , false ) ;
} ) ;
}
if ( server_channel_w_lock . owns_lock ( ) )
server_channel_w_lock . unlock ( ) ;
if ( ! channel_tree_read_lock . owns_lock ( ) )
channel_tree_read_lock . lock ( ) ;
if ( update_clients_in_channel & & this - > server ) {
for ( const auto & client : this - > server - > getClientsByChannel ( channel ) )
client - > updateChannelClientProperties ( true , true ) ; //TODO: May only update the talk power and not all?
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelMove ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
RESOLVE_CHANNEL_W ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
if ( channel - > deleted )
return command_result { error : : channel_is_deleted } ;
if ( ! cmd [ 0 ] . has ( " order " ) )
cmd [ " order " ] = 0 ;
auto l_parent = channel_tree - > findLinkedChannel ( cmd [ " cpid " ] ) ;
shared_ptr < TreeView : : LinkedTreeEntry > l_order ;
if ( cmd [ 0 ] . has ( " order " ) ) {
l_order = channel_tree - > findLinkedChannel ( cmd [ " order " ] ) ;
if ( ! l_order & & cmd [ " order " ] . as < ChannelId > ( ) ! = 0 ) return command_result { error : : channel_invalid_id } ;
} else {
l_order = l_parent ? l_parent - > child_head : ( this - > server ? this - > server - > getChannelTree ( ) : serverInstance - > getChannelTree ( ) . get ( ) ) - > tree_head ( ) ;
while ( l_order & & l_order - > next )
l_order = l_order - > next ;
}
auto parent = l_parent ? dynamic_pointer_cast < ServerChannel > ( l_parent - > entry ) : nullptr ;
auto order = l_order ? dynamic_pointer_cast < ServerChannel > ( l_order - > entry ) : nullptr ;
if ( ( parent & & parent - > deleted ) | | ( order & & order - > deleted ) )
return command_result { error : : channel_is_deleted , " parent channel order previous channel has been deleted " } ;
if ( channel - > parent ( ) = = parent & & channel - > channelOrder ( ) = = ( order ? order - > channelId ( ) : 0 ) )
return command_result { error : : ok } ;
if ( channel - > parent ( ) ! = parent )
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_parent , 1 , channel_id ) ;
if ( ( order ? order - > channelId ( ) : 0 ) ! = channel - > channelOrder ( ) )
ACTION_REQUIRES_PERMISSION ( permission : : b_channel_modify_sortorder , 1 , channel_id ) ;
{
auto min_channel_deep = this - > calculate_permission ( permission : : i_channel_min_depth , 0 , false ) ;
auto max_channel_deep = this - > calculate_permission ( permission : : i_channel_max_depth , 0 , false ) ;
if ( min_channel_deep . has_value | | max_channel_deep . has_value ) {
auto channel_deep = 0 ;
auto local_parent = l_parent ;
while ( local_parent ) {
channel_deep + + ;
local_parent = local_parent - > parent . lock ( ) ;
}
if ( min_channel_deep . has_value & & ( channel_deep < min_channel_deep . value & & ! min_channel_deep . has_infinite_power ( ) ) ) return command_result { permission : : i_channel_min_depth } ;
if ( max_channel_deep . has_value & & ! permission : : v2 : : permission_granted ( channel_deep , max_channel_deep ) ) return command_result { permission : : i_channel_max_depth } ;
}
}
{
auto name = channel_tree - > findChannel ( channel - > name ( ) , parent ) ;
if ( name & & name ! = channel ) return command_result { error : : channel_name_inuse } ;
}
debugMessage ( this - > getServerId ( ) , " Moving channel {} from old [{} | {}] to [{} | {}] " , channel - > name ( ) , channel - > channelOrder ( ) , channel - > parent ( ) ? channel - > parent ( ) - > channelId ( ) : 0 , order ? order - > channelId ( ) : 0 , parent ? parent - > channelId ( ) : 0 ) ;
if ( ! channel_tree - > move_channel ( channel , parent , order ) ) return command_result { error : : channel_invalid_order , " Cant change order id " } ;
deque < shared_ptr < BasicChannel > > channel_type_updates ;
{
auto flag_default = channel - > defaultChannel ( ) ;
auto current_channel = channel ;
do {
if ( flag_default ) {
if ( current_channel - > channelType ( ) ! = ChannelType : : permanent ) {
current_channel - > setChannelType ( ChannelType : : permanent ) ;
channel_type_updates . push_front ( current_channel ) ;
}
} else if ( current_channel - > hasParent ( ) ) {
if ( current_channel - > channelType ( ) < current_channel - > parent ( ) - > channelType ( ) ) {
current_channel - > setChannelType ( current_channel - > parent ( ) - > channelType ( ) ) ;
channel_type_updates . push_front ( current_channel ) ;
}
}
} while ( ( current_channel = dynamic_pointer_cast < ServerChannel > ( current_channel - > parent ( ) ) ) ) ;
}
if ( this - > server ) {
auto self_rev = this - > ref ( ) ;
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & client ) {
unique_lock channel_lock ( client - > channel_lock ) ;
for ( const auto & type_update : channel_type_updates )
client - > notifyChannelEdited ( type_update , { property : : CHANNEL_FLAG_PERMANENT , property : : CHANNEL_FLAG_SEMI_PERMANENT } , self_rev , false ) ;
auto actions = client - > channels - > change_order ( l_channel , l_parent , l_order ) ;
std : : deque < ChannelId > deletions ;
for ( const auto & action : actions ) {
switch ( action . first ) {
case ClientChannelView : : NOTHING :
continue ;
case ClientChannelView : : ENTER_VIEW :
client - > notifyChannelShow ( action . second - > channel ( ) , action . second - > previous_channel ) ;
break ;
case ClientChannelView : : DELETE_VIEW :
deletions . push_back ( action . second - > channelId ( ) ) ;
break ;
case ClientChannelView : : MOVE :
client - > notifyChannelMoved ( action . second - > channel ( ) , action . second - > previous_channel , _this . lock ( ) ) ;
break ;
case ClientChannelView : : REORDER :
client - > notifyChannelEdited ( action . second - > channel ( ) , { property : : CHANNEL_ORDER } , self_rev , false ) ;
break ;
}
}
if ( ! deletions . empty ( ) )
client - > notifyChannelHide ( deletions , false ) ;
} ) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelPermList ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < BasicChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
ACTION_REQUIRES_PERMISSION ( permission : : b_virtualserver_channel_permission_list , 1 , channel - > channelId ( ) ) ;
if ( this - > getType ( ) = = ClientType : : CLIENT_TEAMSPEAK & & this - > command_times . last_notify + this - > command_times . notify_timeout < system_clock : : now ( ) ) {
this - > sendTSPermEditorWarning ( ) ;
}
auto sids = cmd . hasParm ( " permsid " ) ;
Command result ( this - > notify_response_command ( " notifychannelpermlist " ) ) ;
int index = 0 ;
result [ " cid " ] = channel - > channelId ( ) ;
auto permission_mapper = serverInstance - > getPermissionMapper ( ) ;
auto type = this - > getType ( ) ;
auto permission_manager = channel - > permissions ( ) ;
for ( const auto & permission_data : permission_manager - > permissions ( ) ) {
auto & permission = std : : get < 1 > ( permission_data ) ;
if ( permission . flags . value_set ) {
if ( sids ) {
result [ index ] [ " permsid " ] = permission_mapper - > permission_name ( type , std : : get < 0 > ( permission_data ) ) ;
} else {
result [ index ] [ " permid " ] = std : : get < 0 > ( permission_data ) ;
}
result [ index ] [ " permvalue " ] = permission . values . value ;
result [ index ] [ " permnegated " ] = permission . flags . negate ;
result [ index ] [ " permskip " ] = permission . flags . skip ;
index + + ;
}
if ( permission . flags . grant_set ) {
if ( sids ) {
result [ index ] [ " permsid " ] = permission_mapper - > permission_name_grant ( type , std : : get < 0 > ( permission_data ) ) ;
} else {
result [ index ] [ " permid " ] = ( uint16_t ) ( std : : get < 0 > ( permission_data ) | PERM_ID_GRANT ) ;
}
result [ index ] [ " permvalue " ] = permission . values . grant ;
result [ index ] [ " permnegated " ] = 0 ;
result [ index ] [ " permskip " ] = 0 ;
index + + ;
}
}
if ( index = = 0 )
return command_result { error : : database_empty_result } ;
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
//
//channel_icon_id=18446744073297259750
//channel_name
//channel_topic
//Desctiption has no extra parm
command_result ConnectedClient : : handleCommandChannelAddPerm ( Command & cmd ) {
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < BasicChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
ACTION_REQUIRES_CHANNEL_PERMISSION ( channel , permission : : i_channel_needed_permission_modify_power , permission : : i_channel_permission_modify_power , true ) ;
auto max_value = this - > calculate_permission ( permission : : i_permission_modify_power , channel_id , true ) ;
if ( ! max_value . has_value ) return command_result { permission : : i_permission_modify_power } ;
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , channel_id ) ) ;
auto updateClients = false , update_view = false , update_channel_properties = false ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto permission_manager = channel - > permissions ( ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & ! permission : : v2 : : permission_granted ( val , max_value ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
2020-02-03 19:41:18 +01:00
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permType , channel_id , true ) ) ) {
2020-01-26 14:21:34 +01:00
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
if ( grant ) {
permission_manager - > set_permission ( permType , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : set_value ) ;
} else {
permission_manager - > set_permission (
permType ,
{ cmd [ index ] [ " permvalue " ] , 0 } ,
permission : : v2 : : PermissionUpdateType : : set_value ,
permission : : v2 : : PermissionUpdateType : : do_nothing ,
cmd [ index ] [ " permskip " ] . as < bool > ( ) ? 1 : 0 ,
cmd [ index ] [ " permnegated " ] . as < bool > ( ) ? 1 : 0
) ;
updateClients | = permission_is_client_property ( permType ) ;
update_view | = permType = = permission : : i_channel_needed_view_power ;
update_channel_properties | = channel - > permission_require_property_update ( permType ) ;
if ( permType = = permission : : i_icon_id ) {
if ( this - > server ) {
auto self_ref = this - > ref ( ) ;
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
shared_lock client_channel_lock ( cl - > channel_lock ) ;
cl - > notifyChannelEdited ( channel , { property : : CHANNEL_ICON_ID } , self_ref , false ) ;
} ) ;
}
continue ;
}
}
}
/* broadcast the updated channel properties */
if ( update_channel_properties ) {
auto updates = channel - > update_properties_from_permissions ( ) ;
if ( ! updates . empty ( ) & & this - > server ) {
auto self_ref = this - > ref ( ) ;
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
shared_lock client_channel_lock ( cl - > channel_lock ) ;
cl - > notifyChannelEdited ( channel , updates , self_ref , false ) ;
} ) ;
}
}
if ( updateClients & & this - > server )
for ( const auto & client : this - > server - > getClientsByChannel ( channel ) ) {
/* let them lock the server channel tree as well (read lock so does not matter) */
client - > updateChannelClientProperties ( true , true ) ;
client - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
if ( update_view & & this - > server ) {
auto l_source = this - > server - > channelTree - > findLinkedChannel ( channel - > channelId ( ) ) ;
this - > server - > forEachClient ( [ & ] ( const shared_ptr < ConnectedClient > & cl ) {
/* server tree read lock still active */
auto l_target = ! cl - > currentChannel ? nullptr : cl - > server - > channelTree - > findLinkedChannel ( cl - > currentChannel - > channelId ( ) ) ;
sassert ( l_source ) ;
if ( cl - > currentChannel ) sassert ( l_target ) ;
{
unique_lock client_channel_lock ( cl - > channel_lock ) ;
deque < ChannelId > deleted ;
for ( const auto & update_entry : cl - > channels - > update_channel ( l_source , l_target ) ) {
if ( update_entry . first )
cl - > notifyChannelShow ( update_entry . second - > channel ( ) , update_entry . second - > previous_channel ) ;
else deleted . push_back ( update_entry . second - > channelId ( ) ) ;
}
if ( ! deleted . empty ( ) )
cl - > notifyChannelHide ( deleted , false ) ;
}
} ) ;
}
return command_result { error : : ok } ; ;
}
command_result ConnectedClient : : handleCommandChannelDelPerm ( Command & cmd ) {
CMD_RESET_IDLE ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true )
auto channel = dynamic_pointer_cast < BasicChannel > ( l_channel - > entry ) ;
assert ( channel ) ;
ACTION_REQUIRES_CHANNEL_PERMISSION ( channel , permission : : i_channel_needed_permission_modify_power , permission : : i_channel_permission_modify_power , true ) ;
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , channel_id ) ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto updateClients = false , update_view = false , update_channel_properties = false ;
auto permission_manager = channel - > permissions ( ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 0 , this - > calculate_permission ( permType , channel_id , true ) ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
if ( grant ) {
permission_manager - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : PermissionUpdateType : : do_nothing , permission : : v2 : : PermissionUpdateType : : delete_value ) ;
} else {
permission_manager - > set_permission ( permType , permission : : v2 : : empty_permission_values , permission : : v2 : : PermissionUpdateType : : delete_value , permission : : v2 : : PermissionUpdateType : : do_nothing ) ;
updateClients | = permission_is_client_property ( permType ) ;
update_view | = permType = = permission : : i_channel_needed_view_power ;
update_channel_properties | = channel - > permission_require_property_update ( permType ) ;
}
}
/* broadcast the updated channel properties */
if ( update_channel_properties ) {
auto updates = channel - > update_properties_from_permissions ( ) ;
if ( ! updates . empty ( ) & & this - > server ) {
auto self_ref = this - > ref ( ) ;
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
shared_lock client_channel_lock ( cl - > channel_lock ) ;
cl - > notifyChannelEdited ( channel , updates , self_ref , false ) ;
} ) ;
}
}
if ( updateClients & & this - > server )
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
if ( cl - > currentChannel = = channel ) {
cl - > updateChannelClientProperties ( true , true ) ;
cl - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
} ) ;
if ( update_view & & this - > server ) {
this - > server - > forEachClient ( [ & ] ( std : : shared_ptr < ConnectedClient > cl ) {
/* server tree read lock still active */
auto l_source = cl - > server - > channelTree - > findLinkedChannel ( channel - > channelId ( ) ) ;
auto l_target = ! cl - > currentChannel ? nullptr : cl - > server - > channelTree - > findLinkedChannel ( cl - > currentChannel - > channelId ( ) ) ;
sassert ( l_source ) ;
if ( cl - > currentChannel ) sassert ( l_target ) ;
{
unique_lock client_channel_lock ( cl - > channel_lock ) ;
deque < ChannelId > deleted ;
for ( const auto & update_entry : cl - > channels - > update_channel ( l_source , l_target ) ) {
if ( update_entry . first )
cl - > notifyChannelShow ( update_entry . second - > channel ( ) , update_entry . second - > previous_channel ) ;
else deleted . push_back ( update_entry . second - > channelId ( ) ) ;
}
if ( ! deleted . empty ( ) )
cl - > notifyChannelHide ( deleted , false ) ;
}
} ) ;
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelClientPermList ( Command & cmd ) {
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
if ( ! channel ) return command_result { error : : vs_critical } ;
ACTION_REQUIRES_PERMISSION ( permission : : b_virtualserver_channelclient_permission_list , 1 , channel_id ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cmd [ " cldbid " ] ) ) return command_result { error : : client_invalid_id } ;
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > server , cmd [ " cldbid " ] . as < ClientDbId > ( ) ) ;
Command res ( this - > getExternalType ( ) = = CLIENT_TEAMSPEAK ? " notifychannelclientpermlist " : " " ) ;
auto permissions = mgr - > channel_permissions ( channel - > channelId ( ) ) ;
if ( permissions . empty ( ) )
return command_result { error : : database_empty_result } ;
int index = 0 ;
res [ index ] [ " cid " ] = channel - > channelId ( ) ;
res [ index ] [ " cldbid " ] = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
auto sids = cmd . hasParm ( " permsid " ) ;
auto permission_mapper = serverInstance - > getPermissionMapper ( ) ;
auto type = this - > getType ( ) ;
for ( const auto & permission_data : permissions ) {
auto & permission = std : : get < 1 > ( permission_data ) ;
if ( permission . flags . value_set ) {
if ( sids )
res [ index ] [ " permsid " ] = permission_mapper - > permission_name ( type , get < 0 > ( permission_data ) ) ;
else
res [ index ] [ " permid " ] = get < 0 > ( permission_data ) ;
res [ index ] [ " permvalue " ] = permission . values . value ;
res [ index ] [ " permnegated " ] = permission . flags . negate ;
res [ index ] [ " permskip " ] = permission . flags . skip ;
index + + ;
}
if ( permission . flags . grant_set ) {
if ( sids )
res [ index ] [ " permsid " ] = permission_mapper - > permission_name_grant ( type , get < 0 > ( permission_data ) ) ;
else
res [ index ] [ " permid " ] = ( get < 0 > ( permission_data ) | PERM_ID_GRANT ) ;
res [ index ] [ " permvalue " ] = permission . values . grant ;
res [ index ] [ " permnegated " ] = 0 ;
res [ index ] [ " permskip " ] = 0 ;
index + + ;
}
}
this - > sendCommand ( res ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelClientDelPerm ( Command & cmd ) {
CMD_REF_SERVER ( server_ref ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto cldbid = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cldbid ) )
return command_result { error : : parameter_invalid , " Invalid manager db id " } ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
if ( ! channel ) return command_result { error : : vs_critical } ;
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > server , cldbid ) ;
{
auto required_permissions = this - > server - > calculate_permission ( permission : : i_client_needed_permission_modify_power , cmd [ " cldbid " ] , ClientType : : CLIENT_TEAMSPEAK , channel_id ) ;
ACTION_REQUIRES_PERMISSION ( permission : : i_client_permission_modify_power , required_permissions , channel_id ) ;
}
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , channel_id ) ) ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) , update_view = false ;
auto cll = this - > server - > findClientsByCldbId ( cldbid ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 0 , this - > calculate_permission ( permType , channel_id , true ) ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
if ( grant ) {
mgr - > set_channel_permission ( permType , channel - > channelId ( ) , permission : : v2 : : empty_permission_values , permission : : v2 : : do_nothing , permission : : v2 : : delete_value ) ;
} else {
mgr - > set_channel_permission ( permType , channel - > channelId ( ) , permission : : v2 : : empty_permission_values , permission : : v2 : : delete_value , permission : : v2 : : do_nothing ) ;
update_view = permType = = permission : : b_channel_ignore_view_power | | permType = = permission : : i_channel_view_power ;
}
}
serverInstance - > databaseHelper ( ) - > saveClientPermissions ( this - > server , cldbid , mgr ) ;
if ( ! cll . empty ( ) ) {
for ( const auto & elm : cll ) {
if ( elm - > update_cached_permissions ( ) ) /* update cached calculated permissions */
elm - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
if ( elm - > currentChannel = = channel ) {
elm - > updateChannelClientProperties ( true , true ) ;
} else if ( update_view ) {
unique_lock client_channel_lock ( this - > channel_lock ) ;
auto elm_channel = elm - > currentChannel ;
if ( elm_channel ) {
deque < ChannelId > deleted ;
for ( const auto & update_entry : elm - > channels - > update_channel_path ( l_channel , this - > server - > channelTree - > findLinkedChannel ( elm - > currentChannel - > channelId ( ) ) ) ) {
if ( update_entry . first )
elm - > notifyChannelShow ( update_entry . second - > channel ( ) , update_entry . second - > previous_channel ) ;
else deleted . push_back ( update_entry . second - > channelId ( ) ) ;
}
if ( ! deleted . empty ( ) )
elm - > notifyChannelHide ( deleted , false ) ; /* we've locked the tree before */
}
}
elm - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelClientAddPerm ( Command & cmd ) {
CMD_REF_SERVER ( server_ref ) ;
CMD_RESET_IDLE ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
auto cldbid = cmd [ " cldbid " ] . as < ClientDbId > ( ) ;
if ( ! serverInstance - > databaseHelper ( ) - > validClientDatabaseId ( this - > server , cldbid ) )
return command_result { error : : parameter_invalid , " Invalid client db id " } ;
RESOLVE_CHANNEL_R ( cmd [ " cid " ] , true ) ;
auto channel = dynamic_pointer_cast < ServerChannel > ( l_channel - > entry ) ;
if ( ! channel ) return command_result { error : : vs_critical } ;
auto mgr = serverInstance - > databaseHelper ( ) - > loadClientPermissionManager ( this - > server , cldbid ) ;
{
auto required_permissions = this - > server - > calculate_permission ( permission : : i_client_needed_permission_modify_power , cmd [ " cldbid " ] , ClientType : : CLIENT_TEAMSPEAK , channel_id ) ;
ACTION_REQUIRES_PERMISSION ( permission : : i_client_permission_modify_power , required_permissions , channel_id ) ;
}
auto max_value = this - > calculate_permission ( permission : : i_permission_modify_power , channel_id , true ) ;
if ( ! max_value . has_value ) return command_result { permission : : i_permission_modify_power } ;
auto ignore_granted_values = permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_permission_modify_power_ignore , channel_id ) ) ;
auto update_view = false ;
bool conOnError = cmd [ 0 ] . has ( " continueonerror " ) ;
auto onlineClientInstances = this - > server - > findClientsByCldbId ( cldbid ) ;
for ( int index = 0 ; index < cmd . bulkCount ( ) ; index + + ) {
PARSE_PERMISSION ( cmd ) ;
auto val = cmd [ index ] [ " permvalue " ] . as < permission : : PermissionValue > ( ) ;
if ( permission_require_granted_value ( permType ) & & ! permission : : v2 : : permission_granted ( val , max_value ) ) {
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
2020-02-03 19:41:18 +01:00
if ( ! ignore_granted_values & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permType , channel_id , true ) ) ) {
2020-01-26 14:21:34 +01:00
if ( conOnError ) continue ;
return command_result { permission : : i_permission_modify_power } ;
}
if ( grant ) {
mgr - > set_channel_permission ( permType , channel - > channelId ( ) , { 0 , cmd [ index ] [ " permvalue " ] } , permission : : v2 : : do_nothing , permission : : v2 : : set_value ) ;
} else {
mgr - > set_channel_permission ( permType , channel - > channelId ( ) , { cmd [ index ] [ " permvalue " ] , 0 } , permission : : v2 : : set_value , permission : : v2 : : do_nothing , cmd [ index ] [ " permskip " ] ? 1 : 0 , cmd [ index ] [ " permnegated " ] ? 1 : 0 ) ;
update_view = permType = = permission : : b_channel_ignore_view_power | | permType = = permission : : i_channel_view_power ;
}
}
serverInstance - > databaseHelper ( ) - > saveClientPermissions ( this - > server , cldbid , mgr ) ;
if ( ! onlineClientInstances . empty ( ) )
for ( const auto & elm : onlineClientInstances ) {
if ( elm - > update_cached_permissions ( ) ) /* update cached calculated permissions */
elm - > sendNeededPermissions ( false ) ; /* cached permissions had changed, notify the client */
if ( elm - > currentChannel = = channel ) {
elm - > updateChannelClientProperties ( true , true ) ;
} else if ( update_view ) {
unique_lock client_channel_lock ( this - > channel_lock ) ;
auto elm_channel = elm - > currentChannel ;
if ( elm_channel ) {
deque < ChannelId > deleted ;
for ( const auto & update_entry : elm - > channels - > update_channel_path ( l_channel , this - > server - > channelTree - > findLinkedChannel ( elm - > currentChannel - > channelId ( ) ) ) ) {
if ( update_entry . first )
elm - > notifyChannelShow ( update_entry . second - > channel ( ) , update_entry . second - > previous_channel ) ;
else deleted . push_back ( update_entry . second - > channelId ( ) ) ;
}
if ( ! deleted . empty ( ) )
elm - > notifyChannelHide ( deleted , false ) ; /* we've locked the tree before */
}
}
elm - > join_state_id + + ; /* join permission may changed, all channels need to be recalculate dif needed */
}
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelFind ( Command & cmd ) {
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
string pattern = cmd [ " pattern " ] ;
std : : transform ( pattern . begin ( ) , pattern . end ( ) , pattern . begin ( ) , : : tolower ) ;
Command res ( " " ) ;
int index = 0 ;
for ( const auto & cl : ( this - > server ? this - > server - > channelTree : serverInstance - > getChannelTree ( ) . get ( ) ) - > channels ( ) ) {
string name = cl - > name ( ) ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , : : tolower ) ;
if ( name . find ( pattern ) ! = std : : string : : npos ) {
res [ index ] [ " cid " ] = cl - > channelId ( ) ;
res [ index ] [ " channel_name " ] = cl - > name ( ) ;
index + + ;
}
}
if ( index = = 0 ) return command_result { error : : database_empty_result } ;
this - > sendCommand ( res ) ;
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandChannelInfo ( Command & cmd ) {
std : : shared_ptr < BasicChannel > channel = ( this - > server ? this - > server - > channelTree : serverInstance - > getChannelTree ( ) . get ( ) ) - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel ) return command_result { error : : channel_invalid_id , " Cant resolve channel " } ;
Command res ( " " ) ;
for ( const auto & prop : channel - > properties ( ) . list_properties ( property : : FLAG_CHANNEL_VIEW | property : : FLAG_CHANNEL_VARIABLE , this - > getType ( ) = = CLIENT_TEAMSPEAK ? property : : FLAG_NEW : ( uint16_t ) 0 ) )
res [ prop . type ( ) . name ] = prop . value ( ) ;
res [ " seconds_empty " ] = channel - > emptySince ( ) ;
res [ " pid " ] = res [ " cpid " ] . string ( ) ;
this - > sendCommand ( res ) ;
return command_result { error : : ok } ;
}