text: /*
   * Copyright (C) 2005 - 2012 MaNGOS <http://www.getmangos.com/>
   *
   * Copyright (C) 2008 - 2012 Trinity <http://www.trinitycore.org/>
   *
   * Copyright (C) 2006 - 2012 ScriptDev2 <http://www.scriptdev2.com/>
   *
   * Copyright (C) 2010 - 2012 ProjectSkyfire <http://www.projectskyfire.org/>
   *
   * Copyright (C) 2011 - 2012 ArkCORE <http://www.arkania.net/>
   *
   * 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
   */
  
  /* ScriptData
   Name: account_commandscript
   %Complete: 100
   Comment: All account related commands
   Category: commandscripts
   EndScriptData */
  
  #include "ScriptMgr.h"
  #include "AccountMgr.h"
  #include "Chat.h"
  
  class account_commandscript: public CommandScript
  {
  public:
      account_commandscript () :
              CommandScript("account_commandscript")
      {
      }
  
      ChatCommand* GetCommands () const
      {
          static ChatCommand accountSetCommandTable[] =
          {
          { "addon", SEC_ADMINISTRATOR, true, &HandleAccountSetAddonCommand, "", NULL },
          { "gmlevel", SEC_CONSOLE, true, &HandleAccountSetGmLevelCommand, "", NULL },
          { "password", SEC_CONSOLE, true, &HandleAccountSetPasswordCommand, "", NULL },
          { NULL, 0, false, NULL, "", NULL } };
          static ChatCommand accountCommandTable[] =
          {
          { "addon", SEC_ADMINISTRATOR, false, &HandleAccountAddonCommand, "", NULL },
          { "create", SEC_CONSOLE, true, &HandleAccountCreateCommand, "", NULL },
          { "delete", SEC_CONSOLE, true, &HandleAccountDeleteCommand, "", NULL },
          { "onlinelist", SEC_CONSOLE, true, &HandleAccountOnlineListCommand, "", NULL },
          { "lock", SEC_PLAYER, false, &HandleAccountLockCommand, "", NULL },
          { "set", SEC_ADMINISTRATOR, true, NULL, "", accountSetCommandTable },
          { "password", SEC_PLAYER, false, &HandleAccountPasswordCommand, "", NULL },
          { "", SEC_PLAYER, false, &HandleAccountCommand, "", NULL },
          { NULL, 0, false, NULL, "", NULL } };
          static ChatCommand commandTable[] =
          {
          { "account", SEC_PLAYER, true, NULL, "", accountCommandTable },
          { NULL, 0, false, NULL, "", NULL } };
          return commandTable;
      }
  
      static bool HandleAccountAddonCommand (ChatHandler* handler, const char* args)
      {
          if (!*args)
          {
              handler->SendSysMessage(LANG_CMD_SYNTAX);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          char *szExp = strtok((char*) args, " ");
  
          uint32 account_id = handler->GetSession()->GetAccountId();
  
          int expansion = atoi(szExp);          //get int anyway (0 if error)
          if (expansion < 0 || uint8(expansion) > sWorld->getIntConfig(CONFIG_EXPANSION))
          {
              handler->SendSysMessage(LANG_IMPROPER_VALUE);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          // No SQL injection
          LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'", expansion, account_id);
          handler->PSendSysMessage(LANG_ACCOUNT_ADDON, expansion);
          return true;
      }
  
      /// Create an account
      static bool HandleAccountCreateCommand (ChatHandler* handler, const char* args)
      {
          if (!*args)
              return false;
  
          ///- %Parse the command line arguments
          char *szAcc = strtok((char*) args, " ");
          char *szPassword = strtok(NULL, " ");
          if (!szAcc || !szPassword)
              return false;
  
          // normalized in sAccountMgr->CreateAccount
          std::string account_name = szAcc;
          std::string password = szPassword;
  
          AccountOpResult result = sAccountMgr->CreateAccount(account_name, password);
          switch (result)
          {
          case AOR_OK:
              handler->PSendSysMessage(LANG_ACCOUNT_CREATED, account_name.c_str());
              break;
          case AOR_NAME_TOO_LONG:
              handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG);
              handler->SetSentErrorMessage(true);
              return false;
          case AOR_NAME_ALREDY_EXIST:
              handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST);
              handler->SetSentErrorMessage(true);
              return false;
          case AOR_DB_INTERNAL_ERROR:
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, account_name.c_str());
              handler->SetSentErrorMessage(true);
              return false;
          default:
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, account_name.c_str());
              handler->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
      static bool HandleAccountDeleteCommand (ChatHandler* handler, const char* args)
      {
          if (!*args)
              return false;
  
          ///- Get the account name from the command line
          char *account_name_str = strtok((char*) args, " ");
          if (!account_name_str)
              return false;
  
          std::string account_name = account_name_str;
          if (!AccountMgr::normalizeString(account_name))
          {
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          uint32 account_id = sAccountMgr->GetId(account_name);
          if (!account_id)
          {
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
              handler->SetSentErrorMessage(true);
              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 (handler->HasLowerSecurityAccount(NULL, account_id, true))
              return false;
  
          AccountOpResult result = sAccountMgr->DeleteAccount(account_id);
          switch (result)
          {
          case AOR_OK:
              handler->PSendSysMessage(LANG_ACCOUNT_DELETED, account_name.c_str());
              break;
          case AOR_NAME_NOT_EXIST:
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
              handler->SetSentErrorMessage(true);
              return false;
          case AOR_DB_INTERNAL_ERROR:
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_DELETED_SQL_ERROR, account_name.c_str());
              handler->SetSentErrorMessage(true);
              return false;
          default:
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_DELETED, account_name.c_str());
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          return true;
      }
  
      /// Display info on users currently in the realm
      static bool HandleAccountOnlineListCommand (ChatHandler* handler, const char* /*args*/)
      {
          ///- Get the list of accounts ID logged to the realm
          QueryResult resultDB = CharacterDatabase.Query("SELECT name, account, map, zone FROM characters WHERE online > 0");
          if (!resultDB)
          {
              handler->SendSysMessage(LANG_ACCOUNT_LIST_EMPTY);
              return true;
          }
  
          ///- Display the list of account/characters online
          handler->SendSysMessage(LANG_ACCOUNT_LIST_BAR_HEADER);
          handler->SendSysMessage(LANG_ACCOUNT_LIST_HEADER);
          handler->SendSysMessage(LANG_ACCOUNT_LIST_BAR);
  
          ///- Cycle through accounts
          do
          {
              Field *fieldsDB = resultDB->Fetch();
              std::string name = fieldsDB[0].GetString();
              uint32 account = fieldsDB[1].GetUInt32();
  
              ///- Get the username, last IP and GM level of each account
              // No SQL injection. account is uint32.
              QueryResult resultLogin = LoginDatabase.PQuery("SELECT a.username, a.last_ip, aa.gmlevel, a.expansion "
                      "FROM account a "
                      "LEFT JOIN account_access aa "
                      "ON (a.id = aa.id) "
                      "WHERE a.id = '%u'", account);
              if (resultLogin)
              {
                  Field *fieldsLogin = resultLogin->Fetch();
                  handler->PSendSysMessage(LANG_ACCOUNT_LIST_LINE, fieldsLogin[0].GetCString(), name.c_str(), fieldsLogin[1].GetCString(), fieldsDB[2].GetUInt16(), fieldsDB[3].GetUInt16(), fieldsLogin[3].GetUInt32(), fieldsLogin[2].GetUInt32());
              }
              else
                  handler->PSendSysMessage(LANG_ACCOUNT_LIST_ERROR, name.c_str());
          }
          while (resultDB->NextRow());
  
          handler->SendSysMessage(LANG_ACCOUNT_LIST_BAR);
          return true;
      }
  
      static bool HandleAccountLockCommand (ChatHandler* handler, const char* args)
      {
          if (!*args)
          {
              handler->SendSysMessage(LANG_USE_BOL);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          std::string argstr = (char*) args;
          if (argstr == "on")
          {
              LoginDatabase.PExecute("UPDATE account SET locked = '1' WHERE id = '%d'", handler->GetSession()->GetAccountId());
              handler->PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED);
              return true;
          }
  
          if (argstr == "off")
          {
              LoginDatabase.PExecute("UPDATE account SET locked = '0' WHERE id = '%d'", handler->GetSession()->GetAccountId());
              handler->PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED);
              return true;
          }
  
          handler->SendSysMessage(LANG_USE_BOL);
          handler->SetSentErrorMessage(true);
          return false;
      }
  
      static bool HandleAccountPasswordCommand (ChatHandler* handler, const char* args)
      {
          if (!*args)
          {
              handler->SendSysMessage(LANG_CMD_SYNTAX);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          char *old_pass = strtok((char*) args, " ");
          char *new_pass = strtok(NULL, " ");
          char *new_pass_c = strtok(NULL, " ");
  
          if (!old_pass || !new_pass || !new_pass_c)
          {
              handler->SendSysMessage(LANG_CMD_SYNTAX);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          std::string password_old = old_pass;
          std::string password_new = new_pass;
          std::string password_new_c = new_pass_c;
  
          if (!sAccountMgr->CheckPassword(handler->GetSession()->GetAccountId(), password_old))
          {
              handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          if (strcmp(new_pass, new_pass_c) != 0)
          {
              handler->SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          AccountOpResult result = sAccountMgr->ChangePassword(handler->GetSession()->GetAccountId(), password_new);
          switch (result)
          {
          case AOR_OK:
              handler->SendSysMessage(LANG_COMMAND_PASSWORD);
              break;
          case AOR_PASS_TOO_LONG:
              handler->SendSysMessage(LANG_PASSWORD_TOO_LONG);
              handler->SetSentErrorMessage(true);
              return false;
          default:
              handler->SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          return true;
      }
  
      static bool HandleAccountCommand (ChatHandler* handler, const char* /*args*/)
      {
          AccountTypes gmlevel = handler->GetSession()->GetSecurity();
          handler->PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmlevel));
          return true;
      }
  
      /// Set/Unset the expansion level for an account
      static bool HandleAccountSetAddonCommand (ChatHandler* handler, const char *args)
      {
          ///- Get the command line arguments
          char *szAcc = strtok((char*) args, " ");
          char *szExp = strtok(NULL, " ");
  
          if (!szAcc)
              return false;
  
          std::string account_name;
          uint32 account_id;
  
          if (!szExp)
          {
              Player* player = handler->getSelectedPlayer();
              if (!player)
                  return false;
  
              account_id = player->GetSession()->GetAccountId();
              sAccountMgr->GetName(account_id, account_name);
              szExp = szAcc;
          }
          else
          {
              ///- Convert Account name to Upper Format
              account_name = szAcc;
              if (!AccountMgr::normalizeString(account_name))
              {
                  handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
                  handler->SetSentErrorMessage(true);
                  return false;
              }
  
              account_id = sAccountMgr->GetId(account_name);
              if (!account_id)
              {
                  handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
                  handler->SetSentErrorMessage(true);
                  return false;
              }
          }
  
          // Let set addon state only for lesser (strong) security level
          // or to self account
          if (handler->GetSession() && handler->GetSession()->GetAccountId() != account_id && handler->HasLowerSecurityAccount(NULL, account_id, true))
              return false;
  
          int expansion = atoi(szExp);          //get int anyway (0 if error)
          if (expansion < 0 || uint8(expansion) > sWorld->getIntConfig(CONFIG_EXPANSION))
              return false;
  
          // No SQL injection
          LoginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE id = '%u'", expansion, account_id);
          handler->PSendSysMessage(LANG_ACCOUNT_SETADDON, account_name.c_str(), account_id, expansion);
          return true;
      }
  
      static bool HandleAccountSetGmLevelCommand (ChatHandler* handler, const char *args)
      {
          if (!*args)
              return false;
  
          std::string targetAccountName;
          uint32 targetAccountId = 0;
          uint32 targetSecurity = 0;
          uint32 gm = 0;
          char* arg1 = strtok((char*) args, " ");
          char* arg2 = strtok(NULL, " ");
          char* arg3 = strtok(NULL, " ");
          bool isAccountNameGiven = true;
  
          if (arg1 && !arg3)
          {
              if (!handler->getSelectedPlayer())
                  return false;
              isAccountNameGiven = false;
          }
  
          // Check for second parameter
          if (!isAccountNameGiven && !arg2)
              return false;
  
          // Check for account
          if (isAccountNameGiven)
          {
              targetAccountName = arg1;
              if (!AccountMgr::normalizeString(targetAccountName))
              {
                  handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, targetAccountName.c_str());
                  handler->SetSentErrorMessage(true);
                  return false;
              }
          }
  
          // Check for invalid specified GM level.
          gm = (isAccountNameGiven) ? atoi(arg2) : atoi(arg1);
          if (gm > SEC_CONSOLE)
          {
              handler->SendSysMessage(LANG_BAD_VALUE);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          // handler->getSession() == NULL only for console
          targetAccountId = (isAccountNameGiven) ? sAccountMgr->GetId(targetAccountName) : handler->getSelectedPlayer()->GetSession()->GetAccountId();
          int32 gmRealmID = (isAccountNameGiven) ? atoi(arg3) : atoi(arg2);
          uint32 plSecurity;
          if (handler->GetSession())
              plSecurity = sAccountMgr->GetSecurity(handler->GetSession()->GetAccountId(), gmRealmID);
          else
              plSecurity = SEC_CONSOLE;
  
          // 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
          targetSecurity = sAccountMgr->GetSecurity(targetAccountId, gmRealmID);
          if (targetSecurity >= plSecurity || gm >= plSecurity)
          {
              handler->SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          // Check and abort if the target gm has a higher rank on one of the realms and the new realm is -1
          if (gmRealmID == -1)
          {
              QueryResult result = LoginDatabase.PQuery("SELECT * FROM account_access WHERE id = '%u' AND gmlevel > '%d'", targetAccountId, gm);
              if (result)
              {
                  handler->SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
                  handler->SetSentErrorMessage(true);
                  return false;
              }
          }
  
          // Check if provided realmID has a negative value other than -1
          if (gmRealmID < -1)
          {
              handler->SendSysMessage(LANG_INVALID_REALMID);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          // If gmRealmID is -1, delete all values for the account id, else, insert values for the specific realmID
          if (gmRealmID == -1)
              LoginDatabase.PExecute("DELETE FROM account_access WHERE id = '%u'", targetAccountId);
          else
              LoginDatabase.PExecute("DELETE FROM account_access WHERE id = '%u' AND (RealmID = '%d' OR RealmID = '-1')", targetAccountId, realmID);
  
          if (gm != 0)
              LoginDatabase.PExecute("INSERT INTO account_access VALUES ('%u', '%d', '%d')", targetAccountId, gm, realmID);
          handler->PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm);
          return true;
      }
  
      /// Set password for account
      static bool HandleAccountSetPasswordCommand (ChatHandler* handler, const char *args)
      {
          if (!*args)
              return false;
  
          ///- Get the command line arguments
          char *szAccount = strtok((char*) args, " ");
          char *szPassword1 = strtok(NULL, " ");
          char *szPassword2 = strtok(NULL, " ");
  
          if (!szAccount || !szPassword1 || !szPassword2)
              return false;
  
          std::string account_name = szAccount;
          if (!AccountMgr::normalizeString(account_name))
          {
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          uint32 targetAccountId = sAccountMgr->GetId(account_name);
          if (!targetAccountId)
          {
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          /// can set password only for target with less security
          /// This is also reject self apply in fact
          if (handler->HasLowerSecurityAccount(NULL, targetAccountId, true))
              return false;
  
          if (strcmp(szPassword1, szPassword2))
          {
              handler->SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH);
              handler->SetSentErrorMessage(true);
              return false;
          }
  
          AccountOpResult result = sAccountMgr->ChangePassword(targetAccountId, szPassword1);
  
          switch (result)
          {
          case AOR_OK:
              handler->SendSysMessage(LANG_COMMAND_PASSWORD);
              break;
          case AOR_NAME_NOT_EXIST:
              handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, account_name.c_str());
              handler->SetSentErrorMessage(true);
              return false;
          case AOR_PASS_TOO_LONG:
              handler->SendSysMessage(LANG_PASSWORD_TOO_LONG);
              handler->SetSentErrorMessage(true);
              return false;
          default:
              handler->SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD);
              handler->SetSentErrorMessage(true);
              return false;
          }
          return true;
      }
  };
  
  void AddSC_account_commandscript ()
  {
      new account_commandscript();
  }
  