diff options
Diffstat (limited to 'src/game/IRCIO.cpp')
-rw-r--r-- | src/game/IRCIO.cpp | 436 |
1 files changed, 436 insertions, 0 deletions
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(), "<IRC>[" + 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<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();
+ for(HashMapHolder<Player>::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<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();
+ for(HashMapHolder<Player>::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<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();
+ for(HashMapHolder<Player>::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);
+}
|