diff --git a/src/command_type.h b/src/command_type.h index 193802ef17..2d7fc86672 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -295,7 +295,7 @@ enum Commands : uint16_t { CMD_CREATE_SUBSIDY, ///< create a new subsidy CMD_COMPANY_CTRL, ///< used in multiplayer to create a new companies etc. - CMD_COMPANY_ADD_ALLOW_LIST, ///< Used in multiplayer to add a client's public key to the company's allow list. + CMD_COMPANY_ALLOW_LIST_CTRL, ///< Used in multiplayer to add/remove a client's public key to/from the company's allow list. CMD_CUSTOM_NEWS_ITEM, ///< create a custom news message CMD_CREATE_GOAL, ///< create a new goal CMD_REMOVE_GOAL, ///< remove a goal diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index ec9d273857..74ad2893f4 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -979,16 +979,46 @@ CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID return CommandCost(); } +static bool ExecuteAllowListCtrlAction(CompanyAllowListCtrlAction action, Company *c, const std::string &public_key) +{ + switch (action) { + case CALCA_ADD: + return c->allow_list.Add(public_key); + + case CALCA_REMOVE: + return c->allow_list.Remove(public_key); + + default: + NOT_REACHED(); + } +} + /** - * Add the given public key to the allow list of this company. + * Add or remove the given public key to the allow list of this company. * @param flags Operation to perform. - * @param public_key The public key of the client to add. + * @param action The action to perform. + * @param public_key The public key of the client to add or remove. * @return The cost of this operation or an error. */ -CommandCost CmdCompanyAddAllowList(DoCommandFlag flags, const std::string &public_key) +CommandCost CmdCompanyAllowListCtrl(DoCommandFlag flags, CompanyAllowListCtrlAction action, const std::string &public_key) { + Company *c = Company::GetIfValid(_current_company); + if (c == nullptr) return CMD_ERROR; + + /* The public key length includes the '\0'. */ + if (public_key.size() != NETWORK_PUBLIC_KEY_LENGTH - 1) return CMD_ERROR; + + switch (action) { + case CALCA_ADD: + case CALCA_REMOVE: + break; + + default: + return CMD_ERROR; + } + if (flags & DC_EXEC) { - if (Company::Get(_current_company)->allow_list.Add(public_key)) { + if (ExecuteAllowListCtrlAction(action, c, public_key)) { InvalidateWindowData(WC_CLIENT_LIST, 0); SetWindowDirty(WC_COMPANY, _current_company); } diff --git a/src/company_cmd.h b/src/company_cmd.h index 4ee9efc1e9..513293a995 100644 --- a/src/company_cmd.h +++ b/src/company_cmd.h @@ -18,7 +18,7 @@ enum ClientID : uint32_t; enum Colours : uint8_t; CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id); -CommandCost CmdCompanyAddAllowList(DoCommandFlag flags, const std::string &public_key); +CommandCost CmdCompanyAllowListCtrl(DoCommandFlag flags, CompanyAllowListCtrlAction action, const std::string &public_key); CommandCost CmdGiveMoney(DoCommandFlag flags, Money money, CompanyID dest_company); CommandCost CmdRenameCompany(DoCommandFlag flags, const std::string &text); CommandCost CmdRenamePresident(DoCommandFlag flags, const std::string &text); @@ -26,7 +26,7 @@ CommandCost CmdSetCompanyManagerFace(DoCommandFlag flags, CompanyManagerFace cmf CommandCost CmdSetCompanyColour(DoCommandFlag flags, LiveryScheme scheme, bool primary, Colours colour); DEF_CMD_TRAIT(CMD_COMPANY_CTRL, CmdCompanyCtrl, CMD_SPECTATOR | CMD_CLIENT_ID | CMD_NO_EST, CMDT_SERVER_SETTING) -DEF_CMD_TRAIT(CMD_COMPANY_ADD_ALLOW_LIST, CmdCompanyAddAllowList, CMD_NO_EST, CMDT_SERVER_SETTING) +DEF_CMD_TRAIT(CMD_COMPANY_ALLOW_LIST_CTRL, CmdCompanyAllowListCtrl, CMD_NO_EST, CMDT_SERVER_SETTING) DEF_CMD_TRAIT(CMD_GIVE_MONEY, CmdGiveMoney, 0, CMDT_MONEY_MANAGEMENT) DEF_CMD_TRAIT(CMD_RENAME_COMPANY, CmdRenameCompany, 0, CMDT_COMPANY_SETTING) DEF_CMD_TRAIT(CMD_RENAME_PRESIDENT, CmdRenamePresident, 0, CMDT_COMPANY_SETTING) diff --git a/src/company_type.h b/src/company_type.h index c119a17719..355bde8630 100644 --- a/src/company_type.h +++ b/src/company_type.h @@ -72,4 +72,12 @@ enum CompanyCtrlAction : uint8_t { CCA_END, ///< Sentinel for end. }; +/** The action to do with CMD_COMPANY_ALLOW_LIST_CTRL. */ +enum CompanyAllowListCtrlAction : uint8_t { + CALCA_ADD, ///< Create a public key. + CALCA_REMOVE, ///< Remove a public key. + + CALCA_END, ///< Sentinel for end. +}; + #endif /* COMPANY_TYPE_H */ diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index e6a45e5ce9..fb5ced4066 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1519,7 +1519,7 @@ private: static void OnClickClientAuthorize([[maybe_unused]] NetworkClientListWindow *w, [[maybe_unused]] Point pt, ClientID client_id) { AutoRestoreBackup cur_company(_current_company, NetworkClientInfo::GetByClientID(_network_own_client_id)->client_playas); - Command::Post(NetworkClientInfo::GetByClientID(client_id)->public_key); + Command::Post(CALCA_ADD, NetworkClientInfo::GetByClientID(client_id)->public_key); } /** diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 0db16a5660..be04e39a99 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -1117,11 +1117,12 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet } } - if (cp.cmd == CMD_COMPANY_ADD_ALLOW_LIST) { + if (cp.cmd == CMD_COMPANY_ALLOW_LIST_CTRL) { /* Maybe the client just got moved before allowing? */ if (ci->client_id != CLIENT_ID_SERVER && ci->client_playas != cp.company) return NETWORK_RECV_STATUS_OKAY; - std::string public_key = std::get<0>(EndianBufferReader::ToValue::Args>(cp.data)); + /* Only allow clients to add/remove currently joined clients. The server owner does not go via this method, so is allowed to do more. */ + std::string public_key = std::get<1>(EndianBufferReader::ToValue::Args>(cp.data)); bool found = false; for (const NetworkClientInfo *info : NetworkClientInfo::Iterate()) { if (info->public_key == public_key) { @@ -2164,7 +2165,7 @@ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci) * different state/president/company name in the different clients, we need to * circumvent the normal ::Post logic and go directly to sending the command. */ - Command::SendNet(STR_NULL, c->index, ci->public_key); + Command::SendNet(STR_NULL, c->index, CALCA_ADD, ci->public_key); Command::SendNet(STR_NULL, c->index, ci->client_name); NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1);