diff --git a/server/src/client/ConnectedClientCommandHandler.cpp b/server/src/client/ConnectedClientCommandHandler.cpp index 9b97827..5dc4bcd 100644 --- a/server/src/client/ConnectedClientCommandHandler.cpp +++ b/server/src/client/ConnectedClientCommandHandler.cpp @@ -949,46 +949,98 @@ CommandResult ConnectedClient::handleCommandChannelGroupAdd(Command &cmd) { //name=Channel\sAdmin scgid=5 tcgid=4 type=1 CommandResult ConnectedClient::handleCommandChannelGroupCopy(Command &cmd) { - CMD_RESET_IDLE; - CMD_CHK_AND_INC_FLOOD_POINTS(5); + CMD_RESET_IDLE; + CMD_CHK_AND_INC_FLOOD_POINTS(5); + + auto ref_server = this->server; CACHED_PERM_CHECK(permission::b_virtualserver_channelgroup_create, 1, true); - auto group_manager = this->server ? this->server->getGroupManager() : serverInstance->getGroupManager().get(); - auto src = group_manager->findGroup(cmd["scgid"].as()); - if (!src || src->target() != GROUPTARGET_CHANNEL) return {findError("parameter_invalid"), "invalid channel group id"}; + auto group_manager = this->server ? this->server->groups : serverInstance->getGroupManager().get(); - bool global = false; - if(cmd[0].has("tcgid")&& cmd["tcgid"].as() != 0) { - auto target = group_manager->findGroup(cmd["tcgid"].as()); - if (!target || target->target() != GROUPTARGET_CHANNEL) return {findError("parameter_invalid"), "invalid target channel group id"}; - auto result = group_manager->copyGroupPermissions(src, target); - if(!result) return {findError("vs_critical"), "could not copy group!"}; - global = !this->server || group_manager->isLocalGroup(target); - } else { - auto type = cmd["type"].as(); - if(type == GroupType::GROUP_TYPE_QUERY) - CACHED_PERM_CHECK(permission::b_serverinstance_modify_querygroup, 1, true); - if(type == GroupType::GROUP_TYPE_TEMPLATE) - CACHED_PERM_CHECK(permission::b_serverinstance_modify_templates, 1, true); + auto source_group_id = cmd["scgid"].as(); + auto source_group = group_manager->findGroup(source_group_id); - if(type == GroupType::GROUP_TYPE_NORMAL && !this->server) return {findError("parameter_invalid"), "You cant create normal channel groups on the template server"}; - auto result = group_manager->copyGroup(src, cmd["type"], cmd["name"], type == GROUP_TYPE_NORMAL ? this->getServerId() : 0); //TODO maybe check by name? No duplicated groups? - if (!result) return {findError("vs_critical"), "could not copy group!"}; - global = !this->server || type != GroupType::GROUP_TYPE_NORMAL; + if(!source_group || source_group->target() != GROUPTARGET_CHANNEL) + return {findError("group_invalid_id"), "invalid source group"}; - if(this->getType() == ClientType::CLIENT_QUERY) { - Command notify(""); - notify["cgid"] = group_manager->availableChannelGroups(false).back()->groupId(); - this->sendCommand(notify); - } - } + const auto group_type_modificable = [&](GroupType type) { + switch(type) { + case GroupType::GROUP_TYPE_TEMPLATE: + if(!this->permission_granted(this->permissionValue(permission::b_serverinstance_modify_templates, 0), 1, true)) + return permission::b_serverinstance_modify_templates; + break; + case GroupType::GROUP_TYPE_QUERY: + if(!this->permission_granted(this->permissionValue(permission::b_serverinstance_modify_querygroup, 0), 1, true)) + return permission::b_serverinstance_modify_querygroup; + break; - for(const auto& server : (global ? serverInstance->getVoiceServerManager()->serverInstances() : deque>{this->server})) - if(server) - server->forEachClient([](shared_ptr cl) { - cl->notifyChannelGroupList(); - }); - return CommandResult::Success; + default: + break; + } + return permission::undefined; + }; + + { + auto result = group_type_modificable(source_group->type()); + if(result != permission::undefined) + return CommandResultPermissionError{result}; + } + + auto global_update = false; + if(cmd[0].has("tcgid") && cmd["tcgid"].as() != 0) { + //Copy an existing group + auto target_group = group_manager->findGroup(cmd["tcgid"]); + if(!target_group || target_group->target() != GROUPTARGET_CHANNEL) + return {findError("group_invalid_id"), "invalid target group"}; + + { + auto result = group_type_modificable(target_group->type()); + if(result != permission::undefined) + return CommandResultPermissionError{result}; + } + + if(!target_group->permission_granted(permission::i_channel_group_needed_modify_power, this->calculate_permission_value(permission::i_channel_group_modify_power, 0), true)) + return CommandResultPermissionError{permission::i_channel_group_modify_power}; + + if(!group_manager->copyGroupPermissions(source_group, target_group)) + return {findError("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(); + + { + auto result = group_type_modificable(target_type); + if(result != permission::undefined) + return CommandResultPermissionError{result}; + } + + if(!ref_server && target_type == GroupType::GROUP_TYPE_NORMAL) + return {findError("parameter_invalid"), "You cant create normal groups on the template server!"}; + + if(!group_manager->findGroup(GroupTarget::GROUPTARGET_CHANNEL, cmd["name"].string()).empty()) + return {findError("group_name_used"), "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 {findError("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)); + } + + for(const auto& server : (global_update ? serverInstance->getVoiceServerManager()->serverInstances() : deque>{this->server})) + if(server) + server->forEachClient([](shared_ptr cl) { + cl->notifyChannelGroupList(); + }); + return CommandResult::Success; } CommandResult ConnectedClient::handleCommandChannelGroupRename(Command &cmd) { @@ -2514,7 +2566,6 @@ CommandResult ConnectedClient::handleCommandServerGroupAdd(Command &cmd) { return CommandResult::Success; } -//name=Server\sAdmin\s(Copy) ssgid=1 tsgid=0 type=1 CommandResult ConnectedClient::handleCommandServerGroupCopy(Command &cmd) { CMD_RESET_IDLE; CMD_CHK_AND_INC_FLOOD_POINTS(5);