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; }
// 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); } }
void IRCClient::HandleCTCP(IRCMessage message) { std::string to = message.parameters.at(0); std::string text = message.parameters.at(message.parameters.size() - 1); // Remove '\001' from start/end of the string text = text.substr(1, text.size() - 2); std::cout << "[" + message.prefix.nick << " requested CTCP " << text << "]" << std::endl; if (to == _nick) { if (text == "VERSION") // Respond to CTCP VERSION { SendIRC("NOTICE " + message.prefix.nick + " :\001VERSION Open source IRC client by Fredi Machado - https://github.com/Fredi/IRCClient \001"); return; } // CTCP not implemented SendIRC("NOTICE " + message.prefix.nick + " :\001ERRMSG " + text + " :Not implemented\001"); } }
bool CIRC :: Update( void *fd, void *send_fd ) { uint32_t Time = GetTime( ); if( m_Socket->GetConnected( ) ) { // the socket is connected and everything appears to be working properly if( Time - m_LastPacketTime > 210 ) { Print( "[IRC: " + m_Server + "] ping timeout, reconnecting" ); m_Socket->Reset( ); m_WaitingToConnect = true; return m_Exiting; } if( Time - m_LastAntiIdleTime > 60 ) { SendIRC( "TIME" ); m_LastAntiIdleTime = Time; } m_Socket->DoRecv( (fd_set *)fd ); ExtractPackets( ); m_Socket->DoSend( (fd_set *)send_fd ); return m_Exiting; } if( m_Socket->HasError( ) ) { // the socket has an error Print( "[IRC: " + m_Server + "] disconnected due to socket error, waiting 60 seconds to reconnect" ); m_Socket->Reset( ); m_WaitingToConnect = true; m_LastConnectionAttemptTime = Time; return m_Exiting; } if( !m_Socket->GetConnecting( ) && !m_Socket->GetConnected( ) && !m_WaitingToConnect ) { // the socket was disconnected Print( "[IRC: " + m_Server + "] disconnected, waiting 60 seconds to reconnect" ); m_Socket->Reset( ); m_WaitingToConnect = true; m_LastConnectionAttemptTime = Time; return m_Exiting; } if( m_Socket->GetConnecting( ) ) { // we are currently attempting to connect to irc if( m_Socket->CheckConnect( ) ) { // the connection attempt completed if( !m_OriginalNick ) m_Nickname = m_NicknameCpy; SendIRC( "NICK " + m_Nickname ); SendIRC( "USER " + m_Username + " " + m_Nickname + " " + m_Username + " :by h4x0rz88" ); m_Socket->DoSend( (fd_set *)send_fd ); Print( "[IRC: " + m_Server + "] connected" ); m_LastPacketTime = Time; return m_Exiting; } else if( Time - m_LastConnectionAttemptTime > 15 ) { // the connection attempt timed out (15 seconds) Print( "[IRC: " + m_Server + "] connect timed out, waiting 60 seconds to reconnect" ); m_Socket->Reset( ); m_LastConnectionAttemptTime = Time; m_WaitingToConnect = true; return m_Exiting; } } if( !m_Socket->GetConnecting( ) && !m_Socket->GetConnected( ) && ( Time - m_LastConnectionAttemptTime > 60 ) ) { // attempt to connect to irc Print( "[IRC: " + m_Server + "] connecting to server [" + m_Server + "] on port " + UTIL_ToString( m_Port ) ); if( m_ServerIP.empty( ) ) { m_Socket->Connect( string( ), m_Server, m_Port ); if( !m_Socket->HasError( ) ) { m_ServerIP = m_Socket->GetIPString( ); } } else { // use cached server IP address since resolving takes time and is blocking m_Socket->Connect( string( ), m_ServerIP, m_Port ); } m_WaitingToConnect = false; m_LastConnectionAttemptTime = Time; } return m_Exiting; }
inline void CIRC :: ExtractPackets( ) { string Token, PreviousToken, Recv = *( m_Socket->GetBytes( ) ); uint32_t Time = GetTime( ); unsigned int i; /* loop through whole recv buffer */ for( i = 0; i < Recv.size( ); ++i ) { // add chars to token if( Recv[i] != ' ' && Recv[i] != CR && Recv[i] != LF ) { Token += Recv[i]; } else if( Recv[i] == ' ' || Recv[i] == LF ) { // end of token, examine if( Token == "PRIVMSG" ) { // parse the PreviousToken as it holds the user info and then the Token for the message itself string Nickname, Hostname, Message, Command, Payload; bool IsCommand = true; unsigned int j = 1; // get nickname for( ; PreviousToken[j] != '!'; ++j ) Nickname += PreviousToken[j]; // skip username for( j += 2; PreviousToken[j] != '@'; ++j ); // get hostname for( ++j; j < PreviousToken.size( ); ++j ) Hostname += PreviousToken[j]; // skip channel for( i += 3; Recv[i] != ':'; ++i ); // process message for( ++i; Recv[i] != CR; ++i ) { Message += Recv[i]; if( Recv[i] == ' ' && IsCommand ) { IsCommand = false; continue; } if( Message.size( ) != 1 ) { if( IsCommand ) Command += tolower( Recv[i] ); else Payload += Recv[i]; } } // move position after the \n i += 2; if( Message.empty( ) ) { PreviousToken = Token; Token.clear( ); continue; } if( Message[0] != SOH ) { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { if( Message[0] == (*i)->GetCommandTrigger( ) ) { CIncomingChatEvent event = CIncomingChatEvent( CBNETProtocol :: EID_IRC, Nickname, Message ); (*i)->ProcessChatEvent( &event ); break; } } if( Message[0] == m_CommandTrigger[0] ) { bool Root = Hostname.substr( 0, 6 ) == "Aurani" || Hostname.substr( 0, 8 ) == "h4x0rz88"; if( Command == "nick" && Root ) { SendIRC( "NICK :" + Payload ); m_Nickname = Payload; m_OriginalNick= false; } else if( Command == "dcclist" ) { string on, off; for( vector<CDCC *> :: iterator i = m_DCC.begin( ); i != m_DCC.end( ); ++i ) { if( (*i)->m_Socket->GetConnected( ) ) on += (*i)->m_Nickname + "[" + UTIL_ToString( (*i)->m_Port ) +"] "; else off += (*i)->m_Nickname + "[" + UTIL_ToString( (*i)->m_Port ) +"] "; } SendMessageIRC( "ON: " + on, string( ) ); SendMessageIRC( "OFF: " + off, string( ) ); } else if( Command == "bnetoff" ) { if( Payload.empty( ) ) { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { (*i)->Deactivate( ); SendMessageIRC( "[BNET: " + (*i)->GetServerAlias( ) + "] deactivated.", string( ) ); } } else { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { if( (*i)->GetServerAlias( ) == Payload ) { (*i)->Deactivate( ); SendMessageIRC( "[BNET: " + (*i)->GetServerAlias( ) + "] deactivated.", string( ) ); break; } } } } else if( Command == "bneton" ) { if( Payload.empty( ) ) { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { (*i)->Activate( ); SendMessageIRC( "[BNET: " + (*i)->GetServerAlias( ) + "] activated.", string( ) ); } } else { for( vector<CBNET *> :: iterator i = m_Aura->m_BNETs.begin( ); i != m_Aura->m_BNETs.end( ); ++i ) { if( (*i)->GetServerAlias( ) == Payload ) { (*i)->Activate( ); SendMessageIRC( "[BNET: " + (*i)->GetServerAlias( ) + "] activated.", string( ) ); break; } } } } } } else if( Payload.size( ) > 12 && Payload.substr( 0, 4 ) == "CHAT" ) { // CHAT chat 3162588924 1025 string strIP, strPort; bool IsPort = false; for( unsigned int j = 10; j < ( Payload.size( ) - 1 ); ++j ) { if( !IsPort && Payload[j] == ' ' ) { IsPort = true; continue; } if( !IsPort ) strIP += Payload[j]; else strPort += Payload[j]; } unsigned int Port = UTIL_ToUInt16( strPort ); if( Port < 1024 || 1026 < Port ) Port = 1024; bool Local = false; for( vector<string> :: iterator i = m_Locals.begin( ); i != m_Locals.end( ); ++i ) { if( Nickname == (*i) ) { strIP = "127.0.0.1"; Local = true; break; } } if( !Local ) { unsigned long IP = UTIL_ToUInt32( strIP ), divider = 16777216UL; strIP = ""; for( int i = 0; i <= 3; ++i ) { stringstream ss; ss << (unsigned long) IP / divider; IP %= divider; divider /= 256; strIP += ss.str( ); if( i != 3 ) strIP += '.'; } } bool Existing = false; for( vector<CDCC *> :: iterator i = m_DCC.begin( ); i != m_DCC.end( ); ++i ) { if( (*i)->m_Nickname == Nickname ) { (*i)->Connect( strIP, Port ); Existing = true; break; } } if( !Existing ) m_DCC.push_back( new CDCC( this, strIP, Port, Nickname ) ); } // remember last packet time m_LastPacketTime = Time; } else if( Token == "391" ) { // move position after the \n (next packet) for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "PING" ) { string Packet; // PING :blabla // skip until : for( ++i; Recv[i] != ':'; ++i ); for( ++i; Recv[i] != CR; ++i ) Packet += Recv[i]; SendIRC( "PONG :" + Packet ); // move position after the \n i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "NOTICE" ) { // move position after the \n for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "221" ) { // Q auth if the server is QuakeNet if( m_Server.find( "quakenet.org" ) != string :: npos && !m_Password.empty( ) ) { SendMessageIRC( "AUTH " + m_Username + " " + m_Password, "*****@*****.**" ); SendIRC( "MODE " + m_Nickname + " +x" ); } // join channels for( vector<string> :: iterator j = m_Channels.begin( ); j != m_Channels.end( ); ++j ) { SendIRC( "JOIN " + (*j) ); } // move position after the \n for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "433" ) { // nick taken, append _ m_OriginalNick = false; m_Nickname += '_'; SendIRC( "NICK " + m_Nickname ); // move position after the \n (next packet) for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "353" ) { // move position after the \n (next packet) for( ++i; Recv[i] != CR; ++i ); i += 2; // remember last packet time m_LastPacketTime = Time; } else if( Token == "KICK" ) { string Channel, Victim; bool Space = false; // get channel for( ++i; Recv[i] != ' '; ++i ) Channel += Recv[i]; // get the victim for( ++i ; i < Recv.size( ); ++i ) { if( Recv[i] == ' ' ) Space = true; else if( Recv[i] == CR ) break; else if( Space && Recv[i] != ':' ) Victim += Recv[i]; } // we're the victim here! rejoin if( Victim == m_Nickname ) { SendIRC( "JOIN " + Channel ); } // move position after the \n i += 2; // remember last packet time m_LastPacketTime = Time; } // empty the token PreviousToken = Token; Token.clear( ); } } m_Socket->ClearRecvBuffer( ); }
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 trinitycore.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 [email protected] :AUTH " + sIRC._Nick + " " + sIRC._Pass); break; case 4: SendIRC("PRIVMSG [email protected] :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++) { if (sIRC._irc_pass[i].size() > 0) SendIRC("JOIN #" + sIRC._irc_chan[i] + " " + sIRC._irc_pass[i]); else SendIRC("JOIN #" + sIRC._irc_chan[i]); } // See if there's a logchannel available, if so: join it. if(sIRC.logchan.size() > 0) { if(sIRC.logchanpw.size() > 0) SendIRC("JOIN #" + sIRC.logchan + " " + sIRC.logchanpw); else SendIRC("JOIN #" + sIRC.logchan); } } // 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. // ArkChat now uses Send_WoW_Channel to send to the client // this makes ArkChat 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 ArkChat 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 MGACHAT %s ©2008- 2013 Biglad - http://www.mgawow.co.uk \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; } } } }