2008-10-02 16:23:55 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2009-02-04 12:04:12 +01:00
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.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-11-15 11:56:59 -06: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-11-15 11:56:59 -06:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-14 11:57:03 -05:00
/// \addtogroup Trinityd
2008-10-02 16:23:55 -05:00
/// @{
/// \file
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "Common.h"
#include "ObjectMgr.h"
2009-06-04 21:41:07 +02:00
#include "World.h"
2008-10-02 16:23:55 -05:00
#include "WorldSession.h"
#include "Config/ConfigEnv.h"
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "AccountMgr.h"
2009-06-04 21:41:07 +02:00
#include "Chat.h"
2008-10-02 16:23:55 -05:00
#include "CliRunnable.h"
2009-06-04 21:41:07 +02:00
#include "Language.h"
#include "Log.h"
2008-10-02 16:23:55 -05:00
#include "MapManager.h"
#include "Player.h"
2009-06-04 21:41:07 +02:00
#include "ScriptCalls.h"
#include "Util.h"
2009-10-17 15:51:44 -07:00
2009-06-08 20:19:13 +02:00
#if PLATFORM != WINDOWS
#include <readline/readline.h>
#include <readline/history.h>
2009-10-17 15:51:44 -07:00
2009-06-08 20:19:13 +02:00
char * command_finder ( const char * text , int state )
{
2009-08-15 19:16:47 -07:00
static int idx , len ;
const char * ret ;
ChatCommand * cmd = ChatHandler :: getCommandTable ();
2009-10-17 15:51:44 -07:00
2009-08-15 19:16:47 -07:00
if ( ! state )
2009-08-15 19:18:30 -07:00
{
idx = 0 ;
len = strlen ( text );
}
2009-10-17 15:51:44 -07:00
2009-08-15 19:16:47 -07:00
while ( ret = cmd [ idx ]. Name )
2009-08-15 19:18:30 -07:00
{
if ( ! cmd [ idx ]. AllowConsole )
2009-08-15 19:16:47 -07:00
{
idx ++ ;
2009-08-15 19:18:30 -07:00
continue ;
2009-08-15 19:16:47 -07:00
}
2009-10-17 15:51:44 -07:00
2009-08-15 19:18:30 -07:00
idx ++ ;
//printf("Checking %s \n", cmd[idx].Name);
if ( strncmp ( ret , text , len ) == 0 )
return strdup ( ret );
if ( cmd [ idx ]. Name == NULL )
break ;
}
2009-10-17 15:51:44 -07:00
2009-08-15 19:18:30 -07:00
return (( char * ) NULL );
2009-06-08 20:19:13 +02:00
}
2009-10-17 15:51:44 -07:00
2009-06-08 20:19:13 +02:00
char ** cli_completion ( const char * text , int start , int end )
{
2009-08-15 19:16:47 -07:00
char ** matches ;
matches = ( char ** ) NULL ;
2009-10-17 16:20:24 -07:00
2009-08-15 19:16:47 -07:00
if ( start == 0 )
matches = rl_completion_matches (( char * ) text , & command_finder );
else
rl_bind_key ( '\t' , rl_abort );
return ( matches );
2009-06-08 20:19:13 +02:00
}
#endif
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
void utf8print ( const char * str )
2008-10-02 16:23:55 -05:00
{
#if PLATFORM == PLATFORM_WINDOWS
2008-11-30 12:47:26 -06:00
wchar_t wtemp_buf [ 6000 ];
2008-10-26 13:32:42 -05:00
size_t wtemp_len = 6000 - 1 ;
if ( ! Utf8toWStr ( str , strlen ( str ), wtemp_buf , wtemp_len ))
return ;
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
char temp_buf [ 6000 ];
CharToOemBuffW ( & wtemp_buf [ 0 ], & temp_buf [ 0 ], wtemp_len + 1 );
printf ( temp_buf );
2008-10-02 16:23:55 -05:00
#else
2008-11-15 11:56:59 -06:00
printf ( str );
2008-10-02 16:23:55 -05:00
#endif
2008-10-26 13:32:42 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
/// 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 ( const char * args )
2008-10-02 16:23:55 -05:00
{
2008-10-26 13:32:42 -05:00
if ( !* args )
return false ;
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
///- Get the account name from the command line
char * account_name_str = strtok (( char * ) args , " " );
if ( ! account_name_str )
return false ;
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
std :: string account_name = account_name_str ;
2009-05-21 19:06:09 +02:00
if ( ! AccountMgr :: normalizeString ( account_name ))
2008-10-02 16:23:55 -05:00
{
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , account_name . c_str ());
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
uint32 account_id = accmgr . GetId ( account_name );
2008-10-02 16:23:55 -05:00
if ( ! account_id )
{
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , account_name . c_str ());
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
/// Commands not recommended call from chat, but support anyway
2009-03-20 22:17:39 +01:00
/// can delete only for account with less security
/// This is also reject self apply in fact
if ( HasLowerSecurityAccount ( NULL , account_id , true ))
return false ;
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
AccountOpResult result = accmgr . DeleteAccount ( account_id );
2008-10-02 16:23:55 -05:00
switch ( result )
{
case AOR_OK :
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_DELETED , account_name . c_str ());
2008-10-02 16:23:55 -05:00
break ;
case AOR_NAME_NOT_EXIST :
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_NOT_EXIST , account_name . c_str ());
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
case AOR_DB_INTERNAL_ERROR :
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_NOT_DELETED_SQL_ERROR , account_name . c_str ());
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
default :
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_NOT_DELETED , account_name . c_str ());
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-15 11:56:59 -06:00
return true ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
bool ChatHandler :: HandleCharacterDeleteCommand ( const char * args )
2008-10-02 16:23:55 -05:00
{
2008-10-26 13:32:42 -05:00
if ( !* args )
return false ;
2009-10-17 15:51:44 -07:00
2008-11-15 11:56:59 -06:00
char * character_name_str = strtok (( char * ) args , " " );
2008-10-02 16:23:55 -05:00
if ( ! character_name_str )
2008-11-15 11:56:59 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
std :: string character_name = character_name_str ;
2008-10-02 16:23:55 -05:00
if ( ! normalizePlayerName ( character_name ))
2008-11-15 11:56:59 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint64 character_guid ;
uint32 account_id ;
2009-10-17 15:51:44 -07:00
2008-11-15 11:56:59 -06:00
Player * player = objmgr . GetPlayer ( character_name . c_str ());
2008-10-02 16:23:55 -05:00
if ( player )
{
character_guid = player -> GetGUID ();
account_id = player -> GetSession () -> GetAccountId ();
player -> GetSession () -> KickPlayer ();
}
else
{
character_guid = objmgr . GetPlayerGUIDByName ( character_name );
if ( ! character_guid )
{
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_NO_PLAYER , character_name . c_str ());
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
account_id = objmgr . GetPlayerAccountIdByGUID ( character_guid );
}
2009-10-17 15:51:44 -07:00
2008-11-15 11:56:59 -06:00
std :: string account_name ;
2008-10-26 13:32:42 -05:00
accmgr . GetName ( account_id , account_name );
2009-10-17 15:51:44 -07:00
2008-11-15 11:56:59 -06:00
Player :: DeleteFromDB ( character_guid , account_id , true );
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_CHARACTER_DELETED , character_name . c_str (), GUID_LOPART ( character_guid ), account_name . c_str (), account_id );
return true ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Exit the realm
2009-05-13 18:22:21 -05:00
bool ChatHandler :: HandleServerExitCommand ( const char * /*args*/ )
2008-10-02 16:23:55 -05:00
{
2008-10-26 13:32:42 -05:00
SendSysMessage ( LANG_COMMAND_EXIT );
2008-11-20 16:16:57 -06:00
World :: StopNow ( SHUTDOWN_EXIT_CODE );
2008-11-15 11:56:59 -06:00
return true ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Display info on users currently in the realm
2009-05-13 18:22:21 -05:00
bool ChatHandler :: HandleAccountOnlineListCommand ( const char * /*args*/ )
2008-10-02 16:23:55 -05:00
{
///- Get the list of accounts ID logged to the realm
QueryResult * resultDB = CharacterDatabase . Query ( "SELECT name,account FROM characters WHERE online > 0" );
if ( ! resultDB )
2009-03-28 17:31:27 -06:00
{
SendSysMessage ( LANG_ACCOUNT_LIST_EMPTY );
2008-10-26 13:32:42 -05:00
return true ;
2009-03-28 17:31:27 -06:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Display the list of account/characters online
2009-03-28 17:31:27 -06:00
SendSysMessage ( LANG_ACCOUNT_LIST_BAR );
2008-10-26 13:32:42 -05:00
SendSysMessage ( LANG_ACCOUNT_LIST_HEADER );
2009-03-28 17:31:27 -06:00
SendSysMessage ( LANG_ACCOUNT_LIST_BAR );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Circle through accounts
do
{
Field * fieldsDB = resultDB -> Fetch ();
std :: string name = fieldsDB [ 0 ]. GetCppString ();
uint32 account = fieldsDB [ 1 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- Get the username, last IP and GM level of each account
// No SQL injection. account is uint32.
// 0 1 2 3
2009-07-31 11:29:28 +08:00
QueryResult * resultLogin = loginDatabase . PQuery ( "SELECT username, last_ip, gmlevel, expansion FROM account WHERE id = '%u'" , account );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
if ( resultLogin )
{
Field * fieldsLogin = resultLogin -> Fetch ();
2009-03-28 17:31:27 -06:00
PSendSysMessage ( LANG_ACCOUNT_LIST_LINE ,
2008-10-02 16:23:55 -05:00
fieldsLogin [ 0 ]. GetString (), name . c_str (), fieldsLogin [ 1 ]. GetString (), fieldsLogin [ 2 ]. GetUInt32 (), fieldsLogin [ 3 ]. GetUInt32 ());
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
delete resultLogin ;
}
else
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_LIST_ERROR , name . c_str ());
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
} while ( resultDB -> NextRow ());
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
delete resultDB ;
2009-10-17 15:51:44 -07:00
2009-03-28 17:31:27 -06:00
SendSysMessage ( LANG_ACCOUNT_LIST_BAR );
2008-10-26 13:32:42 -05:00
return true ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Create an account
2008-10-26 13:32:42 -05:00
bool ChatHandler :: HandleAccountCreateCommand ( const char * args )
2008-10-02 16:23:55 -05:00
{
2008-10-26 13:32:42 -05:00
if ( !* args )
return false ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- %Parse the command line arguments
2008-10-26 13:32:42 -05:00
char * szAcc = strtok (( char * ) args , " " );
2008-10-02 16:23:55 -05:00
char * szPassword = strtok ( NULL , " " );
if ( ! szAcc || ! szPassword )
2008-11-15 11:56:59 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2009-05-21 19:06:09 +02:00
// normalized in accmgr.CreateAccount
2008-10-26 13:32:42 -05:00
std :: string account_name = szAcc ;
std :: string password = szPassword ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
AccountOpResult result = accmgr . CreateAccount ( account_name , password );
switch ( result )
{
case AOR_OK :
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_CREATED , account_name . c_str ());
2008-10-02 16:23:55 -05:00
break ;
case AOR_NAME_TOO_LONG :
2008-10-26 13:32:42 -05:00
SendSysMessage ( LANG_ACCOUNT_TOO_LONG );
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
case AOR_NAME_ALREDY_EXIST :
2008-10-26 13:32:42 -05:00
SendSysMessage ( LANG_ACCOUNT_ALREADY_EXIST );
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
case AOR_DB_INTERNAL_ERROR :
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_NOT_CREATED_SQL_ERROR , account_name . c_str ());
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
default :
2008-10-26 13:32:42 -05:00
PSendSysMessage ( LANG_ACCOUNT_NOT_CREATED , account_name . c_str ());
SetSentErrorMessage ( true );
return false ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-11-15 11:56:59 -06:00
return true ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-04-09 13:48:01 -05:00
/// Set the level of logging
bool ChatHandler :: HandleServerSetLogFileLevelCommand ( const char * args )
{
if ( !* args )
return false ;
2009-10-17 15:51:44 -07:00
2009-04-09 13:48:01 -05:00
char * NewLevel = strtok (( char * ) args , " " );
if ( ! NewLevel )
return false ;
2009-10-17 15:51:44 -07:00
2009-04-09 13:48:01 -05:00
sLog . SetLogFileLevel ( NewLevel );
return true ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// Set the level of logging
2008-10-26 13:32:42 -05:00
bool ChatHandler :: HandleServerSetLogLevelCommand ( const char * args )
2008-10-02 16:23:55 -05:00
{
2008-10-26 13:32:42 -05:00
if ( !* args )
return false ;
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
char * NewLevel = strtok (( char * ) args , " " );
if ( ! NewLevel )
2008-11-15 11:56:59 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
sLog . SetLogLevel ( NewLevel );
2008-11-15 11:56:59 -06:00
return true ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-01-01 19:32:44 -06:00
/// set diff time record interval
bool ChatHandler :: HandleServerSetDiffTimeCommand ( const char * args )
{
if ( !* args )
return false ;
2009-10-17 15:51:44 -07:00
2009-01-01 19:32:44 -06:00
char * NewTimeStr = strtok (( char * ) args , " " );
if ( ! NewTimeStr )
return false ;
2009-10-17 15:51:44 -07:00
2009-01-01 19:32:44 -06:00
int32 NewTime = atoi ( NewTimeStr );
if ( NewTime < 0 )
return false ;
2009-10-17 15:51:44 -07:00
2009-01-01 19:32:44 -06:00
sWorld . SetRecordDiffInterval ( NewTime );
printf ( "Record diff every %u ms \n " , NewTime );
return true ;
}
2008-10-02 16:23:55 -05:00
/// @}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#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
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
/// %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
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
char commandbuf [ 256 ];
2009-06-08 20:19:13 +02:00
bool canflush = true ;
2008-10-02 16:23:55 -05:00
///- Display the list of available CLI functions then beep
2009-03-20 22:17:39 +01:00
sLog . outString ( "" );
2009-08-15 19:08:39 -07:00
#if PLATFORM != WINDOWS
2009-06-08 20:19:13 +02:00
rl_attempted_completion_function = cli_completion ;
2009-08-15 19:08:39 -07:00
#endif
2008-10-02 16:23:55 -05:00
if ( sConfig . GetBoolDefault ( "BeepAtStart" , true ))
printf ( " \a " ); // \a = Alert
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// 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>" );
2009-10-17 15:51:44 -07:00
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
2008-11-20 16:16:57 -06:00
while ( ! World :: IsStopped ())
2008-10-02 16:23:55 -05:00
{
fflush ( stdout );
2009-10-17 15:51:44 -07:00
2009-06-08 20:19:13 +02:00
char * command_str ; // = fgets(commandbuf,sizeof(commandbuf),stdin);
2009-10-17 15:51:44 -07:00
2009-08-15 19:16:47 -07:00
#if PLATFORM == WINDOWS
command_str = fgets ( commandbuf , sizeof ( commandbuf ), stdin );
#else
command_str = readline ( "TC>" );
rl_bind_key ( '\t' , rl_complete );
#endif
if ( command_str != NULL )
2008-10-02 16:23:55 -05:00
{
2009-10-17 16:20:24 -07:00
for ( int x = 0 ; command_str [ x ]; x ++ )
2008-10-26 13:32:42 -05:00
if ( command_str [ x ] == '\r' || command_str [ x ] == '\n' )
2009-08-15 19:16:47 -07:00
{
command_str [ x ] = 0 ;
break ;
}
2008-10-26 13:32:42 -05:00
2008-11-15 11:56:59 -06:00
if ( !* command_str )
2008-10-02 16:23:55 -05:00
{
2009-08-15 19:16:47 -07:00
#if PLATFORM == WINDOWS
printf ( "TC>" );
#endif
2008-10-26 13:32:42 -05:00
continue ;
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-26 13:32:42 -05:00
std :: string command ;
if ( ! consoleToUtf8 ( command_str , command )) // convert from console encoding to utf8
{
2009-08-15 19:16:47 -07:00
#if PLATFORM == WINDOWS
printf ( "TC>" );
#endif
2008-10-26 13:32:42 -05:00
continue ;
}
2009-08-15 19:16:47 -07:00
fflush ( stdout );
2008-10-26 13:32:42 -05:00
sWorld . QueueCliCommand ( & utf8print , command . c_str ());
2009-08-15 19:16:47 -07:00
#if PLATFORM != WINDOWS
add_history ( command . c_str ());
#endif
2009-10-17 15:51:44 -07:00
2009-08-15 19:16:47 -07:00
}
2008-10-02 16:23:55 -05:00
else if ( feof ( stdin ))
2008-11-15 11:56:59 -06:00
{
2008-11-20 16:16:57 -06:00
World :: StopNow ( SHUTDOWN_EXIT_CODE );
2008-11-15 11:56:59 -06:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
///- End the database thread
WorldDatabase . ThreadEnd (); // free mySQL thread resources
}