diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 06428af69fa..c88ef20a4f9 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -952,6 +952,7 @@ INSERT INTO `rbac_linked_permissions` VALUES (196,773), (196,775), (196,777), +(196,830), (196,836), (196,837), (196,838), @@ -1824,6 +1825,7 @@ INSERT INTO `rbac_permissions` VALUES (792,'Command: ahbot reload'), (793,'Command: ahbot status'), (794,'Command: guild info'), +(830,'Command: bnetaccount listgameaccounts'), (835,'Command: debug loadcells'), (836,'Command: debug boundary'), (837,'Command: npc evade'), @@ -2000,7 +2002,8 @@ INSERT INTO `updates` VALUES ('2019_09_29_00_auth.sql','73C820469E1EF2501C3126CA098D6FE7DD4E0D3C','RELEASED','2019-11-06 00:17:44',85), ('2019_10_03_00_auth.sql','A0D27DAFDE2F7F1F7FAAACF1E13FA104A50D603A','RELEASED','2019-11-06 00:17:44',80), ('2019_10_06_00_auth.sql','0E25F5CB2CEDAB52B899085EEC9EEB37B8236F20','RELEASED','2019-11-06 00:17:44',64), -('2019_10_08_00_auth.sql','1CD55291FED15182C2E71F8695E4B304EDB3F35E','RELEASED','2019-11-06 00:17:44',63); +('2019_10_08_00_auth.sql','1CD55291FED15182C2E71F8695E4B304EDB3F35E','RELEASED','2019-11-06 00:17:44',63), +('9999_99_99_99_auth.sql','B3738FB3FA1C75E430EC64B5E9635A5E52E3AB36','RELEASED','2020-02-13 16:37:42',37); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/4.3.4/9999_99_99_99_auth.sql b/sql/updates/auth/4.3.4/9999_99_99_99_auth.sql new file mode 100644 index 00000000000..dcdaf999553 --- /dev/null +++ b/sql/updates/auth/4.3.4/9999_99_99_99_auth.sql @@ -0,0 +1,7 @@ +DELETE FROM `rbac_permissions` WHERE `id`=830; +INSERT INTO `rbac_permissions` (`id`,`name`) VALUES +(830,'Command: bnetaccount listgameaccounts'); + +DELETE FROM `rbac_linked_permissions` WHERE `id`=196 AND `linkedId`=830; +INSERT INTO `rbac_linked_permissions` (`id`, `linkedId`) VALUES +(196, 830); diff --git a/sql/updates/world/custom/custom_9999_99_99_99_world.sql b/sql/updates/world/custom/custom_9999_99_99_99_world.sql new file mode 100644 index 00000000000..2e45b7d2b83 --- /dev/null +++ b/sql/updates/world/custom/custom_9999_99_99_99_world.sql @@ -0,0 +1,11 @@ +DELETE FROM `command` WHERE `name`='bnetaccount listgameaccounts'; +INSERT INTO `command` (`name`,`permission`,`help`) VALUES +('bnetaccount listgameaccounts', 830, 'Syntax: .bnetaccount listgameaccounts $email $password\nLists all game accounts linked to battle.net $email'); + +DELETE FROM `trinity_string` WHERE `entry` IN (1030, 1032, 1033, 1034, 1035); +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES +(1030, 'You are attempting to create a battle.net account with wrong command, use .bnetaccount create'), +(1032, 'Battle.net account created: %s with game account %s'), +(1033, 'Battle.net account created: %s'), +(1034, '| Account Id | Internal name | Display name |'), +(1035, 'Battle.net account %s has no linked game accounts.'); diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index 82232bb36d5..e5d56114687 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -579,7 +579,7 @@ void HexStrToByteArray(std::string const& str, uint8* out, bool reverse /*= fals bool StringToBool(std::string const& str) { std::string lowerStr = str; - std::transform(str.begin(), str.end(), lowerStr.begin(), ::tolower); + std::transform(str.begin(), str.end(), lowerStr.begin(), [](char c) { return char(::tolower(c)); }); return lowerStr == "1" || lowerStr == "true" || lowerStr == "yes"; } diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index d55d66eddf6..91a21d03d07 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -148,6 +148,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT, "SELECT battlenet_account FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LINK, "UPDATE account SET battlenet_account = ?, battlenet_index = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_MAX_ACCOUNT_INDEX, "SELECT MAX(battlenet_index) FROM account WHERE battlenet_account = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_LIST, "SELECT a.id, a.username FROM account a LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id WHERE ba.email = ?", CONNECTION_SYNCH); } LoginDatabaseConnection::LoginDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo) diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index 0ed20093f0e..593be33ab9d 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -130,6 +130,7 @@ enum LoginDatabaseStatements : uint32 LOGIN_SEL_BNET_ACCOUNT_ID_BY_GAME_ACCOUNT, LOGIN_UPD_BNET_GAME_ACCOUNT_LINK, LOGIN_SEL_BNET_MAX_ACCOUNT_INDEX, + LOGIN_SEL_BNET_GAME_ACCOUNT_LIST, MAX_LOGINDATABASE_STATEMENTS }; diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp index aa176f438ff..54f4113f0d0 100644 --- a/src/server/game/Accounts/BattlenetAccountMgr.cpp +++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp @@ -15,15 +15,15 @@ * with this program. If not, see . */ -#include "AccountMgr.h" #include "BattlenetAccountMgr.h" +#include "AccountMgr.h" #include "DatabaseEnv.h" #include "Util.h" #include "SHA256.h" using GameAccountMgr = AccountMgr; -AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, std::string password) +AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, std::string password, bool withGameAccount, std::string* gameAccountName) { if (utf8length(email) > MAX_BNET_EMAIL_STR) return AccountOpResult::AOR_NAME_TOO_LONG; @@ -35,7 +35,7 @@ AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, Utf8ToUpperOnlyLatin(password); if (GetId(email)) - return AccountOpResult::AOR_NAME_ALREADY_EXIST; + return AccountOpResult::AOR_NAME_ALREADY_EXIST; PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT); stmt->setString(0, email); @@ -45,7 +45,11 @@ AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, uint32 newAccountId = GetId(email); ASSERT(newAccountId); - GameAccountMgr::instance()->CreateAccount(std::to_string(newAccountId) + "#1", password, email, newAccountId, 1); + if (withGameAccount) + { + *gameAccountName = std::to_string(newAccountId) + "#1"; + GameAccountMgr::instance()->CreateAccount(*gameAccountName, password, email, newAccountId, 1); + } return AccountOpResult::AOR_OK; } diff --git a/src/server/game/Accounts/BattlenetAccountMgr.h b/src/server/game/Accounts/BattlenetAccountMgr.h index 5a169374cd7..fb2e333d4b5 100644 --- a/src/server/game/Accounts/BattlenetAccountMgr.h +++ b/src/server/game/Accounts/BattlenetAccountMgr.h @@ -29,7 +29,7 @@ namespace Battlenet { namespace AccountMgr { - TC_GAME_API AccountOpResult CreateBattlenetAccount(std::string email, std::string password); + TC_GAME_API AccountOpResult CreateBattlenetAccount(std::string email, std::string password, bool withGameAccount, std::string* gameAccountName); TC_GAME_API AccountOpResult ChangePassword(uint32 accountId, std::string newPassword); TC_GAME_API bool CheckPassword(uint32 accountId, std::string password); TC_GAME_API AccountOpResult LinkWithGameAccount(std::string const& email, std::string const& gameAccountName); diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index d9522b2334f..756b5f9184b 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -727,7 +727,7 @@ enum RBACPermissions RBAC_PERM_COMMAND_TICKET_SUGGESTION_UNASSIGN = 827, // not on 3.3.5a or 4.3.4 RBAC_PERM_COMMAND_TICKET_SUGGESTION_VIEW = 828, // not on 3.3.5a or 4.3.4 RBAC_PERM_COMMAND_TICKET_RESET_ALL = 829, // not on 3.3.5a or 4.3.4 - RBAC_PERM_COMMAND_BNET_ACCOUNT_LIST_GAME_ACCOUTNS = 830, // not on 3.3.5a or 4.3.4 + RBAC_PERM_COMMAND_BNET_ACCOUNT_LIST_GAME_ACCOUNTS = 830, RBAC_PERM_COMMAND_TICKET_RESET_BUG = 831, // not on 3.3.5a or 4.3.4 RBAC_PERM_COMMAND_TICKET_RESET_COMPLAINT = 832, // not on 3.3.5a or 4.3.4 RBAC_PERM_COMMAND_TICKET_RESET_SUGGESTION = 833, // not on 3.3.5a or 4.3.4 diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 71b2e802e65..95d5535d28c 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -829,13 +829,13 @@ enum TrinityStrings LANG_CHARACTER_DELETED_LIST_LINE_CHAT = 1026, LANG_SQLDRIVER_QUERY_LOGGING_ENABLED = 1027, LANG_SQLDRIVER_QUERY_LOGGING_DISABLED = 1028, - LANG_ACCOUNT_INVALID_BNET_NAME = 1029, // 6.x ONLY - LANG_ACCOUNT_USE_BNET_COMMANDS = 1030, // 6.x enum value name but different text in DB + LANG_ACCOUNT_INVALID_BNET_NAME = 1029, + LANG_ACCOUNT_USE_BNET_COMMANDS = 1030, LANG_ACCOUNT_PASS_TOO_LONG = 1031, - LANG_ACCOUNT_CREATED_BNET_WITH_GAME = 1032, // master branch ONLY - LANG_ACCOUNT_CREATED_BNET = 1033, // master branch ONLY - LANG_ACCOUNT_BNET_LIST_HEADER = 1034, // master branch ONLY - LANG_ACCOUNT_BNET_LIST_NO_ACCOUNTS = 1035, // master branch ONLY + LANG_ACCOUNT_CREATED_BNET_WITH_GAME = 1032, + LANG_ACCOUNT_CREATED_BNET = 1033, + LANG_ACCOUNT_BNET_LIST_HEADER = 1034, + LANG_ACCOUNT_BNET_LIST_NO_ACCOUNTS = 1035, LANG_ACCOUNT_BNET_LINKED = 1036, LANG_ACCOUNT_OR_BNET_DOES_NOT_EXIST = 1037, LANG_ACCOUNT_ALREADY_LINKED = 1038, diff --git a/src/server/scripts/Commands/cs_battlenet_account.cpp b/src/server/scripts/Commands/cs_battlenet_account.cpp index f3a1444ceab..93bb7497c7d 100644 --- a/src/server/scripts/Commands/cs_battlenet_account.cpp +++ b/src/server/scripts/Commands/cs_battlenet_account.cpp @@ -15,9 +15,9 @@ * with this program. If not, see . */ -#include "ScriptMgr.h" #include "AccountMgr.h" #include "BattlenetAccountMgr.h" +#include "BigNumber.h" #include "Chat.h" #include "DatabaseEnv.h" #include "IpAddress.h" @@ -25,7 +25,8 @@ #include "Language.h" #include "Log.h" #include "Player.h" -#include "RBAC.h" +#include "ScriptMgr.h" +#include "Util.h" #include "WorldSession.h" class battlenet_account_commandscript : public CommandScript @@ -48,13 +49,14 @@ public: static std::vector accountCommandTable = { - { "create", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE, true, &HandleAccountCreateCommand, "" }, - { "gameaccountcreate", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE_GAME, true, &HandleGameAccountCreateCommand, "", }, - { "lock", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, false, nullptr, "", accountLockCommandTable }, - { "set", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_SET, true, nullptr, "", accountSetCommandTable }, - { "password", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD, false, &HandleAccountPasswordCommand, "" }, - { "link", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_LINK, true, &HandleAccountLinkCommand, "", }, - { "unlink", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_UNLINK, true, &HandleAccountUnlinkCommand, "", }, + { "create", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE, true, &HandleAccountCreateCommand, "" }, + { "gameaccountcreate", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_CREATE_GAME, true, &HandleGameAccountCreateCommand, "", }, + { "lock", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT, false, nullptr, "", accountLockCommandTable }, + { "set", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_SET, true, nullptr, "", accountSetCommandTable }, + { "password", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_PASSWORD, false, &HandleAccountPasswordCommand, "" }, + { "link", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_LINK, true, &HandleAccountLinkCommand, "", }, + { "unlink", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_UNLINK, true, &HandleAccountUnlinkCommand, "", }, + { "listgameaccounts", rbac::RBAC_PERM_COMMAND_BNET_ACCOUNT_LIST_GAME_ACCOUNTS, true, &HandleListGameAccountsCommand, "" } }; static std::vector commandTable = @@ -71,8 +73,6 @@ public: if (!*args) return false; - std::string email; - ///- %Parse the command line arguments char* accountName = strtok((char*)args, " "); char* password = strtok(nullptr, " "); @@ -86,32 +86,44 @@ public: return false; } - switch (Battlenet::AccountMgr::CreateBattlenetAccount(std::string(accountName), std::string(password))) + char* createGameAccountParam = strtok(nullptr, " "); + bool createGameAccount = true; + if (createGameAccountParam) + createGameAccount = StringToBool(createGameAccountParam); + + std::string gameAccountName; + switch (Battlenet::AccountMgr::CreateBattlenetAccount(std::string(accountName), std::string(password), createGameAccount, &gameAccountName)) { case AccountOpResult::AOR_OK: - handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName); + { + if (createGameAccount) + handler->PSendSysMessage(LANG_ACCOUNT_CREATED_BNET_WITH_GAME, accountName, gameAccountName.c_str()); + else + handler->PSendSysMessage(LANG_ACCOUNT_CREATED_BNET, accountName); + if (handler->GetSession()) { - TC_LOG_INFO("entities.player.character", "Battle.net account: %d (IP: %s) Character:[%s] (GUID: %u) created Account %s", + TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (%s) created Battle.net account %s%s%s", handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), - handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().GetCounter(), - accountName); + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().ToString().c_str(), + accountName, createGameAccount ? " with game account " : "", createGameAccount ? gameAccountName.c_str() : ""); } break; + } case AccountOpResult::AOR_NAME_TOO_LONG: handler->SendSysMessage(LANG_ACCOUNT_NAME_TOO_LONG); handler->SetSentErrorMessage(true); return false; - case AccountOpResult::AOR_NAME_ALREADY_EXIST: - handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); - handler->SetSentErrorMessage(true); - return false; case AccountOpResult::AOR_PASS_TOO_LONG: handler->SendSysMessage(LANG_PASSWORD_TOO_LONG); handler->SetSentErrorMessage(true); return false; - default: + case AccountOpResult::AOR_NAME_ALREADY_EXIST: + handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); + handler->SetSentErrorMessage(true); return false; + default: + break; } return true; @@ -224,12 +236,12 @@ public: } // We compare the old, saved password to the entered old password - no chance for the unauthorized. - if (!Battlenet::AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), std::string(oldPassword))) + if (!Battlenet::AccountMgr::CheckPassword(handler->GetSession()->GetBattlenetAccountId(), std::string(oldPassword))) { handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD); handler->SetSentErrorMessage(true); TC_LOG_INFO("entities.player.character", "Battle.net account: %u (IP: %s) Character:[%s] (GUID: %u) Tried to change password, but the provided old password is wrong.", - handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), + handler->GetSession()->GetBattlenetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().GetCounter()); return false; } @@ -412,38 +424,80 @@ public: uint8 index = Battlenet::AccountMgr::GetMaxIndex(accountId) + 1; std::string accountName = std::to_string(accountId) + '#' + std::to_string(uint32(index)); - switch (sAccountMgr->CreateAccount(accountName, "DUMMY", bnetAccountName, accountId, index)) + // Generate random hex string for password, these accounts must not be logged on with GRUNT + BigNumber randPassword; + randPassword.SetRand(8 * 16); + + switch (sAccountMgr->CreateAccount(accountName, ByteArrayToHexStr(randPassword.AsByteArray().get(), randPassword.GetNumBytes()), bnetAccountName, accountId, index)) { - case AccountOpResult::AOR_OK: - handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName.c_str()); - if (handler->GetSession()) - { - TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (%s) created Account %s (Email: '%s')", - handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), - handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().ToString().c_str(), - accountName.c_str(), bnetAccountName.c_str()); - } - break; - case AccountOpResult::AOR_NAME_TOO_LONG: - handler->SendSysMessage(LANG_ACCOUNT_NAME_TOO_LONG); - handler->SetSentErrorMessage(true); - return false; - case AccountOpResult::AOR_NAME_ALREADY_EXIST: - handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); - handler->SetSentErrorMessage(true); - return false; - case AccountOpResult::AOR_DB_INTERNAL_ERROR: - handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName.c_str()); - handler->SetSentErrorMessage(true); - return false; - default: - handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, accountName.c_str()); - handler->SetSentErrorMessage(true); - return false; + case AccountOpResult::AOR_OK: + handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName.c_str()); + if (handler->GetSession()) + { + TC_LOG_INFO("entities.player.character", "Account: %u (IP: %s) Character:[%s] (%s) created Account %s (Email: '%s')", + handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(), + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUID().ToString().c_str(), + accountName.c_str(), bnetAccountName.c_str()); + } + break; + case AccountOpResult::AOR_NAME_TOO_LONG: + handler->SendSysMessage(LANG_ACCOUNT_NAME_TOO_LONG); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_PASS_TOO_LONG: + handler->SendSysMessage(LANG_ACCOUNT_PASS_TOO_LONG); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_NAME_ALREADY_EXIST: + handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); + handler->SetSentErrorMessage(true); + return false; + case AccountOpResult::AOR_DB_INTERNAL_ERROR: + handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName.c_str()); + handler->SetSentErrorMessage(true); + return false; + default: + handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, accountName.c_str()); + handler->SetSentErrorMessage(true); + return false; } return true; } + + static bool HandleListGameAccountsCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + char* battlenetAccountName = strtok((char*)args, " "); + PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_GAME_ACCOUNT_LIST); + stmt->setString(0, battlenetAccountName); + if (PreparedQueryResult accountList = LoginDatabase.Query(stmt)) + { + auto formatDisplayName = [](char const* name) -> std::string + { + if (char const* hashPos = strchr(name, '#')) + return std::string("WoW") + ++hashPos; + else + return name; + }; + + handler->SendSysMessage("----------------------------------------------------"); + handler->SendSysMessage(LANG_ACCOUNT_BNET_LIST_HEADER); + handler->SendSysMessage("----------------------------------------------------"); + do + { + Field* fields = accountList->Fetch(); + handler->PSendSysMessage("| %10u | %-16.16s | %-16.16s |", fields[0].GetUInt32(), fields[1].GetCString(), formatDisplayName(fields[1].GetCString()).c_str()); + } while (accountList->NextRow()); + handler->SendSysMessage("----------------------------------------------------"); + } + else + handler->PSendSysMessage(LANG_ACCOUNT_BNET_LIST_NO_ACCOUNTS, battlenetAccountName); + + return true; + } }; void AddSC_battlenet_account_commandscript()