2019-07-17 19:37:18 +02:00
# include <algorithm>
# include <log/LogUtils.h>
# include <misc/memtracker.h>
# include <misc/sassert.h>
# include "misc/rnd.h"
2020-01-26 18:04:38 +01:00
# include "src/VirtualServer.h"
2019-07-17 19:37:18 +02:00
# include "src/client/ConnectedClient.h"
# include "src/InstanceHandler.h"
2019-07-19 22:55:03 +02:00
# include "../manager/ConversationManager.h"
2019-07-17 19:37:18 +02:00
using namespace std ;
using namespace ts ;
using namespace ts : : server ;
2020-11-07 13:17:51 +01:00
ServerChannel : : ServerChannel ( uint32_t rtc_channel_id , ChannelId parentId , ChannelId channelId ) : BasicChannel ( parentId , channelId ) ,
rtc_channel_id { rtc_channel_id } {
2020-01-24 02:57:58 +01:00
memtrack : : allocated < ServerChannel > ( this ) ;
2019-07-17 19:37:18 +02:00
}
ServerChannel : : ~ ServerChannel ( ) {
2020-01-24 02:57:58 +01:00
memtrack : : freed < ServerChannel > ( this ) ;
2019-07-17 19:37:18 +02:00
}
void ServerChannel : : register_client ( const std : : shared_ptr < ts : : server : : ConnectedClient > & client ) {
2020-01-24 02:57:58 +01:00
unique_lock lock ( this - > client_lock ) ;
for ( const auto & _client : this - > clients ) {
if ( _client . lock ( ) = = client ) {
return ;
}
}
this - > clients . push_back ( client ) ;
2019-07-17 19:37:18 +02:00
}
void ServerChannel : : unregister_client ( const std : : shared_ptr < ts : : server : : ConnectedClient > & client ) {
2020-01-24 02:57:58 +01:00
unique_lock lock ( this - > client_lock ) ;
this - > clients . erase ( remove_if ( this - > clients . begin ( ) , this - > clients . end ( ) , [ client ] ( const auto & weak ) {
auto locked = weak . lock ( ) ;
if ( ! locked | | client = = locked ) return true ;
return false ;
} ) , this - > clients . end ( ) ) ;
2019-07-17 19:37:18 +02:00
}
size_t ServerChannel : : client_count ( ) {
2020-01-24 02:57:58 +01:00
shared_lock lock ( this - > client_lock ) ;
size_t result = 0 ;
for ( const auto & weak_entry : this - > clients ) {
if ( auto entry = weak_entry . lock ( ) ) {
auto current_channel = entry - > getChannel ( ) ;
if ( current_channel & & current_channel . get ( ) = = this )
result + + ;
}
}
return result ;
2019-07-17 19:37:18 +02:00
}
void ServerChannel : : setProperties ( const std : : shared_ptr < Properties > & ptr ) {
2020-01-24 02:57:58 +01:00
BasicChannel : : setProperties ( ptr ) ;
2019-07-17 19:37:18 +02:00
}
2020-11-07 13:17:51 +01:00
ServerChannelTree : : ServerChannelTree ( const std : : shared_ptr < server : : VirtualServer > & server , sql : : SqlManager * sql ) : sql ( sql ) , server_ref ( server ) { }
2019-07-17 19:37:18 +02:00
ServerChannelTree : : ~ ServerChannelTree ( ) { }
void ServerChannelTree : : deleteSemiPermanentChannels ( ) {
2020-01-24 02:57:58 +01:00
loop :
2019-07-17 19:37:18 +02:00
2020-11-07 13:17:51 +01:00
for ( const auto & ch : this - > channels ( ) ) {
2020-01-24 02:57:58 +01:00
if ( ch - > channelType ( ) = = ChannelType : : semipermanent | | ch - > channelType ( ) = = ChannelType : : temporary ) { //We also delete private channels
this - > delete_channel_root ( ch ) ;
goto loop ;
}
2020-11-07 13:17:51 +01:00
}
2019-07-17 19:37:18 +02:00
}
ChannelId ServerChannelTree : : generateChannelId ( ) {
2020-01-24 02:57:58 +01:00
ChannelId channelId = 0 ;
auto res = sql : : command ( this - > sql , " SELECT `channelId` FROM `channels` WHERE `serverId` = :sid ORDER BY `channelId` DESC LIMIT 1 " , variable { " :sid " , this - > getServerId ( ) } ) . query ( [ ] ( ChannelId * num , int , char * * value , char * * ) {
* num = ( ChannelId ) stoll ( value [ 0 ] ) ;
return 0 ;
} , & channelId ) ;
auto pf = LOG_SQL_CMD ;
pf ( res ) ;
if ( ! res ) return 0 ;
return channelId + 1 ;
2019-07-17 19:37:18 +02:00
}
std : : shared_ptr < BasicChannel > ServerChannelTree : : createChannel ( ChannelId parentId , ChannelId orderId , const string & name ) {
std : : shared_ptr < BasicChannel > channel = BasicChannelTree : : createChannel ( parentId , orderId , name ) ;
2020-01-24 02:57:58 +01:00
if ( ! channel ) return channel ;
2019-07-17 19:37:18 +02:00
2020-11-07 13:17:51 +01:00
auto properties = serverInstance - > databaseHelper ( ) - > loadChannelProperties ( this - > server_ref . lock ( ) , channel - > channelId ( ) ) ;
for ( const auto & prop : channel - > properties ( ) . list_properties ( ) ) {
if ( prop . isModified ( ) ) { //Copy the already set properties
2020-01-24 02:57:58 +01:00
( * properties ) [ prop . type ( ) ] = prop . value ( ) ;
2020-11-07 13:17:51 +01:00
}
}
2019-07-17 19:37:18 +02:00
static_pointer_cast < ServerChannel > ( channel ) - > setProperties ( properties ) ;
2020-11-07 13:17:51 +01:00
static_pointer_cast < ServerChannel > ( channel ) - > setPermissionManager ( serverInstance - > databaseHelper ( ) - > loadChannelPermissions ( this - > server_ref . lock ( ) , channel - > channelId ( ) ) ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
channel - > properties ( ) [ property : : CHANNEL_CREATED_AT ] = chrono : : duration_cast < chrono : : milliseconds > ( chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
channel - > properties ( ) [ property : : CHANNEL_LAST_LEFT ] = chrono : : duration_cast < chrono : : milliseconds > ( chrono : : system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
2019-07-17 19:37:18 +02:00
2020-04-16 14:05:58 +02:00
auto result = sql : : command ( this - > sql , " INSERT INTO `channels` (`serverId`, `channelId`, `parentId`) VALUES(:sid, :chid, :parent); " , variable { " :sid " , this - > getServerId ( ) } , variable { " :chid " , channel - > channelId ( ) } , variable { " :parent " , channel - > parent ( ) ? channel - > parent ( ) - > channelId ( ) : 0 } ) . execute ( ) ;
2020-01-24 02:57:58 +01:00
auto pf = LOG_SQL_CMD ;
pf ( result ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
return channel ;
2019-07-17 19:37:18 +02:00
}
inline std : : shared_ptr < BasicChannel > findChannelByPool ( const std : : deque < std : : shared_ptr < TreeView : : LinkedTreeEntry > > & pool , size_t chId ) {
2020-01-24 02:57:58 +01:00
for ( const auto & elm : pool )
if ( elm - > entry - > channelId ( ) = = chId ) return dynamic_pointer_cast < BasicChannel > ( elm - > entry ) ;
return nullptr ;
2019-07-17 19:37:18 +02:00
}
inline std : : shared_ptr < TreeView : : LinkedTreeEntry > findLinkedChannelByPool ( const std : : deque < std : : shared_ptr < TreeView : : LinkedTreeEntry > > & pool , size_t chId ) {
for ( const auto & elm : pool )
if ( elm - > entry - > channelId ( ) = = chId ) return elm ;
return nullptr ;
}
ServerId ServerChannelTree : : getServerId ( ) {
2020-11-07 13:17:51 +01:00
auto s = this - > server_ref . lock ( ) ;
2020-01-24 02:57:58 +01:00
return s ? s - > getServerId ( ) : 0UL ;
2019-07-17 19:37:18 +02:00
}
bool ServerChannelTree : : initializeTempParents ( ) {
2020-01-24 02:57:58 +01:00
auto channelList = this - > tmpChannelList ;
for ( const auto & linked_channel : channelList ) {
auto channel = dynamic_pointer_cast < BasicChannel > ( linked_channel - > entry ) ;
assert ( channel ) ;
if ( channel - > properties ( ) . hasProperty ( property : : CHANNEL_PID ) & & channel - > properties ( ) [ property : : CHANNEL_PID ] . as < ChannelId > ( ) ! = 0 ) {
if ( ! channel - > parent ( ) )
linked_channel - > parent = findLinkedChannelByPool ( this - > tmpChannelList , channel - > properties ( ) [ property : : CHANNEL_PID ] ) ;
if ( ! channel - > parent ( ) ) {
logError ( this - > getServerId ( ) , " Invalid channel parent (Channel does not exists). Channel id: {} ({}) Missing parent id: {} " , channel - > channelId ( ) , channel - > name ( ) , channel - > properties ( ) [ property : : CHANNEL_PID ] . as < ChannelId > ( ) ) ;
logError ( this - > getServerId ( ) , " Resetting parent " ) ;
channel - > properties ( ) [ property : : CHANNEL_PID ] = 0 ;
}
}
}
return true ;
2019-07-17 19:37:18 +02:00
}
typedef std : : deque < std : : shared_ptr < TreeView : : LinkedTreeEntry > > ChannelPool ;
inline ChannelPool remoteTopChannels ( const std : : shared_ptr < TreeView : : LinkedTreeEntry > & parent , ChannelPool & pool ) {
ChannelPool result ;
2020-01-24 02:57:58 +01:00
for ( const auto & elm : pool )
if ( elm - > parent . lock ( ) = = parent )
result . push_back ( elm ) ;
for ( const auto & elm : result )
pool . erase ( std : : find ( pool . begin ( ) , pool . end ( ) , elm ) ) ;
return result ;
2019-07-17 19:37:18 +02:00
}
inline ChannelPool resolveChannelHeads ( ServerId serverId , ChannelPool pool ) {
ChannelPool result ;
while ( ! pool . empty ( ) ) {
auto element = pool . front ( ) ;
if ( ! element ) continue ;
2020-01-24 02:57:58 +01:00
ChannelPool tmp_pool = pool ;
auto f = find ( tmp_pool . begin ( ) , tmp_pool . end ( ) , element ) ;
if ( f ! = tmp_pool . end ( ) )
tmp_pool . erase ( f ) ;
2019-07-17 19:37:18 +02:00
while ( element - > previous ) {
2020-01-24 02:57:58 +01:00
auto found = find ( tmp_pool . begin ( ) , tmp_pool . end ( ) , element - > previous ) ;
2019-07-17 19:37:18 +02:00
if ( found = = tmp_pool . end ( ) ) {
logError ( serverId , " Found recursive channel heads! Cutting " ) ;
if ( element - > previous & & element - > previous - > next = = element )
2020-01-24 02:57:58 +01:00
element - > previous - > next = nullptr ;
element - > previous = nullptr ;
break ;
2019-07-17 19:37:18 +02:00
}
2020-01-24 02:57:58 +01:00
tmp_pool . erase ( found ) ;
element = element - > previous ;
2019-07-17 19:37:18 +02:00
} ; //Find the head
result . push_back ( element ) ;
auto last = element ;
while ( element ) {
auto it = find ( pool . begin ( ) , pool . end ( ) , element ) ;
if ( it = = pool . end ( ) ) {
2020-01-24 02:57:58 +01:00
logError ( serverId , " Circular tail. Cutting previus. " ) ;
if ( last ! = element ) {
if ( element - > previous = = last )
element - > previous = nullptr ;
if ( last - > next = = element )
last - > next = nullptr ;
}
break ;
2019-07-17 19:37:18 +02:00
} else
2020-01-24 02:57:58 +01:00
pool . erase ( it ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
last = element ;
2019-07-17 19:37:18 +02:00
element = element - > next ;
}
}
return result ;
}
inline std : : shared_ptr < TreeView : : LinkedTreeEntry > buildChannelTree ( ServerId serverId , const std : : shared_ptr < TreeView : : LinkedTreeEntry > & parent , ChannelPool & channel_pool ) {
2020-01-24 02:57:58 +01:00
auto top_channels = remoteTopChannels ( parent , channel_pool ) ;
if ( top_channels . empty ( ) ) return nullptr ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
bool brokenTree = false ;
for ( const auto & linked_channel : top_channels ) {
auto channel = dynamic_pointer_cast < BasicChannel > ( linked_channel - > entry ) ;
assert ( channel ) ;
2019-07-17 19:37:18 +02:00
if ( channel - > channelOrder ( ) ! = 0 ) {
2020-01-24 02:57:58 +01:00
if ( channel - > channelOrder ( ) = = channel - > channelId ( ) ) {
2019-07-17 19:37:18 +02:00
brokenTree = true ;
2020-01-24 02:57:58 +01:00
logError ( serverId , " Channel order refers to itself! (Resetting) " ) ;
2019-07-17 19:37:18 +02:00
channel - > properties ( ) [ property : : CHANNEL_ORDER ] = 0 ;
2020-01-24 02:57:58 +01:00
continue ;
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
auto previous_linked = findLinkedChannelByPool ( top_channels , channel - > channelOrder ( ) ) ;
if ( ! previous_linked ) {
2019-07-17 19:37:18 +02:00
brokenTree = true ;
2020-01-24 02:57:58 +01:00
logError ( serverId , " Failed to resolve previous channel for channel {} ({}). Previous channel id: {} (Resetting order) " , channel - > channelId ( ) , channel - > name ( ) , channel - > channelOrder ( ) ) ;
2019-07-17 19:37:18 +02:00
channel - > properties ( ) [ property : : CHANNEL_ORDER ] = 0 ;
continue ;
2020-01-24 02:57:58 +01:00
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
if ( previous_linked - > next ) {
if ( previous_linked - > next ! = linked_channel ) {
2019-07-17 19:37:18 +02:00
brokenTree = true ;
2020-01-24 02:57:58 +01:00
logError ( serverId , " Previous channel {} ({}) of channel {} ({}) is already linked with another channel {} ({}). " ,
2019-07-17 19:37:18 +02:00
previous_linked - > entry - > channelId ( ) , dynamic_pointer_cast < BasicChannel > ( previous_linked - > entry ) - > name ( ) ,
channel - > channelId ( ) , channel - > name ( ) ,
previous_linked - > next - > entry - > channelId ( ) , dynamic_pointer_cast < BasicChannel > ( previous_linked - > next - > entry ) - > name ( )
) ;
2020-01-24 02:57:58 +01:00
logError ( serverId , " Inserting channel anyway! " ) ;
previous_linked - > next - > previous = linked_channel ;
linked_channel - > next = previous_linked - > next ;
}
}
2019-07-17 19:37:18 +02:00
previous_linked - > next = linked_channel ;
linked_channel - > previous = previous_linked ;
2020-01-24 02:57:58 +01:00
}
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
for ( const auto & elm : top_channels ) {
if ( elm - > next ) {
if ( elm - > next - > previous ! = elm ) {
2019-07-17 19:37:18 +02:00
brokenTree = true ;
2020-01-24 02:57:58 +01:00
logError ( serverId , " Test 'elm->next->previous != elm' failed! Assigning elm->next->previous to elm! " ) ;
2019-07-17 19:37:18 +02:00
elm - > next - > previous = elm ;
2020-01-24 02:57:58 +01:00
}
}
2019-07-17 19:37:18 +02:00
if ( elm - > previous ) {
if ( elm - > previous - > next ! = elm ) {
brokenTree = true ;
logError ( serverId , " Test 'elm->previous->next != elm' failed! Assigning elm->previous->next to elm! " ) ;
elm - > previous - > next = elm ;
}
}
2020-01-24 02:57:58 +01:00
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
/* Get the heads and merge them */
auto heads = resolveChannelHeads ( serverId , top_channels ) ;
if ( heads . size ( ) > 1 ) {
brokenTree = true ;
logError ( serverId , " Got multiple channel heads! (Count {}) " , heads . size ( ) ) ;
2019-07-17 19:37:18 +02:00
logError ( serverId , " Try to appending them " , heads . size ( ) ) ;
debugMessage ( serverId , " Got head: " ) ;
//FIXME print head
for ( int index = 1 ; index < heads . size ( ) ; index + + ) {
auto tail = heads [ 0 ] ;
while ( tail - > next ) tail = tail - > next ;
tail - > next = heads [ index ] ;
tail - > next - > previous = tail ;
}
2020-01-24 02:57:58 +01:00
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
/* Testing tree */
2019-07-17 19:37:18 +02:00
if ( brokenTree ) {
auto new_heads = resolveChannelHeads ( serverId , top_channels ) ;
if ( new_heads . size ( ) ! = 1 ) {
logCritical ( serverId , " Failed to merge channel heads (Got {} heads)! Unknown reason! " , new_heads . size ( ) ) ;
logCritical ( serverId , " Dropping a part! " ) ;
}
}
2020-01-24 02:57:58 +01:00
brokenTree = true ;
if ( brokenTree ) {
2019-07-17 19:37:18 +02:00
auto entry = heads [ 0 ] ;
2020-01-24 02:57:58 +01:00
while ( entry ) {
auto channel = dynamic_pointer_cast < BasicChannel > ( entry - > entry ) ;
assert ( channel ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
auto evaluated_order_id = entry - > previous ? entry - > previous - > entry - > channelId ( ) : 0 ;
if ( evaluated_order_id ! = channel - > previousChannelId ( ) ) {
2019-07-17 19:37:18 +02:00
channel - > setPreviousChannelId ( evaluated_order_id ) ;
2020-01-24 02:57:58 +01:00
debugMessage ( serverId , " Fixed order id for channel {} ({}). New previous channel {} " , entry - > entry - > channelId ( ) , channel - > name ( ) , channel - > channelOrder ( ) ) ;
}
2019-07-17 19:37:18 +02:00
auto evaluated_parent_id = channel - > parent ( ) ? channel - > parent ( ) - > channelId ( ) : 0 ;
if ( evaluated_parent_id ! = channel - > properties ( ) [ property : : CHANNEL_PID ] . as < ChannelId > ( ) ) {
debugMessage ( serverId , " Fixed parent id for channel {} ({}). New parent channel {} " , entry - > entry - > channelId ( ) , channel - > name ( ) , evaluated_parent_id ) ;
channel - > properties ( ) [ property : : CHANNEL_PID ] = evaluated_parent_id ;
}
entry = entry - > next ;
2020-01-24 02:57:58 +01:00
}
}
2019-07-17 19:37:18 +02:00
{ /* building sub trees */
auto entry = heads [ 0 ] ;
while ( entry ) {
entry - > child_head = buildChannelTree ( serverId , entry , channel_pool ) ;
entry = entry - > next ;
}
}
2020-01-24 02:57:58 +01:00
return heads [ 0 ] ;
2019-07-17 19:37:18 +02:00
}
bool ServerChannelTree : : buildChannelTreeFromTemp ( ) {
2020-01-24 02:57:58 +01:00
if ( this - > tmpChannelList . empty ( ) ) return true ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
this - > head = buildChannelTree ( this - > getServerId ( ) , nullptr , this - > tmpChannelList ) ;
assert ( tmpChannelList . empty ( ) ) ;
return true ;
2019-07-17 19:37:18 +02:00
}
2020-01-27 13:02:22 +01:00
inline void walk_tree ( const std : : shared_ptr < TreeView : : LinkedTreeEntry > & parent , std : : shared_ptr < TreeView : : LinkedTreeEntry > head ) {
auto parent_id = parent ? parent - > entry - > channelId ( ) : 0 ;
std : : shared_ptr < TreeView : : LinkedTreeEntry > previous { nullptr } ;
while ( head ) {
head - > entry - > setParentChannelId ( parent_id ) ;
if ( head - > previous ! = previous ) {
logCritical ( 0 , " Detect broken channel tree! " ) ;
} else if ( previous ) {
head - > entry - > setPreviousChannelId ( previous - > entry - > channelId ( ) ) ;
} else {
head - > entry - > setPreviousChannelId ( 0 ) ;
}
if ( head - > child_head )
walk_tree ( head , head - > child_head ) ;
previous = head ;
head = head - > next ;
}
}
bool ServerChannelTree : : updateOrderIds ( ) {
walk_tree ( nullptr , this - > head ) ;
return true ;
}
2019-07-17 19:37:18 +02:00
inline ssize_t count_characters ( const std : : string & in ) {
2020-01-24 02:57:58 +01:00
size_t index = 0 ;
size_t count = 0 ;
while ( index < in . length ( ) ) {
count + + ;
auto current = ( uint8_t ) in [ index ] ;
if ( current > = 128 ) { //UTF8 check
if ( current > = 192 & & ( current < = 193 | | current > = 245 ) ) {
return - 1 ;
} else if ( current > = 194 & & current < = 223 ) {
if ( in . length ( ) - index < = 1 ) return - 1 ;
else if ( ( uint8_t ) in [ index + 1 ] > = 128 & & ( uint8_t ) in [ index + 1 ] < = 191 ) index + = 1 ; //Valid
else return - 1 ;
} else if ( current > = 224 & & current < = 239 ) {
if ( in . length ( ) - index < = 2 ) return - 1 ;
else if ( ( uint8_t ) in [ index + 1 ] > = 128 & & ( uint8_t ) in [ index + 1 ] < = 191 & &
( uint8_t ) in [ index + 2 ] > = 128 & & ( uint8_t ) in [ index + 2 ] < = 191 ) index + = 2 ; //Valid
else return - 1 ;
} else if ( current > = 240 & & current < = 244 ) {
if ( in . length ( ) - index < = 3 ) return - 1 ;
else if ( ( uint8_t ) in [ index + 1 ] > = 128 & & ( uint8_t ) in [ index + 1 ] < = 191 & &
( uint8_t ) in [ index + 2 ] > = 128 & & ( uint8_t ) in [ index + 2 ] < = 191 & &
( uint8_t ) in [ index + 3 ] > = 128 & & ( uint8_t ) in [ index + 3 ] < = 191 ) index + = 3 ; //Valid
else return - 1 ;
} else {
return - 1 ;
}
}
index + + ;
}
return count ;
2019-07-17 19:37:18 +02:00
}
bool ServerChannelTree : : validateChannelNames ( ) {
2020-01-24 02:57:58 +01:00
/*
2019-07-17 19:37:18 +02:00
if ( count_characters ( cmd [ " channel_name " ] ) < 1 ) return { findError ( " channel_name_inuse " ) , " Invalid channel name (too short) " } ;
if ( count_characters ( cmd [ " channel_name " ] ) > 40 ) return { findError ( " channel_name_inuse " ) , " Invalid channel name (too long) " } ;
2020-01-24 02:57:58 +01:00
*/
/*
for ( const auto & channel : this - > channels ( ) ) {
mainSearch :
for ( const auto & ref : this - > channels ( channel - > parent ( ) , 1 ) )
if ( ref - > name ( ) = = channel - > name ( ) & & ref ! = channel ) {
logError ( lstream < < " Duplicated channel name ' " < < channel - > name ( ) < < " '. Fixing it by appending '1' " < < endl ) ;
channel - > properties ( ) [ " channel_name " ] = channel - > name ( ) + " 1 " ;
goto mainSearch ;
}
if ( channel - > name ( ) . length ( ) > 40 ) {
channel - > properties ( ) [ " channel_name " ] = channel - > name ( ) . substr ( 0 , 35 ) + rnd_string ( 5 ) ;
goto mainSearch ;
}
}
*/
for ( const auto & channel : this - > channels ( ) ) {
auto name_length = count_characters ( channel - > name ( ) ) ;
if ( name_length > 40 ) {
logError ( this - > getServerId ( ) , " Channel {} loaded an invalid name from the database (name to long). Cutting channel name " ) ;
channel - > properties ( ) [ property : : CHANNEL_NAME ] = channel - > name ( ) . substr ( 0 , 40 ) ; //FIXME count UTF8
} else if ( name_length < 1 ) {
logError ( this - > getServerId ( ) , " Channel {} loaded an invalid name from the database (empty name). Resetting channel name " ) ;
channel - > properties ( ) [ property : : CHANNEL_NAME ] = " undefined " ;
}
}
function < void ( const std : : shared_ptr < LinkedTreeEntry > & ) > test_level ;
test_level = [ & ] ( const std : : shared_ptr < LinkedTreeEntry > & head ) {
map < string , shared_ptr < ServerChannel > > used_names ;
auto it = head ;
while ( it ) {
auto channel = dynamic_pointer_cast < ServerChannel > ( it - > entry ) ;
auto name = channel - > name ( ) ;
if ( used_names . count ( name ) > 0 ) {
auto taken_channel = used_names [ name ] ;
assert ( taken_channel ) ;
size_t index = 1 ;
while ( true ) {
auto _name = name + to_string ( index ) ;
if ( _name . length ( ) > 40 ) //FIXME count UTF8
_name = _name . substr ( _name . length ( ) - 40 ) ;
if ( used_names [ _name ] )
index + + ;
else {
name = _name ;
break ;
}
}
channel - > properties ( ) [ property : : CHANNEL_NAME ] = name ;
logError ( this - > getServerId ( ) , " Channel {} has the same name as channel {}. Name: {}. Changing name to {} by appending an index. " ,
channel - > channelId ( ) ,
taken_channel - > channelId ( ) ,
taken_channel - > name ( ) ,
name
) ;
}
used_names [ name ] = channel ;
if ( it - > child_head )
test_level ( it - > child_head ) ;
it = it - > next ;
}
} ;
test_level ( this - > tree_head ( ) ) ;
return true ;
2019-07-17 19:37:18 +02:00
}
bool ServerChannelTree : : validateChannelIcons ( ) {
2020-01-24 02:57:58 +01:00
for ( const auto & channel : this - > channels ( ) ) {
auto iconId = ( IconId ) channel - > properties ( ) [ property : : CHANNEL_ICON_ID ] ;
2020-05-13 11:32:08 +02:00
#if 0
2020-01-24 02:57:58 +01:00
if ( iconId ! = 0 & & ! serverInstance - > getFileServer ( ) - > iconExists ( this - > server . lock ( ) , iconId ) ) {
logMessage ( this - > getServerId ( ) , " [FILE] Missing channel icon ( " + to_string ( iconId ) + " ). " ) ;
if ( config : : server : : delete_missing_icon_permissions ) {
channel - > properties ( ) [ property : : CHANNEL_ICON_ID ] = 0 ;
channel - > permissions ( ) - > set_permission ( permission : : i_icon_id , { 0 , 0 } , permission : : v2 : : PermissionUpdateType : : set_value , permission : : v2 : : PermissionUpdateType : : do_nothing ) ;
}
}
2020-05-13 11:32:08 +02:00
# endif
2020-01-24 02:57:58 +01:00
}
return true ;
2019-07-17 19:37:18 +02:00
}
void ServerChannelTree : : loadChannelsFromDatabase ( ) {
2020-04-16 14:05:58 +02:00
auto res = sql : : command ( this - > sql , " SELECT `channelId`, `parentId` FROM `channels` WHERE `serverId` = :sid " , variable { " :sid " , this - > getServerId ( ) } ) . query ( & ServerChannelTree : : loadChannelFromData , this ) ;
2020-01-24 02:57:58 +01:00
( LOG_SQL_CMD ) ( res ) ;
if ( ! res ) {
logError ( this - > getServerId ( ) , " Could not load channel tree from database " ) ;
return ;
}
logMessage ( this - > getServerId ( ) , " Loaded {} saved channels. Assembling... " , this - > tmpChannelList . size ( ) ) ;
this - > initializeTempParents ( ) ;
this - > buildChannelTreeFromTemp ( ) ;
2020-01-27 13:02:22 +01:00
this - > updateOrderIds ( ) ;
2020-01-24 02:57:58 +01:00
this - > validateChannelNames ( ) ;
this - > validateChannelIcons ( ) ;
//this->printChannelTree();
2019-07-17 19:37:18 +02:00
}
int ServerChannelTree : : loadChannelFromData ( int argc , char * * data , char * * column ) {
2020-01-24 02:57:58 +01:00
ChannelId channelId = 0 ;
ChannelId parentId = 0 ;
int index = 0 ;
try {
for ( index = 0 ; index < argc ; index + + ) {
if ( strcmp ( column [ index ] , " channelId " ) = = 0 ) channelId = static_cast < ChannelId > ( stoll ( data [ index ] ) ) ;
else if ( strcmp ( column [ index ] , " parentId " ) = = 0 ) parentId = static_cast < ChannelId > ( stoll ( data [ index ] ) ) ;
else logError ( this - > getServerId ( ) , " ServerChannelTree::loadChannelFromData called with invalid column from sql \" { } \ " " , column [ index ] ) ;
}
} catch ( std : : exception & ex ) {
logError ( this - > getServerId ( ) , " Failed to load channel. Got exception {}. Exception was thrown at parsing row {} with data \" {} \" " , ex . what ( ) , column [ index ] , data [ index ] ) ;
return 0 ;
}
//assert(type != 0xFF);
assert ( channelId ! = 0 ) ;
2020-07-31 17:35:14 +02:00
if ( channelId = = 0 )
return 0 ;
2020-01-24 02:57:58 +01:00
2020-11-07 13:17:51 +01:00
auto server = this - > server_ref . lock ( ) ;
std : : shared_ptr < ServerChannel > channel ;
if ( server ) {
auto rtc_channel_id = server - > rtc_server ( ) . create_channel ( ) ;
channel = std : : make_shared < ServerChannel > ( rtc_channel_id , parentId , channelId ) ;
} else {
channel = std : : make_shared < ServerChannel > ( 0 , parentId , channelId ) ;
}
2020-01-24 02:57:58 +01:00
static_pointer_cast < ServerChannel > ( channel ) - > setProperties ( serverInstance - > databaseHelper ( ) - > loadChannelProperties ( server , channelId ) ) ;
static_pointer_cast < ServerChannel > ( channel ) - > setPermissionManager ( serverInstance - > databaseHelper ( ) - > loadChannelPermissions ( server , channel - > channelId ( ) ) ) ;
auto entry = make_shared < TreeView : : LinkedTreeEntry > ( channel ) ;
channel - > setLinkedHandle ( entry ) ;
this - > tmpChannelList . push_back ( entry ) ;
return 0 ;
2019-07-17 19:37:18 +02:00
}
deque < ChannelId > ServerChannelTree : : deleteChannelRoot ( const std : : shared_ptr < BasicChannel > & channel ) {
2020-11-07 13:17:51 +01:00
auto server = this - > server_ref . lock ( ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
auto channels = this - > delete_channel_root ( channel ) ;
deque < ChannelId > channel_ids ;
2020-11-07 13:17:51 +01:00
for ( const auto & channel : channels ) {
2020-01-24 02:57:58 +01:00
channel_ids . push_back ( channel - > channelId ( ) ) ;
2020-11-07 13:17:51 +01:00
}
2020-01-24 02:57:58 +01:00
return channel_ids ;
2019-07-17 19:37:18 +02:00
}
void ServerChannelTree : : on_channel_entry_deleted ( const shared_ptr < BasicChannel > & channel ) {
2020-01-24 02:57:58 +01:00
BasicChannelTree : : on_channel_entry_deleted ( channel ) ;
2019-07-17 19:37:18 +02:00
2020-11-07 13:17:51 +01:00
auto server_channel = dynamic_pointer_cast < ServerChannel > ( channel ) ;
assert ( server_channel ) ;
auto server = this - > server_ref . lock ( ) ;
2020-01-24 02:57:58 +01:00
if ( server ) {
server - > getGroupManager ( ) - > handleChannelDeleted ( channel - > channelId ( ) ) ;
server - > conversation_manager ( ) - > delete_conversation ( channel - > channelId ( ) ) ;
2020-11-07 13:17:51 +01:00
server - > rtc_server ( ) . destroy_channel ( server_channel - > rtc_channel_id ) ;
} else {
2020-01-24 02:57:58 +01:00
serverInstance - > getGroupManager ( ) - > handleChannelDeleted ( channel - > channelId ( ) ) ;
2020-11-07 13:17:51 +01:00
}
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
auto sql_result = sql : : command ( this - > sql , " DELETE FROM `channels` WHERE `serverId` = ' " + to_string ( this - > getServerId ( ) ) + " ' AND `channelId` = ' " + to_string ( channel - > channelId ( ) ) + " ' " ) . execute ( ) ;
LOG_SQL_CMD ( sql_result ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
sql_result = sql : : command ( this - > sql , " DELETE FROM `properties` WHERE `serverId` = ' " + to_string ( this - > getServerId ( ) ) + " ' AND `id` = ' " + to_string ( channel - > channelId ( ) ) + " ' AND `type` = " + to_string ( property : : PropertyType : : PROP_TYPE_CHANNEL ) ) . execute ( ) ;
LOG_SQL_CMD ( sql_result ) ;
2019-07-17 19:37:18 +02:00
2020-11-07 13:17:51 +01:00
serverInstance - > databaseHelper ( ) - > deleteChannelPermissions ( this - > server_ref . lock ( ) , channel - > channelId ( ) ) ;
2020-01-24 02:57:58 +01:00
sql_result = sql : : command ( this - > sql , " DELETE FROM `assignedGroups` WHERE `serverId` = ' " + to_string ( this - > getServerId ( ) ) + " ' AND `channelId` = ' " + to_string ( channel - > channelId ( ) ) + " ' " ) . execute ( ) ;
LOG_SQL_CMD ( sql_result ) ;
2019-07-17 19:37:18 +02:00
}
std : : shared_ptr < BasicChannel > ServerChannelTree : : allocateChannel ( const shared_ptr < BasicChannel > & parent , ChannelId channelId ) {
2020-11-07 13:17:51 +01:00
auto server = this - > server_ref . lock ( ) ;
if ( server ) {
auto rtc_channel_id = server - > rtc_server ( ) . create_channel ( ) ;
return std : : make_shared < ServerChannel > ( rtc_channel_id , parent - > channelId ( ) , channelId ) ;
} else {
return std : : make_shared < ServerChannel > ( 0 , parent - > channelId ( ) , channelId ) ;
}
2019-07-17 19:37:18 +02:00
}