root/trunk/src/trinitycore/CliRunnable.cpp @ 2

Revision 2, 40.4 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19/// \addtogroup mangosd
20/// @{
21/// \file
22
23#include "Common.h"
24#include "Language.h"
25#include "Log.h"
26#include "World.h"
27#include "ScriptCalls.h"
28#include "GlobalEvents.h"
29#include "ObjectMgr.h"
30#include "WorldSession.h"
31#include "SystemConfig.h"
32#include "Config/ConfigEnv.h"
33#include "Util.h"
34#include "AccountMgr.h"
35#include "CliRunnable.h"
36#include "MapManager.h"
37#include "PlayerDump.h"
38#include "Player.h"
39
40//CliCommand and CliCommandHolder are defined in World.h to avoid cyclic deps
41
42//func prototypes must be defined
43
44void CliHelp(char*,pPrintf);
45void CliInfo(char*,pPrintf);
46void CliBan(char*,pPrintf);
47void CliBanList(char*,pPrintf);
48void CliRemoveBan(char*,pPrintf);
49void CliSetGM(char*,pPrintf);
50void CliListGM(char*,pPrintf);
51void CliVersion(char*,pPrintf);
52void CliExit(char*,pPrintf);
53void CliIdleRestart(char*,pPrintf zprintf);
54void CliRestart(char*,pPrintf zprintf);
55void CliIdleShutdown(char*,pPrintf zprintf);
56void CliShutdown(char*,pPrintf zprintf);
57void CliBroadcast(char*,pPrintf);
58void CliCreate(char*,pPrintf);
59void CliDelete(char*,pPrintf);
60void CliCharDelete(char *,pPrintf);
61void CliLoadScripts(char*,pPrintf);
62void CliKick(char*,pPrintf);
63void CliTele(char*,pPrintf);
64void CliMotd(char*,pPrintf);
65void CliCorpses(char*,pPrintf);
66void CliSetLogLevel(char*,pPrintf);
67void CliUpTime(char*,pPrintf);
68void CliSetTBC(char*,pPrintf);
69void CliWritePlayerDump(char*,pPrintf);
70void CliLoadPlayerDump(char*,pPrintf);
71void CliSave(char*,pPrintf);
72void CliSend(char*,pPrintf);
73void CliPLimit(char*,pPrintf);
74void CliSetPassword(char*,pPrintf);
75/// Table of known commands
76const CliCommand Commands[]=
77{
78    {"help", & CliHelp,"Display this help message"},
79    {"broadcast", & CliBroadcast,"Announce in-game message"},
80    {"create", & CliCreate,"Create account"},
81    {"delete", & CliDelete,"Delete account and characters"},
82    {"chardelete", & CliCharDelete,"Delete character"},
83    {"info", & CliInfo,"Display Server infomation"},
84    {"uptime", & CliUpTime, "Displays the server uptime"},
85    {"motd", & CliMotd,"Change or display motd"},
86    {"kick", & CliKick,"Kick user"},
87    {"ban", & CliBan,"Ban account|ip"},
88    {"listbans", & CliBanList,"List bans"},
89    {"unban", & CliRemoveBan,"Remove ban from account|ip"},
90    {"setgm", & CliSetGM,"Edit user privileges"},
91    {"setpass", & CliSetPassword,"Set password for account"},
92    {"setbc", & CliSetTBC,"Set user expansion allowed"},
93    {"listgm", & CliListGM,"Display user privileges"},
94    {"loadscripts", & CliLoadScripts,"Load script library"},
95    {"setloglevel", & CliSetLogLevel,"Set Log Level"},
96    {"corpses", & CliCorpses,"Manually call corpses erase global even code"},
97    {"version", & CliVersion,"Display server version"},
98    {"idlerestart", & CliIdleRestart,"Restart server with some delay when there are no active connections remaining"},
99    {"restart", & CliRestart,"Restart server with some delay"},
100    {"idleshutdown", & CliIdleShutdown,"Shutdown server with some delay when there are no active connections remaining"},
101    {"shutdown", & CliShutdown,"Shutdown server with some delay"},
102    {"exit", & CliExit,"Shutdown server NOW"},
103    {"writepdump", &CliWritePlayerDump,"Write a player dump to a file"},
104    {"loadpdump", &CliLoadPlayerDump,"Load a player dump from a file"},
105    {"saveall", &CliSave,"Save all players"},
106    {"send", &CliSend,"Send message to a player"},
107    {"tele", &CliTele,"Teleport player to location"},
108    {"plimit", &CliPLimit,"Show or set player login limitations"}
109};
110/// \todo Need some pragma pack? Else explain why in a comment.
111#define CliTotalCmds sizeof(Commands)/sizeof(CliCommand)
112
113#if PLATFORM == PLATFORM_WINDOWS
114int utf8printf(const char* str,...)
115{
116    UTF8PRINTF(stdout,str,1);
117    return 0;
118}
119#define UTF8ZPRINTF utf8printf
120#else
121#define UTF8ZPRINTF printf
122#endif
123
124/// Create a character dump file
125void CliWritePlayerDump(char*command,pPrintf zprintf)
126{
127    char * file = strtok(command, " ");
128    char * p2 = strtok(NULL, " ");
129    if(!file || !p2)
130    {
131        zprintf("Syntax is: writepdump $filename $playerNameOrGUID\r\n");
132        return;
133    }
134
135    std::string name;
136    if(!consoleToUtf8(p2,name))                             // convert from console encoding to utf8
137        return;
138
139    if(!normalizePlayerName(name))
140    {
141        zprintf("Syntax is: writepdump $filename $playerNameOrGUID\r\n");
142        return;
143    }
144
145    uint32 guid = objmgr.GetPlayerGUIDByName(name);
146    if(!guid)
147        guid = atoi(p2);
148
149    if(!guid)
150    {
151        zprintf("Syntax is: writepdump $filename $playerNameOrGUID\r\n");
152        return;
153    }
154
155    PlayerDumpWriter().WriteDump(file, guid);
156}
157
158/// Load a character from a dump file
159void CliLoadPlayerDump(char*command,pPrintf zprintf)
160{
161    char * file = strtok(command, " ");
162    char * acc = strtok(NULL, " ");
163    if (!file ||!acc)
164    {
165        zprintf("Syntax is: loadpdump $filename $account ($newname) ($newguid)\r\n");
166        return;
167    }
168
169    uint32 account_id = objmgr.GetAccountByAccountName(acc);
170    if(!account_id)
171    {
172        account_id = atoi(acc);
173        if(account_id)
174        {
175            std::string acc_name;
176            if(!objmgr.GetAccountNameByAccount(account_id,acc_name))
177            {
178                zprintf("Failed to load the character! Account not exist.\r\n");
179                return;
180            }
181        }
182        else
183        {
184            zprintf("Failed to load the character! Account not exist.\r\n");
185            return;
186        }
187    }
188
189    char * name_str = strtok(NULL, " ");
190    char * guid_str = name_str ? strtok(NULL, " ") : NULL;
191
192    uint32 guid = guid_str ? atoi(guid_str) : 0;
193
194    std::string name;
195    if(name_str)
196    {
197        if(!consoleToUtf8(name_str,name))                   // convert from console encoding to utf8
198            return;
199
200        if(!normalizePlayerName(name))
201        {
202            zprintf("Syntax is: loadpdump $filename $account ($newname) ($newguid)\r\n");
203            return;
204        }
205    }
206
207    if(PlayerDumpReader().LoadDump(file, account_id, name, guid))
208        zprintf("Character loaded successfully!\r\n");
209    else
210        zprintf("Failed to load the character!\r\n");
211}
212
213/// Reload the scripts and notify the players
214void CliLoadScripts(char*command,pPrintf zprintf)
215{
216    char const *del=strtok(command," ");
217    if (!del)
218        del="";
219    if(!LoadScriptingModule(del))                           // Error report is already done by LoadScriptingModule
220        return;
221
222    sWorld.SendWorldText(LANG_SCRIPTS_RELOADED);
223}
224
225/// Delete a user account and all associated characters in this realm
226/// \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
227void CliDelete(char*command,pPrintf zprintf)
228{
229    ///- Get the account name from the command line
230    char *account_name_str=strtok(command," ");
231    if(!account_name_str)
232    {
233        // \r\n is used because this function can also be called from RA
234        zprintf("Syntax is: delete $account\r\n");
235        return;
236    }
237
238    std::string account_name;
239    if(!consoleToUtf8(account_name_str,account_name))       // convert from console encoding to utf8
240        return;
241
242    AccountOpResult result = accmgr.DeleteAccount(accmgr.GetId(account_name));
243    switch(result)
244    {
245        case AOR_OK:
246            zprintf("We deleted account: %s\r\n",account_name.c_str());
247            break;
248        case AOR_NAME_NOT_EXIST:
249            zprintf("User %s does not exist\r\n",account_name.c_str());
250            break;
251        case AOR_DB_INTERNAL_ERROR:
252            zprintf("User %s NOT deleted (probably sql file format was updated)\r\n",account_name.c_str());
253            break;
254        default:
255            zprintf("User %s NOT deleted (unknown error)\r\n",account_name.c_str());
256            break;
257    }
258}
259
260void CliCharDelete(char*command,pPrintf zprintf)
261{
262    char *character_name_str = strtok(command," ");
263
264    if(!character_name_str)
265    {
266        zprintf("Syntax is: chardelete $character_name\r\n");
267        return;
268    }
269
270    std::string character_name;
271    if(!consoleToUtf8(character_name_str,character_name))   // convert from console encoding to utf8
272        return;
273
274    if(!normalizePlayerName(character_name))
275    {
276        zprintf("Syntax is: chardelete $character_name\r\n");
277        return;
278    }
279
280    Player *player = objmgr.GetPlayer(character_name.c_str());
281
282    uint64 character_guid;
283    uint32 account_id;
284
285    if(player)
286    {
287        character_guid = player->GetGUID();
288        account_id = player->GetSession()->GetAccountId();
289        player->GetSession()->KickPlayer();
290    }
291    else
292    {
293        character_guid = objmgr.GetPlayerGUIDByName(character_name);
294        if(!character_guid)
295        {
296            zprintf("Player %s not found!\r\n",character_name.c_str());
297            return;
298        }
299
300        account_id = objmgr.GetPlayerAccountIdByGUID(character_guid);
301    }
302
303    Player::DeleteFromDB(character_guid, account_id, true); 
304    zprintf("Player %s (Guid: %u AccountId: %u) deleted\r\n",character_name.c_str(),GUID_LOPART(character_guid),account_id);
305}
306
307/// Broadcast a message to the World
308void CliBroadcast(char *text,pPrintf zprintf)
309{
310    std::string textUtf8;
311    if(!consoleToUtf8(text,textUtf8))                       // convert from console encoding to utf8
312        return;
313
314    sWorld.SendWorldText(LANG_SYSTEMMESSAGE,textUtf8.c_str());
315    zprintf("Broadcasting to the world: %s\r\n",textUtf8.c_str());
316}
317
318/// Print the list of commands and associated description
319void CliHelp(char*,pPrintf zprintf)
320{
321    for (unsigned int x=0;x<CliTotalCmds;x++)
322        zprintf("%-13s - %s.\r\n",Commands[x].cmd ,Commands[x].description);
323}
324
325/// Exit the realm
326void CliExit(char*,pPrintf zprintf)
327{
328    zprintf( "Exiting daemon...\r\n" );
329    World::m_stopEvent = true;
330}
331
332/// Restart the server (with some delay) as soon as no active connections remain on the server
333void CliIdleRestart(char* command,pPrintf zprintf)
334{
335    char *args = strtok(command," ");
336
337    if(!args)
338    {
339        zprintf("Syntax is: idlerestart $seconds|cancel\r\n");
340        return;
341    }
342
343    if(std::string(args)=="cancel")
344    {
345        sWorld.ShutdownCancel();
346    }
347    else
348    {
349
350        uint32 time = atoi(args);
351
352        ///- Prevent interpret wrong arg value as 0 secs shutdown time
353        if(time==0 && (args[0]!='0' || args[1]!='\0') || time < 0)
354        {
355            zprintf("Syntax is: idlerestart $seconds|cancel\r\n");
356            return;
357        }
358
359        sWorld.ShutdownServ(time,SHUTDOWN_MASK_RESTART|SHUTDOWN_MASK_IDLE);
360    }
361}
362
363/// Restart the server with some delay
364void CliRestart(char* command,pPrintf zprintf)
365{
366    char *args = strtok(command," ");
367
368    if(!args)
369    {
370        zprintf("Syntax is: restart $seconds|cancel\r\n");
371        return;
372    }
373
374    if(std::string(args)=="cancel")
375    {
376        sWorld.ShutdownCancel();
377    }
378    else
379    {
380        int32 time = atoi(args);
381
382        ///- Prevent interpret wrong arg value as 0 secs shutdown time
383        if(time==0 && (args[0]!='0' || args[1]!='\0') || time < 0)
384        {
385            zprintf("Syntax is: restart $seconds|cancel\r\n");
386            return;
387        }
388
389        sWorld.ShutdownServ(time,SHUTDOWN_MASK_RESTART);
390    }
391}
392
393/// Shutdown the server (with some delay) as soon as no active connections remain on the server
394void CliIdleShutdown(char* command,pPrintf zprintf)
395{
396    char *args = strtok(command," ");
397
398    if(!args)
399    {
400        zprintf("Syntax is: idleshutdown $seconds|cancel\r\n");
401        return;
402    }
403
404    if(std::string(args)=="cancel")
405    {
406        sWorld.ShutdownCancel();
407    }
408    else
409    {
410
411        uint32 time = atoi(args);
412
413        ///- Prevent interpret wrong arg value as 0 secs shutdown time
414        if(time==0 && (args[0]!='0' || args[1]!='\0') || time < 0)
415        {
416            zprintf("Syntax is: idleshutdown $seconds|cancel\r\n");
417            return;
418        }
419
420        sWorld.ShutdownServ(time,SHUTDOWN_MASK_IDLE);
421    }
422}
423
424/// Shutdown the server with some delay
425void CliShutdown(char* command,pPrintf zprintf)
426{
427    char *args = strtok(command," ");
428
429    if(!args)
430    {
431        zprintf("Syntax is: shutdown $seconds|cancel\r\n");
432        return;
433    }
434
435    if(std::string(args)=="cancel")
436    {
437        sWorld.ShutdownCancel();
438    }
439    else
440    {
441        int32 time = atoi(args);
442
443        ///- Prevent interpret wrong arg value as 0 secs shutdown time
444        if(time==0 && (args[0]!='0' || args[1]!='\0') || time < 0)
445        {
446            zprintf("Syntax is: shutdown $seconds|cancel\r\n");
447            return;
448        }
449
450        sWorld.ShutdownServ(time);
451    }
452}
453
454/// Display info on users currently in the realm
455void CliInfo(char*,pPrintf zprintf)
456{
457    uint32 activeClientsNum = sWorld.GetActiveSessionCount();
458    uint32 queuedClientsNum = sWorld.GetQueuedSessionCount();
459    uint32 maxActiveClientsNum = sWorld.GetMaxActiveSessionCount();
460    uint32 maxQueuedClientsNum = sWorld.GetMaxQueuedSessionCount();
461    std::string timeStr = secsToTimeString(sWorld.GetUptime(),true);
462
463    zprintf("Online players: %u (max: %u) queued: %u (max: %u) Uptime: %s\r\n",activeClientsNum,maxActiveClientsNum,queuedClientsNum,maxQueuedClientsNum,timeStr.c_str());
464
465    ///- Get the list of accounts ID logged to the realm
466    QueryResult *resultDB = CharacterDatabase.Query("SELECT name,account FROM characters WHERE online > 0");
467
468    if (!resultDB)
469        return;
470
471    ///- Display the list of account/characters online
472    zprintf("=====================================================================\r\n");
473    zprintf("|    Account    |       Character      |       IP        | GM | TBC |\r\n");
474    zprintf("=====================================================================\r\n");
475
476    ///- Circle through accounts
477    do
478    {
479        Field *fieldsDB = resultDB->Fetch();
480        std::string name = fieldsDB[0].GetCppString();
481        uint32 account = fieldsDB[1].GetUInt32();
482
483        ///- Get the username, last IP and GM level of each account
484        // No SQL injection. account is uint32.
485        //                                                      0         1        2        3
486        QueryResult *resultLogin = loginDatabase.PQuery("SELECT username, last_ip, gmlevel, tbc FROM account WHERE id = '%u'",account);
487
488        if(resultLogin)
489        {
490            Field *fieldsLogin = resultLogin->Fetch();
491            zprintf("|%15s| %20s | %15s |%4d|%5d|\r\n",
492                fieldsLogin[0].GetString(),name.c_str(),fieldsLogin[1].GetString(),fieldsLogin[2].GetUInt32(),fieldsLogin[3].GetUInt32());
493
494            delete resultLogin;
495        }
496        else
497            zprintf("|<Error>        | %20s |<Error>          |<Er>|<Err>|\r\n",name.c_str());
498
499    }while(resultDB->NextRow());
500
501    delete resultDB;
502
503    zprintf("=====================================================================\r\n");
504}
505
506/// Display a list of banned accounts and ip addresses
507void CliBanList(char*,pPrintf zprintf)
508{
509    bool found = false;
510    ///- Get the list of banned accounts and display them
511    QueryResult *result = loginDatabase.Query("SELECT id,username FROM account WHERE id IN (SELECT id FROM account_banned WHERE active = 1)");
512    if(result)
513    {
514        found = true;
515
516        zprintf("Currently Banned Accounts:\r\n");
517        zprintf("===============================================================================\r\n");
518        zprintf("|    Account    |   BanDate    |   UnbanDate  |  Banned By    |   Ban Reason  |\r\n");
519        do
520        {
521            zprintf("-------------------------------------------------------------------------------\r\n");
522            Field *fields = result->Fetch();
523            // No SQL injection. id is uint32.
524            QueryResult *banInfo = loginDatabase.PQuery("SELECT bandate,unbandate,bannedby,banreason FROM account_banned WHERE id = %u AND active = 1 ORDER BY unbandate", fields[0].GetUInt32());
525            if (banInfo)
526            {
527                Field *fields2 = banInfo->Fetch();
528                do
529                {
530                    time_t t_ban = fields2[0].GetUInt64();
531                    tm* aTm_ban = localtime(&t_ban);
532                    zprintf("|%-15.15s|", fields[1].GetString());
533                    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);
534                    if ( fields2[0].GetUInt64() == fields2[1].GetUInt64() )
535                        zprintf("   permanent  |");
536                    else
537                    {
538                        time_t t_unban = fields2[1].GetUInt64();
539                        tm* aTm_unban = localtime(&t_unban);
540                        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);
541                    }
542                    zprintf("%-15.15s|%-15.15s|\r\n",fields2[2].GetString(),fields2[3].GetString());
543                }while ( banInfo->NextRow() );
544                delete banInfo;
545            }
546        }while( result->NextRow() );
547        zprintf("===============================================================================\r\n");
548        delete result;
549    }
550
551    ///- Get the list of banned IP addresses and display them
552    result = loginDatabase.Query( "SELECT ip,bandate,unbandate,bannedby,banreason FROM ip_banned WHERE (bandate=unbandate OR unbandate>UNIX_TIMESTAMP()) ORDER BY unbandate" );
553    if(result)
554    {
555        found = true;
556
557        zprintf("Currently Banned IPs:\r\n");
558        zprintf("===============================================================================\r\n");
559        zprintf("|      IP       |   BanDate    |   UnbanDate  |  Banned By    |   Ban Reason  |\r\n");
560        do
561        {
562            zprintf("-------------------------------------------------------------------------------\r\n");
563            Field *fields = result->Fetch();
564            time_t t_ban = fields[1].GetUInt64();
565            tm* aTm_ban = localtime(&t_ban);
566            zprintf("|%-15.15s|", fields[0].GetString());
567            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);
568            if ( fields[1].GetUInt64() == fields[2].GetUInt64() )
569                zprintf("   permanent  |");
570            else
571            {
572                time_t t_unban = fields[2].GetUInt64();
573                tm* aTm_unban = localtime(&t_unban);
574                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);
575            }
576            zprintf("%-15.15s|%-15.15s|\r\n", fields[3].GetString(), fields[4].GetString());
577        }while( result->NextRow() );
578        zprintf("===============================================================================\r\n");
579        delete result;
580    }
581
582    if(!found)
583        zprintf("We do not have banned users\r\n");
584}
585
586/// Ban an IP address or a user account
587void CliBan(char*command,pPrintf zprintf)
588{
589    ///- Get the command parameter
590    char* type_str = strtok((char*)command, " ");
591    char* nameOrIP_str = strtok(NULL, " ");
592    char* duration_str = strtok(NULL," ");
593    char* reason_str = strtok(NULL,"");
594
595    if(!type_str||!nameOrIP_str||!duration_str||!reason_str)// ?!? input of single char "0"-"9" wouldn't detect when with: || !atoi(duration)
596    {
597        zprintf("Syntax: ban account|ip|character $AccountOrIpOrCharacter $duration[s|m|h|d] $reason \r\n");
598        return;
599    }
600
601    std::string type;
602    if(!consoleToUtf8(type_str,type))                       // convert from console encoding to utf8
603        return;
604
605    std::string nameOrIP;
606    if(!consoleToUtf8(nameOrIP_str,nameOrIP))               // convert from console encoding to utf8
607        return;
608
609    std::string duration;
610    if(!consoleToUtf8(duration_str,duration))               // convert from console encoding to utf8
611        return;
612
613    std::string reason;
614    if(!consoleToUtf8(reason_str,reason))                   // convert from console encoding to utf8
615        return;
616
617    switch (sWorld.BanAccount(type, nameOrIP, duration, reason, "Set by console."))
618    {
619        case BAN_SUCCESS:
620            if(atoi(duration_str)>0)
621                zprintf("%s is banned for %s. Reason: %s.\r\n",nameOrIP.c_str(),secsToTimeString(TimeStringToSecs(duration_str),true,false).c_str(),reason.c_str());
622            else
623                zprintf("%s is banned permanently. Reason: %s.\r\n",nameOrIP.c_str(),reason.c_str());
624            break;
625        case BAN_NOTFOUND:
626            zprintf("%s %s not found\r\n", type.c_str(), nameOrIP.c_str());
627            break;
628        case BAN_SYNTAX_ERROR:
629            zprintf("Syntax: ban account|ip|character $AccountOrIpOrCharacter $duration[s|m|h|d] $reason \r\n");
630            break;
631    }
632}
633
634/// Display %MaNGOS version
635void CliVersion(char*,pPrintf zprintf)
636{
637                                                            //<--maybe better append to info cmd
638    zprintf( "%s (world-daemon)\r\n", _FULLVERSION );
639}
640
641/// Unban an IP adress or a user account
642void CliRemoveBan(char *command,pPrintf zprintf)
643{
644    ///- Get the command parameter
645    char *type_str = strtok(command," ");
646    char *nameorip_str = strtok(NULL," ");
647    if(!nameorip_str||!type_str)
648    {
649        zprintf("Syntax is: unban account|ip|character $nameorip\r\n");
650        return;
651    }
652
653    std::string type;
654    if(!consoleToUtf8(type_str,type))                       // convert from console encoding to utf8
655        return;
656
657    std::string nameorip;
658    if(!consoleToUtf8(nameorip_str,nameorip))               // convert from console encoding to utf8
659        return;
660
661    if (!sWorld.RemoveBanAccount(type, nameorip))
662        zprintf("%s %s not found\r\n", type.c_str(), nameorip.c_str());
663    else
664        zprintf("We removed ban from %s: %s\r\n",type_str,nameorip.c_str());
665}
666
667/// Display the list of GMs
668void CliListGM(char*,pPrintf zprintf)
669{
670
671    ///- Get the accounts with GM Level >0
672    Field *fields;
673
674    QueryResult *result = loginDatabase.Query( "SELECT username,gmlevel FROM account WHERE gmlevel > 0" );
675    if(result)
676    {
677
678        zprintf("Current gamemasters:\r\n");
679        zprintf("========================\r\n");
680        zprintf("|    Account    |  GM  |\r\n");
681        zprintf("========================\r\n");
682
683        ///- Circle through them. Display username and GM level
684        do
685        {
686            fields = result->Fetch();
687            zprintf("|%15s|", fields[0].GetString());
688            zprintf("%6s|\r\n",fields[1].GetString());
689        }while( result->NextRow() );
690
691        zprintf("========================\r\n");
692        delete result;
693    }
694    else
695    {
696        zprintf("No gamemasters\r\n");
697    }
698}
699
700/// Set the GM level of an account
701void CliSetGM(char *command,pPrintf zprintf)
702{
703    ///- Get the command line arguments
704    char *szAcc = strtok(command," ");
705    char *szLevel =  strtok(NULL," ");
706
707    if(!szAcc||!szLevel)                                    //wrong syntax 'setgm' without name
708    {
709        zprintf("Syntax is: setgm $account $number (0 - normal, 3 - gamemaster)>\r\n");
710        return;
711    }
712
713    //wow it's ok,let's hope it was integer given
714    int lev=atoi(szLevel);                                  //get int anyway (0 if error)
715
716    std::string safe_account_name;
717    if(!consoleToUtf8(szAcc,safe_account_name))             // convert from console encoding to utf8
718        return;
719
720    ///- Convert Account name to Upper Format
721    AccountMgr::normilizeString(safe_account_name);
722
723    ///- Escape the account name to allow quotes in names
724    loginDatabase.escape_string(safe_account_name);
725
726    ///- Try to find the account, then update the GM level
727    // No SQL injection (account name is escaped)
728    QueryResult *result = loginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",safe_account_name.c_str());
729
730    if (result)
731    {
732        Field *fields = result->Fetch();
733        uint32 account_id = fields[0].GetUInt32();
734        delete result;
735
736        WorldSession* session = sWorld.FindSession(account_id);
737        if(session)
738            session->SetSecurity(lev);
739
740        // No SQL injection (account name is escaped)
741        loginDatabase.PExecute("UPDATE account SET gmlevel = '%d' WHERE username = '%s'",lev,safe_account_name.c_str());
742        zprintf("We set %s gmlevel %d\r\n",safe_account_name.c_str(),lev);
743    }
744    else
745    {
746        zprintf("No account %s found\r\n",safe_account_name.c_str());
747    }
748}
749
750/// Set password for account
751void CliSetPassword(char *command,pPrintf zprintf)
752{
753    ///- Get the command line arguments
754    char *szAcc = strtok(command," ");
755    char *szPassword1 =  strtok(NULL," ");
756    char *szPassword2 =  strtok(NULL," ");
757
758    if(!szAcc||!szPassword1 || !szPassword2)
759    {
760        zprintf("Syntax is: setpass $account $password $password\r\n");
761        return;
762    }
763
764    std::string account_name;
765    if(!consoleToUtf8(szAcc,account_name))                  // convert from console encoding to utf8
766        return;
767
768    std::string pass1;
769    if(!consoleToUtf8(szPassword1,pass1))                   // convert from console encoding to utf8
770        return;
771
772    std::string pass2;
773    if(!consoleToUtf8(szPassword2,pass2))                   // convert from console encoding to utf8
774        return;
775
776    uint32 acc_id = accmgr.GetId(szAcc);
777    if (!acc_id)
778    {
779        zprintf("Account '%s' does not exist!\r\n", account_name.c_str());
780        return;
781    }
782
783    if (pass1 != pass2)
784    {
785        zprintf("Password does not match the confirm password, password not changed!\r\n");
786        return;
787    }
788
789    AccountOpResult result = accmgr.ChangePassword(acc_id, pass1);
790
791    switch(result)
792    {
793        case AOR_OK:
794            zprintf("The password was changed for account '%s' (ID: %u).\r\n",account_name.c_str(),acc_id);
795            break;
796        case AOR_PASS_TOO_LONG:
797            zprintf("Password can't be longer than 16 characters (client limit), password not changed!\r\n");
798            break;
799        case AOR_NAME_NOT_EXIST:
800            zprintf("Account '%s' does not exist!\r\n", account_name.c_str());
801            break;
802        case AOR_DB_INTERNAL_ERROR:
803            zprintf("Password not changed! (probably sql file format was updated)\r\n");
804            break;
805        default:
806            zprintf("Password not changed! (unknown error\r\n");
807            break;
808    }
809}
810
811/// Create an account
812void CliCreate(char *command,pPrintf zprintf)
813{
814    //I see no need in this function (why would an admin personally create accounts
815    //instead of using account registration page or accessing db directly?)
816    //but still let it be
817
818    ///- %Parse the command line arguments
819    char *szAcc = strtok(command, " ");
820    char *szPassword = strtok(NULL, " ");
821    if(!szAcc || !szPassword)
822    {
823        zprintf("Syntax is: create $username $password\r\n");
824        return;
825    }
826
827    std::string account_name;
828    if(!consoleToUtf8(szAcc,account_name))                   // convert from console encoding to utf8
829        return;
830
831    std::string password;
832    if(!consoleToUtf8(szPassword,password))                 // convert from console encoding to utf8
833        return;
834
835    AccountOpResult result = accmgr.CreateAccount(account_name, password);
836    switch(result)
837    {
838        case AOR_OK:
839            zprintf("User %s with password %s created successfully\r\n",account_name.c_str(),password.c_str());
840            break;
841        case AOR_NAME_TOO_LONG:
842            zprintf("Username %s is too long\r\n", account_name.c_str());
843            break;
844        case AOR_NAME_ALREDY_EXIST:
845            zprintf("User %s already exists\r\n",account_name.c_str());
846            break;
847        case AOR_DB_INTERNAL_ERROR:
848            zprintf("User %s with password %s NOT created (probably sql file format was updated)\r\n",account_name.c_str(),password.c_str());
849            break;
850        default:
851            zprintf("User %s with password %s NOT created (unknown error)\r\n",account_name.c_str(),password.c_str());
852            break;
853    }
854}
855
856/// Command parser and dispatcher
857void ParseCommand( pPrintf zprintf, char* input)
858{
859    unsigned int x;
860    bool bSuccess=false;
861    if (!input)
862        return;
863
864    unsigned int l=strlen(input);
865    char *supposedCommand=NULL,* arguments=(char*)("");
866    if(l)
867    {
868        ///- Get the command and the arguments
869        supposedCommand = strtok(input," ");
870        if (supposedCommand)
871        {
872            if (l>strlen(supposedCommand))
873                arguments=&input[strlen(supposedCommand)+1];
874
875            ///- Circle through the command table and, if found, put the command in the queue
876            for ( x=0;x<CliTotalCmds;x++)
877                if(!strcmp(Commands[x].cmd,supposedCommand))
878            {
879                sWorld.QueueCliCommand(new CliCommandHolder(&Commands[x], arguments, zprintf));
880                bSuccess=true;
881                break;
882            }
883
884            ///- Display an error message if the command is unknown
885            if(x==CliTotalCmds)
886                zprintf("Unknown command: %s\r\n", input);
887        }
888    }
889    if (!bSuccess)
890        zprintf("mangos>");
891}
892
893/// Kick a character out of the realm
894void CliKick(char*command,pPrintf zprintf)
895{
896    char *kickName = strtok(command, " ");
897
898    if (!kickName)
899    {
900        zprintf("Syntax is: kick $charactername\r\n");
901        return;
902    }
903
904    std::string name;
905    if(!consoleToUtf8(kickName,name))                       // convert from console encoding to utf8
906        return;
907   
908    if(!normalizePlayerName(name))
909        return;
910
911    sWorld.KickPlayer(name);
912}
913
914/// Teleport a character to location
915void CliTele(char*command,pPrintf zprintf)
916{
917    char *charName = strtok(command, " ");
918    char *locName = strtok(NULL, " ");
919
920    if (!charName || !locName)
921    {
922        zprintf("Syntax is: tele $charactername $location\r\n");
923        return;
924    }
925
926    std::string name = charName;
927    if(!consoleToUtf8(charName,name))                       // convert from console encoding to utf8
928        return;
929   
930    if(!normalizePlayerName(name))
931        return;
932
933    std::string location;
934    if(!consoleToUtf8(locName,location))                    // convert from console encoding to utf8
935        return;
936
937    WorldDatabase.escape_string(location);
938    QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM game_tele WHERE name = '%s'",location.c_str());
939    if (!result)
940    {
941        zprintf(objmgr.GetMangosStringForDBCLocale(LANG_COMMAND_TELE_NOTFOUND),"\r\n");
942        return;
943    }
944
945    Field *fields = result->Fetch();
946    float x = fields[0].GetFloat();
947    float y = fields[1].GetFloat();
948    float z = fields[2].GetFloat();
949    float ort = fields[3].GetFloat();
950    int mapid = fields[4].GetUInt16();
951    delete result;
952
953    if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort))
954    {
955        zprintf(objmgr.GetMangosStringForDBCLocale(LANG_INVALID_TARGET_COORD),"\r\n",x,y,mapid);
956        return;
957    }
958
959    Player *chr = objmgr.GetPlayer(name.c_str());
960    if (chr)
961    {
962
963        if(chr->IsBeingTeleported()==true)
964        {
965            zprintf(objmgr.GetMangosStringForDBCLocale(LANG_IS_TELEPORTED),"\r\n",chr->GetName());
966            return;
967        }
968
969        if(chr->isInFlight())
970        {
971            zprintf(objmgr.GetMangosStringForDBCLocale(LANG_CHAR_IN_FLIGHT),"\r\n",chr->GetName());
972            return;
973        }
974
975        zprintf(objmgr.GetMangosStringForDBCLocale(LANG_TELEPORTING_TO),"\r\n",chr->GetName(),"", location.c_str());
976
977        chr->SaveRecallPosition();
978
979        chr->TeleportTo(mapid,x,y,z,chr->GetOrientation());
980    }
981    else if (uint64 guid = objmgr.GetPlayerGUIDByName(name.c_str()))
982    {
983        zprintf(objmgr.GetMangosStringForDBCLocale(LANG_TELEPORTING_TO),"\r\n",name.c_str(), objmgr.GetMangosStringForDBCLocale(LANG_OFFLINE), location.c_str());
984        Player::SavePositionInDB(mapid,x,y,z,ort,MapManager::Instance().GetZoneId(mapid,x,y),guid);
985    }
986    else
987        zprintf(objmgr.GetMangosStringForDBCLocale(LANG_NO_PLAYER),"\r\n",name.c_str());
988}
989
990/// Display/Define the 'Message of the day' for the realm
991void CliMotd(char*command,pPrintf zprintf)
992{
993
994    if (strlen(command) == 0)
995    {
996        zprintf("Current Message of the day: \r\n%s\r\n", sWorld.GetMotd());
997        return;
998    }
999    else
1000    {
1001        std::string commandUtf8;
1002        if(!consoleToUtf8(command,commandUtf8))             // convert from console encoding to utf8
1003            return;
1004
1005        sWorld.SetMotd(commandUtf8);
1006        zprintf("Message of the day changed to:\r\n%s\r\n", commandUtf8.c_str());
1007    }
1008}
1009
1010/// Comment me
1011/// \todo What is CorpsesErase for?
1012void CliCorpses(char*,pPrintf)
1013{
1014    CorpsesErase();
1015}
1016
1017/// Set the level of logging
1018void CliSetLogLevel(char*command,pPrintf zprintf)
1019{
1020    char *NewLevel = strtok(command, " ");
1021    if (!NewLevel)
1022    {
1023        zprintf("Syntax is: setloglevel $loglevel\r\n");
1024        return;
1025    }
1026    sLog.SetLogLevel(NewLevel);
1027}
1028
1029/// Display the server uptime
1030void CliUpTime(char*,pPrintf zprintf)
1031{
1032    uint32 uptime = sWorld.GetUptime();
1033    std::string suptime = secsToTimeString(uptime,true,(uptime > 86400));
1034    zprintf("Server has been up for: %s\r\n", suptime.c_str());
1035}
1036
1037/// Set/Unset the TBC flag for an account
1038void CliSetTBC(char *command,pPrintf zprintf)
1039{
1040    ///- Get the command line arguments
1041    char *szAcc = strtok(command," ");
1042    char *szTBC =  strtok(NULL," ");
1043
1044    if(!szAcc||!szTBC)
1045    {
1046        zprintf("Syntax is: setbc $account $number (0 - normal, 1 - tbc)>\r\n");
1047        return;
1048    }
1049
1050    int lev=atoi(szTBC);                                    //get int anyway (0 if error)
1051
1052    if((lev > 1)|| (lev < 0))
1053    {
1054        zprintf("Syntax is: setbc $account $number (0 - normal, 1 - tbc)>\r\n");
1055        return;
1056    }
1057
1058    ///- Escape the account name to allow quotes in names
1059    std::string safe_account_name;
1060    if(!consoleToUtf8(szAcc,safe_account_name))             // convert from console encoding to utf8
1061        return;
1062
1063    ///- Convert Account name to Upper Format
1064    AccountMgr::normilizeString(safe_account_name);
1065
1066    ///- Escape the account name to allow quotes in names
1067    loginDatabase.escape_string(safe_account_name);
1068
1069    // No SQL injection (account name is escaped)
1070    QueryResult *result = loginDatabase.PQuery("SELECT 1 FROM account WHERE username = '%s'",safe_account_name.c_str());
1071
1072    if (result)
1073    {
1074        // No SQL injection (account name is escaped)
1075        loginDatabase.PExecute("UPDATE account SET tbc = '%d' WHERE username = '%s'",lev,safe_account_name.c_str());
1076        zprintf("We set %s to expansion allowed %d\r\n",safe_account_name.c_str(),lev);
1077
1078        delete result;
1079    }
1080    else
1081    {
1082        zprintf("No account %s found\r\n",safe_account_name.c_str());
1083    }
1084}
1085
1086/// Save all players
1087void CliSave(char*,pPrintf zprintf)
1088{
1089    ///- Save players
1090    ObjectAccessor::Instance().SaveAllPlayers();
1091    zprintf( objmgr.GetMangosStringForDBCLocale(LANG_PLAYERS_SAVED) );
1092
1093    ///- Send a message
1094    sWorld.SendWorldText(LANG_PLAYERS_SAVED);
1095}
1096
1097/// Send a message to a player in game
1098void CliSend(char *playerN,pPrintf zprintf)
1099{
1100    ///- Get the command line arguments
1101    char* name_str = strtok((char*)playerN, " ");
1102    char* msg_str = strtok(NULL, "");
1103
1104    if(!name_str || !msg_str)
1105    {
1106        zprintf("Syntax: send $player $message (Player name is case sensitive)\r\n");
1107        return;
1108    }
1109
1110    std::string name;
1111    if(!consoleToUtf8(name_str,name))                       // convert from console encoding to utf8
1112        return;
1113
1114    std::string msg;
1115    if(!consoleToUtf8(msg_str,msg))             // convert from console encoding to utf8
1116        return;
1117
1118    if(!normalizePlayerName(name))
1119    {
1120        zprintf("Syntax: send $player $message (Player name is case sensitive)\r\n");
1121        return;
1122    }
1123
1124    ///- Find the player and check that he is not logging out.
1125    Player *rPlayer = objmgr.GetPlayer(name.c_str());
1126    if(!rPlayer)
1127    {
1128        zprintf("Player %s not found!\r\n", name.c_str());
1129        return;
1130    }
1131
1132    if (rPlayer->GetSession()->isLogingOut())
1133    {
1134        zprintf("Cannot send message while player %s is logging out!\r\n",name.c_str());
1135        return;
1136    }
1137
1138    ///- Send the message
1139    //Use SendAreaTriggerMessage for fastest delivery.
1140    rPlayer->GetSession()->SendAreaTriggerMessage("%s", msg.c_str());
1141    rPlayer->GetSession()->SendAreaTriggerMessage("|cffff0000[Message from administrator]:|r");
1142
1143    //Confirmation message
1144    zprintf("Message '%s' sent to %s\r\n",msg.c_str(), name.c_str());
1145}
1146
1147void CliPLimit(char *args,pPrintf zprintf)
1148{
1149    if(*args)
1150    {
1151        char* param = strtok((char*)args, " ");
1152        if(!param || !*param)
1153            return;
1154
1155        int l = strlen(param);
1156
1157        if(     strncmp(param,"player",l) == 0 )
1158            sWorld.SetPlayerLimit(-SEC_PLAYER);
1159        else if(strncmp(param,"moderator",l) == 0 )
1160            sWorld.SetPlayerLimit(-SEC_MODERATOR);
1161        else if(strncmp(param,"gamemaster",l) == 0 )
1162            sWorld.SetPlayerLimit(-SEC_GAMEMASTER);
1163        else if(strncmp(param,"administrator",l) == 0 )
1164            sWorld.SetPlayerLimit(-SEC_ADMINISTRATOR);
1165        else if(strncmp(param,"reset",l) == 0 )
1166            sWorld.SetPlayerLimit(sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT));
1167        else
1168        {
1169            int val = atoi(param);
1170            if(val < -SEC_ADMINISTRATOR) val = -SEC_ADMINISTRATOR;
1171
1172            sWorld.SetPlayerLimit(val);
1173        }
1174
1175        // kick all low security level players
1176        if(sWorld.GetPlayerAmountLimit() > SEC_PLAYER)
1177            sWorld.KickAllLess(sWorld.GetPlayerSecurityLimit());
1178    }
1179
1180    uint32 pLimit = sWorld.GetPlayerAmountLimit();
1181    AccountTypes allowedAccountType = sWorld.GetPlayerSecurityLimit();
1182    char const* secName = "";
1183    switch(allowedAccountType)
1184    {
1185        case SEC_PLAYER:        secName = "Player";        break;
1186        case SEC_MODERATOR:     secName = "Moderator";     break;
1187        case SEC_GAMEMASTER:    secName = "Gamemaster";    break;
1188        case SEC_ADMINISTRATOR: secName = "Administrator"; break;
1189        default:                secName = "<unknown>";     break;
1190    }
1191
1192    zprintf("Player limits: amount %u, min. security level %s.\r\n",pLimit,secName);
1193}
1194
1195/// @}
1196
1197#ifdef linux
1198// Non-blocking keypress detector, when return pressed, return 1, else always return 0
1199int kb_hit_return()
1200{
1201    struct timeval tv;
1202    fd_set fds;
1203    tv.tv_sec = 0;
1204    tv.tv_usec = 0;
1205    FD_ZERO(&fds);
1206    FD_SET(STDIN_FILENO, &fds);
1207    select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
1208    return FD_ISSET(STDIN_FILENO, &fds);
1209}
1210#endif
1211
1212/// %Thread start
1213void CliRunnable::run()
1214{
1215    ///- Init new SQL thread for the world database (one connection call enough)
1216    WorldDatabase.ThreadStart();                                // let thread do safe mySQL requests
1217
1218    char commandbuf[256];
1219
1220    ///- Display the list of available CLI functions then beep
1221    sLog.outString();
1222    /// \todo Shoudn't we use here also the sLog singleton?
1223    CliHelp(NULL,&UTF8ZPRINTF);
1224
1225    if(sConfig.GetBoolDefault("BeepAtStart", true))
1226    {
1227        printf("\a");                                       // \a = Alert
1228    }
1229
1230    // print this here the first time
1231    // later it will be printed after command queue updates
1232    printf("mangos>");
1233
1234    ///- As long as the World is running (no World::m_stopEvent), get the command line and handle it
1235    while (!World::m_stopEvent)
1236    {
1237        fflush(stdout);
1238        #ifdef linux
1239        while (!kb_hit_return() && !World::m_stopEvent)
1240            // With this, we limit CLI to 10commands/second
1241            usleep(100);
1242        if (World::m_stopEvent)
1243            break;
1244        #endif
1245        char *command = fgets(commandbuf,sizeof(commandbuf),stdin);
1246        if (command != NULL)
1247        {
1248            for(int x=0;command[x];x++)
1249                if(command[x]=='\r'||command[x]=='\n')
1250            {
1251                command[x]=0;
1252                break;
1253            }
1254            //// \todo Shoudn't we use here also the sLog singleton?
1255            ParseCommand(&UTF8ZPRINTF,command);
1256        }
1257        else if (feof(stdin))
1258        {
1259            World::m_stopEvent = true;
1260        }
1261    }
1262
1263    ///- End the database thread
1264    WorldDatabase.ThreadEnd();                                  // free mySQL thread resources
1265}
Note: See TracBrowser for help on using the browser.