/* tag: irc class Copyright (c) 2001 David Roundy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // For compilers that support precompilation, includes . #include // for all others, include the necessary headers (this file is usually all you // need because it includes almost all "standard" wxWindows headers #ifndef WX_PRECOMP #include #include #endif #include #include #include "irc.h" #include "debug.h" #include "globals.h" #include WX_DEFINE_LIST(IrcChannelList); const wxString newline = "\x0D\x0A"; // CRLF as in RFC whatever. #define ID_SOCKET 1000 BEGIN_EVENT_TABLE(Irc,wxEvtHandler) EVT_SOCKET(ID_SOCKET, Irc::OnSocketEvent) END_EVENT_TABLE() Irc::Irc() { tail_end = ""; m_sock = 0; m_connected = 0; m_login = "Anonymous"; m_rooms = new IrcChannelList(wxKEY_STRING); m_topic_askers = new IrcChannelList(wxKEY_STRING); } Irc::~Irc() { if(m_sock) { m_sock->Close(); delete m_sock; } } void Irc::OnSocketEvent(wxSocketEvent& event) { #define BUFSIZE 2900 int done = 0, bytesRead; unsigned char buf[BUFSIZE]; int the_event_type = event.GetSocketEvent(); if (the_event_type == wxSOCKET_INPUT) { while(!done) { m_sock->Read((char *)buf, BUFSIZE); if((bytesRead = m_sock->LastCount()) != BUFSIZE) done = 1; ProcessInput(buf, bytesRead); } } else if (the_event_type == wxSOCKET_LOST) { DebugMsg("Socket Lost!"); ImportantDebugMsg("Socket Lost!"); m_connected = 0; m_sock->Close(); delete m_sock; m_sock = 0; // should sent a message... } else if (the_event_type == wxSOCKET_CONNECTION) { m_connected = 1; DebugMsg("We have connected to server."); // Login as 'm_login'. SendBack("NICK " + m_login + newline); SendBack("USER " + m_login + " * * :" + m_login + newline); if (m_login.IsSameAs("aBdealer")) { // ugh. This is very very crufty. SendBack("OPER " + m_login + " " + newline); } } } void Irc::ProcessInput(const unsigned char *buf, int bytesRead) { wxString str = tail_end + wxString(buf, bytesRead); tail_end = str.AfterLast('\x0A'); str = str.BeforeLast('\x0A'); wxStringTokenizer my_lines(str, newline); while ( my_lines.HasMoreTokens() ) { //wxString *message = new wxString; wxString message; wxString line = my_lines.GetNextToken(); wxString from = line.BeforeFirst('!'); from.Replace(":",""); wxString msg = line.AfterFirst(':').AfterFirst(':'); // msg.Replace("\r",""); msg.Replace(newline,""); if (!line.StartsWith("PING ")) { DebugMsg("IRC: " + line); } // process token here if (msg.StartsWith(aBridgeMagic,&message)) { // Received a message! GotMessageCmd(message); // Sort out the room in GotMessageCmd... } else if (line.StartsWith("PING ",&message)) { SendBack("PONG " + message + newline); } else if (line.Find("PRIVMSG ") != -1) { wxString the_room = line.Mid(line.Find("PRIVMSG ")); the_room = the_room.AfterFirst(' ').BeforeFirst(' '); // the room should now be the channel name! from.Replace(":",""); from.Replace("_"," "); if (m_rooms->Find(the_room)) m_rooms->Find(the_room)->GetData()->GotChat(from, msg); } else if (line.Matches("* 001 *")) { // We just signed in!!! :) //Join(m_room); //m_connected = 1; DebugMsg("We seem to have just signed in to IRC"); for (unsigned int i=0;iGetCount();i++) { SendBack("JOIN " + m_rooms->Item(i)->GetData()->TheRoom() + newline); } } else if (line.Matches("*353*")) { // NAMES GotNames(line); } else if (line.Matches("*332*")) { // Topic!!! GotTopic(line); } else if (line.Matches("*372*")) { // MOTD for (unsigned int i=0;iGetCount();i++) { m_rooms->Item(i)->GetData()->GotChat("", msg); } } else if (line.Matches("*352*")) { // Who. GotWhoCmd(line); // fix this in GotWhoCmd... } else if (line.Matches("*NOTICE*")) { // Server message... if (!msg.Matches("")) { for (unsigned int i=0;iGetCount();i++) { m_rooms->Item(i)->GetData()->GotChat("!!!", msg); } } } else if (line.Matches("* JOIN :*")) { GotJoinedCmd(line); // fix this in GotJoinedCmd... } else if (line.Matches("* QUIT :*")|| line.Matches("* PART *")) { GotLeftCmd(line); // Fix this in GotLeftCmd... } else { // I don't understand the message... } } } void Irc::GotWhoCmd(const wxString &line) { wxString name = line.AfterLast(' '); wxString nick = line.AfterFirst('#').AfterFirst('~').BeforeFirst(' '); for (unsigned int i=0;iGetCount();i++) { m_rooms->Item(i)->GetData()->GotChat("WHO:", nick + " - " + name); } } IrcChannel *Irc::GetRoom(const wxString &room) { IrcChannelList::Node *node = m_rooms->Find(room); if (node) { return node->GetData(); } else { return NULL; } } void Irc::GotMessageCmd(const wxString &message) { // We now issue a custom event, which would be received by the // appropriate target. //printf("### %s\n", message.c_str()); wxString room = message.BeforeFirst(' '); room.Replace(" ",""); wxString from = message.AfterFirst(' ').BeforeFirst(' '); from.Replace(" ",""); wxString type = message.AfterFirst(' ').AfterFirst(' ').BeforeFirst(' '); type.Replace(" ",""); wxString msg = message.AfterFirst(' ').AfterFirst(' ').AfterFirst(' '); IrcMsgEvent my_event( this, from, type, msg); // here we send to the room... should check which room IrcChannel *ircc = GetRoom(room); if (ircc) ircc->GotMessageEvent(my_event); } void Irc::GotLeftCmd(const wxString &line) { wxString from = line.BeforeFirst('!'); from.Replace(":",""); wxString room = line.AfterFirst('#').BeforeFirst(' '); room = "#" + room; if (line.Matches("* QUIT *")) { for (unsigned int i=0;iGetCount();i++) { m_rooms->Item(i)->GetData()->GotLeftCmd(from); } } else { if (m_rooms->Find(room)) { m_rooms->Find(room)->GetData()->GotLeftCmd(from); } } } void Irc::GotJoinedCmd(const wxString &line) { wxString from = line.BeforeFirst('!'); from.Replace(":",""); wxString room = line.AfterLast(':'); // room.Replace("\r",""); room.Replace(newline,""); if (from.IsSameAs(Login())) return; // don't announce that we've joined. if(m_rooms->Find(room)) m_rooms->Find(room)->GetData()->GotJoiner(from); } void Irc::SendBack(const wxString &str) { SendBack(str.Len(),str.c_str()); } void Irc::SendBack(int len, const char *data) { if(m_sock) m_sock->Write((char *)data, len); } IrcChannel *Irc::Join(const wxString& room, wxEvtHandler* parent, wxTextCtrl* output) { wxString the_room = room; the_room.Replace("\n",""); IrcChannel *the_ch = new IrcChannel(this, parent, output, the_room); m_rooms->Append(the_room,the_ch); return the_ch; } void Irc::AskTopic(const wxString &channel, const wxString &asker) { SendBack("TOPIC " + channel + newline); if (!asker.IsSameAs("none")) { IrcChannel *ircc = GetRoom(asker); if (ircc) m_topic_askers->Append(asker,ircc);; } } void Irc::SetTopic(const wxString &topic, const wxString &channel) { SendBack("TOPIC " + channel + " :" + topic + newline); } void Irc::GotNames(const wxString &line) { wxString channel = line.BeforeLast(':'); channel = channel.BeforeLast(' '); // just chomp of trailing space... channel = channel.AfterLast(' '); // this should be it... wxString names = line.AfterLast(':'); names.Replace("@",""); names.Replace(" aBdealer "," "); // This is a hokey bit... ugh! IrcChannel *ircc = GetRoom(channel); if (ircc) ircc->GotNames(names); } void Irc::GotTopic(const wxString &line) { wxString channel = line.BeforeLast(':'); channel = channel.BeforeLast(' '); // just chomp of trailing space... channel = channel.AfterLast(' '); // this should be it... wxString topic = line.AfterLast(':'); IrcMsgEvent my_event( this, channel, "TOPIC", topic); IrcChannel *ircc = GetRoom(channel); if (ircc) ircc->GotMessageEvent(my_event); IrcChannelList::Node *node = m_topic_askers->GetFirst(); while (node) { node->GetData()->GotMessageEvent(my_event); node = node->GetNext(); } } void Irc::Leave(const wxString& room) { if (m_rooms->Find(room)) { m_rooms->DeleteNode(m_rooms->Find(room)); SendBack("PART :" + room + newline); } if (m_topic_askers->Find(room)) { m_topic_askers->DeleteNode(m_topic_askers->Find(room)); } // Tell all the 'topic askers' when we leave a room. This is so the host // will know when a dealer has been deleted. IrcMsgEvent my_event( this, room, "PART", ""); IrcChannelList::Node *node = m_topic_askers->GetFirst(); while (node) { node->GetData()->GotMessageEvent(my_event); node = node->GetNext(); } } IrcChannel *Irc::AmInChannel(const wxString& room) { if (m_rooms->Find(room)) { return m_rooms->Find(room)->GetData(); } else { return (IrcChannel *)false; } } wxStringList &Irc::ListRooms() { wxStringList * list = new wxStringList; IrcChannelList::Node *node = m_rooms->GetFirst(); while (node) { wxString room = node->GetData()->TheRoom(); list->Add(room); node = node->GetNext(); } return *list; } void Irc::Connect(const wxString& hostname, unsigned short port, const wxString& username) { wxIPV4address addr; m_login = username; irc_name(m_login); if(m_connected) Disconnect(); addr.Hostname(hostname); addr.Service(port); m_sock = new wxSocketClient(); m_sock->SetFlags(wxSOCKET_NOWAIT); m_sock->SetEventHandler(*this, ID_SOCKET); m_sock->SetNotify(wxSOCKET_CONNECTION_FLAG | wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG); m_sock->Notify(TRUE); m_sock->Connect(addr, FALSE); } void Irc::Disconnect(void) { if(m_sock) { m_sock->Close(); delete m_sock; m_sock = 0; } m_connected = 0; // Reset(); // Refresh(); } bool Irc::IsConnected(void) { if(m_sock) return m_sock->IsConnected(); return FALSE; }