2020-01-26 14:21:34 +01:00
//
// Created by wolverindev on 26.01.20.
//
# include <memory>
# include <bitset>
# include <algorithm>
# include <openssl/sha.h>
# include "../../build.h"
# include "../ConnectedClient.h"
# include "../InternalClient.h"
# include "../../server/VoiceServer.h"
# include "../voice/VoiceClient.h"
# include "../../InstanceHandler.h"
# include "../../server/QueryServer.h"
# include "../music/MusicClient.h"
# include "../query/QueryClient.h"
# include "../../weblist/WebListManager.h"
# include "../../manager/ConversationManager.h"
# include "../../manager/PermissionNameMapper.h"
# include "helpers.h"
2020-05-13 11:32:08 +02:00
# include <files/FileServer.h>
2020-01-26 14:21:34 +01:00
# include <log/LogUtils.h>
# include <misc/sassert.h>
# include <misc/base64.h>
# include <misc/hex.h>
# include <misc/rnd.h>
# include <misc/strobf.h>
# include <bbcode/bbcodes.h>
using namespace std : : chrono ;
using namespace std ;
using namespace ts ;
using namespace ts : : server ;
using namespace ts : : token ;
2020-05-13 11:32:08 +02:00
constexpr static auto kFileAPITimeout = std : : chrono : : milliseconds { 500 } ;
constexpr static auto kMaxClientTransfers = 10 ;
2020-01-26 14:21:34 +01:00
# define QUERY_PASSWORD_LENGTH 12
//ftgetfilelist cid=1 cpw path=\/ return_code=1:x
//Answer:
//1 .. n
// notifyfilelist cid=1 path=\/ return_code=1:x name=testFile size=35256 datetime=1509459767 type=1|name=testDir size=0 datetime=1509459741 type=0|name=testDir_2 size=0 datetime=1509459763 type=0
//notifyfilelistfinished cid=1 path=\/
command_result ConnectedClient : : handleCommandFTGetFileList ( Command & cmd ) {
2020-05-13 11:32:08 +02:00
using directory_query_response_t = file : : filesystem : : AbstractProvider : : directory_query_response_t ;
using DirectoryEntry = file : : filesystem : : DirectoryEntry ;
2020-01-26 14:21:34 +01:00
CMD_REQ_SERVER ;
CMD_RESET_IDLE ;
2020-05-13 11:32:08 +02:00
auto virtual_file_server = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! virtual_file_server ) return command_result { error : : file_virtual_server_not_registered } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
auto & file_system = file : : server ( ) - > file_system ( ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
auto directory_path = cmd [ " path " ] . string ( ) ;
std : : shared_ptr < directory_query_response_t > query_result { } ;
2020-01-26 14:21:34 +01:00
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] ! = 0 ) { //Channel
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
2020-05-13 11:32:08 +02:00
if ( ! channel )
return command_result { error : : channel_invalid_id } ;
2020-01-26 14:21:34 +01:00
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_ft_ignore_password , channel - > channelId ( ) ) ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? command_result { permission : : b_ft_ignore_password } : command_result { error : : channel_invalid_password } ;
2020-05-13 11:32:08 +02:00
if ( ! channel - > permission_granted ( permission : : i_ft_needed_file_browse_power , this - > calculate_permission ( permission : : i_ft_file_browse_power , channel - > channelId ( ) ) , true ) )
return command_result { permission : : i_ft_file_browse_power } ;
query_result = file_system . query_channel_directory ( virtual_file_server , cmd [ " cid " ] . as < ChannelId > ( ) , cmd [ " path " ] . string ( ) ) ;
2020-01-26 14:21:34 +01:00
} else {
2020-05-13 11:32:08 +02:00
if ( directory_path = = " /icons " | | directory_path = = " /icons/ " ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_icon_manage , 0 ) ) )
return command_result { permission : : b_icon_manage } ;
query_result = file_system . query_icon_directory ( virtual_file_server ) ;
} else if ( directory_path = = " / " ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_icon_manage , 0 ) ) )
return command_result { permission : : b_icon_manage } ;
query_result = file_system . query_avatar_directory ( virtual_file_server ) ;
2020-01-26 14:21:34 +01:00
} else {
2020-05-13 11:32:08 +02:00
debugMessage ( this - > getServerId ( ) , " {} Requested file list for unknown path/name: path: {} name: {} " , cmd [ " path " ] . string ( ) , cmd [ " name " ] . string ( ) ) ;
return command_result { error : : parameter_invalid , " path " } ;
2020-01-26 14:21:34 +01:00
}
}
2020-05-13 11:32:08 +02:00
if ( ! query_result - > wait_for ( kFileAPITimeout ) )
return command_result { error : : file_api_timeout } ;
if ( ! query_result - > succeeded ( ) ) {
debugMessage ( this - > getServerId ( ) , " {} Failed to query directory: {} / {} " , CLIENT_STR_LOG_PREFIX , file : : filesystem : : directory_query_error_messages [ ( int ) query_result - > error ( ) . error_type ] , query_result - > error ( ) . error_message ) ;
using ErrorType = file : : filesystem : : DirectoryQueryErrorType ;
switch ( query_result - > error ( ) . error_type ) {
case ErrorType : : UNKNOWN :
case ErrorType : : FAILED_TO_LIST_FILES :
return command_result { error : : vs_critical , query_result - > error ( ) . error_message } ;
case ErrorType : : PATH_IS_A_FILE :
case ErrorType : : PATH_EXCEEDS_ROOT_PATH :
return command_result { error : : file_invalid_path } ;
case ErrorType : : PATH_DOES_NOT_EXISTS :
/* directory has not been created because there are no files */
if ( directory_path . empty ( ) | | directory_path = = " / " )
return command_result { error : : database_empty_result } ;
return command_result { error : : file_not_found } ;
default :
assert ( false ) ;
return command_result { error : : vs_critical } ;
}
}
const auto & files = query_result - > response ( ) ;
if ( files . empty ( ) )
2020-01-26 14:21:34 +01:00
return command_result { error : : database_empty_result } ;
2020-05-13 11:32:08 +02:00
auto return_code = cmd [ " return_code " ] . size ( ) > 0 ? cmd [ " return_code " ] . string ( ) : " " ;
{
ts : : command_builder notify_file_list { this - > notify_response_command ( " notifyfilelist " ) } ;
size_t bulk_index { 0 } ;
for ( const auto & file : files ) {
if ( bulk_index = = 0 ) {
notify_file_list . reset ( ) ;
notify_file_list . put_unchecked ( 0 , " path " , cmd [ " path " ] . string ( ) ) ;
notify_file_list . put_unchecked ( 0 , " cid " , cmd [ " cid " ] . string ( ) ) ;
if ( ! return_code . empty ( ) )
notify_file_list . put_unchecked ( 0 , " return_code " , return_code ) ;
}
auto bulk = notify_file_list . bulk ( bulk_index + + ) ;
switch ( file . type ) {
case DirectoryEntry : : DIRECTORY :
bulk . put_unchecked ( " type " , " 0 " ) ;
break ;
case DirectoryEntry : : FILE :
bulk . put_unchecked ( " type " , " 1 " ) ;
break ;
case DirectoryEntry : : UNKNOWN :
bulk . reset ( ) ;
bulk_index - - ;
continue ;
}
bulk . put_unchecked ( " name " , file . name ) ;
bulk . put_unchecked ( " size " , file . size ) ;
bulk . put_unchecked ( " datetime " , std : : chrono : : duration_cast < std : : chrono : : seconds > ( file . modified_at . time_since_epoch ( ) ) . count ( ) ) ;
if ( bulk_index > = 16 ) {
this - > sendCommand ( notify_file_list ) ;
bulk_index = 0 ;
}
}
if ( bulk_index > 0 )
this - > sendCommand ( notify_file_list ) ;
}
if ( this - > getExternalType ( ) ! = ClientType : : CLIENT_QUERY ) {
ts : : command_builder notify_file_list_finished { this - > notify_response_command ( " notifyfilelistfinished " ) } ;
notify_file_list_finished . put_unchecked ( 0 , " path " , cmd [ " path " ] . string ( ) ) ;
notify_file_list_finished . put_unchecked ( 0 , " cid " , cmd [ " cid " ] . string ( ) ) ;
if ( ! return_code . empty ( ) )
notify_file_list_finished . put_unchecked ( 0 , " return_code " , return_code ) ;
this - > sendCommand ( notify_file_list_finished ) ;
2020-01-26 14:21:34 +01:00
}
2020-05-13 11:32:08 +02:00
return command_result { error : : ok } ;
2020-01-26 14:21:34 +01:00
}
//ftcreatedir cid=4 cpw dirname=\/TestDir return_code=1:17
command_result ConnectedClient : : handleCommandFTCreateDir ( Command & cmd ) {
2020-05-13 11:32:08 +02:00
using ErrorType = file : : filesystem : : DirectoryModifyErrorType ;
2020-01-26 14:21:34 +01:00
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
2020-05-13 11:32:08 +02:00
auto virtual_file_server = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! virtual_file_server ) return command_result { error : : file_virtual_server_not_registered } ;
auto & file_system = file : : server ( ) - > file_system ( ) ;
2020-01-26 14:21:34 +01:00
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
2020-05-13 11:32:08 +02:00
if ( ! channel )
return command_result { error : : channel_invalid_id } ;
2020-01-26 14:21:34 +01:00
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_ft_ignore_password , channel - > channelId ( ) ) ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? command_result { permission : : b_ft_ignore_password } : command_result { error : : channel_invalid_password } ;
2020-05-13 11:32:08 +02:00
if ( ! channel - > permission_granted ( permission : : i_ft_needed_directory_create_power , this - > calculate_permission ( permission : : i_ft_directory_create_power , channel - > channelId ( ) ) , true ) )
return command_result { permission : : i_ft_directory_create_power } ;
auto create_result = file_system . create_channel_directory ( virtual_file_server , channel - > channelId ( ) , cmd [ " dirname " ] . string ( ) ) ;
if ( ! create_result - > wait_for ( kFileAPITimeout ) )
return command_result { error : : file_api_timeout } ;
if ( ! create_result - > succeeded ( ) ) {
debugMessage ( this - > getServerId ( ) , " {} Failed to create channel directory: {} / {} " , CLIENT_STR_LOG_PREFIX , ( int ) create_result - > error ( ) . error_type , create_result - > error ( ) . error_message ) ;
switch ( create_result - > error ( ) . error_type ) {
case ErrorType : : UNKNOWN :
case ErrorType : : FAILED_TO_CREATE_DIRECTORIES : {
auto error_detail = std : : to_string ( ( int ) create_result - > error ( ) . error_type ) ;
if ( ! create_result - > error ( ) . error_message . empty ( ) )
error_detail + = " / " + create_result - > error ( ) . error_message ;
return command_result { error : : file_io_error , error_detail } ;
}
case ErrorType : : PATH_ALREADY_EXISTS :
return command_result { error : : file_already_exists } ;
case ErrorType : : PATH_EXCEEDS_ROOT_PATH :
return command_result { error : : file_invalid_path } ;
}
}
2020-01-26 14:21:34 +01:00
return command_result { error : : ok } ;
}
command_result ConnectedClient : : handleCommandFTDeleteFile ( Command & cmd ) {
2020-05-13 11:32:08 +02:00
using ErrorType = file : : filesystem : : FileDeleteErrorType ;
2020-01-26 14:21:34 +01:00
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
2020-05-13 11:32:08 +02:00
auto virtual_file_server = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! virtual_file_server ) return command_result { error : : file_virtual_server_not_registered } ;
auto & file_system = file : : server ( ) - > file_system ( ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
ts : : command_result_bulk response { } ;
response . emplace_result_n ( cmd . bulkCount ( ) , error : : ok ) ;
auto file_path = cmd [ " path " ] . string ( ) ;
std : : shared_ptr < file : : ExecuteResponse < file : : filesystem : : FileDeleteError , file : : filesystem : : FileDeleteResponse > > delete_response { } ;
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] ! = 0 ) {
2020-01-26 14:21:34 +01:00
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
2020-05-13 11:32:08 +02:00
if ( ! channel )
return command_result { error : : channel_invalid_id } ;
2020-01-26 14:21:34 +01:00
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_ft_ignore_password , channel - > channelId ( ) ) ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? command_result { permission : : b_ft_ignore_password } : command_result { error : : channel_invalid_password } ;
2020-05-13 11:32:08 +02:00
if ( ! channel - > permission_granted ( permission : : i_ft_needed_file_delete_power , this - > calculate_permission ( permission : : i_ft_file_delete_power , channel - > channelId ( ) ) , true ) )
return command_result { permission : : i_ft_file_delete_power } ;
std : : vector < std : : string > delete_files { } ;
delete_files . reserve ( cmd . bulkCount ( ) ) ;
for ( size_t index { 0 } ; index < cmd . bulkCount ( ) ; index + + )
delete_files . push_back ( cmd [ index ] [ " name " ] . string ( ) ) ;
delete_response = file_system . delete_channel_files ( virtual_file_server , channel - > channelId ( ) , delete_files ) ;
2020-01-26 14:21:34 +01:00
} else {
2020-05-13 11:32:08 +02:00
auto first_entry_name = cmd [ " name " ] . string ( ) ;
if ( first_entry_name . find ( " /icon_ " ) = = 0 & & file_path . empty ( ) ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_icon_manage , 0 ) ) )
return command_result { permission : : b_icon_manage } ;
std : : vector < std : : string > delete_files { } ;
delete_files . reserve ( cmd . bulkCount ( ) ) ;
for ( size_t index { 0 } ; index < cmd . bulkCount ( ) ; index + + ) {
auto file_name = cmd [ index ] [ " name " ] . string ( ) ;
if ( ! file_name . starts_with ( " /icon_ " ) ) {
response . set_result ( index , ts : : command_result { error : : parameter_constraint_violation } ) ;
continue ;
2020-01-26 14:21:34 +01:00
}
2020-05-13 11:32:08 +02:00
delete_files . push_back ( file_name ) ;
2020-01-26 14:21:34 +01:00
}
2020-05-13 11:32:08 +02:00
delete_response = file_system . delete_icons ( virtual_file_server , delete_files ) ;
} else if ( first_entry_name . starts_with ( " /avatar_ " ) & & file_path . empty ( ) ) {
enum PermissionTestState {
SUCCEEDED ,
FAILED ,
UNSET
} permission_delete_other { PermissionTestState : : UNSET } ;
std : : vector < std : : string > delete_files { } ;
delete_files . reserve ( cmd . bulkCount ( ) ) ;
for ( size_t index { 0 } ; index < cmd . bulkCount ( ) ; index + + ) {
auto file_name = cmd [ index ] [ " name " ] . string ( ) ;
if ( ! file_name . starts_with ( " /avatar_ " ) ) {
response . set_result ( index , ts : : command_result { error : : parameter_constraint_violation } ) ;
continue ;
}
if ( file_name ! = " /avatar_ " ) {
if ( permission_delete_other = = PermissionTestState : : UNSET ) {
if ( permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_client_avatar_delete_other , 0 ) ) )
permission_delete_other = PermissionTestState : : SUCCEEDED ;
else
permission_delete_other = PermissionTestState : : FAILED ;
}
if ( permission_delete_other ! = PermissionTestState : : SUCCEEDED ) {
response . set_result ( index , ts : : command_result { permission : : b_client_avatar_delete_other } ) ;
continue ;
}
auto uid = file_name . substr ( strlen ( " /avatar_ " ) ) ;
auto avId = hex : : hex ( base64 : : decode ( uid ) , ' a ' , ' q ' ) ;
auto cls = this - > server - > findClientsByUid ( uid ) ;
for ( const auto & cl : cls ) {
cl - > properties ( ) [ property : : CLIENT_FLAG_AVATAR ] = " " ;
this - > server - > notifyClientPropertyUpdates ( cl , deque < property : : ClientProperties > { property : : CLIENT_FLAG_AVATAR } ) ;
}
delete_files . push_back ( " /avatar_ " + avId ) ;
} else {
this - > properties ( ) [ property : : CLIENT_FLAG_AVATAR ] = " " ;
this - > server - > notifyClientPropertyUpdates ( _this . lock ( ) , deque < property : : ClientProperties > { property : : CLIENT_FLAG_AVATAR } ) ;
}
}
delete_response = file_system . delete_avatars ( virtual_file_server , delete_files ) ;
2020-01-26 14:21:34 +01:00
} else {
logError ( this - > getServerId ( ) , " Unknown requested file to delete: {} " , cmd [ " path " ] . as < std : : string > ( ) ) ;
return command_result { error : : not_implemented } ;
}
}
2020-05-13 11:32:08 +02:00
if ( ! delete_response - > wait_for ( kFileAPITimeout ) )
return command_result { error : : file_api_timeout } ;
if ( ! delete_response - > succeeded ( ) ) {
debugMessage ( this - > getServerId ( ) , " {} Failed to create channel directory: {} / {} " , CLIENT_STR_LOG_PREFIX , ( int ) delete_response - > error ( ) . error_type , delete_response - > error ( ) . error_message ) ;
switch ( delete_response - > error ( ) . error_type ) {
case ErrorType : : UNKNOWN : {
auto error_detail = std : : to_string ( ( int ) delete_response - > error ( ) . error_type ) ;
if ( ! delete_response - > error ( ) . error_message . empty ( ) )
error_detail + = " / " + delete_response - > error ( ) . error_message ;
return command_result { error : : vs_critical , error_detail } ;
}
2020-01-26 14:21:34 +01:00
}
}
2020-05-13 11:32:08 +02:00
const auto & file_status = delete_response - > response ( ) ;
size_t bulk_index { 0 } ;
for ( const auto & file : file_status . delete_results ) {
while ( response . response ( bulk_index ) . error_code ( ) ! = error : : ok )
bulk_index + + ;
using Status = file : : filesystem : : FileDeleteResponse : : StatusType ;
switch ( file . status ) {
case Status : : SUCCESS :
/* we already emplaced success */
break ;
case Status : : PATH_EXCEEDS_ROOT_PATH :
response . set_result ( bulk_index , ts : : command_result { error : : file_invalid_path } ) ;
break ;
case Status : : PATH_DOES_NOT_EXISTS :
response . set_result ( bulk_index , ts : : command_result { error : : file_not_found } ) ;
break ;
case Status : : SOME_FILES_ARE_LOCKED :
response . set_result ( bulk_index , ts : : command_result { error : : file_already_in_use , file . error_detail } ) ;
break ;
case Status : : FAILED_TO_DELETE_FILES :
response . set_result ( bulk_index , ts : : command_result { error : : file_io_error , file . error_detail } ) ;
break ;
}
bulk_index + + ;
}
while ( response . length ( ) > bulk_index & & response . response ( bulk_index ) . type ( ) = = command_result_type : : error & & response . response ( bulk_index ) . error_code ( ) ! = error : : ok )
bulk_index + + ;
assert ( bulk_index = = cmd . bulkCount ( ) ) ;
return command_result { std : : move ( response ) } ;
2020-01-26 14:21:34 +01:00
}
2020-05-13 11:32:08 +02:00
/*
* Usage : ftgetfileinfo cid = { channelID } cpw = { channelPassword } name = { filePath } . . .
Permissions :
i_ft_file_browse_power
i_ft_needed_file_browse_power
Description :
Displays detailed information about one or more specified files stored in a
channels file repository .
Example :
ftgetfileinfo cid = 2 cpw = path = \ / Pic1 . PNG | cid = 2 cpw = path = \ / Pic2 . PNG
cid = 2 path = \ / name = Stuff size = 0 datetime = 1259415210 type = 0 | name = Pic1 . PNG size = 563783 datetime = 1259425462 type = 1 | name = Pic2 . PNG . . .
error id = 0 msg = ok
*/
command_result ConnectedClient : : handleCommandFTGetFileInfo ( ts : : Command & cmd ) {
using ErrorType = file : : filesystem : : FileInfoErrorType ;
using DirectoryEntry = file : : filesystem : : DirectoryEntry ;
CMD_RESET_IDLE ;
2020-01-26 14:21:34 +01:00
CMD_REQ_SERVER ;
2020-05-13 11:32:08 +02:00
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
auto virtual_file_server = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! virtual_file_server ) return command_result { error : : file_virtual_server_not_registered } ;
auto & file_system = file : : server ( ) - > file_system ( ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
ts : : command_result_bulk response { } ;
response . emplace_result_n ( cmd . bulkCount ( ) , error : : ok ) ;
auto file_path = cmd [ " path " ] . string ( ) ;
std : : shared_ptr < file : : ExecuteResponse < file : : filesystem : : FileInfoError , file : : filesystem : : FileInfoResponse > > info_response { } ;
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] ! = 0 ) {
2020-01-26 14:21:34 +01:00
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
2020-05-13 11:32:08 +02:00
if ( ! channel )
return command_result { error : : channel_invalid_id } ;
2020-01-26 14:21:34 +01:00
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_ft_ignore_password , channel - > channelId ( ) ) ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? command_result { permission : : b_ft_ignore_password } : command_result { error : : channel_invalid_password } ;
2020-05-13 11:32:08 +02:00
if ( ! channel - > permission_granted ( permission : : i_ft_needed_file_browse_power , this - > calculate_permission ( permission : : i_ft_file_browse_power , channel - > channelId ( ) ) , true ) )
return command_result { permission : : i_ft_file_browse_power } ;
std : : vector < std : : string > delete_files { } ;
delete_files . reserve ( cmd . bulkCount ( ) ) ;
for ( size_t index { 0 } ; index < cmd . bulkCount ( ) ; index + + )
delete_files . push_back ( cmd [ index ] [ " name " ] . string ( ) ) ;
info_response = file_system . query_channel_info ( virtual_file_server , channel - > channelId ( ) , delete_files ) ;
2020-01-26 14:21:34 +01:00
} else {
2020-05-13 11:32:08 +02:00
auto first_entry_name = cmd [ " name " ] . string ( ) ;
if ( first_entry_name . find ( " /icon_ " ) = = 0 & & file_path . empty ( ) ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_icon_manage , 0 ) ) )
return command_result { permission : : b_icon_manage } ;
std : : vector < std : : string > delete_files { } ;
delete_files . reserve ( cmd . bulkCount ( ) ) ;
for ( size_t index { 0 } ; index < cmd . bulkCount ( ) ; index + + ) {
auto file_name = cmd [ index ] [ " name " ] . string ( ) ;
if ( ! file_name . starts_with ( " /icon_ " ) ) {
response . set_result ( index , ts : : command_result { error : : parameter_constraint_violation } ) ;
continue ;
}
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
delete_files . push_back ( file_name ) ;
}
info_response = file_system . query_icon_info ( virtual_file_server , delete_files ) ;
} else if ( first_entry_name . starts_with ( " /avatar_ " ) & & file_path . empty ( ) ) {
if ( ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_icon_manage , 0 ) ) )
return command_result { permission : : b_icon_manage } ;
std : : vector < std : : string > delete_files { } ;
delete_files . reserve ( cmd . bulkCount ( ) ) ;
for ( size_t index { 0 } ; index < cmd . bulkCount ( ) ; index + + ) {
auto file_name = cmd [ index ] [ " name " ] . string ( ) ;
if ( ! file_name . starts_with ( " /avatar_ " ) ) {
response . set_result ( index , ts : : command_result { error : : parameter_constraint_violation } ) ;
continue ;
}
if ( file_name ! = " /avatar_ " ) {
auto uid = file_name . substr ( strlen ( " /avatar_ " ) ) ;
auto avId = hex : : hex ( base64 : : decode ( uid ) , ' a ' , ' q ' ) ;
delete_files . push_back ( " /avatar_ " + avId ) ;
} else {
this - > properties ( ) [ property : : CLIENT_FLAG_AVATAR ] = " " ;
this - > server - > notifyClientPropertyUpdates ( _this . lock ( ) , deque < property : : ClientProperties > { property : : CLIENT_FLAG_AVATAR } ) ;
}
}
info_response = file_system . query_avatar_info ( virtual_file_server , delete_files ) ;
2020-01-26 14:21:34 +01:00
} else {
2020-05-13 11:32:08 +02:00
logError ( this - > getServerId ( ) , " Unknown requested file to query info: {} " , cmd [ " path " ] . as < std : : string > ( ) ) ;
return command_result { error : : parameter_invalid } ;
2020-01-26 14:21:34 +01:00
}
}
2020-05-13 11:32:08 +02:00
if ( ! info_response - > wait_for ( kFileAPITimeout ) )
return command_result { error : : file_api_timeout } ;
if ( ! info_response - > succeeded ( ) ) {
debugMessage ( this - > getServerId ( ) , " {} Failed to execute file info query: {} / {} " , CLIENT_STR_LOG_PREFIX , ( int ) info_response - > error ( ) . error_type , info_response - > error ( ) . error_message ) ;
switch ( info_response - > error ( ) . error_type ) {
case ErrorType : : UNKNOWN : {
auto error_detail = std : : to_string ( ( int ) info_response - > error ( ) . error_type ) ;
if ( ! info_response - > error ( ) . error_message . empty ( ) )
error_detail + = " / " + info_response - > error ( ) . error_message ;
return command_result { error : : vs_critical , error_detail } ;
}
}
}
const auto & file_status = info_response - > response ( ) ;
size_t bulk_index { 0 } ;
ts : : command_builder notify_file_info { this - > notify_response_command ( " notifyfileinfo " ) } ;
size_t notify_index { 0 } ;
for ( const auto & file : file_status . file_info ) {
while ( response . response ( bulk_index ) . error_code ( ) ! = error : : ok )
bulk_index + + ;
using Status = file : : filesystem : : FileInfoResponse : : StatusType ;
switch ( file . status ) {
case Status : : SUCCESS :
/* we already emplaced success */
break ;
case Status : : PATH_EXCEEDS_ROOT_PATH :
response . set_result ( bulk_index , ts : : command_result { error : : file_invalid_path } ) ;
break ;
case Status : : PATH_DOES_NOT_EXISTS :
case Status : : UNKNOWN_FILE_TYPE :
response . set_result ( bulk_index , ts : : command_result { error : : file_not_found } ) ;
break ;
case Status : : FAILED_TO_QUERY_INFO :
response . set_result ( bulk_index , ts : : command_result { error : : file_io_error , file . error_detail } ) ;
break ;
}
bulk_index + + ;
auto bulk = notify_file_info . bulk ( notify_index + + ) ;
switch ( file . info . type ) {
case DirectoryEntry : : DIRECTORY :
bulk . put_unchecked ( " type " , " 0 " ) ;
break ;
case DirectoryEntry : : FILE :
bulk . put_unchecked ( " type " , " 1 " ) ;
break ;
case DirectoryEntry : : UNKNOWN :
bulk . reset ( ) ;
notify_index - - ;
continue ;
}
bulk . put_unchecked ( " name " , file . info . name ) ;
bulk . put_unchecked ( " size " , file . info . size ) ;
bulk . put_unchecked ( " datetime " , std : : chrono : : duration_cast < std : : chrono : : seconds > ( file . info . modified_at . time_since_epoch ( ) ) . count ( ) ) ;
2020-01-26 14:21:34 +01:00
}
2020-05-13 11:32:08 +02:00
if ( notify_index > 0 )
this - > sendCommand ( notify_file_info ) ;
while ( response . length ( ) > bulk_index & & response . response ( bulk_index ) . type ( ) = = command_result_type : : error & & response . response ( bulk_index ) . error_code ( ) ! = error : : ok )
bulk_index + + ;
assert ( bulk_index = = cmd . bulkCount ( ) ) ;
return command_result { std : : move ( response ) } ;
}
/*
ftinitupload clientftfid = { clientFileTransferID } name = { filePath }
cid = { channelID } cpw = { channelPassword } size = { fileSize } overwrite = { 1 | 0 }
resume = { 1 | 0 } [ proto = 0 - 1 ]
*/
command_result ConnectedClient : : handleCommandFTInitUpload ( ts : : Command & cmd ) {
CMD_REQ_SERVER ;
auto virtual_file_server = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! virtual_file_server ) return command_result { error : : file_virtual_server_not_registered } ;
if ( ! cmd [ 0 ] . has ( " path " ) ) cmd [ " path " ] = " " ;
file : : transfer : : AbstractProvider : : TransferInfo info { } ;
std : : shared_ptr < file : : ExecuteResponse < file : : transfer : : TransferInitError , std : : shared_ptr < file : : transfer : : Transfer > > > transfer_response { } ;
info . max_bandwidth = - 1 ;
2020-05-14 15:08:28 +02:00
{
auto max_quota = this - > calculate_permission ( permission : : i_ft_max_bandwidth_upload , this - > getClientId ( ) ) ;
if ( max_quota . has_value )
info . max_bandwidth = max_quota . value ;
}
2020-05-13 11:32:08 +02:00
info . file_offset = 0 ;
info . expected_file_size = cmd [ " size " ] . as < size_t > ( ) ;
info . override_exiting = cmd [ " overwrite " ] . as < bool > ( ) ;
info . file_path = cmd [ " name " ] . string ( ) ;
info . client_unique_id = this - > getUid ( ) ;
info . client_id = this - > getClientId ( ) ;
info . max_concurrent_transfers = kMaxClientTransfers ;
/* TODO: Save last file offset and resume */
if ( cmd [ " resume " ] . as < bool > ( ) & & info . override_exiting )
return ts : : command_result { error : : file_overwrite_excludes_resume } ;
2020-01-26 14:21:34 +01:00
{
auto server_quota = this - > server - > properties ( ) [ property : : VIRTUALSERVER_UPLOAD_QUOTA ] . as < ssize_t > ( ) ;
auto server_used_quota = this - > server - > properties ( ) [ property : : VIRTUALSERVER_MONTH_BYTES_UPLOADED ] . as < size_t > ( ) ;
server_used_quota + = cmd [ " size " ] . as < uint64_t > ( ) ;
if ( server_quota > = 0 & & server_quota * 1024 * 1024 < ( int64_t ) server_used_quota ) return command_result { error : : file_transfer_server_quota_exceeded } ;
auto client_quota = this - > calculate_permission ( permission : : i_ft_quota_mb_upload_per_client , 0 ) ;
auto client_used_quota = this - > properties ( ) [ property : : CLIENT_MONTH_BYTES_UPLOADED ] . as < size_t > ( ) ;
client_used_quota + = cmd [ " size " ] . as < uint64_t > ( ) ;
if ( client_quota . has_value & & ! client_quota . has_infinite_power ( ) & & ( client_quota . value < 0 | | client_quota . value * 1024 * 1024 < ( int64_t ) client_used_quota ) )
return command_result { error : : file_transfer_client_quota_exceeded } ;
}
2020-05-13 11:32:08 +02:00
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] ! = 0 ) { //Channel
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
if ( ! channel )
return command_result { error : : channel_invalid_id , " Cant resolve channel " } ;
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_ft_ignore_password , channel - > channelId ( ) ) ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? command_result { permission : : b_ft_ignore_password } : command_result { error : : channel_invalid_password } ;
ACTION_REQUIRES_CHANNEL_PERMISSION ( channel , permission : : i_ft_needed_file_upload_power , permission : : i_ft_file_upload_power , true ) ;
transfer_response = file : : server ( ) - > file_transfer ( ) . initialize_channel_transfer ( file : : transfer : : Transfer : : DIRECTION_UPLOAD , virtual_file_server , channel - > channelId ( ) , info ) ;
} else {
if ( cmd [ " path " ] . string ( ) . empty ( ) & & cmd [ " name " ] . string ( ) . starts_with ( " /icon_ " ) = = 0 ) {
auto max_size = this - > calculate_permission ( permission : : i_max_icon_filesize , 0 ) ;
if ( max_size . has_value & & ! max_size . has_infinite_power ( ) & & ( max_size . value < 0 | | max_size . value < cmd [ " size " ] . as < size_t > ( ) ) )
return command_result { permission : : i_max_icon_filesize } ;
transfer_response = file : : server ( ) - > file_transfer ( ) . initialize_icon_transfer ( file : : transfer : : Transfer : : DIRECTION_UPLOAD , virtual_file_server , info ) ;
} else if ( cmd [ " path " ] . as < std : : string > ( ) . empty ( ) & & cmd [ " name " ] . string ( ) = = " /avatar " ) {
auto max_size = this - > calculate_permission ( permission : : i_client_max_avatar_filesize , 0 ) ;
if ( max_size . has_value & & ! max_size . has_infinite_power ( ) & & ( max_size . value < 0 | | max_size . value < cmd [ " size " ] . as < size_t > ( ) ) )
return command_result { permission : : i_client_max_avatar_filesize } ;
info . file_path = " /avatar_ " + this - > getAvatarId ( ) ;
transfer_response = file : : server ( ) - > file_transfer ( ) . initialize_avatar_transfer ( file : : transfer : : Transfer : : DIRECTION_UPLOAD , virtual_file_server , info ) ;
} else {
return command_result { error : : parameter_invalid , " name " } ;
}
}
if ( ! transfer_response - > wait_for ( kFileAPITimeout ) )
return command_result { error : : file_api_timeout } ;
if ( ! transfer_response - > succeeded ( ) ) {
using ErrorType = file : : transfer : : TransferInitError ;
debugMessage ( this - > getServerId ( ) , " {} Failed to initialize file upload: {} / {} " , CLIENT_STR_LOG_PREFIX , ( int ) transfer_response - > error ( ) . error_type , transfer_response - > error ( ) . error_message ) ;
switch ( transfer_response - > error ( ) . error_type ) {
case ErrorType : : UNKNOWN : {
auto error_detail = std : : to_string ( ( int ) transfer_response - > error ( ) . error_type ) ;
if ( ! transfer_response - > error ( ) . error_message . empty ( ) )
error_detail + = " / " + transfer_response - > error ( ) . error_message ;
return command_result { error : : vs_critical , error_detail } ;
2020-01-26 14:21:34 +01:00
}
2020-05-13 11:32:08 +02:00
case ErrorType : : IO_ERROR :
return command_result { error : : file_io_error , transfer_response - > error ( ) . error_message } ;
case ErrorType : : FILE_IS_NOT_A_FILE :
case ErrorType : : INVALID_FILE_TYPE :
case ErrorType : : FILE_DOES_NOT_EXISTS :
return command_result { error : : file_not_found } ;
case ErrorType : : SERVER_QUOTA_EXCEEDED :
return command_result { error : : file_transfer_server_quota_exceeded } ;
case ErrorType : : CLIENT_QUOTA_EXCEEDED :
return command_result { error : : file_transfer_client_quota_exceeded } ;
case ErrorType : : SERVER_TOO_MANY_TRANSFERS :
return command_result { error : : file_server_transfer_limit_reached } ;
case ErrorType : : CLIENT_TOO_MANY_TRANSFERS :
return command_result { error : : file_client_transfer_limit_reached } ;
2020-01-26 14:21:34 +01:00
}
}
2020-05-13 11:32:08 +02:00
auto transfer = transfer_response - > response ( ) ;
if ( transfer - > server_addresses . empty ( ) ) {
logError ( 0 , " {} Received transfer without any addresses! " , CLIENT_STR_LOG_PREFIX ) ;
return ts : : command_result { error : : vs_critical } ;
}
transfer - > client_transfer_id = cmd [ " clientftfid " ] ;
ts : : command_builder result { this - > notify_response_command ( " notifystartupload " ) } ;
result . put_unchecked ( 0 , " clientftfid " , cmd [ " clientftfid " ] . string ( ) ) ;
result . put_unchecked ( 0 , " serverftfid " , transfer - > server_transfer_id ) ;
auto used_address = transfer - > server_addresses [ 0 ] ;
result . put_unchecked ( 0 , " ip " , used_address . hostname ) ;
result . put_unchecked ( 0 , " port " , used_address . port ) ;
result . put_unchecked ( 0 , " ftkey " , std : : string_view { transfer - > transfer_key , TRANSFER_KEY_LENGTH } ) ;
result . put_unchecked ( 0 , " seekpos " , transfer - > file_offset ) ;
result . put_unchecked ( 0 , " proto " , " 1 " ) ;
2020-01-26 14:21:34 +01:00
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
2020-05-13 11:32:08 +02:00
/*
ftinitdownload clientftfid = { clientFileTransferID } name = { filePath }
cid = { channelID } cpw = { channelPassword } seekpos = { seekPosition } [ proto = 0 - 1 ]
*/
command_result ConnectedClient : : handleCommandFTInitDownload ( ts : : Command & cmd ) {
2020-01-26 14:21:34 +01:00
CMD_REQ_SERVER ;
2020-05-13 11:32:08 +02:00
auto virtual_file_server = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! virtual_file_server ) return command_result { error : : file_virtual_server_not_registered } ;
2020-01-26 14:21:34 +01:00
if ( ! cmd [ 0 ] . has ( " path " ) ) cmd [ " path " ] = " " ;
2020-05-13 11:32:08 +02:00
file : : transfer : : AbstractProvider : : TransferInfo info { } ;
std : : shared_ptr < file : : ExecuteResponse < file : : transfer : : TransferInitError , std : : shared_ptr < file : : transfer : : Transfer > > > transfer_response { } ;
{
auto server_quota = this - > server - > properties ( ) [ property : : VIRTUALSERVER_DOWNLOAD_QUOTA ] . as < ssize_t > ( ) ;
auto server_used_quota = this - > server - > properties ( ) [ property : : VIRTUALSERVER_MONTH_BYTES_DOWNLOADED ] . as < size_t > ( ) ;
if ( server_quota > = 0 ) {
if ( ( size_t ) server_quota * 1024 * 1024 < = server_used_quota )
return command_result { error : : file_transfer_server_quota_exceeded } ;
info . download_server_quota_limit = server_quota * 1024 * 1024 - server_used_quota ;
}
auto client_quota = this - > calculate_permission ( permission : : i_ft_quota_mb_download_per_client , 0 ) ;
auto client_used_quota = this - > properties ( ) [ property : : CLIENT_MONTH_BYTES_DOWNLOADED ] . as < size_t > ( ) ;
if ( client_quota . has_value ) {
if ( client_quota . value > 0 ) {
if ( ( size_t ) client_quota . value * 1024 * 1024 < = client_used_quota )
return command_result { error : : file_transfer_server_quota_exceeded } ;
info . download_client_quota_limit = client_quota . value * 1024 * 1024 - client_used_quota ;
} else if ( client_quota . value ! = - 1 ) {
return command_result { error : : file_transfer_client_quota_exceeded } ;
}
}
}
info . max_bandwidth = - 1 ;
2020-05-14 15:08:28 +02:00
{
auto max_quota = this - > calculate_permission ( permission : : i_ft_max_bandwidth_download , this - > getClientId ( ) ) ;
if ( max_quota . has_value )
info . max_bandwidth = max_quota . value ;
}
2020-05-13 11:32:08 +02:00
info . file_offset = cmd [ " seekpos " ] . as < size_t > ( ) ;
info . override_exiting = false ;
info . file_path = cmd [ " name " ] . string ( ) ;
info . client_unique_id = this - > getUid ( ) ;
info . client_id = this - > getClientId ( ) ;
info . max_concurrent_transfers = kMaxClientTransfers ;
if ( cmd [ 0 ] . has ( " cid " ) & & cmd [ " cid " ] ! = 0 ) { //Channel
2020-01-26 14:21:34 +01:00
auto channel = this - > server - > channelTree - > findChannel ( cmd [ " cid " ] . as < ChannelId > ( ) ) ;
2020-05-13 11:32:08 +02:00
if ( ! channel )
return command_result { error : : channel_invalid_id } ;
2020-01-26 14:21:34 +01:00
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_ft_ignore_password , channel - > channelId ( ) ) ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? command_result { permission : : b_ft_ignore_password } : command_result { error : : channel_invalid_password } ;
2020-05-13 11:32:08 +02:00
ACTION_REQUIRES_CHANNEL_PERMISSION ( channel , permission : : i_ft_needed_file_download_power , permission : : i_ft_file_download_power , true ) ;
transfer_response = file : : server ( ) - > file_transfer ( ) . initialize_channel_transfer ( file : : transfer : : Transfer : : DIRECTION_DOWNLOAD , virtual_file_server , channel - > channelId ( ) , info ) ;
2020-01-26 14:21:34 +01:00
} else {
2020-05-13 11:32:08 +02:00
if ( cmd [ " path " ] . as < std : : string > ( ) . empty ( ) & & cmd [ " name " ] . string ( ) . find ( " /icon_ " ) = = 0 ) {
transfer_response = file : : server ( ) - > file_transfer ( ) . initialize_icon_transfer ( file : : transfer : : Transfer : : DIRECTION_DOWNLOAD , virtual_file_server , info ) ;
} else if ( cmd [ " path " ] . as < std : : string > ( ) . empty ( ) & & cmd [ " name " ] . string ( ) = = " /avatar " ) {
info . file_path = " /avatar_ " + this - > getAvatarId ( ) ;
transfer_response = file : : server ( ) - > file_transfer ( ) . initialize_avatar_transfer ( file : : transfer : : Transfer : : DIRECTION_DOWNLOAD , virtual_file_server , info ) ;
2020-01-26 14:21:34 +01:00
} else {
2020-05-13 11:32:08 +02:00
return command_result { error : : parameter_invalid , " name " } ;
2020-01-26 14:21:34 +01:00
}
}
2020-05-13 11:32:08 +02:00
if ( ! transfer_response - > wait_for ( kFileAPITimeout ) )
return command_result { error : : file_api_timeout } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
if ( ! transfer_response - > succeeded ( ) ) {
using ErrorType = file : : transfer : : TransferInitError ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
debugMessage ( this - > getServerId ( ) , " {} Failed to initialize file download: {} / {} " , CLIENT_STR_LOG_PREFIX , ( int ) transfer_response - > error ( ) . error_type , transfer_response - > error ( ) . error_message ) ;
switch ( transfer_response - > error ( ) . error_type ) {
case ErrorType : : UNKNOWN : {
auto error_detail = std : : to_string ( ( int ) transfer_response - > error ( ) . error_type ) ;
if ( ! transfer_response - > error ( ) . error_message . empty ( ) )
error_detail + = " / " + transfer_response - > error ( ) . error_message ;
return command_result { error : : vs_critical , error_detail } ;
}
case ErrorType : : IO_ERROR :
return command_result { error : : file_io_error , transfer_response - > error ( ) . error_message } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
case ErrorType : : FILE_IS_NOT_A_FILE :
case ErrorType : : INVALID_FILE_TYPE :
case ErrorType : : FILE_DOES_NOT_EXISTS :
return command_result { error : : file_not_found } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
case ErrorType : : SERVER_QUOTA_EXCEEDED :
return command_result { error : : file_transfer_server_quota_exceeded } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
case ErrorType : : CLIENT_QUOTA_EXCEEDED :
return command_result { error : : file_transfer_client_quota_exceeded } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
case ErrorType : : SERVER_TOO_MANY_TRANSFERS :
return command_result { error : : file_server_transfer_limit_reached } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
case ErrorType : : CLIENT_TOO_MANY_TRANSFERS :
return command_result { error : : file_client_transfer_limit_reached } ;
2020-01-26 14:21:34 +01:00
}
}
2020-05-13 11:32:08 +02:00
auto transfer = transfer_response - > response ( ) ;
if ( transfer - > server_addresses . empty ( ) ) {
logError ( 0 , " {} Received transfer without any addresses! " , CLIENT_STR_LOG_PREFIX ) ;
return ts : : command_result { error : : vs_critical } ;
}
transfer - > client_transfer_id = cmd [ " clientftfid " ] ;
ts : : command_builder result { this - > notify_response_command ( " notifystartdownload " ) } ;
result . put_unchecked ( 0 , " clientftfid " , cmd [ " clientftfid " ] . string ( ) ) ;
result . put_unchecked ( 0 , " serverftfid " , transfer - > server_transfer_id ) ;
auto used_address = transfer - > server_addresses [ 0 ] ;
result . put_unchecked ( 0 , " ip " , used_address . hostname ) ;
result . put_unchecked ( 0 , " port " , used_address . port ) ;
result . put_unchecked ( 0 , " ftkey " , std : : string_view { transfer - > transfer_key , TRANSFER_KEY_LENGTH } ) ;
result . put_unchecked ( 0 , " proto " , " 1 " ) ;
result . put_unchecked ( 0 , " size " , transfer - > expected_file_size ) ;
result . put_unchecked ( 0 , " seekpos " , transfer - > file_offset ) ;
2020-01-26 14:21:34 +01:00
this - > sendCommand ( result ) ;
return command_result { error : : ok } ;
}
/*
2020-05-13 11:32:08 +02:00
* Usage : ftrenamefile cid = { channelID } cpw = { channelPassword }
[ tcid = { targetChannelID } ] [ tcpw = { targetChannelPassword } ]
oldname = { oldFilePath } newname = { newFilePath }
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
i_ft_file_rename_power
i_ft_needed_file_rename_power
*/
command_result ConnectedClient : : handleCommandFTRenameFile ( ts : : Command & cmd ) {
CMD_RESET_IDLE ;
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 5 ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
auto virtual_file_server = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! virtual_file_server ) return command_result { error : : file_virtual_server_not_registered } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
auto channel_id = cmd [ " cid " ] . as < ChannelId > ( ) ;
auto target_channel_id = cmd [ 0 ] . has ( " tcid " ) ? cmd [ " tcid " ] . as < ChannelId > ( ) : channel_id ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
auto channel = this - > server - > channelTree - > findChannel ( channel_id ) ;
if ( ! channel )
return command_result { error : : channel_invalid_id } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
if ( ! channel - > passwordMatch ( cmd [ " cpw " ] ) & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_ft_ignore_password , channel - > channelId ( ) ) ) )
return cmd [ " cpw " ] . string ( ) . empty ( ) ? command_result { permission : : b_ft_ignore_password } : command_result { error : : channel_invalid_password } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
ACTION_REQUIRES_CHANNEL_PERMISSION ( channel , permission : : i_ft_needed_file_rename_power , permission : : i_ft_file_rename_power , true ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
if ( target_channel_id ! = channel_id ) {
auto targetChannel = this - > server - > channelTree - > findChannel ( target_channel_id ) ;
if ( ! targetChannel )
return command_result { error : : channel_invalid_id } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
if ( ! channel - > passwordMatch ( cmd [ " tcpw " ] ) & & ! permission : : v2 : : permission_granted ( 1 , this - > calculate_permission ( permission : : b_ft_ignore_password , channel - > channelId ( ) ) ) )
return cmd [ " tcpw " ] . string ( ) . empty ( ) ? command_result { permission : : b_ft_ignore_password } : command_result { error : : channel_invalid_password } ;
ACTION_REQUIRES_CHANNEL_PERMISSION ( targetChannel , permission : : i_ft_needed_file_rename_power , permission : : i_ft_file_rename_power , true ) ;
}
auto rename_response = file : : server ( ) - > file_system ( ) . rename_channel_file ( virtual_file_server , channel_id , cmd [ " oldname " ] . string ( ) , target_channel_id , cmd [ " newname " ] . string ( ) ) ;
if ( ! rename_response - > wait_for ( kFileAPITimeout ) )
return command_result { error : : file_api_timeout } ;
if ( ! rename_response - > succeeded ( ) ) {
using ErrorType = file : : filesystem : : FileModifyErrorType ;
debugMessage ( this - > getServerId ( ) , " {} Failed to rename file: {} / {} " , CLIENT_STR_LOG_PREFIX , ( int ) rename_response - > error ( ) . error_type , rename_response - > error ( ) . error_message ) ;
switch ( rename_response - > error ( ) . error_type ) {
case ErrorType : : UNKNOWN :
case ErrorType : : FAILED_TO_RENAME_FILE :
case ErrorType : : FAILED_TO_DELETE_FILES :
case ErrorType : : FAILED_TO_CREATE_DIRECTORIES : {
auto error_detail = std : : to_string ( ( int ) rename_response - > error ( ) . error_type ) ;
if ( ! rename_response - > error ( ) . error_message . empty ( ) )
error_detail + = " / " + rename_response - > error ( ) . error_message ;
return command_result { error : : vs_critical , error_detail } ;
2020-01-26 14:21:34 +01:00
}
2020-05-13 11:32:08 +02:00
case ErrorType : : PATH_EXCEEDS_ROOT_PATH :
case ErrorType : : TARGET_PATH_EXCEEDS_ROOT_PATH :
case ErrorType : : PATH_DOES_NOT_EXISTS :
return command_result { error : : file_invalid_path } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
case ErrorType : : TARGET_PATH_ALREADY_EXISTS :
return command_result { error : : file_already_exists } ;
case ErrorType : : SOME_FILES_ARE_LOCKED :
return command_result { error : : file_already_in_use , rename_response - > error ( ) . error_message } ;
2020-01-26 14:21:34 +01:00
}
}
return command_result { error : : ok } ;
}
2020-05-13 11:32:08 +02:00
//clid=2 path=files\/virtualserver_1\/channel_5 name=image.iso
// size=673460224 sizedone=450756 clientftfid=2
// serverftfid=6 sender=0 status=1 current_speed=60872.8 average_speed runtime
command_result ConnectedClient : : handleCommandFTList ( ts : : Command & cmd ) {
CMD_RESET_IDLE ;
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
ACTION_REQUIRES_PERMISSION ( permission : : b_ft_transfer_list , 1 , 0 ) ;
auto virtual_file_server = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! virtual_file_server ) return command_result { error : : file_virtual_server_not_registered } ;
auto list_response = file : : server ( ) - > file_transfer ( ) . list_transfer ( ) ; //FIXME: Only for the appropriate servers!
if ( ! list_response - > wait_for ( kFileAPITimeout ) )
return command_result { error : : file_api_timeout } ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
if ( ! list_response - > succeeded ( ) ) {
using ErrorType = file : : transfer : : TransferListError ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
debugMessage ( this - > getServerId ( ) , " {} Failed to list current transfers: {} " , CLIENT_STR_LOG_PREFIX , ( int ) list_response - > error ( ) ) ;
switch ( list_response - > error ( ) ) {
case ErrorType : : UNKNOWN : {
auto error_detail = std : : to_string ( ( int ) list_response - > error ( ) ) ;
return command_result { error : : vs_critical , error_detail } ;
}
}
}
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
const auto & transfers = list_response - > response ( ) ;
if ( transfers . empty ( ) )
return command_result { error : : database_empty_result } ;
ts : : command_builder notify { this - > notify_response_command ( " notifyftlist " ) } ;
size_t bulk_index { 0 } ;
for ( const auto & transfer : transfers ) {
auto bulk = notify . bulk ( bulk_index + + ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
bulk . put_unchecked ( " clientftfid " , transfer . client_transfer_id ) ;
bulk . put_unchecked ( " serverftfid " , transfer . server_transfer_id ) ;
bulk . put_unchecked ( " sender " , transfer . direction = = file : : transfer : : Transfer : : DIRECTION_DOWNLOAD ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
bulk . put_unchecked ( " clid " , transfer . client_id ) ;
bulk . put_unchecked ( " cluid " , transfer . client_unique_id ) ;
bulk . put_unchecked ( " path " , transfer . file_path ) ;
bulk . put_unchecked ( " name " , transfer . file_name ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
bulk . put_unchecked ( " size " , transfer . expected_size ) ;
bulk . put_unchecked ( " sizedone " , transfer . size_done ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
bulk . put_unchecked ( " status " , ( int ) transfer . status ) ;
2020-01-26 14:21:34 +01:00
2020-05-13 11:32:08 +02:00
bulk . put_unchecked ( " runtime " , transfer . runtime . count ( ) ) ;
bulk . put_unchecked ( " current_speed " , transfer . current_speed ) ;
bulk . put_unchecked ( " average_speed " , transfer . average_speed ) ;
}
this - > sendCommand ( notify ) ;
return command_result { error : : ok } ;
}
//ftstop serverftfid='2' clientftfid='4096' delete='0'
command_result ConnectedClient : : handleCommandFTStop ( ts : : Command & cmd ) {
CMD_RESET_IDLE ;
CMD_REQ_SERVER ;
CMD_CHK_AND_INC_FLOOD_POINTS ( 25 ) ;
auto virtual_file_server = file : : server ( ) - > find_virtual_server ( this - > getServerId ( ) ) ;
if ( ! virtual_file_server ) return command_result { error : : file_virtual_server_not_registered } ;
auto stop_response = file : : server ( ) - > file_transfer ( ) . stop_transfer ( virtual_file_server , cmd [ " serverftfid " ] , false ) ;
if ( ! stop_response - > wait_for ( kFileAPITimeout ) )
return command_result { error : : file_api_timeout } ;
if ( ! stop_response - > succeeded ( ) ) {
using ErrorType = file : : transfer : : TransferActionError : : Type ;
switch ( stop_response - > error ( ) . error_type ) {
case ErrorType : : UNKNOWN_TRANSFER :
/* not known, so not stopped but it has the same result as it would have been stopped */
return command_result { error : : ok } ;
case ErrorType : : UNKNOWN : {
auto error_detail = std : : to_string ( ( int ) stop_response - > error ( ) . error_type ) ;
if ( ! stop_response - > error ( ) . error_message . empty ( ) )
error_detail + = " / " + stop_response - > error ( ) . error_message ;
return command_result { error : : vs_critical , error_detail } ;
}
}
}
return command_result { error : : ok } ;
}
2020-01-26 14:21:34 +01:00