diff --git a/src/PermissionRegister.cpp b/src/PermissionRegister.cpp index ccaa6f2..fdc8a26 100644 --- a/src/PermissionRegister.cpp +++ b/src/PermissionRegister.cpp @@ -1,1520 +1,1520 @@ -#include -#include -#include "misc/memtracker.h" -#include "BasicChannel.h" -#include "log/LogUtils.h" - -using namespace std; -using namespace ts; -using namespace ts::permission; - -deque> ts::permission::availablePermissions = deque>{ - make_shared(PermissionType::b_serverinstance_help_view, PermissionGroup::global_info, "b_serverinstance_help_view", "Retrieve information about ServerQuery commands"), - make_shared(PermissionType::b_serverinstance_version_view, PermissionGroup::global_info, "b_serverinstance_version_view", "Retrieve global server version (including platform and build number)"), - make_shared(PermissionType::b_serverinstance_info_view, PermissionGroup::global_info, "b_serverinstance_info_view", "Retrieve global server information"), - make_shared(PermissionType::b_serverinstance_virtualserver_list, PermissionGroup::global_info, "b_serverinstance_virtualserver_list", "List virtual servers stored in the sql"), - make_shared(PermissionType::b_serverinstance_binding_list, PermissionGroup::global_info, "b_serverinstance_binding_list", "List active IP bindings on multi-homed machines"), - //Removed due its useless - make_shared(PermissionType::b_serverinstance_permission_list, PermissionGroup::global_info, "b_serverinstance_permission_list", "List permissions available available on the server instance"), - make_shared(PermissionType::b_serverinstance_permission_find, PermissionGroup::global_info, "b_serverinstance_permission_find", "Search permission assignments by name or ID"), - make_shared(PermissionType::b_virtualserver_create, PermissionGroup::global_vsmanage, "b_virtualserver_create", "Create virtual servers"), - make_shared(PermissionType::b_virtualserver_delete, PermissionGroup::global_vsmanage, "b_virtualserver_delete", "Delete virtual servers"), - make_shared(PermissionType::b_virtualserver_start_any, PermissionGroup::global_vsmanage, "b_virtualserver_start_any", "Start any virtual server in the server instance"), - make_shared(PermissionType::b_virtualserver_stop_any, PermissionGroup::global_vsmanage, "b_virtualserver_stop_any", "Stop any virtual server in the server instance"), - make_shared(PermissionType::b_virtualserver_change_machine_id, PermissionGroup::global_vsmanage, "b_virtualserver_change_machine_id", "Change a virtual servers machine ID"), - make_shared(PermissionType::b_virtualserver_change_template, PermissionGroup::global_vsmanage, "b_virtualserver_change_template", "Edit virtual server default template values"), - make_shared(PermissionType::b_serverquery_login, PermissionGroup::global_admin, "b_serverquery_login", "Login to ServerQuery"), - make_shared(PermissionType::b_serverinstance_textmessage_send, PermissionGroup::global_admin, "b_serverinstance_textmessage_send", "Send text messages to all virtual servers at once"), - make_shared(PermissionType::b_serverinstance_log_view, PermissionGroup::global_admin, "b_serverinstance_log_view", "Retrieve global server log"), - make_shared(PermissionType::b_serverinstance_log_add, PermissionGroup::global_admin, "b_serverinstance_log_add", "Write to global server log"), - make_shared(PermissionType::b_serverinstance_stop, PermissionGroup::global_admin, "b_serverinstance_stop", "Shutdown the server process"), - make_shared(PermissionType::b_serverinstance_modify_settings, PermissionGroup::global_settings, "b_serverinstance_modify_settings", "Edit global settings"), - make_shared(PermissionType::b_serverinstance_modify_querygroup, PermissionGroup::global_settings, "b_serverinstance_modify_querygroup", "Edit global ServerQuery groups"), - make_shared(PermissionType::b_serverinstance_modify_templates, PermissionGroup::global_settings, "b_serverinstance_modify_templates", "Edit global template groups"), - make_shared(PermissionType::b_virtualserver_select, PermissionGroup::vs_info, "b_virtualserver_select", "Select a virtual server"), - make_shared(PermissionType::b_virtualserver_select_godmode, PermissionGroup::vs_info, "b_virtualserver_select_godmode", "Select a virtual server but be invisible"), - make_shared(PermissionType::b_virtualserver_info_view, PermissionGroup::vs_info, "b_virtualserver_info_view", "Retrieve virtual server information"), - make_shared(PermissionType::b_virtualserver_connectioninfo_view, PermissionGroup::vs_info, "b_virtualserver_connectioninfo_view", "Retrieve virtual server connection information"), - make_shared(PermissionType::b_virtualserver_channel_list, PermissionGroup::vs_info, "b_virtualserver_channel_list", "List channels on a virtual server"), - make_shared(PermissionType::b_virtualserver_channel_search, PermissionGroup::vs_info, "b_virtualserver_channel_search", "Search for channels on a virtual server"), - make_shared(PermissionType::b_virtualserver_client_list, PermissionGroup::vs_info, "b_virtualserver_client_list", "List clients online on a virtual server"), - make_shared(PermissionType::b_virtualserver_client_search, PermissionGroup::vs_info, "b_virtualserver_client_search", "Search for clients online on a virtual server"), - make_shared(PermissionType::b_virtualserver_client_dblist, PermissionGroup::vs_info, "b_virtualserver_client_dblist", "List client identities known by the virtual server"), - make_shared(PermissionType::b_virtualserver_client_dbsearch, PermissionGroup::vs_info, "b_virtualserver_client_dbsearch", "Search for client identities known by the virtual server"), - make_shared(PermissionType::b_virtualserver_client_dbinfo, PermissionGroup::vs_info, "b_virtualserver_client_dbinfo", "Retrieve client information"), - make_shared(PermissionType::b_virtualserver_permission_find, PermissionGroup::vs_info, "b_virtualserver_permission_find", "Find permissions"), - make_shared(PermissionType::b_virtualserver_custom_search, PermissionGroup::vs_info, "b_virtualserver_custom_search", "Find custom fields"), - make_shared(PermissionType::b_virtualserver_start, PermissionGroup::vs_admin, "b_virtualserver_start", "Start own virtual server"), - make_shared(PermissionType::b_virtualserver_stop, PermissionGroup::vs_admin, "b_virtualserver_stop", "Stop own virtual server"), - make_shared(PermissionType::b_virtualserver_token_list, PermissionGroup::vs_admin, "b_virtualserver_token_list", "List privilege keys available"), - make_shared(PermissionType::b_virtualserver_token_add, PermissionGroup::vs_admin, "b_virtualserver_token_add", "Create new privilege keys"), - make_shared(PermissionType::b_virtualserver_token_use, PermissionGroup::vs_admin, "b_virtualserver_token_use", "Use a privilege keys to gain access to groups"), - make_shared(PermissionType::b_virtualserver_token_delete, PermissionGroup::vs_admin, "b_virtualserver_token_delete", "Delete a privilege key"), - make_shared(PermissionType::b_virtualserver_log_view, PermissionGroup::vs_admin, "b_virtualserver_log_view", "Retrieve virtual server log"), - make_shared(PermissionType::b_virtualserver_log_add, PermissionGroup::vs_admin, "b_virtualserver_log_add", "Write to virtual server log"), - make_shared(PermissionType::b_virtualserver_join_ignore_password, PermissionGroup::vs_admin, "b_virtualserver_join_ignore_password", "Join virtual server ignoring its password"), - make_shared(PermissionType::b_virtualserver_notify_register, PermissionGroup::vs_admin, "b_virtualserver_notify_register", "Register for server notifications"), - make_shared(PermissionType::b_virtualserver_notify_unregister, PermissionGroup::vs_admin, "b_virtualserver_notify_unregister", "Unregister from server notifications"), - make_shared(PermissionType::b_virtualserver_snapshot_create, PermissionGroup::vs_admin, "b_virtualserver_snapshot_create", "Create server snapshots"), - make_shared(PermissionType::b_virtualserver_snapshot_deploy, PermissionGroup::vs_admin, "b_virtualserver_snapshot_deploy", "Deploy server snapshots"), - make_shared(PermissionType::b_virtualserver_permission_reset, PermissionGroup::vs_admin, "b_virtualserver_permission_reset", "Reset the server permission settings to default values"), - make_shared(PermissionType::b_virtualserver_modify_name, PermissionGroup::vs_settings, "b_virtualserver_modify_name", "Modify server name"), - make_shared(PermissionType::b_virtualserver_modify_welcomemessage, PermissionGroup::vs_settings, "b_virtualserver_modify_welcomemessage", "Modify welcome message"), - make_shared(PermissionType::b_virtualserver_modify_maxchannels, PermissionGroup::vs_settings, "b_virtualserver_modify_maxchannels", "Modify servers max channels"), - make_shared(PermissionType::b_virtualserver_modify_maxclients, PermissionGroup::vs_settings, "b_virtualserver_modify_maxclients", "Modify servers max clients"), - make_shared(PermissionType::b_virtualserver_modify_reserved_slots, PermissionGroup::vs_settings, "b_virtualserver_modify_reserved_slots", "Modify reserved slots"), - make_shared(PermissionType::b_virtualserver_modify_password, PermissionGroup::vs_settings, "b_virtualserver_modify_password", "Modify server password"), - make_shared(PermissionType::b_virtualserver_modify_default_servergroup, PermissionGroup::vs_settings, "b_virtualserver_modify_default_servergroup", "Modify default Server Group"), - make_shared(PermissionType::b_virtualserver_modify_default_musicgroup, PermissionGroup::vs_settings, "b_virtualserver_modify_default_musicgroup", "Modify default music Group"), - make_shared(PermissionType::b_virtualserver_modify_default_channelgroup, PermissionGroup::vs_settings, "b_virtualserver_modify_default_channelgroup", "Modify default Channel Group"), - make_shared(PermissionType::b_virtualserver_modify_default_channeladmingroup, PermissionGroup::vs_settings, "b_virtualserver_modify_default_channeladmingroup", "Modify default Channel Admin Group"), - make_shared(PermissionType::b_virtualserver_modify_channel_forced_silence, PermissionGroup::vs_settings, "b_virtualserver_modify_channel_forced_silence", "Modify channel force silence value"), - make_shared(PermissionType::b_virtualserver_modify_complain, PermissionGroup::vs_settings, "b_virtualserver_modify_complain", "Modify individual complain settings"), - make_shared(PermissionType::b_virtualserver_modify_antiflood, PermissionGroup::vs_settings, "b_virtualserver_modify_antiflood", "Modify individual antiflood settings"), - make_shared(PermissionType::b_virtualserver_modify_ft_settings, PermissionGroup::vs_settings, "b_virtualserver_modify_ft_settings", "Modify file transfer settings"), - make_shared(PermissionType::b_virtualserver_modify_ft_quotas, PermissionGroup::vs_settings, "b_virtualserver_modify_ft_quotas", "Modify file transfer quotas"), - make_shared(PermissionType::b_virtualserver_modify_hostmessage, PermissionGroup::vs_settings, "b_virtualserver_modify_hostmessage", "Modify individual hostmessage settings"), - make_shared(PermissionType::b_virtualserver_modify_hostbanner, PermissionGroup::vs_settings, "b_virtualserver_modify_hostbanner", "Modify individual hostbanner settings"), - make_shared(PermissionType::b_virtualserver_modify_hostbutton, PermissionGroup::vs_settings, "b_virtualserver_modify_hostbutton", "Modify individual hostbutton settings"), - make_shared(PermissionType::b_virtualserver_modify_port, PermissionGroup::vs_settings, "b_virtualserver_modify_port", "Modify server port"), -#ifndef LAGENCY - make_shared(PermissionType::b_virtualserver_modify_host, PermissionGroup::vs_settings, "b_virtualserver_modify_host", "Modify server host"), -#endif - make_shared(PermissionType::b_virtualserver_modify_autostart, PermissionGroup::vs_settings, "b_virtualserver_modify_autostart", "Modify server autostart"), - make_shared(PermissionType::b_virtualserver_modify_needed_identity_security_level, PermissionGroup::vs_settings, "b_virtualserver_modify_needed_identity_security_level", "Modify required identity security level"), - make_shared(PermissionType::b_virtualserver_modify_priority_speaker_dimm_modificator, PermissionGroup::vs_settings, "b_virtualserver_modify_priority_speaker_dimm_modificator", "Modify priority speaker dimm modificator"), - make_shared(PermissionType::b_virtualserver_modify_log_settings, PermissionGroup::vs_settings, "b_virtualserver_modify_log_settings", "Modify log settings"), - make_shared(PermissionType::b_virtualserver_modify_min_client_version, PermissionGroup::vs_settings, "b_virtualserver_modify_min_client_version", "Modify min client version"), - make_shared(PermissionType::b_virtualserver_modify_icon_id, PermissionGroup::vs_settings, "b_virtualserver_modify_icon_id", "Modify server icon"), - make_shared(PermissionType::b_virtualserver_modify_weblist, PermissionGroup::vs_settings, "b_virtualserver_modify_weblist", "Modify web server list reporting settings"), - make_shared(PermissionType::b_virtualserver_modify_country_code, PermissionGroup::vs_settings, "b_virtualserver_modify_country_code", "Modify servers country code property"), - make_shared(PermissionType::b_virtualserver_modify_codec_encryption_mode, PermissionGroup::vs_settings, "b_virtualserver_modify_codec_encryption_mode", "Modify codec encryption mode"), - make_shared(PermissionType::b_virtualserver_modify_temporary_passwords, PermissionGroup::vs_settings, "b_virtualserver_modify_temporary_passwords", "Modify temporary serverpasswords"), - make_shared(PermissionType::b_virtualserver_modify_temporary_passwords_own, PermissionGroup::vs_settings, "b_virtualserver_modify_temporary_passwords_own", "Modify own temporary serverpasswords"), - make_shared(PermissionType::b_virtualserver_modify_channel_temp_delete_delay_default, PermissionGroup::vs_settings, "b_virtualserver_modify_channel_temp_delete_delay_default", "Modify default temporary channel delete delay"), - make_shared(PermissionType::b_virtualserver_modify_music_bot_limit, PermissionGroup::vs_settings, "b_virtualserver_modify_music_bot_limit", "Allow client to edit the server music bot limit"), - make_shared(PermissionType::b_virtualserver_modify_default_messages, PermissionGroup::vs_settings, "b_virtualserver_modify_default_messages", "Allows the client to edit the default messages"), - make_shared(PermissionType::i_channel_min_depth, PermissionGroup::channel, "i_channel_min_depth", "Min channel creation depth in hierarchy"), - make_shared(PermissionType::i_channel_max_depth, PermissionGroup::channel, "i_channel_max_depth", "Max channel creation depth in hierarchy"), - make_shared(PermissionType::b_channel_group_inheritance_end, PermissionGroup::channel, "b_channel_group_inheritance_end", "Stop inheritance of channel group permissions"), - make_shared(PermissionType::i_channel_permission_modify_power, PermissionGroup::channel, "i_channel_permission_modify_power", "Modify channel permission power"), - make_shared(PermissionType::i_channel_needed_permission_modify_power, PermissionGroup::channel, "i_channel_needed_permission_modify_power", "Needed modify channel permission power"), - make_shared(PermissionType::b_channel_info_view, PermissionGroup::channel_info, "b_channel_info_view", "Retrieve channel information"), - make_shared(PermissionType::b_channel_create_child, PermissionGroup::channel_create, "b_channel_create_child", "Create sub-channels"), - make_shared(PermissionType::b_channel_create_permanent, PermissionGroup::channel_create, "b_channel_create_permanent", "Create permanent channels"), - make_shared(PermissionType::b_channel_create_semi_permanent, PermissionGroup::channel_create, "b_channel_create_semi_permanent", "Create semi-permanent channels"), - make_shared(PermissionType::b_channel_create_temporary, PermissionGroup::channel_create, "b_channel_create_temporary", "Create temporary channels"), - make_shared(PermissionType::b_channel_create_private, PermissionGroup::channel_create, "b_channel_create_private", "Create private channel"), - make_shared(PermissionType::b_channel_create_with_topic, PermissionGroup::channel_create, "b_channel_create_with_topic", "Create channels with a topic"), - make_shared(PermissionType::b_channel_create_with_description, PermissionGroup::channel_create, "b_channel_create_with_description", "Create channels with a description"), - make_shared(PermissionType::b_channel_create_with_password, PermissionGroup::channel_create, "b_channel_create_with_password", "Create password protected channels"), - make_shared(PermissionType::b_channel_create_modify_with_codec_speex8, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_speex8", "Create channels using Speex Narrowband (8 kHz) codecs"), - make_shared(PermissionType::b_channel_create_modify_with_codec_speex16, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_speex16", "Create channels using Speex Wideband (16 kHz) codecs"), - make_shared(PermissionType::b_channel_create_modify_with_codec_speex32, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_speex32", "Create channels using Speex Ultra-Wideband (32 kHz) codecs"), - make_shared(PermissionType::b_channel_create_modify_with_codec_celtmono48, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_celtmono48", "Create channels using the CELT Mono (48 kHz) codec"), - make_shared(PermissionType::b_channel_create_modify_with_codec_opusvoice, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_opusvoice", "Create channels using OPUS (voice) codec"), - make_shared(PermissionType::b_channel_create_modify_with_codec_opusmusic, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_opusmusic", "Create channels using OPUS (music) codec"), - make_shared(PermissionType::i_channel_create_modify_with_codec_maxquality, PermissionGroup::channel_create, "i_channel_create_modify_with_codec_maxquality", "Create channels with custom codec quality"), - make_shared(PermissionType::i_channel_create_modify_with_codec_latency_factor_min, PermissionGroup::channel_create, "i_channel_create_modify_with_codec_latency_factor_min", "Create channels with minimal custom codec latency factor"), - make_shared(PermissionType::b_channel_create_with_maxclients, PermissionGroup::channel_create, "b_channel_create_with_maxclients", "Create channels with custom max clients"), - make_shared(PermissionType::b_channel_create_with_maxfamilyclients, PermissionGroup::channel_create, "b_channel_create_with_maxfamilyclients", "Create channels with custom max family clients"), - make_shared(PermissionType::b_channel_create_with_sortorder, PermissionGroup::channel_create, "b_channel_create_with_sortorder", "Create channels with custom sort order"), - make_shared(PermissionType::b_channel_create_with_default, PermissionGroup::channel_create, "b_channel_create_with_default", "Create default channels"), - make_shared(PermissionType::b_channel_create_with_needed_talk_power, PermissionGroup::channel_create, "b_channel_create_with_needed_talk_power", "Create channels with needed talk power"), - make_shared(PermissionType::b_channel_create_modify_with_force_password, PermissionGroup::channel_create, "b_channel_create_modify_with_force_password", "Create new channels only with password"), - make_shared(PermissionType::i_channel_create_modify_with_temp_delete_delay, PermissionGroup::channel_create, "i_channel_create_modify_with_temp_delete_delay", "Max delete delay for temporary channels"), - make_shared(PermissionType::i_channel_create_modify_conversation_history_length, PermissionGroup::channel_create, "i_channel_create_modify_conversation_history_length", "Upper limmit for the setting of the max conversation history limit"), - make_shared(PermissionType::b_channel_create_modify_conversation_history_unlimited, PermissionGroup::channel_create, "b_channel_create_modify_conversation_history_unlimited", "Allows the user to set the channel conversation history to unlimited"), - make_shared(PermissionType::b_channel_create_modify_conversation_private, PermissionGroup::channel_create, "b_channel_create_modify_conversation_private", "Allows the user to set the channel conversation to private"), - make_shared(PermissionType::b_channel_modify_parent, PermissionGroup::channel_modify, "b_channel_modify_parent", "Move channels"), - make_shared(PermissionType::b_channel_modify_make_default, PermissionGroup::channel_modify, "b_channel_modify_make_default", "Make channel default"), - make_shared(PermissionType::b_channel_modify_make_permanent, PermissionGroup::channel_modify, "b_channel_modify_make_permanent", "Make channel permanent"), - make_shared(PermissionType::b_channel_modify_make_semi_permanent, PermissionGroup::channel_modify, "b_channel_modify_make_semi_permanent", "Make channel semi-permanent"), - make_shared(PermissionType::b_channel_modify_make_temporary, PermissionGroup::channel_modify, "b_channel_modify_make_temporary", "Make channel temporary"), - make_shared(PermissionType::b_channel_modify_name, PermissionGroup::channel_modify, "b_channel_modify_name", "Modify channel name"), - make_shared(PermissionType::b_channel_modify_topic, PermissionGroup::channel_modify, "b_channel_modify_topic", "Modify channel topic"), - make_shared(PermissionType::b_channel_modify_description, PermissionGroup::channel_modify, "b_channel_modify_description", "Modify channel description"), - make_shared(PermissionType::b_channel_modify_password, PermissionGroup::channel_modify, "b_channel_modify_password", "Modify channel password"), - make_shared(PermissionType::b_channel_modify_codec, PermissionGroup::channel_modify, "b_channel_modify_codec", "Modify channel codec"), - make_shared(PermissionType::b_channel_modify_codec_quality, PermissionGroup::channel_modify, "b_channel_modify_codec_quality", "Modify channel codec quality"), - make_shared(PermissionType::b_channel_modify_codec_latency_factor, PermissionGroup::channel_modify, "b_channel_modify_codec_latency_factor", "Modify channel codec latency factor"), - make_shared(PermissionType::b_channel_modify_maxclients, PermissionGroup::channel_modify, "b_channel_modify_maxclients", "Modify channels max clients"), - make_shared(PermissionType::b_channel_modify_maxfamilyclients, PermissionGroup::channel_modify, "b_channel_modify_maxfamilyclients", "Modify channels max family clients"), - make_shared(PermissionType::b_channel_modify_sortorder, PermissionGroup::channel_modify, "b_channel_modify_sortorder", "Modify channel sort order"), - make_shared(PermissionType::b_channel_modify_needed_talk_power, PermissionGroup::channel_modify, "b_channel_modify_needed_talk_power", "Change needed channel talk power"), - make_shared(PermissionType::i_channel_modify_power, PermissionGroup::channel_modify, "i_channel_modify_power", "Channel modify power"), - make_shared(PermissionType::i_channel_needed_modify_power, PermissionGroup::channel_modify, "i_channel_needed_modify_power", "Needed channel modify power"), - make_shared(PermissionType::b_channel_modify_make_codec_encrypted, PermissionGroup::channel_modify, "b_channel_modify_make_codec_encrypted", "Make channel codec encrypted"), - make_shared(PermissionType::b_channel_modify_temp_delete_delay, PermissionGroup::channel_modify, "b_channel_modify_temp_delete_delay", "Modify temporary channel delete delay"), - make_shared(PermissionType::b_channel_conversation_message_delete, PermissionGroup::channel_modify, "b_channel_conversation_message_delete", "If set the user is able to delete conversation messages"), - - make_shared(PermissionType::b_channel_delete_permanent, PermissionGroup::channel_delete, "b_channel_delete_permanent", "Delete permanent channels"), - make_shared(PermissionType::b_channel_delete_semi_permanent, PermissionGroup::channel_delete, "b_channel_delete_semi_permanent", "Delete semi-permanent channels"), - make_shared(PermissionType::b_channel_delete_temporary, PermissionGroup::channel_delete, "b_channel_delete_temporary", "Delete temporary channels"), - make_shared(PermissionType::b_channel_delete_flag_force, PermissionGroup::channel_delete, "b_channel_delete_flag_force", "Force channel delete"), - make_shared(PermissionType::i_channel_delete_power, PermissionGroup::channel_delete, "i_channel_delete_power", "Delete channel power"), - make_shared(PermissionType::i_channel_needed_delete_power, PermissionGroup::channel_delete, "i_channel_needed_delete_power", "Needed delete channel power"), - make_shared(PermissionType::b_channel_join_permanent, PermissionGroup::channel_access, "b_channel_join_permanent", "Join permanent channels"), - make_shared(PermissionType::b_channel_join_semi_permanent, PermissionGroup::channel_access, "b_channel_join_semi_permanent", "Join semi-permanent channels"), - make_shared(PermissionType::b_channel_join_temporary, PermissionGroup::channel_access, "b_channel_join_temporary", "Join temporary channels"), - make_shared(PermissionType::b_channel_join_ignore_password, PermissionGroup::channel_access, "b_channel_join_ignore_password", "Join channel ignoring its password"), - make_shared(PermissionType::b_channel_join_ignore_maxclients, PermissionGroup::channel_access, "b_channel_join_ignore_maxclients", "Ignore channels max clients limit"), - make_shared(PermissionType::b_channel_ignore_view_power, PermissionGroup::channel_access, "b_channel_ignore_view_power", "If set the client see's every channel"), - make_shared(PermissionType::i_channel_join_power, PermissionGroup::channel_access, "i_channel_join_power", "Channel join power"), - make_shared(PermissionType::i_channel_needed_join_power, PermissionGroup::channel_access, "i_channel_needed_join_power", "Needed channel join power"), - make_shared(PermissionType::b_channel_ignore_join_power, PermissionGroup::channel_access, "b_channel_ignore_join_power", "Allows the client to bypass the channel join power"), - make_shared(PermissionType::i_channel_view_power, PermissionGroup::channel_access, "i_channel_view_power", "Channel view power"), - make_shared(PermissionType::i_channel_needed_view_power, PermissionGroup::channel_access, "i_channel_needed_view_power", "Needed channel view power"), - make_shared(PermissionType::i_channel_subscribe_power, PermissionGroup::channel_access, "i_channel_subscribe_power", "Channel subscribe power"), - make_shared(PermissionType::i_channel_needed_subscribe_power, PermissionGroup::channel_access, "i_channel_needed_subscribe_power", "Needed channel subscribe power"), - make_shared(PermissionType::b_channel_ignore_subscribe_power, PermissionGroup::channel_access, "b_channel_ignore_subscribe_power", "Allows the client to bypass the subscribe power"), - make_shared(PermissionType::i_channel_description_view_power, PermissionGroup::channel_access, "i_channel_description_view_power", "Channel description view power"), - make_shared(PermissionType::i_channel_needed_description_view_power, PermissionGroup::channel_access, "i_channel_needed_description_view_power", "Needed channel needed description view power"), - make_shared(PermissionType::b_channel_ignore_description_view_power, PermissionGroup::channel_access, "b_channel_ignore_description_view_power", "Allows the client to bypass the channel description view power"), - make_shared(PermissionType::i_icon_id, PermissionGroup::group, "i_icon_id", "Group icon identifier"), - make_shared(PermissionType::i_max_icon_filesize, PermissionGroup::group, "i_max_icon_filesize", "Max icon filesize in bytes"), - make_shared(PermissionType::i_max_playlist_size, PermissionGroup::group, "i_max_playlist_size", "Max songs within one playlist"), - make_shared(PermissionType::i_max_playlists, PermissionGroup::group, "i_max_playlists", "Max amount of playlists a client could own"), - make_shared(PermissionType::b_icon_manage, PermissionGroup::group, "b_icon_manage", "Enables icon management"), - make_shared(PermissionType::b_group_is_permanent, PermissionGroup::group, "b_group_is_permanent", "Group is permanent"), - make_shared(PermissionType::i_group_auto_update_type, PermissionGroup::group, "i_group_auto_update_type", "Group auto-update type"), - make_shared(PermissionType::i_group_auto_update_max_value, PermissionGroup::group, "i_group_auto_update_max_value", "Group auto-update max value"), - make_shared(PermissionType::i_group_sort_id, PermissionGroup::group, "i_group_sort_id", "Group sort id"), - make_shared(PermissionType::i_group_show_name_in_tree, PermissionGroup::group, "i_group_show_name_in_tree", "Show group name in tree depending on selected mode"), - make_shared(PermissionType::b_virtualserver_servergroup_list, PermissionGroup::group_info, "b_virtualserver_servergroup_list", "List server groups"), - make_shared(PermissionType::b_virtualserver_servergroup_permission_list, PermissionGroup::group_info, "b_virtualserver_servergroup_permission_list", "Allows the client to view all server group permissions"), - make_shared(PermissionType::b_virtualserver_servergroup_client_list, PermissionGroup::group_info, "b_virtualserver_servergroup_client_list", "List clients from a server group"), - make_shared(PermissionType::b_virtualserver_channelgroup_list, PermissionGroup::group_info, "b_virtualserver_channelgroup_list", "List channel groups"), - make_shared(PermissionType::b_virtualserver_channelgroup_permission_list, PermissionGroup::group_info, "b_virtualserver_channelgroup_permission_list", "Allows the client to view all channel group permissions"), - make_shared(PermissionType::b_virtualserver_channelgroup_client_list, PermissionGroup::group_info, "b_virtualserver_channelgroup_client_list", "List clients from a channel group"), - make_shared(PermissionType::b_virtualserver_client_permission_list, PermissionGroup::group_info, "b_virtualserver_client_permission_list", "Allows the client to view all client permissions"), - make_shared(PermissionType::b_virtualserver_channel_permission_list, PermissionGroup::group_info, "b_virtualserver_channel_permission_list", "Allows the client to view all channel permissions"), - make_shared(PermissionType::b_virtualserver_channelclient_permission_list, PermissionGroup::group_info, "b_virtualserver_channelclient_permission_list", "Allows the client to view all client channel permissions"), - make_shared(PermissionType::b_virtualserver_playlist_permission_list, PermissionGroup::group_info, "b_virtualserver_playlist_permission_list", "Allows the client to view all playlist permissions"), - make_shared(PermissionType::b_virtualserver_servergroup_create, PermissionGroup::group_create, "b_virtualserver_servergroup_create", "Create server groups"), - make_shared(PermissionType::b_virtualserver_channelgroup_create, PermissionGroup::group_create, "b_virtualserver_channelgroup_create", "Create channel groups"), - -#ifdef LAGENCY - make_shared(PermissionType::i_group_modify_power, PermissionGroup::group_168, "i_group_modify_power", "Group modify power"), - make_shared(PermissionType::i_group_needed_modify_power, PermissionGroup::group_168, "i_group_needed_modify_power", "Needed group modify power"), - make_shared(PermissionType::i_group_member_add_power, PermissionGroup::group_168, "i_group_member_add_power", "Group member add power"), - make_shared(PermissionType::i_group_needed_member_add_power, PermissionGroup::group_168, "i_group_needed_member_add_power", "Needed group member add power"), - make_shared(PermissionType::i_group_member_remove_power, PermissionGroup::group_168, "i_group_member_remove_power", "Group member delete power"), - make_shared(PermissionType::i_group_needed_member_remove_power, PermissionGroup::group_168, "i_group_needed_member_remove_power", "Needed group member delete power"), -#else - make_shared(PermissionType::i_server_group_modify_power, PermissionGroup::group_modify, "i_server_group_modify_power", "Server group modify power"), - make_shared(PermissionType::i_server_group_needed_modify_power, PermissionGroup::group_modify, "i_server_group_needed_modify_power", "Needed server group modify power"), - make_shared(PermissionType::i_server_group_member_add_power, PermissionGroup::group_modify, "i_server_group_member_add_power", "Server group member add power"), - make_shared(PermissionType::i_server_group_self_add_power, PermissionGroup::group_modify, "i_server_group_self_add_power", "Server group self add power"), - make_shared(PermissionType::i_server_group_needed_member_add_power, PermissionGroup::group_modify, "i_server_group_needed_member_add_power", "Needed server group member add power"), - make_shared(PermissionType::i_server_group_member_remove_power, PermissionGroup::group_modify, "i_server_group_member_remove_power", "Server group member delete power"), - make_shared(PermissionType::i_server_group_self_remove_power, PermissionGroup::group_modify, "i_server_group_self_remove_power", "Server group self delete power"), - make_shared(PermissionType::i_server_group_needed_member_remove_power, PermissionGroup::group_modify, "i_server_group_needed_member_remove_power", "Needed server group member delete power"), - - make_shared(PermissionType::i_channel_group_modify_power, PermissionGroup::group_modify, "i_channel_group_modify_power", "Channel group modify power"), - make_shared(PermissionType::i_channel_group_needed_modify_power, PermissionGroup::group_modify, "i_channel_group_needed_modify_power", "Needed channel group modify power"), - make_shared(PermissionType::i_channel_group_member_add_power, PermissionGroup::group_modify, "i_channel_group_member_add_power", "Channel group member add power"), - make_shared(PermissionType::i_channel_group_self_add_power, PermissionGroup::group_modify, "i_channel_group_self_add_power", "Channel group self add power"), - make_shared(PermissionType::i_channel_group_needed_member_add_power, PermissionGroup::group_modify, "i_channel_group_needed_member_add_power", "Needed channel group member add power"), - make_shared(PermissionType::i_channel_group_member_remove_power, PermissionGroup::group_modify, "i_channel_group_member_remove_power", "Channel group member delete power"), - make_shared(PermissionType::i_channel_group_self_remove_power, PermissionGroup::group_modify, "i_channel_group_self_remove_power", "Channel group self delete power"), - make_shared(PermissionType::i_channel_group_needed_member_remove_power, PermissionGroup::group_modify, "i_channel_group_needed_member_remove_power", "Needed channel group member delete power"), - - //old enum mapping - make_shared(PermissionType::i_displayed_group_member_add_power, PermissionGroup::group_modify, "i_group_member_add_power", "The displayed member add power (Enables/Disabled the group in the select menu)"), - make_shared(PermissionType::i_displayed_group_needed_member_add_power, PermissionGroup::group_modify, "i_group_needed_member_add_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)"), - make_shared(PermissionType::i_displayed_group_member_remove_power, PermissionGroup::group_modify, "i_group_member_remove_power", "The displayed member add power (Enables/Disabled the group in the select menu)"), - make_shared(PermissionType::i_displayed_group_needed_member_remove_power, PermissionGroup::group_modify, "i_group_needed_member_remove_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)"), - make_shared(PermissionType::i_displayed_group_modify_power, PermissionGroup::group_modify, "i_group_modify_power", "The displayed member add power (Enables/Disabled the group in the select menu)"), - make_shared(PermissionType::i_displayed_group_needed_modify_power, PermissionGroup::group_modify, "i_group_needed_modify_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)"), - - //new enum mapping (must come AFTER the supported permissions) - make_shared(PermissionType::i_displayed_group_member_add_power, PermissionGroup::group_modify, "i_displayed_group_member_add_power", "The displayed member add power (Enables/Disabled the group in the select menu)", false), - make_shared(PermissionType::i_displayed_group_needed_member_add_power, PermissionGroup::group_modify, "i_displayed_group_needed_member_add_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)", false), - make_shared(PermissionType::i_displayed_group_member_remove_power, PermissionGroup::group_modify, "i_displayed_group_member_remove_power", "The displayed member add power (Enables/Disabled the group in the select menu)", false), - make_shared(PermissionType::i_displayed_group_needed_member_remove_power, PermissionGroup::group_modify, "i_displayed_group_needed_member_remove_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)", false), - make_shared(PermissionType::i_displayed_group_modify_power, PermissionGroup::group_modify, "i_displayed_group_modify_power", "The displayed member add power (Enables/Disabled the group in the select menu)", false), - make_shared(PermissionType::i_displayed_group_needed_modify_power, PermissionGroup::group_modify, "i_displayed_group_needed_modify_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)", false), -#endif - - make_shared(PermissionType::i_permission_modify_power, PermissionGroup::group_modify, "i_permission_modify_power", "Permission modify power"), - make_shared(PermissionType::b_permission_modify_power_ignore, PermissionGroup::group_modify, "b_permission_modify_power_ignore", "Ignore needed permission modify power"), - make_shared(PermissionType::b_virtualserver_servergroup_delete, PermissionGroup::group_delete, "b_virtualserver_servergroup_delete", "Delete server groups"), - make_shared(PermissionType::b_virtualserver_channelgroup_delete, PermissionGroup::group_delete, "b_virtualserver_channelgroup_delete", "Delete channel groups"), - make_shared(PermissionType::i_client_permission_modify_power, PermissionGroup::client, "i_client_permission_modify_power", "Client permission modify power"), - make_shared(PermissionType::i_client_needed_permission_modify_power, PermissionGroup::client, "i_client_needed_permission_modify_power", "Needed client permission modify power"), - make_shared(PermissionType::i_client_max_clones_uid, PermissionGroup::client, "i_client_max_clones_uid", "Max additional connections per client identity"), - make_shared(PermissionType::i_client_max_clones_ip, PermissionGroup::client, "i_client_max_clones_ip", "Max additional connections per client address"), - make_shared(PermissionType::i_client_max_clones_hwid, PermissionGroup::client, "i_client_max_clones_hwid", "Max additional connections per client hardware id"), - make_shared(PermissionType::i_client_max_idletime, PermissionGroup::client, "i_client_max_idletime", "Max idle time in seconds"), - make_shared(PermissionType::i_client_max_avatar_filesize, PermissionGroup::client, "i_client_max_avatar_filesize", "Max avatar filesize in bytes"), - make_shared(PermissionType::i_client_max_channel_subscriptions, PermissionGroup::client, "i_client_max_channel_subscriptions", "Max channel subscriptions"), - make_shared(PermissionType::i_client_max_channels, PermissionGroup::client, "i_client_max_channels", "Limit of created channels"), - make_shared(PermissionType::i_client_max_temporary_channels, PermissionGroup::client, "i_client_max_temporary_channels", "Limit of created temporary channels"), - make_shared(PermissionType::i_client_max_semi_channels, PermissionGroup::client, "i_client_max_semi_channels", "Limit of created semi-permanent channels"), - make_shared(PermissionType::i_client_max_permanent_channels, PermissionGroup::client, "i_client_max_permanent_channels", "Limit of created permanent channels"), - make_shared(PermissionType::b_client_use_priority_speaker, PermissionGroup::client, "b_client_use_priority_speaker", "Allows the client to use priority speaker"), - make_shared(PermissionType::b_client_is_priority_speaker, PermissionGroup::client, "b_client_is_priority_speaker", "Toogels the client priority speaker mode"), - make_shared(PermissionType::b_client_skip_channelgroup_permissions, PermissionGroup::client, "b_client_skip_channelgroup_permissions", "Ignore channel group permissions"), - make_shared(PermissionType::b_client_force_push_to_talk, PermissionGroup::client, "b_client_force_push_to_talk", "Force Push-To-Talk capture mode"), - make_shared(PermissionType::b_client_ignore_bans, PermissionGroup::client, "b_client_ignore_bans", "Ignore bans"), - make_shared(PermissionType::b_client_ignore_vpn, PermissionGroup::client, "b_client_ignore_vpn", "Ignore the vpn check"), - make_shared(PermissionType::b_client_ignore_antiflood, PermissionGroup::client, "b_client_ignore_antiflood", "Ignore antiflood measurements"), - make_shared(PermissionType::b_client_enforce_valid_hwid, PermissionGroup::client, "b_client_enforce_valid_hwid", "Enforces the client to have a valid hardware id"), - make_shared(PermissionType::b_client_allow_invalid_packet, PermissionGroup::client, "b_client_allow_invalid_packet", "Allow client to send invalid packets"), - make_shared(PermissionType::b_client_allow_invalid_badges, PermissionGroup::client, "b_client_allow_invalid_badges", "Allow client to have invalid badges"), - make_shared(PermissionType::b_client_issue_client_query_command, PermissionGroup::client, "b_client_issue_client_query_command", "Issue query commands from client"), - make_shared(PermissionType::b_client_use_reserved_slot, PermissionGroup::client, "b_client_use_reserved_slot", "Use an reserved slot"), - make_shared(PermissionType::b_client_use_channel_commander, PermissionGroup::client, "b_client_use_channel_commander", "Use channel commander"), - make_shared(PermissionType::b_client_request_talker, PermissionGroup::client, "b_client_request_talker", "Allow to request talk power"), - make_shared(PermissionType::b_client_avatar_delete_other, PermissionGroup::client, "b_client_avatar_delete_other", "Allow deletion of avatars from other clients"), - make_shared(PermissionType::b_client_is_sticky, PermissionGroup::client, "b_client_is_sticky", "Client will be sticked to current channel"), - make_shared(PermissionType::b_client_ignore_sticky, PermissionGroup::client, "b_client_ignore_sticky", "Client ignores sticky flag"), -#ifndef LAGACY - make_shared(PermissionType::b_client_music_channel_list, PermissionGroup::client_info, "b_client_music_channel_list", "List all music bots in the current channel"), - make_shared(PermissionType::b_client_music_server_list, PermissionGroup::client_info, "b_client_music_server_list", "List all music bots on the sderver"), - make_shared(PermissionType::i_client_music_info, PermissionGroup::client_info, "i_client_music_info", "Permission to view music bot info"), - make_shared(PermissionType::i_client_music_needed_info, PermissionGroup::client_info, "i_client_music_needed_info", "Required permission to view music bot info"), -#endif - make_shared(PermissionType::b_client_info_view, PermissionGroup::client_info, "b_client_info_view", "Retrieve client information"), - make_shared(PermissionType::b_client_permissionoverview_view, PermissionGroup::client_info, "b_client_permissionoverview_view", "Retrieve client permissions overview"), - make_shared(PermissionType::b_client_permissionoverview_own, PermissionGroup::client_info, "b_client_permissionoverview_own", "Retrieve clients own permissions overview"), - make_shared(PermissionType::b_client_remoteaddress_view, PermissionGroup::client_info, "b_client_remoteaddress_view", "View client IP address and port"), - make_shared(PermissionType::i_client_serverquery_view_power, PermissionGroup::client_info, "i_client_serverquery_view_power", "ServerQuery view power"), - make_shared(PermissionType::i_client_needed_serverquery_view_power, PermissionGroup::client_info, "i_client_needed_serverquery_view_power", "Needed ServerQuery view power"), - make_shared(PermissionType::b_client_custom_info_view, PermissionGroup::client_info, "b_client_custom_info_view", "View custom fields"), - make_shared(PermissionType::i_client_kick_from_server_power, PermissionGroup::client_admin, "i_client_kick_from_server_power", "Client kick power from server"), - make_shared(PermissionType::i_client_needed_kick_from_server_power, PermissionGroup::client_admin, "i_client_needed_kick_from_server_power", "Needed client kick power from server"), - make_shared(PermissionType::i_client_kick_from_channel_power, PermissionGroup::client_admin, "i_client_kick_from_channel_power", "Client kick power from channel"), - make_shared(PermissionType::i_client_needed_kick_from_channel_power, PermissionGroup::client_admin, "i_client_needed_kick_from_channel_power", "Needed client kick power from channel"), - make_shared(PermissionType::i_client_ban_power, PermissionGroup::client_admin, "i_client_ban_power", "Client ban power"), - make_shared(PermissionType::i_client_needed_ban_power, PermissionGroup::client_admin, "i_client_needed_ban_power", "Needed client ban power"), - make_shared(PermissionType::i_client_move_power, PermissionGroup::client_admin, "i_client_move_power", "Client move power"), - make_shared(PermissionType::i_client_needed_move_power, PermissionGroup::client_admin, "i_client_needed_move_power", "Needed client move power"), - make_shared(PermissionType::i_client_complain_power, PermissionGroup::client_admin, "i_client_complain_power", "Complain power"), - make_shared(PermissionType::i_client_needed_complain_power, PermissionGroup::client_admin, "i_client_needed_complain_power", "Needed complain power"), - make_shared(PermissionType::b_client_complain_list, PermissionGroup::client_admin, "b_client_complain_list", "Show complain list"), - make_shared(PermissionType::b_client_complain_delete_own, PermissionGroup::client_admin, "b_client_complain_delete_own", "Delete own complains"), - make_shared(PermissionType::b_client_complain_delete, PermissionGroup::client_admin, "b_client_complain_delete", "Delete complains"), - make_shared(PermissionType::b_client_ban_list, PermissionGroup::client_admin, "b_client_ban_list", "Show banlist"), - make_shared(PermissionType::b_client_ban_trigger_list, PermissionGroup::client_admin, "b_client_ban_trigger_list", "Show trigger banlist"), - make_shared(PermissionType::b_client_ban_list_global, PermissionGroup::client_admin, "b_client_ban_list_global", "Show banlist globaly"), - make_shared(PermissionType::b_client_ban_create, PermissionGroup::client_admin, "b_client_ban_create", "Add a ban"), - make_shared(PermissionType::b_client_ban_create_global, PermissionGroup::client_admin, "b_client_ban_create_global", "Allow to create global bans"), - make_shared(PermissionType::b_client_ban_name, PermissionGroup::client_admin, "b_client_ban_name", "Allows the client to ban a client by name"), - make_shared(PermissionType::b_client_ban_ip, PermissionGroup::client_admin, "b_client_ban_ip", "Allows the client to ban a client by ip"), - make_shared(PermissionType::b_client_ban_hwid, PermissionGroup::client_admin, "b_client_ban_hwid", "Allows the client to ban a client hardware id"), - make_shared(PermissionType::b_client_ban_edit, PermissionGroup::client_admin, "b_client_ban_edit", "Allow to edit bans"), - make_shared(PermissionType::b_client_ban_edit_global, PermissionGroup::client_admin, "b_client_ban_edit_global", "Allow to edit global bans"), - make_shared(PermissionType::b_client_ban_delete_own, PermissionGroup::client_admin, "b_client_ban_delete_own", "Delete own bans"), - make_shared(PermissionType::b_client_ban_delete, PermissionGroup::client_admin, "b_client_ban_delete", "Delete bans"), - make_shared(PermissionType::b_client_ban_delete_own_global, PermissionGroup::client_admin, "b_client_ban_delete_own_global", "Delete own global bans"), - make_shared(PermissionType::b_client_ban_delete_global, PermissionGroup::client_admin, "b_client_ban_delete_global", "Delete global bans"), - make_shared(PermissionType::i_client_ban_max_bantime, PermissionGroup::client_admin, "i_client_ban_max_bantime", "Max bantime"), - make_shared(PermissionType::b_client_even_textmessage_send, PermissionGroup::client_basic, "b_client_even_textmessage_send", "Allows the client to send text messages to himself"), - make_shared(PermissionType::i_client_private_textmessage_power, PermissionGroup::client_basic, "i_client_private_textmessage_power", "Client private message power"), - make_shared(PermissionType::i_client_needed_private_textmessage_power, PermissionGroup::client_basic, "i_client_needed_private_textmessage_power", "Needed client private message power"), - make_shared(PermissionType::b_client_server_textmessage_send, PermissionGroup::client_basic, "b_client_server_textmessage_send", "Send text messages to virtual server"), - make_shared(PermissionType::b_client_channel_textmessage_send, PermissionGroup::client_basic, "b_client_channel_textmessage_send", "Send text messages to channel"), - make_shared(PermissionType::b_client_offline_textmessage_send, PermissionGroup::client_basic, "b_client_offline_textmessage_send", "Send offline messages to clients"), - make_shared(PermissionType::i_client_talk_power, PermissionGroup::client_basic, "i_client_talk_power", "Client talk power"), - make_shared(PermissionType::i_client_needed_talk_power, PermissionGroup::client_basic, "i_client_needed_talk_power", "Needed client talk power"), - make_shared(PermissionType::i_client_poke_power, PermissionGroup::client_basic, "i_client_poke_power", "Client poke power"), - make_shared(PermissionType::i_client_needed_poke_power, PermissionGroup::client_basic, "i_client_needed_poke_power", "Needed client poke power"), - make_shared(PermissionType::b_client_set_flag_talker, PermissionGroup::client_basic, "b_client_set_flag_talker", "Set the talker flag for clients and allow them to speak"), - make_shared(PermissionType::i_client_whisper_power, PermissionGroup::client_basic, "i_client_whisper_power", "Client whisper power"), - make_shared(PermissionType::i_client_needed_whisper_power, PermissionGroup::client_basic, "i_client_needed_whisper_power", "Client needed whisper power"), - make_shared(PermissionType::b_client_modify_description, PermissionGroup::client_modify, "b_client_modify_description", "Edit a clients description"), - make_shared(PermissionType::b_client_modify_own_description, PermissionGroup::client_modify, "b_client_modify_own_description", "Allow client to edit own description"), - make_shared(PermissionType::b_client_modify_dbproperties, PermissionGroup::client_modify, "b_client_modify_dbproperties", "Edit a clients properties in the sql"), - make_shared(PermissionType::b_client_delete_dbproperties, PermissionGroup::client_modify, "b_client_delete_dbproperties", "Delete a clients properties in the sql"), - make_shared(PermissionType::b_client_create_modify_serverquery_login, PermissionGroup::client_modify, "b_client_create_modify_serverquery_login", "Create or modify own ServerQuery account"), - - make_shared(PermissionType::b_client_query_create, PermissionGroup::client_modify, "b_client_query_create", "Create your own ServerQuery account"), - make_shared(PermissionType::b_client_query_list, PermissionGroup::client_modify, "b_client_query_list", "List all ServerQuery accounts"), - make_shared(PermissionType::b_client_query_list_own, PermissionGroup::client_modify, "b_client_query_list_own", "List all own ServerQuery accounts"), - make_shared(PermissionType::b_client_query_rename, PermissionGroup::client_modify, "b_client_query_rename", "Rename a ServerQuery account"), - make_shared(PermissionType::b_client_query_rename_own, PermissionGroup::client_modify, "b_client_query_rename_own", "Rename the own ServerQuery account"), - make_shared(PermissionType::b_client_query_change_password, PermissionGroup::client_modify, "b_client_query_change_password", "Change a server query accounts password"), - make_shared(PermissionType::b_client_query_change_own_password, PermissionGroup::client_modify, "b_client_query_change_own_password", "Change a query accounts own password"), - make_shared(PermissionType::b_client_query_change_password_global, PermissionGroup::client_modify, "b_client_query_change_password_global", "Change a global query accounts own password"), - make_shared(PermissionType::b_client_query_delete, PermissionGroup::client_modify, "b_client_query_delete", "Delete a query accounts password"), - make_shared(PermissionType::b_client_query_delete_own, PermissionGroup::client_modify, "b_client_query_delete_own", "Delete own query accounts password"), - -#ifndef LAGENCY - make_shared(PermissionType::b_client_music_create_temporary, PermissionGroup::client, "b_client_music_create_temporary", "Permission to create a music bot"), - make_shared(PermissionType::b_client_music_create_semi_permanent, PermissionGroup::client, "b_client_music_create_semi_permanent", "Allows the client to create semi permanent music bots"), - make_shared(PermissionType::b_client_music_create_permanent, PermissionGroup::client, "b_client_music_create_permanent", "Allows the client to create permanent music bots"), - make_shared(PermissionType::b_client_music_modify_temporary, PermissionGroup::client, "b_client_music_modify_temporary", "Permission to make a music bot temporary"), - make_shared(PermissionType::b_client_music_modify_semi_permanent, PermissionGroup::client, "b_client_music_modify_semi_permanent", "Allows the client to make a bot semi permanent"), - make_shared(PermissionType::b_client_music_modify_permanent, PermissionGroup::client, "b_client_music_modify_permanent", "Allows the client to make a bot permanent"), - make_shared(PermissionType::i_client_music_create_modify_max_volume, PermissionGroup::client, "i_client_music_create_modify_max_volume", "Sets the max allowed music bot volume"), - make_shared(PermissionType::i_client_music_limit, PermissionGroup::client, "i_client_music_limit", "The limit of music bots bound to this client"), - make_shared(PermissionType::i_client_music_delete_power, PermissionGroup::client, "i_client_music_delete_power", "Power to delete the music bot"), - make_shared(PermissionType::i_client_music_needed_delete_power, PermissionGroup::client, "i_client_music_needed_delete_power", "Required power to delete the music bot"), - make_shared(PermissionType::i_client_music_play_power, PermissionGroup::client, "i_client_music_play_power", "Power to play music"), - make_shared(PermissionType::i_client_music_needed_modify_power, PermissionGroup::client, "i_client_music_needed_modify_power", "Required power to modify the bot settings"), - make_shared(PermissionType::i_client_music_modify_power, PermissionGroup::client, "i_client_music_modify_power", "Power to modify the music bot settings"), - make_shared(PermissionType::i_client_music_needed_play_power, PermissionGroup::client, "i_client_music_needed_play_power", "Required power to play music"), - make_shared(PermissionType::i_client_music_rename_power, PermissionGroup::client, "i_client_music_rename_power", "Power to rename the bot"), - make_shared(PermissionType::i_client_music_needed_rename_power, PermissionGroup::client, "i_client_music_needed_rename_power", "The required rename power for a music bot"), - - make_shared(PermissionType::b_playlist_create, PermissionGroup::client, "b_playlist_create", "Allows the client to create playlists"), - make_shared(PermissionType::i_playlist_view_power, PermissionGroup::client, "i_playlist_view_power", "Power to see a playlist, and their songs"), - make_shared(PermissionType::i_playlist_needed_view_power, PermissionGroup::client, "i_playlist_needed_view_power", "Needed power to see a playlist, and their songs"), - make_shared(PermissionType::i_playlist_modify_power, PermissionGroup::client, "i_playlist_modify_power", "Power to modify the playlist properties"), - make_shared(PermissionType::i_playlist_needed_modify_power, PermissionGroup::client, "i_playlist_needed_modify_power", "Needed power to modify the playlist properties"), - make_shared(PermissionType::i_playlist_permission_modify_power, PermissionGroup::client, "i_playlist_permission_modify_power", "Power to modify the playlist permissions"), - make_shared(PermissionType::i_playlist_needed_permission_modify_power, PermissionGroup::client, "i_playlist_needed_permission_modify_power", "Needed power to modify the playlist permissions"), - make_shared(PermissionType::i_playlist_delete_power, PermissionGroup::client, "i_playlist_delete_power", "Power to delete the playlist"), - make_shared(PermissionType::i_playlist_needed_delete_power, PermissionGroup::client, "i_playlist_needed_delete_power", "Needed power to delete the playlist"), - - make_shared(PermissionType::i_playlist_song_add_power, PermissionGroup::client, "i_playlist_song_add_power", "Power to add songs to a playlist"), - make_shared(PermissionType::i_playlist_song_needed_add_power, PermissionGroup::client, "i_playlist_song_needed_add_power", "Needed power to add songs to a playlist"), - make_shared(PermissionType::i_playlist_song_remove_power, PermissionGroup::client, "i_playlist_song_remove_power", "Power to remove songs from a playlist"), - make_shared(PermissionType::i_playlist_song_needed_remove_power, PermissionGroup::client, "i_playlist_song_needed_remove_power", "Needed power to remove songs from a playlist"), - make_shared(PermissionType::i_playlist_song_move_power, PermissionGroup::client, "i_playlist_song_move_power", "Power to move songs witin a playlist"), - make_shared(PermissionType::i_playlist_song_needed_move_power, PermissionGroup::client, "i_playlist_song_needed_move_power", "Needed power to move songs within a playlist"), - - make_shared(PermissionType::b_client_use_bbcode_any, PermissionGroup::client, "b_client_use_bbcode_any", "Allows the client to use any bbcodes"), - make_shared(PermissionType::b_client_use_bbcode_image, PermissionGroup::client, "b_client_use_bbcode_image", "Allows the client to use img bbcode"), - make_shared(PermissionType::b_client_use_bbcode_url, PermissionGroup::client, "b_client_use_bbcode_url", "Allows the client to use url bbcode"), -#endif - make_shared(PermissionType::b_ft_ignore_password, PermissionGroup::ft, "b_ft_ignore_password", "Browse files without channel password"), - make_shared(PermissionType::b_ft_transfer_list, PermissionGroup::ft, "b_ft_transfer_list", "Retrieve list of running filetransfers"), - make_shared(PermissionType::i_ft_file_upload_power, PermissionGroup::ft, "i_ft_file_upload_power", "File upload power"), - make_shared(PermissionType::i_ft_needed_file_upload_power, PermissionGroup::ft, "i_ft_needed_file_upload_power", "Needed file upload power"), - make_shared(PermissionType::i_ft_file_download_power, PermissionGroup::ft, "i_ft_file_download_power", "File download power"), - make_shared(PermissionType::i_ft_needed_file_download_power, PermissionGroup::ft, "i_ft_needed_file_download_power", "Needed file download power"), - make_shared(PermissionType::i_ft_file_delete_power, PermissionGroup::ft, "i_ft_file_delete_power", "File delete power"), - make_shared(PermissionType::i_ft_needed_file_delete_power, PermissionGroup::ft, "i_ft_needed_file_delete_power", "Needed file delete power"), - make_shared(PermissionType::i_ft_file_rename_power, PermissionGroup::ft, "i_ft_file_rename_power", "File rename power"), - make_shared(PermissionType::i_ft_needed_file_rename_power, PermissionGroup::ft, "i_ft_needed_file_rename_power", "Needed file rename power"), - make_shared(PermissionType::i_ft_file_browse_power, PermissionGroup::ft, "i_ft_file_browse_power", "File browse power"), - make_shared(PermissionType::i_ft_needed_file_browse_power, PermissionGroup::ft, "i_ft_needed_file_browse_power", "Needed file browse power"), - make_shared(PermissionType::i_ft_directory_create_power, PermissionGroup::ft, "i_ft_directory_create_power", "Create directory power"), - make_shared(PermissionType::i_ft_needed_directory_create_power, PermissionGroup::ft, "i_ft_needed_directory_create_power", "Needed create directory power"), - make_shared(PermissionType::i_ft_quota_mb_download_per_client, PermissionGroup::ft, "i_ft_quota_mb_download_per_client", "Download quota per client in MByte"), - make_shared(PermissionType::i_ft_quota_mb_upload_per_client, PermissionGroup::ft, "i_ft_quota_mb_upload_per_client", "Upload quota per client in MByte") -}; - -deque ts::permission::neededPermissions = { - b_client_force_push_to_talk, - b_channel_join_ignore_password, - b_ft_ignore_password, - i_client_max_avatar_filesize, - i_client_max_channel_subscriptions, - i_permission_modify_power, - b_virtualserver_servergroup_permission_list, - b_virtualserver_client_permission_list, - b_virtualserver_channelgroup_permission_list, - b_virtualserver_channelclient_permission_list, - b_virtualserver_playlist_permission_list, - b_virtualserver_channelgroup_client_list, - b_client_permissionoverview_view, - b_client_ban_list, - b_client_ban_trigger_list, - b_client_complain_list, - b_client_complain_delete, - b_client_complain_delete_own, - b_virtualserver_log_view, - b_client_create_modify_serverquery_login, - b_virtualserver_connectioninfo_view, - b_client_modify_description, - b_client_server_textmessage_send, - b_client_channel_textmessage_send, -#ifdef LAGENCY -i_group_modify_power, - i_group_member_add_power, - i_group_member_remove_power, -#else - i_displayed_group_modify_power, - i_displayed_group_member_add_power, - i_displayed_group_member_remove_power, - - i_server_group_modify_power, - i_server_group_member_add_power, - i_server_group_self_add_power, - i_server_group_member_remove_power, - i_server_group_self_remove_power, - - i_channel_group_modify_power, - i_channel_group_member_add_power, - i_channel_group_self_add_power, - i_channel_group_member_remove_power, - i_channel_group_self_remove_power, -#endif - i_ft_file_browse_power, - b_permission_modify_power_ignore, - b_virtualserver_modify_hostmessage, - b_virtualserver_modify_ft_settings, - b_virtualserver_modify_default_musicgroup, - b_virtualserver_modify_default_servergroup, - b_virtualserver_modify_default_channelgroup, - b_virtualserver_modify_default_channeladmingroup, - b_virtualserver_modify_hostbanner, - b_virtualserver_modify_channel_forced_silence, - b_virtualserver_modify_needed_identity_security_level, - b_virtualserver_modify_name, - b_virtualserver_modify_welcomemessage, - b_virtualserver_modify_maxclients, - b_virtualserver_modify_password, - b_virtualserver_modify_complain, - b_virtualserver_modify_antiflood, - b_virtualserver_modify_ft_quotas, - b_virtualserver_modify_hostbutton, - b_virtualserver_modify_autostart, - b_virtualserver_modify_port, - b_virtualserver_modify_host, - b_virtualserver_modify_log_settings, - b_virtualserver_modify_priority_speaker_dimm_modificator, - b_virtualserver_modify_music_bot_limit, - b_virtualserver_modify_default_messages, - i_channel_create_modify_conversation_history_length, - b_channel_create_modify_conversation_history_unlimited, - b_channel_create_modify_conversation_private, - b_channel_modify_name, - b_channel_modify_password, - b_channel_modify_topic, - b_channel_modify_description, - b_channel_modify_codec, - b_channel_modify_codec_quality, - b_channel_modify_make_permanent, - b_channel_modify_make_semi_permanent, - b_channel_modify_make_temporary, - b_channel_modify_make_default, - b_channel_modify_maxclients, - b_channel_modify_maxfamilyclients, - b_channel_modify_sortorder, - b_channel_modify_needed_talk_power, - i_channel_permission_modify_power, - b_channel_create_child, - b_channel_create_permanent, - b_channel_create_temporary, - b_channel_create_with_topic, - b_channel_create_with_description, - b_channel_create_with_password, - b_channel_create_with_maxclients, - b_channel_create_with_maxfamilyclients, - b_channel_create_with_sortorder, - b_channel_create_with_default, - b_channel_create_modify_with_codec_speex8, - b_channel_create_modify_with_codec_speex16, - b_channel_create_modify_with_codec_speex32, - b_channel_create_modify_with_codec_celtmono48, - b_channel_create_modify_with_codec_opusvoice, - b_channel_create_modify_with_codec_opusmusic, - i_channel_create_modify_with_codec_maxquality, - i_client_serverquery_view_power, - b_channel_create_semi_permanent, - b_serverinstance_modify_querygroup, - b_serverinstance_modify_templates, - b_virtualserver_channel_permission_list, - b_channel_delete_permanent, - b_channel_delete_semi_permanent, - b_channel_delete_temporary, - b_channel_delete_flag_force, - b_client_set_flag_talker, - b_channel_create_with_needed_talk_power, - b_virtualserver_token_list, - b_virtualserver_token_add, - b_virtualserver_token_use, - b_virtualserver_token_delete, - - /* ban functions */ - b_client_ban_create, - b_client_ban_create_global, - - b_client_ban_list_global, - b_client_ban_list, - - b_client_ban_edit, - b_client_ban_edit_global, - - b_client_ban_name, - b_client_ban_ip, - b_client_ban_hwid, - - b_virtualserver_servergroup_list, - b_virtualserver_servergroup_client_list, - b_virtualserver_channelgroup_list, - i_client_ban_max_bantime, - b_icon_manage, - i_max_icon_filesize, - i_max_playlist_size, - i_max_playlists, - - i_client_needed_whisper_power, - i_client_whisper_power, - - b_virtualserver_modify_icon_id, - b_client_modify_own_description, - b_client_offline_textmessage_send, - b_virtualserver_client_dblist, - b_virtualserver_modify_reserved_slots, - b_channel_conversation_message_delete, - i_channel_create_modify_with_codec_latency_factor_min, - b_channel_modify_codec_latency_factor, - b_channel_modify_make_codec_encrypted, - b_virtualserver_modify_codec_encryption_mode, - b_client_use_channel_commander, - b_virtualserver_servergroup_create, - b_virtualserver_channelgroup_create, - b_client_permissionoverview_own, - i_ft_quota_mb_upload_per_client, - i_ft_quota_mb_download_per_client, - b_virtualserver_modify_weblist, - b_virtualserver_modify_country_code, - b_virtualserver_channelgroup_delete, - b_virtualserver_servergroup_delete, - b_client_ban_delete, - b_client_ban_delete_own, - b_client_ban_delete_global, - b_client_ban_delete_own_global, - b_virtualserver_modify_temporary_passwords, - b_virtualserver_modify_temporary_passwords_own, - b_client_request_talker, - b_client_avatar_delete_other, - b_channel_create_modify_with_force_password, - b_channel_create_private, - b_channel_join_ignore_maxclients, - b_virtualserver_modify_channel_temp_delete_delay_default, - i_channel_create_modify_with_temp_delete_delay, - b_channel_modify_temp_delete_delay, - i_client_poke_power, - - b_client_remoteaddress_view, - - i_client_music_play_power, - i_client_music_modify_power, - i_client_music_rename_power, - b_client_music_create_temporary, - b_client_music_create_semi_permanent, - b_client_music_create_permanent, - b_client_music_modify_temporary, - b_client_music_modify_semi_permanent, - b_client_music_modify_permanent, - i_client_music_create_modify_max_volume, - - b_playlist_create, - i_playlist_view_power, - i_playlist_modify_power, - i_playlist_permission_modify_power, - i_playlist_delete_power, - - i_playlist_song_add_power, - i_playlist_song_remove_power, - i_playlist_song_move_power, - - b_client_query_create, - b_client_query_list, - b_client_query_list_own, - b_client_query_rename, - b_client_query_rename_own, - b_client_query_change_password, - b_client_query_change_own_password, - b_client_query_change_password_global, - b_client_query_delete, - b_client_query_delete_own, -}; - -std::deque permission::availableGroups = { - global, - global_info, - global_vsmanage, - global_admin, - global_settings, - vs, - vs_info, - vs_admin, - vs_settings, - channel, - channel_info, - channel_create, - channel_modify, - channel_delete, - channel_access, - group, - group_info, - group_create, - group_modify, - group_delete, - client, - client_info, - client_admin, - client_basic, - client_modify, - ft -}; - -std::shared_ptr PermissionTypeEntry::unknown = make_shared(PermissionType::unknown, PermissionGroup::global, "unknown", "unknown"); - -vector> permission_id_map; -void permission::setup_permission_resolve() { - permission_id_map.resize(permission::permission_id_max); - - for(auto& permission : availablePermissions) { - if(!permission->clientSupported || permission->type < 0 || permission->type > permission::permission_id_max) - continue; - permission_id_map[permission->type] = permission; - } - - /* fix "holes" as well set the permission id 0 (unknown) */ - for(auto& permission : permission_id_map) { - if(permission) - continue; - permission = PermissionTypeEntry::unknown; - } -} - -std::shared_ptr permission::resolvePermissionData(PermissionType type) { - if((type & PERM_ID_GRANT) > 0) - type &= ~PERM_ID_GRANT; - - assert(!permission_id_map.empty()); - if(type < 0 || type >= permission::permission_id_max) - return PermissionTypeEntry::unknown; - - return permission_id_map[type]; -} - -std::shared_ptr permission::resolvePermissionData(const std::string& name) { - for(auto& elm : availablePermissions) - if(elm->name == name || elm->grant_name == name) - return elm; - return PermissionTypeEntry::unknown; -} - -ChannelId Permission::channelId() { - return this->channel ? this->channel->channelId() : 0; -} - -PermissionManager::PermissionManager() { - memtrack::allocated(this); -} -PermissionManager::~PermissionManager() { - memtrack::freed(this); -} - -std::shared_ptr PermissionManager::registerPermission(ts::permission::PermissionType type, - ts::permission::PermissionValue val, - const std::shared_ptr &channel, - uint16_t flag) { - return this->registerPermission(resolvePermissionData(type), val, channel, flag); -} - -std::shared_ptr PermissionManager::registerPermission(const std::shared_ptr& type, PermissionValue value, const std::shared_ptr& channel, uint16_t flagMask) { - { - auto found = getPermission(type->type, channel, false); - if(!found.empty()) return found.front(); - } - auto permission = std::make_shared(type, value, permNotGranted, flagMask, channel); - this->permissions.push_back(permission); - for(auto& elm : this->updateHandler) - elm(permission); - return permission; -} - -bool PermissionManager::hasPermission(PermissionType type, const std::shared_ptr& channel, bool testGlobal) { - return !this->getPermission(type, channel, testGlobal).empty(); -} - -bool PermissionManager::setPermission(PermissionType type, PermissionValue value, const std::shared_ptr& channel) { - auto list = this->getPermission(type, channel, false); - if(list.empty()) - list.push_back(registerPermission(type, value, channel, PERM_FLAG_PUBLIC)); - - list.front()->value = value; - for(const auto& elm : this->updateHandler) - elm(list.front()); - - return true; -} - -bool PermissionManager::setPermission(ts::permission::PermissionType type, ts::permission::PermissionValue value, const std::shared_ptr &channel, bool negated, bool skiped) { - auto list = this->getPermission(type, channel, false); - if(list.empty()) - list.push_back(registerPermission(type, value, channel, PERM_FLAG_PUBLIC)); - - list.front()->value = value; - list.front()->flag_negate = negated; - list.front()->flag_skip = skiped; - - for(const auto& elm : this->updateHandler) - elm(list.front()); - - return true; -} - -bool PermissionManager::setPermissionGranted(PermissionType type, PermissionValue value, const std::shared_ptr& channel) { - auto list = this->getPermission(type, channel, false); - if(list.empty()) - list.push_back(registerPermission(type, permNotGranted, channel, PERM_FLAG_PUBLIC)); - list.front()->granted = value; - - for(auto& elm : this->updateHandler) - elm(list.front()); - - return true; -} - -void PermissionManager::deletePermission(PermissionType type, const std::shared_ptr& channel) { - auto list = getPermission(type, channel, false); - if(list.empty()) return; - list.front()->value = permNotGranted; - //list.front()->deleted = true; - //this->permissions.erase(std::find(this->permissions.begin(), this->permissions.end(), list.front())); - - for(auto& e : this->updateHandler) - e(list.front()); -} - -std::deque> PermissionManager::getPermission(PermissionType type, const std::shared_ptr& channel, bool testGlobal) { - std::deque> res; - - std::shared_ptr channel_permission; - std::shared_ptr global_permission; - for(const auto &perm : this->permissions) - if(perm->type->type == type) { - if(perm->channel == channel) - channel_permission = perm; - else if(!perm->channel && testGlobal) - global_permission = perm; - } - if(channel_permission) res.push_back(channel_permission); - if(global_permission) res.push_back(global_permission); - return res; -} - -std::vector> PermissionManager::listPermissions(uint16_t flags) { - vector> result; - for(const auto &perm : this->permissions) - if((perm->flagMask & flags) > 0 || true) //FIXME? - result.push_back(perm); - return result; -} - -std::vector> PermissionManager::allPermissions() { - return std::vector>(this->permissions.begin(), this->permissions.end()); -} - -std::deque> PermissionManager::all_channel_specific_permissions() { - std::deque> result; - - for(const auto& permission : this->permissions) - if(permission->channel) - result.push_back(permission); - - return result; -} - -std::deque> PermissionManager::all_channel_unspecific_permissions() { - std::deque> result; - - for(const auto& permission : this->permissions) - if(!permission->channel) - result.push_back(permission); - - return result; -} - -teamspeak::MapType teamspeak::unmapping; -teamspeak::MapType teamspeak::mapping; - -teamspeak::MapType build_mapping(){ - return { - {teamspeak::GENERAL, { - {"b_virtualserver_modify_port", {"b_virtualserver_modify_port", "b_virtualserver_modify_host"}}, - {"i_client_max_clones_uid", {"i_client_max_clones_uid", "i_client_max_clones_ip", "i_client_max_clones_hwid"}}, - {"b_client_ignore_bans", {"b_client_ignore_bans", "b_client_ignore_vpn"}}, - {"b_client_ban_list", {"b_client_ban_list", "b_client_ban_list_global"}}, - - //Permissions which TeaSpeak has but TeamSpeak not - {"", {"b_virtualserver_modify_music_bot_limit"}}, - {"", {"b_client_music_channel_list"}}, - {"", {"b_client_music_server_list"}}, - {"", {"i_client_music_info"}}, - {"", {"i_client_music_needed_info"}}, - - {"", {"b_client_ban_edit"}}, - {"", {"b_client_ban_edit_global"}}, - {"", {"b_client_ban_create_global"}}, - {"", {"b_client_ban_delete_own_global"}}, - {"", {"b_client_ban_delete_global"}}, - - {"", {"b_client_even_textmessage_send"}}, - {"", {"b_client_enforce_valid_hwid"}}, - {"", {"b_client_allow_invalid_packet"}}, - {"", {"b_client_allow_invalid_badges"}}, - - {"", {"b_client_music_create"}}, - {"", {"b_client_music_delete_own"}}, - - {"", {"i_client_music_limit"}}, - {"", {"i_client_music_needed_delete_power"}}, - {"", {"i_client_music_delete_power"}}, - {"", {"i_client_music_play_power"}}, - {"", {"i_client_music_needed_play_power"}}, - {"", {"i_client_music_rename_power"}}, - {"", {"i_client_music_needed_rename_power"}}, - - {"", {"b_client_use_bbcode_any"}}, - {"", {"b_client_use_bbcode_url"}}, - {"", {"b_client_use_bbcode_image"}}, - - {"", {"b_channel_ignore_view_power"}}, - {"", {"i_channel_view_power"}}, - {"", {"i_channel_needed_view_power"}}, - - {"", {"i_client_max_channels"}}, - {"", {"i_client_max_temporary_channels"}}, - {"", {"i_client_max_semi_channels"}}, - {"", {"i_client_max_permanent_channels"}}, - - {"", {"b_virtualserver_modify_default_messages"}}, - - {"b_client_ban_list", {"b_client_ban_list", "b_client_ban_trigger_list"}}, - {"b_virtualserver_select", {"b_virtualserver_select", "b_virtualserver_select_godmode"}}, - {"b_virtualserver_modify_default_servergroup", {"b_virtualserver_modify_default_servergroup", "b_virtualserver_modify_default_musicgroup"}}, - - {"b_client_ban_create", {"b_client_ban_create", "b_client_ban_name", "b_client_ban_ip", "b_client_ban_hwid"}} - }, - }, - {teamspeak::SERVER, { - {"i_group_modify_power", {"i_server_group_modify_power", "i_channel_group_modify_power", "i_displayed_group_modify_power"}}, - {"i_group_member_add_power", {"i_server_group_member_add_power", "i_channel_group_member_add_power", "i_displayed_group_member_add_power"}}, - {"i_group_member_remove_power", {"i_server_group_member_remove_power", "i_channel_group_member_remove_power", "i_displayed_group_member_remove_power"}}, - {"i_group_needed_modify_power", {"i_server_group_needed_modify_power", "i_channel_group_needed_modify_power", "i_displayed_group_needed_modify_power"}}, - {"i_group_needed_member_add_power", {"i_server_group_needed_member_add_power", "i_channel_group_needed_member_add_power", "i_displayed_group_needed_member_add_power"}}, - {"i_group_needed_member_remove_power", {"i_server_group_needed_member_remove_power", "i_channel_group_needed_member_remove_power", "i_displayed_group_needed_member_remove_power"}}, - }, - }, - {teamspeak::CLIENT, { - {"i_group_modify_power", {"i_server_group_modify_power", "i_channel_group_modify_power", "i_displayed_group_modify_power"}}, - {"i_group_member_add_power", {"i_server_group_member_add_power", "i_channel_group_member_add_power", "i_displayed_group_member_add_power"}}, - {"i_group_member_remove_power", {"i_server_group_member_remove_power", "i_channel_group_member_remove_power", "i_displayed_group_member_remove_power"}}, - {"i_group_needed_modify_power", {"i_server_group_needed_modify_power", "i_channel_group_needed_modify_power", "i_displayed_group_needed_modify_power"}}, - {"i_group_needed_member_add_power", {"i_server_group_needed_member_add_power", "i_channel_group_needed_member_add_power", "i_displayed_group_needed_member_add_power"}}, - {"i_group_needed_member_remove_power", {"i_server_group_needed_member_remove_power", "i_channel_group_needed_member_remove_power", "i_displayed_group_needed_member_remove_power"}}, - }, - }, - {teamspeak::CHANNEL, { - {"i_group_modify_power", {"i_channel_group_modify_power", "i_displayed_group_modify_power"}}, - {"i_group_member_add_power", {"i_channel_group_member_add_power", "i_displayed_group_member_add_power"}}, - {"i_group_member_remove_power", {"i_channel_group_member_remove_power", "i_displayed_group_member_remove_power"}}, - {"i_group_needed_modify_power", {"i_channel_group_needed_modify_power", "i_displayed_group_needed_modify_power"}}, - {"i_group_needed_member_add_power", {"i_channel_group_needed_member_add_power", "i_displayed_group_needed_member_add_power"}}, - {"i_group_needed_member_remove_power", {"i_channel_group_needed_member_remove_power", "i_displayed_group_needed_member_remove_power"}}, - }, - }, - }; -}; - -inline teamspeak::MapType build_unmapping() { - teamspeak::MapType result; - - for(const auto& map : teamspeak::mapping) { - for(const auto& entry : map.second) { - for(const auto& key : entry.second) { - auto& m = result[map.first]; - auto it = m.find(key); - if(it == m.end()) - m.insert({key, {}}); - it = m.find(key); - if(!entry.first.empty()) it->second.push_back(entry.first); - } - } - } - - return result; -}; - -inline void init_mapping() { - if(teamspeak::mapping.empty()) teamspeak::mapping = build_mapping(); - if(teamspeak::unmapping.empty()) teamspeak::unmapping = build_unmapping(); -} - -template -inline deque operator+(const deque& a, const deque& b) { - deque result; - result.insert(result.end(), a.begin(), a.end()); - result.insert(result.end(), b.begin(), b.end()); - return result; -} - -inline deque mmget(teamspeak::MapType& map, teamspeak::GroupType type, const std::string& key) { - return map[type].count(key) > 0 ? map[type].find(key)->second : deque{}; -} - -inline std::deque map_entry(std::string key, teamspeak::GroupType type, teamspeak::MapType& map_table) { - init_mapping(); - - if(key.find("_needed_modify_power_") == 1) { - key = key.substr(strlen("x_needed_modify_power_")); - - deque result; - if(map_table[type].count("i_" + key) > 0 || map_table[teamspeak::GroupType::GENERAL].count("i_" + key) > 0) result = mmget(map_table, type, "i_" + key) + mmget(map_table, teamspeak::GroupType::GENERAL, "i_" + key); - else if(map_table[type].count("b_" + key) > 0 || map_table[teamspeak::GroupType::GENERAL].count("b_" + key) > 0) result = mmget(map_table, type, "b_" + key) + mmget(map_table, teamspeak::GroupType::GENERAL, "b_" + key); - else result = {"x_" + key}; - - for(auto& entry : result) - entry = "i_needed_modify_power_" + entry.substr(2); - return result; - } - if(map_table[type].count(key) > 0 || map_table[teamspeak::GroupType::GENERAL].count(key) > 0) return mmget(map_table, type, key) + mmget(map_table, teamspeak::GroupType::GENERAL, key); - return {key}; -} - -std::deque teamspeak::map_key(std::string key, GroupType type) { - return map_entry(key, type, teamspeak::mapping); -} - -std::deque teamspeak::unmap_key(std::string key, GroupType type) { - return map_entry(key, type, teamspeak::unmapping); -} - - -#define AQB(name) \ -{update::QUERY_ADMIN, {name, 1, 100, false, false}}, \ -{update::SERVER_ADMIN, {name, 1, 75, false, false}}, \ - -#define AQBG(name) \ -{update::QUERY_ADMIN, {name, permNotGranted, 100, false, false}}, \ -{update::SERVER_ADMIN, {name, permNotGranted, 75, false, false}}, \ - -#define AQI(name) \ -{update::QUERY_ADMIN, {name, 100, 100, false, false}}, \ -{update::SERVER_ADMIN, {name, 75, 75, false, false}}, \ - -#define AQIG(name) \ -{update::QUERY_ADMIN, {name, permNotGranted, 100, false, false}}, \ -{update::SERVER_ADMIN, {name, permNotGranted, 75, false, false}}, \ - -deque update::migrate = { - AQB("b_virtualserver_modify_music_bot_limit") - {update::QUERY_ADMIN, {"b_client_music_channel_list", 1, 100, false, false}}, - {update::SERVER_ADMIN, {"b_client_music_channel_list", 1, 75, false, false}}, - {update::CHANNEL_ADMIN, {"b_client_music_channel_list", 1, 75, false, false}}, - - {update::QUERY_ADMIN, {"b_client_music_server_list", 1, 100, false, false}}, - {update::SERVER_ADMIN, {"b_client_music_server_list", 1, 75, false, false}}, - - {update::QUERY_ADMIN, {"i_client_music_info", 100, 100, false, false}}, - {update::SERVER_ADMIN, {"i_client_music_info", 75, 75, false, false}}, - - {update::QUERY_ADMIN, {"i_client_music_needed_info", permNotGranted, 100, false, false}}, - {update::SERVER_ADMIN, {"i_client_music_needed_info", permNotGranted, 75, false, false}}, - - {update::QUERY_ADMIN, {"b_client_ban_list_global", 1, 100, false, false}}, - {update::SERVER_ADMIN, {"b_client_ban_list_global", 1, 75, false, false}}, - - {update::QUERY_ADMIN, {"b_client_ban_edit", 1, 100, false, false}}, - {update::SERVER_ADMIN, {"b_client_ban_edit", 1, 75, false, false}}, - - {update::QUERY_ADMIN, {"b_client_ban_create_global", 1, 100, false, false}}, - {update::QUERY_ADMIN, {"b_client_ban_edit_global", 1, 100, false, false}}, - {update::QUERY_ADMIN, {"b_client_ban_delete_own_global", 1, 100, false, false}}, - {update::QUERY_ADMIN, {"b_client_ban_delete_global", 1, 100, false, false}}, - - AQB("b_client_even_textmessage_send") - AQBG("b_client_enforce_valid_hwid") - AQB("b_client_allow_invalid_packet") - AQB("b_client_allow_invalid_badges") - - AQB("b_client_music_create") - AQB("b_client_music_delete_own") - - AQI("i_client_music_limit") - AQIG("i_client_music_needed_delete_power") - AQI("i_client_music_delete_power") - AQI("i_client_music_play_power") - AQIG("i_client_music_needed_play_power") - AQI("i_client_music_rename_power") - AQIG("i_client_music_needed_rename_power") - - - AQB("b_client_use_bbcode_any") - AQB("b_client_use_bbcode_url") - AQB("b_client_use_bbcode_image") - - {update::QUERY_ADMIN, {"b_channel_ignore_view_power", 1, 100, false, false}}, - AQI("i_channel_view_power") - AQIG("i_channel_needed_view_power") - - AQB("b_client_ignore_vpn") - - AQIG("i_client_max_channels") - AQIG("i_client_max_temporary_channels") - AQIG("i_client_max_semi_channels") - AQIG("i_client_max_permanent_channels") - {update::SERVER_NORMAL, {"i_client_max_channels", 2, permNotGranted, false, false}}, - {update::SERVER_GUEST, {"i_client_max_channels", 1, permNotGranted, false, false}}, - - AQB("b_virtualserver_modify_default_messages") - AQB("b_virtualserver_modify_default_musicgroup") - AQB("b_channel_ignore_join_power") - AQB("b_virtualserver_select_godmode") - AQB("b_client_ban_trigger_list") -}; - -v2::PermissionRegister::PermissionRegister() { - memset(this->block_use_count, 0, sizeof(this->block_use_count)); - memset(this->block_containers, 0, sizeof(this->block_containers)); -} - -v2::PermissionRegister::~PermissionRegister() { - for(auto& block : this->block_containers) - delete block; -} - -void v2::PermissionRegister::load_permission(const ts::permission::PermissionType &permission, const ts::permission::v2::PermissionValues &values, bool flag_skip, bool flag_negate, bool flag_value, bool flag_grant) { - if(permission < 0 || permission >= PermissionType::permission_id_max) - return; - - const auto block = this->calculate_block(permission); - this->ref_allocate_block(block); - - auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; - data.values = values; - data.flags.database_reference = true; - data.flags.skip = flag_skip; - data.flags.negate = flag_negate; - data.flags.value_set = flag_value; - data.flags.grant_set = flag_grant; - this->unref_block(block); -} - -void v2::PermissionRegister::load_permission(const ts::permission::PermissionType &permission, const ts::permission::v2::PermissionValues &values, ChannelId channel_id, bool flag_skip, bool flag_negate, bool flag_value, bool flag_grant) { - if(permission < 0 || permission >= PermissionType::permission_id_max) - return; - - unique_lock channel_perm_lock(this->channel_list_lock); - ChannelPermissionContainer* permission_container = nullptr; - for(auto& entry : this->_channel_permissions) - if(entry->permission == permission && entry->channel_id == channel_id) { - permission_container = &*entry; - break; - } - - if(!permission_container) { - auto container = make_unique(); - container->permission = permission; - container->channel_id = channel_id; - permission_container = &*container; - this->_channel_permissions.push_back(std::move(container)); - - /* now set the channel flag for that permission */ - const auto block = this->calculate_block(permission); - this->ref_allocate_block(block); - - auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; - data.flags.channel_specific = true; - this->unref_block(block); - } - - permission_container->values = values; - permission_container->flags.database_reference = true; - permission_container->flags.skip = flag_skip; - permission_container->flags.negate = flag_negate; - permission_container->flags.value_set = flag_value; - permission_container->flags.grant_set = flag_grant; -} - -const v2::PermissionFlags v2::PermissionRegister::permission_flags(const ts::permission::PermissionType &permission) { - if(permission < 0 || permission >= PermissionType::permission_id_max) - return empty_flags; - - const auto block = this->calculate_block(permission); - if(!this->ref_block(block)) - return empty_flags; - - PermissionFlags result{this->block_containers[block]->permissions[this->calculate_block_index(permission)].flags}; - this->unref_block(block); - return result; -} - -const v2::PermissionValues v2::PermissionRegister::permission_values(const ts::permission::PermissionType &permission) { - if(permission < 0 || permission >= PermissionType::permission_id_max) - return v2::empty_permission_values; - - const auto block = this->calculate_block(permission); - if(!this->ref_block(block)) - return v2::empty_permission_values; /* TODO: may consider to throw an exception because the existence should be checked by getting the permission flags */ - - v2::PermissionValues data{this->block_containers[block]->permissions[this->calculate_block_index(permission)].values}; - this->unref_block(block); - return data; -} - -const v2::PermissionFlaggedValue v2::PermissionRegister::permission_value_flagged(const ts::permission::PermissionType &permission) { - if(permission < 0 || permission >= PermissionType::permission_id_max) - return v2::empty_permission_flagged_value; - - const auto block = this->calculate_block(permission); - if(!this->ref_block(block)) - return v2::empty_permission_flagged_value; - - auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; - v2::PermissionFlaggedValue result{data.values.value, data.flags.value_set}; - this->unref_block(block); - return result; -} - -const v2::PermissionFlaggedValue v2::PermissionRegister::permission_granted_flagged(const ts::permission::PermissionType &permission) { - if(permission < 0 || permission >= PermissionType::permission_id_max) - return v2::empty_permission_flagged_value; - - const auto block = this->calculate_block(permission); - if(!this->ref_block(block)) - return v2::empty_permission_flagged_value; - - auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; - v2::PermissionFlaggedValue result{data.values.grant, data.flags.grant_set}; - this->unref_block(block); - return result; -} - -const v2::PermissionContainer v2::PermissionRegister::channel_permission(const PermissionType &permission, ts::ChannelId channel_id) { - if(permission < 0 || permission >= PermissionType::permission_id_max) - return empty_channel_permission; - - shared_lock channel_perm_lock(this->channel_list_lock); - for(auto& entry : this->_channel_permissions) - if(entry->permission == permission && entry->channel_id == channel_id) - return v2::PermissionContainer{entry->flags, entry->values}; - return empty_channel_permission; -} - -void v2::PermissionRegister::set_permission(const PermissionType &permission, const v2::PermissionValues &values, const v2::PermissionUpdateType &action_value, const v2::PermissionUpdateType &action_grant, int flag_skip, int flag_negate) { - if(permission < 0 || permission >= PermissionType::permission_id_max) - return; - - const auto block = this->calculate_block(permission); - this->ref_allocate_block(block); - - auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; - if(action_value == v2::PermissionUpdateType::set_value) { - data.flags.value_set = true; - data.flags.flag_value_update = true; - data.values.value = values.value; - } else if(action_value == v2::PermissionUpdateType::delete_value) { - data.flags.value_set = false; - data.flags.flag_value_update = true; - data.values.value = permNotGranted; /* required for the database else it does not "deletes" the value */ - } - - if(action_grant == v2::PermissionUpdateType::set_value) { - data.flags.grant_set = true; - data.flags.flag_grant_update = true; - data.values.grant = values.grant; - } else if(action_grant == v2::PermissionUpdateType::delete_value) { - data.flags.grant_set = false; - data.flags.flag_grant_update = true; - data.values.grant = permNotGranted; /* required for the database else it does not "deletes" the value */ - } - - if(flag_skip >= 0) { - data.flags.flag_value_update = true; - data.flags.skip = flag_skip == 1; - } - - if(flag_negate >= 0) { - data.flags.flag_value_update = true; - data.flags.negate = flag_negate == 1; - } - - this->unref_block(block); - this->trigger_db_update(); -} - -void v2::PermissionRegister::set_channel_permission(const PermissionType &permission, ChannelId channel_id, const v2::PermissionValues &values, const v2::PermissionUpdateType &action_value, const v2::PermissionUpdateType &action_grant, int flag_skip, int flag_negate) { - if(permission < 0 || permission >= PermissionType::permission_id_max) - return; - - unique_lock channel_perm_lock(this->channel_list_lock); - ChannelPermissionContainer* permission_container = nullptr; - for(auto& entry : this->_channel_permissions) - if(entry->permission == permission && entry->channel_id == channel_id) { - permission_container = &*entry; - break; - } - - /* register a new permission if we have no permission already*/ - if(!permission_container || !permission_container->flags.permission_set()) { /* if the permission isn't set then we have to register it again */ - if(action_value != v2::PermissionUpdateType::set_value && action_grant == v2::PermissionUpdateType::set_value) { - return; /* we were never willing to set this permission */ - } - - if(!permission_container) { - auto container = make_unique(); - container->permission = permission; - container->channel_id = channel_id; - permission_container = &*container; - this->_channel_permissions.push_back(std::move(container)); - } - - /* now set the channel flag for that permission */ - const auto block = this->calculate_block(permission); - this->ref_allocate_block(block); - - auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; - data.flags.channel_specific = true; - this->unref_block(block); - } - - if(action_value == v2::PermissionUpdateType::set_value) { - permission_container->flags.value_set = true; - permission_container->flags.flag_value_update = true; - permission_container->values.value = values.value; - } else if(action_value == v2::PermissionUpdateType::delete_value) { - permission_container->flags.value_set = false; - permission_container->flags.flag_value_update = true; - } - - if(action_grant == v2::PermissionUpdateType::set_value) { - permission_container->flags.grant_set = true; - permission_container->flags.flag_grant_update = true; - permission_container->values.grant = values.grant; - } else if(action_grant == v2::PermissionUpdateType::delete_value) { - permission_container->flags.grant_set = false; - permission_container->flags.flag_grant_update = true; - } - - if(flag_skip >= 0) { - permission_container->flags.flag_value_update = true; - permission_container->flags.skip = flag_skip == 1; - } - - if(flag_negate >= 0) { - permission_container->flags.flag_value_update = true; - permission_container->flags.negate = flag_negate == 1; - } - - if(!permission_container->flags.permission_set()) { /* unregister the permission again because its unset, we delete the channel permission as soon we've flushed the updates */ - auto other_channel_permission = std::find_if(this->_channel_permissions.begin(), this->_channel_permissions.end(), [&](unique_ptr& perm) { return perm->permission == permission && perm->flags.permission_set(); }); - if(other_channel_permission == this->_channel_permissions.end()) { /* no more channel specific permissions c*/ - const auto block = this->calculate_block(permission); - if(this->ref_block(block)) { - this->block_containers[block]->permissions[this->calculate_block_index(permission)].flags.channel_specific = false; - this->unref_block(block); - } - } - } - this->trigger_db_update(); -} - -const std::vector> v2::PermissionRegister::permissions() { - std::unique_lock use_lock(this->block_use_count_lock); - decltype(this->block_containers) block_containers; /* save the states/nullptr's */ - memcpy(block_containers, this->block_containers, sizeof(this->block_containers)); - size_t block_count = 0; - for(size_t index = 0; index < BULK_COUNT; index++) { - if(block_containers[index]) { - block_count++; - this->block_use_count[index]++; - } - } - use_lock.unlock(); - - vector> result; - result.reserve(block_count * PERMISSIONS_BULK_ENTRY_COUNT); - - for(size_t block_index = 0; block_index < BULK_COUNT; block_index++) { - auto& block = block_containers[block_index]; - if(!block) - continue; - - for(size_t permission_index = 0; permission_index < PERMISSIONS_BULK_ENTRY_COUNT; permission_index++) { - auto& permission = block->permissions[permission_index]; - if(!permission.flags.permission_set()) - continue; - - result.emplace_back((PermissionType) (block_index * PERMISSIONS_BULK_ENTRY_COUNT + permission_index), permission); - } - } - result.shrink_to_fit(); - - use_lock.lock(); - for(size_t index = 0; index < BULK_COUNT; index++) { - if(block_containers[index]) - this->block_use_count[index]--; - } - use_lock.unlock(); - - return result; -} - -const vector> v2::PermissionRegister::channel_permissions(ts::ChannelId channel_id) { - shared_lock channel_perm_lock(this->channel_list_lock); - - vector> result; - for(auto& entry : this->_channel_permissions) - if((channel_id == entry->channel_id) && (entry->flags.value_set || entry->flags.grant_set)) - result.emplace_back(entry->permission, v2::PermissionContainer{entry->flags, entry->values}); - return result; -} - -const vector> v2::PermissionRegister::channel_permissions() { - shared_lock channel_perm_lock(this->channel_list_lock); - - vector> result; - for(auto& entry : this->_channel_permissions) - if(entry->flags.value_set || entry->flags.grant_set) - result.emplace_back(entry->permission, entry->channel_id, v2::PermissionContainer{entry->flags, entry->values}); - return result; -} - -const std::vector v2::PermissionRegister::flush_db_updates() { - if(!this->requires_db_save) - return {}; - - this->requires_db_save = false; - std::vector result; - - { - lock_guard use_lock(this->block_use_count_lock); - size_t block_count = 0; - for (auto &block_container : block_containers) - if (block_container) - block_count++; - result.reserve(block_count * PERMISSIONS_BULK_ENTRY_COUNT); - - for(size_t block_index = 0; block_index < BULK_COUNT; block_index++) { - auto& block = block_containers[block_index]; - if(!block) - continue; - - for(size_t permission_index = 0; permission_index < PERMISSIONS_BULK_ENTRY_COUNT; permission_index++) { - auto& permission = block->permissions[permission_index]; - - if(!permission.flags.flag_value_update && !permission.flags.flag_grant_update) - continue; - - /* we only need an update it the permission has a DB reference or we will set the permission */ - if(permission.flags.database_reference || permission.flags.permission_set()) { - /* - PermissionType permission; - ChannelId channel_id; - - PermissionValues values; - PermissionUpdateType update_value; - PermissionUpdateType update_grant; - - bool flag_db: 1; - bool flag_delete: 1; - bool flag_skip: 1; - bool flag_negate: 1; - */ - auto& entry = result.emplace_back(v2::PermissionDBUpdateEntry{ - (PermissionType) (block_index * PERMISSIONS_BULK_ENTRY_COUNT + permission_index), - (ChannelId) 0, - - permission.values, - (PermissionUpdateType) (permission.flags.flag_value_update ? (permission.flags.value_set ? PermissionUpdateType::set_value : PermissionUpdateType::delete_value) : PermissionUpdateType::do_nothing), - (PermissionUpdateType) (permission.flags.flag_grant_update ? (permission.flags.grant_set ? PermissionUpdateType::set_value : PermissionUpdateType::delete_value) : PermissionUpdateType::do_nothing), - - (bool) permission.flags.database_reference, - (bool) !permission.flags.permission_set(), /* db delete */ - (bool) permission.flags.skip, - (bool) permission.flags.negate - }); - - /* required for the database */ - if(!permission.flags.value_set) - entry.values.value = permNotGranted; - - if(!permission.flags.grant_set) - entry.values.grant = permNotGranted; - - permission.flags.database_reference = permission.flags.permission_set(); - } - - permission.flags.flag_value_update = false; - permission.flags.flag_grant_update = false; - } - } - } - { - lock_guard chanel_lock(this->channel_list_lock); - for(size_t index = 0; index < this->_channel_permissions.size(); index++) { - auto& permission = this->_channel_permissions[index]; - if(!permission->flags.flag_value_update && !permission->flags.flag_grant_update) - continue; - - - /* we only need an update it the permission has a DB reference or we will set the permission */ - if(permission->flags.database_reference || permission->flags.permission_set()) { - - auto& entry = result.emplace_back(v2::PermissionDBUpdateEntry{ - permission->permission, - permission->channel_id, - - permission->values, - (PermissionUpdateType) (permission->flags.flag_value_update ? (permission->flags.value_set ? PermissionUpdateType::set_value : PermissionUpdateType::delete_value) : PermissionUpdateType::do_nothing), - (PermissionUpdateType) (permission->flags.flag_grant_update ? (permission->flags.grant_set ? PermissionUpdateType::set_value : PermissionUpdateType::delete_value) : PermissionUpdateType::do_nothing), - - (bool) permission->flags.database_reference, - (bool) !permission->flags.permission_set(), /* db delete */ - (bool) permission->flags.skip, - (bool) permission->flags.negate - }); - - /* required for the database */ - if(!permission->flags.value_set) - entry.values.value = permNotGranted; - - if(!permission->flags.grant_set) - entry.values.grant = permNotGranted; - - permission->flags.database_reference = permission->flags.permission_set(); - } - - permission->flags.flag_value_update = false; - permission->flags.flag_grant_update = false; - if(!permission->flags.permission_set()) { - this->_channel_permissions.erase(this->_channel_permissions.begin() + index); - index--; - } - } - } - - return result; -} - -size_t v2::PermissionRegister::used_memory() { - size_t result = sizeof(*this); - - for (auto &block_container : block_containers) { - if (block_container) - result += sizeof(PermissionContainerBulk); - } - - { - - shared_lock channel_lock(this->channel_list_lock); - result += this->_channel_permissions.size() * (sizeof(ChannelPermissionContainer) + sizeof(unique_ptr)); - } - - return result; -} - -void v2::PermissionRegister::cleanup() { - lock_guard use_lock(this->block_use_count_lock); - - for (auto &block_container : block_containers) { - if (!block_container) continue; - - bool used = false; - for(auto& permission : block_container->permissions) { - if(permission.flags.value_set || permission.flags.grant_set || permission.flags.channel_specific) { - used = true; - break; - } - } - if(used) - continue; - - delete block_container; - block_container = nullptr; - } -} +#include +#include +#include "misc/memtracker.h" +#include "BasicChannel.h" +#include "log/LogUtils.h" + +using namespace std; +using namespace ts; +using namespace ts::permission; + +deque> ts::permission::availablePermissions = deque>{ + make_shared(PermissionType::b_serverinstance_help_view, PermissionGroup::global_info, "b_serverinstance_help_view", "Retrieve information about ServerQuery commands"), + make_shared(PermissionType::b_serverinstance_version_view, PermissionGroup::global_info, "b_serverinstance_version_view", "Retrieve global server version (including platform and build number)"), + make_shared(PermissionType::b_serverinstance_info_view, PermissionGroup::global_info, "b_serverinstance_info_view", "Retrieve global server information"), + make_shared(PermissionType::b_serverinstance_virtualserver_list, PermissionGroup::global_info, "b_serverinstance_virtualserver_list", "List virtual servers stored in the sql"), + make_shared(PermissionType::b_serverinstance_binding_list, PermissionGroup::global_info, "b_serverinstance_binding_list", "List active IP bindings on multi-homed machines"), + //Removed due its useless + make_shared(PermissionType::b_serverinstance_permission_list, PermissionGroup::global_info, "b_serverinstance_permission_list", "List permissions available available on the server instance"), + make_shared(PermissionType::b_serverinstance_permission_find, PermissionGroup::global_info, "b_serverinstance_permission_find", "Search permission assignments by name or ID"), + make_shared(PermissionType::b_virtualserver_create, PermissionGroup::global_vsmanage, "b_virtualserver_create", "Create virtual servers"), + make_shared(PermissionType::b_virtualserver_delete, PermissionGroup::global_vsmanage, "b_virtualserver_delete", "Delete virtual servers"), + make_shared(PermissionType::b_virtualserver_start_any, PermissionGroup::global_vsmanage, "b_virtualserver_start_any", "Start any virtual server in the server instance"), + make_shared(PermissionType::b_virtualserver_stop_any, PermissionGroup::global_vsmanage, "b_virtualserver_stop_any", "Stop any virtual server in the server instance"), + make_shared(PermissionType::b_virtualserver_change_machine_id, PermissionGroup::global_vsmanage, "b_virtualserver_change_machine_id", "Change a virtual servers machine ID"), + make_shared(PermissionType::b_virtualserver_change_template, PermissionGroup::global_vsmanage, "b_virtualserver_change_template", "Edit virtual server default template values"), + make_shared(PermissionType::b_serverquery_login, PermissionGroup::global_admin, "b_serverquery_login", "Login to ServerQuery"), + make_shared(PermissionType::b_serverinstance_textmessage_send, PermissionGroup::global_admin, "b_serverinstance_textmessage_send", "Send text messages to all virtual servers at once"), + make_shared(PermissionType::b_serverinstance_log_view, PermissionGroup::global_admin, "b_serverinstance_log_view", "Retrieve global server log"), + make_shared(PermissionType::b_serverinstance_log_add, PermissionGroup::global_admin, "b_serverinstance_log_add", "Write to global server log"), + make_shared(PermissionType::b_serverinstance_stop, PermissionGroup::global_admin, "b_serverinstance_stop", "Shutdown the server process"), + make_shared(PermissionType::b_serverinstance_modify_settings, PermissionGroup::global_settings, "b_serverinstance_modify_settings", "Edit global settings"), + make_shared(PermissionType::b_serverinstance_modify_querygroup, PermissionGroup::global_settings, "b_serverinstance_modify_querygroup", "Edit global ServerQuery groups"), + make_shared(PermissionType::b_serverinstance_modify_templates, PermissionGroup::global_settings, "b_serverinstance_modify_templates", "Edit global template groups"), + make_shared(PermissionType::b_virtualserver_select, PermissionGroup::vs_info, "b_virtualserver_select", "Select a virtual server"), + make_shared(PermissionType::b_virtualserver_select_godmode, PermissionGroup::vs_info, "b_virtualserver_select_godmode", "Select a virtual server but be invisible"), + make_shared(PermissionType::b_virtualserver_info_view, PermissionGroup::vs_info, "b_virtualserver_info_view", "Retrieve virtual server information"), + make_shared(PermissionType::b_virtualserver_connectioninfo_view, PermissionGroup::vs_info, "b_virtualserver_connectioninfo_view", "Retrieve virtual server connection information"), + make_shared(PermissionType::b_virtualserver_channel_list, PermissionGroup::vs_info, "b_virtualserver_channel_list", "List channels on a virtual server"), + make_shared(PermissionType::b_virtualserver_channel_search, PermissionGroup::vs_info, "b_virtualserver_channel_search", "Search for channels on a virtual server"), + make_shared(PermissionType::b_virtualserver_client_list, PermissionGroup::vs_info, "b_virtualserver_client_list", "List clients online on a virtual server"), + make_shared(PermissionType::b_virtualserver_client_search, PermissionGroup::vs_info, "b_virtualserver_client_search", "Search for clients online on a virtual server"), + make_shared(PermissionType::b_virtualserver_client_dblist, PermissionGroup::vs_info, "b_virtualserver_client_dblist", "List client identities known by the virtual server"), + make_shared(PermissionType::b_virtualserver_client_dbsearch, PermissionGroup::vs_info, "b_virtualserver_client_dbsearch", "Search for client identities known by the virtual server"), + make_shared(PermissionType::b_virtualserver_client_dbinfo, PermissionGroup::vs_info, "b_virtualserver_client_dbinfo", "Retrieve client information"), + make_shared(PermissionType::b_virtualserver_permission_find, PermissionGroup::vs_info, "b_virtualserver_permission_find", "Find permissions"), + make_shared(PermissionType::b_virtualserver_custom_search, PermissionGroup::vs_info, "b_virtualserver_custom_search", "Find custom fields"), + make_shared(PermissionType::b_virtualserver_start, PermissionGroup::vs_admin, "b_virtualserver_start", "Start own virtual server"), + make_shared(PermissionType::b_virtualserver_stop, PermissionGroup::vs_admin, "b_virtualserver_stop", "Stop own virtual server"), + make_shared(PermissionType::b_virtualserver_token_list, PermissionGroup::vs_admin, "b_virtualserver_token_list", "List privilege keys available"), + make_shared(PermissionType::b_virtualserver_token_add, PermissionGroup::vs_admin, "b_virtualserver_token_add", "Create new privilege keys"), + make_shared(PermissionType::b_virtualserver_token_use, PermissionGroup::vs_admin, "b_virtualserver_token_use", "Use a privilege keys to gain access to groups"), + make_shared(PermissionType::b_virtualserver_token_delete, PermissionGroup::vs_admin, "b_virtualserver_token_delete", "Delete a privilege key"), + make_shared(PermissionType::b_virtualserver_log_view, PermissionGroup::vs_admin, "b_virtualserver_log_view", "Retrieve virtual server log"), + make_shared(PermissionType::b_virtualserver_log_add, PermissionGroup::vs_admin, "b_virtualserver_log_add", "Write to virtual server log"), + make_shared(PermissionType::b_virtualserver_join_ignore_password, PermissionGroup::vs_admin, "b_virtualserver_join_ignore_password", "Join virtual server ignoring its password"), + make_shared(PermissionType::b_virtualserver_notify_register, PermissionGroup::vs_admin, "b_virtualserver_notify_register", "Register for server notifications"), + make_shared(PermissionType::b_virtualserver_notify_unregister, PermissionGroup::vs_admin, "b_virtualserver_notify_unregister", "Unregister from server notifications"), + make_shared(PermissionType::b_virtualserver_snapshot_create, PermissionGroup::vs_admin, "b_virtualserver_snapshot_create", "Create server snapshots"), + make_shared(PermissionType::b_virtualserver_snapshot_deploy, PermissionGroup::vs_admin, "b_virtualserver_snapshot_deploy", "Deploy server snapshots"), + make_shared(PermissionType::b_virtualserver_permission_reset, PermissionGroup::vs_admin, "b_virtualserver_permission_reset", "Reset the server permission settings to default values"), + make_shared(PermissionType::b_virtualserver_modify_name, PermissionGroup::vs_settings, "b_virtualserver_modify_name", "Modify server name"), + make_shared(PermissionType::b_virtualserver_modify_welcomemessage, PermissionGroup::vs_settings, "b_virtualserver_modify_welcomemessage", "Modify welcome message"), + make_shared(PermissionType::b_virtualserver_modify_maxchannels, PermissionGroup::vs_settings, "b_virtualserver_modify_maxchannels", "Modify servers max channels"), + make_shared(PermissionType::b_virtualserver_modify_maxclients, PermissionGroup::vs_settings, "b_virtualserver_modify_maxclients", "Modify servers max clients"), + make_shared(PermissionType::b_virtualserver_modify_reserved_slots, PermissionGroup::vs_settings, "b_virtualserver_modify_reserved_slots", "Modify reserved slots"), + make_shared(PermissionType::b_virtualserver_modify_password, PermissionGroup::vs_settings, "b_virtualserver_modify_password", "Modify server password"), + make_shared(PermissionType::b_virtualserver_modify_default_servergroup, PermissionGroup::vs_settings, "b_virtualserver_modify_default_servergroup", "Modify default Server Group"), + make_shared(PermissionType::b_virtualserver_modify_default_musicgroup, PermissionGroup::vs_settings, "b_virtualserver_modify_default_musicgroup", "Modify default music Group"), + make_shared(PermissionType::b_virtualserver_modify_default_channelgroup, PermissionGroup::vs_settings, "b_virtualserver_modify_default_channelgroup", "Modify default Channel Group"), + make_shared(PermissionType::b_virtualserver_modify_default_channeladmingroup, PermissionGroup::vs_settings, "b_virtualserver_modify_default_channeladmingroup", "Modify default Channel Admin Group"), + make_shared(PermissionType::b_virtualserver_modify_channel_forced_silence, PermissionGroup::vs_settings, "b_virtualserver_modify_channel_forced_silence", "Modify channel force silence value"), + make_shared(PermissionType::b_virtualserver_modify_complain, PermissionGroup::vs_settings, "b_virtualserver_modify_complain", "Modify individual complain settings"), + make_shared(PermissionType::b_virtualserver_modify_antiflood, PermissionGroup::vs_settings, "b_virtualserver_modify_antiflood", "Modify individual antiflood settings"), + make_shared(PermissionType::b_virtualserver_modify_ft_settings, PermissionGroup::vs_settings, "b_virtualserver_modify_ft_settings", "Modify file transfer settings"), + make_shared(PermissionType::b_virtualserver_modify_ft_quotas, PermissionGroup::vs_settings, "b_virtualserver_modify_ft_quotas", "Modify file transfer quotas"), + make_shared(PermissionType::b_virtualserver_modify_hostmessage, PermissionGroup::vs_settings, "b_virtualserver_modify_hostmessage", "Modify individual hostmessage settings"), + make_shared(PermissionType::b_virtualserver_modify_hostbanner, PermissionGroup::vs_settings, "b_virtualserver_modify_hostbanner", "Modify individual hostbanner settings"), + make_shared(PermissionType::b_virtualserver_modify_hostbutton, PermissionGroup::vs_settings, "b_virtualserver_modify_hostbutton", "Modify individual hostbutton settings"), + make_shared(PermissionType::b_virtualserver_modify_port, PermissionGroup::vs_settings, "b_virtualserver_modify_port", "Modify server port"), +#ifndef LAGENCY + make_shared(PermissionType::b_virtualserver_modify_host, PermissionGroup::vs_settings, "b_virtualserver_modify_host", "Modify server host"), +#endif + make_shared(PermissionType::b_virtualserver_modify_autostart, PermissionGroup::vs_settings, "b_virtualserver_modify_autostart", "Modify server autostart"), + make_shared(PermissionType::b_virtualserver_modify_needed_identity_security_level, PermissionGroup::vs_settings, "b_virtualserver_modify_needed_identity_security_level", "Modify required identity security level"), + make_shared(PermissionType::b_virtualserver_modify_priority_speaker_dimm_modificator, PermissionGroup::vs_settings, "b_virtualserver_modify_priority_speaker_dimm_modificator", "Modify priority speaker dimm modificator"), + make_shared(PermissionType::b_virtualserver_modify_log_settings, PermissionGroup::vs_settings, "b_virtualserver_modify_log_settings", "Modify log settings"), + make_shared(PermissionType::b_virtualserver_modify_min_client_version, PermissionGroup::vs_settings, "b_virtualserver_modify_min_client_version", "Modify min client version"), + make_shared(PermissionType::b_virtualserver_modify_icon_id, PermissionGroup::vs_settings, "b_virtualserver_modify_icon_id", "Modify server icon"), + make_shared(PermissionType::b_virtualserver_modify_weblist, PermissionGroup::vs_settings, "b_virtualserver_modify_weblist", "Modify web server list reporting settings"), + make_shared(PermissionType::b_virtualserver_modify_country_code, PermissionGroup::vs_settings, "b_virtualserver_modify_country_code", "Modify servers country code property"), + make_shared(PermissionType::b_virtualserver_modify_codec_encryption_mode, PermissionGroup::vs_settings, "b_virtualserver_modify_codec_encryption_mode", "Modify codec encryption mode"), + make_shared(PermissionType::b_virtualserver_modify_temporary_passwords, PermissionGroup::vs_settings, "b_virtualserver_modify_temporary_passwords", "Modify temporary serverpasswords"), + make_shared(PermissionType::b_virtualserver_modify_temporary_passwords_own, PermissionGroup::vs_settings, "b_virtualserver_modify_temporary_passwords_own", "Modify own temporary serverpasswords"), + make_shared(PermissionType::b_virtualserver_modify_channel_temp_delete_delay_default, PermissionGroup::vs_settings, "b_virtualserver_modify_channel_temp_delete_delay_default", "Modify default temporary channel delete delay"), + make_shared(PermissionType::b_virtualserver_modify_music_bot_limit, PermissionGroup::vs_settings, "b_virtualserver_modify_music_bot_limit", "Allow client to edit the server music bot limit"), + make_shared(PermissionType::b_virtualserver_modify_default_messages, PermissionGroup::vs_settings, "b_virtualserver_modify_default_messages", "Allows the client to edit the default messages"), + make_shared(PermissionType::i_channel_min_depth, PermissionGroup::channel, "i_channel_min_depth", "Min channel creation depth in hierarchy"), + make_shared(PermissionType::i_channel_max_depth, PermissionGroup::channel, "i_channel_max_depth", "Max channel creation depth in hierarchy"), + make_shared(PermissionType::b_channel_group_inheritance_end, PermissionGroup::channel, "b_channel_group_inheritance_end", "Stop inheritance of channel group permissions"), + make_shared(PermissionType::i_channel_permission_modify_power, PermissionGroup::channel, "i_channel_permission_modify_power", "Modify channel permission power"), + make_shared(PermissionType::i_channel_needed_permission_modify_power, PermissionGroup::channel, "i_channel_needed_permission_modify_power", "Needed modify channel permission power"), + make_shared(PermissionType::b_channel_info_view, PermissionGroup::channel_info, "b_channel_info_view", "Retrieve channel information"), + make_shared(PermissionType::b_channel_create_child, PermissionGroup::channel_create, "b_channel_create_child", "Create sub-channels"), + make_shared(PermissionType::b_channel_create_permanent, PermissionGroup::channel_create, "b_channel_create_permanent", "Create permanent channels"), + make_shared(PermissionType::b_channel_create_semi_permanent, PermissionGroup::channel_create, "b_channel_create_semi_permanent", "Create semi-permanent channels"), + make_shared(PermissionType::b_channel_create_temporary, PermissionGroup::channel_create, "b_channel_create_temporary", "Create temporary channels"), + make_shared(PermissionType::b_channel_create_private, PermissionGroup::channel_create, "b_channel_create_private", "Create private channel"), + make_shared(PermissionType::b_channel_create_with_topic, PermissionGroup::channel_create, "b_channel_create_with_topic", "Create channels with a topic"), + make_shared(PermissionType::b_channel_create_with_description, PermissionGroup::channel_create, "b_channel_create_with_description", "Create channels with a description"), + make_shared(PermissionType::b_channel_create_with_password, PermissionGroup::channel_create, "b_channel_create_with_password", "Create password protected channels"), + make_shared(PermissionType::b_channel_create_modify_with_codec_speex8, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_speex8", "Create channels using Speex Narrowband (8 kHz) codecs"), + make_shared(PermissionType::b_channel_create_modify_with_codec_speex16, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_speex16", "Create channels using Speex Wideband (16 kHz) codecs"), + make_shared(PermissionType::b_channel_create_modify_with_codec_speex32, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_speex32", "Create channels using Speex Ultra-Wideband (32 kHz) codecs"), + make_shared(PermissionType::b_channel_create_modify_with_codec_celtmono48, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_celtmono48", "Create channels using the CELT Mono (48 kHz) codec"), + make_shared(PermissionType::b_channel_create_modify_with_codec_opusvoice, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_opusvoice", "Create channels using OPUS (voice) codec"), + make_shared(PermissionType::b_channel_create_modify_with_codec_opusmusic, PermissionGroup::channel_create, "b_channel_create_modify_with_codec_opusmusic", "Create channels using OPUS (music) codec"), + make_shared(PermissionType::i_channel_create_modify_with_codec_maxquality, PermissionGroup::channel_create, "i_channel_create_modify_with_codec_maxquality", "Create channels with custom codec quality"), + make_shared(PermissionType::i_channel_create_modify_with_codec_latency_factor_min, PermissionGroup::channel_create, "i_channel_create_modify_with_codec_latency_factor_min", "Create channels with minimal custom codec latency factor"), + make_shared(PermissionType::b_channel_create_with_maxclients, PermissionGroup::channel_create, "b_channel_create_with_maxclients", "Create channels with custom max clients"), + make_shared(PermissionType::b_channel_create_with_maxfamilyclients, PermissionGroup::channel_create, "b_channel_create_with_maxfamilyclients", "Create channels with custom max family clients"), + make_shared(PermissionType::b_channel_create_with_sortorder, PermissionGroup::channel_create, "b_channel_create_with_sortorder", "Create channels with custom sort order"), + make_shared(PermissionType::b_channel_create_with_default, PermissionGroup::channel_create, "b_channel_create_with_default", "Create default channels"), + make_shared(PermissionType::b_channel_create_with_needed_talk_power, PermissionGroup::channel_create, "b_channel_create_with_needed_talk_power", "Create channels with needed talk power"), + make_shared(PermissionType::b_channel_create_modify_with_force_password, PermissionGroup::channel_create, "b_channel_create_modify_with_force_password", "Create new channels only with password"), + make_shared(PermissionType::i_channel_create_modify_with_temp_delete_delay, PermissionGroup::channel_create, "i_channel_create_modify_with_temp_delete_delay", "Max delete delay for temporary channels"), + make_shared(PermissionType::i_channel_create_modify_conversation_history_length, PermissionGroup::channel_create, "i_channel_create_modify_conversation_history_length", "Upper limmit for the setting of the max conversation history limit"), + make_shared(PermissionType::b_channel_create_modify_conversation_history_unlimited, PermissionGroup::channel_create, "b_channel_create_modify_conversation_history_unlimited", "Allows the user to set the channel conversation history to unlimited"), + make_shared(PermissionType::b_channel_create_modify_conversation_private, PermissionGroup::channel_create, "b_channel_create_modify_conversation_private", "Allows the user to set the channel conversation to private"), + make_shared(PermissionType::b_channel_modify_parent, PermissionGroup::channel_modify, "b_channel_modify_parent", "Move channels"), + make_shared(PermissionType::b_channel_modify_make_default, PermissionGroup::channel_modify, "b_channel_modify_make_default", "Make channel default"), + make_shared(PermissionType::b_channel_modify_make_permanent, PermissionGroup::channel_modify, "b_channel_modify_make_permanent", "Make channel permanent"), + make_shared(PermissionType::b_channel_modify_make_semi_permanent, PermissionGroup::channel_modify, "b_channel_modify_make_semi_permanent", "Make channel semi-permanent"), + make_shared(PermissionType::b_channel_modify_make_temporary, PermissionGroup::channel_modify, "b_channel_modify_make_temporary", "Make channel temporary"), + make_shared(PermissionType::b_channel_modify_name, PermissionGroup::channel_modify, "b_channel_modify_name", "Modify channel name"), + make_shared(PermissionType::b_channel_modify_topic, PermissionGroup::channel_modify, "b_channel_modify_topic", "Modify channel topic"), + make_shared(PermissionType::b_channel_modify_description, PermissionGroup::channel_modify, "b_channel_modify_description", "Modify channel description"), + make_shared(PermissionType::b_channel_modify_password, PermissionGroup::channel_modify, "b_channel_modify_password", "Modify channel password"), + make_shared(PermissionType::b_channel_modify_codec, PermissionGroup::channel_modify, "b_channel_modify_codec", "Modify channel codec"), + make_shared(PermissionType::b_channel_modify_codec_quality, PermissionGroup::channel_modify, "b_channel_modify_codec_quality", "Modify channel codec quality"), + make_shared(PermissionType::b_channel_modify_codec_latency_factor, PermissionGroup::channel_modify, "b_channel_modify_codec_latency_factor", "Modify channel codec latency factor"), + make_shared(PermissionType::b_channel_modify_maxclients, PermissionGroup::channel_modify, "b_channel_modify_maxclients", "Modify channels max clients"), + make_shared(PermissionType::b_channel_modify_maxfamilyclients, PermissionGroup::channel_modify, "b_channel_modify_maxfamilyclients", "Modify channels max family clients"), + make_shared(PermissionType::b_channel_modify_sortorder, PermissionGroup::channel_modify, "b_channel_modify_sortorder", "Modify channel sort order"), + make_shared(PermissionType::b_channel_modify_needed_talk_power, PermissionGroup::channel_modify, "b_channel_modify_needed_talk_power", "Change needed channel talk power"), + make_shared(PermissionType::i_channel_modify_power, PermissionGroup::channel_modify, "i_channel_modify_power", "Channel modify power"), + make_shared(PermissionType::i_channel_needed_modify_power, PermissionGroup::channel_modify, "i_channel_needed_modify_power", "Needed channel modify power"), + make_shared(PermissionType::b_channel_modify_make_codec_encrypted, PermissionGroup::channel_modify, "b_channel_modify_make_codec_encrypted", "Make channel codec encrypted"), + make_shared(PermissionType::b_channel_modify_temp_delete_delay, PermissionGroup::channel_modify, "b_channel_modify_temp_delete_delay", "Modify temporary channel delete delay"), + make_shared(PermissionType::b_channel_conversation_message_delete, PermissionGroup::channel_modify, "b_channel_conversation_message_delete", "If set the user is able to delete conversation messages"), + + make_shared(PermissionType::b_channel_delete_permanent, PermissionGroup::channel_delete, "b_channel_delete_permanent", "Delete permanent channels"), + make_shared(PermissionType::b_channel_delete_semi_permanent, PermissionGroup::channel_delete, "b_channel_delete_semi_permanent", "Delete semi-permanent channels"), + make_shared(PermissionType::b_channel_delete_temporary, PermissionGroup::channel_delete, "b_channel_delete_temporary", "Delete temporary channels"), + make_shared(PermissionType::b_channel_delete_flag_force, PermissionGroup::channel_delete, "b_channel_delete_flag_force", "Force channel delete"), + make_shared(PermissionType::i_channel_delete_power, PermissionGroup::channel_delete, "i_channel_delete_power", "Delete channel power"), + make_shared(PermissionType::i_channel_needed_delete_power, PermissionGroup::channel_delete, "i_channel_needed_delete_power", "Needed delete channel power"), + make_shared(PermissionType::b_channel_join_permanent, PermissionGroup::channel_access, "b_channel_join_permanent", "Join permanent channels"), + make_shared(PermissionType::b_channel_join_semi_permanent, PermissionGroup::channel_access, "b_channel_join_semi_permanent", "Join semi-permanent channels"), + make_shared(PermissionType::b_channel_join_temporary, PermissionGroup::channel_access, "b_channel_join_temporary", "Join temporary channels"), + make_shared(PermissionType::b_channel_join_ignore_password, PermissionGroup::channel_access, "b_channel_join_ignore_password", "Join channel ignoring its password"), + make_shared(PermissionType::b_channel_join_ignore_maxclients, PermissionGroup::channel_access, "b_channel_join_ignore_maxclients", "Ignore channels max clients limit"), + make_shared(PermissionType::b_channel_ignore_view_power, PermissionGroup::channel_access, "b_channel_ignore_view_power", "If set the client see's every channel"), + make_shared(PermissionType::i_channel_join_power, PermissionGroup::channel_access, "i_channel_join_power", "Channel join power"), + make_shared(PermissionType::i_channel_needed_join_power, PermissionGroup::channel_access, "i_channel_needed_join_power", "Needed channel join power"), + make_shared(PermissionType::b_channel_ignore_join_power, PermissionGroup::channel_access, "b_channel_ignore_join_power", "Allows the client to bypass the channel join power"), + make_shared(PermissionType::i_channel_view_power, PermissionGroup::channel_access, "i_channel_view_power", "Channel view power"), + make_shared(PermissionType::i_channel_needed_view_power, PermissionGroup::channel_access, "i_channel_needed_view_power", "Needed channel view power"), + make_shared(PermissionType::i_channel_subscribe_power, PermissionGroup::channel_access, "i_channel_subscribe_power", "Channel subscribe power"), + make_shared(PermissionType::i_channel_needed_subscribe_power, PermissionGroup::channel_access, "i_channel_needed_subscribe_power", "Needed channel subscribe power"), + make_shared(PermissionType::b_channel_ignore_subscribe_power, PermissionGroup::channel_access, "b_channel_ignore_subscribe_power", "Allows the client to bypass the subscribe power"), + make_shared(PermissionType::i_channel_description_view_power, PermissionGroup::channel_access, "i_channel_description_view_power", "Channel description view power"), + make_shared(PermissionType::i_channel_needed_description_view_power, PermissionGroup::channel_access, "i_channel_needed_description_view_power", "Needed channel needed description view power"), + make_shared(PermissionType::b_channel_ignore_description_view_power, PermissionGroup::channel_access, "b_channel_ignore_description_view_power", "Allows the client to bypass the channel description view power"), + make_shared(PermissionType::i_icon_id, PermissionGroup::group, "i_icon_id", "Group icon identifier"), + make_shared(PermissionType::i_max_icon_filesize, PermissionGroup::group, "i_max_icon_filesize", "Max icon filesize in bytes"), + make_shared(PermissionType::i_max_playlist_size, PermissionGroup::group, "i_max_playlist_size", "Max songs within one playlist"), + make_shared(PermissionType::i_max_playlists, PermissionGroup::group, "i_max_playlists", "Max amount of playlists a client could own"), + make_shared(PermissionType::b_icon_manage, PermissionGroup::group, "b_icon_manage", "Enables icon management"), + make_shared(PermissionType::b_group_is_permanent, PermissionGroup::group, "b_group_is_permanent", "Group is permanent"), + make_shared(PermissionType::i_group_auto_update_type, PermissionGroup::group, "i_group_auto_update_type", "Group auto-update type"), + make_shared(PermissionType::i_group_auto_update_max_value, PermissionGroup::group, "i_group_auto_update_max_value", "Group auto-update max value"), + make_shared(PermissionType::i_group_sort_id, PermissionGroup::group, "i_group_sort_id", "Group sort id"), + make_shared(PermissionType::i_group_show_name_in_tree, PermissionGroup::group, "i_group_show_name_in_tree", "Show group name in tree depending on selected mode"), + make_shared(PermissionType::b_virtualserver_servergroup_list, PermissionGroup::group_info, "b_virtualserver_servergroup_list", "List server groups"), + make_shared(PermissionType::b_virtualserver_servergroup_permission_list, PermissionGroup::group_info, "b_virtualserver_servergroup_permission_list", "Allows the client to view all server group permissions"), + make_shared(PermissionType::b_virtualserver_servergroup_client_list, PermissionGroup::group_info, "b_virtualserver_servergroup_client_list", "List clients from a server group"), + make_shared(PermissionType::b_virtualserver_channelgroup_list, PermissionGroup::group_info, "b_virtualserver_channelgroup_list", "List channel groups"), + make_shared(PermissionType::b_virtualserver_channelgroup_permission_list, PermissionGroup::group_info, "b_virtualserver_channelgroup_permission_list", "Allows the client to view all channel group permissions"), + make_shared(PermissionType::b_virtualserver_channelgroup_client_list, PermissionGroup::group_info, "b_virtualserver_channelgroup_client_list", "List clients from a channel group"), + make_shared(PermissionType::b_virtualserver_client_permission_list, PermissionGroup::group_info, "b_virtualserver_client_permission_list", "Allows the client to view all client permissions"), + make_shared(PermissionType::b_virtualserver_channel_permission_list, PermissionGroup::group_info, "b_virtualserver_channel_permission_list", "Allows the client to view all channel permissions"), + make_shared(PermissionType::b_virtualserver_channelclient_permission_list, PermissionGroup::group_info, "b_virtualserver_channelclient_permission_list", "Allows the client to view all client channel permissions"), + make_shared(PermissionType::b_virtualserver_playlist_permission_list, PermissionGroup::group_info, "b_virtualserver_playlist_permission_list", "Allows the client to view all playlist permissions"), + make_shared(PermissionType::b_virtualserver_servergroup_create, PermissionGroup::group_create, "b_virtualserver_servergroup_create", "Create server groups"), + make_shared(PermissionType::b_virtualserver_channelgroup_create, PermissionGroup::group_create, "b_virtualserver_channelgroup_create", "Create channel groups"), + +#ifdef LAGENCY + make_shared(PermissionType::i_group_modify_power, PermissionGroup::group_168, "i_group_modify_power", "Group modify power"), + make_shared(PermissionType::i_group_needed_modify_power, PermissionGroup::group_168, "i_group_needed_modify_power", "Needed group modify power"), + make_shared(PermissionType::i_group_member_add_power, PermissionGroup::group_168, "i_group_member_add_power", "Group member add power"), + make_shared(PermissionType::i_group_needed_member_add_power, PermissionGroup::group_168, "i_group_needed_member_add_power", "Needed group member add power"), + make_shared(PermissionType::i_group_member_remove_power, PermissionGroup::group_168, "i_group_member_remove_power", "Group member delete power"), + make_shared(PermissionType::i_group_needed_member_remove_power, PermissionGroup::group_168, "i_group_needed_member_remove_power", "Needed group member delete power"), +#else + make_shared(PermissionType::i_server_group_modify_power, PermissionGroup::group_modify, "i_server_group_modify_power", "Server group modify power"), + make_shared(PermissionType::i_server_group_needed_modify_power, PermissionGroup::group_modify, "i_server_group_needed_modify_power", "Needed server group modify power"), + make_shared(PermissionType::i_server_group_member_add_power, PermissionGroup::group_modify, "i_server_group_member_add_power", "Server group member add power"), + make_shared(PermissionType::i_server_group_self_add_power, PermissionGroup::group_modify, "i_server_group_self_add_power", "Server group self add power"), + make_shared(PermissionType::i_server_group_needed_member_add_power, PermissionGroup::group_modify, "i_server_group_needed_member_add_power", "Needed server group member add power"), + make_shared(PermissionType::i_server_group_member_remove_power, PermissionGroup::group_modify, "i_server_group_member_remove_power", "Server group member delete power"), + make_shared(PermissionType::i_server_group_self_remove_power, PermissionGroup::group_modify, "i_server_group_self_remove_power", "Server group self delete power"), + make_shared(PermissionType::i_server_group_needed_member_remove_power, PermissionGroup::group_modify, "i_server_group_needed_member_remove_power", "Needed server group member delete power"), + + make_shared(PermissionType::i_channel_group_modify_power, PermissionGroup::group_modify, "i_channel_group_modify_power", "Channel group modify power"), + make_shared(PermissionType::i_channel_group_needed_modify_power, PermissionGroup::group_modify, "i_channel_group_needed_modify_power", "Needed channel group modify power"), + make_shared(PermissionType::i_channel_group_member_add_power, PermissionGroup::group_modify, "i_channel_group_member_add_power", "Channel group member add power"), + make_shared(PermissionType::i_channel_group_self_add_power, PermissionGroup::group_modify, "i_channel_group_self_add_power", "Channel group self add power"), + make_shared(PermissionType::i_channel_group_needed_member_add_power, PermissionGroup::group_modify, "i_channel_group_needed_member_add_power", "Needed channel group member add power"), + make_shared(PermissionType::i_channel_group_member_remove_power, PermissionGroup::group_modify, "i_channel_group_member_remove_power", "Channel group member delete power"), + make_shared(PermissionType::i_channel_group_self_remove_power, PermissionGroup::group_modify, "i_channel_group_self_remove_power", "Channel group self delete power"), + make_shared(PermissionType::i_channel_group_needed_member_remove_power, PermissionGroup::group_modify, "i_channel_group_needed_member_remove_power", "Needed channel group member delete power"), + + //old enum mapping + make_shared(PermissionType::i_displayed_group_member_add_power, PermissionGroup::group_modify, "i_group_member_add_power", "The displayed member add power (Enables/Disabled the group in the select menu)"), + make_shared(PermissionType::i_displayed_group_needed_member_add_power, PermissionGroup::group_modify, "i_group_needed_member_add_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)"), + make_shared(PermissionType::i_displayed_group_member_remove_power, PermissionGroup::group_modify, "i_group_member_remove_power", "The displayed member add power (Enables/Disabled the group in the select menu)"), + make_shared(PermissionType::i_displayed_group_needed_member_remove_power, PermissionGroup::group_modify, "i_group_needed_member_remove_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)"), + make_shared(PermissionType::i_displayed_group_modify_power, PermissionGroup::group_modify, "i_group_modify_power", "The displayed member add power (Enables/Disabled the group in the select menu)"), + make_shared(PermissionType::i_displayed_group_needed_modify_power, PermissionGroup::group_modify, "i_group_needed_modify_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)"), + + //new enum mapping (must come AFTER the supported permissions) + make_shared(PermissionType::i_displayed_group_member_add_power, PermissionGroup::group_modify, "i_displayed_group_member_add_power", "The displayed member add power (Enables/Disabled the group in the select menu)", false), + make_shared(PermissionType::i_displayed_group_needed_member_add_power, PermissionGroup::group_modify, "i_displayed_group_needed_member_add_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)", false), + make_shared(PermissionType::i_displayed_group_member_remove_power, PermissionGroup::group_modify, "i_displayed_group_member_remove_power", "The displayed member add power (Enables/Disabled the group in the select menu)", false), + make_shared(PermissionType::i_displayed_group_needed_member_remove_power, PermissionGroup::group_modify, "i_displayed_group_needed_member_remove_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)", false), + make_shared(PermissionType::i_displayed_group_modify_power, PermissionGroup::group_modify, "i_displayed_group_modify_power", "The displayed member add power (Enables/Disabled the group in the select menu)", false), + make_shared(PermissionType::i_displayed_group_needed_modify_power, PermissionGroup::group_modify, "i_displayed_group_needed_modify_power", "The needed displayed member add power (Enables/Disabled the group in the select menu)", false), +#endif + + make_shared(PermissionType::i_permission_modify_power, PermissionGroup::group_modify, "i_permission_modify_power", "Permission modify power"), + make_shared(PermissionType::b_permission_modify_power_ignore, PermissionGroup::group_modify, "b_permission_modify_power_ignore", "Ignore needed permission modify power"), + make_shared(PermissionType::b_virtualserver_servergroup_delete, PermissionGroup::group_delete, "b_virtualserver_servergroup_delete", "Delete server groups"), + make_shared(PermissionType::b_virtualserver_channelgroup_delete, PermissionGroup::group_delete, "b_virtualserver_channelgroup_delete", "Delete channel groups"), + make_shared(PermissionType::i_client_permission_modify_power, PermissionGroup::client, "i_client_permission_modify_power", "Client permission modify power"), + make_shared(PermissionType::i_client_needed_permission_modify_power, PermissionGroup::client, "i_client_needed_permission_modify_power", "Needed client permission modify power"), + make_shared(PermissionType::i_client_max_clones_uid, PermissionGroup::client, "i_client_max_clones_uid", "Max additional connections per client identity"), + make_shared(PermissionType::i_client_max_clones_ip, PermissionGroup::client, "i_client_max_clones_ip", "Max additional connections per client address"), + make_shared(PermissionType::i_client_max_clones_hwid, PermissionGroup::client, "i_client_max_clones_hwid", "Max additional connections per client hardware id"), + make_shared(PermissionType::i_client_max_idletime, PermissionGroup::client, "i_client_max_idletime", "Max idle time in seconds"), + make_shared(PermissionType::i_client_max_avatar_filesize, PermissionGroup::client, "i_client_max_avatar_filesize", "Max avatar filesize in bytes"), + make_shared(PermissionType::i_client_max_channel_subscriptions, PermissionGroup::client, "i_client_max_channel_subscriptions", "Max channel subscriptions"), + make_shared(PermissionType::i_client_max_channels, PermissionGroup::client, "i_client_max_channels", "Limit of created channels"), + make_shared(PermissionType::i_client_max_temporary_channels, PermissionGroup::client, "i_client_max_temporary_channels", "Limit of created temporary channels"), + make_shared(PermissionType::i_client_max_semi_channels, PermissionGroup::client, "i_client_max_semi_channels", "Limit of created semi-permanent channels"), + make_shared(PermissionType::i_client_max_permanent_channels, PermissionGroup::client, "i_client_max_permanent_channels", "Limit of created permanent channels"), + make_shared(PermissionType::b_client_use_priority_speaker, PermissionGroup::client, "b_client_use_priority_speaker", "Allows the client to use priority speaker"), + make_shared(PermissionType::b_client_is_priority_speaker, PermissionGroup::client, "b_client_is_priority_speaker", "Toogels the client priority speaker mode"), + make_shared(PermissionType::b_client_skip_channelgroup_permissions, PermissionGroup::client, "b_client_skip_channelgroup_permissions", "Ignore channel group permissions"), + make_shared(PermissionType::b_client_force_push_to_talk, PermissionGroup::client, "b_client_force_push_to_talk", "Force Push-To-Talk capture mode"), + make_shared(PermissionType::b_client_ignore_bans, PermissionGroup::client, "b_client_ignore_bans", "Ignore bans"), + make_shared(PermissionType::b_client_ignore_vpn, PermissionGroup::client, "b_client_ignore_vpn", "Ignore the vpn check"), + make_shared(PermissionType::b_client_ignore_antiflood, PermissionGroup::client, "b_client_ignore_antiflood", "Ignore antiflood measurements"), + make_shared(PermissionType::b_client_enforce_valid_hwid, PermissionGroup::client, "b_client_enforce_valid_hwid", "Enforces the client to have a valid hardware id"), + make_shared(PermissionType::b_client_allow_invalid_packet, PermissionGroup::client, "b_client_allow_invalid_packet", "Allow client to send invalid packets"), + make_shared(PermissionType::b_client_allow_invalid_badges, PermissionGroup::client, "b_client_allow_invalid_badges", "Allow client to have invalid badges"), + make_shared(PermissionType::b_client_issue_client_query_command, PermissionGroup::client, "b_client_issue_client_query_command", "Issue query commands from client"), + make_shared(PermissionType::b_client_use_reserved_slot, PermissionGroup::client, "b_client_use_reserved_slot", "Use an reserved slot"), + make_shared(PermissionType::b_client_use_channel_commander, PermissionGroup::client, "b_client_use_channel_commander", "Use channel commander"), + make_shared(PermissionType::b_client_request_talker, PermissionGroup::client, "b_client_request_talker", "Allow to request talk power"), + make_shared(PermissionType::b_client_avatar_delete_other, PermissionGroup::client, "b_client_avatar_delete_other", "Allow deletion of avatars from other clients"), + make_shared(PermissionType::b_client_is_sticky, PermissionGroup::client, "b_client_is_sticky", "Client will be sticked to current channel"), + make_shared(PermissionType::b_client_ignore_sticky, PermissionGroup::client, "b_client_ignore_sticky", "Client ignores sticky flag"), +#ifndef LAGACY + make_shared(PermissionType::b_client_music_channel_list, PermissionGroup::client_info, "b_client_music_channel_list", "List all music bots in the current channel"), + make_shared(PermissionType::b_client_music_server_list, PermissionGroup::client_info, "b_client_music_server_list", "List all music bots on the sderver"), + make_shared(PermissionType::i_client_music_info, PermissionGroup::client_info, "i_client_music_info", "Permission to view music bot info"), + make_shared(PermissionType::i_client_music_needed_info, PermissionGroup::client_info, "i_client_music_needed_info", "Required permission to view music bot info"), +#endif + make_shared(PermissionType::b_client_info_view, PermissionGroup::client_info, "b_client_info_view", "Retrieve client information"), + make_shared(PermissionType::b_client_permissionoverview_view, PermissionGroup::client_info, "b_client_permissionoverview_view", "Retrieve client permissions overview"), + make_shared(PermissionType::b_client_permissionoverview_own, PermissionGroup::client_info, "b_client_permissionoverview_own", "Retrieve clients own permissions overview"), + make_shared(PermissionType::b_client_remoteaddress_view, PermissionGroup::client_info, "b_client_remoteaddress_view", "View client IP address and port"), + make_shared(PermissionType::i_client_serverquery_view_power, PermissionGroup::client_info, "i_client_serverquery_view_power", "ServerQuery view power"), + make_shared(PermissionType::i_client_needed_serverquery_view_power, PermissionGroup::client_info, "i_client_needed_serverquery_view_power", "Needed ServerQuery view power"), + make_shared(PermissionType::b_client_custom_info_view, PermissionGroup::client_info, "b_client_custom_info_view", "View custom fields"), + make_shared(PermissionType::i_client_kick_from_server_power, PermissionGroup::client_admin, "i_client_kick_from_server_power", "Client kick power from server"), + make_shared(PermissionType::i_client_needed_kick_from_server_power, PermissionGroup::client_admin, "i_client_needed_kick_from_server_power", "Needed client kick power from server"), + make_shared(PermissionType::i_client_kick_from_channel_power, PermissionGroup::client_admin, "i_client_kick_from_channel_power", "Client kick power from channel"), + make_shared(PermissionType::i_client_needed_kick_from_channel_power, PermissionGroup::client_admin, "i_client_needed_kick_from_channel_power", "Needed client kick power from channel"), + make_shared(PermissionType::i_client_ban_power, PermissionGroup::client_admin, "i_client_ban_power", "Client ban power"), + make_shared(PermissionType::i_client_needed_ban_power, PermissionGroup::client_admin, "i_client_needed_ban_power", "Needed client ban power"), + make_shared(PermissionType::i_client_move_power, PermissionGroup::client_admin, "i_client_move_power", "Client move power"), + make_shared(PermissionType::i_client_needed_move_power, PermissionGroup::client_admin, "i_client_needed_move_power", "Needed client move power"), + make_shared(PermissionType::i_client_complain_power, PermissionGroup::client_admin, "i_client_complain_power", "Complain power"), + make_shared(PermissionType::i_client_needed_complain_power, PermissionGroup::client_admin, "i_client_needed_complain_power", "Needed complain power"), + make_shared(PermissionType::b_client_complain_list, PermissionGroup::client_admin, "b_client_complain_list", "Show complain list"), + make_shared(PermissionType::b_client_complain_delete_own, PermissionGroup::client_admin, "b_client_complain_delete_own", "Delete own complains"), + make_shared(PermissionType::b_client_complain_delete, PermissionGroup::client_admin, "b_client_complain_delete", "Delete complains"), + make_shared(PermissionType::b_client_ban_list, PermissionGroup::client_admin, "b_client_ban_list", "Show banlist"), + make_shared(PermissionType::b_client_ban_trigger_list, PermissionGroup::client_admin, "b_client_ban_trigger_list", "Show trigger banlist"), + make_shared(PermissionType::b_client_ban_list_global, PermissionGroup::client_admin, "b_client_ban_list_global", "Show banlist globaly"), + make_shared(PermissionType::b_client_ban_create, PermissionGroup::client_admin, "b_client_ban_create", "Add a ban"), + make_shared(PermissionType::b_client_ban_create_global, PermissionGroup::client_admin, "b_client_ban_create_global", "Allow to create global bans"), + make_shared(PermissionType::b_client_ban_name, PermissionGroup::client_admin, "b_client_ban_name", "Allows the client to ban a client by name"), + make_shared(PermissionType::b_client_ban_ip, PermissionGroup::client_admin, "b_client_ban_ip", "Allows the client to ban a client by ip"), + make_shared(PermissionType::b_client_ban_hwid, PermissionGroup::client_admin, "b_client_ban_hwid", "Allows the client to ban a client hardware id"), + make_shared(PermissionType::b_client_ban_edit, PermissionGroup::client_admin, "b_client_ban_edit", "Allow to edit bans"), + make_shared(PermissionType::b_client_ban_edit_global, PermissionGroup::client_admin, "b_client_ban_edit_global", "Allow to edit global bans"), + make_shared(PermissionType::b_client_ban_delete_own, PermissionGroup::client_admin, "b_client_ban_delete_own", "Delete own bans"), + make_shared(PermissionType::b_client_ban_delete, PermissionGroup::client_admin, "b_client_ban_delete", "Delete bans"), + make_shared(PermissionType::b_client_ban_delete_own_global, PermissionGroup::client_admin, "b_client_ban_delete_own_global", "Delete own global bans"), + make_shared(PermissionType::b_client_ban_delete_global, PermissionGroup::client_admin, "b_client_ban_delete_global", "Delete global bans"), + make_shared(PermissionType::i_client_ban_max_bantime, PermissionGroup::client_admin, "i_client_ban_max_bantime", "Max bantime"), + make_shared(PermissionType::b_client_even_textmessage_send, PermissionGroup::client_basic, "b_client_even_textmessage_send", "Allows the client to send text messages to himself"), + make_shared(PermissionType::i_client_private_textmessage_power, PermissionGroup::client_basic, "i_client_private_textmessage_power", "Client private message power"), + make_shared(PermissionType::i_client_needed_private_textmessage_power, PermissionGroup::client_basic, "i_client_needed_private_textmessage_power", "Needed client private message power"), + make_shared(PermissionType::b_client_server_textmessage_send, PermissionGroup::client_basic, "b_client_server_textmessage_send", "Send text messages to virtual server"), + make_shared(PermissionType::b_client_channel_textmessage_send, PermissionGroup::client_basic, "b_client_channel_textmessage_send", "Send text messages to channel"), + make_shared(PermissionType::b_client_offline_textmessage_send, PermissionGroup::client_basic, "b_client_offline_textmessage_send", "Send offline messages to clients"), + make_shared(PermissionType::i_client_talk_power, PermissionGroup::client_basic, "i_client_talk_power", "Client talk power"), + make_shared(PermissionType::i_client_needed_talk_power, PermissionGroup::client_basic, "i_client_needed_talk_power", "Needed client talk power"), + make_shared(PermissionType::i_client_poke_power, PermissionGroup::client_basic, "i_client_poke_power", "Client poke power"), + make_shared(PermissionType::i_client_needed_poke_power, PermissionGroup::client_basic, "i_client_needed_poke_power", "Needed client poke power"), + make_shared(PermissionType::b_client_set_flag_talker, PermissionGroup::client_basic, "b_client_set_flag_talker", "Set the talker flag for clients and allow them to speak"), + make_shared(PermissionType::i_client_whisper_power, PermissionGroup::client_basic, "i_client_whisper_power", "Client whisper power"), + make_shared(PermissionType::i_client_needed_whisper_power, PermissionGroup::client_basic, "i_client_needed_whisper_power", "Client needed whisper power"), + make_shared(PermissionType::b_client_modify_description, PermissionGroup::client_modify, "b_client_modify_description", "Edit a clients description"), + make_shared(PermissionType::b_client_modify_own_description, PermissionGroup::client_modify, "b_client_modify_own_description", "Allow client to edit own description"), + make_shared(PermissionType::b_client_modify_dbproperties, PermissionGroup::client_modify, "b_client_modify_dbproperties", "Edit a clients properties in the sql"), + make_shared(PermissionType::b_client_delete_dbproperties, PermissionGroup::client_modify, "b_client_delete_dbproperties", "Delete a clients properties in the sql"), + make_shared(PermissionType::b_client_create_modify_serverquery_login, PermissionGroup::client_modify, "b_client_create_modify_serverquery_login", "Create or modify own ServerQuery account"), + + make_shared(PermissionType::b_client_query_create, PermissionGroup::client_modify, "b_client_query_create", "Create your own ServerQuery account"), + make_shared(PermissionType::b_client_query_list, PermissionGroup::client_modify, "b_client_query_list", "List all ServerQuery accounts"), + make_shared(PermissionType::b_client_query_list_own, PermissionGroup::client_modify, "b_client_query_list_own", "List all own ServerQuery accounts"), + make_shared(PermissionType::b_client_query_rename, PermissionGroup::client_modify, "b_client_query_rename", "Rename a ServerQuery account"), + make_shared(PermissionType::b_client_query_rename_own, PermissionGroup::client_modify, "b_client_query_rename_own", "Rename the own ServerQuery account"), + make_shared(PermissionType::b_client_query_change_password, PermissionGroup::client_modify, "b_client_query_change_password", "Change a server query accounts password"), + make_shared(PermissionType::b_client_query_change_own_password, PermissionGroup::client_modify, "b_client_query_change_own_password", "Change a query accounts own password"), + make_shared(PermissionType::b_client_query_change_password_global, PermissionGroup::client_modify, "b_client_query_change_password_global", "Change a global query accounts own password"), + make_shared(PermissionType::b_client_query_delete, PermissionGroup::client_modify, "b_client_query_delete", "Delete a query accounts password"), + make_shared(PermissionType::b_client_query_delete_own, PermissionGroup::client_modify, "b_client_query_delete_own", "Delete own query accounts password"), + +#ifndef LAGENCY + make_shared(PermissionType::b_client_music_create_temporary, PermissionGroup::client, "b_client_music_create_temporary", "Permission to create a music bot"), + make_shared(PermissionType::b_client_music_create_semi_permanent, PermissionGroup::client, "b_client_music_create_semi_permanent", "Allows the client to create semi permanent music bots"), + make_shared(PermissionType::b_client_music_create_permanent, PermissionGroup::client, "b_client_music_create_permanent", "Allows the client to create permanent music bots"), + make_shared(PermissionType::b_client_music_modify_temporary, PermissionGroup::client, "b_client_music_modify_temporary", "Permission to make a music bot temporary"), + make_shared(PermissionType::b_client_music_modify_semi_permanent, PermissionGroup::client, "b_client_music_modify_semi_permanent", "Allows the client to make a bot semi permanent"), + make_shared(PermissionType::b_client_music_modify_permanent, PermissionGroup::client, "b_client_music_modify_permanent", "Allows the client to make a bot permanent"), + make_shared(PermissionType::i_client_music_create_modify_max_volume, PermissionGroup::client, "i_client_music_create_modify_max_volume", "Sets the max allowed music bot volume"), + make_shared(PermissionType::i_client_music_limit, PermissionGroup::client, "i_client_music_limit", "The limit of music bots bound to this client"), + make_shared(PermissionType::i_client_music_delete_power, PermissionGroup::client, "i_client_music_delete_power", "Power to delete the music bot"), + make_shared(PermissionType::i_client_music_needed_delete_power, PermissionGroup::client, "i_client_music_needed_delete_power", "Required power to delete the music bot"), + make_shared(PermissionType::i_client_music_play_power, PermissionGroup::client, "i_client_music_play_power", "Power to play music"), + make_shared(PermissionType::i_client_music_needed_modify_power, PermissionGroup::client, "i_client_music_needed_modify_power", "Required power to modify the bot settings"), + make_shared(PermissionType::i_client_music_modify_power, PermissionGroup::client, "i_client_music_modify_power", "Power to modify the music bot settings"), + make_shared(PermissionType::i_client_music_needed_play_power, PermissionGroup::client, "i_client_music_needed_play_power", "Required power to play music"), + make_shared(PermissionType::i_client_music_rename_power, PermissionGroup::client, "i_client_music_rename_power", "Power to rename the bot"), + make_shared(PermissionType::i_client_music_needed_rename_power, PermissionGroup::client, "i_client_music_needed_rename_power", "The required rename power for a music bot"), + + make_shared(PermissionType::b_playlist_create, PermissionGroup::client, "b_playlist_create", "Allows the client to create playlists"), + make_shared(PermissionType::i_playlist_view_power, PermissionGroup::client, "i_playlist_view_power", "Power to see a playlist, and their songs"), + make_shared(PermissionType::i_playlist_needed_view_power, PermissionGroup::client, "i_playlist_needed_view_power", "Needed power to see a playlist, and their songs"), + make_shared(PermissionType::i_playlist_modify_power, PermissionGroup::client, "i_playlist_modify_power", "Power to modify the playlist properties"), + make_shared(PermissionType::i_playlist_needed_modify_power, PermissionGroup::client, "i_playlist_needed_modify_power", "Needed power to modify the playlist properties"), + make_shared(PermissionType::i_playlist_permission_modify_power, PermissionGroup::client, "i_playlist_permission_modify_power", "Power to modify the playlist permissions"), + make_shared(PermissionType::i_playlist_needed_permission_modify_power, PermissionGroup::client, "i_playlist_needed_permission_modify_power", "Needed power to modify the playlist permissions"), + make_shared(PermissionType::i_playlist_delete_power, PermissionGroup::client, "i_playlist_delete_power", "Power to delete the playlist"), + make_shared(PermissionType::i_playlist_needed_delete_power, PermissionGroup::client, "i_playlist_needed_delete_power", "Needed power to delete the playlist"), + + make_shared(PermissionType::i_playlist_song_add_power, PermissionGroup::client, "i_playlist_song_add_power", "Power to add songs to a playlist"), + make_shared(PermissionType::i_playlist_song_needed_add_power, PermissionGroup::client, "i_playlist_song_needed_add_power", "Needed power to add songs to a playlist"), + make_shared(PermissionType::i_playlist_song_remove_power, PermissionGroup::client, "i_playlist_song_remove_power", "Power to remove songs from a playlist"), + make_shared(PermissionType::i_playlist_song_needed_remove_power, PermissionGroup::client, "i_playlist_song_needed_remove_power", "Needed power to remove songs from a playlist"), + make_shared(PermissionType::i_playlist_song_move_power, PermissionGroup::client, "i_playlist_song_move_power", "Power to move songs witin a playlist"), + make_shared(PermissionType::i_playlist_song_needed_move_power, PermissionGroup::client, "i_playlist_song_needed_move_power", "Needed power to move songs within a playlist"), + + make_shared(PermissionType::b_client_use_bbcode_any, PermissionGroup::client, "b_client_use_bbcode_any", "Allows the client to use any bbcodes"), + make_shared(PermissionType::b_client_use_bbcode_image, PermissionGroup::client, "b_client_use_bbcode_image", "Allows the client to use img bbcode"), + make_shared(PermissionType::b_client_use_bbcode_url, PermissionGroup::client, "b_client_use_bbcode_url", "Allows the client to use url bbcode"), +#endif + make_shared(PermissionType::b_ft_ignore_password, PermissionGroup::ft, "b_ft_ignore_password", "Browse files without channel password"), + make_shared(PermissionType::b_ft_transfer_list, PermissionGroup::ft, "b_ft_transfer_list", "Retrieve list of running filetransfers"), + make_shared(PermissionType::i_ft_file_upload_power, PermissionGroup::ft, "i_ft_file_upload_power", "File upload power"), + make_shared(PermissionType::i_ft_needed_file_upload_power, PermissionGroup::ft, "i_ft_needed_file_upload_power", "Needed file upload power"), + make_shared(PermissionType::i_ft_file_download_power, PermissionGroup::ft, "i_ft_file_download_power", "File download power"), + make_shared(PermissionType::i_ft_needed_file_download_power, PermissionGroup::ft, "i_ft_needed_file_download_power", "Needed file download power"), + make_shared(PermissionType::i_ft_file_delete_power, PermissionGroup::ft, "i_ft_file_delete_power", "File delete power"), + make_shared(PermissionType::i_ft_needed_file_delete_power, PermissionGroup::ft, "i_ft_needed_file_delete_power", "Needed file delete power"), + make_shared(PermissionType::i_ft_file_rename_power, PermissionGroup::ft, "i_ft_file_rename_power", "File rename power"), + make_shared(PermissionType::i_ft_needed_file_rename_power, PermissionGroup::ft, "i_ft_needed_file_rename_power", "Needed file rename power"), + make_shared(PermissionType::i_ft_file_browse_power, PermissionGroup::ft, "i_ft_file_browse_power", "File browse power"), + make_shared(PermissionType::i_ft_needed_file_browse_power, PermissionGroup::ft, "i_ft_needed_file_browse_power", "Needed file browse power"), + make_shared(PermissionType::i_ft_directory_create_power, PermissionGroup::ft, "i_ft_directory_create_power", "Create directory power"), + make_shared(PermissionType::i_ft_needed_directory_create_power, PermissionGroup::ft, "i_ft_needed_directory_create_power", "Needed create directory power"), + make_shared(PermissionType::i_ft_quota_mb_download_per_client, PermissionGroup::ft, "i_ft_quota_mb_download_per_client", "Download quota per client in MByte"), + make_shared(PermissionType::i_ft_quota_mb_upload_per_client, PermissionGroup::ft, "i_ft_quota_mb_upload_per_client", "Upload quota per client in MByte") +}; + +deque ts::permission::neededPermissions = { + b_client_force_push_to_talk, + b_channel_join_ignore_password, + b_ft_ignore_password, + i_client_max_avatar_filesize, + i_client_max_channel_subscriptions, + i_permission_modify_power, + b_virtualserver_servergroup_permission_list, + b_virtualserver_client_permission_list, + b_virtualserver_channelgroup_permission_list, + b_virtualserver_channelclient_permission_list, + b_virtualserver_playlist_permission_list, + b_virtualserver_channelgroup_client_list, + b_client_permissionoverview_view, + b_client_ban_list, + b_client_ban_trigger_list, + b_client_complain_list, + b_client_complain_delete, + b_client_complain_delete_own, + b_virtualserver_log_view, + b_client_create_modify_serverquery_login, + b_virtualserver_connectioninfo_view, + b_client_modify_description, + b_client_server_textmessage_send, + b_client_channel_textmessage_send, +#ifdef LAGENCY +i_group_modify_power, + i_group_member_add_power, + i_group_member_remove_power, +#else + i_displayed_group_modify_power, + i_displayed_group_member_add_power, + i_displayed_group_member_remove_power, + + i_server_group_modify_power, + i_server_group_member_add_power, + i_server_group_self_add_power, + i_server_group_member_remove_power, + i_server_group_self_remove_power, + + i_channel_group_modify_power, + i_channel_group_member_add_power, + i_channel_group_self_add_power, + i_channel_group_member_remove_power, + i_channel_group_self_remove_power, +#endif + i_ft_file_browse_power, + b_permission_modify_power_ignore, + b_virtualserver_modify_hostmessage, + b_virtualserver_modify_ft_settings, + b_virtualserver_modify_default_musicgroup, + b_virtualserver_modify_default_servergroup, + b_virtualserver_modify_default_channelgroup, + b_virtualserver_modify_default_channeladmingroup, + b_virtualserver_modify_hostbanner, + b_virtualserver_modify_channel_forced_silence, + b_virtualserver_modify_needed_identity_security_level, + b_virtualserver_modify_name, + b_virtualserver_modify_welcomemessage, + b_virtualserver_modify_maxclients, + b_virtualserver_modify_password, + b_virtualserver_modify_complain, + b_virtualserver_modify_antiflood, + b_virtualserver_modify_ft_quotas, + b_virtualserver_modify_hostbutton, + b_virtualserver_modify_autostart, + b_virtualserver_modify_port, + b_virtualserver_modify_host, + b_virtualserver_modify_log_settings, + b_virtualserver_modify_priority_speaker_dimm_modificator, + b_virtualserver_modify_music_bot_limit, + b_virtualserver_modify_default_messages, + i_channel_create_modify_conversation_history_length, + b_channel_create_modify_conversation_history_unlimited, + b_channel_create_modify_conversation_private, + b_channel_modify_name, + b_channel_modify_password, + b_channel_modify_topic, + b_channel_modify_description, + b_channel_modify_codec, + b_channel_modify_codec_quality, + b_channel_modify_make_permanent, + b_channel_modify_make_semi_permanent, + b_channel_modify_make_temporary, + b_channel_modify_make_default, + b_channel_modify_maxclients, + b_channel_modify_maxfamilyclients, + b_channel_modify_sortorder, + b_channel_modify_needed_talk_power, + i_channel_permission_modify_power, + b_channel_create_child, + b_channel_create_permanent, + b_channel_create_temporary, + b_channel_create_with_topic, + b_channel_create_with_description, + b_channel_create_with_password, + b_channel_create_with_maxclients, + b_channel_create_with_maxfamilyclients, + b_channel_create_with_sortorder, + b_channel_create_with_default, + b_channel_create_modify_with_codec_speex8, + b_channel_create_modify_with_codec_speex16, + b_channel_create_modify_with_codec_speex32, + b_channel_create_modify_with_codec_celtmono48, + b_channel_create_modify_with_codec_opusvoice, + b_channel_create_modify_with_codec_opusmusic, + i_channel_create_modify_with_codec_maxquality, + i_client_serverquery_view_power, + b_channel_create_semi_permanent, + b_serverinstance_modify_querygroup, + b_serverinstance_modify_templates, + b_virtualserver_channel_permission_list, + b_channel_delete_permanent, + b_channel_delete_semi_permanent, + b_channel_delete_temporary, + b_channel_delete_flag_force, + b_client_set_flag_talker, + b_channel_create_with_needed_talk_power, + b_virtualserver_token_list, + b_virtualserver_token_add, + b_virtualserver_token_use, + b_virtualserver_token_delete, + + /* ban functions */ + b_client_ban_create, + b_client_ban_create_global, + + b_client_ban_list_global, + b_client_ban_list, + + b_client_ban_edit, + b_client_ban_edit_global, + + b_client_ban_name, + b_client_ban_ip, + b_client_ban_hwid, + + b_virtualserver_servergroup_list, + b_virtualserver_servergroup_client_list, + b_virtualserver_channelgroup_list, + i_client_ban_max_bantime, + b_icon_manage, + i_max_icon_filesize, + i_max_playlist_size, + i_max_playlists, + + i_client_needed_whisper_power, + i_client_whisper_power, + + b_virtualserver_modify_icon_id, + b_client_modify_own_description, + b_client_offline_textmessage_send, + b_virtualserver_client_dblist, + b_virtualserver_modify_reserved_slots, + b_channel_conversation_message_delete, + i_channel_create_modify_with_codec_latency_factor_min, + b_channel_modify_codec_latency_factor, + b_channel_modify_make_codec_encrypted, + b_virtualserver_modify_codec_encryption_mode, + b_client_use_channel_commander, + b_virtualserver_servergroup_create, + b_virtualserver_channelgroup_create, + b_client_permissionoverview_own, + i_ft_quota_mb_upload_per_client, + i_ft_quota_mb_download_per_client, + b_virtualserver_modify_weblist, + b_virtualserver_modify_country_code, + b_virtualserver_channelgroup_delete, + b_virtualserver_servergroup_delete, + b_client_ban_delete, + b_client_ban_delete_own, + b_client_ban_delete_global, + b_client_ban_delete_own_global, + b_virtualserver_modify_temporary_passwords, + b_virtualserver_modify_temporary_passwords_own, + b_client_request_talker, + b_client_avatar_delete_other, + b_channel_create_modify_with_force_password, + b_channel_create_private, + b_channel_join_ignore_maxclients, + b_virtualserver_modify_channel_temp_delete_delay_default, + i_channel_create_modify_with_temp_delete_delay, + b_channel_modify_temp_delete_delay, + i_client_poke_power, + + b_client_remoteaddress_view, + + i_client_music_play_power, + i_client_music_modify_power, + i_client_music_rename_power, + b_client_music_create_temporary, + b_client_music_create_semi_permanent, + b_client_music_create_permanent, + b_client_music_modify_temporary, + b_client_music_modify_semi_permanent, + b_client_music_modify_permanent, + i_client_music_create_modify_max_volume, + + b_playlist_create, + i_playlist_view_power, + i_playlist_modify_power, + i_playlist_permission_modify_power, + i_playlist_delete_power, + + i_playlist_song_add_power, + i_playlist_song_remove_power, + i_playlist_song_move_power, + + b_client_query_create, + b_client_query_list, + b_client_query_list_own, + b_client_query_rename, + b_client_query_rename_own, + b_client_query_change_password, + b_client_query_change_own_password, + b_client_query_change_password_global, + b_client_query_delete, + b_client_query_delete_own, +}; + +std::deque permission::availableGroups = { + global, + global_info, + global_vsmanage, + global_admin, + global_settings, + vs, + vs_info, + vs_admin, + vs_settings, + channel, + channel_info, + channel_create, + channel_modify, + channel_delete, + channel_access, + group, + group_info, + group_create, + group_modify, + group_delete, + client, + client_info, + client_admin, + client_basic, + client_modify, + ft +}; + +std::shared_ptr PermissionTypeEntry::unknown = make_shared(PermissionType::unknown, PermissionGroup::global, "unknown", "unknown"); + +vector> permission_id_map; +void permission::setup_permission_resolve() { + permission_id_map.resize(permission::permission_id_max); + + for(auto& permission : availablePermissions) { + if(!permission->clientSupported || permission->type < 0 || permission->type > permission::permission_id_max) + continue; + permission_id_map[permission->type] = permission; + } + + /* fix "holes" as well set the permission id 0 (unknown) */ + for(auto& permission : permission_id_map) { + if(permission) + continue; + permission = PermissionTypeEntry::unknown; + } +} + +std::shared_ptr permission::resolvePermissionData(PermissionType type) { + if((type & PERM_ID_GRANT) > 0) + type &= ~PERM_ID_GRANT; + + assert(!permission_id_map.empty()); + if(type < 0 || type >= permission::permission_id_max) + return PermissionTypeEntry::unknown; + + return permission_id_map[type]; +} + +std::shared_ptr permission::resolvePermissionData(const std::string& name) { + for(auto& elm : availablePermissions) + if(elm->name == name || elm->grant_name == name) + return elm; + return PermissionTypeEntry::unknown; +} + +ChannelId Permission::channelId() { + return this->channel ? this->channel->channelId() : 0; +} + +PermissionManager::PermissionManager() { + memtrack::allocated(this); +} +PermissionManager::~PermissionManager() { + memtrack::freed(this); +} + +std::shared_ptr PermissionManager::registerPermission(ts::permission::PermissionType type, + ts::permission::PermissionValue val, + const std::shared_ptr &channel, + uint16_t flag) { + return this->registerPermission(resolvePermissionData(type), val, channel, flag); +} + +std::shared_ptr PermissionManager::registerPermission(const std::shared_ptr& type, PermissionValue value, const std::shared_ptr& channel, uint16_t flagMask) { + { + auto found = getPermission(type->type, channel, false); + if(!found.empty()) return found.front(); + } + auto permission = std::make_shared(type, value, permNotGranted, flagMask, channel); + this->permissions.push_back(permission); + for(auto& elm : this->updateHandler) + elm(permission); + return permission; +} + +bool PermissionManager::hasPermission(PermissionType type, const std::shared_ptr& channel, bool testGlobal) { + return !this->getPermission(type, channel, testGlobal).empty(); +} + +bool PermissionManager::setPermission(PermissionType type, PermissionValue value, const std::shared_ptr& channel) { + auto list = this->getPermission(type, channel, false); + if(list.empty()) + list.push_back(registerPermission(type, value, channel, PERM_FLAG_PUBLIC)); + + list.front()->value = value; + for(const auto& elm : this->updateHandler) + elm(list.front()); + + return true; +} + +bool PermissionManager::setPermission(ts::permission::PermissionType type, ts::permission::PermissionValue value, const std::shared_ptr &channel, bool negated, bool skiped) { + auto list = this->getPermission(type, channel, false); + if(list.empty()) + list.push_back(registerPermission(type, value, channel, PERM_FLAG_PUBLIC)); + + list.front()->value = value; + list.front()->flag_negate = negated; + list.front()->flag_skip = skiped; + + for(const auto& elm : this->updateHandler) + elm(list.front()); + + return true; +} + +bool PermissionManager::setPermissionGranted(PermissionType type, PermissionValue value, const std::shared_ptr& channel) { + auto list = this->getPermission(type, channel, false); + if(list.empty()) + list.push_back(registerPermission(type, permNotGranted, channel, PERM_FLAG_PUBLIC)); + list.front()->granted = value; + + for(auto& elm : this->updateHandler) + elm(list.front()); + + return true; +} + +void PermissionManager::deletePermission(PermissionType type, const std::shared_ptr& channel) { + auto list = getPermission(type, channel, false); + if(list.empty()) return; + list.front()->value = permNotGranted; + //list.front()->deleted = true; + //this->permissions.erase(std::find(this->permissions.begin(), this->permissions.end(), list.front())); + + for(auto& e : this->updateHandler) + e(list.front()); +} + +std::deque> PermissionManager::getPermission(PermissionType type, const std::shared_ptr& channel, bool testGlobal) { + std::deque> res; + + std::shared_ptr channel_permission; + std::shared_ptr global_permission; + for(const auto &perm : this->permissions) + if(perm->type->type == type) { + if(perm->channel == channel) + channel_permission = perm; + else if(!perm->channel && testGlobal) + global_permission = perm; + } + if(channel_permission) res.push_back(channel_permission); + if(global_permission) res.push_back(global_permission); + return res; +} + +std::vector> PermissionManager::listPermissions(uint16_t flags) { + vector> result; + for(const auto &perm : this->permissions) + if((perm->flagMask & flags) > 0 || true) //FIXME? + result.push_back(perm); + return result; +} + +std::vector> PermissionManager::allPermissions() { + return std::vector>(this->permissions.begin(), this->permissions.end()); +} + +std::deque> PermissionManager::all_channel_specific_permissions() { + std::deque> result; + + for(const auto& permission : this->permissions) + if(permission->channel) + result.push_back(permission); + + return result; +} + +std::deque> PermissionManager::all_channel_unspecific_permissions() { + std::deque> result; + + for(const auto& permission : this->permissions) + if(!permission->channel) + result.push_back(permission); + + return result; +} + +teamspeak::MapType teamspeak::unmapping; +teamspeak::MapType teamspeak::mapping; + +teamspeak::MapType build_mapping(){ + return { + {teamspeak::GENERAL, { + {"b_virtualserver_modify_port", {"b_virtualserver_modify_port", "b_virtualserver_modify_host"}}, + {"i_client_max_clones_uid", {"i_client_max_clones_uid", "i_client_max_clones_ip", "i_client_max_clones_hwid"}}, + {"b_client_ignore_bans", {"b_client_ignore_bans", "b_client_ignore_vpn"}}, + {"b_client_ban_list", {"b_client_ban_list", "b_client_ban_list_global"}}, + + //Permissions which TeaSpeak has but TeamSpeak not + {"", {"b_virtualserver_modify_music_bot_limit"}}, + {"", {"b_client_music_channel_list"}}, + {"", {"b_client_music_server_list"}}, + {"", {"i_client_music_info"}}, + {"", {"i_client_music_needed_info"}}, + + {"", {"b_client_ban_edit"}}, + {"", {"b_client_ban_edit_global"}}, + {"", {"b_client_ban_create_global"}}, + {"", {"b_client_ban_delete_own_global"}}, + {"", {"b_client_ban_delete_global"}}, + + {"", {"b_client_even_textmessage_send"}}, + {"", {"b_client_enforce_valid_hwid"}}, + {"", {"b_client_allow_invalid_packet"}}, + {"", {"b_client_allow_invalid_badges"}}, + + {"", {"b_client_music_create"}}, + {"", {"b_client_music_delete_own"}}, + + {"", {"i_client_music_limit"}}, + {"", {"i_client_music_needed_delete_power"}}, + {"", {"i_client_music_delete_power"}}, + {"", {"i_client_music_play_power"}}, + {"", {"i_client_music_needed_play_power"}}, + {"", {"i_client_music_rename_power"}}, + {"", {"i_client_music_needed_rename_power"}}, + + {"", {"b_client_use_bbcode_any"}}, + {"", {"b_client_use_bbcode_url"}}, + {"", {"b_client_use_bbcode_image"}}, + + {"", {"b_channel_ignore_view_power"}}, + {"", {"i_channel_view_power"}}, + {"", {"i_channel_needed_view_power"}}, + + {"", {"i_client_max_channels"}}, + {"", {"i_client_max_temporary_channels"}}, + {"", {"i_client_max_semi_channels"}}, + {"", {"i_client_max_permanent_channels"}}, + + {"", {"b_virtualserver_modify_default_messages"}}, + + {"b_client_ban_list", {"b_client_ban_list", "b_client_ban_trigger_list"}}, + {"b_virtualserver_select", {"b_virtualserver_select", "b_virtualserver_select_godmode"}}, + {"b_virtualserver_modify_default_servergroup", {"b_virtualserver_modify_default_servergroup", "b_virtualserver_modify_default_musicgroup"}}, + + {"b_client_ban_create", {"b_client_ban_create", "b_client_ban_name", "b_client_ban_ip", "b_client_ban_hwid"}} + }, + }, + {teamspeak::SERVER, { + {"i_group_modify_power", {"i_server_group_modify_power", "i_channel_group_modify_power", "i_displayed_group_modify_power"}}, + {"i_group_member_add_power", {"i_server_group_member_add_power", "i_channel_group_member_add_power", "i_displayed_group_member_add_power"}}, + {"i_group_member_remove_power", {"i_server_group_member_remove_power", "i_channel_group_member_remove_power", "i_displayed_group_member_remove_power"}}, + {"i_group_needed_modify_power", {"i_server_group_needed_modify_power", "i_channel_group_needed_modify_power", "i_displayed_group_needed_modify_power"}}, + {"i_group_needed_member_add_power", {"i_server_group_needed_member_add_power", "i_channel_group_needed_member_add_power", "i_displayed_group_needed_member_add_power"}}, + {"i_group_needed_member_remove_power", {"i_server_group_needed_member_remove_power", "i_channel_group_needed_member_remove_power", "i_displayed_group_needed_member_remove_power"}}, + }, + }, + {teamspeak::CLIENT, { + {"i_group_modify_power", {"i_server_group_modify_power", "i_channel_group_modify_power", "i_displayed_group_modify_power"}}, + {"i_group_member_add_power", {"i_server_group_member_add_power", "i_channel_group_member_add_power", "i_displayed_group_member_add_power"}}, + {"i_group_member_remove_power", {"i_server_group_member_remove_power", "i_channel_group_member_remove_power", "i_displayed_group_member_remove_power"}}, + {"i_group_needed_modify_power", {"i_server_group_needed_modify_power", "i_channel_group_needed_modify_power", "i_displayed_group_needed_modify_power"}}, + {"i_group_needed_member_add_power", {"i_server_group_needed_member_add_power", "i_channel_group_needed_member_add_power", "i_displayed_group_needed_member_add_power"}}, + {"i_group_needed_member_remove_power", {"i_server_group_needed_member_remove_power", "i_channel_group_needed_member_remove_power", "i_displayed_group_needed_member_remove_power"}}, + }, + }, + {teamspeak::CHANNEL, { + {"i_group_modify_power", {"i_channel_group_modify_power", "i_displayed_group_modify_power"}}, + {"i_group_member_add_power", {"i_channel_group_member_add_power", "i_displayed_group_member_add_power"}}, + {"i_group_member_remove_power", {"i_channel_group_member_remove_power", "i_displayed_group_member_remove_power"}}, + {"i_group_needed_modify_power", {"i_channel_group_needed_modify_power", "i_displayed_group_needed_modify_power"}}, + {"i_group_needed_member_add_power", {"i_channel_group_needed_member_add_power", "i_displayed_group_needed_member_add_power"}}, + {"i_group_needed_member_remove_power", {"i_channel_group_needed_member_remove_power", "i_displayed_group_needed_member_remove_power"}}, + }, + }, + }; +}; + +inline teamspeak::MapType build_unmapping() { + teamspeak::MapType result; + + for(const auto& map : teamspeak::mapping) { + for(const auto& entry : map.second) { + for(const auto& key : entry.second) { + auto& m = result[map.first]; + auto it = m.find(key); + if(it == m.end()) + m.insert({key, {}}); + it = m.find(key); + if(!entry.first.empty()) it->second.push_back(entry.first); + } + } + } + + return result; +}; + +inline void init_mapping() { + if(teamspeak::mapping.empty()) teamspeak::mapping = build_mapping(); + if(teamspeak::unmapping.empty()) teamspeak::unmapping = build_unmapping(); +} + +template +inline deque operator+(const deque& a, const deque& b) { + deque result; + result.insert(result.end(), a.begin(), a.end()); + result.insert(result.end(), b.begin(), b.end()); + return result; +} + +inline deque mmget(teamspeak::MapType& map, teamspeak::GroupType type, const std::string& key) { + return map[type].count(key) > 0 ? map[type].find(key)->second : deque{}; +} + +inline std::deque map_entry(std::string key, teamspeak::GroupType type, teamspeak::MapType& map_table) { + init_mapping(); + + if(key.find("_needed_modify_power_") == 1) { + key = key.substr(strlen("x_needed_modify_power_")); + + deque result; + if(map_table[type].count("i_" + key) > 0 || map_table[teamspeak::GroupType::GENERAL].count("i_" + key) > 0) result = mmget(map_table, type, "i_" + key) + mmget(map_table, teamspeak::GroupType::GENERAL, "i_" + key); + else if(map_table[type].count("b_" + key) > 0 || map_table[teamspeak::GroupType::GENERAL].count("b_" + key) > 0) result = mmget(map_table, type, "b_" + key) + mmget(map_table, teamspeak::GroupType::GENERAL, "b_" + key); + else result = {"x_" + key}; + + for(auto& entry : result) + entry = "i_needed_modify_power_" + entry.substr(2); + return result; + } + if(map_table[type].count(key) > 0 || map_table[teamspeak::GroupType::GENERAL].count(key) > 0) return mmget(map_table, type, key) + mmget(map_table, teamspeak::GroupType::GENERAL, key); + return {key}; +} + +std::deque teamspeak::map_key(std::string key, GroupType type) { + return map_entry(key, type, teamspeak::mapping); +} + +std::deque teamspeak::unmap_key(std::string key, GroupType type) { + return map_entry(key, type, teamspeak::unmapping); +} + + +#define AQB(name) \ +{update::QUERY_ADMIN, {name, 1, 100, false, false}}, \ +{update::SERVER_ADMIN, {name, 1, 75, false, false}}, \ + +#define AQBG(name) \ +{update::QUERY_ADMIN, {name, permNotGranted, 100, false, false}}, \ +{update::SERVER_ADMIN, {name, permNotGranted, 75, false, false}}, \ + +#define AQI(name) \ +{update::QUERY_ADMIN, {name, 100, 100, false, false}}, \ +{update::SERVER_ADMIN, {name, 75, 75, false, false}}, \ + +#define AQIG(name) \ +{update::QUERY_ADMIN, {name, permNotGranted, 100, false, false}}, \ +{update::SERVER_ADMIN, {name, permNotGranted, 75, false, false}}, \ + +deque update::migrate = { + AQB("b_virtualserver_modify_music_bot_limit") + {update::QUERY_ADMIN, {"b_client_music_channel_list", 1, 100, false, false}}, + {update::SERVER_ADMIN, {"b_client_music_channel_list", 1, 75, false, false}}, + {update::CHANNEL_ADMIN, {"b_client_music_channel_list", 1, 75, false, false}}, + + {update::QUERY_ADMIN, {"b_client_music_server_list", 1, 100, false, false}}, + {update::SERVER_ADMIN, {"b_client_music_server_list", 1, 75, false, false}}, + + {update::QUERY_ADMIN, {"i_client_music_info", 100, 100, false, false}}, + {update::SERVER_ADMIN, {"i_client_music_info", 75, 75, false, false}}, + + {update::QUERY_ADMIN, {"i_client_music_needed_info", permNotGranted, 100, false, false}}, + {update::SERVER_ADMIN, {"i_client_music_needed_info", permNotGranted, 75, false, false}}, + + {update::QUERY_ADMIN, {"b_client_ban_list_global", 1, 100, false, false}}, + {update::SERVER_ADMIN, {"b_client_ban_list_global", 1, 75, false, false}}, + + {update::QUERY_ADMIN, {"b_client_ban_edit", 1, 100, false, false}}, + {update::SERVER_ADMIN, {"b_client_ban_edit", 1, 75, false, false}}, + + {update::QUERY_ADMIN, {"b_client_ban_create_global", 1, 100, false, false}}, + {update::QUERY_ADMIN, {"b_client_ban_edit_global", 1, 100, false, false}}, + {update::QUERY_ADMIN, {"b_client_ban_delete_own_global", 1, 100, false, false}}, + {update::QUERY_ADMIN, {"b_client_ban_delete_global", 1, 100, false, false}}, + + AQB("b_client_even_textmessage_send") + AQBG("b_client_enforce_valid_hwid") + AQB("b_client_allow_invalid_packet") + AQB("b_client_allow_invalid_badges") + + AQB("b_client_music_create") + AQB("b_client_music_delete_own") + + AQI("i_client_music_limit") + AQIG("i_client_music_needed_delete_power") + AQI("i_client_music_delete_power") + AQI("i_client_music_play_power") + AQIG("i_client_music_needed_play_power") + AQI("i_client_music_rename_power") + AQIG("i_client_music_needed_rename_power") + + + AQB("b_client_use_bbcode_any") + AQB("b_client_use_bbcode_url") + AQB("b_client_use_bbcode_image") + + {update::QUERY_ADMIN, {"b_channel_ignore_view_power", 1, 100, false, false}}, + AQI("i_channel_view_power") + AQIG("i_channel_needed_view_power") + + AQB("b_client_ignore_vpn") + + AQIG("i_client_max_channels") + AQIG("i_client_max_temporary_channels") + AQIG("i_client_max_semi_channels") + AQIG("i_client_max_permanent_channels") + {update::SERVER_NORMAL, {"i_client_max_channels", 2, permNotGranted, false, false}}, + {update::SERVER_GUEST, {"i_client_max_channels", 1, permNotGranted, false, false}}, + + AQB("b_virtualserver_modify_default_messages") + AQB("b_virtualserver_modify_default_musicgroup") + AQB("b_channel_ignore_join_power") + AQB("b_virtualserver_select_godmode") + AQB("b_client_ban_trigger_list") +}; + +v2::PermissionRegister::PermissionRegister() { + memset(this->block_use_count, 0, sizeof(this->block_use_count)); + memset(this->block_containers, 0, sizeof(this->block_containers)); +} + +v2::PermissionRegister::~PermissionRegister() { + for(auto& block : this->block_containers) + delete block; +} + +void v2::PermissionRegister::load_permission(const ts::permission::PermissionType &permission, const ts::permission::v2::PermissionValues &values, bool flag_skip, bool flag_negate, bool flag_value, bool flag_grant) { + if(permission < 0 || permission >= PermissionType::permission_id_max) + return; + + const auto block = this->calculate_block(permission); + this->ref_allocate_block(block); + + auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; + data.values = values; + data.flags.database_reference = true; + data.flags.skip = flag_skip; + data.flags.negate = flag_negate; + data.flags.value_set = flag_value; + data.flags.grant_set = flag_grant; + this->unref_block(block); +} + +void v2::PermissionRegister::load_permission(const ts::permission::PermissionType &permission, const ts::permission::v2::PermissionValues &values, ChannelId channel_id, bool flag_skip, bool flag_negate, bool flag_value, bool flag_grant) { + if(permission < 0 || permission >= PermissionType::permission_id_max) + return; + + unique_lock channel_perm_lock(this->channel_list_lock); + ChannelPermissionContainer* permission_container = nullptr; + for(auto& entry : this->_channel_permissions) + if(entry->permission == permission && entry->channel_id == channel_id) { + permission_container = &*entry; + break; + } + + if(!permission_container) { + auto container = make_unique(); + container->permission = permission; + container->channel_id = channel_id; + permission_container = &*container; + this->_channel_permissions.push_back(std::move(container)); + + /* now set the channel flag for that permission */ + const auto block = this->calculate_block(permission); + this->ref_allocate_block(block); + + auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; + data.flags.channel_specific = true; + this->unref_block(block); + } + + permission_container->values = values; + permission_container->flags.database_reference = true; + permission_container->flags.skip = flag_skip; + permission_container->flags.negate = flag_negate; + permission_container->flags.value_set = flag_value; + permission_container->flags.grant_set = flag_grant; +} + +const v2::PermissionFlags v2::PermissionRegister::permission_flags(const ts::permission::PermissionType &permission) { + if(permission < 0 || permission >= PermissionType::permission_id_max) + return empty_flags; + + const auto block = this->calculate_block(permission); + if(!this->ref_block(block)) + return empty_flags; + + PermissionFlags result{this->block_containers[block]->permissions[this->calculate_block_index(permission)].flags}; + this->unref_block(block); + return result; +} + +const v2::PermissionValues v2::PermissionRegister::permission_values(const ts::permission::PermissionType &permission) { + if(permission < 0 || permission >= PermissionType::permission_id_max) + return v2::empty_permission_values; + + const auto block = this->calculate_block(permission); + if(!this->ref_block(block)) + return v2::empty_permission_values; /* TODO: may consider to throw an exception because the existence should be checked by getting the permission flags */ + + v2::PermissionValues data{this->block_containers[block]->permissions[this->calculate_block_index(permission)].values}; + this->unref_block(block); + return data; +} + +const v2::PermissionFlaggedValue v2::PermissionRegister::permission_value_flagged(const ts::permission::PermissionType &permission) { + if(permission < 0 || permission >= PermissionType::permission_id_max) + return v2::empty_permission_flagged_value; + + const auto block = this->calculate_block(permission); + if(!this->ref_block(block)) + return v2::empty_permission_flagged_value; + + auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; + v2::PermissionFlaggedValue result{data.values.value, data.flags.value_set}; + this->unref_block(block); + return result; +} + +const v2::PermissionFlaggedValue v2::PermissionRegister::permission_granted_flagged(const ts::permission::PermissionType &permission) { + if(permission < 0 || permission >= PermissionType::permission_id_max) + return v2::empty_permission_flagged_value; + + const auto block = this->calculate_block(permission); + if(!this->ref_block(block)) + return v2::empty_permission_flagged_value; + + auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; + v2::PermissionFlaggedValue result{data.values.grant, data.flags.grant_set}; + this->unref_block(block); + return result; +} + +const v2::PermissionContainer v2::PermissionRegister::channel_permission(const PermissionType &permission, ts::ChannelId channel_id) { + if(permission < 0 || permission >= PermissionType::permission_id_max) + return empty_channel_permission; + + shared_lock channel_perm_lock(this->channel_list_lock); + for(auto& entry : this->_channel_permissions) + if(entry->permission == permission && entry->channel_id == channel_id) + return v2::PermissionContainer{entry->flags, entry->values}; + return empty_channel_permission; +} + +void v2::PermissionRegister::set_permission(const PermissionType &permission, const v2::PermissionValues &values, const v2::PermissionUpdateType &action_value, const v2::PermissionUpdateType &action_grant, int flag_skip, int flag_negate) { + if(permission < 0 || permission >= PermissionType::permission_id_max) + return; + + const auto block = this->calculate_block(permission); + this->ref_allocate_block(block); + + auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; + if(action_value == v2::PermissionUpdateType::set_value) { + data.flags.value_set = true; + data.flags.flag_value_update = true; + data.values.value = values.value; + } else if(action_value == v2::PermissionUpdateType::delete_value) { + data.flags.value_set = false; + data.flags.flag_value_update = true; + data.values.value = permNotGranted; /* required for the database else it does not "deletes" the value */ + } + + if(action_grant == v2::PermissionUpdateType::set_value) { + data.flags.grant_set = true; + data.flags.flag_grant_update = true; + data.values.grant = values.grant; + } else if(action_grant == v2::PermissionUpdateType::delete_value) { + data.flags.grant_set = false; + data.flags.flag_grant_update = true; + data.values.grant = permNotGranted; /* required for the database else it does not "deletes" the value */ + } + + if(flag_skip >= 0) { + data.flags.flag_value_update = true; + data.flags.skip = flag_skip == 1; + } + + if(flag_negate >= 0) { + data.flags.flag_value_update = true; + data.flags.negate = flag_negate == 1; + } + + this->unref_block(block); + this->trigger_db_update(); +} + +void v2::PermissionRegister::set_channel_permission(const PermissionType &permission, ChannelId channel_id, const v2::PermissionValues &values, const v2::PermissionUpdateType &action_value, const v2::PermissionUpdateType &action_grant, int flag_skip, int flag_negate) { + if(permission < 0 || permission >= PermissionType::permission_id_max) + return; + + unique_lock channel_perm_lock(this->channel_list_lock); + ChannelPermissionContainer* permission_container = nullptr; + for(auto& entry : this->_channel_permissions) + if(entry->permission == permission && entry->channel_id == channel_id) { + permission_container = &*entry; + break; + } + + /* register a new permission if we have no permission already*/ + if(!permission_container || !permission_container->flags.permission_set()) { /* if the permission isn't set then we have to register it again */ + if(action_value != v2::PermissionUpdateType::set_value && action_grant == v2::PermissionUpdateType::set_value) { + return; /* we were never willing to set this permission */ + } + + if(!permission_container) { + auto container = make_unique(); + container->permission = permission; + container->channel_id = channel_id; + permission_container = &*container; + this->_channel_permissions.push_back(std::move(container)); + } + + /* now set the channel flag for that permission */ + const auto block = this->calculate_block(permission); + this->ref_allocate_block(block); + + auto& data = this->block_containers[block]->permissions[this->calculate_block_index(permission)]; + data.flags.channel_specific = true; + this->unref_block(block); + } + + if(action_value == v2::PermissionUpdateType::set_value) { + permission_container->flags.value_set = true; + permission_container->flags.flag_value_update = true; + permission_container->values.value = values.value; + } else if(action_value == v2::PermissionUpdateType::delete_value) { + permission_container->flags.value_set = false; + permission_container->flags.flag_value_update = true; + } + + if(action_grant == v2::PermissionUpdateType::set_value) { + permission_container->flags.grant_set = true; + permission_container->flags.flag_grant_update = true; + permission_container->values.grant = values.grant; + } else if(action_grant == v2::PermissionUpdateType::delete_value) { + permission_container->flags.grant_set = false; + permission_container->flags.flag_grant_update = true; + } + + if(flag_skip >= 0) { + permission_container->flags.flag_value_update = true; + permission_container->flags.skip = flag_skip == 1; + } + + if(flag_negate >= 0) { + permission_container->flags.flag_value_update = true; + permission_container->flags.negate = flag_negate == 1; + } + + if(!permission_container->flags.permission_set()) { /* unregister the permission again because its unset, we delete the channel permission as soon we've flushed the updates */ + auto other_channel_permission = std::find_if(this->_channel_permissions.begin(), this->_channel_permissions.end(), [&](unique_ptr& perm) { return perm->permission == permission && perm->flags.permission_set(); }); + if(other_channel_permission == this->_channel_permissions.end()) { /* no more channel specific permissions c*/ + const auto block = this->calculate_block(permission); + if(this->ref_block(block)) { + this->block_containers[block]->permissions[this->calculate_block_index(permission)].flags.channel_specific = false; + this->unref_block(block); + } + } + } + this->trigger_db_update(); +} + +const std::vector> v2::PermissionRegister::permissions() { + std::unique_lock use_lock(this->block_use_count_lock); + decltype(this->block_containers) block_containers; /* save the states/nullptr's */ + memcpy(block_containers, this->block_containers, sizeof(this->block_containers)); + size_t block_count = 0; + for(size_t index = 0; index < BULK_COUNT; index++) { + if(block_containers[index]) { + block_count++; + this->block_use_count[index]++; + } + } + use_lock.unlock(); + + vector> result; + result.reserve(block_count * PERMISSIONS_BULK_ENTRY_COUNT); + + for(size_t block_index = 0; block_index < BULK_COUNT; block_index++) { + auto& block = block_containers[block_index]; + if(!block) + continue; + + for(size_t permission_index = 0; permission_index < PERMISSIONS_BULK_ENTRY_COUNT; permission_index++) { + auto& permission = block->permissions[permission_index]; + if(!permission.flags.permission_set()) + continue; + + result.emplace_back((PermissionType) (block_index * PERMISSIONS_BULK_ENTRY_COUNT + permission_index), permission); + } + } + result.shrink_to_fit(); + + use_lock.lock(); + for(size_t index = 0; index < BULK_COUNT; index++) { + if(block_containers[index]) + this->block_use_count[index]--; + } + use_lock.unlock(); + + return result; +} + +const vector> v2::PermissionRegister::channel_permissions(ts::ChannelId channel_id) { + shared_lock channel_perm_lock(this->channel_list_lock); + + vector> result; + for(auto& entry : this->_channel_permissions) + if((channel_id == entry->channel_id) && (entry->flags.value_set || entry->flags.grant_set)) + result.emplace_back(entry->permission, v2::PermissionContainer{entry->flags, entry->values}); + return result; +} + +const vector> v2::PermissionRegister::channel_permissions() { + shared_lock channel_perm_lock(this->channel_list_lock); + + vector> result; + for(auto& entry : this->_channel_permissions) + if(entry->flags.value_set || entry->flags.grant_set) + result.emplace_back(entry->permission, entry->channel_id, v2::PermissionContainer{entry->flags, entry->values}); + return result; +} + +const std::vector v2::PermissionRegister::flush_db_updates() { + if(!this->requires_db_save) + return {}; + + this->requires_db_save = false; + std::vector result; + + { + lock_guard use_lock(this->block_use_count_lock); + size_t block_count = 0; + for (auto &block_container : block_containers) + if (block_container) + block_count++; + result.reserve(block_count * PERMISSIONS_BULK_ENTRY_COUNT); + + for(size_t block_index = 0; block_index < BULK_COUNT; block_index++) { + auto& block = block_containers[block_index]; + if(!block) + continue; + + for(size_t permission_index = 0; permission_index < PERMISSIONS_BULK_ENTRY_COUNT; permission_index++) { + auto& permission = block->permissions[permission_index]; + + if(!permission.flags.flag_value_update && !permission.flags.flag_grant_update) + continue; + + /* we only need an update it the permission has a DB reference or we will set the permission */ + if(permission.flags.database_reference || permission.flags.permission_set()) { + /* + PermissionType permission; + ChannelId channel_id; + + PermissionValues values; + PermissionUpdateType update_value; + PermissionUpdateType update_grant; + + bool flag_db: 1; + bool flag_delete: 1; + bool flag_skip: 1; + bool flag_negate: 1; + */ + auto& entry = result.emplace_back(v2::PermissionDBUpdateEntry{ + (PermissionType) (block_index * PERMISSIONS_BULK_ENTRY_COUNT + permission_index), + (ChannelId) 0, + + permission.values, + (PermissionUpdateType) (permission.flags.flag_value_update ? (permission.flags.value_set ? PermissionUpdateType::set_value : PermissionUpdateType::delete_value) : PermissionUpdateType::do_nothing), + (PermissionUpdateType) (permission.flags.flag_grant_update ? (permission.flags.grant_set ? PermissionUpdateType::set_value : PermissionUpdateType::delete_value) : PermissionUpdateType::do_nothing), + + (bool) permission.flags.database_reference, + (bool) !permission.flags.permission_set(), /* db delete */ + (bool) permission.flags.skip, + (bool) permission.flags.negate + }); + + /* required for the database */ + if(!permission.flags.value_set) + entry.values.value = permNotGranted; + + if(!permission.flags.grant_set) + entry.values.grant = permNotGranted; + + permission.flags.database_reference = permission.flags.permission_set(); + } + + permission.flags.flag_value_update = false; + permission.flags.flag_grant_update = false; + } + } + } + { + lock_guard chanel_lock(this->channel_list_lock); + for(size_t index = 0; index < this->_channel_permissions.size(); index++) { + auto& permission = this->_channel_permissions[index]; + if(!permission->flags.flag_value_update && !permission->flags.flag_grant_update) + continue; + + + /* we only need an update it the permission has a DB reference or we will set the permission */ + if(permission->flags.database_reference || permission->flags.permission_set()) { + + auto& entry = result.emplace_back(v2::PermissionDBUpdateEntry{ + permission->permission, + permission->channel_id, + + permission->values, + (PermissionUpdateType) (permission->flags.flag_value_update ? (permission->flags.value_set ? PermissionUpdateType::set_value : PermissionUpdateType::delete_value) : PermissionUpdateType::do_nothing), + (PermissionUpdateType) (permission->flags.flag_grant_update ? (permission->flags.grant_set ? PermissionUpdateType::set_value : PermissionUpdateType::delete_value) : PermissionUpdateType::do_nothing), + + (bool) permission->flags.database_reference, + (bool) !permission->flags.permission_set(), /* db delete */ + (bool) permission->flags.skip, + (bool) permission->flags.negate + }); + + /* required for the database */ + if(!permission->flags.value_set) + entry.values.value = permNotGranted; + + if(!permission->flags.grant_set) + entry.values.grant = permNotGranted; + + permission->flags.database_reference = permission->flags.permission_set(); + } + + permission->flags.flag_value_update = false; + permission->flags.flag_grant_update = false; + if(!permission->flags.permission_set()) { + this->_channel_permissions.erase(this->_channel_permissions.begin() + index); + index--; + } + } + } + + return result; +} + +size_t v2::PermissionRegister::used_memory() { + size_t result = sizeof(*this); + + for (auto &block_container : block_containers) { + if (block_container) + result += sizeof(PermissionContainerBulk); + } + + { + + shared_lock channel_lock(this->channel_list_lock); + result += this->_channel_permissions.size() * (sizeof(ChannelPermissionContainer) + sizeof(unique_ptr)); + } + + return result; +} + +void v2::PermissionRegister::cleanup() { + lock_guard use_lock(this->block_use_count_lock); + + for (auto &block_container : block_containers) { + if (!block_container) continue; + + bool used = false; + for(auto& permission : block_container->permissions) { + if(permission.flags.value_set || permission.flags.grant_set || permission.flags.channel_specific) { + used = true; + break; + } + } + if(used) + continue; + + delete block_container; + block_container = nullptr; + } +} diff --git a/src/PermissionRegister.h b/src/PermissionRegister.h index 78cb2c2..22b32ce 100644 --- a/src/PermissionRegister.h +++ b/src/PermissionRegister.h @@ -1,951 +1,951 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for memset */ -#include "./misc/spin_lock.h" -#include "Definitions.h" -#include "Variable.h" -#include "spdlog/fmt/ostr.h" // must be included - -#define permNotGranted (-2) -#define PERM_ID_GRANT ((ts::permission::PermissionType) (1U << 15U)) - -namespace ts { - class BasicChannel; - namespace permission { - typedef int32_t PermissionValue; - - enum PermissionSqlType { - SQL_PERM_GROUP, - SQL_PERM_CHANNEL, - SQL_PERM_USER, - SQL_PERM_PLAYLIST - }; - enum PermissionType : uint16_t { - undefined = (uint16_t) -1, - - permission_id_min = 0, /* we count unknown as defined permission as well */ - unknown = (uint16_t) 0, - ok = 0, - type_begin = 1, - - /* global */ - - /* global::information */ - b_serverinstance_help_view = type_begin, - b_serverinstance_version_view, - b_serverinstance_info_view, - b_serverinstance_virtualserver_list, - b_serverinstance_binding_list, - b_serverinstance_permission_list, - b_serverinstance_permission_find, - //b_serverinstance_allow_teaspeak_plugin, - - /* global::vs_management */ - b_virtualserver_create, - b_virtualserver_delete, - b_virtualserver_start_any, - b_virtualserver_stop_any, - b_virtualserver_change_machine_id, - b_virtualserver_change_template, - - /* global::administration */ - b_serverquery_login, - b_serverinstance_textmessage_send, - b_serverinstance_log_view, - b_serverinstance_log_add, - b_serverinstance_stop, - - /* global::settings */ - b_serverinstance_modify_settings, - b_serverinstance_modify_querygroup, - b_serverinstance_modify_templates, - - /* virtual_server */ - - /* virtual_server::information */ - b_virtualserver_select, - b_virtualserver_select_godmode, - b_virtualserver_info_view, - b_virtualserver_connectioninfo_view, - b_virtualserver_channel_list, - b_virtualserver_channel_search, - b_virtualserver_client_list, - b_virtualserver_client_search, - b_virtualserver_client_dblist, - b_virtualserver_client_dbsearch, - b_virtualserver_client_dbinfo, - b_virtualserver_permission_find, - b_virtualserver_custom_search, - - /* virtual_server::administration */ - b_virtualserver_start, - b_virtualserver_stop, - b_virtualserver_token_list, - b_virtualserver_token_add, - b_virtualserver_token_use, - b_virtualserver_token_delete, - b_virtualserver_log_view, - b_virtualserver_log_add, - b_virtualserver_join_ignore_password, - b_virtualserver_notify_register, - b_virtualserver_notify_unregister, - b_virtualserver_snapshot_create, - b_virtualserver_snapshot_deploy, - b_virtualserver_permission_reset, - - /* virtual_server::settings */ - b_virtualserver_modify_name, - b_virtualserver_modify_welcomemessage, - b_virtualserver_modify_maxchannels, - b_virtualserver_modify_maxclients, - b_virtualserver_modify_reserved_slots, - b_virtualserver_modify_password, - b_virtualserver_modify_default_servergroup, - b_virtualserver_modify_default_musicgroup, - b_virtualserver_modify_default_channelgroup, - b_virtualserver_modify_default_channeladmingroup, - b_virtualserver_modify_channel_forced_silence, - b_virtualserver_modify_complain, - b_virtualserver_modify_antiflood, - b_virtualserver_modify_ft_settings, - b_virtualserver_modify_ft_quotas, - b_virtualserver_modify_hostmessage, - b_virtualserver_modify_hostbanner, - b_virtualserver_modify_hostbutton, - b_virtualserver_modify_port, -#ifndef LAGENCY - b_virtualserver_modify_host, - b_virtualserver_modify_default_messages, -#endif - b_virtualserver_modify_autostart, - b_virtualserver_modify_needed_identity_security_level, - b_virtualserver_modify_priority_speaker_dimm_modificator, - b_virtualserver_modify_log_settings, - b_virtualserver_modify_min_client_version, - b_virtualserver_modify_icon_id, - b_virtualserver_modify_weblist, - b_virtualserver_modify_country_code, - b_virtualserver_modify_codec_encryption_mode, - b_virtualserver_modify_temporary_passwords, - b_virtualserver_modify_temporary_passwords_own, - b_virtualserver_modify_channel_temp_delete_delay_default, - b_virtualserver_modify_music_bot_limit, - - /* channel */ - i_channel_min_depth, - i_channel_max_depth, - b_channel_group_inheritance_end, - i_channel_permission_modify_power, - i_channel_needed_permission_modify_power, - - /* channel::info */ - b_channel_info_view, - b_virtualserver_channel_permission_list, - - /* channel::create */ - b_channel_create_child, - b_channel_create_permanent, - b_channel_create_semi_permanent, - b_channel_create_temporary, - b_channel_create_private, - b_channel_create_with_topic, - b_channel_create_with_description, - b_channel_create_with_password, - b_channel_create_modify_with_codec_speex8, - b_channel_create_modify_with_codec_speex16, - b_channel_create_modify_with_codec_speex32, - b_channel_create_modify_with_codec_celtmono48, - b_channel_create_modify_with_codec_opusvoice, - b_channel_create_modify_with_codec_opusmusic, - i_channel_create_modify_with_codec_maxquality, - i_channel_create_modify_with_codec_latency_factor_min, - b_channel_create_with_maxclients, - b_channel_create_with_maxfamilyclients, - b_channel_create_with_sortorder, - b_channel_create_with_default, - b_channel_create_with_needed_talk_power, - b_channel_create_modify_with_force_password, - i_channel_create_modify_with_temp_delete_delay, - i_channel_create_modify_conversation_history_length, - b_channel_create_modify_conversation_history_unlimited, - b_channel_create_modify_conversation_private, - - /* channel::modify */ - b_channel_modify_parent, - b_channel_modify_make_default, - b_channel_modify_make_permanent, - b_channel_modify_make_semi_permanent, - b_channel_modify_make_temporary, - b_channel_modify_name, - b_channel_modify_topic, - b_channel_modify_description, - b_channel_modify_password, - b_channel_modify_codec, - b_channel_modify_codec_quality, - b_channel_modify_codec_latency_factor, - b_channel_modify_maxclients, - b_channel_modify_maxfamilyclients, - b_channel_modify_sortorder, - b_channel_modify_needed_talk_power, - i_channel_modify_power, - i_channel_needed_modify_power, - b_channel_modify_make_codec_encrypted, - b_channel_modify_temp_delete_delay, - b_channel_conversation_message_delete, - - /* channel::delete */ - b_channel_delete_permanent, - b_channel_delete_semi_permanent, - b_channel_delete_temporary, - b_channel_delete_flag_force, - i_channel_delete_power, - i_channel_needed_delete_power, - - /* channel::access */ - b_channel_join_permanent, - b_channel_join_semi_permanent, - b_channel_join_temporary, - b_channel_join_ignore_password, - b_channel_join_ignore_maxclients, - i_channel_join_power, - i_channel_needed_join_power, - b_channel_ignore_join_power, - - i_channel_view_power, - i_channel_needed_view_power, - b_channel_ignore_view_power, - - i_channel_subscribe_power, - i_channel_needed_subscribe_power, - b_channel_ignore_subscribe_power, - - i_channel_description_view_power, - i_channel_needed_description_view_power, - b_channel_ignore_description_view_power, - - /* group */ - i_icon_id, - i_max_icon_filesize, - i_max_playlist_size, - i_max_playlists, - b_icon_manage, - b_group_is_permanent, - i_group_auto_update_type, - i_group_auto_update_max_value, - i_group_sort_id, - i_group_show_name_in_tree, - - /* group::info */ - b_virtualserver_servergroup_list, //Unused - b_virtualserver_servergroup_permission_list, - b_virtualserver_servergroup_client_list, - - b_virtualserver_channelgroup_list, //Unused - b_virtualserver_channelgroup_permission_list, - b_virtualserver_channelgroup_client_list, - - /* group::create */ - b_virtualserver_servergroup_create, - b_virtualserver_channelgroup_create, - - /* group::modify */ -#ifdef LAGENCY - i_group_modify_power, - i_group_needed_modify_power, - i_group_member_add_power, - i_group_needed_member_add_power, - i_group_member_remove_power, - i_group_needed_member_remove_power, -#else - //permission patch start - i_server_group_modify_power, - i_server_group_needed_modify_power, - i_server_group_member_add_power, - i_server_group_self_add_power, - i_server_group_needed_member_add_power, - i_server_group_member_remove_power, - i_server_group_self_remove_power, - i_server_group_needed_member_remove_power, - i_channel_group_modify_power, - i_channel_group_needed_modify_power, - i_channel_group_member_add_power, - i_channel_group_self_add_power, - i_channel_group_needed_member_add_power, - i_channel_group_member_remove_power, - i_channel_group_self_remove_power, - i_channel_group_needed_member_remove_power, - - i_displayed_group_member_add_power, - i_displayed_group_needed_member_add_power, - i_displayed_group_member_remove_power, - i_displayed_group_needed_member_remove_power, - i_displayed_group_modify_power, - i_displayed_group_needed_modify_power, - //permission patch end -#endif - i_permission_modify_power, - b_permission_modify_power_ignore, - - /* group::delete */ - b_virtualserver_servergroup_delete, - b_virtualserver_channelgroup_delete, - - /* client */ - i_client_permission_modify_power, - i_client_needed_permission_modify_power, - i_client_max_clones_uid, - i_client_max_clones_ip, - i_client_max_clones_hwid, - i_client_max_idletime, - i_client_max_avatar_filesize, - i_client_max_channel_subscriptions, - i_client_max_channels, - i_client_max_temporary_channels, - i_client_max_semi_channels, - i_client_max_permanent_channels, - b_client_use_priority_speaker, - b_client_is_priority_speaker, - b_client_skip_channelgroup_permissions, - b_client_force_push_to_talk, - b_client_ignore_bans, - b_client_ignore_vpn, - b_client_ignore_antiflood, - b_client_enforce_valid_hwid, - b_client_allow_invalid_packet, - b_client_allow_invalid_badges, - b_client_issue_client_query_command, - b_client_use_reserved_slot, - b_client_use_channel_commander, - b_client_request_talker, - b_client_avatar_delete_other, - b_client_is_sticky, - b_client_ignore_sticky, - - b_client_music_create_permanent, - b_client_music_create_semi_permanent, - b_client_music_create_temporary, - b_client_music_modify_permanent, - b_client_music_modify_semi_permanent, - b_client_music_modify_temporary, - i_client_music_create_modify_max_volume, - - i_client_music_limit, - i_client_music_needed_delete_power, - i_client_music_delete_power, - i_client_music_play_power, - i_client_music_needed_play_power, - i_client_music_modify_power, - i_client_music_needed_modify_power, - i_client_music_rename_power, - i_client_music_needed_rename_power, - - b_virtualserver_playlist_permission_list, - b_playlist_create, - i_playlist_view_power, - i_playlist_needed_view_power, - i_playlist_modify_power, - i_playlist_needed_modify_power, - i_playlist_permission_modify_power, - i_playlist_needed_permission_modify_power, - i_playlist_delete_power, - i_playlist_needed_delete_power, - - i_playlist_song_add_power, - i_playlist_song_needed_add_power, - i_playlist_song_remove_power, - i_playlist_song_needed_remove_power, - i_playlist_song_move_power, - i_playlist_song_needed_move_power, - - /* client::info */ - b_client_info_view, - b_client_permissionoverview_view, - b_client_permissionoverview_own, - b_client_remoteaddress_view, - i_client_serverquery_view_power, - i_client_needed_serverquery_view_power, - b_client_custom_info_view, - b_client_music_channel_list, - b_client_music_server_list, - i_client_music_info, - i_client_music_needed_info, - b_virtualserver_channelclient_permission_list, - b_virtualserver_client_permission_list, - - /* client::admin */ - i_client_kick_from_server_power, - i_client_needed_kick_from_server_power, - i_client_kick_from_channel_power, - i_client_needed_kick_from_channel_power, - i_client_ban_power, - i_client_needed_ban_power, - i_client_move_power, - i_client_needed_move_power, - i_client_complain_power, - i_client_needed_complain_power, - b_client_complain_list, - b_client_complain_delete_own, - b_client_complain_delete, - b_client_ban_list, - b_client_ban_list_global, - b_client_ban_trigger_list, - b_client_ban_create, - b_client_ban_create_global, - b_client_ban_name, - b_client_ban_ip, - b_client_ban_hwid, - b_client_ban_edit, - b_client_ban_edit_global, - b_client_ban_delete_own, - b_client_ban_delete, - b_client_ban_delete_own_global, - b_client_ban_delete_global, - i_client_ban_max_bantime, - - /* client::basics */ - i_client_private_textmessage_power, - i_client_needed_private_textmessage_power, - b_client_even_textmessage_send, - b_client_server_textmessage_send, - b_client_channel_textmessage_send, - b_client_offline_textmessage_send, - i_client_talk_power, - i_client_needed_talk_power, - i_client_poke_power, - i_client_needed_poke_power, - b_client_set_flag_talker, - i_client_whisper_power, - i_client_needed_whisper_power, - - /* client::modify */ - b_client_modify_description, - b_client_modify_own_description, - b_client_use_bbcode_any, - b_client_use_bbcode_url, - b_client_use_bbcode_image, - b_client_modify_dbproperties, - b_client_delete_dbproperties, - b_client_create_modify_serverquery_login, - b_client_query_create, - b_client_query_list, - b_client_query_list_own, - b_client_query_rename, - b_client_query_rename_own, - b_client_query_change_password, - b_client_query_change_own_password, - b_client_query_change_password_global, - b_client_query_delete, - b_client_query_delete_own, - - /* file_transfer */ - b_ft_ignore_password, - b_ft_transfer_list, - i_ft_file_upload_power, - i_ft_needed_file_upload_power, - i_ft_file_download_power, - i_ft_needed_file_download_power, - i_ft_file_delete_power, - i_ft_needed_file_delete_power, - i_ft_file_rename_power, - i_ft_needed_file_rename_power, - i_ft_file_browse_power, - i_ft_needed_file_browse_power, - i_ft_directory_create_power, - i_ft_needed_directory_create_power, - i_ft_quota_mb_download_per_client, - i_ft_quota_mb_upload_per_client, - - permission_id_max - }; - inline PermissionType& operator&=(PermissionType& a, int b) { return a = (PermissionType) ((int) a & b); } - - enum PermissionGroup : uint16_t { - group_begin, - global = group_begin, - global_info = b_serverinstance_permission_find, - global_vsmanage = b_virtualserver_change_template, - global_admin = b_serverinstance_stop, - global_settings = b_serverinstance_modify_templates, - - vs = global_settings, /* we dont have any permissions in here */ - vs_info = b_virtualserver_custom_search, - vs_admin = b_virtualserver_permission_reset, -#ifdef LEGENCY - vs_settings = b_virtualserver_modify_channel_temp_delete_delay_default, -#else - vs_settings = b_virtualserver_modify_music_bot_limit, -#endif - - channel = i_channel_needed_permission_modify_power, - channel_info = b_virtualserver_channel_permission_list, - channel_create = b_channel_create_modify_conversation_private, - channel_modify = b_channel_modify_temp_delete_delay, - channel_delete = i_channel_needed_delete_power, - channel_access = b_channel_ignore_description_view_power, - - group = i_group_show_name_in_tree, - group_info = b_virtualserver_channelgroup_client_list, - group_create = b_virtualserver_channelgroup_create, - group_modify = b_permission_modify_power_ignore, - group_delete = b_virtualserver_channelgroup_delete, -#ifdef LAGENCY - client = b_client_ignore_sticky, -#else - client = i_playlist_song_needed_move_power, -#endif -#ifdef LAGENCY - client_info = b_client_custom_info_view, -#else - client_info = b_virtualserver_client_permission_list, -#endif - client_admin = i_client_ban_max_bantime, - client_basic = i_client_needed_whisper_power, - client_modify = b_client_query_delete_own, - ft = i_ft_quota_mb_upload_per_client, - group_end - }; - - enum PermissionTestType { - PERMTEST_HIGHEST, - PERMTEST_ORDERED, - }; - - struct PermissionTypeEntry { - static std::shared_ptr unknown; - - PermissionTypeEntry& operator=(const PermissionTypeEntry& other) = delete; - /* - PermissionTypeEntry& operator=(const PermissionTypeEntry& other) { - this->type = other.type; - this->group = other.group; - this->name = other.name; - this->description = other.description; - this->clientSupported = other.clientSupported; - - this->grant_name = std::string() + (name[0] == 'i' ? "i" : "i") + "_needed_modify_power_" + name.substr(2); - return *this; - } - - bool operator==(const PermissionTypeEntry& other) { - return other.type == this->type; - } - */ - - PermissionType type; - PermissionGroup group; - std::string name; - std::string grant_name; - inline std::string grantName(bool useBool = false) const { return this->grant_name; } - std::string description; - - bool clientSupported = true; - - // PermissionTypeEntry(PermissionTypeEntry&& ref) : type(ref.type), group(ref.group), name(ref.name), description(ref.description), clientSupported(ref.clientSupported) {} - //PermissionTypeEntry(const PermissionTypeEntry& ref) : type(ref.type), group(ref.group), name(ref.name), description(ref.description), clientSupported(ref.clientSupported) {} - PermissionTypeEntry(PermissionTypeEntry&& ref) = delete; - PermissionTypeEntry(const PermissionTypeEntry& ref) = delete; - //PermissionTypeEntry(const PermissionTypeEntry& ref) : type(ref.type), group(ref.group), name(ref.name), description(ref.description), clientSupported(ref.clientSupported) {} - - PermissionTypeEntry(PermissionType type, PermissionGroup group, std::string name, std::string description, bool clientSupported = true) : type(type), - group(group), - name(std::move(name)), - description(std::move(description)), - clientSupported(clientSupported) { - this->grant_name = std::string() + (this->name[0] == 'i' ? "i" : "i") + "_needed_modify_power_" + this->name.substr(2); - } - }; - - namespace teamspeak { - enum GroupType { - GENERAL, - SERVER, - CHANNEL, - CLIENT - }; - - typedef std::map>> MapType; - extern MapType unmapping; - extern MapType mapping; - extern std::deque map_key(std::string key, GroupType type); //TeamSpeak -> TeaSpeak - extern std::deque unmap_key(std::string key, GroupType type); //TeaSpeak -> TeamSpeak - } - - namespace update { - enum GroupUpdateType { - NONE = 0, - - CHANNEL_GUEST = 10, - CHANNEL_VOICE = 25, - CHANNEL_OPERATOR = 35, - CHANNEL_ADMIN = 40, - - SERVER_GUEST = 15, - SERVER_NORMAL = 30, - SERVER_ADMIN = 45, - - QUERY_GUEST = 20, - QUERY_ADMIN = 50 - }; - - struct UpdatePermission { - UpdatePermission(std::string name, permission::PermissionValue value, permission::PermissionValue granted, bool negated, bool skipped) : name(std::move(name)), value(value), granted(granted), negated(negated), skipped(skipped) {} - UpdatePermission() = default; - - std::string name; - permission::PermissionValue value = permNotGranted; - permission::PermissionValue granted = permNotGranted; - - bool negated = false; - bool skipped = false; - }; - - struct UpdateEntry { - GroupUpdateType type; - UpdatePermission permission; - }; - - extern std::deque migrate; //TeamSpeak -> TeaSpeak - } - - extern std::deque> availablePermissions; - extern std::deque neededPermissions; - extern std::deque availableGroups; - - void setup_permission_resolve(); - std::shared_ptr resolvePermissionData(PermissionType); - std::shared_ptr resolvePermissionData(const std::string&); - -#define PERM_FLAG_PRIVATE 0b1 -#define PERM_FLAG_PUBLIC 0b10 - - class PermissionManager; - struct Permission { - public: - Permission(const std::shared_ptr& type, PermissionValue value, PermissionValue grant, uint16_t flagMask, std::shared_ptr ch) : type(type), channel(std::move(ch)) { - this->type = type; - this->value = value; - this->granted = grant; - this->flagMask = flagMask; - } - - - Permission(const Permission &) = delete; - - Permission() = delete; - ~Permission()= default; - - std::shared_ptr channel = nullptr; - ChannelId channelId(); - - bool hasValue(){ return value != permNotGranted; } - bool hasGrant(){ return granted != permNotGranted; } - std::shared_ptr type; - PermissionValue value; - PermissionValue granted; - uint16_t flagMask; - - bool flag_negate = false; - bool flag_skip = false; - bool dbReference = false; - }; - - class PermissionManager { - public: - PermissionManager(); - ~PermissionManager(); - - std::shared_ptr registerPermission(PermissionType, PermissionValue, const std::shared_ptr& channel, uint16_t = PERM_FLAG_PUBLIC); - std::shared_ptr registerPermission(const std::shared_ptr&, PermissionValue, const std::shared_ptr& channel, uint16_t = PERM_FLAG_PUBLIC); - //void registerAllPermissions(uint16_t flagMask); - - bool setPermissionGranted(PermissionType, PermissionValue, const std::shared_ptr& channel); - bool setPermission(PermissionType, PermissionValue, const std::shared_ptr& channel); - bool setPermission(PermissionType, PermissionValue, const std::shared_ptr& channel, bool negated, bool skiped); - void deletePermission(PermissionType, const std::shared_ptr& channel); - bool hasPermission(PermissionType, const std::shared_ptr& channel, bool testGlobal); - - /** - * @param channel Should be null for general testing - * @return , - */ - std::deque> getPermission(PermissionType, const std::shared_ptr& channel, bool testGlobal = true); - - PermissionValue getPermissionGrand(permission::PermissionTestType test, PermissionType type, const std::shared_ptr& channel, PermissionValue def = permNotGranted){ - PermissionValue result = def; - auto perms = this->getPermission(type, channel); - if(test == PermissionTestType::PERMTEST_HIGHEST) { - PermissionValue higest = permNotGranted; - for(const auto &e : perms) - if((e->granted > higest || e->granted == -1) && higest != -1) higest = e->granted; - if(higest != permNotGranted) - result = higest; - } else if(test == PermissionTestType::PERMTEST_ORDERED) - while(!perms.empty() && result == permNotGranted) { - result = perms.front()->granted; - perms.pop_front(); - }; - return result; - } - - inline PermissionValue getPermissionValue(PermissionType type, const std::shared_ptr& channel = nullptr, PermissionValue default_value = permNotGranted) { - return this->getPermissionValue(permission::PERMTEST_ORDERED, type, channel, default_value); - } - - PermissionValue getPermissionValue(permission::PermissionTestType test, PermissionType type, const std::shared_ptr& channel = nullptr, PermissionValue def = permNotGranted) { - PermissionValue result = permNotGranted; - auto perms = this->getPermission(type, channel); - if(test == permission::PERMTEST_HIGHEST) { - PermissionValue higest = permNotGranted; - for(const auto &e : perms) - if((e->value > higest || e->value == -1) && higest != -1) higest = e->value; - if(higest != permNotGranted) - result = higest; - } else if(test == PermissionTestType::PERMTEST_ORDERED) - while(!perms.empty() && result == permNotGranted) { - result = perms.front()->value; - perms.pop_front(); - }; - return result == permNotGranted ? def : result; - } - - std::vector> listPermissions(uint16_t = ~0); - std::vector> allPermissions(); - - std::deque> all_channel_specific_permissions(); - std::deque> all_channel_unspecific_permissions(); - - void fireUpdate(PermissionType); - void registerUpdateHandler(const std::function)> &fn){ updateHandler.push_back(fn); } - - void clearPermissions(){ - permissions.clear(); - } - private: - std::deque> permissions; - std::deque)>> updateHandler; - }; - - namespace v2 { - #pragma pack(push, 1) - struct PermissionFlags { - bool database_reference: 1; /* if set the permission is known within the database, else it has tp be inserted */ - bool channel_specific: 1; /* set if there are channel specific permissions */ - - bool value_set: 1; - bool grant_set: 1; - - bool skip: 1; - bool negate: 1; - - bool flag_value_update: 1; - bool flag_grant_update: 1; - - ts_always_inline bool permission_set() { - return this->value_set || this->grant_set; - } - }; - static_assert(sizeof(PermissionFlags) == 1); - - struct PermissionValues { - PermissionValue value; - PermissionValue grant; - }; - static_assert(sizeof(PermissionValues) == 8); - static constexpr PermissionValues empty_permission_values{0, 0}; - - struct PermissionContainer { - PermissionFlags flags; - PermissionValues values; - }; - static_assert(sizeof(PermissionContainer) == 9); - - struct ChannelPermissionContainer : public PermissionContainer { - PermissionType permission; - ChannelId channel_id; - }; - static_assert(sizeof(ChannelPermissionContainer) == 19); - static constexpr v2::PermissionFlags empty_flags = {false, false, false, false, false, false, false}; - static constexpr v2::PermissionContainer empty_channel_permission = {empty_flags, v2::empty_permission_values}; - - #pragma pack(pop) - - #pragma pack(push, 1) - template - struct PermissionContainerBulk { - PermissionContainer permissions[element_count]; - - PermissionContainerBulk() { - memset(this->permissions, 0, sizeof(this->permissions)); - } - }; - #pragma pack(pop) - - enum PermissionUpdateType { - do_nothing, - set_value, - delete_value - }; - - struct PermissionDBUpdateEntry { - PermissionType permission; - ChannelId channel_id; - - PermissionValues values; - PermissionUpdateType update_value; - PermissionUpdateType update_grant; - - bool flag_db: 1; /* only needs an update if set */ - bool flag_delete: 1; - bool flag_skip: 1; - bool flag_negate: 1; - }; - - struct PermissionFlaggedValue { - PermissionValue value = permNotGranted; - bool has_value = false; - - constexpr bool has_power() const { return this->has_value && (this->value > 0 || this->value == -1); } - constexpr bool has_infinite_power() const { return this->has_value && this->value == -1; } - - inline bool operator==(const PermissionFlaggedValue& other) const { return other.value == this->value && other.has_value == this->has_value; } - inline bool operator!=(const PermissionFlaggedValue& other) const { return !(*this == other); } - }; - static constexpr PermissionFlaggedValue empty_permission_flagged_value{0, false}; - - - static constexpr bool permission_granted(const PermissionFlaggedValue& required, const PermissionFlaggedValue& given, bool requires_given = true) { - if(!required.has_value) { - return !requires_given || given.has_power(); - } else if(!given.has_power()) { - return false; - } else if(given.has_infinite_power()) { - return true; - } else if(required.has_infinite_power()) { - return false; - } else { - return given.value >= required.value; - } - } - static constexpr bool permission_granted(const PermissionValue& required, const PermissionFlaggedValue& given, bool requires_given = true) { - return permission_granted({required, true}, given, requires_given); - } - - class PermissionRegister { - public: - static constexpr size_t PERMISSIONS_BULK_BITS = 4; /* 16 permissions per block */ - static constexpr size_t PERMISSIONS_BULK_ENTRY_COUNT = 1 << PERMISSIONS_BULK_BITS; - static constexpr size_t BULK_COUNT = (PermissionType::permission_id_max / (1 << PERMISSIONS_BULK_BITS)) + ((PermissionType::permission_id_max % PERMISSIONS_BULK_ENTRY_COUNT == 0) ? 0 : 1); - static_assert(PERMISSIONS_BULK_ENTRY_COUNT * BULK_COUNT >= PermissionType::permission_id_max); - - PermissionRegister(); - virtual ~PermissionRegister(); - - /* load permissions from the database */ - void load_permission(const PermissionType&, const PermissionValues& /* values */, bool /* flag skip */, bool /* flag negate */, bool /* value present */,bool /* grant present */); - void load_permission(const PermissionType&, const PermissionValues& /* values */, ChannelId /* channel */, bool /* flag skip */, bool /* flag negate */, bool /* value present */,bool /* grant present */); - - /* general getters/setters */ - const PermissionFlags permission_flags(const PermissionType&); /* we return a "copy" because the actual permission could be deleted while we're analyzing the flags */ - ts_always_inline const PermissionFlags permission_flags(const std::shared_ptr& permission_info) { return this->permission_flags(permission_info->type); } - - const PermissionValues permission_values(const PermissionType&); - ts_always_inline const PermissionValues permission_values(const std::shared_ptr& permission_info) { return this->permission_values(permission_info->type); } - - const PermissionFlaggedValue permission_value_flagged(const PermissionType&); - ts_always_inline const PermissionFlaggedValue permission_value_flagged(const std::shared_ptr& permission_info) { return this->permission_value_flagged(permission_info->type); } - - const PermissionFlaggedValue permission_granted_flagged(const PermissionType&); - ts_always_inline const PermissionFlaggedValue permission_granted_flagged(const std::shared_ptr& permission_info) { return this->permission_granted_flagged(permission_info->type); } - - /* only worth looking up if channel_specific is set */ - const PermissionContainer channel_permission(const PermissionType& /* permission */, ChannelId /* channel id */); - ts_always_inline const PermissionContainer channel_permission(const std::shared_ptr& permission_info, ChannelId channel_id) { return this->channel_permission(permission_info->type, channel_id); } - - /* modifiers */ - void set_permission(const PermissionType& /* permission */, const PermissionValues& /* values */, const PermissionUpdateType& /* update value */, const PermissionUpdateType& /* update grant */, int /* flag skip */ = -1, int /* flag negate */ = -1); - void set_channel_permission(const PermissionType& /* permission */, ChannelId /* channel id */, const PermissionValues& /* values */, const PermissionUpdateType& /* update value */, const PermissionUpdateType& /* update grant */, int /* flag skip */ = -1, int /* flag negate */ = -1); - - /* bulk info */ - const std::vector> permissions(); - const std::vector> channel_permissions(ChannelId /* channel id */); - const std::vector> channel_permissions(); - - size_t used_memory(); - void cleanup(); - - ts_always_inline bool require_db_updates() { return this->requires_db_save; } - const std::vector flush_db_updates(); - private: - static constexpr size_t PERMISSIONS_BULK_BLOCK_MASK = (~(1 << PERMISSIONS_BULK_BITS)) & ((1 << PERMISSIONS_BULK_BITS) - 1); - - bool requires_db_save = false; - ts_always_inline void trigger_db_update() { this->requires_db_save = true; } - - spin_lock block_use_count_lock{}; - int16_t block_use_count[BULK_COUNT]; - PermissionContainerBulk* block_containers[BULK_COUNT]; - - //TODO: Bulk permissions for channels as well, specially because they're client permissions in terms of the music bot! - std::shared_mutex channel_list_lock{}; - std::deque> _channel_permissions{}; - - ts_always_inline size_t calculate_block(const PermissionType& permission) { - return permission >> PERMISSIONS_BULK_BITS; - } - - ts_always_inline size_t calculate_block_index(const PermissionType& permission) { - return permission & PERMISSIONS_BULK_BLOCK_MASK; - } - - /** - * @param block - * @return true if block exists else false - */ - ts_always_inline bool ref_block(size_t block) { - std::lock_guard use_lock(this->block_use_count_lock); - if(!this->block_containers[block]) - return false; - this->block_use_count[block]++; - assert(this->block_use_count[block] > 0); - return true; - } - - ts_always_inline void unref_block(size_t block) { - std::lock_guard use_lock(this->block_use_count_lock); - this->block_use_count[block]--; - assert(this->block_use_count[block] >= 0); - } - - ts_always_inline void ref_allocate_block(size_t block) { - std::lock_guard use_lock(this->block_use_count_lock); - if(!this->block_containers[block]) - this->block_containers[block] = new PermissionContainerBulk(); - this->block_use_count[block]++; - assert(this->block_use_count[block] > 0); - } - }; - } - } -} - -inline std::ostream& operator<<(std::ostream& os, const ts::permission::v2::PermissionFlaggedValue& c) { - if(c.has_value) - return os << c.value; - else - return os << "unset"; -} - -DEFINE_VARIABLE_TRANSFORM(ts::permission::PermissionType, VARTYPE_INT, std::to_string((int16_t) in), static_cast(in.as())); -DEFINE_VARIABLE_TRANSFORM(ts::permission::PermissionGroup, VARTYPE_INT, std::to_string((uint16_t) in), static_cast(in.as())); +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for memset */ +#include "./misc/spin_lock.h" +#include "Definitions.h" +#include "Variable.h" +#include "spdlog/fmt/ostr.h" // must be included + +#define permNotGranted (-2) +#define PERM_ID_GRANT ((ts::permission::PermissionType) (1U << 15U)) + +namespace ts { + class BasicChannel; + namespace permission { + typedef int32_t PermissionValue; + + enum PermissionSqlType { + SQL_PERM_GROUP, + SQL_PERM_CHANNEL, + SQL_PERM_USER, + SQL_PERM_PLAYLIST + }; + enum PermissionType : uint16_t { + undefined = (uint16_t) -1, + + permission_id_min = 0, /* we count unknown as defined permission as well */ + unknown = (uint16_t) 0, + ok = 0, + type_begin = 1, + + /* global */ + + /* global::information */ + b_serverinstance_help_view = type_begin, + b_serverinstance_version_view, + b_serverinstance_info_view, + b_serverinstance_virtualserver_list, + b_serverinstance_binding_list, + b_serverinstance_permission_list, + b_serverinstance_permission_find, + //b_serverinstance_allow_teaspeak_plugin, + + /* global::vs_management */ + b_virtualserver_create, + b_virtualserver_delete, + b_virtualserver_start_any, + b_virtualserver_stop_any, + b_virtualserver_change_machine_id, + b_virtualserver_change_template, + + /* global::administration */ + b_serverquery_login, + b_serverinstance_textmessage_send, + b_serverinstance_log_view, + b_serverinstance_log_add, + b_serverinstance_stop, + + /* global::settings */ + b_serverinstance_modify_settings, + b_serverinstance_modify_querygroup, + b_serverinstance_modify_templates, + + /* virtual_server */ + + /* virtual_server::information */ + b_virtualserver_select, + b_virtualserver_select_godmode, + b_virtualserver_info_view, + b_virtualserver_connectioninfo_view, + b_virtualserver_channel_list, + b_virtualserver_channel_search, + b_virtualserver_client_list, + b_virtualserver_client_search, + b_virtualserver_client_dblist, + b_virtualserver_client_dbsearch, + b_virtualserver_client_dbinfo, + b_virtualserver_permission_find, + b_virtualserver_custom_search, + + /* virtual_server::administration */ + b_virtualserver_start, + b_virtualserver_stop, + b_virtualserver_token_list, + b_virtualserver_token_add, + b_virtualserver_token_use, + b_virtualserver_token_delete, + b_virtualserver_log_view, + b_virtualserver_log_add, + b_virtualserver_join_ignore_password, + b_virtualserver_notify_register, + b_virtualserver_notify_unregister, + b_virtualserver_snapshot_create, + b_virtualserver_snapshot_deploy, + b_virtualserver_permission_reset, + + /* virtual_server::settings */ + b_virtualserver_modify_name, + b_virtualserver_modify_welcomemessage, + b_virtualserver_modify_maxchannels, + b_virtualserver_modify_maxclients, + b_virtualserver_modify_reserved_slots, + b_virtualserver_modify_password, + b_virtualserver_modify_default_servergroup, + b_virtualserver_modify_default_musicgroup, + b_virtualserver_modify_default_channelgroup, + b_virtualserver_modify_default_channeladmingroup, + b_virtualserver_modify_channel_forced_silence, + b_virtualserver_modify_complain, + b_virtualserver_modify_antiflood, + b_virtualserver_modify_ft_settings, + b_virtualserver_modify_ft_quotas, + b_virtualserver_modify_hostmessage, + b_virtualserver_modify_hostbanner, + b_virtualserver_modify_hostbutton, + b_virtualserver_modify_port, +#ifndef LAGENCY + b_virtualserver_modify_host, + b_virtualserver_modify_default_messages, +#endif + b_virtualserver_modify_autostart, + b_virtualserver_modify_needed_identity_security_level, + b_virtualserver_modify_priority_speaker_dimm_modificator, + b_virtualserver_modify_log_settings, + b_virtualserver_modify_min_client_version, + b_virtualserver_modify_icon_id, + b_virtualserver_modify_weblist, + b_virtualserver_modify_country_code, + b_virtualserver_modify_codec_encryption_mode, + b_virtualserver_modify_temporary_passwords, + b_virtualserver_modify_temporary_passwords_own, + b_virtualserver_modify_channel_temp_delete_delay_default, + b_virtualserver_modify_music_bot_limit, + + /* channel */ + i_channel_min_depth, + i_channel_max_depth, + b_channel_group_inheritance_end, + i_channel_permission_modify_power, + i_channel_needed_permission_modify_power, + + /* channel::info */ + b_channel_info_view, + b_virtualserver_channel_permission_list, + + /* channel::create */ + b_channel_create_child, + b_channel_create_permanent, + b_channel_create_semi_permanent, + b_channel_create_temporary, + b_channel_create_private, + b_channel_create_with_topic, + b_channel_create_with_description, + b_channel_create_with_password, + b_channel_create_modify_with_codec_speex8, + b_channel_create_modify_with_codec_speex16, + b_channel_create_modify_with_codec_speex32, + b_channel_create_modify_with_codec_celtmono48, + b_channel_create_modify_with_codec_opusvoice, + b_channel_create_modify_with_codec_opusmusic, + i_channel_create_modify_with_codec_maxquality, + i_channel_create_modify_with_codec_latency_factor_min, + b_channel_create_with_maxclients, + b_channel_create_with_maxfamilyclients, + b_channel_create_with_sortorder, + b_channel_create_with_default, + b_channel_create_with_needed_talk_power, + b_channel_create_modify_with_force_password, + i_channel_create_modify_with_temp_delete_delay, + i_channel_create_modify_conversation_history_length, + b_channel_create_modify_conversation_history_unlimited, + b_channel_create_modify_conversation_private, + + /* channel::modify */ + b_channel_modify_parent, + b_channel_modify_make_default, + b_channel_modify_make_permanent, + b_channel_modify_make_semi_permanent, + b_channel_modify_make_temporary, + b_channel_modify_name, + b_channel_modify_topic, + b_channel_modify_description, + b_channel_modify_password, + b_channel_modify_codec, + b_channel_modify_codec_quality, + b_channel_modify_codec_latency_factor, + b_channel_modify_maxclients, + b_channel_modify_maxfamilyclients, + b_channel_modify_sortorder, + b_channel_modify_needed_talk_power, + i_channel_modify_power, + i_channel_needed_modify_power, + b_channel_modify_make_codec_encrypted, + b_channel_modify_temp_delete_delay, + b_channel_conversation_message_delete, + + /* channel::delete */ + b_channel_delete_permanent, + b_channel_delete_semi_permanent, + b_channel_delete_temporary, + b_channel_delete_flag_force, + i_channel_delete_power, + i_channel_needed_delete_power, + + /* channel::access */ + b_channel_join_permanent, + b_channel_join_semi_permanent, + b_channel_join_temporary, + b_channel_join_ignore_password, + b_channel_join_ignore_maxclients, + i_channel_join_power, + i_channel_needed_join_power, + b_channel_ignore_join_power, + + i_channel_view_power, + i_channel_needed_view_power, + b_channel_ignore_view_power, + + i_channel_subscribe_power, + i_channel_needed_subscribe_power, + b_channel_ignore_subscribe_power, + + i_channel_description_view_power, + i_channel_needed_description_view_power, + b_channel_ignore_description_view_power, + + /* group */ + i_icon_id, + i_max_icon_filesize, + i_max_playlist_size, + i_max_playlists, + b_icon_manage, + b_group_is_permanent, + i_group_auto_update_type, + i_group_auto_update_max_value, + i_group_sort_id, + i_group_show_name_in_tree, + + /* group::info */ + b_virtualserver_servergroup_list, //Unused + b_virtualserver_servergroup_permission_list, + b_virtualserver_servergroup_client_list, + + b_virtualserver_channelgroup_list, //Unused + b_virtualserver_channelgroup_permission_list, + b_virtualserver_channelgroup_client_list, + + /* group::create */ + b_virtualserver_servergroup_create, + b_virtualserver_channelgroup_create, + + /* group::modify */ +#ifdef LAGENCY + i_group_modify_power, + i_group_needed_modify_power, + i_group_member_add_power, + i_group_needed_member_add_power, + i_group_member_remove_power, + i_group_needed_member_remove_power, +#else + //permission patch start + i_server_group_modify_power, + i_server_group_needed_modify_power, + i_server_group_member_add_power, + i_server_group_self_add_power, + i_server_group_needed_member_add_power, + i_server_group_member_remove_power, + i_server_group_self_remove_power, + i_server_group_needed_member_remove_power, + i_channel_group_modify_power, + i_channel_group_needed_modify_power, + i_channel_group_member_add_power, + i_channel_group_self_add_power, + i_channel_group_needed_member_add_power, + i_channel_group_member_remove_power, + i_channel_group_self_remove_power, + i_channel_group_needed_member_remove_power, + + i_displayed_group_member_add_power, + i_displayed_group_needed_member_add_power, + i_displayed_group_member_remove_power, + i_displayed_group_needed_member_remove_power, + i_displayed_group_modify_power, + i_displayed_group_needed_modify_power, + //permission patch end +#endif + i_permission_modify_power, + b_permission_modify_power_ignore, + + /* group::delete */ + b_virtualserver_servergroup_delete, + b_virtualserver_channelgroup_delete, + + /* client */ + i_client_permission_modify_power, + i_client_needed_permission_modify_power, + i_client_max_clones_uid, + i_client_max_clones_ip, + i_client_max_clones_hwid, + i_client_max_idletime, + i_client_max_avatar_filesize, + i_client_max_channel_subscriptions, + i_client_max_channels, + i_client_max_temporary_channels, + i_client_max_semi_channels, + i_client_max_permanent_channels, + b_client_use_priority_speaker, + b_client_is_priority_speaker, + b_client_skip_channelgroup_permissions, + b_client_force_push_to_talk, + b_client_ignore_bans, + b_client_ignore_vpn, + b_client_ignore_antiflood, + b_client_enforce_valid_hwid, + b_client_allow_invalid_packet, + b_client_allow_invalid_badges, + b_client_issue_client_query_command, + b_client_use_reserved_slot, + b_client_use_channel_commander, + b_client_request_talker, + b_client_avatar_delete_other, + b_client_is_sticky, + b_client_ignore_sticky, + + b_client_music_create_permanent, + b_client_music_create_semi_permanent, + b_client_music_create_temporary, + b_client_music_modify_permanent, + b_client_music_modify_semi_permanent, + b_client_music_modify_temporary, + i_client_music_create_modify_max_volume, + + i_client_music_limit, + i_client_music_needed_delete_power, + i_client_music_delete_power, + i_client_music_play_power, + i_client_music_needed_play_power, + i_client_music_modify_power, + i_client_music_needed_modify_power, + i_client_music_rename_power, + i_client_music_needed_rename_power, + + b_virtualserver_playlist_permission_list, + b_playlist_create, + i_playlist_view_power, + i_playlist_needed_view_power, + i_playlist_modify_power, + i_playlist_needed_modify_power, + i_playlist_permission_modify_power, + i_playlist_needed_permission_modify_power, + i_playlist_delete_power, + i_playlist_needed_delete_power, + + i_playlist_song_add_power, + i_playlist_song_needed_add_power, + i_playlist_song_remove_power, + i_playlist_song_needed_remove_power, + i_playlist_song_move_power, + i_playlist_song_needed_move_power, + + /* client::info */ + b_client_info_view, + b_client_permissionoverview_view, + b_client_permissionoverview_own, + b_client_remoteaddress_view, + i_client_serverquery_view_power, + i_client_needed_serverquery_view_power, + b_client_custom_info_view, + b_client_music_channel_list, + b_client_music_server_list, + i_client_music_info, + i_client_music_needed_info, + b_virtualserver_channelclient_permission_list, + b_virtualserver_client_permission_list, + + /* client::admin */ + i_client_kick_from_server_power, + i_client_needed_kick_from_server_power, + i_client_kick_from_channel_power, + i_client_needed_kick_from_channel_power, + i_client_ban_power, + i_client_needed_ban_power, + i_client_move_power, + i_client_needed_move_power, + i_client_complain_power, + i_client_needed_complain_power, + b_client_complain_list, + b_client_complain_delete_own, + b_client_complain_delete, + b_client_ban_list, + b_client_ban_list_global, + b_client_ban_trigger_list, + b_client_ban_create, + b_client_ban_create_global, + b_client_ban_name, + b_client_ban_ip, + b_client_ban_hwid, + b_client_ban_edit, + b_client_ban_edit_global, + b_client_ban_delete_own, + b_client_ban_delete, + b_client_ban_delete_own_global, + b_client_ban_delete_global, + i_client_ban_max_bantime, + + /* client::basics */ + i_client_private_textmessage_power, + i_client_needed_private_textmessage_power, + b_client_even_textmessage_send, + b_client_server_textmessage_send, + b_client_channel_textmessage_send, + b_client_offline_textmessage_send, + i_client_talk_power, + i_client_needed_talk_power, + i_client_poke_power, + i_client_needed_poke_power, + b_client_set_flag_talker, + i_client_whisper_power, + i_client_needed_whisper_power, + + /* client::modify */ + b_client_modify_description, + b_client_modify_own_description, + b_client_use_bbcode_any, + b_client_use_bbcode_url, + b_client_use_bbcode_image, + b_client_modify_dbproperties, + b_client_delete_dbproperties, + b_client_create_modify_serverquery_login, + b_client_query_create, + b_client_query_list, + b_client_query_list_own, + b_client_query_rename, + b_client_query_rename_own, + b_client_query_change_password, + b_client_query_change_own_password, + b_client_query_change_password_global, + b_client_query_delete, + b_client_query_delete_own, + + /* file_transfer */ + b_ft_ignore_password, + b_ft_transfer_list, + i_ft_file_upload_power, + i_ft_needed_file_upload_power, + i_ft_file_download_power, + i_ft_needed_file_download_power, + i_ft_file_delete_power, + i_ft_needed_file_delete_power, + i_ft_file_rename_power, + i_ft_needed_file_rename_power, + i_ft_file_browse_power, + i_ft_needed_file_browse_power, + i_ft_directory_create_power, + i_ft_needed_directory_create_power, + i_ft_quota_mb_download_per_client, + i_ft_quota_mb_upload_per_client, + + permission_id_max + }; + inline PermissionType& operator&=(PermissionType& a, int b) { return a = (PermissionType) ((int) a & b); } + + enum PermissionGroup : uint16_t { + group_begin, + global = group_begin, + global_info = b_serverinstance_permission_find, + global_vsmanage = b_virtualserver_change_template, + global_admin = b_serverinstance_stop, + global_settings = b_serverinstance_modify_templates, + + vs = global_settings, /* we dont have any permissions in here */ + vs_info = b_virtualserver_custom_search, + vs_admin = b_virtualserver_permission_reset, +#ifdef LEGENCY + vs_settings = b_virtualserver_modify_channel_temp_delete_delay_default, +#else + vs_settings = b_virtualserver_modify_music_bot_limit, +#endif + + channel = i_channel_needed_permission_modify_power, + channel_info = b_virtualserver_channel_permission_list, + channel_create = b_channel_create_modify_conversation_private, + channel_modify = b_channel_modify_temp_delete_delay, + channel_delete = i_channel_needed_delete_power, + channel_access = b_channel_ignore_description_view_power, + + group = i_group_show_name_in_tree, + group_info = b_virtualserver_channelgroup_client_list, + group_create = b_virtualserver_channelgroup_create, + group_modify = b_permission_modify_power_ignore, + group_delete = b_virtualserver_channelgroup_delete, +#ifdef LAGENCY + client = b_client_ignore_sticky, +#else + client = i_playlist_song_needed_move_power, +#endif +#ifdef LAGENCY + client_info = b_client_custom_info_view, +#else + client_info = b_virtualserver_client_permission_list, +#endif + client_admin = i_client_ban_max_bantime, + client_basic = i_client_needed_whisper_power, + client_modify = b_client_query_delete_own, + ft = i_ft_quota_mb_upload_per_client, + group_end + }; + + enum PermissionTestType { + PERMTEST_HIGHEST, + PERMTEST_ORDERED, + }; + + struct PermissionTypeEntry { + static std::shared_ptr unknown; + + PermissionTypeEntry& operator=(const PermissionTypeEntry& other) = delete; + /* + PermissionTypeEntry& operator=(const PermissionTypeEntry& other) { + this->type = other.type; + this->group = other.group; + this->name = other.name; + this->description = other.description; + this->clientSupported = other.clientSupported; + + this->grant_name = std::string() + (name[0] == 'i' ? "i" : "i") + "_needed_modify_power_" + name.substr(2); + return *this; + } + + bool operator==(const PermissionTypeEntry& other) { + return other.type == this->type; + } + */ + + PermissionType type; + PermissionGroup group; + std::string name; + std::string grant_name; + inline std::string grantName(bool useBool = false) const { return this->grant_name; } + std::string description; + + bool clientSupported = true; + + // PermissionTypeEntry(PermissionTypeEntry&& ref) : type(ref.type), group(ref.group), name(ref.name), description(ref.description), clientSupported(ref.clientSupported) {} + //PermissionTypeEntry(const PermissionTypeEntry& ref) : type(ref.type), group(ref.group), name(ref.name), description(ref.description), clientSupported(ref.clientSupported) {} + PermissionTypeEntry(PermissionTypeEntry&& ref) = delete; + PermissionTypeEntry(const PermissionTypeEntry& ref) = delete; + //PermissionTypeEntry(const PermissionTypeEntry& ref) : type(ref.type), group(ref.group), name(ref.name), description(ref.description), clientSupported(ref.clientSupported) {} + + PermissionTypeEntry(PermissionType type, PermissionGroup group, std::string name, std::string description, bool clientSupported = true) : type(type), + group(group), + name(std::move(name)), + description(std::move(description)), + clientSupported(clientSupported) { + this->grant_name = std::string() + (this->name[0] == 'i' ? "i" : "i") + "_needed_modify_power_" + this->name.substr(2); + } + }; + + namespace teamspeak { + enum GroupType { + GENERAL, + SERVER, + CHANNEL, + CLIENT + }; + + typedef std::map>> MapType; + extern MapType unmapping; + extern MapType mapping; + extern std::deque map_key(std::string key, GroupType type); //TeamSpeak -> TeaSpeak + extern std::deque unmap_key(std::string key, GroupType type); //TeaSpeak -> TeamSpeak + } + + namespace update { + enum GroupUpdateType { + NONE = 0, + + CHANNEL_GUEST = 10, + CHANNEL_VOICE = 25, + CHANNEL_OPERATOR = 35, + CHANNEL_ADMIN = 40, + + SERVER_GUEST = 15, + SERVER_NORMAL = 30, + SERVER_ADMIN = 45, + + QUERY_GUEST = 20, + QUERY_ADMIN = 50 + }; + + struct UpdatePermission { + UpdatePermission(std::string name, permission::PermissionValue value, permission::PermissionValue granted, bool negated, bool skipped) : name(std::move(name)), value(value), granted(granted), negated(negated), skipped(skipped) {} + UpdatePermission() = default; + + std::string name; + permission::PermissionValue value = permNotGranted; + permission::PermissionValue granted = permNotGranted; + + bool negated = false; + bool skipped = false; + }; + + struct UpdateEntry { + GroupUpdateType type; + UpdatePermission permission; + }; + + extern std::deque migrate; //TeamSpeak -> TeaSpeak + } + + extern std::deque> availablePermissions; + extern std::deque neededPermissions; + extern std::deque availableGroups; + + void setup_permission_resolve(); + std::shared_ptr resolvePermissionData(PermissionType); + std::shared_ptr resolvePermissionData(const std::string&); + +#define PERM_FLAG_PRIVATE 0b1 +#define PERM_FLAG_PUBLIC 0b10 + + class PermissionManager; + struct Permission { + public: + Permission(const std::shared_ptr& type, PermissionValue value, PermissionValue grant, uint16_t flagMask, std::shared_ptr ch) : type(type), channel(std::move(ch)) { + this->type = type; + this->value = value; + this->granted = grant; + this->flagMask = flagMask; + } + + + Permission(const Permission &) = delete; + + Permission() = delete; + ~Permission()= default; + + std::shared_ptr channel = nullptr; + ChannelId channelId(); + + bool hasValue(){ return value != permNotGranted; } + bool hasGrant(){ return granted != permNotGranted; } + std::shared_ptr type; + PermissionValue value; + PermissionValue granted; + uint16_t flagMask; + + bool flag_negate = false; + bool flag_skip = false; + bool dbReference = false; + }; + + class PermissionManager { + public: + PermissionManager(); + ~PermissionManager(); + + std::shared_ptr registerPermission(PermissionType, PermissionValue, const std::shared_ptr& channel, uint16_t = PERM_FLAG_PUBLIC); + std::shared_ptr registerPermission(const std::shared_ptr&, PermissionValue, const std::shared_ptr& channel, uint16_t = PERM_FLAG_PUBLIC); + //void registerAllPermissions(uint16_t flagMask); + + bool setPermissionGranted(PermissionType, PermissionValue, const std::shared_ptr& channel); + bool setPermission(PermissionType, PermissionValue, const std::shared_ptr& channel); + bool setPermission(PermissionType, PermissionValue, const std::shared_ptr& channel, bool negated, bool skiped); + void deletePermission(PermissionType, const std::shared_ptr& channel); + bool hasPermission(PermissionType, const std::shared_ptr& channel, bool testGlobal); + + /** + * @param channel Should be null for general testing + * @return , + */ + std::deque> getPermission(PermissionType, const std::shared_ptr& channel, bool testGlobal = true); + + PermissionValue getPermissionGrand(permission::PermissionTestType test, PermissionType type, const std::shared_ptr& channel, PermissionValue def = permNotGranted){ + PermissionValue result = def; + auto perms = this->getPermission(type, channel); + if(test == PermissionTestType::PERMTEST_HIGHEST) { + PermissionValue higest = permNotGranted; + for(const auto &e : perms) + if((e->granted > higest || e->granted == -1) && higest != -1) higest = e->granted; + if(higest != permNotGranted) + result = higest; + } else if(test == PermissionTestType::PERMTEST_ORDERED) + while(!perms.empty() && result == permNotGranted) { + result = perms.front()->granted; + perms.pop_front(); + }; + return result; + } + + inline PermissionValue getPermissionValue(PermissionType type, const std::shared_ptr& channel = nullptr, PermissionValue default_value = permNotGranted) { + return this->getPermissionValue(permission::PERMTEST_ORDERED, type, channel, default_value); + } + + PermissionValue getPermissionValue(permission::PermissionTestType test, PermissionType type, const std::shared_ptr& channel = nullptr, PermissionValue def = permNotGranted) { + PermissionValue result = permNotGranted; + auto perms = this->getPermission(type, channel); + if(test == permission::PERMTEST_HIGHEST) { + PermissionValue higest = permNotGranted; + for(const auto &e : perms) + if((e->value > higest || e->value == -1) && higest != -1) higest = e->value; + if(higest != permNotGranted) + result = higest; + } else if(test == PermissionTestType::PERMTEST_ORDERED) + while(!perms.empty() && result == permNotGranted) { + result = perms.front()->value; + perms.pop_front(); + }; + return result == permNotGranted ? def : result; + } + + std::vector> listPermissions(uint16_t = ~0); + std::vector> allPermissions(); + + std::deque> all_channel_specific_permissions(); + std::deque> all_channel_unspecific_permissions(); + + void fireUpdate(PermissionType); + void registerUpdateHandler(const std::function)> &fn){ updateHandler.push_back(fn); } + + void clearPermissions(){ + permissions.clear(); + } + private: + std::deque> permissions; + std::deque)>> updateHandler; + }; + + namespace v2 { + #pragma pack(push, 1) + struct PermissionFlags { + bool database_reference: 1; /* if set the permission is known within the database, else it has tp be inserted */ + bool channel_specific: 1; /* set if there are channel specific permissions */ + + bool value_set: 1; + bool grant_set: 1; + + bool skip: 1; + bool negate: 1; + + bool flag_value_update: 1; + bool flag_grant_update: 1; + + ts_always_inline bool permission_set() { + return this->value_set || this->grant_set; + } + }; + static_assert(sizeof(PermissionFlags) == 1); + + struct PermissionValues { + PermissionValue value; + PermissionValue grant; + }; + static_assert(sizeof(PermissionValues) == 8); + static constexpr PermissionValues empty_permission_values{0, 0}; + + struct PermissionContainer { + PermissionFlags flags; + PermissionValues values; + }; + static_assert(sizeof(PermissionContainer) == 9); + + struct ChannelPermissionContainer : public PermissionContainer { + PermissionType permission; + ChannelId channel_id; + }; + static_assert(sizeof(ChannelPermissionContainer) == 19); + static constexpr v2::PermissionFlags empty_flags = {false, false, false, false, false, false, false}; + static constexpr v2::PermissionContainer empty_channel_permission = {empty_flags, v2::empty_permission_values}; + + #pragma pack(pop) + + #pragma pack(push, 1) + template + struct PermissionContainerBulk { + PermissionContainer permissions[element_count]; + + PermissionContainerBulk() { + memset(this->permissions, 0, sizeof(this->permissions)); + } + }; + #pragma pack(pop) + + enum PermissionUpdateType { + do_nothing, + set_value, + delete_value + }; + + struct PermissionDBUpdateEntry { + PermissionType permission; + ChannelId channel_id; + + PermissionValues values; + PermissionUpdateType update_value; + PermissionUpdateType update_grant; + + bool flag_db: 1; /* only needs an update if set */ + bool flag_delete: 1; + bool flag_skip: 1; + bool flag_negate: 1; + }; + + struct PermissionFlaggedValue { + PermissionValue value = permNotGranted; + bool has_value = false; + + constexpr bool has_power() const { return this->has_value && (this->value > 0 || this->value == -1); } + constexpr bool has_infinite_power() const { return this->has_value && this->value == -1; } + + inline bool operator==(const PermissionFlaggedValue& other) const { return other.value == this->value && other.has_value == this->has_value; } + inline bool operator!=(const PermissionFlaggedValue& other) const { return !(*this == other); } + }; + static constexpr PermissionFlaggedValue empty_permission_flagged_value{0, false}; + + + static constexpr bool permission_granted(const PermissionFlaggedValue& required, const PermissionFlaggedValue& given, bool requires_given = true) { + if(!required.has_value) { + return !requires_given || given.has_power(); + } else if(!given.has_power()) { + return false; + } else if(given.has_infinite_power()) { + return true; + } else if(required.has_infinite_power()) { + return false; + } else { + return given.value >= required.value; + } + } + static constexpr bool permission_granted(const PermissionValue& required, const PermissionFlaggedValue& given, bool requires_given = true) { + return permission_granted({required, true}, given, requires_given); + } + + class PermissionRegister { + public: + static constexpr size_t PERMISSIONS_BULK_BITS = 4; /* 16 permissions per block */ + static constexpr size_t PERMISSIONS_BULK_ENTRY_COUNT = 1 << PERMISSIONS_BULK_BITS; + static constexpr size_t BULK_COUNT = (PermissionType::permission_id_max / (1 << PERMISSIONS_BULK_BITS)) + ((PermissionType::permission_id_max % PERMISSIONS_BULK_ENTRY_COUNT == 0) ? 0 : 1); + static_assert(PERMISSIONS_BULK_ENTRY_COUNT * BULK_COUNT >= PermissionType::permission_id_max); + + PermissionRegister(); + virtual ~PermissionRegister(); + + /* load permissions from the database */ + void load_permission(const PermissionType&, const PermissionValues& /* values */, bool /* flag skip */, bool /* flag negate */, bool /* value present */,bool /* grant present */); + void load_permission(const PermissionType&, const PermissionValues& /* values */, ChannelId /* channel */, bool /* flag skip */, bool /* flag negate */, bool /* value present */,bool /* grant present */); + + /* general getters/setters */ + const PermissionFlags permission_flags(const PermissionType&); /* we return a "copy" because the actual permission could be deleted while we're analyzing the flags */ + ts_always_inline const PermissionFlags permission_flags(const std::shared_ptr& permission_info) { return this->permission_flags(permission_info->type); } + + const PermissionValues permission_values(const PermissionType&); + ts_always_inline const PermissionValues permission_values(const std::shared_ptr& permission_info) { return this->permission_values(permission_info->type); } + + const PermissionFlaggedValue permission_value_flagged(const PermissionType&); + ts_always_inline const PermissionFlaggedValue permission_value_flagged(const std::shared_ptr& permission_info) { return this->permission_value_flagged(permission_info->type); } + + const PermissionFlaggedValue permission_granted_flagged(const PermissionType&); + ts_always_inline const PermissionFlaggedValue permission_granted_flagged(const std::shared_ptr& permission_info) { return this->permission_granted_flagged(permission_info->type); } + + /* only worth looking up if channel_specific is set */ + const PermissionContainer channel_permission(const PermissionType& /* permission */, ChannelId /* channel id */); + ts_always_inline const PermissionContainer channel_permission(const std::shared_ptr& permission_info, ChannelId channel_id) { return this->channel_permission(permission_info->type, channel_id); } + + /* modifiers */ + void set_permission(const PermissionType& /* permission */, const PermissionValues& /* values */, const PermissionUpdateType& /* update value */, const PermissionUpdateType& /* update grant */, int /* flag skip */ = -1, int /* flag negate */ = -1); + void set_channel_permission(const PermissionType& /* permission */, ChannelId /* channel id */, const PermissionValues& /* values */, const PermissionUpdateType& /* update value */, const PermissionUpdateType& /* update grant */, int /* flag skip */ = -1, int /* flag negate */ = -1); + + /* bulk info */ + const std::vector> permissions(); + const std::vector> channel_permissions(ChannelId /* channel id */); + const std::vector> channel_permissions(); + + size_t used_memory(); + void cleanup(); + + ts_always_inline bool require_db_updates() { return this->requires_db_save; } + const std::vector flush_db_updates(); + private: + static constexpr size_t PERMISSIONS_BULK_BLOCK_MASK = (~(1 << PERMISSIONS_BULK_BITS)) & ((1 << PERMISSIONS_BULK_BITS) - 1); + + bool requires_db_save = false; + ts_always_inline void trigger_db_update() { this->requires_db_save = true; } + + spin_lock block_use_count_lock{}; + int16_t block_use_count[BULK_COUNT]; + PermissionContainerBulk* block_containers[BULK_COUNT]; + + //TODO: Bulk permissions for channels as well, specially because they're client permissions in terms of the music bot! + std::shared_mutex channel_list_lock{}; + std::deque> _channel_permissions{}; + + ts_always_inline size_t calculate_block(const PermissionType& permission) { + return permission >> PERMISSIONS_BULK_BITS; + } + + ts_always_inline size_t calculate_block_index(const PermissionType& permission) { + return permission & PERMISSIONS_BULK_BLOCK_MASK; + } + + /** + * @param block + * @return true if block exists else false + */ + ts_always_inline bool ref_block(size_t block) { + std::lock_guard use_lock(this->block_use_count_lock); + if(!this->block_containers[block]) + return false; + this->block_use_count[block]++; + assert(this->block_use_count[block] > 0); + return true; + } + + ts_always_inline void unref_block(size_t block) { + std::lock_guard use_lock(this->block_use_count_lock); + this->block_use_count[block]--; + assert(this->block_use_count[block] >= 0); + } + + ts_always_inline void ref_allocate_block(size_t block) { + std::lock_guard use_lock(this->block_use_count_lock); + if(!this->block_containers[block]) + this->block_containers[block] = new PermissionContainerBulk(); + this->block_use_count[block]++; + assert(this->block_use_count[block] > 0); + } + }; + } + } +} + +inline std::ostream& operator<<(std::ostream& os, const ts::permission::v2::PermissionFlaggedValue& c) { + if(c.has_value) + return os << c.value; + else + return os << "unset"; +} + +DEFINE_VARIABLE_TRANSFORM(ts::permission::PermissionType, VARTYPE_INT, std::to_string((int16_t) in), static_cast(in.as())); +DEFINE_VARIABLE_TRANSFORM(ts::permission::PermissionGroup, VARTYPE_INT, std::to_string((uint16_t) in), static_cast(in.as())); DEFINE_VARIABLE_TRANSFORM(ts::permission::PermissionSqlType, VARTYPE_INT, std::to_string((int8_t) in), static_cast(in.as())); \ No newline at end of file diff --git a/src/lock/rw_mutex.cpp b/src/lock/rw_mutex.cpp index 138d336..68cc067 100644 --- a/src/lock/rw_mutex.cpp +++ b/src/lock/rw_mutex.cpp @@ -1,5 +1,5 @@ -// -// Created by WolverinDEV on 03/03/2020. -// - -#include "rw_mutex.h" +// +// Created by WolverinDEV on 03/03/2020. +// + +#include "rw_mutex.h" diff --git a/src/lock/rw_mutex.h b/src/lock/rw_mutex.h index 5d412bc..1eed292 100644 --- a/src/lock/rw_mutex.h +++ b/src/lock/rw_mutex.h @@ -1,690 +1,690 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#if !defined(NDEBUG) or 1 - #define DEBUG_RW_MUTEX - #define rw_mutex_assert(arg) assert(arg) -#else - #define rw_mutex_assert(arg) -#endif - -namespace ts { - enum rw_action_result { - success = 0, - resource_error = -1, - timeout = -2, - would_deadlock = -3, - }; - - template - struct rw_mutex_options { - constexpr static auto write_preferred{write_preferred_}; - }; - - struct mutex_action_validator { - public: - inline void try_exclusive_lock_acquire(); - inline void try_shared_lock_acquire(); - - inline void exclusive_lock_acquire(); - inline void shared_lock_acquire(); - - - inline void try_exclusive_lock_release(); - inline void try_shared_lock_release(); - - inline void exclusive_lock_release(); - inline void shared_lock_release(); - - - inline void try_shared_lock_upgrade(); - inline void try_exclusive_lock_downgrade(); - - inline void shared_lock_upgrade(); - inline void exclusive_lock_downgrade(); - - private: - std::thread::id exclusive_lock{}; - bool exclusive_lock_upgraded{false}; - std::vector shared_lockers{}; - }; - - struct dummy_action_validator { - inline void try_exclusive_lock_acquire() {} - inline void try_shared_lock_acquire() {} - - inline void exclusive_lock_acquire() {} - inline void shared_lock_acquire() {} - - - inline void try_exclusive_lock_release() {} - inline void try_shared_lock_release() {} - - inline void exclusive_lock_release() {} - inline void shared_lock_release() {} - - - inline void try_shared_lock_upgrade() {} - inline void try_exclusive_lock_downgrade() {} - - inline void shared_lock_upgrade() {} - inline void exclusive_lock_downgrade() {} - }; - - template - class rw_mutex_impl { - public: - rw_mutex_impl() = default; - ~rw_mutex_impl(); - - template - rw_mutex_impl(const rw_mutex_impl&) = delete; - - template - rw_mutex_impl&operator=(const rw_mutex_impl&) = delete; - - /** - * Acquire the write lock - */ - inline void lock(); - - /** - * Acquire the write lock with a timeout - */ - [[nodiscard]] inline std::cv_status lock_until(const std::chrono::system_clock::time_point& timeout); - - /** - * Acquire the write lock with a timeout - */ - template - [[nodiscard]] inline std::cv_status lock_for(const duration_t& duration) { - auto now = std::chrono::system_clock::now(); - now += duration; - return this->lock_until(now); - } - - /** - * Acquire the read lock - */ - inline void lock_shared(); - - /** - * Acquire the read lock with a timeout - */ - [[nodiscard]] inline std::cv_status lock_shared_until(const std::chrono::system_clock::time_point& timeout); - - /** - * Acquire the read lock with a timeout - */ - template - [[nodiscard]] inline std::cv_status lock_shared_for(const duration_t& duration) { - auto now = std::chrono::system_clock::now(); - now += duration; - return this->lock_shared_until(now); - } - - /** - * Release the write lock - */ - inline void unlock(); - - /** - * Release the read lock - */ - inline void unlock_shared(); - - /** - * Upgrade from a shared lock to an exclusive lock. - * Could fail due to the following reasons: - * would_deadlock: Another thread already tried to upgrade the lock and we're not supposed to release the shared lock - * resource_error: Another thread already claimed the write lock while we're waiting - * - * Note: This will cause a deadlock if the lock has been locked shared twice - */ - [[nodiscard]] inline rw_action_result upgrade_lock(); - - /** - * Upgrade from a shared lock to an exclusive lock. - * Could fail due to the following reasons: - * would_deadlock: Another thread already tried to upgrade the lock and we're not supposed to release the shared lock - * resource_error: Another thread already claimed the write lock while we're waiting - * timeout: If the action could not be performed within the given time frame - * Note: This will cause a deadlock if the lock has been locked shared twice - */ - [[nodiscard]] inline rw_action_result upgrade_lock_until(const std::chrono::system_clock::time_point& timeout); - - /** - * Upgrade from a shared lock to an exclusive lock with an timeout. - * For return codes see upgrade_lock_until. - */ - template - [[nodiscard]] inline rw_action_result upgrade_lock_for(const duration_t& duration) { - auto now = std::chrono::system_clock::now(); - now += duration; - return this->upgrade_lock_until(now); - } - - /** - * Downgrade from an exclusive lock to a shared lock. - * No other thread could lock the lock exclusive until unlock_shared() has been called. - */ - inline void downgrade_lock(); - private: - action_validator_t action_validator_{}; - - std::mutex status_lock_{}; - std::condition_variable upgrade_update_{}; - std::condition_variable write_update_{}; - std::condition_variable read_update_{}; - - bool write_locked{false}; - bool upgrade_pending{false}, write_lock_upgraded{false}; - uint32_t write_lock_pending{0}; - uint32_t read_lock_pending{0}; - uint32_t read_lock_count{0}; - }; - - typedef rw_mutex_impl, mutex_action_validator> rw_safe_mutex; - typedef rw_mutex_impl, mutex_action_validator> rw_unsafe_mutex; - typedef rw_safe_mutex rw_mutex; - - struct rw_lock_defered_t {}; - struct rw_lock_shared_t {}; - struct rw_lock_exclusive_t {}; - - constexpr rw_lock_defered_t rw_lock_defered{}; - constexpr rw_lock_shared_t rw_lock_shared{}; - constexpr rw_lock_exclusive_t rw_lock_exclusive{}; - - template - struct rwshared_lock { - public: - explicit rwshared_lock(lock_t& lock) : rwshared_lock{lock, rw_lock_shared} {} - - explicit rwshared_lock(lock_t& lock, const rw_lock_defered_t&) : lock_{lock} { - this->lock_type_ = unlocked; - } - - explicit rwshared_lock(lock_t& lock, const rw_lock_shared_t&) : lock_{lock} { - this->lock_.lock_shared(); - this->lock_type_ = locked_shared; - } - - explicit rwshared_lock(lock_t& lock, const rw_lock_exclusive_t&) : lock_{lock} { - this->lock_.lock(); - this->lock_type_ = locked_exclusive; - } - - ~rwshared_lock() { - if(this->lock_type_ == locked_shared) { - this->lock_.unlock_shared(); - } else if(this->lock_type_ == locked_exclusive) { - this->lock_.unlock(); - } - } - - rwshared_lock(const rwshared_lock&) = delete; - rwshared_lock&operator=(const rwshared_lock&) = delete; - - /* state testers */ - [[nodiscard]] inline bool exclusive_locked() const { - return this->lock_type_ == locked_exclusive; - } - - [[nodiscard]] inline bool shared_locked() const { - return this->lock_type_ == locked_shared; - } - - /* basic lock functions */ - inline void lock_shared() { - rw_mutex_assert(this->lock_type_ == unlocked); - this->lock_.lock_shared(); - this->lock_type_ = locked_shared; - } - - [[nodiscard]] inline std::cv_status lock_shared_until(const std::chrono::system_clock::time_point& timeout) { - rw_mutex_assert(this->lock_type_ == unlocked); - if(auto error = this->lock_.lock_shared_until(timeout); error == std::cv_status::timeout) - return error; - this->lock_type_ = locked_shared; - return std::cv_status::no_timeout; - } - - inline void unlock_shared() { - rw_mutex_assert(this->lock_type_ == locked_shared); - this->lock_.unlock_shared(); - this->lock_type_ = unlocked; - } - - inline void lock_exclusive() { - rw_mutex_assert(this->lock_type_ == unlocked); - this->lock_.lock(); - this->lock_type_ = locked_exclusive; - } - - [[nodiscard]] inline std::cv_status lock_exclusive_until(const std::chrono::system_clock::time_point& timeout) { - rw_mutex_assert(this->lock_type_ == unlocked); - if(auto error = this->lock_.lock_until(timeout); error == std::cv_status::timeout) - return error; - this->lock_type_ = locked_exclusive; - return std::cv_status::no_timeout; - } - - inline void unlock_exclusive() { - rw_mutex_assert(this->lock_type_ == locked_exclusive); - this->lock_.unlock(); - this->lock_type_ = unlocked; - } - - /* upgrade/downgrade functions */ - [[nodiscard]] inline rw_action_result upgrade_lock() { - rw_mutex_assert(this->lock_type_ == locked_shared); - auto err = this->lock_.upgrade_lock(); - if(err != rw_action_result::success) return err; - - this->lock_type_ = locked_exclusive; - return rw_action_result::success; - } - - [[nodiscard]] inline rw_action_result upgrade_lock_until(const std::chrono::system_clock::time_point& timeout) { - rw_mutex_assert(this->lock_type_ == locked_shared); - auto err = this->lock_.upgrade_lock_until(timeout); - if(err != rw_action_result::success) return err; - - this->lock_type_ = locked_exclusive; - return rw_action_result::success; - } - - inline void downgrade_lock() { - rw_mutex_assert(this->lock_type_ == locked_exclusive); - this->lock_.downgrade_lock(); - this->lock_type_ = locked_shared; - } - - /* auto lock to the target state */ - [[nodiscard]] inline rw_action_result auto_lock_exclusive() { - if(this->lock_type_ == unlocked) - this->lock_exclusive(); - else if(this->lock_type_ == locked_shared) - return this->upgrade_lock(); - return rw_action_result::success; - } - - [[nodiscard]] inline rw_action_result auto_lock_exclusive_until(const std::chrono::system_clock::time_point& timeout) { - if(this->lock_type_ == unlocked) - this->lock_exclusive_until(timeout); - else if(this->lock_type_ == locked_shared) - return this->upgrade_lock_until(timeout); - return rw_action_result::success; - } - - inline void auto_lock_shared() { - if(this->lock_type_ == unlocked) - this->lock_shared(); - else if(this->lock_type_ == locked_exclusive) - this->downgrade_lock(); - } - - [[nodiscard]] inline std::cv_status auto_lock_shared_until(const std::chrono::system_clock::time_point& timeout) { - if(this->lock_type_ == unlocked) - return this->lock_shared_until(timeout); - else if(this->lock_type_ == locked_exclusive) - this->downgrade_lock_until(); - return std::cv_status::no_timeout; - } - - void auto_unlock() { - if(this->lock_type_ == locked_shared) - this->unlock_shared(); - else if(this->lock_type_ == locked_exclusive) - this->unlock_exclusive(); - } - private: - enum { - unlocked, - locked_shared, - locked_exclusive - } lock_type_; - - lock_t& lock_; - }; -} - -/* the implementation */ -namespace ts { -#if __cplusplus > 201703L and 0 - #define unlikely_annotation [[unlikely]] -#else - #define unlikely_annotation -#endif - - template -#ifndef DEBUG_RW_MUTEX - rw_mutex_impl::~rw_mutex_impl() = default; -#else - rw_mutex_impl::~rw_mutex_impl() { - rw_mutex_assert(!this->write_locked); - rw_mutex_assert(!this->upgrade_pending); - rw_mutex_assert(this->write_lock_pending == 0); - rw_mutex_assert(this->read_lock_pending == 0); - rw_mutex_assert(this->read_lock_count == 0); - } -#endif - - template - void rw_mutex_impl::lock() { - std::unique_lock slock{this->status_lock_}; - this->action_validator_.try_exclusive_lock_acquire(); - - this->write_lock_pending++; - acquire: { - while (this->read_lock_count > 0) unlikely_annotation - this->write_update_.wait(slock); - - while (this->write_locked) unlikely_annotation - this->write_update_.wait(slock); - - /* - * Even when write_preferred is enabled, another thread which wants to read lock claims the mutex - * and read locks the lock before the write could be acquired. - */ - if(this->read_lock_count > 0) /* this could be changed while waiting for the write lock to unlock */ - goto acquire; - } - - this->write_locked = true; - this->write_lock_pending--; - this->action_validator_.exclusive_lock_acquire(); - } - - template - std::cv_status rw_mutex_impl::lock_until(const std::chrono::system_clock::time_point& timeout) { - std::unique_lock slock{this->status_lock_}; - this->action_validator_.try_exclusive_lock_acquire(); - this->write_lock_pending++; - acquire: { - while(this->read_lock_count > 0) unlikely_annotation - if(auto err = this->write_update_.wait_until(slock, timeout); err != std::cv_status::no_timeout) { - assert(this->write_lock_pending > 0); - this->write_lock_pending--; - return std::cv_status::timeout; - } - - while(this->write_locked) unlikely_annotation - if(auto err = this->write_update_.wait_until(slock, timeout); err != std::cv_status::no_timeout) { - assert(this->write_lock_pending > 0); - this->write_lock_pending--; - return std::cv_status::timeout; - } - - /* - * Even when write_preferred is enabled, another thread which wants to read lock claims the mutex - * and read locks the lock before the write could be acquired. - */ - if(this->read_lock_count > 0) /* this could be changed while waiting for the write lock to unlock */ - goto acquire; - } - - this->write_locked = true; - this->write_lock_pending--; - this->action_validator_.exclusive_lock_acquire(); - } - - template - void rw_mutex_impl::lock_shared() { - std::unique_lock slock{this->status_lock_}; - this->action_validator_.try_shared_lock_acquire(); - this->read_lock_pending++; - while(this->write_locked) unlikely_annotation - this->read_update_.wait(slock); - - this->read_lock_count++; - this->read_lock_pending--; - this->action_validator_.shared_lock_acquire(); - } - - template - std::cv_status rw_mutex_impl::lock_shared_until(const std::chrono::system_clock::time_point& timeout) { - std::unique_lock slock{this->status_lock_}; - this->action_validator_.try_shared_lock_acquire(); - this->read_lock_pending++; - while(this->write_locked) unlikely_annotation - if(auto err = this->read_update_.wait_until(slock, timeout); err != std::cv_status::no_timeout) { - rw_mutex_assert(this->read_lock_pending > 0); - this->read_lock_pending--; - return std::cv_status::timeout; - } - - this->read_lock_count++; - this->read_lock_pending--; - this->action_validator_.shared_lock_acquire(); - } - - template - void rw_mutex_impl::unlock() { - std::lock_guard slock{this->status_lock_}; - this->action_validator_.try_exclusive_lock_release(); - rw_mutex_assert(this->write_locked); - - this->write_locked = false; - if(this->write_lock_upgraded) unlikely_annotation { - rw_mutex_assert(this->read_lock_count == 1); /* is was a upgraded lock */ - this->read_lock_count--; - this->write_lock_upgraded = false; - } else { - rw_mutex_assert(this->read_lock_count == 0); - } - - if(options_t::write_preferred) { - if(this->write_lock_pending > 0) - this->write_update_.notify_one(); - else if(this->read_lock_pending > 0) - this->read_update_.notify_one(); - } else { - if(this->read_lock_pending > 0) - this->read_update_.notify_all(); - else if(this->write_lock_pending > 0) - this->write_update_.notify_one(); /* only one thread could write at the time */ - } - this->action_validator_.exclusive_lock_release(); - } - - template - void rw_mutex_impl::unlock_shared() { - std::lock_guard slock{this->status_lock_}; - this->action_validator_.try_shared_lock_release(); - rw_mutex_assert(!this->write_locked); - rw_mutex_assert(this->read_lock_count > 0); - - this->read_lock_count--; - if(this->read_lock_count == 0) { - if(this->write_lock_pending > 0) { - /* notify all writers that we're ready to lock */ - rw_mutex_assert(!this->upgrade_pending); - this->write_update_.notify_one(); /* only one thread could write at the time */ - } - } else if(this->read_lock_count == 1) unlikely_annotation { - if(this->upgrade_pending) { - this->write_locked = true; - this->upgrade_pending = false; - this->upgrade_update_.notify_one(); - } - } - this->action_validator_.shared_lock_release(); - } - - template - rw_action_result rw_mutex_impl::upgrade_lock() { - std::unique_lock slock{this->status_lock_}; - this->action_validator_.try_shared_lock_upgrade(); - rw_mutex_assert(!this->write_locked); - rw_mutex_assert(this->read_lock_count > 0); - - if(this->upgrade_pending) - return rw_action_result::would_deadlock; - if(this->write_locked) - return rw_action_result::resource_error; - - this->upgrade_pending = true; - if(this->read_lock_count > 1) { - while(this->read_lock_count > 1) unlikely_annotation - this->upgrade_update_.wait(slock); - - /* whoever allowed us to upgrade should have done that already */ - rw_mutex_assert(this->write_locked); - rw_mutex_assert(!this->upgrade_pending); - } - this->upgrade_pending = false; - this->write_lock_upgraded = true; - this->write_locked = true; - - this->action_validator_.shared_lock_upgrade(); - return rw_action_result::success; - } - - template - rw_action_result rw_mutex_impl::upgrade_lock_until(const std::chrono::system_clock::time_point& timeout) { - std::unique_lock slock{this->status_lock_}; - this->action_validator_.try_shared_lock_upgrade(); - rw_mutex_assert(!this->write_locked); - rw_mutex_assert(this->read_lock_count > 0); - - if(this->upgrade_pending) - return rw_action_result::would_deadlock; - if(this->write_locked) - return rw_action_result::resource_error; - - this->upgrade_pending = true; - if(this->read_lock_count > 1) { - while(this->read_lock_count > 1) unlikely_annotation - if(auto err = this->upgrade_update_.wait_until(slock, timeout); err != std::cv_status::no_timeout) { - this->upgrade_pending = false; - return rw_action_result::timeout; - } - - /* whoever allowed us to upgrade should have done that already */ - rw_mutex_assert(this->write_locked); - rw_mutex_assert(!this->upgrade_pending); - } - this->upgrade_pending = false; - this->write_lock_upgraded = true; - this->write_locked = true; - this->action_validator_.shared_lock_upgrade(); - - return rw_action_result::success; - } - - template - void rw_mutex_impl::downgrade_lock() { - std::unique_lock slock{this->status_lock_}; - this->action_validator_.try_exclusive_lock_downgrade(); - rw_mutex_assert(this->write_locked); - - if(this->write_lock_upgraded) { - rw_mutex_assert(this->read_lock_count == 1); /* our own thread */ - } else unlikely_annotation { - this->read_lock_count++; - } - - this->write_lock_upgraded = false; - this->write_locked = false; - this->read_update_.notify_all(); - this->action_validator_.exclusive_lock_downgrade(); - } - - /* action validator */ - /* shared lock part */ - void mutex_action_validator::try_shared_lock_acquire() { - if(this->exclusive_lock == std::this_thread::get_id()) - throw std::logic_error{"mutex has been locked in exclusive lock by current thread"}; - } - - void mutex_action_validator::shared_lock_acquire() { - this->shared_lockers.push_back(std::this_thread::get_id()); - } - - void mutex_action_validator::try_shared_lock_upgrade() { - if(this->exclusive_lock == std::this_thread::get_id()) - throw std::logic_error{"mutex has been upgraded by current thread"}; - - auto current_id = std::this_thread::get_id(); - auto count = std::count_if(this->shared_lockers.begin(), this->shared_lockers.end(), [&](const auto& id) { - return id == current_id; - }); - - if(count == 0) - throw std::logic_error{"upgrade not possible because shared mutex is not locked by current thread"}; - else if(count > 1) - throw std::logic_error{"upgrade not possible because shared mutex is locked more than once by current thread"}; - } - - void mutex_action_validator::shared_lock_upgrade() { - this->exclusive_lock_upgraded = true; - this->exclusive_lock = std::this_thread::get_id(); - } - - void mutex_action_validator::try_shared_lock_release() { - if(this->exclusive_lock == std::this_thread::get_id()) - throw std::logic_error{this->exclusive_lock_upgraded ? "mutex has been upgraded" : "mutex has been locked in exclusive mode, not in shared mode"}; - - auto it = std::find(this->shared_lockers.begin(), this->shared_lockers.end(), std::this_thread::get_id()); - if(it == this->shared_lockers.end()) - throw std::logic_error{"mutex not locked by current thread"}; - } - - void mutex_action_validator::shared_lock_release() { - auto it = std::find(this->shared_lockers.begin(), this->shared_lockers.end(), std::this_thread::get_id()); - rw_mutex_assert(it != this->shared_lockers.end()); /* this should never happen (try_shared_lock_release has been called before) */ - this->shared_lockers.erase(it); - } - - /* exclusive lock part */ - void mutex_action_validator::try_exclusive_lock_acquire() { - if(this->exclusive_lock == std::this_thread::get_id()) - throw std::logic_error{"mutex has been exclusive locked by current thread"}; - } - - void mutex_action_validator::exclusive_lock_acquire() { - this->exclusive_lock = std::this_thread::get_id(); - this->exclusive_lock_upgraded = false; - } - - void mutex_action_validator::try_exclusive_lock_downgrade() { - if(this->exclusive_lock != std::this_thread::get_id()) - throw std::logic_error{"mutex hasn't been locked in exclusive mode by this thread"}; - } - - void mutex_action_validator::exclusive_lock_downgrade() { - if(!this->exclusive_lock_upgraded) { - this->shared_lockers.push_back(std::this_thread::get_id()); - } else { - /* internal state error check */ - rw_mutex_assert(std::find(this->shared_lockers.begin(), this->shared_lockers.end(), std::this_thread::get_id()) != this->shared_lockers.end()); - } - - this->exclusive_lock_upgraded = false; - this->exclusive_lock = std::thread::id{}; - } - - void mutex_action_validator::try_exclusive_lock_release() { - if(this->exclusive_lock != std::this_thread::get_id()) - throw std::logic_error{"mutex hasn't been locked in exclusive mode by this thread"}; - } - - void mutex_action_validator::exclusive_lock_release() { - if(this->exclusive_lock_upgraded) { - auto it = std::find(this->shared_lockers.begin(), this->shared_lockers.end(), std::this_thread::get_id()); - assert(it != this->shared_lockers.end()); - this->shared_lockers.erase(it); - } - this->exclusive_lock_upgraded = false; - this->exclusive_lock = std::thread::id{}; - } -} +#pragma once + +#include +#include +#include +#include +#include +#include + +#if !defined(NDEBUG) or 1 + #define DEBUG_RW_MUTEX + #define rw_mutex_assert(arg) assert(arg) +#else + #define rw_mutex_assert(arg) +#endif + +namespace ts { + enum rw_action_result { + success = 0, + resource_error = -1, + timeout = -2, + would_deadlock = -3, + }; + + template + struct rw_mutex_options { + constexpr static auto write_preferred{write_preferred_}; + }; + + struct mutex_action_validator { + public: + inline void try_exclusive_lock_acquire(); + inline void try_shared_lock_acquire(); + + inline void exclusive_lock_acquire(); + inline void shared_lock_acquire(); + + + inline void try_exclusive_lock_release(); + inline void try_shared_lock_release(); + + inline void exclusive_lock_release(); + inline void shared_lock_release(); + + + inline void try_shared_lock_upgrade(); + inline void try_exclusive_lock_downgrade(); + + inline void shared_lock_upgrade(); + inline void exclusive_lock_downgrade(); + + private: + std::thread::id exclusive_lock{}; + bool exclusive_lock_upgraded{false}; + std::vector shared_lockers{}; + }; + + struct dummy_action_validator { + inline void try_exclusive_lock_acquire() {} + inline void try_shared_lock_acquire() {} + + inline void exclusive_lock_acquire() {} + inline void shared_lock_acquire() {} + + + inline void try_exclusive_lock_release() {} + inline void try_shared_lock_release() {} + + inline void exclusive_lock_release() {} + inline void shared_lock_release() {} + + + inline void try_shared_lock_upgrade() {} + inline void try_exclusive_lock_downgrade() {} + + inline void shared_lock_upgrade() {} + inline void exclusive_lock_downgrade() {} + }; + + template + class rw_mutex_impl { + public: + rw_mutex_impl() = default; + ~rw_mutex_impl(); + + template + rw_mutex_impl(const rw_mutex_impl&) = delete; + + template + rw_mutex_impl&operator=(const rw_mutex_impl&) = delete; + + /** + * Acquire the write lock + */ + inline void lock(); + + /** + * Acquire the write lock with a timeout + */ + [[nodiscard]] inline std::cv_status lock_until(const std::chrono::system_clock::time_point& timeout); + + /** + * Acquire the write lock with a timeout + */ + template + [[nodiscard]] inline std::cv_status lock_for(const duration_t& duration) { + auto now = std::chrono::system_clock::now(); + now += duration; + return this->lock_until(now); + } + + /** + * Acquire the read lock + */ + inline void lock_shared(); + + /** + * Acquire the read lock with a timeout + */ + [[nodiscard]] inline std::cv_status lock_shared_until(const std::chrono::system_clock::time_point& timeout); + + /** + * Acquire the read lock with a timeout + */ + template + [[nodiscard]] inline std::cv_status lock_shared_for(const duration_t& duration) { + auto now = std::chrono::system_clock::now(); + now += duration; + return this->lock_shared_until(now); + } + + /** + * Release the write lock + */ + inline void unlock(); + + /** + * Release the read lock + */ + inline void unlock_shared(); + + /** + * Upgrade from a shared lock to an exclusive lock. + * Could fail due to the following reasons: + * would_deadlock: Another thread already tried to upgrade the lock and we're not supposed to release the shared lock + * resource_error: Another thread already claimed the write lock while we're waiting + * + * Note: This will cause a deadlock if the lock has been locked shared twice + */ + [[nodiscard]] inline rw_action_result upgrade_lock(); + + /** + * Upgrade from a shared lock to an exclusive lock. + * Could fail due to the following reasons: + * would_deadlock: Another thread already tried to upgrade the lock and we're not supposed to release the shared lock + * resource_error: Another thread already claimed the write lock while we're waiting + * timeout: If the action could not be performed within the given time frame + * Note: This will cause a deadlock if the lock has been locked shared twice + */ + [[nodiscard]] inline rw_action_result upgrade_lock_until(const std::chrono::system_clock::time_point& timeout); + + /** + * Upgrade from a shared lock to an exclusive lock with an timeout. + * For return codes see upgrade_lock_until. + */ + template + [[nodiscard]] inline rw_action_result upgrade_lock_for(const duration_t& duration) { + auto now = std::chrono::system_clock::now(); + now += duration; + return this->upgrade_lock_until(now); + } + + /** + * Downgrade from an exclusive lock to a shared lock. + * No other thread could lock the lock exclusive until unlock_shared() has been called. + */ + inline void downgrade_lock(); + private: + action_validator_t action_validator_{}; + + std::mutex status_lock_{}; + std::condition_variable upgrade_update_{}; + std::condition_variable write_update_{}; + std::condition_variable read_update_{}; + + bool write_locked{false}; + bool upgrade_pending{false}, write_lock_upgraded{false}; + uint32_t write_lock_pending{0}; + uint32_t read_lock_pending{0}; + uint32_t read_lock_count{0}; + }; + + typedef rw_mutex_impl, mutex_action_validator> rw_safe_mutex; + typedef rw_mutex_impl, mutex_action_validator> rw_unsafe_mutex; + typedef rw_safe_mutex rw_mutex; + + struct rw_lock_defered_t {}; + struct rw_lock_shared_t {}; + struct rw_lock_exclusive_t {}; + + constexpr rw_lock_defered_t rw_lock_defered{}; + constexpr rw_lock_shared_t rw_lock_shared{}; + constexpr rw_lock_exclusive_t rw_lock_exclusive{}; + + template + struct rwshared_lock { + public: + explicit rwshared_lock(lock_t& lock) : rwshared_lock{lock, rw_lock_shared} {} + + explicit rwshared_lock(lock_t& lock, const rw_lock_defered_t&) : lock_{lock} { + this->lock_type_ = unlocked; + } + + explicit rwshared_lock(lock_t& lock, const rw_lock_shared_t&) : lock_{lock} { + this->lock_.lock_shared(); + this->lock_type_ = locked_shared; + } + + explicit rwshared_lock(lock_t& lock, const rw_lock_exclusive_t&) : lock_{lock} { + this->lock_.lock(); + this->lock_type_ = locked_exclusive; + } + + ~rwshared_lock() { + if(this->lock_type_ == locked_shared) { + this->lock_.unlock_shared(); + } else if(this->lock_type_ == locked_exclusive) { + this->lock_.unlock(); + } + } + + rwshared_lock(const rwshared_lock&) = delete; + rwshared_lock&operator=(const rwshared_lock&) = delete; + + /* state testers */ + [[nodiscard]] inline bool exclusive_locked() const { + return this->lock_type_ == locked_exclusive; + } + + [[nodiscard]] inline bool shared_locked() const { + return this->lock_type_ == locked_shared; + } + + /* basic lock functions */ + inline void lock_shared() { + rw_mutex_assert(this->lock_type_ == unlocked); + this->lock_.lock_shared(); + this->lock_type_ = locked_shared; + } + + [[nodiscard]] inline std::cv_status lock_shared_until(const std::chrono::system_clock::time_point& timeout) { + rw_mutex_assert(this->lock_type_ == unlocked); + if(auto error = this->lock_.lock_shared_until(timeout); error == std::cv_status::timeout) + return error; + this->lock_type_ = locked_shared; + return std::cv_status::no_timeout; + } + + inline void unlock_shared() { + rw_mutex_assert(this->lock_type_ == locked_shared); + this->lock_.unlock_shared(); + this->lock_type_ = unlocked; + } + + inline void lock_exclusive() { + rw_mutex_assert(this->lock_type_ == unlocked); + this->lock_.lock(); + this->lock_type_ = locked_exclusive; + } + + [[nodiscard]] inline std::cv_status lock_exclusive_until(const std::chrono::system_clock::time_point& timeout) { + rw_mutex_assert(this->lock_type_ == unlocked); + if(auto error = this->lock_.lock_until(timeout); error == std::cv_status::timeout) + return error; + this->lock_type_ = locked_exclusive; + return std::cv_status::no_timeout; + } + + inline void unlock_exclusive() { + rw_mutex_assert(this->lock_type_ == locked_exclusive); + this->lock_.unlock(); + this->lock_type_ = unlocked; + } + + /* upgrade/downgrade functions */ + [[nodiscard]] inline rw_action_result upgrade_lock() { + rw_mutex_assert(this->lock_type_ == locked_shared); + auto err = this->lock_.upgrade_lock(); + if(err != rw_action_result::success) return err; + + this->lock_type_ = locked_exclusive; + return rw_action_result::success; + } + + [[nodiscard]] inline rw_action_result upgrade_lock_until(const std::chrono::system_clock::time_point& timeout) { + rw_mutex_assert(this->lock_type_ == locked_shared); + auto err = this->lock_.upgrade_lock_until(timeout); + if(err != rw_action_result::success) return err; + + this->lock_type_ = locked_exclusive; + return rw_action_result::success; + } + + inline void downgrade_lock() { + rw_mutex_assert(this->lock_type_ == locked_exclusive); + this->lock_.downgrade_lock(); + this->lock_type_ = locked_shared; + } + + /* auto lock to the target state */ + [[nodiscard]] inline rw_action_result auto_lock_exclusive() { + if(this->lock_type_ == unlocked) + this->lock_exclusive(); + else if(this->lock_type_ == locked_shared) + return this->upgrade_lock(); + return rw_action_result::success; + } + + [[nodiscard]] inline rw_action_result auto_lock_exclusive_until(const std::chrono::system_clock::time_point& timeout) { + if(this->lock_type_ == unlocked) + this->lock_exclusive_until(timeout); + else if(this->lock_type_ == locked_shared) + return this->upgrade_lock_until(timeout); + return rw_action_result::success; + } + + inline void auto_lock_shared() { + if(this->lock_type_ == unlocked) + this->lock_shared(); + else if(this->lock_type_ == locked_exclusive) + this->downgrade_lock(); + } + + [[nodiscard]] inline std::cv_status auto_lock_shared_until(const std::chrono::system_clock::time_point& timeout) { + if(this->lock_type_ == unlocked) + return this->lock_shared_until(timeout); + else if(this->lock_type_ == locked_exclusive) + this->downgrade_lock_until(); + return std::cv_status::no_timeout; + } + + void auto_unlock() { + if(this->lock_type_ == locked_shared) + this->unlock_shared(); + else if(this->lock_type_ == locked_exclusive) + this->unlock_exclusive(); + } + private: + enum { + unlocked, + locked_shared, + locked_exclusive + } lock_type_; + + lock_t& lock_; + }; +} + +/* the implementation */ +namespace ts { +#if __cplusplus > 201703L and 0 + #define unlikely_annotation [[unlikely]] +#else + #define unlikely_annotation +#endif + + template +#ifndef DEBUG_RW_MUTEX + rw_mutex_impl::~rw_mutex_impl() = default; +#else + rw_mutex_impl::~rw_mutex_impl() { + rw_mutex_assert(!this->write_locked); + rw_mutex_assert(!this->upgrade_pending); + rw_mutex_assert(this->write_lock_pending == 0); + rw_mutex_assert(this->read_lock_pending == 0); + rw_mutex_assert(this->read_lock_count == 0); + } +#endif + + template + void rw_mutex_impl::lock() { + std::unique_lock slock{this->status_lock_}; + this->action_validator_.try_exclusive_lock_acquire(); + + this->write_lock_pending++; + acquire: { + while (this->read_lock_count > 0) unlikely_annotation + this->write_update_.wait(slock); + + while (this->write_locked) unlikely_annotation + this->write_update_.wait(slock); + + /* + * Even when write_preferred is enabled, another thread which wants to read lock claims the mutex + * and read locks the lock before the write could be acquired. + */ + if(this->read_lock_count > 0) /* this could be changed while waiting for the write lock to unlock */ + goto acquire; + } + + this->write_locked = true; + this->write_lock_pending--; + this->action_validator_.exclusive_lock_acquire(); + } + + template + std::cv_status rw_mutex_impl::lock_until(const std::chrono::system_clock::time_point& timeout) { + std::unique_lock slock{this->status_lock_}; + this->action_validator_.try_exclusive_lock_acquire(); + this->write_lock_pending++; + acquire: { + while(this->read_lock_count > 0) unlikely_annotation + if(auto err = this->write_update_.wait_until(slock, timeout); err != std::cv_status::no_timeout) { + assert(this->write_lock_pending > 0); + this->write_lock_pending--; + return std::cv_status::timeout; + } + + while(this->write_locked) unlikely_annotation + if(auto err = this->write_update_.wait_until(slock, timeout); err != std::cv_status::no_timeout) { + assert(this->write_lock_pending > 0); + this->write_lock_pending--; + return std::cv_status::timeout; + } + + /* + * Even when write_preferred is enabled, another thread which wants to read lock claims the mutex + * and read locks the lock before the write could be acquired. + */ + if(this->read_lock_count > 0) /* this could be changed while waiting for the write lock to unlock */ + goto acquire; + } + + this->write_locked = true; + this->write_lock_pending--; + this->action_validator_.exclusive_lock_acquire(); + } + + template + void rw_mutex_impl::lock_shared() { + std::unique_lock slock{this->status_lock_}; + this->action_validator_.try_shared_lock_acquire(); + this->read_lock_pending++; + while(this->write_locked) unlikely_annotation + this->read_update_.wait(slock); + + this->read_lock_count++; + this->read_lock_pending--; + this->action_validator_.shared_lock_acquire(); + } + + template + std::cv_status rw_mutex_impl::lock_shared_until(const std::chrono::system_clock::time_point& timeout) { + std::unique_lock slock{this->status_lock_}; + this->action_validator_.try_shared_lock_acquire(); + this->read_lock_pending++; + while(this->write_locked) unlikely_annotation + if(auto err = this->read_update_.wait_until(slock, timeout); err != std::cv_status::no_timeout) { + rw_mutex_assert(this->read_lock_pending > 0); + this->read_lock_pending--; + return std::cv_status::timeout; + } + + this->read_lock_count++; + this->read_lock_pending--; + this->action_validator_.shared_lock_acquire(); + } + + template + void rw_mutex_impl::unlock() { + std::lock_guard slock{this->status_lock_}; + this->action_validator_.try_exclusive_lock_release(); + rw_mutex_assert(this->write_locked); + + this->write_locked = false; + if(this->write_lock_upgraded) unlikely_annotation { + rw_mutex_assert(this->read_lock_count == 1); /* is was a upgraded lock */ + this->read_lock_count--; + this->write_lock_upgraded = false; + } else { + rw_mutex_assert(this->read_lock_count == 0); + } + + if(options_t::write_preferred) { + if(this->write_lock_pending > 0) + this->write_update_.notify_one(); + else if(this->read_lock_pending > 0) + this->read_update_.notify_one(); + } else { + if(this->read_lock_pending > 0) + this->read_update_.notify_all(); + else if(this->write_lock_pending > 0) + this->write_update_.notify_one(); /* only one thread could write at the time */ + } + this->action_validator_.exclusive_lock_release(); + } + + template + void rw_mutex_impl::unlock_shared() { + std::lock_guard slock{this->status_lock_}; + this->action_validator_.try_shared_lock_release(); + rw_mutex_assert(!this->write_locked); + rw_mutex_assert(this->read_lock_count > 0); + + this->read_lock_count--; + if(this->read_lock_count == 0) { + if(this->write_lock_pending > 0) { + /* notify all writers that we're ready to lock */ + rw_mutex_assert(!this->upgrade_pending); + this->write_update_.notify_one(); /* only one thread could write at the time */ + } + } else if(this->read_lock_count == 1) unlikely_annotation { + if(this->upgrade_pending) { + this->write_locked = true; + this->upgrade_pending = false; + this->upgrade_update_.notify_one(); + } + } + this->action_validator_.shared_lock_release(); + } + + template + rw_action_result rw_mutex_impl::upgrade_lock() { + std::unique_lock slock{this->status_lock_}; + this->action_validator_.try_shared_lock_upgrade(); + rw_mutex_assert(!this->write_locked); + rw_mutex_assert(this->read_lock_count > 0); + + if(this->upgrade_pending) + return rw_action_result::would_deadlock; + if(this->write_locked) + return rw_action_result::resource_error; + + this->upgrade_pending = true; + if(this->read_lock_count > 1) { + while(this->read_lock_count > 1) unlikely_annotation + this->upgrade_update_.wait(slock); + + /* whoever allowed us to upgrade should have done that already */ + rw_mutex_assert(this->write_locked); + rw_mutex_assert(!this->upgrade_pending); + } + this->upgrade_pending = false; + this->write_lock_upgraded = true; + this->write_locked = true; + + this->action_validator_.shared_lock_upgrade(); + return rw_action_result::success; + } + + template + rw_action_result rw_mutex_impl::upgrade_lock_until(const std::chrono::system_clock::time_point& timeout) { + std::unique_lock slock{this->status_lock_}; + this->action_validator_.try_shared_lock_upgrade(); + rw_mutex_assert(!this->write_locked); + rw_mutex_assert(this->read_lock_count > 0); + + if(this->upgrade_pending) + return rw_action_result::would_deadlock; + if(this->write_locked) + return rw_action_result::resource_error; + + this->upgrade_pending = true; + if(this->read_lock_count > 1) { + while(this->read_lock_count > 1) unlikely_annotation + if(auto err = this->upgrade_update_.wait_until(slock, timeout); err != std::cv_status::no_timeout) { + this->upgrade_pending = false; + return rw_action_result::timeout; + } + + /* whoever allowed us to upgrade should have done that already */ + rw_mutex_assert(this->write_locked); + rw_mutex_assert(!this->upgrade_pending); + } + this->upgrade_pending = false; + this->write_lock_upgraded = true; + this->write_locked = true; + this->action_validator_.shared_lock_upgrade(); + + return rw_action_result::success; + } + + template + void rw_mutex_impl::downgrade_lock() { + std::unique_lock slock{this->status_lock_}; + this->action_validator_.try_exclusive_lock_downgrade(); + rw_mutex_assert(this->write_locked); + + if(this->write_lock_upgraded) { + rw_mutex_assert(this->read_lock_count == 1); /* our own thread */ + } else unlikely_annotation { + this->read_lock_count++; + } + + this->write_lock_upgraded = false; + this->write_locked = false; + this->read_update_.notify_all(); + this->action_validator_.exclusive_lock_downgrade(); + } + + /* action validator */ + /* shared lock part */ + void mutex_action_validator::try_shared_lock_acquire() { + if(this->exclusive_lock == std::this_thread::get_id()) + throw std::logic_error{"mutex has been locked in exclusive lock by current thread"}; + } + + void mutex_action_validator::shared_lock_acquire() { + this->shared_lockers.push_back(std::this_thread::get_id()); + } + + void mutex_action_validator::try_shared_lock_upgrade() { + if(this->exclusive_lock == std::this_thread::get_id()) + throw std::logic_error{"mutex has been upgraded by current thread"}; + + auto current_id = std::this_thread::get_id(); + auto count = std::count_if(this->shared_lockers.begin(), this->shared_lockers.end(), [&](const auto& id) { + return id == current_id; + }); + + if(count == 0) + throw std::logic_error{"upgrade not possible because shared mutex is not locked by current thread"}; + else if(count > 1) + throw std::logic_error{"upgrade not possible because shared mutex is locked more than once by current thread"}; + } + + void mutex_action_validator::shared_lock_upgrade() { + this->exclusive_lock_upgraded = true; + this->exclusive_lock = std::this_thread::get_id(); + } + + void mutex_action_validator::try_shared_lock_release() { + if(this->exclusive_lock == std::this_thread::get_id()) + throw std::logic_error{this->exclusive_lock_upgraded ? "mutex has been upgraded" : "mutex has been locked in exclusive mode, not in shared mode"}; + + auto it = std::find(this->shared_lockers.begin(), this->shared_lockers.end(), std::this_thread::get_id()); + if(it == this->shared_lockers.end()) + throw std::logic_error{"mutex not locked by current thread"}; + } + + void mutex_action_validator::shared_lock_release() { + auto it = std::find(this->shared_lockers.begin(), this->shared_lockers.end(), std::this_thread::get_id()); + rw_mutex_assert(it != this->shared_lockers.end()); /* this should never happen (try_shared_lock_release has been called before) */ + this->shared_lockers.erase(it); + } + + /* exclusive lock part */ + void mutex_action_validator::try_exclusive_lock_acquire() { + if(this->exclusive_lock == std::this_thread::get_id()) + throw std::logic_error{"mutex has been exclusive locked by current thread"}; + } + + void mutex_action_validator::exclusive_lock_acquire() { + this->exclusive_lock = std::this_thread::get_id(); + this->exclusive_lock_upgraded = false; + } + + void mutex_action_validator::try_exclusive_lock_downgrade() { + if(this->exclusive_lock != std::this_thread::get_id()) + throw std::logic_error{"mutex hasn't been locked in exclusive mode by this thread"}; + } + + void mutex_action_validator::exclusive_lock_downgrade() { + if(!this->exclusive_lock_upgraded) { + this->shared_lockers.push_back(std::this_thread::get_id()); + } else { + /* internal state error check */ + rw_mutex_assert(std::find(this->shared_lockers.begin(), this->shared_lockers.end(), std::this_thread::get_id()) != this->shared_lockers.end()); + } + + this->exclusive_lock_upgraded = false; + this->exclusive_lock = std::thread::id{}; + } + + void mutex_action_validator::try_exclusive_lock_release() { + if(this->exclusive_lock != std::this_thread::get_id()) + throw std::logic_error{"mutex hasn't been locked in exclusive mode by this thread"}; + } + + void mutex_action_validator::exclusive_lock_release() { + if(this->exclusive_lock_upgraded) { + auto it = std::find(this->shared_lockers.begin(), this->shared_lockers.end(), std::this_thread::get_id()); + assert(it != this->shared_lockers.end()); + this->shared_lockers.erase(it); + } + this->exclusive_lock_upgraded = false; + this->exclusive_lock = std::thread::id{}; + } +} #undef rw_mutex_assert \ No newline at end of file diff --git a/test/rw_lock.cpp b/test/rw_lock.cpp index 33ae42a..362d478 100644 --- a/test/rw_lock.cpp +++ b/test/rw_lock.cpp @@ -1,269 +1,269 @@ -// -// Created by WolverinDEV on 03/03/2020. -// - -#include "src/lock/rw_mutex.h" -#include -#include -#include -#include -#include -#include - -namespace helper { - std::mutex threads_lock{}; - size_t running_threads{0}; - std::vector thread_handles{}; - bool sync_pending{false}; - - inline void sync_threads() { - static std::condition_variable sync_cv; - static size_t synced_threads{0}; - - auto timeout = std::chrono::system_clock::now() + std::chrono::seconds{5}; - std::unique_lock lock{threads_lock}; - if(++synced_threads == running_threads) { - sync_cv.notify_all(); - synced_threads = 0; - sync_pending = false; - return; - } - - sync_pending = true; - if(sync_cv.wait_until(lock, timeout) == std::cv_status::timeout) { - std::cerr << "failed to sync threads" << std::endl; - abort(); - } - } - - template - inline void create_thread(args_t&&... arguments) { - auto callback = std::bind(arguments...); - - std::lock_guard tlock{threads_lock}; - thread_handles.emplace_back([callback]{ - callback(); - - std::lock_guard tlock{threads_lock}; - auto it = std::find_if(thread_handles.begin(), thread_handles.end(), [](const auto& thread) { - return thread.get_id() == std::this_thread::get_id(); - }); - if(it == thread_handles.end()) - return; /* thread will be joined via await_all_threads */ - - if(sync_pending) { - std::cerr << "thread terminated while sync was pending" << std::endl; - abort(); - } - - running_threads--; - it->detach(); - thread_handles.erase(it); - }); - running_threads++; - } - - inline void await_all_threads() { - std::unique_lock thread_lock{threads_lock}; - while(!thread_handles.empty()) { - auto thread = std::move(thread_handles.back()); - thread_handles.pop_back(); - thread_lock.unlock(); - thread.join(); - thread_lock.lock(); - - if(sync_pending) { - std::cerr << "thread terminated while sync was pending" << std::endl; - abort(); - } - running_threads--; - } - - } -} - -void testSharedLockLock() { - ts::rw_mutex lock{}; - - lock.lock_shared(); - lock.lock_shared(); - - lock.unlock_shared(); - lock.lock_shared(); - lock.unlock_shared(); - lock.unlock_shared(); -} - -void testExclusiveLock() { - ts::rw_mutex lock{}; - - size_t read_locked{0}, write_locked{0}; - for(int i = 0; i < 10; i++) { - if(rand() % 2 == 0) { - write_locked++; - lock.lock(); - lock.unlock(); - } else { - read_locked++; - lock.lock_shared(); - lock.unlock_shared(); - } - } - - /* to ensure that the read and write function has been tested more than once */ - assert(read_locked > 1); - assert(write_locked > 1); -} - -void testRW_Multithread() { - ts::rw_mutex lock{}; - - for(int i = 0; i < 20; i++) { - const auto do_sync = i < 5; - - std::atomic write_locked{false}; - helper::create_thread([&]{ - lock.lock(); - write_locked = true; - if(do_sync) helper::sync_threads(); /* sync point 1 */ - std::this_thread::sleep_for(std::chrono::seconds{1}); - write_locked = false; - lock.unlock(); - }); - - helper::create_thread([&]{ - if(do_sync) helper::sync_threads(); /* sync point 1 */ - lock.lock_shared(); - std::cout << "shared locked" << std::endl; - if(write_locked) { - std::cerr << "Shared lock succeeded, but thread has been write locked!" << std::endl; - return; - } - std::this_thread::sleep_for(std::chrono::seconds{1}); - std::cout << "unlocking shared lock" << std::endl; - lock.unlock_shared(); - }); - helper::await_all_threads(); - std::cout << "Loop " << i << " passed" << std::endl; - } -} - -void testLockUpgrade() { - std::atomic lock_released{true}; - std::atomic lock_shared{false}; - ts::rw_mutex lock{}; - - lock.lock_shared(); - std::cout << "[main] Locked shared lock" << std::endl; - lock_released = false; - lock_shared = true; - - helper::create_thread([&]{ - std::cout << "Awaiting exclusive lock" << std::endl; - lock.lock(); - std::cout << "Received exclusive lock" << std::endl; - if(!lock_released) { - std::cerr << "Acquired write lock even thou is hasn't been released!" << std::endl; - abort(); - } - - lock.unlock(); - }); - std::this_thread::sleep_for(std::chrono::milliseconds {100}); - - if(auto err = lock.upgrade_lock(); err) { - std::cerr << "Failed to upgrade lock: " << err << std::endl; - abort(); - } - std::cout << "[main] Upgraded shared lock" << std::endl; - lock_shared = false; - - helper::create_thread([&]{ - std::cout << "Awaiting shared lock" << std::endl; - lock.lock_shared(); - std::cout << "Received shared lock" << std::endl; - if(!lock_shared) { - std::cerr << "Acquired write lock even thou is hasn't been lock in shared mode!" << std::endl; - abort(); - } - - lock.unlock_shared(); - }); - - std::this_thread::sleep_for(std::chrono::milliseconds {100}); - lock_shared = true; - std::cout << "[main] Downgrading exclusive lock" << std::endl; - lock.downgrade_lock(); - - std::this_thread::sleep_for(std::chrono::milliseconds {10}); - lock_released = true; - std::cout << "[main] Releasing shared lock" << std::endl; - lock.unlock_shared(); - - helper::await_all_threads(); -} - -void testLockUpgradeRelease() { - { - ts::rw_mutex lock{}; - lock.lock_shared(); - (void) lock.upgrade_lock(); - lock.unlock(); - } - { - ts::rw_mutex lock{}; - lock.lock_shared(); - (void) lock.upgrade_lock(); - lock.downgrade_lock(); - lock.unlock_shared(); - } -} - -void testLockGuard() { - ts::rw_mutex mutex{}; - ts::rwshared_lock lock{mutex}; - bool lock_allowed{false}; - - if(auto err = lock.auto_lock_exclusive(); err) { - std::cerr << "Failed to upgrade lock: " << err << std::endl; - abort(); - } - assert(lock.exclusive_locked()); - - helper::create_thread([&]{ - std::cout << "Awaiting exclusive lock" << std::endl; - mutex.lock(); - std::cout << "Received exclusive lock" << std::endl; - if(!lock_allowed) { - std::cerr << "Acquired write lock even thou is hasn't been released!" << std::endl; - abort(); - } - - mutex.unlock(); - }); - std::this_thread::sleep_for(std::chrono::milliseconds {100}); - - lock.auto_lock_shared(); - - std::this_thread::sleep_for(std::chrono::milliseconds {100}); - lock_allowed = true; - lock.auto_unlock(); - helper::await_all_threads(); - - lock.lock_exclusive(); -} - -int main() { - { /* get rid of the unused warnings */ - ts::rw_unsafe_mutex mutex_a{}; - ts::rw_safe_mutex mutex_b{}; - } - - testSharedLockLock(); - testExclusiveLock(); - //testRW_Multithread(); - //TODO: Test lock order - testLockUpgrade(); - testLockUpgradeRelease(); - testLockGuard(); +// +// Created by WolverinDEV on 03/03/2020. +// + +#include "src/lock/rw_mutex.h" +#include +#include +#include +#include +#include +#include + +namespace helper { + std::mutex threads_lock{}; + size_t running_threads{0}; + std::vector thread_handles{}; + bool sync_pending{false}; + + inline void sync_threads() { + static std::condition_variable sync_cv; + static size_t synced_threads{0}; + + auto timeout = std::chrono::system_clock::now() + std::chrono::seconds{5}; + std::unique_lock lock{threads_lock}; + if(++synced_threads == running_threads) { + sync_cv.notify_all(); + synced_threads = 0; + sync_pending = false; + return; + } + + sync_pending = true; + if(sync_cv.wait_until(lock, timeout) == std::cv_status::timeout) { + std::cerr << "failed to sync threads" << std::endl; + abort(); + } + } + + template + inline void create_thread(args_t&&... arguments) { + auto callback = std::bind(arguments...); + + std::lock_guard tlock{threads_lock}; + thread_handles.emplace_back([callback]{ + callback(); + + std::lock_guard tlock{threads_lock}; + auto it = std::find_if(thread_handles.begin(), thread_handles.end(), [](const auto& thread) { + return thread.get_id() == std::this_thread::get_id(); + }); + if(it == thread_handles.end()) + return; /* thread will be joined via await_all_threads */ + + if(sync_pending) { + std::cerr << "thread terminated while sync was pending" << std::endl; + abort(); + } + + running_threads--; + it->detach(); + thread_handles.erase(it); + }); + running_threads++; + } + + inline void await_all_threads() { + std::unique_lock thread_lock{threads_lock}; + while(!thread_handles.empty()) { + auto thread = std::move(thread_handles.back()); + thread_handles.pop_back(); + thread_lock.unlock(); + thread.join(); + thread_lock.lock(); + + if(sync_pending) { + std::cerr << "thread terminated while sync was pending" << std::endl; + abort(); + } + running_threads--; + } + + } +} + +void testSharedLockLock() { + ts::rw_mutex lock{}; + + lock.lock_shared(); + lock.lock_shared(); + + lock.unlock_shared(); + lock.lock_shared(); + lock.unlock_shared(); + lock.unlock_shared(); +} + +void testExclusiveLock() { + ts::rw_mutex lock{}; + + size_t read_locked{0}, write_locked{0}; + for(int i = 0; i < 10; i++) { + if(rand() % 2 == 0) { + write_locked++; + lock.lock(); + lock.unlock(); + } else { + read_locked++; + lock.lock_shared(); + lock.unlock_shared(); + } + } + + /* to ensure that the read and write function has been tested more than once */ + assert(read_locked > 1); + assert(write_locked > 1); +} + +void testRW_Multithread() { + ts::rw_mutex lock{}; + + for(int i = 0; i < 20; i++) { + const auto do_sync = i < 5; + + std::atomic write_locked{false}; + helper::create_thread([&]{ + lock.lock(); + write_locked = true; + if(do_sync) helper::sync_threads(); /* sync point 1 */ + std::this_thread::sleep_for(std::chrono::seconds{1}); + write_locked = false; + lock.unlock(); + }); + + helper::create_thread([&]{ + if(do_sync) helper::sync_threads(); /* sync point 1 */ + lock.lock_shared(); + std::cout << "shared locked" << std::endl; + if(write_locked) { + std::cerr << "Shared lock succeeded, but thread has been write locked!" << std::endl; + return; + } + std::this_thread::sleep_for(std::chrono::seconds{1}); + std::cout << "unlocking shared lock" << std::endl; + lock.unlock_shared(); + }); + helper::await_all_threads(); + std::cout << "Loop " << i << " passed" << std::endl; + } +} + +void testLockUpgrade() { + std::atomic lock_released{true}; + std::atomic lock_shared{false}; + ts::rw_mutex lock{}; + + lock.lock_shared(); + std::cout << "[main] Locked shared lock" << std::endl; + lock_released = false; + lock_shared = true; + + helper::create_thread([&]{ + std::cout << "Awaiting exclusive lock" << std::endl; + lock.lock(); + std::cout << "Received exclusive lock" << std::endl; + if(!lock_released) { + std::cerr << "Acquired write lock even thou is hasn't been released!" << std::endl; + abort(); + } + + lock.unlock(); + }); + std::this_thread::sleep_for(std::chrono::milliseconds {100}); + + if(auto err = lock.upgrade_lock(); err) { + std::cerr << "Failed to upgrade lock: " << err << std::endl; + abort(); + } + std::cout << "[main] Upgraded shared lock" << std::endl; + lock_shared = false; + + helper::create_thread([&]{ + std::cout << "Awaiting shared lock" << std::endl; + lock.lock_shared(); + std::cout << "Received shared lock" << std::endl; + if(!lock_shared) { + std::cerr << "Acquired write lock even thou is hasn't been lock in shared mode!" << std::endl; + abort(); + } + + lock.unlock_shared(); + }); + + std::this_thread::sleep_for(std::chrono::milliseconds {100}); + lock_shared = true; + std::cout << "[main] Downgrading exclusive lock" << std::endl; + lock.downgrade_lock(); + + std::this_thread::sleep_for(std::chrono::milliseconds {10}); + lock_released = true; + std::cout << "[main] Releasing shared lock" << std::endl; + lock.unlock_shared(); + + helper::await_all_threads(); +} + +void testLockUpgradeRelease() { + { + ts::rw_mutex lock{}; + lock.lock_shared(); + (void) lock.upgrade_lock(); + lock.unlock(); + } + { + ts::rw_mutex lock{}; + lock.lock_shared(); + (void) lock.upgrade_lock(); + lock.downgrade_lock(); + lock.unlock_shared(); + } +} + +void testLockGuard() { + ts::rw_mutex mutex{}; + ts::rwshared_lock lock{mutex}; + bool lock_allowed{false}; + + if(auto err = lock.auto_lock_exclusive(); err) { + std::cerr << "Failed to upgrade lock: " << err << std::endl; + abort(); + } + assert(lock.exclusive_locked()); + + helper::create_thread([&]{ + std::cout << "Awaiting exclusive lock" << std::endl; + mutex.lock(); + std::cout << "Received exclusive lock" << std::endl; + if(!lock_allowed) { + std::cerr << "Acquired write lock even thou is hasn't been released!" << std::endl; + abort(); + } + + mutex.unlock(); + }); + std::this_thread::sleep_for(std::chrono::milliseconds {100}); + + lock.auto_lock_shared(); + + std::this_thread::sleep_for(std::chrono::milliseconds {100}); + lock_allowed = true; + lock.auto_unlock(); + helper::await_all_threads(); + + lock.lock_exclusive(); +} + +int main() { + { /* get rid of the unused warnings */ + ts::rw_unsafe_mutex mutex_a{}; + ts::rw_safe_mutex mutex_b{}; + } + + testSharedLockLock(); + testExclusiveLock(); + //testRW_Multithread(); + //TODO: Test lock order + testLockUpgrade(); + testLockUpgradeRelease(); + testLockGuard(); } \ No newline at end of file