2008-10-02 16:23:55 -05:00
/*
2008-10-14 11:57:03 -05:00
* Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
*
* Thanks to the original authors: MaNGOS <http://www.mangosproject.org/>
2008-10-02 16:23:55 -05:00
*
* 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
2008-10-14 11:57:03 -05:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* 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
2008-10-14 11:57:03 -05:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
2008-10-14 11:57:03 -05:00
/// \addtogroup Trinityd
2008-10-02 16:23:55 -05:00
/// @{
/// \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 CliSetTBC ( 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" },
{ "setbc" , & CliSetTBC , "Set user expansion 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 = objmgr . GetAccountByAccountName ( acc );
if ( ! account_id )
{
account_id = atoi ( acc );
if ( account_id )
{
std :: string acc_name ;
if ( ! objmgr . GetAccountNameByAccount ( 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 < CliTotalCmds ; x ++ )
zprintf ( "%-13s - %s. \r\n " , Commands [ x ]. cmd , Commands [ x ]. description );
}
/// Exit the realm
void CliExit ( char * , pPrintf zprintf )
{
zprintf ( "Exiting daemon... \r\n " );
World :: m_stopEvent = true ;
}
/// Restart the server (with some delay) as soon as no active connections remain on the server
void CliIdleRestart ( char * command , pPrintf zprintf )
{
char * args = strtok ( command , " " );
if ( ! args )
{
zprintf ( "Syntax is: idlerestart $seconds|cancel \r\n " );
return ;
}
if ( std :: string ( args ) == "cancel" )
{
sWorld . ShutdownCancel ();
}
else
{
uint32 time = atoi ( args );
///- Prevent interpret wrong arg value as 0 secs shutdown time
if ( time == 0 && ( args [ 0 ] != '0' || args [ 1 ] != '\0' ) || time < 0 )
{
zprintf ( "Syntax is: idlerestart $seconds|cancel \r\n " );
return ;
}
sWorld . ShutdownServ ( time , SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE );
}
}
/// Restart the server with some delay
void CliRestart ( char * command , pPrintf zprintf )
{
char * args = strtok ( command , " " );
if ( ! args )
{
zprintf ( "Syntax is: restart $seconds|cancel \r\n " );
return ;
}
if ( std :: string ( args ) == "cancel" )
{
sWorld . ShutdownCancel ();
}
else
{
int32 time = atoi ( args );
///- Prevent interpret wrong arg value as 0 secs shutdown time
if ( time == 0 && ( args [ 0 ] != '0' || args [ 1 ] != '\0' ) || time < 0 )
{
zprintf ( "Syntax is: restart $seconds|cancel \r\n " );
return ;
}
sWorld . ShutdownServ ( time , SHUTDOWN_MASK_RESTART );
}
}
/// Shutdown the server (with some delay) as soon as no active connections remain on the server
void CliIdleShutdown ( char * command , pPrintf zprintf )
{
char * args = strtok ( command , " " );
if ( ! args )
{
zprintf ( "Syntax is: idleshutdown $seconds|cancel \r\n " );
return ;
}
if ( std :: string ( args ) == "cancel" )
{
sWorld . ShutdownCancel ();
}
else
{
uint32 time = atoi ( args );
///- Prevent interpret wrong arg value as 0 secs shutdown time
if ( time == 0 && ( args [ 0 ] != '0' || args [ 1 ] != '\0' ) || time < 0 )
{
zprintf ( "Syntax is: idleshutdown $seconds|cancel \r\n " );
return ;
}
sWorld . ShutdownServ ( time , SHUTDOWN_MASK_IDLE );
}
}
/// Shutdown the server with some delay
void CliShutdown ( char * command , pPrintf zprintf )
{
char * args = strtok ( command , " " );
if ( ! args )
{
zprintf ( "Syntax is: shutdown $seconds|cancel \r\n " );
return ;
}
if ( std :: string ( args ) == "cancel" )
{
sWorld . ShutdownCancel ();
}
else
{
int32 time = atoi ( args );
///- Prevent interpret wrong arg value as 0 secs shutdown time
if ( time == 0 && ( args [ 0 ] != '0' || args [ 1 ] != '\0' ) || time < 0 )
{
zprintf ( "Syntax is: shutdown $seconds|cancel \r\n " );
return ;
}
sWorld . ShutdownServ ( time );
}
}
/// Display info on users currently in the realm
void CliInfo ( char * , pPrintf zprintf )
{
uint32 activeClientsNum = sWorld . GetActiveSessionCount ();
uint32 queuedClientsNum = sWorld . GetQueuedSessionCount ();
uint32 maxActiveClientsNum = sWorld . GetMaxActiveSessionCount ();
uint32 maxQueuedClientsNum = sWorld . GetMaxQueuedSessionCount ();
std :: string timeStr = secsToTimeString ( sWorld . GetUptime (), true );
zprintf ( "Online players: %u (max: %u) queued: %u (max: %u) Uptime: %s \r\n " , activeClientsNum , maxActiveClientsNum , queuedClientsNum , maxQueuedClientsNum , timeStr . c_str ());
///- Get the list of accounts ID logged to the realm
QueryResult * resultDB = CharacterDatabase . Query ( "SELECT name,account FROM characters WHERE online > 0" );
if ( ! resultDB )
return ;
///- Display the list of account/characters online
zprintf ( "===================================================================== \r\n " );
zprintf ( "| Account | Character | IP | GM | TBC | \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, tbc 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 ( "|<Error> | %20s |<Error> |<Er>|<Err>| \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 ;
}
}
2008-10-14 11:57:03 -05:00
/// Display %TrinIty version
2008-10-02 16:23:55 -05:00
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 < CliTotalCmds ; x ++ )
if ( ! strcmp ( Commands [ x ]. cmd , supposedCommand ))
{
sWorld . QueueCliCommand ( new CliCommandHolder ( & Commands [ x ], arguments , zprintf ));
bSuccess = true ;
break ;
}
///- Display an error message if the command is unknown
if ( x == CliTotalCmds )
zprintf ( "Unknown command: %s \r\n " , input );
}
}
if ( ! bSuccess )
2008-10-12 17:35:16 -05:00
zprintf ( "TC>" );
2008-10-02 16:23:55 -05:00
}
/// 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 )
{
2008-10-14 11:57:03 -05:00
zprintf ( objmgr . GetTrinityStringForDBCLocale ( LANG_COMMAND_TELE_NOTFOUND ), " \r\n " );
2008-10-02 16:23:55 -05:00
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 ))
{
2008-10-14 11:57:03 -05:00
zprintf ( objmgr . GetTrinityStringForDBCLocale ( LANG_INVALID_TARGET_COORD ), " \r\n " , x , y , mapid );
2008-10-02 16:23:55 -05:00
return ;
}
Player * chr = objmgr . GetPlayer ( name . c_str ());
if ( chr )
{
if ( chr -> IsBeingTeleported () == true )
{
2008-10-14 11:57:03 -05:00
zprintf ( objmgr . GetTrinityStringForDBCLocale ( LANG_IS_TELEPORTED ), " \r\n " , chr -> GetName ());
2008-10-02 16:23:55 -05:00
return ;
}
if ( chr -> isInFlight ())
{
2008-10-14 11:57:03 -05:00
zprintf ( objmgr . GetTrinityStringForDBCLocale ( LANG_CHAR_IN_FLIGHT ), " \r\n " , chr -> GetName ());
2008-10-02 16:23:55 -05:00
return ;
}
2008-10-14 11:57:03 -05:00
zprintf ( objmgr . GetTrinityStringForDBCLocale ( LANG_TELEPORTING_TO ), " \r\n " , chr -> GetName (), "" , location . c_str ());
2008-10-02 16:23:55 -05:00
chr -> SaveRecallPosition ();
chr -> TeleportTo ( mapid , x , y , z , chr -> GetOrientation ());
}
else if ( uint64 guid = objmgr . GetPlayerGUIDByName ( name . c_str ()))
{
2008-10-14 11:57:03 -05:00
zprintf ( objmgr . GetTrinityStringForDBCLocale ( LANG_TELEPORTING_TO ), " \r\n " , name . c_str (), objmgr . GetTrinityStringForDBCLocale ( LANG_OFFLINE ), location . c_str ());
2008-10-02 16:23:55 -05:00
Player :: SavePositionInDB ( mapid , x , y , z , ort , MapManager :: Instance (). GetZoneId ( mapid , x , y ), guid );
}
else
2008-10-14 11:57:03 -05:00
zprintf ( objmgr . GetTrinityStringForDBCLocale ( LANG_NO_PLAYER ), " \r\n " , name . c_str ());
2008-10-02 16:23:55 -05:00
}
/// 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 CliSetTBC ( char * command , pPrintf zprintf )
{
///- Get the command line arguments
char * szAcc = strtok ( command , " " );
char * szTBC = strtok ( NULL , " " );
if ( ! szAcc ||! szTBC )
{
zprintf ( "Syntax is: setbc $account $number (0 - normal, 1 - tbc)> \r\n " );
return ;
}
int lev = atoi ( szTBC ); //get int anyway (0 if error)
if (( lev > 1 ) || ( lev < 0 ))
{
zprintf ( "Syntax is: setbc $account $number (0 - normal, 1 - tbc)> \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 tbc = '%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 ();
2008-10-14 11:57:03 -05:00
zprintf ( objmgr . GetTrinityStringForDBCLocale ( LANG_PLAYERS_SAVED ) );
2008-10-02 16:23:55 -05:00
///- 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 = "<unknown>" ; 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
2008-10-12 17:35:16 -05:00
printf ( "TC>" );
2008-10-02 16:23:55 -05:00
///- 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
}