/* * Copyright (C) 2005-2008 MaNGOS * * Copyright (C) 2008 Trinity * * 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 */ /// \addtogroup Trinityd /// @{ /// \file #include "Common.h" #include "Language.h" #include "Log.h" #include "World.h" #include "ScriptCalls.h" #include "GlobalEvents.h" #include "ObjectMgr.h" #include "WorldSession.h" #include "SystemConfig.h" #include "Config/ConfigEnv.h" #include "Util.h" #include "AccountMgr.h" #include "CliRunnable.h" #include "MapManager.h" #include "PlayerDump.h" #include "Player.h" //CliCommand and CliCommandHolder are defined in World.h to avoid cyclic deps //func prototypes must be defined void CliHelp(char*,pPrintf); void CliInfo(char*,pPrintf); void CliBan(char*,pPrintf); void CliBanList(char*,pPrintf); void CliRemoveBan(char*,pPrintf); void CliSetGM(char*,pPrintf); void CliListGM(char*,pPrintf); void CliVersion(char*,pPrintf); void CliExit(char*,pPrintf); void CliIdleRestart(char*,pPrintf zprintf); void CliRestart(char*,pPrintf zprintf); void CliIdleShutdown(char*,pPrintf zprintf); void CliShutdown(char*,pPrintf zprintf); void CliBroadcast(char*,pPrintf); void CliCreate(char*,pPrintf); void CliDelete(char*,pPrintf); void CliCharDelete(char *,pPrintf); void CliLoadScripts(char*,pPrintf); void CliKick(char*,pPrintf); void CliTele(char*,pPrintf); void CliMotd(char*,pPrintf); void CliCorpses(char*,pPrintf); void CliSetLogLevel(char*,pPrintf); void CliUpTime(char*,pPrintf); void CliSetAddon(char*,pPrintf); void CliWritePlayerDump(char*,pPrintf); void CliLoadPlayerDump(char*,pPrintf); void CliSave(char*,pPrintf); void CliSend(char*,pPrintf); void CliPLimit(char*,pPrintf); void CliSetPassword(char*,pPrintf); /// Table of known commands const CliCommand Commands[]= { {"help", & CliHelp,"Display this help message"}, {"broadcast", & CliBroadcast,"Announce in-game message"}, {"create", & CliCreate,"Create account"}, {"delete", & CliDelete,"Delete account and characters"}, {"chardelete", & CliCharDelete,"Delete character"}, {"info", & CliInfo,"Display Server infomation"}, {"uptime", & CliUpTime, "Displays the server uptime"}, {"motd", & CliMotd,"Change or display motd"}, {"kick", & CliKick,"Kick user"}, {"ban", & CliBan,"Ban account|ip"}, {"listbans", & CliBanList,"List bans"}, {"unban", & CliRemoveBan,"Remove ban from account|ip"}, {"setgm", & CliSetGM,"Edit user privileges"}, {"setpass", & CliSetPassword,"Set password for account"}, {"setaddon", & CliSetAddon,"Set user expansion addon level allowed"}, {"listgm", & CliListGM,"Display user privileges"}, {"loadscripts", & CliLoadScripts,"Load script library"}, {"setloglevel", & CliSetLogLevel,"Set Log Level"}, {"corpses", & CliCorpses,"Manually call corpses erase global even code"}, {"version", & CliVersion,"Display server version"}, {"idlerestart", & CliIdleRestart,"Restart server with some delay when there are no active connections remaining"}, {"restart", & CliRestart,"Restart server with some delay"}, {"idleshutdown", & CliIdleShutdown,"Shutdown server with some delay when there are no active connections remaining"}, {"shutdown", & CliShutdown,"Shutdown server with some delay"}, {"exit", & CliExit,"Shutdown server NOW"}, {"writepdump", &CliWritePlayerDump,"Write a player dump to a file"}, {"loadpdump", &CliLoadPlayerDump,"Load a player dump from a file"}, {"saveall", &CliSave,"Save all players"}, {"send", &CliSend,"Send message to a player"}, {"tele", &CliTele,"Teleport player to location"}, {"plimit", &CliPLimit,"Show or set player login limitations"} }; /// \todo Need some pragma pack? Else explain why in a comment. #define CliTotalCmds sizeof(Commands)/sizeof(CliCommand) #if PLATFORM == PLATFORM_WINDOWS int utf8printf(const char* str,...) { UTF8PRINTF(stdout,str,1); return 0; } #define UTF8ZPRINTF utf8printf #else #define UTF8ZPRINTF printf #endif /// Create a character dump file void CliWritePlayerDump(char*command,pPrintf zprintf) { char * file = strtok(command, " "); char * p2 = strtok(NULL, " "); if(!file || !p2) { zprintf("Syntax is: writepdump $filename $playerNameOrGUID\r\n"); return; } std::string name; if(!consoleToUtf8(p2,name)) // convert from console encoding to utf8 return; if(!normalizePlayerName(name)) { zprintf("Syntax is: writepdump $filename $playerNameOrGUID\r\n"); return; } uint32 guid = objmgr.GetPlayerGUIDByName(name); if(!guid) guid = atoi(p2); if(!guid) { zprintf("Syntax is: writepdump $filename $playerNameOrGUID\r\n"); return; } PlayerDumpWriter().WriteDump(file, guid); } /// Load a character from a dump file void CliLoadPlayerDump(char*command,pPrintf zprintf) { char * file = strtok(command, " "); char * acc = strtok(NULL, " "); if (!file ||!acc) { zprintf("Syntax is: loadpdump $filename $account ($newname) ($newguid)\r\n"); return; } uint32 account_id = accmgr.GetId(acc); if(!account_id) { account_id = atoi(acc); if(account_id) { std::string acc_name; if(!accmgr.GetName(account_id,acc_name)) { zprintf("Failed to load the character! Account not exist.\r\n"); return; } } else { zprintf("Failed to load the character! Account not exist.\r\n"); return; } } char * name_str = strtok(NULL, " "); char * guid_str = name_str ? strtok(NULL, " ") : NULL; uint32 guid = guid_str ? atoi(guid_str) : 0; std::string name; if(name_str) { if(!consoleToUtf8(name_str,name)) // convert from console encoding to utf8 return; if(!normalizePlayerName(name)) { zprintf("Syntax is: loadpdump $filename $account ($newname) ($newguid)\r\n"); return; } } if(PlayerDumpReader().LoadDump(file, account_id, name, guid)) zprintf("Character loaded successfully!\r\n"); else zprintf("Failed to load the character!\r\n"); } /// Reload the scripts and notify the players void CliLoadScripts(char*command,pPrintf zprintf) { char const *del=strtok(command," "); if (!del) del=""; if(!LoadScriptingModule(del)) // Error report is already done by LoadScriptingModule return; sWorld.SendWorldText(LANG_SCRIPTS_RELOADED); } /// 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 void CliDelete(char*command,pPrintf zprintf) { ///- Get the account name from the command line char *account_name_str=strtok(command," "); if(!account_name_str) { // \r\n is used because this function can also be called from RA zprintf("Syntax is: delete $account\r\n"); return; } std::string account_name; if(!consoleToUtf8(account_name_str,account_name)) // convert from console encoding to utf8 return; AccountOpResult result = accmgr.DeleteAccount(accmgr.GetId(account_name)); switch(result) { case AOR_OK: zprintf("We deleted account: %s\r\n",account_name.c_str()); break; case AOR_NAME_NOT_EXIST: zprintf("User %s does not exist\r\n",account_name.c_str()); break; case AOR_DB_INTERNAL_ERROR: zprintf("User %s NOT deleted (probably sql file format was updated)\r\n",account_name.c_str()); break; default: zprintf("User %s NOT deleted (unknown error)\r\n",account_name.c_str()); break; } } void CliCharDelete(char*command,pPrintf zprintf) { char *character_name_str = strtok(command," "); if(!character_name_str) { zprintf("Syntax is: chardelete $character_name\r\n"); return; } std::string character_name; if(!consoleToUtf8(character_name_str,character_name)) // convert from console encoding to utf8 return; if(!normalizePlayerName(character_name)) { zprintf("Syntax is: chardelete $character_name\r\n"); return; } Player *player = objmgr.GetPlayer(character_name.c_str()); uint64 character_guid; uint32 account_id; if(player) { character_guid = player->GetGUID(); account_id = player->GetSession()->GetAccountId(); player->GetSession()->KickPlayer(); } else { character_guid = objmgr.GetPlayerGUIDByName(character_name); if(!character_guid) { zprintf("Player %s not found!\r\n",character_name.c_str()); return; } account_id = objmgr.GetPlayerAccountIdByGUID(character_guid); } Player::DeleteFromDB(character_guid, account_id, true); zprintf("Player %s (Guid: %u AccountId: %u) deleted\r\n",character_name.c_str(),GUID_LOPART(character_guid),account_id); } /// Broadcast a message to the World void CliBroadcast(char *text,pPrintf zprintf) { std::string textUtf8; if(!consoleToUtf8(text,textUtf8)) // convert from console encoding to utf8 return; sWorld.SendWorldText(LANG_SYSTEMMESSAGE,textUtf8.c_str()); zprintf("Broadcasting to the world: %s\r\n",textUtf8.c_str()); } /// Print the list of commands and associated description void CliHelp(char*,pPrintf zprintf) { for (unsigned int x=0;x 0"); if (!resultDB) return; ///- Display the list of account/characters online zprintf("=====================================================================\r\n"); zprintf("| Account | Character | IP | GM | Exp |\r\n"); zprintf("=====================================================================\r\n"); ///- Circle through accounts do { Field *fieldsDB = resultDB->Fetch(); std::string name = fieldsDB[0].GetCppString(); uint32 account = fieldsDB[1].GetUInt32(); ///- Get the username, last IP and GM level of each account // No SQL injection. account is uint32. // 0 1 2 3 QueryResult *resultLogin = loginDatabase.PQuery("SELECT username, last_ip, gmlevel, expansion FROM account WHERE id = '%u'",account); if(resultLogin) { Field *fieldsLogin = resultLogin->Fetch(); zprintf("|%15s| %20s | %15s |%4d|%5d|\r\n", fieldsLogin[0].GetString(),name.c_str(),fieldsLogin[1].GetString(),fieldsLogin[2].GetUInt32(),fieldsLogin[3].GetUInt32()); delete resultLogin; } else zprintf("| | %20s | |||\r\n",name.c_str()); }while(resultDB->NextRow()); delete resultDB; zprintf("=====================================================================\r\n"); } /// Display a list of banned accounts and ip addresses void CliBanList(char*,pPrintf zprintf) { bool found = false; ///- Get the list of banned accounts and display them QueryResult *result = loginDatabase.Query("SELECT id,username FROM account WHERE id IN (SELECT id FROM account_banned WHERE active = 1)"); if(result) { found = true; zprintf("Currently Banned Accounts:\r\n"); zprintf("===============================================================================\r\n"); zprintf("| Account | BanDate | UnbanDate | Banned By | Ban Reason |\r\n"); do { zprintf("-------------------------------------------------------------------------------\r\n"); Field *fields = result->Fetch(); // No SQL injection. id is uint32. QueryResult *banInfo = loginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u AND active = 1 ORDER BY unbandate", fields[0].GetUInt32()); if (banInfo) { Field *fields2 = banInfo->Fetch(); do { time_t t_ban = fields2[0].GetUInt64(); tm* aTm_ban = localtime(&t_ban); zprintf("|%-15.15s|", fields[1].GetString()); zprintf("%02d-%02d-%02d %02d:%02d|", aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min); if ( fields2[0].GetUInt64() == fields2[1].GetUInt64() ) zprintf(" permanent |"); else { time_t t_unban = fields2[1].GetUInt64(); tm* aTm_unban = localtime(&t_unban); zprintf("%02d-%02d-%02d %02d:%02d|",aTm_unban->tm_year%100, aTm_unban->tm_mon+1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min); } zprintf("%-15.15s|%-15.15s|\r\n",fields2[2].GetString(),fields2[3].GetString()); }while ( banInfo->NextRow() ); delete banInfo; } }while( result->NextRow() ); zprintf("===============================================================================\r\n"); delete result; } ///- Get the list of banned IP addresses and display them result = loginDatabase.Query( "SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP()) ORDER BY unbandate" ); if(result) { found = true; zprintf("Currently Banned IPs:\r\n"); zprintf("===============================================================================\r\n"); zprintf("| IP | BanDate | UnbanDate | Banned By | Ban Reason |\r\n"); do { zprintf("-------------------------------------------------------------------------------\r\n"); Field *fields = result->Fetch(); time_t t_ban = fields[1].GetUInt64(); tm* aTm_ban = localtime(&t_ban); zprintf("|%-15.15s|", fields[0].GetString()); zprintf("%02d-%02d-%02d %02d:%02d|", aTm_ban->tm_year%100, aTm_ban->tm_mon+1, aTm_ban->tm_mday, aTm_ban->tm_hour, aTm_ban->tm_min); if ( fields[1].GetUInt64() == fields[2].GetUInt64() ) zprintf(" permanent |"); else { time_t t_unban = fields[2].GetUInt64(); tm* aTm_unban = localtime(&t_unban); zprintf("%02d-%02d-%02d %02d:%02d|", aTm_unban->tm_year%100, aTm_unban->tm_mon+1, aTm_unban->tm_mday, aTm_unban->tm_hour, aTm_unban->tm_min); } zprintf("%-15.15s|%-15.15s|\r\n", fields[3].GetString(), fields[4].GetString()); }while( result->NextRow() ); zprintf("===============================================================================\r\n"); delete result; } if(!found) zprintf("We do not have banned users\r\n"); } /// Ban an IP address or a user account void CliBan(char*command,pPrintf zprintf) { ///- Get the command parameter char* type_str = strtok((char*)command, " "); char* nameOrIP_str = strtok(NULL, " "); char* duration_str = strtok(NULL," "); char* reason_str = strtok(NULL,""); if(!type_str||!nameOrIP_str||!duration_str||!reason_str)// ?!? input of single char "0"-"9" wouldn't detect when with: || !atoi(duration) { zprintf("Syntax: ban account|ip|character $AccountOrIpOrCharacter $duration[s|m|h|d] $reason \r\n"); return; } std::string type; if(!consoleToUtf8(type_str,type)) // convert from console encoding to utf8 return; std::string nameOrIP; if(!consoleToUtf8(nameOrIP_str,nameOrIP)) // convert from console encoding to utf8 return; std::string duration; if(!consoleToUtf8(duration_str,duration)) // convert from console encoding to utf8 return; std::string reason; if(!consoleToUtf8(reason_str,reason)) // convert from console encoding to utf8 return; switch (sWorld.BanAccount(type, nameOrIP, duration, reason, "Set by console.")) { case BAN_SUCCESS: if(atoi(duration_str)>0) zprintf("%s is banned for %s. Reason: %s.\r\n",nameOrIP.c_str(),secsToTimeString(TimeStringToSecs(duration_str),true,false).c_str(),reason.c_str()); else zprintf("%s is banned permanently. Reason: %s.\r\n",nameOrIP.c_str(),reason.c_str()); break; case BAN_NOTFOUND: zprintf("%s %s not found\r\n", type.c_str(), nameOrIP.c_str()); break; case BAN_SYNTAX_ERROR: zprintf("Syntax: ban account|ip|character $AccountOrIpOrCharacter $duration[s|m|h|d] $reason \r\n"); break; } } /// Display %TrinIty version void CliVersion(char*,pPrintf zprintf) { //<--maybe better append to info cmd zprintf( "%s (world-daemon)\r\n", _FULLVERSION ); } /// Unban an IP adress or a user account void CliRemoveBan(char *command,pPrintf zprintf) { ///- Get the command parameter char *type_str = strtok(command," "); char *nameorip_str = strtok(NULL," "); if(!nameorip_str||!type_str) { zprintf("Syntax is: unban account|ip|character $nameorip\r\n"); return; } std::string type; if(!consoleToUtf8(type_str,type)) // convert from console encoding to utf8 return; std::string nameorip; if(!consoleToUtf8(nameorip_str,nameorip)) // convert from console encoding to utf8 return; if (!sWorld.RemoveBanAccount(type, nameorip)) zprintf("%s %s not found\r\n", type.c_str(), nameorip.c_str()); else zprintf("We removed ban from %s: %s\r\n",type_str,nameorip.c_str()); } /// Display the list of GMs void CliListGM(char*,pPrintf zprintf) { ///- Get the accounts with GM Level >0 Field *fields; QueryResult *result = loginDatabase.Query( "SELECT username,gmlevel FROM account WHERE gmlevel > 0" ); if(result) { zprintf("Current gamemasters:\r\n"); zprintf("========================\r\n"); zprintf("| Account | GM |\r\n"); zprintf("========================\r\n"); ///- Circle through them. Display username and GM level do { fields = result->Fetch(); zprintf("|%15s|", fields[0].GetString()); zprintf("%6s|\r\n",fields[1].GetString()); }while( result->NextRow() ); zprintf("========================\r\n"); delete result; } else { zprintf("No gamemasters\r\n"); } } /// Set the GM level of an account void CliSetGM(char *command,pPrintf zprintf) { ///- Get the command line arguments char *szAcc = strtok(command," "); char *szLevel = strtok(NULL," "); if(!szAcc||!szLevel) //wrong syntax 'setgm' without name { zprintf("Syntax is: setgm $account $number (0 - normal, 3 - gamemaster)>\r\n"); return; } //wow it's ok,let's hope it was integer given int lev=atoi(szLevel); //get int anyway (0 if error) std::string safe_account_name; if(!consoleToUtf8(szAcc,safe_account_name)) // convert from console encoding to utf8 return; ///- Convert Account name to Upper Format AccountMgr::normilizeString(safe_account_name); ///- Escape the account name to allow quotes in names loginDatabase.escape_string(safe_account_name); ///- Try to find the account, then update the GM level // No SQL injection (account name is escaped) QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",safe_account_name.c_str()); if (result) { Field *fields = result->Fetch(); uint32 account_id = fields[0].GetUInt32(); delete result; WorldSession* session = sWorld.FindSession(account_id); if(session) session->SetSecurity(lev); // No SQL injection (account name is escaped) loginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE username = '%s'",lev,safe_account_name.c_str()); zprintf("We set %s gmlevel %d\r\n",safe_account_name.c_str(),lev); } else { zprintf("No account %s found\r\n",safe_account_name.c_str()); } } /// Set password for account void CliSetPassword(char *command,pPrintf zprintf) { ///- Get the command line arguments char *szAcc = strtok(command," "); char *szPassword1 = strtok(NULL," "); char *szPassword2 = strtok(NULL," "); if(!szAcc||!szPassword1 || !szPassword2) { zprintf("Syntax is: setpass $account $password $password\r\n"); return; } std::string account_name; if(!consoleToUtf8(szAcc,account_name)) // convert from console encoding to utf8 return; std::string pass1; if(!consoleToUtf8(szPassword1,pass1)) // convert from console encoding to utf8 return; std::string pass2; if(!consoleToUtf8(szPassword2,pass2)) // convert from console encoding to utf8 return; uint32 acc_id = accmgr.GetId(szAcc); if (!acc_id) { zprintf("Account '%s' does not exist!\r\n", account_name.c_str()); return; } if (pass1 != pass2) { zprintf("Password does not match the confirm password, password not changed!\r\n"); return; } AccountOpResult result = accmgr.ChangePassword(acc_id, pass1); switch(result) { case AOR_OK: zprintf("The password was changed for account '%s' (ID: %u).\r\n",account_name.c_str(),acc_id); break; case AOR_PASS_TOO_LONG: zprintf("Password can't be longer than 16 characters (client limit), password not changed!\r\n"); break; case AOR_NAME_NOT_EXIST: zprintf("Account '%s' does not exist!\r\n", account_name.c_str()); break; case AOR_DB_INTERNAL_ERROR: zprintf("Password not changed! (probably sql file format was updated)\r\n"); break; default: zprintf("Password not changed! (unknown error\r\n"); break; } } /// Create an account void CliCreate(char *command,pPrintf zprintf) { //I see no need in this function (why would an admin personally create accounts //instead of using account registration page or accessing db directly?) //but still let it be ///- %Parse the command line arguments char *szAcc = strtok(command, " "); char *szPassword = strtok(NULL, " "); if(!szAcc || !szPassword) { zprintf("Syntax is: create $username $password\r\n"); return; } std::string account_name; if(!consoleToUtf8(szAcc,account_name)) // convert from console encoding to utf8 return; std::string password; if(!consoleToUtf8(szPassword,password)) // convert from console encoding to utf8 return; AccountOpResult result = accmgr.CreateAccount(account_name, password); switch(result) { case AOR_OK: zprintf("User %s with password %s created successfully\r\n",account_name.c_str(),password.c_str()); break; case AOR_NAME_TOO_LONG: zprintf("Username %s is too long\r\n", account_name.c_str()); break; case AOR_NAME_ALREDY_EXIST: zprintf("User %s already exists\r\n",account_name.c_str()); break; case AOR_DB_INTERNAL_ERROR: zprintf("User %s with password %s NOT created (probably sql file format was updated)\r\n",account_name.c_str(),password.c_str()); break; default: zprintf("User %s with password %s NOT created (unknown error)\r\n",account_name.c_str(),password.c_str()); break; } } /// Command parser and dispatcher void ParseCommand( pPrintf zprintf, char* input) { unsigned int x; bool bSuccess=false; if (!input) return; unsigned int l=strlen(input); char *supposedCommand=NULL,* arguments=(char*)(""); if(l) { ///- Get the command and the arguments supposedCommand = strtok(input," "); if (supposedCommand) { if (l>strlen(supposedCommand)) arguments=&input[strlen(supposedCommand)+1]; ///- Circle through the command table and, if found, put the command in the queue for ( x=0;x"); } /// Kick a character out of the realm void CliKick(char*command,pPrintf zprintf) { char *kickName = strtok(command, " "); if (!kickName) { zprintf("Syntax is: kick $charactername\r\n"); return; } std::string name; if(!consoleToUtf8(kickName,name)) // convert from console encoding to utf8 return; if(!normalizePlayerName(name)) return; sWorld.KickPlayer(name); } /// Teleport a character to location void CliTele(char*command,pPrintf zprintf) { char *charName = strtok(command, " "); char *locName = strtok(NULL, " "); if (!charName || !locName) { zprintf("Syntax is: tele $charactername $location\r\n"); return; } std::string name = charName; if(!consoleToUtf8(charName,name)) // convert from console encoding to utf8 return; if(!normalizePlayerName(name)) return; std::string location; if(!consoleToUtf8(locName,location)) // convert from console encoding to utf8 return; WorldDatabase.escape_string(location); QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM game_tele WHERE name = '%s'",location.c_str()); if (!result) { zprintf(objmgr.GetTrinityStringForDBCLocale(LANG_COMMAND_TELE_NOTFOUND),"\r\n"); return; } Field *fields = result->Fetch(); float x = fields[0].GetFloat(); float y = fields[1].GetFloat(); float z = fields[2].GetFloat(); float ort = fields[3].GetFloat(); int mapid = fields[4].GetUInt16(); delete result; if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort)) { zprintf(objmgr.GetTrinityStringForDBCLocale(LANG_INVALID_TARGET_COORD),"\r\n",x,y,mapid); return; } Player *chr = objmgr.GetPlayer(name.c_str()); if (chr) { if(chr->IsBeingTeleported()==true) { zprintf(objmgr.GetTrinityStringForDBCLocale(LANG_IS_TELEPORTED),"\r\n",chr->GetName()); return; } if(chr->isInFlight()) { zprintf(objmgr.GetTrinityStringForDBCLocale(LANG_CHAR_IN_FLIGHT),"\r\n",chr->GetName()); return; } zprintf(objmgr.GetTrinityStringForDBCLocale(LANG_TELEPORTING_TO),"\r\n",chr->GetName(),"", location.c_str()); chr->SaveRecallPosition(); chr->TeleportTo(mapid,x,y,z,chr->GetOrientation()); } else if (uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str())) { zprintf(objmgr.GetTrinityStringForDBCLocale(LANG_TELEPORTING_TO),"\r\n",name.c_str(), objmgr.GetTrinityStringForDBCLocale(LANG_OFFLINE), location.c_str()); Player::SavePositionInDB(mapid,x,y,z,ort,MapManager::Instance().GetZoneId(mapid,x,y),guid); } else zprintf(objmgr.GetTrinityStringForDBCLocale(LANG_NO_PLAYER),"\r\n",name.c_str()); } /// Display/Define the 'Message of the day' for the realm void CliMotd(char*command,pPrintf zprintf) { if (strlen(command) == 0) { zprintf("Current Message of the day: \r\n%s\r\n", sWorld.GetMotd()); return; } else { std::string commandUtf8; if(!consoleToUtf8(command,commandUtf8)) // convert from console encoding to utf8 return; sWorld.SetMotd(commandUtf8); zprintf("Message of the day changed to:\r\n%s\r\n", commandUtf8.c_str()); } } /// Comment me /// \todo What is CorpsesErase for? void CliCorpses(char*,pPrintf) { CorpsesErase(); } /// Set the level of logging void CliSetLogLevel(char*command,pPrintf zprintf) { char *NewLevel = strtok(command, " "); if (!NewLevel) { zprintf("Syntax is: setloglevel $loglevel\r\n"); return; } sLog.SetLogLevel(NewLevel); } /// Display the server uptime void CliUpTime(char*,pPrintf zprintf) { uint32 uptime = sWorld.GetUptime(); std::string suptime = secsToTimeString(uptime,true,(uptime > 86400)); zprintf("Server has been up for: %s\r\n", suptime.c_str()); } /// Set/Unset the TBC flag for an account void CliSetAddon(char *command,pPrintf zprintf) { ///- Get the command line arguments char *szAcc = strtok(command," "); char *szExp = strtok(NULL," "); if(!szAcc||!szExp) { zprintf("Syntax is: setbc $account $number (0 - normal, 1 - tbc, 2 - wotlk)>\r\n"); return; } int lev=atoi(szExp); //get int anyway (0 if error) if(lev < 0) { zprintf("Syntax is: setbc $account $number (0 - normal, 1 - tbc, 2 - wotlk)>\r\n"); return; } ///- Escape the account name to allow quotes in names std::string safe_account_name; if(!consoleToUtf8(szAcc,safe_account_name)) // convert from console encoding to utf8 return; ///- Convert Account name to Upper Format AccountMgr::normilizeString(safe_account_name); ///- Escape the account name to allow quotes in names loginDatabase.escape_string(safe_account_name); // No SQL injection (account name is escaped) QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'",safe_account_name.c_str()); if (result) { // No SQL injection (account name is escaped) loginDatabase.PExecute("UPDATE account SET expansion = '%d' WHERE username = '%s'",lev,safe_account_name.c_str()); zprintf("We set %s to expansion allowed %d\r\n",safe_account_name.c_str(),lev); delete result; } else { zprintf("No account %s found\r\n",safe_account_name.c_str()); } } /// Save all players void CliSave(char*,pPrintf zprintf) { ///- Save players ObjectAccessor::Instance().SaveAllPlayers(); zprintf( objmgr.GetTrinityStringForDBCLocale(LANG_PLAYERS_SAVED) ); ///- Send a message sWorld.SendWorldText(LANG_PLAYERS_SAVED); } /// Send a message to a player in game void CliSend(char *playerN,pPrintf zprintf) { ///- Get the command line arguments char* name_str = strtok((char*)playerN, " "); char* msg_str = strtok(NULL, ""); if(!name_str || !msg_str) { zprintf("Syntax: send $player $message (Player name is case sensitive)\r\n"); return; } std::string name; if(!consoleToUtf8(name_str,name)) // convert from console encoding to utf8 return; std::string msg; if(!consoleToUtf8(msg_str,msg)) // convert from console encoding to utf8 return; if(!normalizePlayerName(name)) { zprintf("Syntax: send $player $message (Player name is case sensitive)\r\n"); return; } ///- Find the player and check that he is not logging out. Player *rPlayer = objmgr.GetPlayer(name.c_str()); if(!rPlayer) { zprintf("Player %s not found!\r\n", name.c_str()); return; } if (rPlayer->GetSession()->isLogingOut()) { zprintf("Cannot send message while player %s is logging out!\r\n",name.c_str()); return; } ///- Send the message //Use SendAreaTriggerMessage for fastest delivery. rPlayer->GetSession()->SendAreaTriggerMessage("%s", msg.c_str()); rPlayer->GetSession()->SendAreaTriggerMessage("|cffff0000[Message from administrator]:|r"); //Confirmation message zprintf("Message '%s' sent to %s\r\n",msg.c_str(), name.c_str()); } void CliPLimit(char *args,pPrintf zprintf) { if(*args) { char* param = strtok((char*)args, " "); if(!param || !*param) return; int l = strlen(param); if( strncmp(param,"player",l) == 0 ) sWorld.SetPlayerLimit(-SEC_PLAYER); else if(strncmp(param,"moderator",l) == 0 ) sWorld.SetPlayerLimit(-SEC_MODERATOR); else if(strncmp(param,"gamemaster",l) == 0 ) sWorld.SetPlayerLimit(-SEC_GAMEMASTER); else if(strncmp(param,"administrator",l) == 0 ) sWorld.SetPlayerLimit(-SEC_ADMINISTRATOR); else if(strncmp(param,"reset",l) == 0 ) sWorld.SetPlayerLimit(sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT)); else { int val = atoi(param); if(val < -SEC_ADMINISTRATOR) val = -SEC_ADMINISTRATOR; sWorld.SetPlayerLimit(val); } // kick all low security level players if(sWorld.GetPlayerAmountLimit() > SEC_PLAYER) sWorld.KickAllLess(sWorld.GetPlayerSecurityLimit()); } uint32 pLimit = sWorld.GetPlayerAmountLimit(); AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit(); char const* secName = ""; switch(allowedAccountType) { case SEC_PLAYER: secName = "Player"; break; case SEC_MODERATOR: secName = "Moderator"; break; case SEC_GAMEMASTER: secName = "Gamemaster"; break; case SEC_ADMINISTRATOR: secName = "Administrator"; break; default: secName = ""; break; } zprintf("Player limits: amount %u, min. security level %s.\r\n",pLimit,secName); } /// @} #ifdef linux // Non-blocking keypress detector, when return pressed, return 1, else always return 0 int kb_hit_return() { struct timeval tv; fd_set fds; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); return FD_ISSET(STDIN_FILENO, &fds); } #endif /// %Thread start void CliRunnable::run() { ///- Init new SQL thread for the world database (one connection call enough) WorldDatabase.ThreadStart(); // let thread do safe mySQL requests char commandbuf[256]; ///- Display the list of available CLI functions then beep sLog.outString(); /// \todo Shoudn't we use here also the sLog singleton? CliHelp(NULL,&UTF8ZPRINTF); if(sConfig.GetBoolDefault("BeepAtStart", true)) { printf("\a"); // \a = Alert } // print this here the first time // later it will be printed after command queue updates printf("TC>"); ///- As long as the World is running (no World::m_stopEvent), get the command line and handle it while (!World::m_stopEvent) { fflush(stdout); #ifdef linux while (!kb_hit_return() && !World::m_stopEvent) // With this, we limit CLI to 10commands/second usleep(100); if (World::m_stopEvent) break; #endif char *command = fgets(commandbuf,sizeof(commandbuf),stdin); if (command != NULL) { for(int x=0;command[x];x++) if(command[x]=='\r'||command[x]=='\n') { command[x]=0; break; } //// \todo Shoudn't we use here also the sLog singleton? ParseCommand(&UTF8ZPRINTF,command); } else if (feof(stdin)) { World::m_stopEvent = true; } } ///- End the database thread WorldDatabase.ThreadEnd(); // free mySQL thread resources }