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

Revision 78, 40.5 kB (checked in by yumileroy, 17 years ago)

[svn] * fixed help for subcommands - source mangos
* Renamed accounts column tbc to expansion and it only took a little over 4 hours o.O

Original author: KingPin?
Date: 2008-10-20 12:23:56-05:00

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