Files
moonwell-core-vanilla/src/game/Commands/AccountCommands.cpp
T
2019-05-03 00:03:19 +03:00

1267 lines
41 KiB
C++

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "Database/DatabaseImpl.h"
#include "World.h"
#include "Player.h"
#include "SpellAuras.h"
#include "Chat.h"
#include "ObjectAccessor.h"
#include "Language.h"
#include "AccountMgr.h"
#include "ObjectMgr.h"
#include "SystemConfig.h"
#include "revision.h"
#include "Util.h"
#include "AsyncCommandHandlers.h"
#include "Anticheat.h"
bool ChatHandler::HandleAccountCommand(char* args)
{
// let show subcommands at unexpected data in args
if (*args)
return false;
AccountTypes gmlevel = GetAccessLevel();
PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmlevel));
return true;
}
/// Set/Unset the expansion level for an account
bool ChatHandler::HandleAccountSetAddonCommand(char* args)
{
///- Get the command line arguments
char* accountStr = ExtractOptNotLastArg(&args);
std::string account_name;
uint32 account_id = ExtractAccountId(&accountStr, &account_name);
if (!account_id)
return false;
// Let set addon state only for lesser (strong) security level
// or to self account
if (GetAccountId() && GetAccountId() != account_id &&
HasLowerSecurityAccount(NULL, account_id, true))
return false;
uint32 lev;
if (!ExtractUInt32(&args, lev))
return false;
// No SQL injection
LoginDatabase.PExecute("UPDATE account SET expansion = '%u' WHERE id = '%u'", lev, account_id);
PSendSysMessage(LANG_ACCOUNT_SETADDON, account_name.c_str(), account_id, lev);
return true;
}
bool ChatHandler::HandleAccountSetGmLevelCommand(char* args)
{
char* accountStr = ExtractOptNotLastArg(&args);
std::string targetAccountName;
Player* targetPlayer = NULL;
uint32 targetAccountId = ExtractAccountId(&accountStr, &targetAccountName, &targetPlayer);
if (!targetAccountId)
return false;
/// only target player different from self allowed
if (GetAccountId() == targetAccountId)
return false;
int32 gm;
if (!ExtractInt32(&args, gm))
return false;
if (gm < SEC_PLAYER || gm > SEC_ADMINISTRATOR)
{
SendSysMessage(LANG_BAD_VALUE);
SetSentErrorMessage(true);
return false;
}
/// can set security level only for target with less security and to less security that we have
/// This is also reject self apply in fact
if (HasLowerSecurityAccount(NULL, targetAccountId, true))
return false;
/// account can't set security to same or grater level, need more power GM or console
AccountTypes plSecurity = GetAccessLevel();
if (AccountTypes(gm) >= plSecurity)
{
SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
SetSentErrorMessage(true);
return false;
}
if (targetPlayer)
{
ChatHandler(targetPlayer).PSendSysMessage(LANG_YOURS_SECURITY_CHANGED, GetNameLink().c_str(), gm);
targetPlayer->GetSession()->SetSecurity(AccountTypes(gm));
}
PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm);
sAccountMgr.SetSecurity(targetAccountId, AccountTypes(gm));
return true;
}
/// Set password for account
bool ChatHandler::HandleAccountSetPasswordCommand(char* args)
{
///- Get the command line arguments
std::string account_name;
uint32 targetAccountId = ExtractAccountId(&args, &account_name);
if (!targetAccountId)
return false;
// allow or quoted string with possible spaces or literal without spaces
char *szPassword1 = ExtractQuotedOrLiteralArg(&args);
char *szPassword2 = ExtractQuotedOrLiteralArg(&args);
if (!szPassword1 || !szPassword2)
return false;
/// can set password only for target with less security
/// This is also reject self apply in fact
if (HasLowerSecurityAccount(NULL, targetAccountId, true))
return false;
if (strcmp(szPassword1, szPassword2))
{
SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH);
SetSentErrorMessage(true);
return false;
}
AccountOpResult result = sAccountMgr.ChangePassword(targetAccountId, szPassword1);
switch (result)
{
case AOR_OK:
SendSysMessage(LANG_COMMAND_PASSWORD);
break;
case AOR_NAME_NOT_EXIST:
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
SetSentErrorMessage(true);
return false;
case AOR_PASS_TOO_LONG:
SendSysMessage(LANG_PASSWORD_TOO_LONG);
SetSentErrorMessage(true);
return false;
default:
SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD);
SetSentErrorMessage(true);
return false;
}
return true;
}
/// Set locked status for account
bool ChatHandler::HandleAccountSetLockedCommand(char* args)
{
///- Get the command line arguments
char* accountStr = ExtractOptNotLastArg(&args);
std::string account_name;
uint32 account_id = ExtractAccountId(&accountStr, &account_name);
if (!account_id)
return false;
// Let set locked state only for lesser (strong) security level
// or to self account
if (GetAccountId() && GetAccountId() != account_id &&
HasLowerSecurityAccount(NULL, account_id, true))
return false;
uint32 value;
if (!ExtractUInt32(&args, value))
{
PSendSysMessage(LANG_SET_LOCK_USAGE);
return false;
}
if (value < 16)
{
LoginDatabase.PExecute("UPDATE account SET locked = '%u' WHERE id = '%u'", value, account_id);
PSendSysMessage(LANG_SET_LOCK_SUCCESS, account_name.c_str(), account_id, value);
}
else
{
PSendSysMessage(LANG_SET_LOCK_USAGE);
return false;
}
return true;
}
/// Output list of character for account
bool ChatHandler::HandleAccountCharactersCommand(char* args)
{
///- Get the command line arguments
std::string account_name;
Player* target = NULL; // only for triggering use targeted player account
uint32 account_id = ExtractAccountId(&args, &account_name, &target);
if (!account_id)
return false;
///- Get the characters for account id
CharacterDatabase.AsyncPQuery(&PlayerSearchHandler::HandlePlayerCharacterLookupResult,
GetAccountId(), 100u,
"SELECT guid, name, race, class, level FROM characters WHERE account = %u",
account_id);
return true;
}
/// Create an account
bool ChatHandler::HandleAccountCreateCommand(char* args)
{
///- %Parse the command line arguments
char *szAcc = ExtractQuotedOrLiteralArg(&args);
char *szPassword = ExtractQuotedOrLiteralArg(&args);
if(!szAcc || !szPassword)
return false;
// normalized in accmgr.CreateAccount
std::string account_name = szAcc;
std::string password = szPassword;
AccountOpResult result = sAccountMgr.CreateAccount(account_name, password);
switch(result)
{
case AOR_OK:
PSendSysMessage(LANG_ACCOUNT_CREATED,account_name.c_str());
break;
case AOR_NAME_TOO_LONG:
SendSysMessage(LANG_ACCOUNT_TOO_LONG);
SetSentErrorMessage(true);
return false;
case AOR_NAME_ALREDY_EXIST:
SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST);
SetSentErrorMessage(true);
return false;
case AOR_DB_INTERNAL_ERROR:
PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR,account_name.c_str());
SetSentErrorMessage(true);
return false;
default:
PSendSysMessage(LANG_ACCOUNT_NOT_CREATED,account_name.c_str());
SetSentErrorMessage(true);
return false;
}
return true;
}
/// Delete a user account and all associated characters in this realm
/// \todo This function has to be enhanced to respect the login/realm split (delete char, delete account chars in realm, delete account chars in realm then delete account
bool ChatHandler::HandleAccountDeleteCommand(char* args)
{
if (!*args)
return false;
std::string account_name;
uint32 account_id = ExtractAccountId(&args, &account_name);
if (!account_id)
return false;
/// Commands not recommended call from chat, but support anyway
/// can delete only for account with less security
/// This is also reject self apply in fact
if (HasLowerSecurityAccount (NULL, account_id, true))
return false;
AccountOpResult result = sAccountMgr.DeleteAccount(account_id);
switch(result)
{
case AOR_OK:
PSendSysMessage(LANG_ACCOUNT_DELETED,account_name.c_str());
break;
case AOR_NAME_NOT_EXIST:
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
SetSentErrorMessage(true);
return false;
case AOR_DB_INTERNAL_ERROR:
PSendSysMessage(LANG_ACCOUNT_NOT_DELETED_SQL_ERROR,account_name.c_str());
SetSentErrorMessage(true);
return false;
default:
PSendSysMessage(LANG_ACCOUNT_NOT_DELETED,account_name.c_str());
SetSentErrorMessage(true);
return false;
}
return true;
}
/// Display info on users currently in the realm
bool ChatHandler::HandleAccountOnlineListCommand(char* args)
{
uint32 limit;
if (!ExtractOptUInt32(&args, limit, 100))
return false;
///- Get the list of accounts ID logged to the realm
// 0 1 2 3 4
QueryResult *result = LoginDatabase.PQuery("SELECT id, username, last_ip, gmlevel, expansion FROM account WHERE current_realm = %u LIMIT %u", realmID, limit);
uint32 count = 0;
AccountSearchHandler::ShowAccountListHelper(result, *this, count, limit, true);
if (result)
delete result;
return true;
}
bool ChatHandler::HandleAccountLockCommand(char* args)
{
// allow use from RA, but not from console (not have associated account id)
if (!GetAccountId())
{
SendSysMessage(LANG_RA_ONLY_COMMAND);
SetSentErrorMessage(true);
return false;
}
bool value;
if (!ExtractOnOff(&args, value))
{
SendSysMessage(LANG_USE_BOL);
SetSentErrorMessage(true);
return false;
}
if (value)
{
LoginDatabase.PExecute("UPDATE account SET locked = '1' WHERE id = '%u'", GetAccountId());
PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED);
}
else
{
LoginDatabase.PExecute("UPDATE account SET locked = '0' WHERE id = '%u'", GetAccountId());
PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED);
}
return true;
}
bool ChatHandler::HandleAccountPasswordCommand(char* args)
{
// allow use from RA, but not from console (not have associated account id)
if (!GetAccountId())
{
SendSysMessage(LANG_RA_ONLY_COMMAND);
SetSentErrorMessage(true);
return false;
}
// allow or quoted string with possible spaces or literal without spaces
char *old_pass = ExtractQuotedOrLiteralArg(&args);
char *new_pass = ExtractQuotedOrLiteralArg(&args);
char *new_pass_c = ExtractQuotedOrLiteralArg(&args);
if (!old_pass || !new_pass || !new_pass_c)
return false;
std::string password_old = old_pass;
std::string password_new = new_pass;
std::string password_new_c = new_pass_c;
if (password_new != password_new_c)
{
SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH);
SetSentErrorMessage(true);
return false;
}
if (!sAccountMgr.CheckPassword(GetAccountId(), password_old, m_session->GetUsername()))
{
SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD);
SetSentErrorMessage(true);
return false;
}
AccountOpResult result = sAccountMgr.ChangePassword(GetAccountId(), password_new, m_session->GetUsername());
switch (result)
{
case AOR_OK:
SendSysMessage(LANG_COMMAND_PASSWORD);
break;
case AOR_PASS_TOO_LONG:
SendSysMessage(LANG_PASSWORD_TOO_LONG);
SetSentErrorMessage(true);
return false;
case AOR_NAME_NOT_EXIST: // not possible case, don't want get account name for output
default:
SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD);
SetSentErrorMessage(true);
return false;
}
SetSentErrorMessage(true);
return false;
}
bool ChatHandler::HandleAddCharacterNoteCommand(char* args)
{
ObjectGuid playerGuid;
if (!ExtractPlayerTarget(&args, NULL, &playerGuid))
{
PSendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
PlayerCacheData const* playerData = sObjectMgr.GetPlayerDataByGUID(playerGuid.GetCounter());
if (!playerData)
{
PSendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
std::string authorName = m_session ? m_session->GetPlayerName() : "Console";
char* reason = ExtractQuotedOrLiteralArg(&args);
if (!reason)
reason = "<no reason given>";
sWorld.WarnAccount(playerData->uiAccount, authorName, reason, "NOTE");
PSendSysMessage("Account #%u (character %s): a note has been added \"%s\"", playerData->uiAccount, playerData->sName.c_str(), reason);
return true;
}
bool ChatHandler::HandleWarnCharacterCommand(char* args)
{
ObjectGuid playerGuid;
if (!ExtractPlayerTarget(&args, NULL, &playerGuid))
{
PSendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
PlayerCacheData const* playerData = sObjectMgr.GetPlayerDataByGUID(playerGuid.GetCounter());
if (!playerData)
{
PSendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
std::string authorName = m_session ? m_session->GetPlayerName() : "Console";
char* reason = ExtractQuotedOrLiteralArg(&args);
if (!reason)
reason = "<no reason given>";
sWorld.WarnAccount(playerData->uiAccount, authorName, reason, "WARN");
PSendSysMessage("Account #%u (character %s) has been warned for \"%s\"", playerData->uiAccount, playerData->sName.c_str(), reason);
return true;
}
bool ChatHandler::HandleKickPlayerCommand(char *args)
{
Player* target;
if (!ExtractPlayerTarget(&args, &target))
return false;
if (m_session && target == m_session->GetPlayer())
{
SendSysMessage(LANG_COMMAND_KICKSELF);
SetSentErrorMessage(true);
return false;
}
// check online security
if (HasLowerSecurity(target))
return false;
// send before target pointer invalidate
PSendSysMessage(LANG_COMMAND_KICKMESSAGE, GetNameLink(target).c_str());
// First kick: close socket but keep player online
if (target->GetSession()->IsConnected())
target->GetSession()->KickPlayer();
else
target->GetSession()->KickDisconnectedFromWorld();
return true;
}
bool ChatHandler::HandleBanAccountCommand(char* args)
{
return HandleBanHelper(BAN_ACCOUNT, args);
}
bool ChatHandler::HandleBanCharacterCommand(char* args)
{
return HandleBanHelper(BAN_CHARACTER, args);
}
bool ChatHandler::HandleBanIPCommand(char* args)
{
return HandleBanHelper(BAN_IP, args);
}
bool ChatHandler::HandleBanAllIPCommand(char* args)
{
char* ipStr = ExtractQuotedOrLiteralArg(&args);
if (!ipStr)
return false;
char* reason = ExtractQuotedOrLiteralArg(&args);
if (!reason)
reason = "<no reason given>";
uint32 maxLevel = 10;
uint32 minId = GetAccessLevel() < SEC_ADMINISTRATOR ? 100 : 0; // Don't show GM accounts
std::string ip = ipStr;
LoginDatabase.escape_string(ip);
QueryResult* result = LoginDatabase.PQuery("SELECT id, username FROM account WHERE id >= %u AND last_ip " _LIKE_ " " _CONCAT2_("'%s'", "'%%'"), minId, ip.c_str());
if (!result)
{
PSendSysMessage("No account found on IP '%s'", ip.c_str());
SetSentErrorMessage(true);
return false;
}
std::set<uint32> accountsToBan;
std::map<uint32, std::string> accountsIdToName;
std::stringstream allAccounts;
do
{
Field* fields = result->Fetch();
if (allAccounts.str() != "")
allAccounts << ",";
allAccounts << fields[0].GetUInt32();
accountsToBan.insert(fields[0].GetUInt32());
accountsIdToName[fields[0].GetUInt32()] = fields[1].GetCppString();
} while (result->NextRow());
delete result;
if (result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE account IN (%s) AND level > %u GROUP BY account", allAccounts.str().c_str(), maxLevel))
{
do
{
Field* fields = result->Fetch();
accountsToBan.erase(fields[0].GetUInt32());
} while (result->NextRow());
delete result;
}
uint32 bannedCount = 0;
for (std::set<uint32>::const_iterator it = accountsToBan.begin(); it != accountsToBan.end(); ++it)
{
if (sAccountMgr.IsAccountBanned(*it))
continue;
sWorld.BanAccount(BAN_ACCOUNT, accountsIdToName[*it], 0, reason, m_session ? m_session->GetPlayerName() : "");
PSendSysMessage("Account '%s' permanently banned.", accountsIdToName[*it].c_str(), reason);
++bannedCount;
}
PSendSysMessage("%u accounts banned for %s (%u on this IP)", bannedCount, reason, accountsIdToName.size());
return true;
}
bool ChatHandler::HandleBanHelper(BanMode mode, char* args)
{
if (!*args)
return false;
char* cnameOrIP = ExtractArg(&args);
if (!cnameOrIP)
return false;
std::string nameOrIP = cnameOrIP;
char* duration = ExtractArg(&args); // time string
if (!duration)
return false;
uint32 duration_secs = TimeStringToSecs(duration);
char* cReason = ExtractArg(&args);
if (!cReason)
return false;
std::string reason(cReason);
switch (mode)
{
case BAN_ACCOUNT:
if (!AccountMgr::normalizeString(nameOrIP))
{
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, nameOrIP.c_str());
SetSentErrorMessage(true);
return false;
}
break;
case BAN_CHARACTER:
if (!normalizePlayerName(nameOrIP))
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
break;
case BAN_IP:
if (!IsIPAddress(nameOrIP.c_str()))
return false;
break;
}
sWorld.BanAccount(mode, nameOrIP, duration_secs, reason, m_session ? m_session->GetPlayerName() : "");
return true;
}
void ChatHandler::SendBanResult(BanMode mode, BanReturn result, std::string& banTarget, uint32 duration_secs, std::string& reason)
{
switch (result)
{
case BAN_SUCCESS:
if (duration_secs > 0)
PSendSysMessage(LANG_BAN_YOUBANNED, banTarget.c_str(), secsToTimeString(duration_secs, true).c_str(), reason.c_str());
else
PSendSysMessage(LANG_BAN_YOUPERMBANNED, banTarget.c_str(), reason.c_str());
break;
case BAN_SYNTAX_ERROR:
return;
case BAN_NOTFOUND:
switch (mode)
{
default:
PSendSysMessage(LANG_BAN_NOTFOUND, "account", banTarget.c_str());
break;
case BAN_CHARACTER:
PSendSysMessage(LANG_BAN_NOTFOUND, "character", banTarget.c_str());
break;
case BAN_IP:
PSendSysMessage(LANG_BAN_NOTFOUND, "ip", banTarget.c_str());
break;
}
SetSentErrorMessage(true);
return;
}
}
bool ChatHandler::HandleUnBanAccountCommand(char* args)
{
return HandleUnBanHelper(BAN_ACCOUNT, args);
}
bool ChatHandler::HandleUnBanCharacterCommand(char* args)
{
return HandleUnBanHelper(BAN_CHARACTER, args);
}
bool ChatHandler::HandleUnBanIPCommand(char* args)
{
return HandleUnBanHelper(BAN_IP, args);
}
bool ChatHandler::HandleUnBanHelper(BanMode mode, char* args)
{
if (!*args)
return false;
char* cnameOrIP = ExtractArg(&args);
if (!cnameOrIP)
return false;
std::string nameOrIP = cnameOrIP;
char* message = ExtractQuotedOrLiteralArg(&args);
if (!message)
return false;
std::string unbanMessage(message);
switch (mode)
{
case BAN_ACCOUNT:
if (!AccountMgr::normalizeString(nameOrIP))
{
PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, nameOrIP.c_str());
SetSentErrorMessage(true);
return false;
}
break;
case BAN_CHARACTER:
if (!normalizePlayerName(nameOrIP))
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
SetSentErrorMessage(true);
return false;
}
break;
case BAN_IP:
if (!IsIPAddress(nameOrIP.c_str()))
return false;
break;
}
std::string source = m_session ? m_session->GetPlayerName() : "CONSOLE";
if (sWorld.RemoveBanAccount(mode, source, unbanMessage, nameOrIP))
PSendSysMessage(LANG_UNBAN_UNBANNED, nameOrIP.c_str(), unbanMessage.c_str());
else
PSendSysMessage(LANG_UNBAN_ERROR, nameOrIP.c_str());
return true;
}
bool ChatHandler::HandleBanInfoAccountCommand(char* args)
{
if (!*args)
return false;
std::string account_name;
uint32 accountid = ExtractAccountId(&args, &account_name);
if (!accountid)
return false;
return HandleBanInfoHelper(accountid, account_name.c_str());
}
bool ChatHandler::HandleBanInfoCharacterCommand(char* args)
{
Player* target;
ObjectGuid target_guid;
if (!ExtractPlayerTarget(&args, &target, &target_guid,NULL,true))
return false;
uint32 accountid = target ? target->GetSession()->GetAccountId() : sObjectMgr.GetPlayerAccountIdByGUID(target_guid);
std::string accountname;
if (!sAccountMgr.GetName(accountid, accountname))
{
PSendSysMessage(LANG_BANINFO_NOCHARACTER);
return true;
}
return HandleBanInfoHelper(accountid, accountname.c_str());
}
bool ChatHandler::HandleBanInfoHelper(uint32 accountid, char const* accountname)
{
QueryResult *result = LoginDatabase.PQuery(
"SELECT FROM_UNIXTIME(bandate), unbandate-bandate, active, unbandate,banreason,bannedby,COALESCE(name, \"NoRealm\") , gmlevel "
"FROM account_banned LEFT JOIN realmlist ON realmlist.id = realm "
"WHERE account_banned.id = '%u' ORDER BY bandate ASC", accountid);
if (!result)
{
PSendSysMessage(LANG_BANINFO_NOACCOUNTBAN, accountname);
return true;
}
PSendSysMessage(LANG_BANINFO_BANHISTORY, accountname);
do
{
Field* fields = result->Fetch();
time_t unbandate = time_t(fields[3].GetUInt64());
bool active = false;
if (fields[2].GetBool() && (fields[1].GetUInt64() == (uint64)0 || unbandate >= time(NULL)))
active = true;
bool permanent = (fields[1].GetUInt64() == (uint64)0);
uint32 reqGmLevel = fields[6].GetUInt8();
std::string banreason = fields[4].GetString();
if (reqGmLevel > uint8(GetAccessLevel()))
banreason = "<hidden>";
std::string authorName = fields[5].GetCppString() + " (" + fields[6].GetCppString() + ")";
std::string bantime = permanent ? GetMangosString(LANG_BANINFO_INFINITE) : secsToTimeString(fields[1].GetUInt64(), true);
PSendSysMessage(LANG_BANINFO_HISTORYENTRY,
fields[0].GetString(), bantime.c_str(), active ? GetMangosString(LANG_BANINFO_YES) : GetMangosString(LANG_BANINFO_NO), banreason.c_str(), authorName.c_str());
}
while (result->NextRow());
delete result;
return true;
}
bool ChatHandler::HandleBanInfoIPCommand(char* args)
{
if (!*args)
return false;
char* cIP = ExtractQuotedOrLiteralArg(&args);
if (!cIP)
return false;
if (!IsIPAddress(cIP))
return false;
std::string IP = cIP;
LoginDatabase.escape_string(IP);
QueryResult *result = LoginDatabase.PQuery("SELECT ip, FROM_UNIXTIME(bandate), FROM_UNIXTIME(unbandate), unbandate-UNIX_TIMESTAMP(), banreason,bannedby,unbandate-bandate FROM ip_banned WHERE ip = '%s'", IP.c_str());
if (!result)
{
PSendSysMessage(LANG_BANINFO_NOIP);
return true;
}
Field *fields = result->Fetch();
bool permanent = !fields[6].GetUInt64();
PSendSysMessage(LANG_BANINFO_IPENTRY,
fields[0].GetString(), fields[1].GetString(), permanent ? GetMangosString(LANG_BANINFO_NEVER) : fields[2].GetString(),
permanent ? GetMangosString(LANG_BANINFO_INFINITE) : secsToTimeString(fields[3].GetUInt64(), true).c_str(), fields[4].GetString(), fields[5].GetString());
delete result;
return true;
}
bool ChatHandler::HandleBanListCharacterCommand(char* args)
{
LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
char* cFilter = ExtractLiteralArg(&args);
if (!cFilter)
return false;
std::string filter = cFilter;
CharacterDatabase.escape_string(filter);
QueryResult* result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name " _LIKE_ " " _CONCAT2_("'%s'", "'%%'"), filter.c_str());
if (!result)
{
PSendSysMessage(LANG_BANLIST_NOCHARACTER);
return true;
}
return HandleBanListHelper(result);
}
bool ChatHandler::HandleBanListAccountCommand(char* args)
{
LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
char* cFilter = ExtractLiteralArg(&args);
std::string filter = cFilter ? cFilter : "";
LoginDatabase.escape_string(filter);
QueryResult* result;
if (filter.empty())
{
result = LoginDatabase.Query("SELECT account.id, username FROM account, account_banned"
" WHERE account.id = account_banned.id AND active = 1 GROUP BY account.id");
}
else
{
result = LoginDatabase.PQuery("SELECT account.id, username FROM account, account_banned"
" WHERE account.id = account_banned.id AND active = 1 AND username " _LIKE_ " " _CONCAT2_("'%s'", "'%%'") " GROUP BY account.id",
filter.c_str());
}
if (!result)
{
PSendSysMessage(LANG_BANLIST_NOACCOUNT);
return true;
}
return HandleBanListHelper(result);
}
bool ChatHandler::HandleBanListHelper(QueryResult* result)
{
PSendSysMessage(LANG_BANLIST_MATCHINGACCOUNT);
// Chat short output
if (m_session)
{
do
{
Field* fields = result->Fetch();
uint32 accountid = fields[0].GetUInt32();
QueryResult* banresult = LoginDatabase.PQuery("SELECT account.username FROM account,account_banned WHERE account_banned.id='%u' AND account_banned.id=account.id", accountid);
if (banresult)
{
Field* fields2 = banresult->Fetch();
PSendSysMessage("%s", fields2[0].GetString());
delete banresult;
}
}
while (result->NextRow());
}
// Console wide output
else
{
SendSysMessage(LANG_BANLIST_ACCOUNTS);
SendSysMessage("===============================================================================");
SendSysMessage(LANG_BANLIST_ACCOUNTS_HEADER);
do
{
SendSysMessage("-------------------------------------------------------------------------------");
Field *fields = result->Fetch();
uint32 account_id = fields[0].GetUInt32();
std::string account_name;
// "account" case, name can be get in same query
if (result->GetFieldCount() > 1)
account_name = fields[1].GetCppString();
// "character" case, name need extract from another DB
else
sAccountMgr.GetName(account_id, account_name);
// No SQL injection. id is uint32.
QueryResult *banInfo = LoginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u ORDER BY unbandate", account_id);
if (banInfo)
{
Field *fields2 = banInfo->Fetch();
do
{
time_t t_ban = fields2[0].GetUInt64();
tm* aTm_ban = localtime(&t_ban);
if (fields2[0].GetUInt64() == fields2[1].GetUInt64())
{
PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|",
account_name.c_str(), aTm_ban->tm_year % 100, aTm_ban->tm_mon + 1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min,
fields2[2].GetString(), fields2[3].GetString());
}
else
{
time_t t_unban = fields2[1].GetUInt64();
tm* aTm_unban = localtime(&t_unban);
PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|",
account_name.c_str(), aTm_ban->tm_year % 100, aTm_ban->tm_mon + 1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min,
aTm_unban->tm_year % 100, aTm_unban->tm_mon + 1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min,
fields2[2].GetString(), fields2[3].GetString());
}
}
while (banInfo->NextRow());
delete banInfo;
}
}
while (result->NextRow());
SendSysMessage("===============================================================================");
}
delete result;
return true;
}
bool ChatHandler::HandleBanListIPCommand(char* args)
{
LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
char* cFilter = ExtractLiteralArg(&args);
std::string filter = cFilter ? cFilter : "";
LoginDatabase.escape_string(filter);
QueryResult* result;
if (filter.empty())
{
result = LoginDatabase.Query("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
" WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP())"
" ORDER BY unbandate");
}
else
{
result = LoginDatabase.PQuery("SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned"
" WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP()) AND ip " _LIKE_ " " _CONCAT2_("'%s'", "'%%'")
" ORDER BY unbandate", filter.c_str());
}
if (!result)
{
PSendSysMessage(LANG_BANLIST_NOIP);
return true;
}
PSendSysMessage(LANG_BANLIST_MATCHINGIP);
// Chat short output
if (m_session)
{
do
{
Field* fields = result->Fetch();
PSendSysMessage("%s", fields[0].GetString());
}
while (result->NextRow());
}
// Console wide output
else
{
SendSysMessage(LANG_BANLIST_IPS);
SendSysMessage("===============================================================================");
SendSysMessage(LANG_BANLIST_IPS_HEADER);
do
{
SendSysMessage("-------------------------------------------------------------------------------");
Field *fields = result->Fetch();
time_t t_ban = fields[1].GetUInt64();
tm* aTm_ban = localtime(&t_ban);
if (fields[1].GetUInt64() == fields[2].GetUInt64())
{
PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d| permanent |%-15.15s|%-15.15s|",
fields[0].GetString(), aTm_ban->tm_year % 100, aTm_ban->tm_mon + 1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min,
fields[3].GetString(), fields[4].GetString());
}
else
{
time_t t_unban = fields[2].GetUInt64();
tm* aTm_unban = localtime(&t_unban);
PSendSysMessage("|%-15.15s|%02d-%02d-%02d %02d:%02d|%02d-%02d-%02d %02d:%02d|%-15.15s|%-15.15s|",
fields[0].GetString(), aTm_ban->tm_year % 100, aTm_ban->tm_mon + 1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min,
aTm_unban->tm_year % 100, aTm_unban->tm_mon + 1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min,
fields[3].GetString(), fields[4].GetString());
}
}
while (result->NextRow());
SendSysMessage("===============================================================================");
}
delete result;
return true;
}
bool ChatHandler::HandleAnticheatCommand(char* args)
{
Player* player = NULL;
if (!ExtractPlayerTarget(&args, &player) && m_session)
player = m_session->GetPlayer();
if (!player)
return false;
PSendSysMessage("Cheat report on player '%s' (GUID %u)", player->GetName(), player->GetGUIDLow());
if (player->GetCheatData())
player->GetCheatData()->HandleCommand(this);
return true;
}
bool ChatHandler::HandleListAddonsCommand(char* args)
{
Player* player = GetSelectedPlayer();
if (!player)
return false;
std::set<std::string> const& addons = player->GetSession()->GetAddons();
PSendSysMessage("%u addons on target.", addons.size());
for (std::set<std::string>::const_iterator it = addons.begin(); it != addons.end(); ++it)
PSendSysMessage(">> %s", it->c_str());
return true;
}
bool ChatHandler::HandleClientInfosCommand(char* args)
{
Player* player = NULL;
if (!ExtractPlayerTarget(&args, &player) && m_session)
player = m_session->GetPlayer();
if (!player)
return false;
PSendSysMessage("Account %s has %u client identifiers.", player->GetSession()->GetUsername().c_str(), player->GetSession()->GetClientIdentifiers().size());
for (ClientIdentifiersMap::const_iterator it = player->GetSession()->GetClientIdentifiers().begin(); it != player->GetSession()->GetClientIdentifiers().end(); ++it)
PSendSysMessage("%u: %s", it->first, it->second.c_str());
player->GetSession()->ComputeClientHash();
PSendSysMessage("Hash is %s", playerLink(player->GetSession()->GetClientHash()).c_str());
return true;
}
bool ChatHandler::HandleClientSearchCommand(char* args)
{
ASSERT(args);
std::string searchedHash = args;
uint32 i = 0;
World::SessionMap const& sessMap = sWorld.GetAllSessions();
for (World::SessionMap::const_iterator itr = sessMap.begin(); itr != sessMap.end(); ++itr)
{
if (!itr->second)
continue;
std::string currentHash = itr->second->GetClientHash();
if (currentHash.find(searchedHash) != std::string::npos)
{
PSendSysMessage("%s on account %s, %s",
playerLink(itr->second->GetPlayerName()).c_str(),
playerLink(itr->second->GetUsername()).c_str(),
playerLink(itr->second->GetRemoteAddress()).c_str());
++i;
}
}
if (i == 0)
PSendSysMessage("Not result for hash %s", playerLink(searchedHash).c_str());
else
PSendSysMessage("%u result(s) for %s", i, playerLink(searchedHash).c_str());
return true;
}
bool ChatHandler::HandleSpamerMute(char* args)
{
if (!*args)
return false;
char* cname = ExtractArg(&args);
if (!cname)
return false;
if (Player* player = ObjectAccessor::FindPlayerByName(cname))
{
if (AntispamInterface *a = sAnticheatLib->GetAntispam())
{
a->mute(player->GetSession()->GetAccountId());
PSendSysMessage("Spamer %s was muted", cname);
}
}
return true;
}
bool ChatHandler::HandleSpamerUnmute(char* args)
{
if (!*args)
return false;
char* cname = ExtractArg(&args);
if (!cname)
return false;
if (Player* player = ObjectAccessor::FindPlayerByName(cname))
{
if (AntispamInterface *a = sAnticheatLib->GetAntispam())
{
a->unmute(player->GetSession()->GetAccountId());
PSendSysMessage("Spamer %s was unmuted", cname);
}
}
return true;
}
bool ChatHandler::HandleSpamerList(char* args)
{
if (AntispamInterface *a = sAnticheatLib->GetAntispam())
a->showMuted(GetSession());
return true;
}
//mute player for some times
bool ChatHandler::HandleMuteCommand(char* args)
{
char* nameStr = ExtractOptNotLastArg(&args);
Player* target;
ObjectGuid target_guid;
std::string target_name;
if (!ExtractPlayerTarget(&nameStr, &target, &target_guid, &target_name))
return false;
uint32 notspeaktime;
if (!ExtractUInt32(&args, notspeaktime))
return false;
std::string givenReason;
if (char* givenReasonC = ExtractQuotedOrLiteralArg(&args))
givenReason = givenReasonC;
uint32 account_id = target ? target->GetSession()->GetAccountId() : sObjectMgr.GetPlayerAccountIdByGUID(target_guid);
// find only player from same account if any
if (!target)
{
if (WorldSession* session = sWorld.FindSession(account_id))
target = session->GetPlayer();
}
// must have strong lesser security level
if (HasLowerSecurity(target, target_guid, true))
return false;
time_t mutetime = time(NULL) + notspeaktime * MINUTE;
if (target)
target->GetSession()->m_muteTime = mutetime;
LoginDatabase.PExecute("UPDATE account SET mutetime = " UI64FMTD " WHERE id = '%u'", uint64(mutetime), account_id);
if (target)
{
if (SpellAuraHolder* pAura = target->AddAura(SPELL_PLAYER_MUTED_VISUAL, 0, nullptr))
{
pAura->SetAuraDuration(notspeaktime * MINUTE * IN_MILLISECONDS);
pAura->SetAuraMaxDuration(notspeaktime * MINUTE * IN_MILLISECONDS);
pAura->RefreshHolder();
}
ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime);
}
std::string nameLink = playerLink(target_name);
PSendSysMessage(LANG_YOU_DISABLE_CHAT, nameLink.c_str(), notspeaktime);
// Add warning to the account
std::string authorName = m_session ? m_session->GetPlayerName() : "Console";
PlayerCacheData const* playerData = sObjectMgr.GetPlayerDataByGUID(target_guid);
ASSERT(playerData);
std::stringstream reason;
reason << playerData->sName << " muted " << notspeaktime << " minutes";
if (givenReason != "")
reason << " for \"" << givenReason << "\"";
sWorld.WarnAccount(playerData->uiAccount, authorName, reason.str(), "WARNING");
return true;
}
//unmute player
bool ChatHandler::HandleUnmuteCommand(char* args)
{
Player* target;
ObjectGuid target_guid;
std::string target_name;
if (!ExtractPlayerTarget(&args, &target, &target_guid, &target_name))
return false;
uint32 account_id = target ? target->GetSession()->GetAccountId() : sObjectMgr.GetPlayerAccountIdByGUID(target_guid);
// find only player from same account if any
if (!target)
{
if (WorldSession* session = sWorld.FindSession(account_id))
target = session->GetPlayer();
}
// must have strong lesser security level
if (HasLowerSecurity(target, target_guid, true))
return false;
if (target)
{
if (target->CanSpeak())
{
SendSysMessage(LANG_CHAT_ALREADY_ENABLED);
SetSentErrorMessage(true);
return false;
}
target->GetSession()->m_muteTime = 0;
}
LoginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id);
if (target)
{
target->RemoveAurasDueToSpell(SPELL_PLAYER_MUTED_VISUAL);
ChatHandler(target).PSendSysMessage(LANG_YOUR_CHAT_ENABLED);
}
std::string nameLink = playerLink(target_name);
PSendSysMessage(LANG_YOU_ENABLE_CHAT, nameLink.c_str());
return true;
}