[6830] Implement custom exit codes on server shutdown/restart
[getmangos.git] / src / mangosd / CliRunnable.cpp
blobd4c635660b2b7d2678fd248b4794faf28aa0df9d
1 /*
2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
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.
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.
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
19 /// \addtogroup mangosd
20 /// @{
21 /// \file
23 #include "Common.h"
24 #include "Language.h"
25 #include "Log.h"
26 #include "World.h"
27 #include "ScriptCalls.h"
28 #include "ObjectMgr.h"
29 #include "WorldSession.h"
30 #include "Config/ConfigEnv.h"
31 #include "Util.h"
32 #include "AccountMgr.h"
33 #include "CliRunnable.h"
34 #include "MapManager.h"
35 #include "Player.h"
36 #include "Chat.h"
38 void utf8print(const char* str)
40 #if PLATFORM == PLATFORM_WINDOWS
41 wchar_t wtemp_buf[6000];
42 size_t wtemp_len = 6000-1;
43 if(!Utf8toWStr(str,strlen(str),wtemp_buf,wtemp_len))
44 return;
46 char temp_buf[6000];
47 CharToOemBuffW(&wtemp_buf[0],&temp_buf[0],wtemp_len+1);
48 printf(temp_buf);
49 #else
50 printf(str);
51 #endif
54 /// Delete a user account and all associated characters in this realm
55 /// \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
56 bool ChatHandler::HandleAccountDeleteCommand(const char* args)
58 if(!*args)
59 return false;
61 ///- Get the account name from the command line
62 char *account_name_str=strtok ((char*)args," ");
63 if (!account_name_str)
64 return false;
66 std::string account_name = account_name_str;
67 if(!AccountMgr::normilizeString(account_name))
69 PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
70 SetSentErrorMessage(true);
71 return false;
74 uint32 account_id = accmgr.GetId(account_name);
75 if(!account_id)
77 PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
78 SetSentErrorMessage(true);
79 return false;
82 /// Commands not recommended call from chat, but support anyway
83 if(m_session)
85 uint32 targetSecurity = accmgr.GetSecurity(account_id);
87 /// can delete only for account with less security
88 /// This is also reject self apply in fact
89 if (targetSecurity >= m_session->GetSecurity())
91 SendSysMessage (LANG_YOURS_SECURITY_IS_LOW);
92 SetSentErrorMessage (true);
93 return false;
97 AccountOpResult result = accmgr.DeleteAccount(account_id);
98 switch(result)
100 case AOR_OK:
101 PSendSysMessage(LANG_ACCOUNT_DELETED,account_name.c_str());
102 break;
103 case AOR_NAME_NOT_EXIST:
104 PSendSysMessage(LANG_ACCOUNT_NOT_EXIST,account_name.c_str());
105 SetSentErrorMessage(true);
106 return false;
107 case AOR_DB_INTERNAL_ERROR:
108 PSendSysMessage(LANG_ACCOUNT_NOT_DELETED_SQL_ERROR,account_name.c_str());
109 SetSentErrorMessage(true);
110 return false;
111 default:
112 PSendSysMessage(LANG_ACCOUNT_NOT_DELETED,account_name.c_str());
113 SetSentErrorMessage(true);
114 return false;
117 return true;
120 bool ChatHandler::HandleCharacterDeleteCommand(const char* args)
122 if(!*args)
123 return false;
125 char *character_name_str = strtok((char*)args," ");
126 if(!character_name_str)
127 return false;
129 std::string character_name = character_name_str;
130 if(!normalizePlayerName(character_name))
131 return false;
133 uint64 character_guid;
134 uint32 account_id;
136 Player *player = objmgr.GetPlayer(character_name.c_str());
137 if(player)
139 character_guid = player->GetGUID();
140 account_id = player->GetSession()->GetAccountId();
141 player->GetSession()->KickPlayer();
143 else
145 character_guid = objmgr.GetPlayerGUIDByName(character_name);
146 if(!character_guid)
148 PSendSysMessage(LANG_NO_PLAYER,character_name.c_str());
149 SetSentErrorMessage(true);
150 return false;
153 account_id = objmgr.GetPlayerAccountIdByGUID(character_guid);
156 std::string account_name;
157 accmgr.GetName (account_id,account_name);
159 Player::DeleteFromDB(character_guid, account_id, true);
160 PSendSysMessage(LANG_CHARACTER_DELETED,character_name.c_str(),GUID_LOPART(character_guid),account_name.c_str(), account_id);
161 return true;
164 /// Exit the realm
165 bool ChatHandler::HandleServerExitCommand(const char* args)
167 SendSysMessage(LANG_COMMAND_EXIT);
168 World::StopNow(SHUTDOWN_EXIT_CODE);
169 return true;
172 /// Display info on users currently in the realm
173 bool ChatHandler::HandleAccountOnlineListCommand(const char* args)
175 ///- Get the list of accounts ID logged to the realm
176 QueryResult *resultDB = CharacterDatabase.Query("SELECT name,account FROM characters WHERE online > 0");
177 if (!resultDB)
178 return true;
180 ///- Display the list of account/characters online
181 SendSysMessage("=====================================================================");
182 SendSysMessage(LANG_ACCOUNT_LIST_HEADER);
183 SendSysMessage("=====================================================================");
185 ///- Circle through accounts
188 Field *fieldsDB = resultDB->Fetch();
189 std::string name = fieldsDB[0].GetCppString();
190 uint32 account = fieldsDB[1].GetUInt32();
192 ///- Get the username, last IP and GM level of each account
193 // No SQL injection. account is uint32.
194 // 0 1 2 3
195 QueryResult *resultLogin = loginDatabase.PQuery("SELECT username, last_ip, gmlevel, expansion FROM account WHERE id = '%u'",account);
197 if(resultLogin)
199 Field *fieldsLogin = resultLogin->Fetch();
200 PSendSysMessage("|%15s| %20s | %15s |%4d|%5d|",
201 fieldsLogin[0].GetString(),name.c_str(),fieldsLogin[1].GetString(),fieldsLogin[2].GetUInt32(),fieldsLogin[3].GetUInt32());
203 delete resultLogin;
205 else
206 PSendSysMessage(LANG_ACCOUNT_LIST_ERROR,name.c_str());
208 }while(resultDB->NextRow());
210 delete resultDB;
212 SendSysMessage("=====================================================================");
213 return true;
216 /// Create an account
217 bool ChatHandler::HandleAccountCreateCommand(const char* args)
219 if(!*args)
220 return false;
222 ///- %Parse the command line arguments
223 char *szAcc = strtok((char*)args, " ");
224 char *szPassword = strtok(NULL, " ");
225 if(!szAcc || !szPassword)
226 return false;
228 // normilized in accmgr.CreateAccount
229 std::string account_name = szAcc;
230 std::string password = szPassword;
232 AccountOpResult result = accmgr.CreateAccount(account_name, password);
233 switch(result)
235 case AOR_OK:
236 PSendSysMessage(LANG_ACCOUNT_CREATED,account_name.c_str());
237 break;
238 case AOR_NAME_TOO_LONG:
239 SendSysMessage(LANG_ACCOUNT_TOO_LONG);
240 SetSentErrorMessage(true);
241 return false;
242 case AOR_NAME_ALREDY_EXIST:
243 SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST);
244 SetSentErrorMessage(true);
245 return false;
246 case AOR_DB_INTERNAL_ERROR:
247 PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR,account_name.c_str());
248 SetSentErrorMessage(true);
249 return false;
250 default:
251 PSendSysMessage(LANG_ACCOUNT_NOT_CREATED,account_name.c_str());
252 SetSentErrorMessage(true);
253 return false;
256 return true;
259 /// Set the level of logging
260 bool ChatHandler::HandleServerSetLogLevelCommand(const char *args)
262 if(!*args)
263 return false;
265 char *NewLevel = strtok((char*)args, " ");
266 if (!NewLevel)
267 return false;
269 sLog.SetLogLevel(NewLevel);
270 return true;
273 /// @}
275 #ifdef linux
276 // Non-blocking keypress detector, when return pressed, return 1, else always return 0
277 int kb_hit_return()
279 struct timeval tv;
280 fd_set fds;
281 tv.tv_sec = 0;
282 tv.tv_usec = 0;
283 FD_ZERO(&fds);
284 FD_SET(STDIN_FILENO, &fds);
285 select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
286 return FD_ISSET(STDIN_FILENO, &fds);
288 #endif
290 /// %Thread start
291 void CliRunnable::run()
293 ///- Init new SQL thread for the world database (one connection call enough)
294 WorldDatabase.ThreadStart(); // let thread do safe mySQL requests
296 char commandbuf[256];
298 ///- Display the list of available CLI functions then beep
299 sLog.outString();
301 if(sConfig.GetBoolDefault("BeepAtStart", true))
302 printf("\a"); // \a = Alert
304 // print this here the first time
305 // later it will be printed after command queue updates
306 printf("mangos>");
308 ///- As long as the World is running (no World::m_stopEvent), get the command line and handle it
309 while (!World::IsStopped())
311 fflush(stdout);
312 #ifdef linux
313 while (!kb_hit_return() && !World::IsStopped())
314 // With this, we limit CLI to 10commands/second
315 usleep(100);
316 if (World::IsStopped())
317 break;
318 #endif
319 char *command_str = fgets(commandbuf,sizeof(commandbuf),stdin);
320 if (command_str != NULL)
322 for(int x=0;command_str[x];x++)
323 if(command_str[x]=='\r'||command_str[x]=='\n')
325 command_str[x]=0;
326 break;
330 if(!*command_str)
332 printf("mangos>");
333 continue;
336 std::string command;
337 if(!consoleToUtf8(command_str,command)) // convert from console encoding to utf8
339 printf("mangos>");
340 continue;
343 sWorld.QueueCliCommand(&utf8print,command.c_str());
345 else if (feof(stdin))
347 World::StopNow(SHUTDOWN_EXIT_CODE);
351 ///- End the database thread
352 WorldDatabase.ThreadEnd(); // free mySQL thread resources