From 054725122f1ef534063ffcbc54b25e167ec3ed9c Mon Sep 17 00:00:00 2001 From: XTZGZoReX Date: Sun, 12 Oct 2008 14:03:38 -0500 Subject: [svn] * Various small changes here and there. * Implementing MangChat IRC system. * Added new config option, MAX_WHO, can be used to set the limit of characters being sent in a /who request from client. --HG-- branch : trunk --- src/game/AuctionHouse.cpp | 4 + src/game/Channel.cpp | 12 +- src/game/Chat.cpp | 1 + src/game/Chat.h | 2 + src/game/ChatHandler.cpp | 3 + src/game/GameEvent.cpp | 9 + src/game/IRCClient.cpp | 91 ++ src/game/IRCClient.h | 230 ++++ src/game/IRCCmd.cpp | 827 +++++++++++++++ src/game/IRCCmd.h | 117 ++ src/game/IRCCmde.cpp | 1884 +++++++++++++++++++++++++++++++++ src/game/IRCConf.cpp | 172 +++ src/game/IRCConf.h | 16 + src/game/IRCConf.h.in | 16 + src/game/IRCFunc.h | 251 +++++ src/game/IRCIO.cpp | 436 ++++++++ src/game/IRCLog.cpp | 60 ++ src/game/IRCLog.h | 22 + src/game/IRCSock.cpp | 146 +++ src/game/Language.h | 2 + src/game/Level1.cpp | 35 + src/game/MCS_OnlinePlayers.cpp | 84 ++ src/game/MCS_OnlinePlayers.h | 27 + src/game/Makefile.am | 15 + src/game/MiscHandler.cpp | 5 +- src/game/Player.cpp | 14 + src/game/World.cpp | 36 +- src/game/World.h | 9 +- src/shared/Database/DBCStructure.h | 1 + src/shared/Database/DBCfmt.cpp | 3 +- src/shared/Makefile.am | 1 + src/trinitycore/CliRunnable.cpp | 9 + src/trinitycore/Main.cpp | 6 +- src/trinitycore/Master.cpp | 10 + src/trinitycore/trinitycore.conf.dist | 193 ++++ 35 files changed, 4733 insertions(+), 16 deletions(-) create mode 100644 src/game/IRCClient.cpp create mode 100644 src/game/IRCClient.h create mode 100644 src/game/IRCCmd.cpp create mode 100644 src/game/IRCCmd.h create mode 100644 src/game/IRCCmde.cpp create mode 100644 src/game/IRCConf.cpp create mode 100644 src/game/IRCConf.h create mode 100644 src/game/IRCConf.h.in create mode 100644 src/game/IRCFunc.h create mode 100644 src/game/IRCIO.cpp create mode 100644 src/game/IRCLog.cpp create mode 100644 src/game/IRCLog.h create mode 100644 src/game/IRCSock.cpp create mode 100644 src/game/MCS_OnlinePlayers.cpp create mode 100644 src/game/MCS_OnlinePlayers.h (limited to 'src') diff --git a/src/game/AuctionHouse.cpp b/src/game/AuctionHouse.cpp index 9b527400b04..b6eda29ac26 100644 --- a/src/game/AuctionHouse.cpp +++ b/src/game/AuctionHouse.cpp @@ -26,6 +26,7 @@ #include "UpdateMask.h" #include "AuctionHouseObject.h" #include "Util.h" +#include "IRCClient.h" //please DO NOT use iterator++, because it is slower than ++iterator!!! //post-incrementation is always slower than pre-incrementation ! @@ -313,6 +314,9 @@ void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data ) pl->SaveInventoryAndGoldToDB(); CharacterDatabase.CommitTransaction(); + if((sIRC.BOTMASK & 1024) != 0) + sIRC.AHFunc(it->GetEntry(), it->GetProto()->Name1, pl->GetName(), location); + SendAuctionCommandResult(AH->Id, AUCTION_SELL_ITEM, AUCTION_OK); } diff --git a/src/game/Channel.cpp b/src/game/Channel.cpp index 0fff8c7854b..a6a97a61656 100644 --- a/src/game/Channel.cpp +++ b/src/game/Channel.cpp @@ -20,6 +20,7 @@ #include "ObjectMgr.h" #include "World.h" #include "SocialMgr.h" +#include "IRCClient.h" Channel::Channel(std::string name, uint32 channel_id) : m_name(name), m_announce(true), m_moderate(false), m_channelId(channel_id), m_ownerGUID(0), m_password(""), m_flags(0) @@ -112,14 +113,9 @@ void Channel::Join(uint64 p, const char *pass) MakeYouJoined(&data); SendToOne(&data, p); - JoinNotify(p); + sIRC.Handle_WoW_Channel(m_name, objmgr.GetPlayer(p), CHANNEL_JOIN); - // if no owner first logged will become - if(!IsConstant() && !m_ownerGUID) - { - SetOwner(p, (players.size() > 1 ? true : false)); - players[p].SetModerator(true); - } + JoinNotify(p); } void Channel::Leave(uint64 p, bool send) @@ -159,6 +155,8 @@ void Channel::Leave(uint64 p, bool send) LeaveNotify(p); + sIRC.Handle_WoW_Channel(m_name, objmgr.GetPlayer(p), CHANNEL_LEAVE); + if(changeowner) { uint64 newowner = !players.empty() ? players.begin()->second.player : 0; diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index b8e12a5a8b1..ad588c5a18d 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -456,6 +456,7 @@ ChatCommand * ChatHandler::getCommandTable() { "movegens", SEC_ADMINISTRATOR, &ChatHandler::HandleMovegensCommand, "", NULL }, { "cometome", SEC_ADMINISTRATOR, &ChatHandler::HandleComeToMeCommand, "", NULL }, { "damage", SEC_ADMINISTRATOR, &ChatHandler::HandleDamageCommand, "", NULL }, + { "ircpm", SEC_PLAYER, &ChatHandler::HandleIRCpmCommand, "", NULL }, { "combatstop", SEC_GAMEMASTER, &ChatHandler::HandleCombatStopCommand, "", NULL }, { "flusharenapoints", SEC_ADMINISTRATOR, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL }, diff --git a/src/game/Chat.h b/src/game/Chat.h index ff0eac2caa6..28920c4d112 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -108,6 +108,8 @@ class ChatHandler bool HandleGroupTeleCommand(const char* args); bool HandleDrunkCommand(const char* args); + bool HandleIRCpmCommand(const char* args); + bool HandleEventActiveListCommand(const char* args); bool HandleEventStartCommand(const char* args); bool HandleEventStopCommand(const char* args); diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index 80935be78c6..8ccf6788388 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -34,6 +34,7 @@ #include "Player.h" #include "SpellAuras.h" #include "Language.h" +#include "IRCClient.h" #include "Util.h" void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) @@ -427,6 +428,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data ) if(msg.empty()) break; + sIRC.Send_WoW_IRC(_player, channel, msg); + if(ChannelMgr* cMgr = channelMgr(_player->GetTeam())) { if(Channel *chn = cMgr->GetChannel(channel,_player)) diff --git a/src/game/GameEvent.cpp b/src/game/GameEvent.cpp index e36cb6caae8..5380acf6ace 100644 --- a/src/game/GameEvent.cpp +++ b/src/game/GameEvent.cpp @@ -24,6 +24,7 @@ #include "Log.h" #include "MapManager.h" #include "Policies/SingletonImp.h" +#include "IRCClient.h" INSTANTIATE_SINGLETON_1(GameEvent); @@ -421,6 +422,14 @@ void GameEvent::ApplyNewEvent(uint16 event_id) } sLog.outString("GameEvent %u \"%s\" started.", event_id, mGameEvent[event_id].description.c_str()); + + if((sIRC.BOTMASK & 256) != 0) + { + std::string ircchan = "#"; + ircchan += sIRC._irc_chan[sIRC.anchn].c_str(); + sIRC.Send_IRC_Channel(ircchan, sIRC.MakeMsg("\00304,08\037/!\\\037\017\00304 Game Event \00304,08\037/!\\\037\017 %s", "%s", mGameEvent[event_id].description.c_str()), true); + } + // spawn positive event tagget objects GameEventSpawn(event_id); // un-spawn negative event tagged objects diff --git a/src/game/IRCClient.cpp b/src/game/IRCClient.cpp new file mode 100644 index 00000000000..0cd6e7d5dcf --- /dev/null +++ b/src/game/IRCClient.cpp @@ -0,0 +1,91 @@ +/* + * MangChat By |Death| And Cybrax + * + * This Program Is Free Software; You Can Redistribute It And/Or Modify It Under The Terms + * Of The GNU General Public License + * Written and Developed by Cybrax. cybraxvd@gmail.com + * |Death| , Lice , Dj_baby & Sanaell, Tase + * With Help And Support From The MaNGOS Project Community. + * PLEASE RETAIN THE COPYRIGHT OF THE AUTHORS. + */ +#include "IRCClient.h" +#include "World.h" +#include "ObjectMgr.h" +#include "MapManager.h" + +#include "Policies/SingletonImp.h" +INSTANTIATE_SINGLETON_1( IRCClient ); + +#ifdef WIN32 + #define Delay(x) Sleep(x) +#else + #define Delay(x) sleep(x / 1000) +#endif +// IRCClient Constructor +IRCClient::IRCClient() +{ + for(int i = 0;i > 5;i++) + sIRC.Script_Lock[i] = false; +} +// IRCClient Destructor +IRCClient::~IRCClient(){} + +// ZThread Entry This function is called when the thread is created in Master.cpp (mangosd) +void IRCClient::run() +{ + sIRC.iLog.WriteLog(" %s : IRC bot started.", sIRC.iLog.GetLogDateTimeStr().c_str()); + + // before we begin we wait a few + // mangos is still starting up. + ZThread::Thread::sleep(500); + int cCount = 0; + // Clean Up MySQL Tables + sLog.outString("Cleaning up IRC_Inchan table..."); + WorldDatabase.PExecute("DELETE FROM `IRC_Inchan`"); + sIRC._Max_Script_Inst = 0; + // Create a loop to keep the thread running untill active is set to false + while(sIRC.Active && !World::m_stopEvent) + { + // Initialize socket library + if(this->InitSock()) + { + // Connect To The IRC Server + sLog.outString("IRC: Connecting to %s Try # %d ******", sIRC._Host.c_str(), cCount); + if(this->Connect(sIRC._Host.c_str(), sIRC._Port)) + { + // On connection success reset the connection counter + cCount = 0; + sLog.outString("IRC connected and logging in"); + // Login to the IRC server + if(this->Login(sIRC._Nick, sIRC._User, sIRC._Pass)) + { + sLog.outString("IRC logged in and running"); + // While we are connected to the irc server keep listening for data on the socket + while(sIRC.Connected && !World::m_stopEvent){ sIRC.SockRecv(); } + } + sLog.outString("Connection to IRC server lost!"); + } + // When an error occures or connection lost cleanup + Disconnect(); + // Increase the connection counter + cCount++; + // if MAX_CONNECT_ATTEMPT is reached stop trying + if(sIRC._MCA != 0 && cCount == sIRC._MCA) + sIRC.Active = false; + // If we need to reattempt a connection wait WAIT_CONNECT_TIME milli seconds before we try again + if(sIRC.Active) + ZThread::Thread::sleep(sIRC._wct); + } + else + { + // Socket could not initialize cancel + sIRC.Active = false; + sLog.outError("IRC: Could not initialize socket"); + } + } + // we need to keep the thread alive or mangos will crash + // when sending chat or join/leave channels. + // even when we are not connected the functions must still + // be availlable where chat is sent to so we keep it running + while(!World::m_stopEvent){}; +} diff --git a/src/game/IRCClient.h b/src/game/IRCClient.h new file mode 100644 index 00000000000..31e7b9fbba9 --- /dev/null +++ b/src/game/IRCClient.h @@ -0,0 +1,230 @@ +#ifndef _IRC_CLIENT_H +#define _IRC_CLIENT_H + +#include "Policies/Singleton.h" +#include "Player.h" +#include "IRCLog.h" +#include "IRCCmd.h" + +using namespace std; +// The maximum ammount of channels used +// in the channel array you can have as much channels as you +// want, but it is important to always have at least equal or more +// channels then you specify in your mangosd.conf +#define MAX_CONF_CHANNELS 10 +#define MAX_CHAT_LINES 10 +// time we need to wait before we try another connecton attempt +// Default is 30 seconds +#define MAX_SCRIPT_INST 10 +// CLINES is used for the default chatlines +// By using the GetChatLine function its easier and faster +// to receieve the line you need. +enum CLINES +{ + IRC_WOW = 0, + WOW_IRC = 1, + JOIN_WOW = 2, + JOIN_IRC = 3, + LEAVE_WOW = 4, + LEAVE_IRC = 5, + CHANGE_NICK = 6 +}; // Chatlines +// CACTION is used by the Handle_WoW_Channel function +// this function is called in channel.h when a player +// joins or leave a channel inside the client. +enum CACTION +{ + CHANNEL_JOIN, + CHANNEL_LEAVE, +}; + +enum script_Names +{ + MCS_Players_Online = 0, +}; + +// IRCClient main class +class IRCClient : public ZThread::Runnable +{ + public: + // IRCClient Constructor + IRCClient(); + // IRCClient Destructor + ~IRCClient(); + // ZThread Entry + void run(); + public: + // AH Function + void AHFunc(uint64 itmid, std::string itmnme, std::string plname, uint32 faction); + // IRCClient active + bool Active; + // Connected to IRC + bool Connected; + // Socket indentifier + int SOCKET; + fd_set sfdset; + // Send data to IRC, in addition the endline is added \n + bool SendIRC(std::string data); + // This function is called in ChatHandler.cpp and processes the chat from game to IRC + void Send_WoW_IRC(Player *plr, std::string Channel, std::string Msg); + // Sends a message to all players on the specified channel + void Send_WoW_Channel(const char *channel, std::string chat); + // Send a system message to all players + void Send_WoW_System(std::string Message); + // Send a message to the specified IRC channel + void Send_IRC_Channel(std::string sChannel, std::string sMsg, bool NoPrefix = false, std::string nType = "PRIVMSG"); + // Sends a message to all IRC Channels + void Send_IRC_Channels(std::string sMsg); + std::string MakeMsg(std::string msg, std::string var, std::string val) + { + std::size_t start = msg.find(var); + if (start != std::string::npos) + msg.replace(start, var.length(), val); + return msg; + } + void Send_WoW_Player(string sPlayer, string sMsg); + void Send_WoW_Player(Player *plr, string sMsg); + + // This function is called in Channel.cpp and processes Join/leave messages + void Handle_WoW_Channel(std::string Channel, Player *plr, int nAction); + void ResetIRC(); + public: + void AutoJoinChannel(Player *plr); + + public: + bool Script_Lock[5]; + bool _AmiOp; + + public: + string _Mver; + // IRC Server host + string _Host; + // IRC Server Port + int _Port; + // IRC Username + string _User; + // IRC Password + string _Pass; + // IRC Nickname + string _Nick; + // Authentication type + int _Auth; + string _Auth_Nick; + // IRC Connect code + string _ICC; + // IRC Default channel + string _defchan; + // IRC Leave Default channel + int _ldefc; + // Wait Connect Time + int _wct; + // BotMask Options + int Botmask; + // Status Channel + int Status; + // Announce Channel + int anchn; + int autoanc; + // IRC Channel count + int _chan_count; + // IRC Channel list + // Array to store our IRC channels + // each element will corrospond + // with _wow_chan array below. + std::string _irc_chan[MAX_CONF_CHANNELS]; + // Game Channel list + std::string _wow_chan[MAX_CONF_CHANNELS]; + // AutoJoin Options + int ajoin; + string ajchan; + // Online Command Max Results + int onlrslt; + // Channel OnJoin/Restart/Kick Messages + string JoinMsg; + string RstMsg; + string kikmsg; + // Misc Options + string ojGM1; + string ojGM2; + string ojGM3; + string ojGM4; + string ojGM5; + string logfile; + int games; + int gmlog; + // IRC Commands Security Level + int CACCT; + int CBAN; + int CCHAN; + int CCHAR; + int CFUN; + int CHELP; + int CINCHAN; + int CINFO; + int CITEM; + int CJAIL; + int CKICK; + int _KILL; + int CLEVEL; + int CLOOKUP; + int CMONEY; + int CMUTE; + int CONLINE; + int CPM; + int CRESTART; + int CREVIVE; + int CSAVEALL; + int CSHUTDOWN; + int CSPELL; + int CSYSMSG; + int CTELE; + int CTOP; + int CWHO; + // BotMask + int BOTMASK; + // Max connect attempt + int _MCA; + // Auto rejoin when kicked from irc + int _autojoinkick; + // IRC Command prefix + string _cmd_prefx; + int _op_gm; + int _op_gm_lev; + // Array that contains our chatlines from the conf file + // To increase this value change the MAX_CHAT_LINE define above + // Make sure the number of elements must match your items + // (remeber this starts at 0 so 0..9 is 10 items) + // and that you load the line in the LoadConfig function. + string ILINES[MAX_CHAT_LINES]; + string GetChatLine(int nItem); + + int _Max_Script_Inst; + // MAX_SCRIPT_INST + + IRCLog iLog; + +public: + // Load MangChat configuration file + bool LoadConfig(char const* cfgfile); + void SetCfg(char const* cfgfile); + char const* CfgFile; + +private: + // Returns default chatline based on enum CLINES + // Initialize socket library + bool InitSock(); + // Connect to IRC Server + bool Connect(const char *cHost, int nPort); + // Login to IRC Server + bool Login(std::string sNick, std::string sUser, std::string sPass); + // Send raw data to IRC + bool SendData(const char *data); + // Disconnect from IRC and cleanup socket + void Disconnect(); + // Processes the data receieved from IRC + void Handle_IRC(std::string sData); + // Receieves data from the socket. + void SockRecv(); +}; +#endif +#define sIRC MaNGOS::Singleton::Instance() diff --git a/src/game/IRCCmd.cpp b/src/game/IRCCmd.cpp new file mode 100644 index 00000000000..62e5e565d75 --- /dev/null +++ b/src/game/IRCCmd.cpp @@ -0,0 +1,827 @@ +/* + * MangChat By |Death| And Cybrax + * + * This Program Is Free Software; You Can Redistribute It And/Or Modify It Under The Terms + * Of The GNU General Public License + * Written and Developed by Cybrax. cybraxvd@gmail.com + * |Death| , Lice , Dj_baby & Sanaell, Tase + * With Help And Support From The MaNGOS Project Community. + * PLEASE RETAIN THE COPYRIGHT OF THE AUTHORS. + */ +#include "IRCCmd.h" +#include "IRCClient.h" +#include "Database/DatabaseEnv.h" +#include "ObjectMgr.h" +#include "MapManager.h" +// Constructor +IRCCmd::IRCCmd(){} +// Destructor +IRCCmd::~IRCCmd(){} + +std::string IRCCmd::MakeUpper(std::string Channel) +{ + std::string tmpchan = Channel; + std::transform(tmpchan.begin(), tmpchan.end(), tmpchan.begin(), towupper); + return tmpchan; +} +bool IRCCmd::ParamsValid(_CDATA *CD, int pCnt) +{ + CD->PCOUNT = pCnt; + if(CD->PARAMS.size() == 0) + return false; + return ValidParams(CD->PARAMS, pCnt); +} + +int IRCCmd::ParamsValid(_CDATA *CD, int pCnt, int rLev) +{ + //CD->PCOUNT = pCnt; + if(!CanUse(CD->USER, rLev)) + return E_AUTH; + else if(pCnt == 0) + return E_OK; + else if(CD->PARAMS.size() == 0) + return E_SIZE; + else if(!ValidParams(CD->PARAMS, pCnt)) + return E_SIZE; + return E_OK; +} + +// This function checks if chat from irc is a command or not +// return true on yes and false on no +bool IRCCmd::IsValid(std::string USER, std::string FROM, std::string CHAT, std::string TYPE) +{ + // If the first line of our chat is the command prefix we have a command + if(CHAT.substr(0, 1) == sIRC._cmd_prefx && CHAT.size() > 1 ) + { + _CDATA CDATA; + bool cValid = false; + bool AuthValid = true; + bool dontlog = true; + std::string* _PARAMS = getArray(CHAT, 2); + CDATA.USER = USER; + CDATA.FROM = FROM; + CDATA.TYPE = TYPE; + CDATA.PCOUNT = 0; + CDATA.CMD = MakeUpper(_PARAMS[0].substr(1, _PARAMS[0].size() - 1)); + CDATA.PARAMS = _PARAMS[1]; + if(CDATA.CMD == "LOGIN") + { + if(FROM == sIRC._Nick) + { + if(ParamsValid(&CDATA, 2)) + Handle_Login(&CDATA); + else + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"login )", true, "ERROR"); + } + else + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Please Send A PM To Login!", true, "ERROR"); + if(GetLevel(USER) >= sIRC.gmlog) + dontlog = false; + cValid = true; + } + else if(CDATA.CMD == "LOGOUT") + { + if(FROM == sIRC._Nick) + { + Handle_Logout(&CDATA); + } + else + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Please Send A PM To Logout!", true, "ERROR"); + cValid = true; + } + else if(CDATA.CMD == "ACCT") + { + switch(ParamsValid(&CDATA, 2, sIRC.CACCT)) + { + case E_OK: + Account_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"acct <(un)lock/mail/pass/rename> )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "BAN") + { + switch(ParamsValid(&CDATA, 2, sIRC.CBAN)) + { + case E_OK: + Ban_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"ban )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "CHAN") + { + switch(ParamsValid(&CDATA, 1, sIRC.CCHAN)) + { + case E_OK: + Chan_Control(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"chan )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "CHAR") + { + switch(ParamsValid(&CDATA, 2, sIRC.CCHAR)) + { + case E_OK: + Char_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"char )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "FUN") + { + switch(ParamsValid(&CDATA, 2, sIRC.CFUN)) + { + case E_OK: + Fun_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"fun )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "HELP") + { + switch(ParamsValid(&CDATA, 0, sIRC.CHELP)) + { + case E_OK: + Help_IRC(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"help )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "INCHAN") + { + switch(ParamsValid(&CDATA, 1, sIRC.CINCHAN)) + { + case E_OK: + Inchan_Server(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"inchan )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "INFO") + { + switch(ParamsValid(&CDATA, 0, sIRC.CINFO)) + { + case E_OK: + Info_Server(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"info )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "ITEM") + { + CDATA.PCOUNT = 3; + switch(ParamsValid(&CDATA, 2, sIRC.CITEM)) + { + case E_OK: + Item_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"item )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "JAIL") + { + CDATA.PCOUNT = 3; + switch(ParamsValid(&CDATA, 1, sIRC.CJAIL)) + { + case E_OK: + Jail_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"jail )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "KICK") + { + CDATA.PCOUNT = 2; + switch(ParamsValid(&CDATA, 1, sIRC.CKICK)) + { + case E_OK: + Kick_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"kick )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "KILL") + { + CDATA.PCOUNT = 2; + switch(ParamsValid(&CDATA, 1, sIRC._KILL)) + { + case E_OK: + Kill_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"kill )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "LEVEL") + { + CDATA.PCOUNT = 2; + switch(ParamsValid(&CDATA, 2, sIRC.CLEVEL)) + { + case E_OK: + Level_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"level )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "LOOKUP") + { + CDATA.PCOUNT = 2; + switch(ParamsValid(&CDATA, 2, sIRC.CLOOKUP)) + { + case E_OK: + Lookup_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"lookup )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "MONEY") + { + CDATA.PCOUNT = 2; + switch(ParamsValid(&CDATA, 2, sIRC.CMONEY)) + { + case E_OK: + Money_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"money <(-)Money> )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "MUTE") + { + switch(ParamsValid(&CDATA, 2, sIRC.CMUTE)) + { + case E_OK: + Mute_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"mute )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "ONLINE") + { + switch(ParamsValid(&CDATA, 0, sIRC.CONLINE)) + { + case E_OK: + Online_Players(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"online )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "PM") + { + switch(ParamsValid(&CDATA, 2, sIRC.CPM)) + { + case E_OK: + PM_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"pm )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "RELOAD") + { + switch(ParamsValid(&CDATA, 0, sIRC.CRESTART)) + { + case E_OK: + sIRC.Send_IRC_Channels("Reloading MangChat Config Options. (Command Disabled)"); + //sIRC.LoadConfig(); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "RESTART") + { + switch(ParamsValid(&CDATA, 0, sIRC.CRESTART)) + { + case E_OK: + sIRC.Send_IRC_Channels(sIRC.RstMsg); + sIRC.ResetIRC(); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "REVIVE") + { + CDATA.PCOUNT = 2; + switch(ParamsValid(&CDATA, 1, sIRC.CREVIVE)) + { + case E_OK: + Revive_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"revive )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "SAVEALL") + { + switch(ParamsValid(&CDATA, 0, sIRC.CSAVEALL)) + { + case E_OK: + Saveall_Player(&CDATA); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "SHUTDOWN") + { + switch(ParamsValid(&CDATA, 1, sIRC.CSHUTDOWN)) + { + case E_OK: + Shutdown_Mangos(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"shutdown )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "SPELL") + { + switch(ParamsValid(&CDATA, 2, sIRC.CSPELL)) + { + case E_OK: + Spell_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"spell )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "SYSMSG") + { + CDATA.PCOUNT = 2; + switch(ParamsValid(&CDATA, 2, sIRC.CSYSMSG)) + { + case E_OK: + Sysmsg_Server(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"sysmsg )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "TELE") + { + switch(ParamsValid(&CDATA, 2, sIRC.CTELE)) + { + case E_OK: + Tele_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"tele )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "TOP") + { + CDATA.PCOUNT = 1; + switch(ParamsValid(&CDATA, 1, sIRC.CTOP)) + { + case E_OK: + Top_Player(&CDATA); + break; + case E_SIZE: + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"top )", true, "ERROR"); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + else if(CDATA.CMD == "WHO") + { + switch(ParamsValid(&CDATA, 0, sIRC.CWHO)) + { + case E_OK: + Who_Logged(&CDATA); + break; + case E_AUTH: + AuthValid = false; + break; + } + cValid = true; + } + if(!AuthValid && IsLoggedIn(USER)) + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Access Denied! Your Security Level Is Too Low To Use This Command!", true, "ERROR"); + if(cValid == false && (sIRC.BOTMASK & 4) != 0) + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : Unknown Command!", true, "ERROR"); + if(cValid && dontlog) + { + sIRC.iLog.WriteLog(" %s : [ %s(%d) ] Used Command: [ %s ] With Parameters: [ %s ]", sIRC.iLog.GetLogDateTimeStr().c_str(), CDATA.USER.c_str(), GetLevel(USER), CDATA.CMD.c_str(), CDATA.PARAMS.c_str()); + } + return cValid; + } + return false; +} + +bool IRCCmd::CanUse(std::string USER, int nLevel) +{ + if(IsLoggedIn(USER)) + { + if(GetLevel(USER) >= nLevel) + return true; + else + return false; + } + else if(nLevel == 0) + { + return true; + } + else + sIRC.Send_IRC_Channel(USER, "\0034[ERROR] : You Are Not Logged In!", true, "ERROR"); + return false; +} + +std::string IRCCmd::ChanOrPM(_CDATA *CD) +{ + if(CD->FROM == sIRC._Nick) + return CD->USER; + else + return CD->FROM; +} + +Player *IRCCmd::GetPlayer(std::string WHO) +{ + normalizePlayerName(WHO); + return ObjectAccessor::Instance().FindPlayerByName(WHO.c_str()); +} + +_client *IRCCmd::GetClient(std::string cname) +{ + for(std::list<_client*>::iterator i=_CLIENTS.begin(); i!=_CLIENTS.end();i++) + { + if((*i)->Name == cname) + return (*i); + } + return (NULL); +} + +bool IRCCmd::IsLoggedIn(std::string USER) +{ + for(std::list<_client*>::iterator i=_CLIENTS.begin(); i!=_CLIENTS.end();i++) + { + if((*i)->Name == USER) + return true; + } + return false; +} + +bool IRCCmd::AcctIsLoggedIn(std::string USER) +{ + for(std::list<_client*>::iterator i=_CLIENTS.begin(); i!=_CLIENTS.end();i++) + { + if(MakeUpper((*i)->UName) == MakeUpper(USER)) + return true; + } + return false; +} + +std::string IRCCmd::AcctIsBanned(std::string ACCT) +{ + uint32 acctid = objmgr.GetAccountByAccountName(ACCT); + std::string banned = "NOTBANNED"; + QueryResult *result = loginDatabase.PQuery("SELECT banreason FROM ip_banned WHERE ip=(SELECT last_ip FROM account WHERE id = '%i')", acctid); + if(result) + { + banned = (*result)[0].GetCppString(); + delete result; + return "IP Banned. Reason:" + banned; + } + QueryResult *result2 = loginDatabase.PQuery("SELECT banreason FROM account_banned WHERE id='%i'", acctid); + if(result2) + { + banned = (*result2)[0].GetCppString(); + delete result2; + return "Account Banned. Reason:" + banned; + } + return banned; +} + +int IRCCmd::GetLevel(std::string sName) +{ + for(std::list<_client*>::iterator i=_CLIENTS.begin(); i!=_CLIENTS.end();i++) + { + if((*i)->Name == sName) + return (*i)->GMLevel; + } + return 0; +} + +int IRCCmd::AcctLevel(std::string plnme) +{ + uint64 guid = objmgr.GetPlayerGUIDByName(plnme); + uint32 account_id = 0; + uint32 security = 0; + account_id = objmgr.GetPlayerAccountIdByGUID(guid); + security = objmgr.GetSecurityByAccount(account_id); + return security; +} + +std::string IRCCmd::GetAccName(std::string sName) +{ + for(std::list<_client*>::iterator i=_CLIENTS.begin(); i!=_CLIENTS.end();i++) + { + if((*i)->Name == sName) + return (*i)->UName; + } + return ""; +} + +std::string IRCCmd::GetNameFromAcct(std::string sName) +{ + for(std::list<_client*>::iterator i=_CLIENTS.begin(); i!=_CLIENTS.end();i++) + { + if((*i)->UName == sName) + return (*i)->Name; + } + return ""; +} + +int IRCCmd::GetAcctIDFromName(std::string sName) +{ + for(std::list<_client*>::iterator i=_CLIENTS.begin(); i!=_CLIENTS.end();i++) + { + if((*i)->Name == sName) + { + uint32 acct_id = 0; + acct_id = objmgr.GetAccountByAccountName((*i)->UName.c_str()); + return acct_id; + } + } + return 0; +} + +std::string IRCCmd::GetAcctNameFromID(uint32 acctid) +{ + QueryResult *result = loginDatabase.PQuery("SELECT username FROM account WHERE id = '%d'", acctid); + if(result) + { + std::string name = (*result)[0].GetCppString(); + delete result; + return name; + } + + return ""; +} + +std::string IRCCmd::GetIPFromPlayer(std::string player) +{ + QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'", player.c_str()); + if(result) + { + std::string acctid = (*result)[0].GetCppString(); + delete result; + QueryResult *result2 = loginDatabase.PQuery("SELECT last_ip FROM account WHERE id = '%s'", acctid.c_str()); + if(result2) + { + std::string ip = (*result2)[0].GetCppString(); + delete result2; + return ip; + } + } + + return ""; +} + +std::string IRCCmd::SecToDay(std::string secons) +{ + unsigned int seconds = atoi(secons.c_str()); + unsigned int days = seconds / 86400; + unsigned int hours = seconds / 3600 % 24; + unsigned int mins = seconds / 60 % 60; + char tottime[1000]; + sprintf(tottime, "%iDays:%iHours:%iMinutes", days, hours, mins); + + return tottime; +} + +bool IRCCmd::ValidParams(std::string PARAMS, int nCount) +{ + if(nCount == 1 && PARAMS.size() == 0) + return false; + int pcount = 0; + size_t p = -1; + for(int i = 0;i < nCount;i++) + { + p = PARAMS.find(" ", p + 1); + if(p == -1) + break; + else + pcount++; + } + nCount--; + if(pcount >= nCount) + return true; + else + return false; +} + +std::string* IRCCmd::getArray(std::string PARAMS, int nCount) +{ + std::string *array = new std::string[nCount]; + if(PARAMS.size() > 0) + { + int pcnt = 0; + size_t ps = 0; + size_t pc = -1; + for(int i = 0;i < nCount;i++) + { + pc = PARAMS.find(" ", pc + 1); + if(i + 1 == nCount && nCount != 1) + { + if(ps > 0 && pc > 0) + array[i] = PARAMS.substr(ps, PARAMS.size() - ps); + } + else + array[i] = PARAMS.substr(ps, pc - ps); + ps = pc + 1; + } + } + return array; +} + +std::string IRCCmd::MakeMsg(const char *sLine, ... ) +{ + va_list ap; + char tmpoutp[1024]; + va_start(ap, sLine); + vsnprintf(tmpoutp, 1024, sLine, ap ); + va_end(ap); + std::string outp = tmpoutp; + return outp; +} + +void IRCClient::AHFunc(uint64 itmid, std::string itmnme, std::string plname, uint32 faction) +{ + IRCCmd Command; + Player* plr = Command.GetPlayer(plname); + if(plr) + { + std::string itemname = itmnme; + + char temp [7]; + sprintf(temp, "%u", itmid); + std::string itemid = temp; + + std::string wowname = ""; + std::string ircname = ""; + switch (plr->GetTeam()) + { + case 67:wowname="|cffff0000"+plname+"|r";ircname="\0034"+plname;break; //horde + case 469:wowname="|cff1589FF"+plname+"|r";ircname="\00312"+plname;break; //alliance + } + + std::string wowfact = "|cffFF8040[Auction House]:|r"; + std::string ircfact = "\00304,08\037/!\\\037\017\00307 Auction House \00304,08\037/!\\\037\017"; + switch(faction) + { + //neutral + case 7:wowfact="|cffff8040[Neutral Auction House]:|r";ircfact="\00304,08\037/!\\\037\017\00307 Neutral Auction House \00304,08\037/!\\\037\017";break; + //horde + case 6:wowfact="|cffff0000[Horde Auction House]:|r";ircfact="\00304,08\037/!\\\037\017\00304 Horde Auction House \00304,08\037/!\\\037\017";break; + //alliance + case 2:wowfact="|cff1589FF[Alliance Auction House]:|r";ircfact="\00304,08\037/!\\\037\017\00312 Alliance Auction House \00304,08\037/!\\\037\017";break; + } + std::string wowstr = Command.MakeMsg("%s A New Item Has Been Added |cffffffff|Hitem:%s:0:0:0:0:0:0:0|h[%s]|h|r. By: %s",wowfact.c_str(), itemid.c_str(), itemname.c_str(), wowname.c_str()); + std::string ircstr = Command.MakeMsg("%s A New Item Has Been Added [%s]. By: %s", ircfact.c_str(), itemname.c_str(), ircname.c_str()); + + sIRC.Send_WoW_Channel(sIRC._wow_chan[sIRC.Status].c_str(), wowstr.c_str()); + sIRC.Send_IRC_Channel(sIRC._irc_chan[sIRC.Status].c_str(), ircstr.c_str()); + } +} diff --git a/src/game/IRCCmd.h b/src/game/IRCCmd.h new file mode 100644 index 00000000000..f2b442c6173 --- /dev/null +++ b/src/game/IRCCmd.h @@ -0,0 +1,117 @@ +#ifndef _IRC_CMD_H +#define _IRC_CMD_H + +#define MAX_CLIENTS 50 +#include "Common.h" +#include "Player.h" +#include "ObjectAccessor.h" + +struct ChannelUser +{ + int UserType; + std::string Name; + std::string UName; + int UserLevel; +}; + +struct _client +{ + bool LoggedIn; + std::string Name; + std::string UName; + int GMLevel; +}; +struct _CDATA +{ + std::string CMD; + std::string USER; + std::string FROM; + std::string PARAMS; + std::string TYPE; + int PCOUNT; +}; +enum APVERR +{ + E_OK, + E_SIZE, + E_AUTH, + E_IVALID, +}; +enum ESOUNDS +{ + S_ENTERWORLD = 602, + S_QUESTFAILED = 847, + S_INVITE = 880, + S_LEVELUP = 888, + S_COINSOUND = 895, + S_WHISPER = 3081, + S_STEALTH = 3325, +}; +class IRCCmd +{ + public: + IRCCmd(); + ~IRCCmd(); + + void Handle_Logout(_CDATA *CD); + bool IsLoggedIn(std::string USER); + bool IsValid(std::string USER, std::string FROM, std::string CHAT, std::string TYPE); + bool AcctIsLoggedIn(std::string USER); + _client *GetClient(std::string cname); + + public: + static std::string MakeMsg(const char *sLine, ... ); + static std::string ChanOrPM(_CDATA *CD); + int AcctLevel(std::string plnme); + int GetLevel(std::string sName); + std::string MakeUpper(std::string Channel); + std::string AcctIsBanned(std::string ACCT); + std::list<_client*> _CLIENTS; + Player* GetPlayer(std::string WHO); + + private: + // MangChat Commands + void Handle_Login(_CDATA *CD); + void Account_Player(_CDATA *CD); + void Ban_Player(_CDATA *CD); + void Chan_Control(_CDATA *CD); + void Char_Player(_CDATA *CD); + void Fun_Player(_CDATA *CD); + void Help_IRC(_CDATA *CD); + void Item_Player(_CDATA *CD); + void Inchan_Server(_CDATA *CD); + void Info_Server(_CDATA *CD); + void Jail_Player(_CDATA *CD); + void Kick_Player(_CDATA *CD); + void Kill_Player(_CDATA *CD); + void Level_Player(_CDATA *CD); + void Lookup_Player(_CDATA *CD); + void Money_Player(_CDATA *CD); + void Mute_Player(_CDATA *CD); + void Online_Players(_CDATA *CD); + void PM_Player(_CDATA *CD); + void Revive_Player(_CDATA *CD); + void Saveall_Player(_CDATA *CD); + void Shutdown_Mangos(_CDATA *CD); + void Spell_Player(_CDATA *CD); + void Sysmsg_Server(_CDATA *CD); + void Tele_Player(_CDATA *CD); + void Top_Player(_CDATA *CD); + void Who_Logged(_CDATA *CD); + bool CanUse(std::string USER, int nLevel); + bool ValidParams(std::string PARAMS, int nCount = 1); + bool ParamsValid(_CDATA *CD, int pCnt); + int ParamsValid(_CDATA *CD, int pCnt, int rLev); + std::string GetAccName(std::string sName); + std::string GetNameFromAcct(std::string sName); + std::string GetAcctNameFromID(uint32 acctid); + std::string GetIPFromPlayer(std::string player); + std::string SecToDay(std::string secons); + int GetAcctIDFromName(std::string sName); + std::string* getArray(std::string PARAMS, int nCount = 1); +}; +inline void MakeLower(std::string& str) +{ + std::transform( str.begin(), str.end(), str.begin(), ::tolower ); +} +#endif diff --git a/src/game/IRCCmde.cpp b/src/game/IRCCmde.cpp new file mode 100644 index 00000000000..ec1ccfae808 --- /dev/null +++ b/src/game/IRCCmde.cpp @@ -0,0 +1,1884 @@ +/* + * MangChat By |Death| And Cybrax + * + * This Program Is Free Software; You Can Redistribute It And/Or Modify It Under The Terms + * Of The GNU General Public License + * Written and Developed by Cybrax. cybraxvd@gmail.com + * |Death| , Lice , Dj_baby & Sanaell, Tase + * With Help And Support From The MaNGOS Project Community. + * PLEASE RETAIN THE COPYRIGHT OF THE AUTHORS. + */ +#include "IRCCmd.h" +#include "IRCClient.h" +#include "MCS_OnlinePlayers.h" +#include "WorldPacket.h" +#include "Database/DatabaseEnv.h" +#include "Chat.h" +#include "MapManager.h" +#include "World.h" +#include "Guild.h" +#include "ObjectMgr.h" +#include "Language.h" +#include "SpellAuras.h" +#include "SystemConfig.h" +#include "Config/ConfigEnv.h" + +#define Send_Player(p, m) sIRC.Send_WoW_Player(p, m) +#define Send_IRCA(c, m, b, t) sIRC.Send_IRC_Channel(c, m, b, t) + +#ifdef WIN32 +#define Delay(x) Sleep(x) +#else +#define Delay(x) sleep(x / 1000) +#endif + +void IRCCmd::Handle_Login(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 2); + std::string isbanned = AcctIsBanned(_PARAMS[0]); + if(isbanned == "NOTBANNED") + { + if(!IsLoggedIn(CD->USER)) + { + if(!AcctIsLoggedIn(_PARAMS[0].c_str())) + { + QueryResult *result = loginDatabase.PQuery("SELECT `gmlevel` FROM `account` WHERE `username`='%s' AND `sha_pass_hash`=SHA1(CONCAT(UPPER(`username`),':',UPPER('%s')));", _PARAMS[0].c_str(), _PARAMS[1].c_str()); + if (result) + { + Field *fields = result->Fetch(); + int GMLevel = fields[0].GetInt16(); + if(GMLevel >= 0) + { + _client *NewClient = new _client(); + NewClient->Name = CD->USER; + NewClient->UName = MakeUpper(_PARAMS[0]); + NewClient->GMLevel = fields[0].GetInt16(); + _CLIENTS.push_back(NewClient); + Send_IRCA(CD->USER, MakeMsg("You Are Now Logged In As %s, Welcome To MangChat Admin Mode.", _PARAMS[0].c_str()), true, CD->TYPE); + + if(sIRC._op_gm == 1 && GMLevel >= sIRC._op_gm_lev) + { + for(int i=1;i < sIRC._chan_count + 1;i++) + sIRC.SendIRC("MODE #"+sIRC._irc_chan[i]+" +o "+CD->USER ); + } + } + }else + Send_IRCA(CD->USER, "\0034[ERROR] : Sorry, Your Username Or Password Is Incorrect. Please Try Again. ", true, "ERROR"); + }else + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : %s Is Already Logged In With This Username. ", GetNameFromAcct(MakeUpper(_PARAMS[0])).c_str()), true, "ERROR"); + }else + Send_IRCA(CD->USER, "\0034[ERROR] : You Are Already Logged In As "+ _PARAMS[0] +"!", true, "ERROR"); + }else + Send_IRCA(CD->USER, "\0034[ERROR] : Sorry You Are "+isbanned+". You Cannot Log In To MangChat "+CD->USER.c_str()+"!", true, "ERROR"); +} + +void IRCCmd::Handle_Logout(_CDATA *CD) +{ + for(std::list<_client*>::iterator i=_CLIENTS.begin(); i!=_CLIENTS.end();i++) + { + if((*i)->Name == CD->USER) + { + _CLIENTS.erase(i); + delete (*i); + Send_IRCA(CD->USER, "You Are Now Logged Out!", true, CD->TYPE); + return; + } + } + Send_IRCA(CD->USER, "\0034[ERROR] : You Are Not Logged In!", true, "ERROR"); +} + +void IRCCmd::Account_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 3); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + normalizePlayerName(_PARAMS[0]); + uint64 guid = objmgr.GetPlayerGUIDByName(_PARAMS[0]); + uint32 account_id = 0; + account_id = objmgr.GetPlayerAccountIdByGUID(guid); + if(account_id) + { + if(account_id == GetAcctIDFromName(CD->USER) || GetLevel(CD->USER) >= sIRC._op_gm_lev) + { + Player* plr = objmgr.GetPlayer(guid); + if(_PARAMS[1] == "lock") + { + loginDatabase.PExecute( "UPDATE `account` SET `locked` = '1' WHERE `id` = '%d'",account_id); + if(plr) Send_Player(plr, MakeMsg("Your Account Has Been Locked To Your Current IP By: %s", CD->USER.c_str())); + Send_IRCA(ChanOrPM(CD), "\00313["+GetAcctNameFromID(account_id)+"] : Account Has Been Locked To Their Current IP Address.", true, CD->TYPE); + } + else if(_PARAMS[1] == "unlock") + { + loginDatabase.PExecute( "UPDATE `account` SET `locked` = '0' WHERE `id` = '%d'",account_id); + if(plr) Send_Player(plr, MakeMsg("Your Account Has Been UnLocked From The Associated IP By: %s", CD->USER.c_str())); + Send_IRCA(ChanOrPM(CD), "\00313["+GetAcctNameFromID(account_id)+"] : Account Has Been UnLocked From The Associated IP Address.", true, CD->TYPE); + } + else if(_PARAMS[1] == "mail") + { + loginDatabase.PExecute( "UPDATE `account` SET `email` = '%s' WHERE `id` = '%d'",_PARAMS[2].c_str() ,account_id); + if (plr) Send_Player(plr, MakeMsg("%s Has Changed Your EMail Adress To: %s", CD->USER.c_str(), _PARAMS[2].c_str())); + Send_IRCA(ChanOrPM(CD), "\00313["+GetAcctNameFromID(account_id)+"] : EMail Address Successfully Changed To: "+_PARAMS[2], true, CD->TYPE); + } + else if(_PARAMS[1] == "pass") + { + loginDatabase.PExecute( "UPDATE `account` SET `sha_pass_hash` = SHA1(CONCAT(UPPER(`username`),':',UPPER('%s'))) WHERE `id` = '%d'",_PARAMS[2].c_str() ,account_id); + if (plr) Send_Player(plr, MakeMsg("%s Has Changed Your Password To: %s", CD->USER.c_str(), _PARAMS[2].c_str())); + Send_IRCA(ChanOrPM(CD), "\00313["+GetAcctNameFromID(account_id)+"] : Password Successfully Changed To: "+_PARAMS[2], true, CD->TYPE); + } + else if(_PARAMS[1] == "rename") + { + if(plr) + { + plr->SetAtLoginFlag(AT_LOGIN_RENAME); + Send_Player(plr, MakeMsg("%s Has Requested You Change This Characters Name, Rename Will Be Forced On Next Login!", CD->USER.c_str())); + } + CharacterDatabase.PExecute("UPDATE `characters` SET `at_login` = `at_login` | '1' WHERE `guid` = '%u'", guid); + Send_IRCA(ChanOrPM(CD), "\00313["+GetAcctNameFromID(account_id)+"] : Has Been Forced To Change Their Characters Name, Rename Will Be Forced On Next Login!", true, CD->TYPE); + } + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : You Are Not A GM, You May Only Change Settings In Your Own Account.", true, "ERROR"); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : No Such Player Exists, So Account Cannot Be Looked Up.", true, "ERROR"); +} + +void IRCCmd::Ban_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 3); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + if(_PARAMS[1] == "ip") + { + std::string ip = GetIPFromPlayer(_PARAMS[0]); + if(_PARAMS[2] == "") + _PARAMS[2] = "No Reason"; + if(ip != "") + { + loginDatabase.PExecute( "INSERT IGNORE INTO `ip_banned` VALUES ('%s', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '%s', '%s')", ip.c_str(), CD->USER.c_str(), _PARAMS[2].c_str()); + if (Player* plr = GetPlayer(_PARAMS[0])) + plr->GetSession()->KickPlayer(); + Send_IRCA(ChanOrPM(CD), MakeMsg("\00313[%s] : Has Had Their IP Address Banned. [%s] Reason: %s",_PARAMS[0].c_str() ,ip.c_str() , _PARAMS[2].c_str()), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : I Cannot Locate An IP Address For The Character Name Given.", true, "ERROR"); + } + if(_PARAMS[1] == "acct") + { + uint64 guid = objmgr.GetPlayerGUIDByName(_PARAMS[0].c_str()); + uint32 acctid = objmgr.GetPlayerAccountIdByGUID(guid); + if(_PARAMS[2] == "") + _PARAMS[2] = "No Reason"; + if(acctid) + { + loginDatabase.PExecute( "INSERT INTO `account_banned` VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '%s', '%s', 1)", acctid, CD->USER.c_str(), _PARAMS[2].c_str()); + if (Player* plr = GetPlayer(_PARAMS[0])) + plr->GetSession()->KickPlayer(); + Send_IRCA(ChanOrPM(CD), MakeMsg("\00313[%s] : Has Had Their Account Banned. Reason: %s",_PARAMS[0].c_str(), _PARAMS[2].c_str()), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : I Cannot Locate An Account For The Character Name Given.", true, "ERROR"); + } + if(_PARAMS[1] == "unban") + { + std::string unbani = _PARAMS[0]; + if(atoi(unbani.c_str()) > 0) + { + loginDatabase.PExecute( "DELETE FROM ip_banned WHERE ip = '%s'", _PARAMS[0].c_str()); + Send_IRCA(ChanOrPM(CD), MakeMsg("\00313[%s] : Has Been Removed From The IP Ban List.", _PARAMS[0].c_str()), true, CD->TYPE); + } + else + { + QueryResult *result = loginDatabase.PQuery("SELECT id FROM `account` WHERE username = '%s'", _PARAMS[0].c_str()); + if(result) + { + Field *fields = result->Fetch(); + std::string id = fields[0].GetCppString(); + + loginDatabase.PExecute( "DELETE FROM account_banned WHERE id = %s", id.c_str()); + delete result; + Send_IRCA(ChanOrPM(CD), MakeMsg("\00313[%s] : Has Been Removed From The Account Ban List.", _PARAMS[0].c_str()), true, CD->TYPE); + + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : I Cannot Locate An Account Or IP Address For The Paramaters Given.", true, "ERROR"); + } + } +} + +void IRCCmd::Chan_Control(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 2); + if(CD->FROM == sIRC._Nick) + { + Send_IRCA(CD->USER, "\0034[ERROR] : You Cannot Use This Command Through A PM Yet.", true, "ERROR"); + return; + } + if(_PARAMS[0] == "op") + { + if(_PARAMS[1].length() > 1) + sIRC.SendIRC("MODE "+CD->FROM+" +o "+_PARAMS[1] ); + else + sIRC.SendIRC("MODE "+CD->FROM+" +o "+CD->USER ); + } + if(_PARAMS[0] == "deop") + { + if(_PARAMS[1].length() > 1) + sIRC.SendIRC("MODE "+CD->FROM+" -o "+_PARAMS[1] ); + else + sIRC.SendIRC("MODE "+CD->FROM+" -o "+CD->USER ); + } + if(_PARAMS[0] == "voice") + { + if(_PARAMS[1].length() > 1) + sIRC.SendIRC("MODE "+CD->FROM+" +v "+_PARAMS[1] ); + else + sIRC.SendIRC("MODE "+CD->FROM+" +v "+CD->USER ); + } + if(_PARAMS[0] == "devoice") + { + if(_PARAMS[1].length() > 1) + sIRC.SendIRC("MODE "+CD->FROM+" -v "+_PARAMS[1] ); + else + sIRC.SendIRC("MODE "+CD->FROM+" -v "+CD->USER ); + } +} + +void IRCCmd::Char_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 5); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + normalizePlayerName(_PARAMS[0]); + uint64 guid = objmgr.GetPlayerGUIDByName(_PARAMS[0]); + Player* plr = objmgr.GetPlayer(guid); + if(plr) + { + if(_PARAMS[1] == "mapcheat") + { + bool explore = false; + if (_PARAMS[2] != "0") + explore = true; + for (uint8 i=0; i<64; i++) + { + if (_PARAMS[2] != "0") + plr->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0xFFFFFFFF); + else + plr->SetFlag(PLAYER_EXPLORED_ZONES_1+i,0); + } + if(explore) + { + Send_Player(plr, MakeMsg("All Your Zones Have Been Set To Explored By: %s", CD->USER.c_str())); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Has Now Explored All Zones.", true, CD->TYPE); + } + else + { + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Has Now Had All Zones Set To Un-Explored.", true, CD->TYPE); + Send_Player(plr, MakeMsg("All Your Zones Have Been Set To Un-Explored By: %s", CD->USER.c_str())); + } + } + if(_PARAMS[1] == "taxicheat") + { + if (_PARAMS[2] != "0") + { + plr->SetTaxiCheater(true); + Send_Player(plr, MakeMsg("Taxi Node Cheat Has Been Enabled By: %s", CD->USER.c_str())); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Taxi Node Cheat Has Been Enabled.", true, CD->TYPE); + } + else + { + plr->SetTaxiCheater(false); + Send_Player(plr, MakeMsg("Taxi Node Cheat Has Been Disabled By: %s", CD->USER.c_str())); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Taxi Node Cheat Has Been Disabled.", true, CD->TYPE); + } + } + if(_PARAMS[1] == "maxskill") + { + plr->UpdateSkillsToMaxSkillsForLevel(); + Send_Player(plr, MakeMsg("Your Skills Have Been Maxed Out By: %s", CD->USER.c_str())); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Skills Have Been Maxed Out.", true, CD->TYPE); + } + if(_PARAMS[1] == "setskill") + { + std::string* _PARAMSA = getArray(_PARAMS[2], 4); + uint32 skill = atoi(_PARAMS[2].c_str()); + uint32 level = atol(_PARAMS[3].c_str()); + int32 max = _PARAMS[4].c_str() ? atol (_PARAMS[4].c_str()) : plr->GetPureMaxSkillValue(skill); + SkillLineEntry const* skilllookup = sSkillLineStore.LookupEntry(skill); + //if skillid entered is not a number and greater then 0 then the command is being used wrong + if(skill >= 0) + { + //does the skill even exist + if(skilllookup) + { + //does player have the skill yet + if(plr->GetSkillValue(skill)) + { + plr->SetSkill(skill,level,max); + Send_Player(plr, MakeMsg("Skill: %s Has Been Set To Level: %i Max: %i By: %s",skilllookup->name[0], level, max, CD->USER.c_str())); + Send_IRCA(ChanOrPM(CD), MakeMsg("\00313[%s] : Has Had Skill: %s Set To Level: %d Max: %d",_PARAMS[0].c_str() , skilllookup->name[0], level, max), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Player Does Not Have The %s Skill Yet.", skilllookup->name[0]), true, "ERROR"); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : That Skill ID Does Not Exist.", true, "ERROR"); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : The Skill ID Entered Is Invalid.", true, "ERROR"); + } + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : No Character With That Name Exists.", true, "ERROR"); +} + +void IRCCmd::Fun_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 3); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + if (Player* plr = GetPlayer(_PARAMS[0])) + { + if(_PARAMS[1] == "say") + { + plr->Say(_PARAMS[2], LANG_UNIVERSAL); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Was Forced To Say: "+_PARAMS[2]+".", true, CD->TYPE); + } + if(_PARAMS[1] == "sound") + { + uint32 sndid = atoi(_PARAMS[2].c_str()); + plr->SendPlaySound(sndid ,true); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Has Just Heard Sound ID: "+_PARAMS[2]+".", true, CD->TYPE); + } + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Player Not Online!", true, "ERROR"); +} + +void IRCCmd::Help_IRC(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 1); + QueryResult *result = WorldDatabase.PQuery("SELECT `Command`, `Description`, `gmlevel` FROM `IRC_Commands`"); + if(result) + { + if(IsLoggedIn(CD->USER)) + { + if(_PARAMS[0] == "") + { + QueryResult *result = WorldDatabase.PQuery("SELECT * FROM `IRC_Commands` WHERE `gmlevel` <= %u ORDER BY `Command`", GetLevel(CD->USER)); + if(result) + { + std::string output = "\002MangChat IRC Commands:\017 "; + for (uint64 i=0; i < result->GetRowCount(); i++) + { + Field *fields = result->Fetch(); + output += fields[0].GetCppString() + ", "; + result->NextRow(); + } + delete result; + Send_IRCA(CD->USER, output, true, CD->TYPE.c_str()); + } + } + else + { + QueryResult *result = WorldDatabase.PQuery("SELECT `Description`, `gmlevel` FROM `IRC_Commands` WHERE `Command` = '%s'", _PARAMS[0].c_str()); + if(result) + { + Field *fields = result->Fetch(); + if(fields[1].GetUInt32() > GetLevel(CD->USER)) + { + Send_IRCA(CD->USER, "You Do Not Have Access To That Command, So No Help Is Available.", true, CD->TYPE.c_str()); + return; + } + if(result) + { + std::string cmdhlp = fields[0].GetCppString(); + delete result; + Send_IRCA(CD->USER, cmdhlp, true, CD->TYPE.c_str()); + } + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : No Such Command Exists, Please Check The Spelling And Try Again.", true, "ERROR"); + } + } + else if(!IsLoggedIn(CD->USER)) + { + if(_PARAMS[0] == "") + { + QueryResult *result = WorldDatabase.PQuery("SELECT * FROM `IRC_Commands` WHERE `gmlevel` = 0 ORDER BY `Command`"); + if(result) + { + std::string output = "\002MangChat IRC Commands:\017 "; + for (uint64 i=0; i < result->GetRowCount(); i++) + { + Field *fields = result->Fetch(); + output += fields[0].GetCppString() + ", "; + result->NextRow(); + } + delete result; + Send_IRCA(CD->USER, output, true, CD->TYPE.c_str()); + Send_IRCA(CD->USER, "You Are Currently Not Logged In, Please Login To See A Complete List Of Commands Available To You.", true, CD->TYPE.c_str()); + } + } + else + { + QueryResult *result = WorldDatabase.PQuery("SELECT `Description`, `gmlevel` FROM `IRC_Commands` WHERE `Command` = '%s'", _PARAMS[0].c_str()); + if(result) + { + Field *fields = result->Fetch(); + if(fields[1].GetUInt32() > 0) + { + Send_IRCA(CD->USER, "You Do Not Have Access To That Command, So No Help Is Available.", true, CD->TYPE.c_str()); + return; + } + std::string cmdhlp = fields[0].GetCppString(); + delete result; + Send_IRCA(CD->USER, cmdhlp, true, CD->TYPE.c_str()); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : No Such Command Exists, Please Check The Spelling And Try Again.", true, "ERROR"); + } + } + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Database Error! Please Make Sure You Used IRC_Commands.sql, You Must Have A Table In Your World Database (IRC_Commands)!", true, "ERROR"); +} + +void IRCCmd::Inchan_Server(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 1); + if(_PARAMS[0] == "") + { + Send_IRCA(CD->USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"inchan )", true, "ERROR"); + return; + } + QueryResult *result = WorldDatabase.PQuery("SELECT * FROM `IRC_Inchan` WHERE `channel` = '%s' ORDER BY `name`", _PARAMS[0].c_str()); + if(result) + { + Field *fields = result->Fetch(); + std::string output = "\002Players In The [ "+fields[2].GetCppString()+" ] Channel:\017 "; + for (uint64 i=0; i < result->GetRowCount(); i++) + { + output += fields[1].GetCppString() + ", "; + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), output, true, CD->TYPE); + } + else + Send_IRCA(ChanOrPM(CD), "No Players Are Currently In [ "+_PARAMS[0]+" ] Channel!", true, CD->TYPE.c_str()); +} + +void IRCCmd::Info_Server(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 1); + char clientsNum [50]; + sprintf(clientsNum, "%u", sWorld.GetActiveSessionCount()); + char maxClientsNum [50]; + sprintf(maxClientsNum, "%u", sWorld.GetMaxActiveSessionCount()); + std::string str = secsToTimeString(sWorld.GetUptime()); + std::string svnrev = _FULLVERSION; + Send_IRCA(ChanOrPM(CD), "\x2 Number of players online:\x3\x31\x30 " + (std::string)clientsNum + "\xF |\x2 Max since last restart:\x3\x31\x30 "+(std::string)maxClientsNum+"\xF |\x2 Uptime:\x3\x31\x30 "+str, true, CD->TYPE); + Send_IRCA(ChanOrPM(CD), "\x2 Trinity Core SVN revision:\x3\x31\x30 "+svnrev, true, CD->TYPE); +} + +void IRCCmd::Item_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 3); + + normalizePlayerName(_PARAMS[0]); + Player *chr = GetPlayer(_PARAMS[0].c_str()); + if(_PARAMS[1] == "add") + { + std::string s_param = _PARAMS[2]; + + char *args = (char*)s_param.c_str(); + uint32 itemId = 0; + if(args[0]=='[') + { + char* citemName = citemName = strtok((char*)args, "]"); + if(citemName && citemName[0]) + { + std::string itemName = citemName+1; + WorldDatabase.escape_string(itemName); + QueryResult *result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE name = '%s'", itemName.c_str()); + if (!result) + { + Send_IRCA(CD->USER, "\0034[ERROR] : Item Not Found!", true, "ERROR"); + return; + } + itemId = result->Fetch()->GetUInt16(); + delete result; + } + else + { + Send_IRCA(CD->USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"item [Exact Item Name] )", true, "ERROR"); + return; + } + } + else + { + std::string itemName = s_param; + WorldDatabase.escape_string(itemName); + QueryResult *result = WorldDatabase.PQuery("SELECT entry FROM item_template WHERE name = '%s'", itemName.c_str()); + if (result) + { + itemId = result->Fetch()->GetUInt16(); + } + delete result; + + char* cId = strtok(args, " "); + if(!cId) + { + Send_IRCA(CD->USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"item )", true, "ERROR"); + return; + } + itemId = atol(cId); + } + char* ccount = strtok(NULL, " "); + int32 count = 1; + if (ccount) { count = atol(ccount); } + Player* plTarget = chr; + if(!plTarget) + { + Send_IRCA(CD->USER, "\0034[ERROR] : "+_PARAMS[0]+" Is Not Online!", true, "ERROR"); + return; + } + ItemPrototype const *pProto = objmgr.GetItemPrototype(itemId); + //Subtract + if (count < 0) + { + plTarget->DestroyItemCount(itemId, -count, true, false); + char itemid2[255]; + sprintf(itemid2,"%d",itemId); + std::string itake = " \00313["+ _PARAMS[0] +"] : Has Had Item " +itemid2+ " Taken From Them!"; + Send_IRCA(ChanOrPM(CD), itake, true, CD->TYPE); + return; + } + //Adding items + uint32 noSpaceForCount = 0; + + // check space and find places + ItemPosCountVec dest; + uint8 msg = plTarget->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount ); + if( msg == EQUIP_ERR_INVENTORY_FULL ) // convert to possibel store amount + count -= noSpaceForCount; + else if( msg != EQUIP_ERR_OK ) // other error, can't add + { + char s_countForStore[255]; + sprintf(s_countForStore,"%d",count); + std::string ierror = " \00313["+ _PARAMS[0] +"] : Could Not Create All Items! " +s_countForStore+ " Item(s) Were Not Created!"; + Send_IRCA(ChanOrPM(CD), ierror, true, CD->TYPE); + return; + } + Item* item = plTarget->StoreNewItem( dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); + if(count > 0 && item) + { + plTarget->SendNewItem(item,count,true,false); + QueryResult *result = WorldDatabase.PQuery("SELECT name FROM item_template WHERE entry = %d", itemId); + char* dbitemname = NULL; + if (result) + { + dbitemname = (char*)result->Fetch()->GetString(); + } + std::string iinfo = " \00313[" + _PARAMS[0] + "] : Has Been Given Item "+dbitemname+". From: "+CD->USER.c_str()+"."; + Send_IRCA(ChanOrPM(CD), iinfo, true, CD->TYPE); + delete result; + } + if(noSpaceForCount > 0) + { + char s_countForStore[255]; + sprintf(s_countForStore,"%d",noSpaceForCount); + std::string ierror = " \00313["+ _PARAMS[0] +"] : Could Not Create All Items! " +s_countForStore+ " Item(s) Were Not Created!"; + Send_IRCA(ChanOrPM(CD), ierror, true, CD->TYPE); + return; + } + } + else + { + Send_IRCA(CD->USER, "\0034[ERROR] : Syntax Error! ( "+sIRC._cmd_prefx+"item )", true, "ERROR"); + return; + } +} + +void IRCCmd::Jail_Player(_CDATA *CD) +{ + if(ValidParams(CD->PARAMS, 1)) + { + std::string* _PARAMS = getArray(CD->PARAMS, 2); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + if (Player *plr = GetPlayer(_PARAMS[0])) + { + std::string sReason = ""; + if(_PARAMS[1] == "release") + { + float rposx, rposy, rposz, rposo = 0; + uint32 rmapid = 0; + CharacterDatabase.escape_string(_PARAMS[0]); + QueryResult *result = CharacterDatabase.PQuery( "SELECT `map`, `position_x`, `position_y`, `position_z` FROM `character_homebind` WHERE `guid` = '" I64FMTD "'", plr->GetGUID() ); + if(result) + { + Field *fields = result->Fetch(); + rmapid = fields[0].GetUInt16(); + rposx = fields[1].GetFloat(); + rposy = fields[2].GetFloat(); + rposz = fields[3].GetFloat(); + delete result; + plr->SetMovement(MOVE_UNROOT); + plr->TeleportTo(rmapid, rposx, rposy, rposz, rposo); + plr->RemoveAurasDueToSpell(42201); + plr->RemoveAurasDueToSpell(23775); + plr->RemoveAurasDueToSpell(9454); + Send_Player(plr, MakeMsg("You Have Been Released By: %s.", CD->USER.c_str())); + sReason = " \00313["+_PARAMS[0]+"] : Has Been Released By: "+CD->USER+"."; + Send_IRCA(ChanOrPM(CD), sReason, true, CD->TYPE); + } + } + else + { + if(_PARAMS[1] == "") + _PARAMS[1] = "No Reason Given."; + plr->TeleportTo(13, 0, 0, 0, 0); + plr->SetMovement(MOVE_ROOT); + plr->CastSpell(plr, 42201, true); + plr->CastSpell(plr, 23775, true); + plr->CastSpell(plr, 9454, true); + Send_Player(plr, MakeMsg("You Have Been Jailed By: %s. Reason: %s.", CD->USER.c_str(), _PARAMS[1].c_str())); + sReason = " \00313["+_PARAMS[0]+"] : Has Been Jailed By: "+CD->USER+". Reason: "+_PARAMS[1]+"."; + Send_IRCA(ChanOrPM(CD), sReason, true, CD->TYPE); + } + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : "+_PARAMS[0]+" Is Not Online!", true, "ERROR"); + } +} + +void IRCCmd::Kick_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, CD->PCOUNT); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + if(_PARAMS[1] == "") + _PARAMS[1] = "No Reason Given."; + if (Player* plr = GetPlayer(_PARAMS[0])) + { + plr->GetSession()->KickPlayer(); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Has Been Kicked By: "+CD->USER+". Reason: "+_PARAMS[1]+".", true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : "+_PARAMS[0]+" Is Not Online!", true, "ERROR"); +} + +void IRCCmd::Kill_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, CD->PCOUNT); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + if (Player* plr = GetPlayer(_PARAMS[0])) + { + if(plr->isAlive()) + { + plr->DealDamage(plr, plr->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); + plr->SaveToDB(); + if(_PARAMS[1] == "") + _PARAMS[1] = "No Reason Given."; + Send_IRCA(ChanOrPM(CD), MakeMsg("\00313[%s] : Has Been Killed By: %s.", _PARAMS[0].c_str(), CD->USER.c_str()) + + + " Reason: "+_PARAMS[1]+".", true, CD->TYPE); + Send_Player(plr, MakeMsg("You Have Been Killed By: %s. Reason: %s.", CD->USER.c_str(), _PARAMS[1].c_str())); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : "+_PARAMS[0]+" Is Already Dead!", true, "ERROR"); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : "+_PARAMS[0]+" Is Not Online!", true, "ERROR"); +} + +void IRCCmd::Lookup_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, CD->PCOUNT); + if(_PARAMS[0] == "acct") + { + uint32 acctid = atoi(_PARAMS[1].c_str()); + if(objmgr.GetAccountByAccountName(_PARAMS[1])) + acctid = objmgr.GetAccountByAccountName(_PARAMS[1]); + if(acctid > 0) + { + std::string DateTime = "%a, %b %d, %Y - %h:%i%p"; + QueryResult *result = loginDatabase.PQuery("SELECT id, username, gmlevel, last_ip, (SELECT banreason FROM account_banned WHERE id = %d LIMIT 1) as banned, (SELECT banreason FROM ip_banned WHERE ip = last_ip) as bannedip, DATE_FORMAT(last_login, '%s') FROM `account` WHERE id = %d", acctid, DateTime.c_str(), acctid, acctid); + if(result) + { + Field *fields = result->Fetch(); + + uint32 id = fields[0].GetUInt32(); + std::string usrname = fields[1].GetCppString(); + uint32 gm = fields[2].GetUInt32(); + std::string lastip = fields[3].GetCppString(); + std::string banreason = fields[4].GetCppString(); + std::string banreasonip = fields[5].GetCppString(); + std::string lastlogin = fields[6].GetCppString(); + delete result; + + QueryResult *chars = CharacterDatabase.PQuery("SELECT guid, name, (SELECT SUM(totaltime) FROM characters WHERE account = %d) AS tottime FROM characters WHERE account = %u", id, id); + std::string characters = "None"; + std::string totaccttime = "Never Logged In"; + if(chars) + { + characters = ""; + Field *fields = chars->Fetch(); + totaccttime = SecToDay(fields[2].GetCppString()); + for (uint64 i=0; i < chars->GetRowCount(); i++) + { + std::string guid = fields[0].GetCppString(); + std::string charname = fields[1].GetCppString(); + characters.append(charname+"("+guid+"), "); + chars->NextRow(); + } + delete chars; + } + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Username:\x3\x31\x30 %s \xF|\x2 AccountID:\x3\x31\x30 %d \xF|\x2 GM Level:\x3\x31\x30 %d \xF|\x2 Last IP:\x3\x31\x30 %s \xF|\x2 Last Login:\x3\x31\x30 %s", usrname.c_str(), id, gm, lastip.c_str(), lastlogin.c_str()), true, CD->TYPE); + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Total Play Time:\x3\x31\x30 %s \xF|\x2 Characters:\x3\x31\x30 %s ", totaccttime.c_str(), characters.c_str()), true, CD->TYPE); + if(banreason.length() > 1) + Send_IRCA(ChanOrPM(CD), MakeMsg("\0034This User Has An Account Ban. Ban Reason: %s", banreason.c_str()), true, CD->TYPE); + if(banreasonip.length() > 1) + Send_IRCA(ChanOrPM(CD), MakeMsg("\0034This User Has An IP Ban. Ban Reason: %s", banreasonip.c_str()), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Account ID." ,true, "ERROR"); + } + else + { + QueryResult *result = loginDatabase.PQuery("SELECT id, username FROM `account` WHERE username LIKE '%%%s%%' LIMIT 10", _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + std::string accts = "\002Account Search Results:\x3\x31\x30 "; + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string acctid = fields[0].GetCppString(); + std::string acctname = fields[1].GetCppString(); + accts.append(acctname+"("+acctid+")\xF | \x3\x31\x30\x2"); + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), accts, true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Username. I Cant Find Any Users With Those Search Terms." ,true, "ERROR"); + } + } + if(_PARAMS[0] == "char") + { + uint32 plguid = atoi(_PARAMS[1].c_str()); + if(objmgr.GetPlayerGUIDByName(_PARAMS[1].c_str())) + plguid = objmgr.GetPlayerGUIDByName(_PARAMS[1].c_str()); + if(plguid > 0) + { + QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, name, race, class, online, SUBSTRING_INDEX(SUBSTRING_INDEX(`data`, ' ' , 35), ' ' , -1) AS level, SUBSTRING_INDEX(SUBSTRING_INDEX(`data`, ' ' , 238), ' ' , -1) AS guildid, SUBSTRING_INDEX(SUBSTRING_INDEX(`data`, ' ' , 239), ' ' , -1) AS guildrank, SUBSTRING_INDEX(SUBSTRING_INDEX(`data`, ' ' , 927), ' ' , -1) AS xp, SUBSTRING_INDEX(SUBSTRING_INDEX(`data`, ' ' , 928), ' ' , -1) AS maxxp, SUBSTRING_INDEX(SUBSTRING_INDEX(data, ' ' , 1462), ' ' , -1) AS gold, SUBSTRING_INDEX(SUBSTRING_INDEX(`data`, ' ' , 1454), ' ' , -1) AS hk, SEC_TO_TIME(totaltime) AS tottime FROM characters WHERE guid =%i", plguid); + uint32 latency = 0; + Player *chr = objmgr.GetPlayer(plguid); + if(chr) + { + latency = chr->GetSession()->GetLatency(); + } + char templatency [100]; + sprintf(templatency, "%ums", latency); + if(result) + { + Field *fields = result->Fetch(); + std::string pguid = fields[0].GetCppString(); + std::string pacct = fields[1].GetCppString(); + std::string pname = fields[2].GetCppString(); + uint32 praceid = fields[3].GetUInt32(); + uint32 pclassid = fields[4].GetUInt32(); + std::string ponline = (fields[5].GetInt32() == 1 ? "\x3\x30\x33Online" : "\x3\x30\x34Offline\xF"); + std::string plevel = fields[6].GetCppString(); + uint32 pguildid = fields[7].GetUInt32(); + uint32 pguildrank = fields[8].GetUInt32(); + std::string pxp = fields[9].GetCppString(); + std::string pmaxxp = fields[10].GetCppString(); + unsigned int money = fields[11].GetInt32(); + std::string hk = fields[12].GetCppString(); + std::string totaltim = SecToDay(fields[13].GetCppString()); + delete result; + std::string sqlquery = "SELECT `gmlevel` FROM `account` WHERE `id` = '" + pacct + "';"; + QueryResult *result = loginDatabase.Query(sqlquery.c_str()); + Field *fields2 = result->Fetch(); + std::string pgmlvl = fields2[0].GetCppString(); + delete result; + std::string guildinfo = ""; + if (pguildid != 0) + { + Guild* guild = objmgr.GetGuildById(pguildid); + if (guild) + { + guildinfo = " " + guild->GetRankName(pguildrank) + " Of " + guild->GetName(); + } + } + else guildinfo = " None"; + ChrRacesEntry const* prace = sChrRacesStore.LookupEntry(praceid); + ChrClassesEntry const* pclass = sChrClassesStore.LookupEntry(pclassid); + + if (atoi(plevel.c_str()) < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)) + plevel += " (" + pxp + "/" + pmaxxp + ")"; + unsigned int gold = money / 10000; + unsigned int silv = (money % 10000) / 100; + unsigned int cop = (money % 10000) % 100; + char tempgold [100]; + sprintf(tempgold, "\x2\x3\x30\x37%ug \x3\x31\x34%us \x3\x30\x35%uc\xF", gold, silv, cop); + if (ponline == "\x3\x30\x33Online") + { + Player * plr = ObjectAccessor::Instance().FindPlayerByName(pname.c_str()); + if (plr) + { + AreaTableEntry const* area = GetAreaEntryByAreaID(plr->GetAreaId()); + ponline += " in " + (std::string) area->area_name[sWorld.GetDefaultDbcLocale()]; + if (area->zone != 0) + { + AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone); + ponline += " (" + (std::string)zone->area_name[sWorld.GetDefaultDbcLocale()] + ")"; + } + } + } + std::string pinfo = "\x2 About Player:\x3\x31\x30 " +pname+ "\xF |\x2 GM Level:\x3\x31\x30 " +pgmlvl+ "\xF |\x2 AcctID:\x3\x31\x30 " +pacct+ "\xF |\x2 CharID:\x3\x31\x30 " +pguid+ " \xF |\x2 Played Time:\x2\x3\x31\x30 " +totaltim+" \xF |\x2 Latency:\x2\x3\x31\x30 "+templatency; + std::string pinfo2 = "\x2 Race:\x2\x3\x31\x30 " + (std::string)prace->name[sWorld.GetDefaultDbcLocale()] + "\xF |\x2 Class:\x2\x3\x31\x30 " + (std::string)pclass->name[sWorld.GetDefaultDbcLocale()] + "\xF |\x2 Level:\x2\x3\x31\x30 " + plevel + "\xF |\x2 Money:\x2 " + tempgold + "\xF |\x2 Guild Info:\x2\x3\x31\x30 "+guildinfo+"\xF |\x2 Status:\x2 " + ponline; + // pinfo3 = " :" + " \x2Honor Kills:\x2\x3\x31\x30 " + hk; + Send_IRCA(ChanOrPM(CD),pinfo , true, CD->TYPE); + Send_IRCA(ChanOrPM(CD),pinfo2 , true, CD->TYPE); + // Send_IRCA(ChanOrPM(CD),pinfo3 , true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Character ID. (GUID)" ,true, "ERROR"); + } + else + { + QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, name FROM characters WHERE name LIKE '%%%s%%' LIMIT 10", _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + std::string items = "\x2 Character Search Results:\x3\x31\x30 "; + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string guid = fields[0].GetCppString(); + std::string account = fields[1].GetCppString(); + std::string name = fields[2].GetCppString(); + MakeUpper(name); + items.append(name+"(Account:"+account+" - GUID:"+guid+")\xF | \x3\x31\x30\x2"); + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), items, true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Character. I Cant Find Any Characters With Those Search Terms." ,true, "ERROR"); + } + } + if(_PARAMS[0] == "creature") + { + std::string creature = _PARAMS[1]; + if(atoi(creature.c_str()) > 0) + { + WorldDatabase.escape_string(_PARAMS[1]); + QueryResult *result = WorldDatabase.PQuery("SELECT entry, modelid_A, name, (minlevel*maxlevel/2) as level, faction_A, armor, (SELECT count(*) FROM creature WHERE id = '%s') as spawns FROM creature_template WHERE entry = '%s';", _PARAMS[1].c_str(), _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + + uint32 entry = fields[0].GetUInt32(); + uint32 modelid = fields[1].GetUInt32(); + std::string name = fields[2].GetCppString(); + uint32 level = fields[3].GetUInt32(); + uint32 faction = fields[4].GetUInt32(); + uint32 armor = fields[5].GetUInt32(); + uint32 spawns = fields[6].GetUInt32(); + delete result; + + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Name:\x3\x31\x30 %s \xF|\x2 CreatureID:\x3\x31\x30 %d \xF|\x2 DisplayID:\x3\x31\x30 %d \xF|\x2 Spawns:\x3\x31\x30 %d", name.c_str(), entry, modelid, spawns), true, CD->TYPE); + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Level:\x3\x31\x30 %d \xF|\x2 Faction:\x3\x31\x30 %d \xF|\x2 Armor:\x3\x31\x30 %d", level, faction, armor), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Creature ID." ,true, "ERROR"); + } + else + { + QueryResult *result = WorldDatabase.PQuery("SELECT entry, name FROM creature_template WHERE name LIKE '%%%s%%' LIMIT 10", _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + std::string items = "\002Creature Search Results:\x3\x31\x30 "; + //Send_IRCA(ChanOrPM(CD), "", true, CD->TYPE); + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string CreatureID = fields[0].GetCppString(); + std::string Name = fields[1].GetCppString(); + items.append(Name+"("+CreatureID+")\xF | \x3\x31\x30\x2"); + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), items, true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Creature. I Cant Find Any Creatures With Those Search Terms." ,true, "ERROR"); + } + } + if(_PARAMS[0] == "faction") + { + std::string faction = _PARAMS[1]; + if(atoi(faction.c_str()) > 0) + { + FactionEntry const *factionEntry = sFactionStore.LookupEntry(atoi(faction.c_str())); + if(factionEntry) + { + std::string name = factionEntry->name[sWorld.GetDefaultDbcLocale()]; + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2 Faction:\x3\x31\x30 %s \xF|\x2 FactionID:\x3\x31\x30 %s",name.c_str(), faction.c_str()), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown FactionID." ,true, "ERROR"); + + } + else + { + uint32 counter = 0; + std::string factions = "\002Faction Search Results:\x3\x31\x30 "; + for (uint32 id = 0; id < sFactionStore.GetNumRows(); id++) + { + FactionEntry const *factionEntry = sFactionStore.LookupEntry(id); + if(factionEntry) + { + MakeLower( _PARAMS[1] ); + std::string name = factionEntry->name[sWorld.GetDefaultDbcLocale()]; + MakeLower( name ); + if (name.find(_PARAMS[1]) != std::string::npos && counter < 10) + { + char factionid[100]; + sprintf(factionid, "%d", id); + factions.append(name+"("+factionid+")\xF | \x3\x31\x30\x2"); + ++counter; + } + } + } + if(counter == 0) + factions.append("No Factions Found."); + Send_IRCA(ChanOrPM(CD), factions, true, CD->TYPE); + } + } + if(_PARAMS[0] == "go") + { + std::string gobject = _PARAMS[1]; + if(atoi(gobject.c_str()) > 0) + { + WorldDatabase.escape_string(_PARAMS[1]); + QueryResult *result = WorldDatabase.PQuery("SELECT entry, type, displayId, name, faction, (SELECT count(*) FROM gameobject WHERE id = '%s') as spawns FROM gameobject_template WHERE entry = '%s';", _PARAMS[1].c_str(), _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + + uint32 entry = fields[0].GetUInt32(); + uint32 type = fields[1].GetUInt32(); + uint32 modelid = fields[2].GetUInt32(); + std::string name = fields[3].GetCppString(); + uint32 faction = fields[4].GetUInt32(); + uint32 spawns = fields[5].GetUInt32(); + delete result; + + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2GO Name:\x3\x31\x30 %s \xF|\x2 GameobjectID:\x3\x31\x30 %d \xF|\x2 DisplayID:\x3\x31\x30 %d \xF|\x2 Spawns:\x3\x31\x30 %d", name.c_str(), entry, modelid, spawns), true, CD->TYPE); + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Type:\x3\x31\x30 %d \xF|\x2 Faction:\x3\x31\x30 %d", type, faction), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Creature ID." ,true, "ERROR"); + } + else + { + QueryResult *result = WorldDatabase.PQuery("SELECT entry, name FROM gameobject_template WHERE name LIKE '%%%s%%' LIMIT 10", _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + std::string gos = "\002Gameobject Search Results:\x3\x31\x30 "; + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string GOID = fields[0].GetCppString(); + std::string GoName = fields[1].GetCppString(); + gos.append(GoName+"("+GOID+")\xF | \x3\x31\x30\x2"); + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), gos, true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Game Object. I Cant Find Any Game Object's With Those Search Terms." ,true, "ERROR"); + } + } + if(_PARAMS[0] == "item") + { + std::string item = _PARAMS[1]; + if(atoi(item.c_str()) > 0) + { + QueryResult *result = WorldDatabase.PQuery("SELECT entry, name, displayid, (SELECT count(*) FROM creature_loot_template WHERE item = '%s') as loot FROM `item_template` WHERE entry = %s", _PARAMS[1].c_str(), _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + QueryResult *result2 = CharacterDatabase.PQuery("SELECT count(*) FROM `character_inventory` WHERE item_template = %s", _PARAMS[1].c_str()); + Field *fields2 = result2->Fetch(); + uint32 charcnt = fields2[0].GetUInt32(); + delete result2; + + uint32 ItemID = fields[0].GetUInt32(); + std::string ItmName = fields[1].GetCppString(); + uint32 DisplayID = fields[2].GetUInt32(); + uint32 loots = 0; + loots = fields[3].GetUInt32(); + delete result; + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Item:\x3\x31\x30 %s \xF|\x2 ItemID:\x3\x31\x30 %d \xF|\x2 DisplayID:\x3\x31\x30 %d \xF|\x2 Owned By:\x3\x31\x30 %d players \xF|\x2 Dropped By:\x3\x31\x30 %d creatures", ItmName.c_str(), ItemID, DisplayID, charcnt, loots), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown ItemID." ,true, "ERROR"); + } + else + { + QueryResult *result = WorldDatabase.PQuery("SELECT entry, name FROM `item_template` WHERE name LIKE '%%%s%%' LIMIT 10", _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + std::string items = "\002Item Search Results:\x3\x31\x30 "; + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string ItemID = fields[0].GetCppString(); + std::string ItemName = fields[1].GetCppString(); + items.append(ItemName+"("+ItemID+")\xF | \x3\x31\x30\x2"); + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), items, true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Item. I Cant Find Any Items With Those Search Terms." ,true, "ERROR"); + } + } + if(_PARAMS[0] == "quest") + { + std::string quest = _PARAMS[1]; + if(atoi(quest.c_str()) > 0) + { + WorldDatabase.escape_string(_PARAMS[1]); + QueryResult *result = WorldDatabase.PQuery("SELECT entry, Title FROM quest_template WHERE entry = '%s';", _PARAMS[1].c_str(), _PARAMS[1].c_str()); + if(result) + { + QueryResult *result2 = CharacterDatabase.PQuery("SELECT count(*) FROM character_queststatus WHERE quest = '%s' AND status = '1';", _PARAMS[1].c_str()); + Field *fields2 = result2->Fetch(); + uint32 status = fields2[0].GetUInt32(); + delete result2; + + Field *fields = result->Fetch(); + uint32 entry = fields[0].GetUInt32(); + std::string name = fields[1].GetCppString(); + delete result; + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Quest Name:\x3\x31\x30 %s \xF|\x2 QuestID:\x3\x31\x30 %d \xF|\x2 Completed:\x3\x31\x30 %d times", name.c_str(), entry, status), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Quest ID." ,true, "ERROR"); + } + else + { + QueryResult *result = WorldDatabase.PQuery("SELECT entry, Title FROM quest_template WHERE Title LIKE '%%%s%%' LIMIT 10", _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + std::string quests = "\002Quest Search Results:\x3\x31\x30 "; + //Send_IRCA(ChanOrPM(CD), "", true, CD->TYPE); + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string QuestID = fields[0].GetCppString(); + std::string QuestName = fields[1].GetCppString(); + quests.append(QuestName+"("+QuestID+")\xF | \x3\x31\x30\x2"); + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), quests, true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Quest. I Cant Find Any Quest's With Those Search Terms." ,true, "ERROR"); + } + } + if(_PARAMS[0] == "skill") + { + std::string skill = _PARAMS[1]; + if(atoi(skill.c_str()) > 0) + { + SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(atoi(skill.c_str())); + if(skillInfo) + { + std::string name = skillInfo->name[sWorld.GetDefaultDbcLocale()]; + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Skill:\x3\x31\x30 %s \xF|\x2 SkillID:\x3\x31\x30 %s",name.c_str(), skill.c_str()), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown SkillID." ,true, "ERROR"); + + } + else + { + uint32 counter = 0; + std::string skills = "\002Skill Search Results:\x3\x31\x30 "; + for (uint32 id = 0; id < sSkillLineStore.GetNumRows(); id++) + { + SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(id); + if(skillInfo) + { + MakeLower( _PARAMS[1] ); + std::string name = skillInfo->name[sWorld.GetDefaultDbcLocale()]; + MakeLower( name ); + if (name.find(_PARAMS[1]) != std::string::npos && counter < 10) + { + char skillid[100]; + sprintf(skillid, "%d", id); + skills.append(name+"("+skillid+")\xF | \x3\x31\x30\x2"); + ++counter; + } + } + } + if(counter == 0) + skills.append("No Skills Found."); + Send_IRCA(ChanOrPM(CD), skills, true, CD->TYPE); + } + } + if(_PARAMS[0] == "spell") + { + std::string spell = _PARAMS[1]; + if(atoi(spell.c_str()) > 0) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(atoi(spell.c_str())); + if(spellInfo) + { + std::string name = spellInfo->SpellName[sWorld.GetDefaultDbcLocale()]; + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Spell:\x3\x31\x30 %s \xF|\x2 SpellID:\x3\x31\x30 %s",name.c_str(), spell.c_str()), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown SpellID." ,true, "ERROR"); + + } + else + { + uint32 counter = 0; + std::string spells = "\002Spell Search Results:\x3\x31\x30 "; + for (uint32 id = 0; id < sSpellStore.GetNumRows(); id++) + { + SpellEntry const *spellInfo = sSpellStore.LookupEntry(id); + if(spellInfo) + { + MakeLower( _PARAMS[1] ); + std::string name = spellInfo->SpellName[sWorld.GetDefaultDbcLocale()]; + MakeLower( name ); + if (name.find(_PARAMS[1]) != std::string::npos && counter < 10) + { + char itemid[100]; + sprintf(itemid, "%d", id); + spells.append(name+"("+itemid+")\xF | \x3\x31\x30\x2"); + ++counter; + } + } + } + if(counter == 0) + spells.append("No Spells Found."); + Send_IRCA(ChanOrPM(CD), spells, true, CD->TYPE); + } + } + if(_PARAMS[0] == "tele") + { + std::string tele = _PARAMS[1]; + if(atoi(tele.c_str()) > 0) + { + QueryResult *result = WorldDatabase.PQuery("SELECT * FROM `game_tele` WHERE id = %s", _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + + uint32 teleid = fields[0].GetUInt32(); + uint32 pos_x = fields[1].GetUInt32(); + uint32 pos_y = fields[2].GetUInt32(); + uint32 pos_z = fields[3].GetUInt32(); + uint32 oriet = fields[4].GetUInt32(); + uint32 map = fields[5].GetUInt32(); + std::string telname = fields[6].GetCppString(); + delete result; + + Send_IRCA(ChanOrPM(CD), MakeMsg("\x2Tele Name:\x3\x31\x30 %s \xF|\x2 TeleID:\x3\x31\x30 %d \xF|\x2 Coordinates:\x3\x31\x30 [X: %d, Y: %d, Z: %d, MAP: %d, Orientation: %d]", telname.c_str(), teleid, pos_x, pos_y, pos_z, map, oriet), true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Teleport Location ID." ,true, "ERROR"); + } + else + { + QueryResult *result = WorldDatabase.PQuery("SELECT id, name FROM `game_tele` WHERE name LIKE '%%%s%%' LIMIT 10", _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + std::string teles = "\002Tele Location Search Results:\x3\x31\x30 "; + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string TeleID = fields[0].GetCppString(); + std::string TeleName = fields[1].GetCppString(); + teles.append(TeleName+"("+TeleID+")\xF | \x3\x31\x30\x2"); + result->NextRow(); + } + Send_IRCA(ChanOrPM(CD), teles, true, CD->TYPE); + delete result; + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Unknown Item. I Cant Find Any Items With Those Search Terms." ,true, "ERROR"); + } + } +} + +void IRCCmd::Level_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, CD->PCOUNT); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + std::string player = _PARAMS[0]; + normalizePlayerName(player); + uint64 guid = objmgr.GetPlayerGUIDByName(player.c_str()); + std::string s_newlevel = _PARAMS[1]; + uint8 i_newlvl = atoi(s_newlevel.c_str()); + if(!guid) + { + Send_IRCA(CD->USER, "\0034[ERROR] : Player Not Found!", true, "ERROR"); + return; + } else if ( i_newlvl < 1 || i_newlvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) ) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Level Must Be Between 1 And %i!",sConfig.GetIntDefault("MaxPlayerLevel", 70)), true, "ERROR"); + return; + } else + { + Player *chr = objmgr.GetPlayer(guid); + int32 i_oldlvl = chr ? chr->getLevel() : Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL,guid); + if(chr) + { + chr->GiveLevel(i_newlvl); + chr->InitTalentForLevel(); + chr->SetUInt32Value(PLAYER_XP,0); + WorldPacket data; + ChatHandler CH(chr->GetSession()); + if(i_oldlvl == i_newlvl) + CH.FillSystemMessageData(&data, "Your level progress has been reset."); + else + if(i_oldlvl < i_newlvl) + CH.FillSystemMessageData(&data, fmtstring("You have been leveled up (%i)",i_newlvl-i_oldlvl)); + else + if(i_oldlvl > i_newlvl) + CH.FillSystemMessageData(&data, fmtstring("You have been leveled down (%i)",i_newlvl-i_oldlvl)); + chr->GetSession()->SendPacket( &data ); + } + else + { + Tokens values; + Player::LoadValuesArrayFromDB(values,guid); + Player::SetUInt32ValueInArray(values,UNIT_FIELD_LEVEL,i_newlvl); + Player::SetUInt32ValueInArray(values,PLAYER_XP,0); + Player::SaveValuesArrayInDB(values,guid); + } + } + Send_IRCA(ChanOrPM(CD), "\00313[" + _PARAMS[0]+ "] : Has Been Leveled To " + _PARAMS[1] + ". By: "+CD->USER+".", true, CD->TYPE); +} + +void IRCCmd::Money_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 2); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + std::string player = _PARAMS[0]; + normalizePlayerName(player); + uint64 guid = objmgr.GetPlayerGUIDByName(player.c_str()); + Player *chr = objmgr.GetPlayer(guid); + + std::string s_money = _PARAMS[1]; + int32 money = atoi(s_money.c_str()); + unsigned int gold = money / 10000; + unsigned int silv = (money % 10000) / 100; + unsigned int cop = (money % 10000) % 100; + char tempgold [100]; + sprintf(tempgold, "\x2\x3\x30\x37%ug \x3\x31\x34%us \x3\x30\x35%uc\xF", gold, silv, cop); + if(!guid) + { + Send_IRCA(CD->USER, "\0034[ERROR] : Player Not Found!", true, "ERROR"); + return; + } + else + { + Player *chr = objmgr.GetPlayer(guid); + uint32 moneyuser = 0; + if(chr) + moneyuser = chr->GetMoney(); + else { + CharacterDatabase.escape_string(player); + std::string sqlquery = "SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(data, ' ' , 1462), ' ' , -1) AS `gold` FROM `characters` WHERE `name` = '"+player+"';"; + QueryResult *result = CharacterDatabase.Query(sqlquery.c_str()); + Field *fields = result->Fetch(); + moneyuser = fields[0].GetInt32(); + delete result; + } + int32 addmoney = money; + int32 newmoney = moneyuser + addmoney; + char s_newmoney[255]; + sprintf(s_newmoney,"%d",newmoney); + if(addmoney < 0) + { + sLog.outDetail("USER1: %i, ADD: %i, DIF: %i\\n", moneyuser, addmoney, newmoney); + if(newmoney <= 0 ) + { + Send_IRCA(ChanOrPM(CD), "\00313["+player+"] : Has Had All Money Taken By: "+CD->USER.c_str()+".", true, CD->TYPE); + if(chr) + { + chr->SetMoney(0); + Send_Player(chr, MakeMsg("You Have Been Liquidated By: %s. Total Money Is Now 0.", CD->USER.c_str())); + } + else + CharacterDatabase.PExecute("UPDATE `characters` SET data=concat(substring_index(data,' ',1462-1),' ','%u',' ', right(data,length(data)-length(substring_index(data,' ',1462))-1) ) where guid='%u'",newmoney, guid ); + } + else + { + Send_IRCA(ChanOrPM(CD), "\00313["+player+"] : Has Had ("+s_money+"\00313) Taken From Them By: "+CD->USER.c_str()+".", true, CD->TYPE); + if(chr) + { + chr->SetMoney( newmoney ); + Send_Player(chr, MakeMsg("You Have Had %s Copper Taken From You By: %s.", _PARAMS[1].c_str(), CD->USER.c_str())); + } + else + CharacterDatabase.PExecute("UPDATE `characters` SET data=concat(substring_index(data,' ',1462-1),' ','%u',' ', right(data,length(data)-length(substring_index(data,' ',1462))-1) ) where guid='%u'",newmoney, guid ); + } + } + else + { + Send_IRCA(ChanOrPM(CD), "\00313["+player+"] : Has Been Given ("+tempgold+"\00313) From: "+CD->USER.c_str()+".", true, CD->TYPE); + if(chr) + { + chr->ModifyMoney( addmoney ); + Send_Player(chr, MakeMsg("You Have Been Given %s Copper. From: %s.", _PARAMS[1].c_str(), CD->USER.c_str())); + } + else + CharacterDatabase.PExecute("UPDATE `characters` SET data=concat(substring_index(data,' ',1462-1),' ','%u',' ', right(data,length(data)-length(substring_index(data,' ',1462))-1) ) where guid='%u'",newmoney, guid ); + } + } +} + +void IRCCmd::Mute_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 3); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + normalizePlayerName(_PARAMS[0]); + uint64 guid = objmgr.GetPlayerGUIDByName(_PARAMS[0]); + if(guid) + { + if(_PARAMS[1] == "release") + { + Player* plr = objmgr.GetPlayer(guid); + uint32 account_id = 0; + account_id = objmgr.GetPlayerAccountIdByGUID(guid); + loginDatabase.PExecute("UPDATE `account` SET `mutetime` = '0' WHERE `id` = '%u'", account_id ); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Has Been UnMuted By: "+CD->USER+"." , true, CD->TYPE); + if(plr) + { + plr->GetSession()->m_muteTime = 0; + Send_Player(plr, MakeMsg("You Have Been UnMuted By: %s.", CD->USER.c_str())); + } + } + else + { + if(_PARAMS[2] == "") + _PARAMS[2] = "No Reason Given"; + Player* plr = objmgr.GetPlayer(guid); + time_t mutetime = time(NULL) + atoi(_PARAMS[1].c_str())*60; + uint32 account_id = 0; + account_id = objmgr.GetPlayerAccountIdByGUID(guid); + if(plr) plr->GetSession()->m_muteTime = mutetime; + loginDatabase.PExecute("UPDATE `account` SET `mutetime` = " I64FMTD " WHERE `id` = '%u'",uint64(mutetime), account_id ); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Has Been Muted By: "+CD->USER+". For: "+_PARAMS[1]+" Minutes. Reason: "+_PARAMS[2] , true, CD->TYPE); + if(plr) Send_Player(plr, MakeMsg("You Have Been Muted By: %s. For: %s Minutes. Reason: %s", CD->USER.c_str(), _PARAMS[1].c_str(), _PARAMS[2].c_str())); + } + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Player Does Not Exist!", true, "ERROR"); +} + +void IRCCmd::Online_Players(_CDATA *CD) +{ + sIRC.Script_Lock[MCS_Players_Online] = true; + ZThread::Thread script(new mcs_OnlinePlayers(CD)); +} + +void IRCCmd::PM_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 2); + if (Player* plr = GetPlayer(_PARAMS[0])) + { + if(plr->isAcceptWhispers()) + { + std::string sMsg = MakeMsg("|cffFE87FD[%s] Whispers: %s|r", CD->USER.c_str(), _PARAMS[1].c_str()); + WorldPacket data(SMSG_MESSAGECHAT, 200); + data << (uint8)CHAT_MSG_SYSTEM; + data << (uint32)LANG_UNIVERSAL; + data << (uint64)plr->GetGUID(); + data << (uint32)0; + data << (uint64)plr->GetGUID(); + data << (uint32)(sMsg.length()+1); + data << sMsg; + data << (uint8)0; + plr->GetSession()->SendPacket(&data); + plr->SendPlaySound(3081, true); + Send_IRCA(ChanOrPM(CD), "\00313To ["+_PARAMS[0]+"] : "+_PARAMS[1]+".", true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Is Not Accepting Private Messages!", true, "ERROR"); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Player not online!", true, "ERROR"); +} + +void IRCCmd::Revive_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, CD->PCOUNT); + if (Player* plr = GetPlayer(_PARAMS[0])) + { + if(plr->isDead()) + { + plr->ResurrectPlayer(0.5f); + plr->SpawnCorpseBones(); + plr->SaveToDB(); + sIRC.Send_IRC_Channel(ChanOrPM(CD), " \00313["+_PARAMS[0]+"] : Has Been Revived By: " + CD->USER, true, CD->TYPE); + Send_Player(plr, MakeMsg("You Have Been Revived By: %s.", CD->USER.c_str())); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : "+_PARAMS[0]+" Is Not Dead!", true, "ERROR"); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : "+_PARAMS[0]+" Is Not Online!", true, "ERROR"); +} + +void IRCCmd::Saveall_Player(_CDATA *CD) +{ + ObjectAccessor::Instance().SaveAllPlayers(); + Send_IRCA(ChanOrPM(CD), "\00313["+CD->USER+"] : Has Saved All Players!", true, CD->TYPE); +} + +void IRCCmd::Shutdown_Mangos(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 1); + if(_PARAMS[0] == "cancel") + { + sWorld.ShutdownCancel(); + Send_IRCA(ChanOrPM(CD), "\0034Server Shutdown Has Been Cancelled.", true, CD->TYPE); + } + + int32 i_time = atoi(_PARAMS[0].c_str()); + if (i_time <= 0 && _PARAMS[0]!="0") + { + Send_IRCA(ChanOrPM(CD), "\00313["+CD->USER+"] : Please Enter A Number! And No Negative Numbers! "+_PARAMS[0]+" Seconds!?", true, CD->TYPE); + return; + } + if (i_time > 1) Send_IRCA(ChanOrPM(CD), "\00313["+CD->USER+"] : Has Requested Server To Be Shut Down In "+_PARAMS[0]+" Seconds!", true, CD->TYPE); + sWorld.ShutdownServ(i_time); + Delay(i_time*1000); + Send_IRCA(ChanOrPM(CD), "\0034Server Will Now Shut Down.. Good Bye!", true, CD->TYPE); + sIRC.Active = false; + sIRC.ResetIRC(); +} + +void IRCCmd::Spell_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 3); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + uint32 spell = atoi(_PARAMS[2].c_str()); + SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell); + if (Player* plr = GetPlayer(_PARAMS[0])) + { + if(spellInfo) + { + std::string name = spellInfo->SpellName[sWorld.GetDefaultDbcLocale()]; + if(_PARAMS[1] == "cast") + { + plr->CastSpell(plr, spell, true); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Has Had Spell "+name+" Casted On Them.", true, CD->TYPE); + } + if(_PARAMS[1] == "learn") + { + plr->learnSpell(spell); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Has Learned Spell "+name+".", true, CD->TYPE); + } + if(_PARAMS[1] == "unlearn") + { + plr->removeSpell(spell); + Send_IRCA(ChanOrPM(CD), "\00313["+_PARAMS[0]+"] : Has Unlearned Spell "+name+".", true, CD->TYPE); + } + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Incorrect Spell ID!", true, "ERROR"); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Player Not Online!", true, "ERROR"); +} + +void IRCCmd::Sysmsg_Server(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, CD->PCOUNT); + std::string ircchan = "#"; + ircchan += sIRC._irc_chan[sIRC.anchn].c_str(); + if(_PARAMS[0] == "a") + { + //std::string str = "|cffff0000[System Message]:|r" + _PARAMS[1]; + std::string ancmsg = MakeMsg("\00304,08\037/!\\\037\017\00304 System Message \00304,08\037/!\\\037\017 %s",_PARAMS[1].c_str()); + sWorld.SendWorldText(LANG_SYSTEMMESSAGE, _PARAMS[1].c_str()); + sIRC.Send_IRC_Channel(ircchan, ancmsg, true); + } + else if (_PARAMS[0] == "e") + { + std::string str = "|cffff0000[Server Event]:|r " + _PARAMS[1]; + std::string notstr = "[Server Event]: " + _PARAMS[1]; + std::string notmsg = MakeMsg("\00304,08\037/!\\\037\017\00304 Server Event \00304,08\037/!\\\037\017 %s",_PARAMS[1].c_str()); + WorldPacket data(SMSG_NOTIFICATION, (notstr.size()+1)); + data << notstr; + WorldPacket data2(SMSG_PLAY_SOUND,32); + data2 << (uint32)1400; + sWorld.SendGlobalMessage(&data2); + sWorld.SendGlobalMessage(&data); + sWorld.SendWorldText(LANG_EVENTMESSAGE, _PARAMS[1].c_str()); + sIRC.Send_IRC_Channel(ircchan, notmsg, true); + } + else if (_PARAMS[0] == "n") + { + std::string str = "Global notify: " + _PARAMS[1]; + std::string notmsg = MakeMsg("\00304,08\037/!\\\037\017\00304 Global Notify \00304,08\037/!\\\037\017 %s",_PARAMS[1].c_str()); + WorldPacket data(SMSG_NOTIFICATION, (str.size()+1)); + data << str; + sWorld.SendGlobalMessage(&data); + sIRC.Send_IRC_Channel(ircchan, notmsg, true); + } + else if (_PARAMS[0] == "add") + { + sIRC.Send_IRC_Channel(ircchan, "This command is currently borken.", true); + // Commented for now -- timer broken + //WorldDatabase.PExecute( "INSERT INTO IRC_AutoAnnounce (message, addedby) VALUES ('%s', '%s')", _PARAMS[1].c_str(), CD->USER.c_str()); + //std::string str = "|cffff0000[Automatic]:|r" + _PARAMS[1]; + //std::string ancmsg = MakeMsg("\00304,08\037/!\\\037\017\00304 Automatic System Message \00304,08\037/!\\\037\017 %s",_PARAMS[1].c_str()); + //sWorld.SendWorldText(LANG_AUTO_ANN, _PARAMS[1].c_str()); + //sIRC.Send_IRC_Channel(ircchan, ancmsg, true); + } + else if (_PARAMS[0] == "del") + { + WorldDatabase.PExecute( "DELETE FROM IRC_AutoAnnounce WHERE id = %s", _PARAMS[1].c_str()); + Send_IRCA(ChanOrPM(CD), MakeMsg("Deleted Automatic Announcement Message ID: %s", _PARAMS[1].c_str()), true, CD->TYPE); + } + else if (_PARAMS[0] == "list") + { + QueryResult *result = WorldDatabase.PQuery("SELECT * FROM IRC_AutoAnnounce LIMIT 5;", _PARAMS[1].c_str()); + if(result) + { + Field *fields = result->Fetch(); + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string id = fields[0].GetCppString(); + std::string message = fields[1].GetCppString(); + std::string addedby = fields[2].GetCppString(); + Send_IRCA(ChanOrPM(CD), MakeMsg("ID: %s - Added By: %s - Message: %s", id.c_str(), addedby.c_str(), message.c_str()), true, CD->TYPE); + result->NextRow(); + } + delete result; + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : No Auto Announce Messages Are In The Database.", true, "ERROR"); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Please Use (a-Announce)(n-Notify)(e-Event) As Second Parameter!", true, "ERROR"); +} + +void IRCCmd::Tele_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 4); + if(AcctLevel(_PARAMS[0]) > GetLevel(CD->USER) && (sIRC.BOTMASK & 512)!= 0) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : Nice Try, This Player Has A Higher GM Level Than You! [ %i ]", AcctLevel(_PARAMS[0])), true, "ERROR"); + return; + } + bool DoTeleport = false; + float pX, pY, pZ, pO = 0; + uint32 mapid = 0; + std::string rMsg = " \0034[ERROR] : Teleport Failed!"; + std::string wMsg = "Invalid Tele Location"; + Player* plr = GetPlayer(_PARAMS[0]); + if(plr) + { + if(plr->isInFlight() || plr->isInCombat()) + { + Send_IRCA(CD->USER, MakeMsg("\0034[ERROR] : %s Is Busy And Cannot Be Teleported! They Could Be In Combat, Or Flying.",_PARAMS[0].c_str()), true, "ERROR"); + return; + } + } + if(_PARAMS[1] == "l" || _PARAMS[1].size() > 2) + { + if(_PARAMS[1].size() > 1) + _PARAMS[2] = _PARAMS[1]; + WorldDatabase.escape_string(_PARAMS[2]); + QueryResult *result = WorldDatabase.PQuery("SELECT position_x, position_y, position_z, orientation, map FROM game_tele WHERE name='%s';", _PARAMS[2].c_str()); + if (result) + { + Field *fields = result->Fetch(); + pX = fields[0].GetFloat(); + pY = fields[1].GetFloat(); + pZ = fields[2].GetFloat(); + pO = fields[3].GetFloat(); + mapid = fields[4].GetUInt16(); + delete result; + rMsg = MakeMsg(" \00313[%s] : Teleported To %s! By: %s.", + _PARAMS[0].c_str(), + _PARAMS[2].c_str(), + CD->USER.c_str()); + wMsg = MakeMsg("You Have Been Teleported To %s By: %s.", + _PARAMS[2].c_str(), + CD->USER.c_str()); + DoTeleport = true; + } + else + { + WorldDatabase.escape_string(_PARAMS[2]); + QueryResult *result = WorldDatabase.PQuery("SELECT name FROM game_tele WHERE name LIKE '%%%s%%' LIMIT 7;", _PARAMS[2].c_str()); + if (result) + { + std::string telename = "<> "; + for (uint64 i=0; i < result->GetRowCount(); i++) + { + Field *fields = result->Fetch(); + telename.append(fields[0].GetCppString()); + result->NextRow(); + telename.append(" <> "); + } + delete result; + Send_IRCA(CD->USER, "I Cannot Find Location: "+_PARAMS[2]+" . Perhaps One Of These Will Work For You.", true, "ERROR"); + Send_IRCA(CD->USER, telename, true, "ERROR"); + return; + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Location Not Found! Nothing Even Close Found!", true, "ERROR"); + return; + } + } + else if(_PARAMS[1] == "c") + { + std::string* _PARAMSA = getArray(_PARAMS[2], 4); + pX = atof(_PARAMSA[1].c_str()); + pY = atof(_PARAMSA[2].c_str()); + pZ = atof(_PARAMSA[3].c_str()); + mapid = atoi(_PARAMSA[0].c_str()); + rMsg = MakeMsg(" \00313[%s] : Teleported To Map: %s. Position: X(%s) Y(%s) Z(%s)! By: %s.", + _PARAMS[0].c_str(), + _PARAMSA[0].c_str(), + _PARAMSA[1].c_str(), + _PARAMSA[2].c_str(), + _PARAMSA[3].c_str(), + CD->USER.c_str()); + wMsg = MakeMsg("You Have Been Teleported To Map: %s. Position: X(%s) Y(%s) Z(%s)! By: %s.", + _PARAMSA[0].c_str(), + _PARAMSA[1].c_str(), + _PARAMSA[2].c_str(), + _PARAMSA[3].c_str(), + CD->USER.c_str()); + DoTeleport = true; + } + else if(_PARAMS[1] == "r") + { + if(plr) + { + pX = plr->m_recallX; + pY = plr->m_recallY; + pZ = plr->m_recallZ; + pO = plr->m_recallO; + mapid = plr->m_recallMap; + rMsg = MakeMsg(" \00313[%s] : Has Been Recalled To Their Previous Location.", + _PARAMS[0].c_str()); + wMsg = MakeMsg("You Have Been Recalled To Your Previous Location. By: %s", + CD->USER.c_str()); + DoTeleport = true; + } + else + { + Send_IRCA(CD->USER, MakeMsg("\00313[%s] : Cannot Be Recalled, They Are Not Online.", _PARAMS[0].c_str()), true, "ERROR"); + return; + } + + } + else if(_PARAMS[1] == "to") + { + Player* plr2 = GetPlayer(_PARAMS[2]); + if(plr2) + { + plr2->GetContactPoint(plr, pX, pY, pZ); + mapid = plr2->GetMapId(); + } + else + { + if(uint64 guid = objmgr.GetPlayerGUIDByName(_PARAMS[2].c_str())) + { + bool in_flight; + Player::LoadPositionFromDB(mapid, pX, pY, pZ, pO, in_flight, guid); + } + else + { + Send_IRCA(CD->USER, "\0034[ERROR] : Second Player Not Found!", true, "ERROR"); + return; + } + } + rMsg = MakeMsg(" \00313[%s] : Teleported To Player: [%s] By: %s.", + _PARAMS[0].c_str(), + _PARAMS[2].c_str(), + CD->USER.c_str()); + wMsg = MakeMsg("You Are Being Teleported To: %s. By: %s.", + _PARAMS[2].c_str(), + CD->USER.c_str()); + DoTeleport = true; + } + if(DoTeleport) + { + if(MapManager::IsValidMapCoord(mapid, pX ,pY)) + { + //if player is online teleport them in real time, if not set the DB to our coordinates. + if(plr) + { + plr->SaveRecallPosition(); + plr->TeleportTo(mapid, pX, pY, pZ, pO); + sIRC.Send_IRC_Channel(ChanOrPM(CD), rMsg, true, CD->TYPE); + Send_Player(plr, wMsg); + } + else + { + uint64 guid = objmgr.GetPlayerGUIDByName(_PARAMS[0]); + Player::SavePositionInDB(mapid,pX,pY,pZ,pO,MapManager::Instance().GetZoneId(mapid,pX,pY),guid); + sIRC.Send_IRC_Channel(ChanOrPM(CD), rMsg + " \0034*Offline Tele.* ", true, CD->TYPE); + } + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Invalid Location!", true, "ERROR"); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : Invalid Paramaters, Please Try Again [ "+sIRC._cmd_prefx+"help tele ] For More Information. ", true, "ERROR"); +} + +void IRCCmd::Top_Player(_CDATA *CD) +{ + std::string* _PARAMS = getArray(CD->PARAMS, 2); + uint32 limitr = 10; + if(atoi(_PARAMS[1].c_str()) > 0 && GetLevel(CD->USER) >= sIRC._op_gm_lev) + limitr = atoi(_PARAMS[1].c_str()); + if(_PARAMS[0] == "accttime") + { + QueryResult *result = CharacterDatabase.PQuery("SELECT account, name, (SUM(totaltime)) AS combinetime FROM characters GROUP BY account ORDER BY combinetime DESC LIMIT 0, %d ", limitr); + if(result) + { + Field *fields = result->Fetch(); + std::string tptime = MakeMsg("\x2 Top%d Accounts By Played Time:\x3\x31\x30 ", limitr); + for (uint64 i=0; i < result->GetRowCount(); i++) + { + uint32 account = fields[0].GetUInt32(); + std::string PlName = GetAcctNameFromID(account); + std::string Time = SecToDay(fields[2].GetCppString()); + uint32 rank = i+1; + tptime.append(MakeMsg("[%u]%s %s \xF| \x3\x31\x30\x2", rank, PlName.c_str(), Time.c_str())); + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), tptime, true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : No Accounts Returned." ,true, "ERROR"); + } + if(_PARAMS[0] == "chartime") + { + QueryResult *result = CharacterDatabase.PQuery("SELECT name, totaltime FROM characters ORDER BY totaltime DESC LIMIT 0, %d ", limitr); + if(result) + { + Field *fields = result->Fetch(); + std::string tptime = MakeMsg("\x2 Top%d Characters By Played Time:\x3\x31\x30 ", limitr); + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string Name = fields[0].GetCppString(); + std::string Time = SecToDay(fields[1].GetCppString()); + uint32 rank = i+1; + tptime.append(MakeMsg("[%u]%s %s \xF| \x3\x31\x30\x2", rank, Name.c_str(), Time.c_str())); + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), tptime, true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : No Characters Returned." ,true, "ERROR"); + } + if(_PARAMS[0] == "money") + { + QueryResult *result = CharacterDatabase.PQuery("SELECT name, CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(data, ' ', 1462), ' ', -1) AS UNSIGNED) AS money FROM characters ORDER BY money DESC LIMIT 0, %d ", limitr); + if(result) + { + Field *fields = result->Fetch(); + std::string tptime = MakeMsg("\x2 Top%d Characters By Money:\x3\x31\x30 ", limitr); + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string Name = fields[0].GetCppString(); + unsigned int money = fields[1].GetInt32(); + + uint32 rank = i+1; + + unsigned int gold = money / 10000; + unsigned int silv = (money % 10000) / 100; + unsigned int cop = (money % 10000) % 100; + char tempgold [100]; + sprintf(tempgold, "\x2\x3\x30\x37%ug \x3\x31\x34%us \x3\x30\x35%uc\xF", gold, silv, cop); + + tptime.append(MakeMsg("[%u]%s %s \xF| \x3\x31\x30\x2", rank, Name.c_str(), tempgold)); + result->NextRow(); + } + delete result; + Send_IRCA(ChanOrPM(CD), tptime, true, CD->TYPE); + } + else + Send_IRCA(CD->USER, "\0034[ERROR] : No Characters Returned." ,true, "ERROR"); + } + +} + +void IRCCmd::Who_Logged(_CDATA *CD) +{ + std::string OPS = ""; + for(std::list<_client*>::iterator i=_CLIENTS.begin(); i!=_CLIENTS.end();i++) + { + OPS.append(MakeMsg(" \002[GM:%d IRC: %s - WoW: %s]\002 ", (*i)->GMLevel, (*i)->Name.c_str(), (*i)->UName.c_str())); + } + Send_IRCA(ChanOrPM(CD), OPS, true, CD->TYPE); +} diff --git a/src/game/IRCConf.cpp b/src/game/IRCConf.cpp new file mode 100644 index 00000000000..92102cd9e41 --- /dev/null +++ b/src/game/IRCConf.cpp @@ -0,0 +1,172 @@ +/* + * MangChat By |Death| And Cybrax + * + * This Program Is Free Software; You Can Redistribute It And/Or Modify It Under The Terms + * Of The GNU General Public License + * Written and Developed by Cybrax. cybraxvd@gmail.com + * |Death| , Lice , Dj_baby & Sanaell, Tase + * With Help And Support From The MaNGOS Project Community. + * PLEASE RETAIN THE COPYRIGHT OF THE AUTHORS. + */ +#include "IRCClient.h" +#include "IRCCmd.h" +#include "../shared/Config/Config.h" +#include "IRCConf.h" +Config MCConfig; +void IRCClient::SetCfg(char const* cfgfile) +{ + sIRC.CfgFile = cfgfile; +} +bool IRCClient::LoadConfig(char const* cfgfile) +{ + if (!MCConfig.SetSource(cfgfile)) + sLog.outString("*** MangChat: Unable to open configuration file, All default options are being used."); + else sLog.outString("*** MangChat: Found the configuration file, %s", cfgfile); + + int ConfCnt = 0; + sIRC._chan_count = 0; + if(MCConfig.GetIntDefault("irc.active", 1) == 1) + sIRC.Active = true; + else + sIRC.Active = false; + sIRC._Host = MCConfig.GetStringDefault("irc.host", "irc.freenode.net"); + if(sIRC._Host.size() > 0) + ConfCnt++; + sIRC._Mver = MCConfig.GetStringDefault("irc.mver", "Version 1.6.5"); + sIRC._Port = MCConfig.GetIntDefault("irc.port", 6667); + sIRC._User = MCConfig.GetStringDefault("irc.user", "MangChat"); + sIRC._Pass = MCConfig.GetStringDefault("irc.pass", "MyDumbPass"); + sIRC._Nick = MCConfig.GetStringDefault("irc.nick", "MangChat"); + sIRC._Auth = MCConfig.GetIntDefault("irc.auth", 0); + sIRC._Auth_Nick = MCConfig.GetStringDefault("irc.auth.nick", "AuthNick"); + sIRC._ICC = MCConfig.GetStringDefault("irc.icc", "001"); + sIRC._defchan = MCConfig.GetStringDefault("irc.defchan", "lobby"); + sIRC._ldefc = MCConfig.GetIntDefault("irc.ldef", 0); + sIRC._wct = MCConfig.GetIntDefault("irc.wct", 30000); + sIRC.ajoin = MCConfig.GetIntDefault("irc.ajoin", 1); + sIRC.ajchan = MCConfig.GetStringDefault("irc.ajchan", "world"); + sIRC.onlrslt = MCConfig.GetIntDefault("irc.online.result", 10); + sIRC.BOTMASK = MCConfig.GetIntDefault("Botmask", 0); + sIRC.logfile = MCConfig.GetStringDefault("irc.logfile.prefix", "IRC_"); + for(int i = 1; i < MAX_CONF_CHANNELS;i++) + { + std::ostringstream ss; + ss << i; + std::string ci = "irc.chan_" + ss.str(); + std::string t_chan = MCConfig.GetStringDefault(ci.c_str(), ""); + if(t_chan.size() > 0) + { + sIRC._chan_count++; + sIRC._irc_chan[sIRC._chan_count] = t_chan; + ci = "wow.chan_" + ss.str(); + sIRC._wow_chan[sIRC._chan_count] = MCConfig.GetStringDefault(ci.c_str(), t_chan.c_str()); + } + } + sIRC.JoinMsg = MCConfig.GetStringDefault("irc.joinmsg", "Whhaaazzzzaaaa, MangChat $Ver Baby!!"); + sIRC.RstMsg = MCConfig.GetStringDefault("irc.rstmsg", "MangChat Is Restarting, I Will Be Right Back!"); + sIRC.kikmsg = MCConfig.GetStringDefault("irc.kickmsg", "Do Not Kick Me Again, Severe Actions Will Be Taken!"); + // IRC LINES + sIRC.ILINES[WOW_IRC] = MCConfig.GetStringDefault("chat.wow_irc", "\003[\002$Name($Level)\002\003] $Msg"); + sIRC.ILINES[IRC_WOW] = MCConfig.GetStringDefault("chat.irc_wow", "\003[$Name]: $Msg"); + sIRC.ILINES[JOIN_WOW] = MCConfig.GetStringDefault("chat.join_wow", "\00312>>\00304 $Name \003Joined The Channel!"); + sIRC.ILINES[JOIN_IRC] = MCConfig.GetStringDefault("chat.join_irc", "\003[$Name]: Has Joined IRC!"); + sIRC.ILINES[LEAVE_WOW] = MCConfig.GetStringDefault("chat.leave_wow", "\00312<<\00304 $Name \003Left The Channel!"); + sIRC.ILINES[LEAVE_IRC] = MCConfig.GetStringDefault("chat.leave_irc", "\003[$Name]: Has Left IRC!"); + sIRC.ILINES[CHANGE_NICK] = MCConfig.GetStringDefault("chat.change_nick", "\003<> $Name Is Now Known As $NewName!"); + // MangChat Options + sIRC._MCA = MCConfig.GetIntDefault("irc.maxattempt", 10); + sIRC._autojoinkick = MCConfig.GetIntDefault("irc.autojoin_kick", 1); + sIRC._cmd_prefx = MCConfig.GetStringDefault("irc.command_prefix", "."); + + sIRC._op_gm = MCConfig.GetIntDefault("irc.op_gm_login", 0); + sIRC._op_gm_lev = MCConfig.GetIntDefault("irc.op_gm_level", 3); + + // Misc Options + sIRC.games = MCConfig.GetIntDefault("irc.fun.games", 0); + sIRC.gmlog = MCConfig.GetIntDefault("irc.gmlog", 1); + sIRC.BOTMASK = MCConfig.GetIntDefault("BotMask", 0); + sIRC.Status = MCConfig.GetIntDefault("irc.StatusChannel", 1); + sIRC.anchn = MCConfig.GetIntDefault("irc.AnnounceChannel", 1); + sIRC.autoanc = MCConfig.GetIntDefault("irc.auto.announce", 30); + sIRC.ojGM1 = MCConfig.GetStringDefault("irc.gm1", "[Moderator]"); + sIRC.ojGM2 = MCConfig.GetStringDefault("irc.gm2", "[Game Master]"); + sIRC.ojGM3 = MCConfig.GetStringDefault("irc.gm3", "[BugTracker]"); + sIRC.ojGM4 = MCConfig.GetStringDefault("irc.gm4", "[DevTeam Admin]"); + sIRC.ojGM5 = MCConfig.GetStringDefault("irc.gm5", "[Root Admin]"); + // REQUIRED GM LEVEL + QueryResult *result = WorldDatabase.PQuery("SELECT `Command`, `gmlevel` FROM `IRC_Commands` ORDER BY `Command`"); + if(result) + { + Field *fields = result->Fetch(); + for (uint64 i=0; i < result->GetRowCount(); i++) + { + std::string command = fields[0].GetCppString(); + uint32 gmlvl = fields[1].GetUInt32(); + if(command == "acct") sIRC.CACCT = gmlvl; + if(command == "ban") sIRC.CBAN = gmlvl; + if(command == "char") sIRC.CCHAN = gmlvl; + if(command == "char") sIRC.CCHAR = gmlvl; + if(command == "fun") sIRC.CFUN = gmlvl; + if(command == "help") sIRC.CHELP = gmlvl; + if(command == "inchan") sIRC.CINCHAN = gmlvl; + if(command == "info") sIRC.CINFO = gmlvl; + if(command == "item") sIRC.CITEM = gmlvl; + if(command == "jail") sIRC.CJAIL = gmlvl; + if(command == "kick") sIRC.CKICK = gmlvl; + if(command == "kill") sIRC._KILL = gmlvl; + if(command == "level") sIRC.CLEVEL = gmlvl; + if(command == "lookup") sIRC.CLOOKUP = gmlvl; + if(command == "money") sIRC.CMONEY = gmlvl; + if(command == "mute") sIRC.CMUTE = gmlvl; + if(command == "online") sIRC.CONLINE = gmlvl; + if(command == "pm") sIRC.CPM = gmlvl; + if(command == "restart") sIRC.CRESTART = gmlvl; + if(command == "revive") sIRC.CREVIVE = gmlvl; + if(command == "saveall") sIRC.CSAVEALL = gmlvl; + if(command == "shutdown") sIRC.CSHUTDOWN = gmlvl; + if(command == "spell") sIRC.CSPELL = gmlvl; + if(command == "sysmsg") sIRC.CSYSMSG = gmlvl; + if(command == "tele") sIRC.CTELE = gmlvl; + if(command == "top") sIRC.CTOP = gmlvl; + if(command == "who") sIRC.CWHO = gmlvl; + result->NextRow(); + } + delete result; + } + else + { + sIRC.CACCT = 3; + sIRC.CBAN = 3; + sIRC.CCHAN = 3; + sIRC.CCHAR = 3; + sIRC.CFUN = 3; + sIRC.CHELP = 3; + sIRC.CINCHAN = 3; + sIRC.CINFO = 3; + sIRC.CITEM = 3; + sIRC.CJAIL = 3; + sIRC.CKICK = 3; + sIRC._KILL = 3; + sIRC.CLEVEL = 3; + sIRC.CLOOKUP = 3; + sIRC.CMONEY = 3; + sIRC.CMUTE = 3; + sIRC.CONLINE = 3; + sIRC.CPM = 3; + sIRC.CRESTART = 3; + sIRC.CREVIVE = 3; + sIRC.CSAVEALL = 3; + sIRC.CSHUTDOWN = 3; + sIRC.CSPELL = 3; + sIRC.CSYSMSG = 3; + sIRC.CTELE = 3; + sIRC.CTOP = 3; + sIRC.CWHO = 3; + } + return true; +} + +std::string IRCClient::GetChatLine(int nItem) +{ + return sIRC.ILINES[nItem]; +} diff --git a/src/game/IRCConf.h b/src/game/IRCConf.h new file mode 100644 index 00000000000..9fa646d79d5 --- /dev/null +++ b/src/game/IRCConf.h @@ -0,0 +1,16 @@ +#ifndef MC_CONFIG_H +#define MC_CONFIG_H + +#include "../framework/Platform/CompilerDefs.h" + +// Format is YYYYMMDDRR where RR is the change in the conf file +// for that day. +#define MANGCHAT_CONF_VERSION 2008011901 + +#if PLATFORM == PLATFORM_WINDOWS + #define _MANGCHAT_CONFIG "trinitycore.conf" +#else + #define _MANGCHAT_CONFIG "@sysconfdir@/trinitycore.conf" +#endif + +#endif diff --git a/src/game/IRCConf.h.in b/src/game/IRCConf.h.in new file mode 100644 index 00000000000..9fa646d79d5 --- /dev/null +++ b/src/game/IRCConf.h.in @@ -0,0 +1,16 @@ +#ifndef MC_CONFIG_H +#define MC_CONFIG_H + +#include "../framework/Platform/CompilerDefs.h" + +// Format is YYYYMMDDRR where RR is the change in the conf file +// for that day. +#define MANGCHAT_CONF_VERSION 2008011901 + +#if PLATFORM == PLATFORM_WINDOWS + #define _MANGCHAT_CONFIG "trinitycore.conf" +#else + #define _MANGCHAT_CONFIG "@sysconfdir@/trinitycore.conf" +#endif + +#endif diff --git a/src/game/IRCFunc.h b/src/game/IRCFunc.h new file mode 100644 index 00000000000..4dca2847727 --- /dev/null +++ b/src/game/IRCFunc.h @@ -0,0 +1,251 @@ +#ifndef _IRC_CLIENT_FUNC +#define _IRC_CLIENT_FUNC + +std::string GetUser(std::string szU) +{ + int pos = szU.find("!"); + return szU.substr(0, pos); +} +// Delink will remove anything considered "non chat" from a string +// Linked items (items that players can click on to see a description) +// contain extra characters wich the client filter out, this function +// makes sure people on irc do not see those characters. +std::string Delink(std::string msg) +{ + std::size_t pos; + while((pos = msg.find("|Hitem")) != std::string::npos) + { + std::size_t find1 = msg.find("|h", pos); + std::size_t find2 = msg.find("|h", find1 + 2); + msg.replace(pos, find1 - pos + 2, "\x2"); + msg.replace(msg.find("|h", pos), 2, "\x2"); + } + while((pos = msg.find("|Henchant")) != std::string::npos) + { + std::size_t find1 = msg.find("|h", pos); + std::size_t find2 = msg.find("|h", find1 + 2); + msg.replace(pos, find1 - pos + 2, "\x2"); + msg.replace(msg.find("|h", pos), 2, "\x2"); + //msg.replace(find2, 2, "\x2"); + } + return msg; +} + +// This function converts the characters used by the client to identify colour to IRC format. +std::string WoWcol2IRC(std::string msg) +{ + std::size_t pos; + char IRCCol[9][4] = { "\xF", "\xF", "\x3\x31\x34", "\x3\x30\x33", "\x3\x31\x32", "\x3\x30\x36", "\x3\x30\x37", "\x3\x30\x34", "\x3\x30\x37"}; + char WoWCol[9][12] = { "|r", "|cffffffff", "|cff9d9d9d", "|cff1eff00", "|cff0070dd", "|cffa335ee", "|cffff8000", "|cffe6cc80", "|cffffd000"}; + for (int i=0; i<=8; i++) + { + while ((pos = msg.find(WoWCol[i])) != std::string::npos) + { + if (i == 0) + msg.replace(pos, 2, IRCCol[i]); + else + msg.replace(pos, 10, IRCCol[i]); + } + } + return msg; +} + +// This function converts the characters used by IRC to identify colour to a format the client can understand. +std::string IRCcol2WoW(std::string msg) +{ + std::size_t pos; + char IRCCol[16][4] = { "\x3\x30", "\x3\x31", "\x3\x32", "\x3\x33", "\x3\x34", "\x3\x35", "\x3\x36", "\x3\x37", "\x3\x38", "\x3\x39", "\x3\x31\x30", "\x3\x31\x31", "\x3\x31\x32", "\x3\x31\x33", "\x3\x31\x34", "\x3\x31\x35"}; + char IRCCol2[10][4] = { "\x3\x30\x30", "\x3\x30\x31", "\x3\x30\x32", "\x3\x30\x33", "\x3\x30\x34", "\x3\x30\x35", "\x3\x30\x36", "\x3\x30\x37", "\x3\x30\x38", "\x3\x30\x39"}; + char WoWcol[16][12] = { "|cffffffff", "|cff000000", "|cff00007f", "|cff009300", "|cffff0000", "|cff7f0000", "|cff9c009c", "|cfffc9300", "|cffffff00", "|cff00fc00", "|cff009393", "|cff00ffff", "|cff0000fc", "|cffff00ff", "|cff7f7f7f", "|cffd2d2d2"}; + for (int i=15; i>=0; i--) + { + if (i<10) + { + while ((pos = msg.find(IRCCol2[i])) != std::string::npos) + { + msg.replace(pos, 3, WoWcol[i]); + } + while ((pos = msg.find(IRCCol[i])) != std::string::npos) + { + msg.replace(pos, 2, WoWcol[i]); + } + + } + else + { + while ((pos = msg.find(IRCCol[i])) != std::string::npos) + { + msg.replace(pos, 3, WoWcol[i]); + } + } + + // Remove Bold, Reverse, Underline from IRC + char Checker[3][3] = {"\x2","\x16","\x1F"}; // This is the Hex part not Dec. In Decimal its (2,22,31) + for(int I=0; I < 3; I++) + { + while ((pos = msg.find(Checker[I])) != std::string::npos) + { + msg.replace(pos, 1, ""); + } + } + // Finished Removing ! + + } + + while ((pos = msg.find("\x3")) != std::string::npos) + { + msg.replace(pos, 1, "|r"); + } + while ((pos = msg.find("\xF")) != std::string::npos) + { + msg.replace(pos, 1, "|r"); + } + + return msg; +} + +// This function compares 2 strings +int nocase_cmp(const string & s1, const string& s2) +{ + string::const_iterator it1=s1.begin(); + string::const_iterator it2=s2.begin(); + + //stop when either string's end has been reached + while ( (it1!=s1.end()) && (it2!=s2.end()) ) + { + if(::toupper(*it1) != ::toupper(*it2)) //letters differ? + // return -1 to indicate smaller than, 1 otherwise + return (::toupper(*it1) < ::toupper(*it2)) ? -1 : 1; + //proceed to the next character in each string + ++it1; + ++it2; + } + size_t size1=s1.size(), size2=s2.size(); // cache lengths + //return -1,0 or 1 according to strings' lengths + if (size1==size2) + return 0; + return (size1GetTeam()) + // { + // case 67:ChatTag.append("4");break; //horde + // case 469:ChatTag.append("12");break; //alliance + // } + std::string sMsg = sIRC.MakeMsg(sIRC.GetChatLine(CLINE), "$Msg", Msg); + // sMsg = ChatTag + MakeMsg(sMsg, "$Name", plr->GetName()); + if (plr->GetTeam() == 67) + sMsg = sIRC.MakeMsg(sMsg, "$Name", MakeMsgA("\0034%s\003", plr->GetName())); + else if (plr->GetTeam() == 469) + sMsg = sIRC.MakeMsg(sMsg, "$Name", MakeMsgA("\00312%s\003", plr->GetName())); + if(plr->isAFK()) + sMsg = sIRC.MakeMsg(sMsg, "$Tag", ""); + else if(plr->isDND()) + sMsg = sIRC.MakeMsg(sMsg, "$Tag", ""); + else + sMsg = sIRC.MakeMsg(sMsg, "$Tag", ""); + sMsg = sIRC.MakeMsg(sMsg, "$Level", MakeMsgA("%d", plr->getLevel())); + sMsg = Delink(sMsg); + sMsg = WoWcol2IRC(sMsg); + return sMsg; +} + +/* +std::string MakeMsg(std::string msg, std::string var, int val) +{ + std::ostringstream ss; + ss << val; + + std::string nval = ss.str(); + std::size_t start = msg.find(var); + if (start != std::string::npos) + msg.replace(start, var.length(), val); + return msg; +} +*/ +/* +std::string MakeMsg(const char *sLine, ... ) +{ + va_list ap; + char tmpoutp[1024]; + va_start(ap, sLine); + vsnprintf(tmpoutp, 1024, sLine, ap ); + va_end(ap); + std::string outp = tmpoutp; + return outp; +} +*/ + +// This function checks if a channel exists in out configuration +// Mangchat supports as many channels as you like +// However the default has been set to 10 +// if you wish to increase this you must edit the: +// MAX_CONF_CHANNELS variable in IRCClient.h +bool Channel_Valid(std::string Channel) +{ + for(int i=1;i < sIRC._chan_count + 1;i++) + { + if(nocase_cmp(sIRC._wow_chan[i], Channel)==0) + return true; + } + return false; +} + +std::string GetWoWChannel(std::string Channel) +{ + for(int i=1;i < sIRC._chan_count + 1;i++) + { + if("#" + sIRC._irc_chan[i] == Channel) + return sIRC._wow_chan[i]; + } + return ""; +} + +std::string GetIRCChannel(std::string Channel) +{ + for(int i=1;i < sIRC._chan_count + 1;i++) + { + if(sIRC._wow_chan[i] == Channel) + return sIRC._irc_chan[i]; + } + return ""; +} + +std::string* getArray(std::string PARAMS, int nCount, std::string ) +{ + std::string *array = new std::string[nCount]; + if(PARAMS.size() > 0) + { + int pcnt = 0; + size_t ps = 0; + size_t pc = -1; + for(int i = 0;i < nCount;i++) + { + pc = PARAMS.find(" ", pc + 1); + if(i + 1 == nCount && nCount != 1) + { + if(ps > 0 && pc > 0) + array[i] = PARAMS.substr(ps, PARAMS.size() - ps); + } + else + array[i] = PARAMS.substr(ps, pc - ps); + ps = pc + 1; + } + } + return array; +} +#endif diff --git a/src/game/IRCIO.cpp b/src/game/IRCIO.cpp new file mode 100644 index 00000000000..c8c0213ed0d --- /dev/null +++ b/src/game/IRCIO.cpp @@ -0,0 +1,436 @@ +#include "IRCClient.h" +#include "IRCCmd.h" +#include "IRCFunc.h" +#include "ObjectAccessor.h" +#include "ObjectMgr.h" +#include "WorldPacket.h" +#include "ChannelMgr.h" +#include "Config/ConfigEnv.h" +#include "Channel.h" +#include "World.h" + +IRCCmd Command; +void IRCClient::Handle_IRC(std::string sData) +{ + sLog.outDebug(sData.c_str()); + // If first 5 chars are ERROR then something is wrong + // either link is being closed, nickserv ghost command, etc... + if(sData.substr(0, 5) == "ERROR") + { + Disconnect(); + return; + } + if(sData.substr(0, 4) == "PING") + { + // if the first 4 characters contain PING + // the server is checking if we are still alive + // sen back PONG back plus whatever the server send with it + SendIRC("PONG " + sData.substr(4, sData.size() - 4)); + } + else + { + // if the first line contains : its an irc message + // such as private messages channel join etc. + if(sData.substr(0, 1) == ":") + { + // find the spaces in the receieved line + size_t p1 = sData.find(" "); + size_t p2 = sData.find(" ", p1 + 1); + // because the irc protocol uses simple spaces + // to seperate data we can easy pick them out + // since we know the position of the spaces + std::string USR = sData.substr(1, p1 - 1); + std::string CMD = sData.substr(p1 + 1, p2 - p1 - 1); + // trasform the commands to lowercase to make sure they always match + std::transform(CMD.begin(), CMD.end(), CMD.begin(), towlower); + // Extract the username from the first part + std::string szUser = GetUser(USR); + // if we receieved the internet connect code + // we know for sure that were in and we can + // authenticate ourself. + if(CMD == sIRC._ICC) + { + // _Auth is defined in mangosd.conf (irc.auth) + // 0 do not authenticate + // 1 use nickserv + // 2 use quakenet + // aditionally you can provide you own authentication method here + switch(sIRC._Auth) + { + case 1: + SendIRC("PRIVMSG nickserv :IDENTIFY " + sIRC._Pass); + break; + case 2: + SendIRC("PRIVMSG nickserv :IDENTIFY " + sIRC._Auth_Nick + " " + sIRC._Pass); + break; + case 3: + SendIRC("PRIVMSG Q@CServe.quakenet.org :AUTH " + sIRC._Nick + " " + sIRC._Pass); + break; + case 4: + SendIRC("PRIVMSG Q@CServe.quakenet.org :AUTH " + sIRC._Auth_Nick + " " + sIRC._Pass); + break; + } + // if we join a default channel leave this now. + if(sIRC._ldefc==1) + SendIRC("PART #" + sIRC._defchan); + // Loop thru the channel array and send a command to join them on IRC. + for(int i=1;i < sIRC._chan_count + 1;i++) + { + SendIRC("JOIN #" + sIRC._irc_chan[i]); + } + } + // someone joined the channel this could be the bot or another user + if(CMD == "join") + { + size_t p = sData.find(":", p1); + std::string CHAN = sData.substr(p + 1, sData.size() - p - 2); + // if the user is us it means we join the channel + if ((szUser == sIRC._Nick) ) + { + // its us that joined the channel + Send_IRC_Channel(CHAN, MakeMsg(MakeMsg(sIRC.JoinMsg, "$Ver", sIRC._Mver.c_str()), "$Trigger", sIRC._cmd_prefx.c_str()), true); + } + else + { + // if the user is not us its someone else that joins + // so we construct a message and send this to the clients. + // MangChat now uses Send_WoW_Channel to send to the client + // this makes MangChat handle the packets instead of previously the world. + if((sIRC.BOTMASK & 2) != 0) + Send_WoW_Channel(GetWoWChannel(CHAN).c_str(), IRCcol2WoW(MakeMsg(MakeMsg(GetChatLine(JOIN_IRC), "$Name", szUser), "$Channel", GetWoWChannel(CHAN)))); + } + } + // someone on irc left or quit the channel + if(CMD == "part" || CMD == "quit") + { + size_t p3 = sData.find(" ", p2 + 1); + std::string CHAN = sData.substr(p2 + 1, p3 - p2 - 1); + // Logout IRC Nick From MangChat If User Leaves Or Quits IRC. + if(Command.IsLoggedIn(szUser)) + { + _CDATA CDATA; + CDATA.USER = szUser; + Command.Handle_Logout(&CDATA); + } + // Construct a message and inform the clients on the same channel. + if((sIRC.BOTMASK & 2) != 0) + Send_WoW_Channel(GetWoWChannel(CHAN).c_str(), IRCcol2WoW(MakeMsg(MakeMsg(GetChatLine(LEAVE_IRC), "$Name", szUser), "$Channel", GetWoWChannel(CHAN)))); + } + // someone changed their nick + if (CMD == "nick" && (sIRC.BOTMASK & 128) != 0) + { + MakeMsg(MakeMsg(GetChatLine(CHANGE_NICK), "$Name", szUser), "$NewName", sData.substr(sData.find(":", p2) + 1)); + // If the user is logged in and changes their nick + // then we want to either log them out or update + // their nick in the bot. I chose to update the bots user list. + if(Command.IsLoggedIn(szUser)) + { + std::string NewNick = sData.substr(sData.find(":", p2) + 1); + // On freenode I noticed the server sends an extra character + // at the end of the string, so we need to erase the last + // character of the string. if you have a problem with getting + // the last letter of your nick erased, then remove the - 1. + NewNick.erase(NewNick.length() - 1, 1); + + for(std::list<_client*>::iterator i=Command._CLIENTS.begin(); i!=Command._CLIENTS.end();i++) + { + if((*i)->Name == szUser) + { + (*i)->Name = NewNick; + sIRC.Send_IRC_Channel(NewNick.c_str(), "I Noticed You Changed Your Nick, I Have Updated My Internal Database Accordingly.", true, "NOTICE"); + + // Figure why not output to the logfile, makes tracing problems easier. + sIRC.iLog.WriteLog(" %s : %s Changed Nick To: %s", sIRC.iLog.GetLogDateTimeStr().c_str(), szUser.c_str(), NewNick.c_str()); + } + } + } + + } + // someone was kicked from irc + if (CMD == "kick") + { + // extract the details + size_t p3 = sData.find(" ", p2 + 1); + size_t p4 = sData.find(" ", p3 + 1); + size_t p5 = sData.find(":", p4); + std::string CHAN = sData.substr(p2 + 1, p3 - p2 - 1); + std::string WHO = sData.substr(p3 + 1, p4 - p3 - 1); + std::string BY = sData.substr(p4 + 1, sData.size() - p4 - 1); + // if the one kicked was us + if(WHO == sIRC._Nick) + { + // and autojoin is enabled + // return to the channel + if(sIRC._autojoinkick == 1) + { + SendIRC("JOIN " + CHAN); + Send_IRC_Channel(CHAN, sIRC.kikmsg, true); + } + } + else + { + // if it is not us who was kicked we need to inform the clients someone + // was removed from the channel + // construct a message and send it to the players. + Send_WoW_Channel(GetWoWChannel(CHAN).c_str(), "[" + WHO + "]: Was Kicked From " + CHAN + " By: " + szUser); + } + } + // a private chat message was receieved. + if(CMD == "privmsg" || CMD == "notice") + { + // extract the values + size_t p = sData.find(" ", p2 + 1); + std::string FROM = sData.substr(p2 + 1, p - p2 - 1); + std::string CHAT = sData.substr(p + 2, sData.size() - p - 3); + // if this is our username it means we recieved a PM + if(FROM == sIRC._Nick) + { + if(CHAT.find("\001VERSION\001") < CHAT.size()) + { + Send_IRC_Channel(szUser, MakeMsg("\001VERSION MangChat %s ©2008 |Death|\001", "%s" , sIRC._Mver.c_str()), true, "PRIVMSG"); + } + // a pm is required for certain commands + // such as login. to validate the command + // we send it to the command class wich handles + // evrything else. + Command.IsValid(szUser, FROM, CHAT, CMD); + } + else + { + // if our name is not in it, it means we receieved chat on one of the channels + // magchat is in. the first thing we do is check if it is a command or not + if(!Command.IsValid(szUser, FROM, CHAT, CMD)) + { + Send_WoW_Channel(GetWoWChannel(FROM).c_str(), IRCcol2WoW(MakeMsg(MakeMsg(GetChatLine(IRC_WOW), "$Name", szUser), "$Msg", CHAT))); + } + // if we indeed receieved a command we do not want to display this to the players + // so only incanse the isvalid command returns false it will be sent to all player. + // the isvalid function will automaitcly process the command on true. + } + } + if(CMD == "mode") + { + // extract the mode details + size_t p3 = sData.find(" ", p2 + 1); + size_t p4 = sData.find(" ", p3 + 1); + size_t p5 = sData.find(" ", p4 + 1); + std::string CHAN = sData.substr(p2 + 1, p3 - p2 - 1); + std::string MODE = sData.substr(p3 + 1, p4 - p3 - 1); + std::string NICK = sData.substr(p4 + 1, p5 - p4 - 1); + bool _AmiOp; + _AmiOp = false; + //A mode was changed on us + if(NICK.c_str() == sIRC._Nick) + _AmiOp = true; + + } + } + } +} + +// This function is called in Channel.h +// based on nAction it will inform the people on +// irc when someone leaves one of the game channels. +// nAction is based on the struct CACTION +void IRCClient::Handle_WoW_Channel(std::string Channel, Player *plr, int nAction) +{ + // make sure that we are connected + if(sIRC.Connected && (sIRC.BOTMASK & 1)!= 0) + { + if(Channel_Valid(Channel)) + { + std::string GMRank = ""; + std::string pname = plr->GetName(); + bool DoGMAnnounce = false; + if (plr->GetSession()->GetSecurity() > 0 && (sIRC.BOTMASK & 8)!= 0) + DoGMAnnounce = true; + if (plr->isGameMaster() && (sIRC.BOTMASK & 16)!= 0) + DoGMAnnounce = true; + if(DoGMAnnounce) + { + switch(plr->GetSession()->GetSecurity()) //switch case to determine what rank the "gm" is + { + case 0: GMRank = "";break; + case 1: GMRank = "\0037"+sIRC.ojGM1;break; + case 2: GMRank = "\0037"+sIRC.ojGM2;break; + case 3: GMRank = "\0037"+sIRC.ojGM3;break; + case 4: GMRank = "\0037"+sIRC.ojGM4;break; + case 5: GMRank = "\0037"+sIRC.ojGM5;break; + } + } + std::string ChatTag = ""; + switch (plr->GetTeam()) + { + case 67:ChatTag.append("\0034");break; //horde + case 469:ChatTag.append("\00312");break; //alliance + } + std::string query = "INSERT INTO `IRC_Inchan` VALUES (%d,'"+pname+"','"+Channel+"')"; + std::string lchan = "DELETE FROM `IRC_Inchan` WHERE `guid` = %d AND `channel` = '"+Channel+"'"; + switch(nAction) + { + case CHANNEL_JOIN: + Send_IRC_Channel(GetIRCChannel(Channel), MakeMsg(MakeMsg(MakeMsg(GetChatLine(JOIN_WOW), "$Name", ChatTag + plr->GetName()), "$Channel", Channel), "$GM", GMRank)); + WorldDatabase.PExecute(lchan.c_str(), plr->GetGUID()); + WorldDatabase.PExecute(query.c_str(), plr->GetGUID()); + break; + case CHANNEL_LEAVE: + Send_IRC_Channel(GetIRCChannel(Channel), MakeMsg(MakeMsg(MakeMsg(GetChatLine(LEAVE_WOW), "$Name", ChatTag + plr->GetName()), "$Channel", Channel), "$GM", GMRank)); + WorldDatabase.PExecute(lchan.c_str(), plr->GetGUID()); + break; + } + } + } +} + +// This function sends chat to a irc channel or user +// to prevent the # beeing appended to send a msg to a user +// set the NoPrefix to true +void IRCClient::Send_IRC_Channel(std::string sChannel, std::string sMsg, bool NoPrefix, std::string nType) +{ + std::string mType = "PRIVMSG"; + if(Command.MakeUpper(nType.c_str()) == "NOTICE") + mType = "NOTICE"; + if(Command.MakeUpper(nType.c_str()) == "ERROR" && (sIRC.BOTMASK & 32)!= 0) + mType = "NOTICE"; + if(sIRC.Connected) + { + if(NoPrefix) + SendIRC(mType + " " + sChannel + " :" + sMsg); + else + SendIRC(mType + " #" + sChannel + " :" + sMsg); + } +} + +// This function sends a message to all irc channels +// that mangchat has in its configuration +void IRCClient::Send_IRC_Channels(std::string sMsg) +{ + for(int i=1;i < sIRC._chan_count + 1;i++) + Send_IRC_Channel(sIRC._irc_chan[i], sMsg); +} + +// This function is called in ChatHandler.cpp, any channel chat from wow will come +// to this function, validates the channel and constructs a message that is send to IRC +void IRCClient::Send_WoW_IRC(Player *plr, std::string Channel, std::string Msg) +{ + // Check if the channel exist in our configuration + if(Channel_Valid(Channel) && Msg.substr(0, 1) != ".") + Send_IRC_Channel(GetIRCChannel(Channel), MakeMsgP(WOW_IRC, Msg, plr)); +} + +void IRCClient::Send_WoW_Player(std::string sPlayer, std::string sMsg) +{ + normalizePlayerName(sPlayer); + if (Player* plr = ObjectAccessor::Instance().FindPlayerByName(sPlayer.c_str())) + Send_WoW_Player(plr, sMsg); +} + +void IRCClient::Send_WoW_Player(Player *plr, string sMsg) +{ + WorldPacket data(SMSG_MESSAGECHAT, 200); + data << (uint8)CHAT_MSG_SYSTEM; + data << (uint32)LANG_UNIVERSAL; + data << (uint64)plr->GetGUID(); + data << (uint32)0; + data << (uint64)plr->GetGUID(); + data << (uint32)(sMsg.length()+1); + data << sMsg; + data << (uint8)0; + plr->GetSession()->SendPacket(&data); +} + +// This function will construct and send a packet to all players +// on the given channel ingame. (previuosly found in world.cpp) +// it loops thru all sessions and checks if they are on the channel +// if so construct a packet and send it. +void IRCClient::Send_WoW_Channel(const char *channel, std::string chat) +{ + if(!(strlen(channel) > 0)) + return; + + #ifdef USE_UTF8 + std::string chat2 = chat; + if(ConvertUTF8(chat2.c_str(), chat2)) + chat = chat2; + #endif + + HashMapHolder::MapType& m = ObjectAccessor::Instance().GetPlayers(); + for(HashMapHolder::MapType::iterator itr = m.begin(); itr != m.end(); ++itr) + { + if (itr->second && itr->second->GetSession()->GetPlayer() && itr->second->GetSession()->GetPlayer()->IsInWorld()) + { + if(ChannelMgr* cMgr = channelMgr(itr->second->GetSession()->GetPlayer()->GetTeam())) + { + if(Channel *chn = cMgr->GetChannel(channel, itr->second->GetSession()->GetPlayer())) + { + WorldPacket data; + data.Initialize(SMSG_MESSAGECHAT); + data << (uint8)CHAT_MSG_CHANNEL; + data << (uint32)LANG_UNIVERSAL; + data << (uint64)0; + data << (uint32)0; + data << channel; + data << (uint64)0; + data << (uint32) (strlen(chat.c_str()) + 1); + data << IRCcol2WoW(chat.c_str()); + data << (uint8)0; + itr->second->GetSession()->SendPacket(&data); + } + } + } + } +} + +void IRCClient::Send_WoW_System(std::string Message) +{ + HashMapHolder::MapType& m = ObjectAccessor::Instance().GetPlayers(); + for(HashMapHolder::MapType::iterator itr = m.begin(); itr != m.end(); ++itr) + { + if (itr->second && itr->second->GetSession()->GetPlayer() && itr->second->GetSession()->GetPlayer()->IsInWorld()) + { + WorldPacket data; + data.Initialize(CHAT_MSG_SYSTEM); + data << (uint8)CHAT_MSG_SYSTEM; + data << (uint32)LANG_UNIVERSAL; + data << (uint64)0; + data << (uint32)0; + data << (uint64)0; + data << (uint32) (strlen(Message.c_str()) + 1); + data << Message.c_str(); + data << (uint8)0; + itr->second->GetSession()->SendPacket(&data); + } + } +} +void IRCClient::ResetIRC() +{ + SendData("QUIT"); + Disconnect(); +} + +#define CHAT_INVITE_NOTICE 0x18 + +// this function should be called on player login Player::AddToWorld +void IRCClient::AutoJoinChannel(Player *plr) +{ + //this will work if at least 1 player is logged in regrdless if he is on the channel or not + // the first person that login empty server is the one with bad luck and wont be invited, + // if at least 1 player is online the player will be inited to the chanel + + std::string m_name = sIRC.ajchan; + WorldPacket data; + data.Initialize(SMSG_CHANNEL_NOTIFY, 1+m_name.size()+1); + data << uint8(CHAT_INVITE_NOTICE); + data << m_name.c_str(); + + HashMapHolder::MapType& m = ObjectAccessor::Instance().GetPlayers(); + for(HashMapHolder::MapType::iterator itr = m.begin(); itr != m.end(); ++itr) + { + if (itr->second && itr->second->GetSession()->GetPlayer() && itr->second->GetSession()->GetPlayer()->IsInWorld()) + { + data << uint64(itr->second->GetGUID()); + break; + } + } + plr->GetSession()->SendPacket(&data); +} diff --git a/src/game/IRCLog.cpp b/src/game/IRCLog.cpp new file mode 100644 index 00000000000..07bde4a6326 --- /dev/null +++ b/src/game/IRCLog.cpp @@ -0,0 +1,60 @@ +#include "IRCLog.h" +#include "Config/ConfigEnv.h" +#include "IRCClient.h" +#include + +IRCLog::IRCLog() +{ + std::string logsDir = sConfig.GetStringDefault("LogsDir",""); + std::string ircLogName = logsDir + "/IRC_"; + std::string ircLogTimestamp = GetLogDateStr(); + ircLogName += ircLogTimestamp +".log"; + ircLogfile.open (ircLogName.c_str(), std::ios::app); +} + +IRCLog::~IRCLog() +{ + ircLogfile.close(); +} +// Was added because using the time for logs is very annoying... one log per day.. much cleaner looking.. +std::string IRCLog::GetLogDateStr() const +{ + time_t t = time(NULL); + tm* aTm = localtime(&t); + // YYYY year + // MM month (2 digits 01-12) + // DD day (2 digits 01-31) + // HH hour (2 digits 00-23) + // MM minutes (2 digits 00-59) + // SS seconds (2 digits 00-59) + char buf[20]; + snprintf(buf,20,"%04d-%02d-%02d",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday); + return std::string(buf); +} + +std::string IRCLog::GetLogDateTimeStr() const +{ + time_t t = time(NULL); + tm* aTm = localtime(&t); + // YYYY year + // MM month (2 digits 01-12) + // DD day (2 digits 01-31) + // HH hour (2 digits 00-23) + // MM minutes (2 digits 00-59) + // SS seconds (2 digits 00-59) + char buf[30]; + snprintf(buf,30,"[ %04d-%02d-%02d ] [ %02d:%02d:%02d ]",aTm->tm_year+1900,aTm->tm_mon+1,aTm->tm_mday,aTm->tm_hour,aTm->tm_min,aTm->tm_sec); + return std::string(buf); +} + +void IRCLog::WriteLog(const char *what, ...) +{ + va_list ap; + char tmpoutp[1024]; + va_start(ap, what); + vsnprintf(tmpoutp, 1024, what, ap ); + va_end(ap); + ircLogfile << tmpoutp; + ircLogfile << "\n"; + ircLogfile.flush(); +} diff --git a/src/game/IRCLog.h b/src/game/IRCLog.h new file mode 100644 index 00000000000..fd35a0aaa79 --- /dev/null +++ b/src/game/IRCLog.h @@ -0,0 +1,22 @@ +#ifndef _IRC_LOG_H +#define _IRC_LOG_H + +#include "Common.h" +#include + +class IRCLog +{ + public: + IRCLog(); + ~IRCLog(); + + public: + void WriteLog(const char *what, ...); + std::string GetLogDateStr() const; + std::string GetLogDateTimeStr() const; + private: + std::ofstream ircLogfile; +}; + + +#endif diff --git a/src/game/IRCSock.cpp b/src/game/IRCSock.cpp new file mode 100644 index 00000000000..cf76161cc02 --- /dev/null +++ b/src/game/IRCSock.cpp @@ -0,0 +1,146 @@ +#include "IRCClient.h" +#define MAXDATASIZE 512 +#include + +#include +#include + + +#define _UNICODE + +#ifdef _MBCS +#undef _MBCS +#endif + +bool IRCClient::InitSock() +{ + #ifdef _WIN32 + WSADATA wsaData; //WSAData + if(WSAStartup(MAKEWORD(2,0),&wsaData) != 0) + { + sLog.outError("IRC Error: Winsock Initialization Error"); + return false; + } + #endif + if ((sIRC.SOCKET = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) + { + sLog.outError("IRC Error: Socket Error"); + return false; + } + int on = 1; + if ( setsockopt ( sIRC.SOCKET, SOL_SOCKET, SO_REUSEADDR, ( const char* ) &on, sizeof ( on ) ) == -1 ) + { + sLog.outError("IRC Error: Invalid Socket"); + return false; + } + #ifdef _WIN32 + u_long iMode = 0; + ioctlsocket(sIRC.SOCKET, FIONBIO, &iMode); + #else + fcntl(sIRC.SOCKET, F_SETFL, O_NONBLOCK); // set to non-blocking + fcntl(sIRC.SOCKET, F_SETFL, O_ASYNC); // set to asynchronous I/O + #endif + return true; +} + +bool IRCClient::Connect(const char *cHost, int nPort) +{ + sIRC.Connected = false; + struct hostent *he; + if ((he=gethostbyname(cHost)) == NULL) + { + sLog.outError("IRCLIENT: Could not resolve host: %s", cHost); + return false; + } + struct sockaddr_in their_addr; + their_addr.sin_family = AF_INET; + their_addr.sin_port = htons(nPort); + their_addr.sin_addr = *((struct in_addr *)he->h_addr); + memset(&(their_addr.sin_zero), '\0', 8); + if (::connect(sIRC.SOCKET, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) + { + sLog.outError("IRCLIENT: Cannot connect to %s", cHost); + return false; + } + //FD_ZERO(&sIRC.sfdset); + //FD_SET(sIRC.SOCKET,&sIRC.sfdset); + sIRC.Connected = true; + return true; +} + +bool IRCClient::Login(std::string sNick, std::string sUser, std::string sPass) +{ + char hostname[128]; + gethostname(hostname, sizeof(hostname)); + if(SendIRC("HELLO")) + if(SendIRC("PASS " + sPass)) + if(SendIRC("NICK " + sNick)) + if(SendIRC("USER " + sUser + " " + (std::string)hostname + " MangChat :MangChat "+sIRC._Mver.c_str())) + return true; + return false; +} + +bool IRCClient::SendData(const char *data) +{ + if(sIRC.Connected) + { + if (send(sIRC.SOCKET, data, strlen(data), 0) == -1) + { + sLog.outError("IRC Error: Socket Receieve ** \n"); + //Disconnect(); + return false; + } + } + return true; +} + +bool IRCClient::SendIRC(std::string data) +{ + std::string RealData = data + "\n"; + return SendData(RealData.c_str()); +} + +void IRCClient::Disconnect() +{ + if(sIRC.SOCKET) + { + #ifdef _WIN32 + closesocket(sIRC.SOCKET); + //WSACleanup(); + #else + close(sIRC.SOCKET); + #endif + } +} + +void IRCClient::SockRecv() +{ +// wchar_t bufferdata; + + char szBuffer[MAXDATASIZE]; + + memset(szBuffer, 0, MAXDATASIZE ); + + int nBytesRecv = ::recv(sIRC.SOCKET, szBuffer, MAXDATASIZE - 1, 0 ); + if ( nBytesRecv == -1 ) + { + sLog.outError("Connection lost."); + sIRC.Connected = false; + } + else + { + if (-1 == nBytesRecv) + { + sLog.outError("Error occurred while receiving from socket."); + } + else + { + std::string reply; + std::istringstream iss(szBuffer); + while(getline(iss, reply)) + { + Handle_IRC(reply); + } + } + } +} diff --git a/src/game/Language.h b/src/game/Language.h index f805103047e..4bfe520ee78 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -640,6 +640,8 @@ enum MangosStrings LANG_ARENA_TESTING = 745, + LANG_AUTO_ANN = 746, + // in game strings LANG_PET_INVALID_NAME = 800, LANG_NOT_ENOUGH_GOLD = 801, diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp index 9bcbb80b811..cf4123c2f24 100644 --- a/src/game/Level1.cpp +++ b/src/game/Level1.cpp @@ -31,6 +31,7 @@ #include "Language.h" #include "CellImpl.h" #include "InstanceSaveMgr.h" +#include "IRCClient.h" #include "Util.h" #ifdef _DEBUG_VMAPS #include "VMapFactory.h" @@ -123,6 +124,14 @@ bool ChatHandler::HandleAnnounceCommand(const char* args) return false; sWorld.SendWorldText(LANG_SYSTEMMESSAGE,args); + + if((sIRC.BOTMASK & 256) != 0) + { + std::string ircchan = "#"; + ircchan += sIRC._irc_chan[sIRC.anchn].c_str(); + sIRC.Send_IRC_Channel(ircchan, sIRC.MakeMsg("\00304,08\037/!\\\037\017\00304 System Message \00304,08\037/!\\\037\017 %s", "%s", args), true); + } + return true; } @@ -139,6 +148,13 @@ bool ChatHandler::HandleNotifyCommand(const char* args) data << str; sWorld.SendGlobalMessage(&data); + if((sIRC.BOTMASK & 256) != 0) + { + std::string ircchan = "#"; + ircchan += sIRC._irc_chan[sIRC.anchn].c_str(); + sIRC.Send_IRC_Channel(ircchan, sIRC.MakeMsg("\00304,08\037/!\\\037\017\00304 Global Notify \00304,08\037/!\\\037\017 %s", "%s", args), true); + } + return true; } @@ -2348,6 +2364,25 @@ bool ChatHandler::HandleGoXYZCommand(const char* args) return true; } +bool ChatHandler::HandleIRCpmCommand(const char* args) +{ + std::string Msg = args; + if (Msg.find(" ") == std::string::npos) + return false; + std::string To = Msg.substr(0, Msg.find(" ")); + Msg = Msg.substr(Msg.find(" ") + 1); + std::size_t pos; + while((pos = To.find("||")) != std::string::npos) + { + std::size_t find1 = To.find("||", pos); + To.replace(pos, find1 - pos + 2, "|"); + } + sIRC.SendIRC("PRIVMSG "+To+" : ["+m_session->GetPlayerName()+"] : " + Msg); + //Msg = "|cffCC4ACCTo [" + To + "]: " + Msg + "|r"; + sIRC.Send_WoW_Player(m_session->GetPlayer(), "|cffCC4ACCTo ["+To+"]: "+Msg); + return true; +} + //teleport at coordinates bool ChatHandler::HandleGoZoneXYCommand(const char* args) { diff --git a/src/game/MCS_OnlinePlayers.cpp b/src/game/MCS_OnlinePlayers.cpp new file mode 100644 index 00000000000..8f48faa6adc --- /dev/null +++ b/src/game/MCS_OnlinePlayers.cpp @@ -0,0 +1,84 @@ +/* + * MangChat By |Death| And Cybrax + * + * This Program Is Free Software; You Can Redistribute It And/Or Modify It Under The Terms + * Of The GNU General Public License + * Written and Developed by Cybrax. cybraxvd@gmail.com + * |Death| , Lice , Dj_baby & Sanaell, Tase + * With Help And Support From The MaNGOS Project Community. + * PLEASE RETAIN THE COPYRIGHT OF THE AUTHORS. + */ +#include "MCS_OnlinePlayers.h" + +#include "MapManager.h" +#include "ObjectMgr.h" +#include "Config/ConfigEnv.h" + +mcs_OnlinePlayers::mcs_OnlinePlayers() { CD = NULL; } + +mcs_OnlinePlayers::mcs_OnlinePlayers(_CDATA *_CD) +{ + //create a new instance of data struct and copy its data + CD = new _CDATA(); + CD->CMD = _CD->CMD; + CD->FROM = _CD->FROM; + CD->PARAMS = _CD->PARAMS; + CD->PCOUNT = _CD->PCOUNT; + CD->USER = _CD->USER; + CD->TYPE = _CD->TYPE; +} + +mcs_OnlinePlayers::~mcs_OnlinePlayers() +{ + if(CD) + delete CD; +} + +void mcs_OnlinePlayers::run() +{ + int OnlineCount = 0; + std::string IRCOut = ""; + HashMapHolder::MapType& m = ObjectAccessor::Instance().GetPlayers(); + for(HashMapHolder::MapType::iterator itr = m.begin(); itr != m.end(); ++itr) + { + if (itr->second && itr->second->GetSession()->GetPlayer() && itr->second->GetSession()->GetPlayer()->IsInWorld()) + { + OnlineCount++; + Player *plr = itr->second->GetSession()->GetPlayer(); + std::string ChatTag = " "; + switch(plr->GetSession()->GetSecurity()) + { + case 0: ChatTag.append("");break; + case 1: ChatTag.append("\0037"+sIRC.ojGM1);break; + case 2: ChatTag.append("\0037"+sIRC.ojGM2);break; + case 3: ChatTag.append("\0037"+sIRC.ojGM3);break; + case 4: ChatTag.append("\0037"+sIRC.ojGM4);break; + case 5: ChatTag.append("\0037"+sIRC.ojGM5);break; + } + if(plr->isAFK()) + ChatTag.append("\002\0037\003\002"); + else if(plr->isDND()) + ChatTag.append("\002\0037\003\002"); + switch (plr->GetTeam()) + { + case 67:ChatTag.append("\0034");break; //horde + case 469:ChatTag.append("\00312");break; //alliance + } + + IRCOut.append(IRCCmd::MakeMsg("%s\002%s\003\017\002(%d)\002\017", ChatTag.c_str(), plr->GetName(), plr->getLevel())); + + // after XX players have been added to the string + // output to irc and reset for the next XX + if(OnlineCount % sIRC.onlrslt == 0) + { + sIRC.Send_IRC_Channel(IRCCmd::ChanOrPM(CD), IRCCmd::MakeMsg("\002 %s", IRCOut.c_str()), true, CD->TYPE.c_str()); + IRCOut = ""; + ZThread::Thread::sleep(1000); + } + } + } + // Remainder in IRCOUT && Total plyersonline + sIRC.Send_IRC_Channel(IRCCmd::ChanOrPM(CD), IRCCmd::MakeMsg("\002Players Online(%d):\017 %s", OnlineCount, IRCOut.c_str()), true, CD->TYPE); + + sIRC.Script_Lock[MCS_Players_Online] = false; +} diff --git a/src/game/MCS_OnlinePlayers.h b/src/game/MCS_OnlinePlayers.h new file mode 100644 index 00000000000..c93db9afdac --- /dev/null +++ b/src/game/MCS_OnlinePlayers.h @@ -0,0 +1,27 @@ +#ifndef _IRC_CLIENT_ONLINE +#define _IRC_CLIENT_ONLINE + +#include "IRCClient.h" +#include "IRCCmd.h" + +// the reason to run this command multithreaded +// is to be able to "spread" the output over irc +// for servers with high player count +// in order not to freeze the mangchat core with sleep +// a new thread is spawned it will output the player data +// evry "10 players" and pauzes to not spam irc +// in addition the command is locked so i cannot be used +// while active. + +class mcs_OnlinePlayers : public ZThread::Runnable +{ + public: + mcs_OnlinePlayers(); + mcs_OnlinePlayers(_CDATA *_CD); + ~mcs_OnlinePlayers(); + void run(); + public: + _CDATA *CD; +}; + +#endif diff --git a/src/game/Makefile.am b/src/game/Makefile.am index 9c953662a18..e839304ad8c 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -141,6 +141,21 @@ $(srcdir)/InstanceData.cpp \ $(srcdir)/InstanceData.h \ $(srcdir)/InstanceSaveMgr.cpp \ $(srcdir)/InstanceSaveMgr.h \ +$(srcdir)/IRCClient.cpp \ +$(srcdir)/IRCClient.h \ +$(srcdir)/IRCCmd.cpp \ +$(srcdir)/IRCCmd.h \ +$(srcdir)/IRCCmde.cpp \ +$(srcdir)/IRCConf.cpp \ +$(srcdir)/IRCConf.h \ +$(srcdir)/IRCConf.h \ +$(srcdir)/IRCFunc.h \ +$(srcdir)/IRCIO.cpp \ +$(srcdir)/IRCLog.cpp \ +$(srcdir)/IRCLog.h \ +$(srcdir)/IRCSock.cpp \ +$(srcdir)/MCS_OnlinePlayers.cpp \ +$(srcdir)/MCS_OnlinePlayers.h \ $(srcdir)/Item.cpp \ $(srcdir)/Item.h \ $(srcdir)/ItemEnchantmentMgr.cpp \ diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index 010af48e050..96f13891938 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -254,8 +254,9 @@ void WorldSession::HandleWhoOpcode( WorldPacket & recv_data ) data << uint8(0); // new 2.4.0 data << uint32( pzoneid ); // player zone id - // 49 is maximum player count sent to client - if ((++clientcount) == 49) + // 49 is maximum player count sent to client - can be overriden + // through config, but is unstable + if ((++clientcount) == sWorld.getConfig(CONFIG_MAX_WHO)) break; } diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 3beadc88278..ce2b936229f 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -58,6 +58,7 @@ #include "Database/DatabaseImpl.h" #include "Spell.h" #include "SocialMgr.h" +#include "IRCClient.h" #include @@ -1716,6 +1717,8 @@ void Player::AddToWorld() if(m_items[i]) m_items[i]->AddToWorld(); } + if(sIRC.ajoin == 1) + sIRC.AutoJoinChannel(this); } void Player::RemoveFromWorld() @@ -2146,6 +2149,17 @@ void Player::GiveLevel(uint32 level) UpdateAllStats(); + if((sIRC.BOTMASK & 64) != 0) + { + char temp [5]; + sprintf(temp, "%u", level); + std::string plevel = temp; + std::string pname = GetName(); + std::string ircchan = "#"; + ircchan += sIRC._irc_chan[sIRC.Status].c_str(); + sIRC.Send_IRC_Channel(ircchan, "\00311["+pname+"] : Has Reached Level: "+plevel, true); + } + if(sWorld.getConfig(CONFIG_ALWAYS_MAXSKILL)) // Max weapon skill when leveling up UpdateSkillsToMaxSkillsForLevel(); diff --git a/src/game/World.cpp b/src/game/World.cpp index 0e2b535c8d2..e352983768e 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -56,6 +56,8 @@ #include "InstanceSaveMgr.h" #include "WaypointManager.h" #include "Util.h" +#include "IRCClient.h" +#include "Language.h" INSTANTIATE_SINGLETON_1( World ); @@ -575,6 +577,8 @@ void World::LoadConfigSettings(bool reload) m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault("CharactersCreatingDisabled", 0); + m_configs[CONFIG_MAX_WHO] = sConfig.GetIntDefault("MaxWhoListReturns", 49); + m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10); if(m_configs[CONFIG_CHARACTERS_PER_REALM] < 1 || m_configs[CONFIG_CHARACTERS_PER_REALM] > 10) { @@ -1176,6 +1180,9 @@ void World::SetInitialWorldSettings() WorldDatabase.PExecute("INSERT INTO uptime (startstring, starttime, uptime) VALUES('%s', %ld, 0)", isoDate, m_startTime ); + static uint32 autoanc = 1; + autoanc = sIRC.autoanc; + m_timers[WUPDATE_OBJECTS].SetInterval(0); m_timers[WUPDATE_SESSIONS].SetInterval(0); m_timers[WUPDATE_WEATHERS].SetInterval(1000); @@ -1184,6 +1191,8 @@ void World::SetInitialWorldSettings() //Update "uptime" table based on configuration entry in minutes. m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*1000); //erase corpses every 20 minutes + m_timers[WUPDATE_AUTOANC].SetInterval(autoanc*MINUTE*1000); + //to set mailtimer to return mails every day between 4 and 5 am //mailtimer is increased when updating auctions //one second is 1000 -(tested on win system) @@ -1420,9 +1429,12 @@ void World::Update(time_t diff) m_timers[WUPDATE_EVENTS].Reset(); } - /// - ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove" - MapManager::Instance().DoDelayedMovesAndRemoves(); + if (m_timers[WUPDATE_AUTOANC].Passed()) + { + m_timers[WUPDATE_AUTOANC].Reset(); /// + SendRNDBroadcast(); + } + MapManager::Instance().DoDelayedMovesAndRemoves(); ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove" // update the instance reset times sInstanceSaveManager.Update(); @@ -2494,7 +2506,23 @@ void World::ProcessCliCommands() delete command; } // print the console message here so it looks right - p_zprintf("mangos>"); + p_zprintf("Trinity Core> "); +} + +void World::SendRNDBroadcast() +{ + std::string msg; + QueryResult *result = WorldDatabase.PQuery("SELECT `message` FROM `IRC_AutoAnnounce` ORDER BY RAND() LIMIT 1"); + if(!result) + return; + msg = result->Fetch()[0].GetString(); + delete result; + std::string str = "|cffff0000[Automatic]:|r"; + str += msg; + sWorld.SendWorldText(LANG_AUTO_ANN); + std::string ircchan = "#"; + ircchan += sIRC._irc_chan[sIRC.anchn].c_str(); + sIRC.Send_IRC_Channel(ircchan, sIRC.MakeMsg("\00304,08\037/!\\\037\017\00304 Automatic System Message \00304,08\037/!\\\037\017 %s", "%s", msg.c_str()), true); } void World::InitResultQueue() diff --git a/src/game/World.h b/src/game/World.h index c67d975ed07..742cd11385e 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -59,7 +59,10 @@ enum WorldTimers WUPDATE_UPTIME = 4, WUPDATE_CORPSES = 5, WUPDATE_EVENTS = 6, - WUPDATE_COUNT = 7 + WUPDATE_COUNT = 7, + + WUPDATE_AUTOANC = 7 + }; /// Configuration elements @@ -91,6 +94,7 @@ enum WorldConfigs CONFIG_STRICT_CHARTER_NAMES, CONFIG_STRICT_PET_NAMES, CONFIG_CHARACTERS_CREATING_DISABLED, + CONFIG_MAX_WHO, CONFIG_CHARACTERS_PER_ACCOUNT, CONFIG_CHARACTERS_PER_REALM, CONFIG_SKIP_CINEMATICS, @@ -365,6 +369,9 @@ class World WorldSession* FindSession(uint32 id) const; void AddSession(WorldSession *s); + + void SendRNDBroadcast(); + bool RemoveSession(uint32 id); /// Get the number of current active sessions void UpdateMaxSessionCounters(); diff --git a/src/shared/Database/DBCStructure.h b/src/shared/Database/DBCStructure.h index bca75923394..ce0887687ef 100644 --- a/src/shared/Database/DBCStructure.h +++ b/src/shared/Database/DBCStructure.h @@ -147,6 +147,7 @@ struct ChrClassesEntry uint32 powerType; // 3 // 4, unused //char* name[16]; // 5-20 unused + char* name[16]; // 5-20 unused // 21 string flag, unused //char* string1[16]; // 21-36 unused // 37 string flag, unused diff --git a/src/shared/Database/DBCfmt.cpp b/src/shared/Database/DBCfmt.cpp index e131d9379c5..0b7e1439520 100644 --- a/src/shared/Database/DBCfmt.cpp +++ b/src/shared/Database/DBCfmt.cpp @@ -23,7 +23,8 @@ const char BattlemasterListEntryfmt[]="niiixxxxxiiiixxssssssssssssssssxx"; const char CharTitlesEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi"; const char ChatChannelsEntryfmt[]="iixssssssssssssssssxxxxxxxxxxxxxxxxxx"; // ChatChannelsEntryfmt, index not used (more compact store) -const char ChrClassesEntryfmt[]="nxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix"; +//const char ChrClassesEntryfmt[]="nxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix"; +const char ChrClassesEntryfmt[]="nxixssssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix"; const char ChrRacesEntryfmt[]="nxixiixxixxxxissssssssssssssssxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; const char CreatureDisplayInfofmt[]="nxxxfxxxxxxxxx"; const char CreatureFamilyfmt[]="nfifiiiissssssssssssssssxx"; diff --git a/src/shared/Makefile.am b/src/shared/Makefile.am index fcdbd6e216b..5a64a45fc29 100644 --- a/src/shared/Makefile.am +++ b/src/shared/Makefile.am @@ -53,6 +53,7 @@ $(srcdir)/Util.cpp \ $(srcdir)/Util.h \ $(srcdir)/WorldPacket.h \ $(srcdir)/SystemConfig.h \ +$(srcdir)../game/IRCConf.h \ $(srcdir)/Auth/AuthCrypt.cpp \ $(srcdir)/Auth/AuthCrypt.h \ $(srcdir)/Auth/BigNumber.cpp \ diff --git a/src/trinitycore/CliRunnable.cpp b/src/trinitycore/CliRunnable.cpp index 2a92273f764..5f1518483f5 100644 --- a/src/trinitycore/CliRunnable.cpp +++ b/src/trinitycore/CliRunnable.cpp @@ -36,6 +36,7 @@ #include "MapManager.h" #include "PlayerDump.h" #include "Player.h" +#include "IRCClient.h" //CliCommand and CliCommandHolder are defined in World.h to avoid cyclic deps @@ -313,6 +314,14 @@ void CliBroadcast(char *text,pPrintf zprintf) sWorld.SendWorldText(LANG_SYSTEMMESSAGE,textUtf8.c_str()); zprintf("Broadcasting to the world: %s\r\n",textUtf8.c_str()); + + if((sIRC.BOTMASK & 256) != 0) + { + std::string ircchan = "#"; + ircchan += sIRC._irc_chan[sIRC.anchn].c_str(); + sIRC.Send_IRC_Channel(ircchan, sIRC.MakeMsg("\00304,08\037/!\\\037\017\00304 System Message \00304,08\037/!\\\037\017 %s", "%s", text), true); + } + } /// Print the list of commands and associated description diff --git a/src/trinitycore/Main.cpp b/src/trinitycore/Main.cpp index 27e8c0861ce..1c3ec6fea6e 100644 --- a/src/trinitycore/Main.cpp +++ b/src/trinitycore/Main.cpp @@ -25,6 +25,8 @@ #include "Config/ConfigEnv.h" #include "Log.h" #include "Master.h" +#include "../game/IRCConf.h" +#include "../game/IRCClient.h" #ifndef _TRINITY_CORE_CONFIG # define _TRINITY_CORE_CONFIG "trinitycore.conf" @@ -75,6 +77,7 @@ extern int main(int argc, char **argv) { ///- Command line parsing to get the configuration file name char const* cfg_file = _TRINITY_CORE_CONFIG; + char const* mc_cfg_file = _TRINITY_CORE_CONFIG; int c=1; while( c < argc ) { @@ -135,7 +138,8 @@ extern int main(int argc, char **argv) sLog.outError("Could not find configuration file %s.", cfg_file); return 1; } - + + sIRC.SetCfg(mc_cfg_file); sLog.outString("Using configuration file %s.", cfg_file); uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0); diff --git a/src/trinitycore/Master.cpp b/src/trinitycore/Master.cpp index ee42f16b87a..216a48c59c0 100644 --- a/src/trinitycore/Master.cpp +++ b/src/trinitycore/Master.cpp @@ -38,6 +38,7 @@ #include "RASocket.h" #include "ScriptCalls.h" #include "Util.h" +#include "IRCClient.h" #include "sockets/TcpSocket.h" #include "sockets/Utility.h" @@ -226,6 +227,9 @@ int Master::Run() if (!_StartDB()) return 1; + ///- Load IRC Config (need DB for gm levels, AutoBroadcast uses world timers) + sIRC.LoadConfig(sIRC.CfgFile); + ///- Initialize the World sWorld.SetInitialWorldSettings(); @@ -309,6 +313,12 @@ int Master::Run() uint32 numLoops = (sConfig.GetIntDefault( "MaxPingTime", 30 ) * (MINUTE * 1000000 / socketSelecttime)); uint32 loopCounter = 0; + // Start up IRC bot + ZThread::Thread irc(new IRCClient); + irc.setPriority ((ZThread::Priority )2); + + + ///- Start up freeze catcher thread uint32 freeze_delay = sConfig.GetIntDefault("MaxCoreStuckTime", 0); if(freeze_delay) diff --git a/src/trinitycore/trinitycore.conf.dist b/src/trinitycore/trinitycore.conf.dist index 5eeacc53561..b6cdd410a8b 100644 --- a/src/trinitycore/trinitycore.conf.dist +++ b/src/trinitycore/trinitycore.conf.dist @@ -388,6 +388,10 @@ LogColors = "" # 2 - disabled only for Horde # 3 - disabled for both teams # +# MaxWhoListReturns +# Set the maximum number of players returned in the /who list and interface. +# Default: 49 (stable) +# # CharactersPerAccount # Limit numbers of characters per account (at all realms). # Note: this setting limit character creating at _current_ realm base at characters amount at all realms @@ -512,6 +516,7 @@ DeclinedNames = 0 StrictPlayerNames = 0 StrictCharterNames = 0 StrictPetNames = 0 +MaxWhoListReturns = 49 CharactersCreatingDisabled = 0 CharactersPerAccount = 50 CharactersPerRealm = 10 @@ -1184,3 +1189,191 @@ PvPToken.MapAllowType = 4 PvPToken.ItemID = 29434 PvPToken.ItemCount = 1 NoResetTalentsCost = 0 + +################################################################################################################### +# IRC SYSTEM CONFIG +# +# irc.active +# Enable IRC bot/system +# Default: 0 - Disable +# 0 - Enable +# irc.icc +# IRC connect code +# Default: 001 - Welcome To Network msg +# 375 - Beginning Of MOTD +# 376 - End Of MOTD +# +# irc.host +# IRC server to connect to +# +# irc.port +# IRC server port to use +# Default: "6667" - Semi-standard IRC port +# +# irc.user +# The username/ident to use when connecting to the IRC server +# +# irc.nick +# IRC nickname to be used by the bot +# +# irc.pass +# The password to be used to identify to NickServ +# +# irc.auth +# IRC Authentication Method +# Default: 0 - Disable +# 1 - NickServ - Normal Method - PRIVMSG NickServ :IDENTIFY Password +# 2 - NickServ - Alternate Method To Identify To A Different Nick - PRIVMSG NickServ :IDENTIFY irc.auth.nick Password +# 3 - QuakeNet - Normal Method - PRIVMSG Q@CServe.quakenet.org :AUTH irc.nick Password +# 4 - QuakeNet - Alternate Method To Identify To A Different Nick - PRIVMSG Q@CServe.quakenet.org :AUTH irc.auth.nick Password +# +# irc.auth.nick +# IRC Nickname to use if Auth method 2 or 4 is used +# +# irc.ldef +# Leave a defined IRC channel on server connect +# Default: 0 - Disable +# 1 - Enable +# irc.defchan +# IRC channel to leave on server connect if irc.ldef is on +# +# irc.wct +# Time to wait before (re)attemptimg connection to IRC server +# Default: 30000 - (30 Seconds) +# +# irc.maxattempt +# Maximum attempts to try IRC server +# Default: 20 +# +# irc.auto.announce +# Time to wait in Minutes to announce random messages from database. +# Default: 30 - (30 Minutes) +# +# irc.autojoin_kick +# Autojoin IRC channel if kicked +# Default: 1 - Enable +# 0 - Disable +# +# irc.command_prefix +# IRC command prefix +# Example: (.)online all +# +# irc.joinmsg +# irc.rstmsg +# irc.kickmsg +# Bot join/restart/kick messages +# +# irc.chan_# +# wow.chan_# +# IRC and WOW channels to link. Leave # out of IRC channel. Both channels _ARE_ case sensitive +# Example: irc.chan_1 = "Trinity" +# irc.chan_2 = "trinity2" +# wow.chan_1 = "world" +# wow.chan_2 = "LookingForGroup" +# +# irc.StatusChannel +# Channel Number To Display Status Messages In (AuctionHouse, Levels, Deaths, Etc) +# Default: 1 - Channel ID 1 +# +# irc.AnnounceChannel +# Channel Number To Display Announcements In (Announces, Notifies, Event) +# Default: 1 - Channel ID 1 +# +# irc.op_gm_login +# Op The GM In All Channels The Bot Is On When They Log In +# Default: 0 - Disable +# 1 - Enable +# +# irc.op_gm_level +# The Minimum GM Level Required To Have The Bot Op The User +# Default: 5 - GM Level 5 +# +# irc.ajoin (Experimental/Under Development) +# Force players to autojoin an in game channel +# Atleast one player must be in the channel on server start, and atleast one person online for invite to work +# Default: 0 - Disable +# 1 - Enable +# irc.ajchan +# Channel to join if above is Enabled. +# +# irc.online.result +# Maximum number of results per line for the online command +# +# chat.*** (Defineable Strings) +# wow_* - String is displayed in IRC channel +# irc_* - String is displayed in WOW channel +# Options: $Name, $Level, $Msg, $GM (not all options work in every string) +# +# Botmask +# This defines what the bot announces, if its 0 everything is disabled +# simply add the values of the elements you want to create this mask. +# Example: WoW join/leaves are 1 and IRC join/leaves are 2, if you want both of these active then the BotMask is 3. +# (1)Display WoW Chan Join/Leaves In IRC +# (2)Display IRC Chan Join/Leaves/NickChanges In WoW +# (4)Display Unknown Command Message When Trigger Is Used And No Command Exists +# (8)Announce Security Level > 0 As GM At Login +# (16)Announce GM In GM ON State AS GM At Login +# (32)Return Errors To Notice. (If disabled then default is Private Message) +# (64)Display WoW Status Messages (Levels/Deaths) +# (128)Display Nick Changes From IRC In WOW +# (256)Display WoW Announces/Notifies In IRC +# (512)Do Not Let Players Use Commands On Higher GM Level Players +# (1024)Enable AuctionHouse Announcements +# +# irc.gmlog +# Minimum GM level to not show login/pass info in IRC logs +# +# irc.logfile.prefix +# The prefix of the IRC logfile. Directories can be added here. +# Example: "IRC/IRC_" outputs IRC_YYYY-MM-DD.log to the IRC subdirectory in your logs dir +# +# irc.fun.games (Experimental/Under Development) +# Enable IRC games +# Default: 0 - Disable +# 1 - Enable +# irc.gm# +# GM tag to append to (GM onjoin / online command) IRC color codes are acceptable +# +################################################################################################################### + +irc.active = 0 +irc.icc = 001 +irc.host = "" +irc.port = "6667" +irc.user = "TC" +irc.nick = "TrinityCoreBot" +irc.pass = "" +irc.auth = 0 +irc.auth.nick = "TrinityCoreBot" +irc.ldef = 0 +irc.defchan = "lobby" +irc.wct = 30000 +irc.maxattempt = 20 +irc.auto.announce = 30 +irc.autojoin_kick = 1 +irc.command_prefix = "." +irc.joinmsg = "Trinity Core running. Command trigger is $Trigger." +irc.rstmsg = "Trinity Core is restarting..." +irc.kickmsg = "Do not kick me." +irc.chan_1 = "mangos" +wow.chan_1 = "world" +irc.StatusChannel = 1 +irc.AnnounceChannel = 1 +irc.op_gm_login = 0 +irc.op_gm_level = 3 +irc.ajoin = 1 +irc.ajchan = "world" +irc.online.result = 30 +chat.wow_irc = "$Name [$Level]: $Msg" +chat.irc_wow = "$Name: $Msg" +chat.join_wow = "[$GM] $Name has joined IRC." +chat.leave_wow = "[$GM] $Name has left IRC." +Botmask = 1023 +irc.gmlog = 1 +irc.logfile.prefix = "irc_" +irc.fun.games = 0 +irc.gm1 = "[Moderator]" +irc.gm2 = "[Game Master]" +irc.gm3 = "[BugTracker]" +irc.gm4 = "[DevTeam Admin]" +irc.gm5 = "[SysOP]" -- cgit v1.2.3