C4Network2IRCChannel *C4Network2IRCClient::getChannel(const char *szName) const { for(C4Network2IRCChannel *pChan = pChannels; pChan; pChan = pChan->Next) if(SEqualNoCase(pChan->getName(), szName)) return pChan; return NULL; }
void C4Network2IRCClient::OnNumericCommand(const char *szSender, int iCommand, const char *szParameters) { bool fShowMessage = true; // Get target StdStrBuf Target = ircExtractPar(&szParameters); // Handle command switch(iCommand) { case 433: // Nickname already in use { StdStrBuf DesiredNick = ircExtractPar(&szParameters); // Automatically try to choose a new one DesiredNick.AppendChar('_'); Send("NICK", DesiredNick.getData()); break; } case 376: // End of MOTD case 422: // MOTD missing // Let's take this a sign that the connection is established. OnConnected(); break; case 331: // No topic set case 332: // Topic notify / change { // Get Channel name and topic StdStrBuf Channel = ircExtractPar(&szParameters); StdStrBuf Topic = (iCommand == 332 ? ircExtractPar(&szParameters) : StdStrBuf("")); // Set it AddChannel(Channel.getData())->OnTopic(Topic.getData()); // Log if(Topic.getLength()) PushMessage(MSG_Status, szSender, Channel.getData(), FormatString(LoadResStr("IDS_MSG_TOPICIN"), Channel.getData(), Topic.getData()).getData()); } break; case 333: // Last topic change fShowMessage = false; // ignore break; case 353: // Names in channel { // Get Channel name and name list StdStrBuf Junk = ircExtractPar(&szParameters); // ??! StdStrBuf Channel = ircExtractPar(&szParameters); StdStrBuf Names = ircExtractPar(&szParameters); // Set it AddChannel(Channel.getData())->OnUsers(Names.getData(), Prefixes.getData()); fShowMessage = false; } break; case 366: // End of names list { // Get Channel name StdStrBuf Channel = ircExtractPar(&szParameters); // Finish AddChannel(Channel.getData())->OnUsersEnd(); fShowMessage = false; // Notify if(pNotify) pNotify->PushEvent(Ev_IRC_Message, this); } break; case 4: // Server version fShowMessage = false; // ignore break; case 5: // Server support string { while(szParameters && *szParameters) { // Get support-token. StdStrBuf Token = ircExtractPar(&szParameters); StdStrBuf Parameter; Parameter.CopyUntil(Token.getData(), '='); // Check if it's interesting and safe data if so. if(SEqualNoCase(Parameter.getData(), "PREFIX")) Prefixes.Copy(SSearch(Token.getData(), "=")); } fShowMessage = false; } break; } // Show embedded message, if any? if(fShowMessage) { // Check if first parameter is some sort of channel name C4Network2IRCChannel *pChannel = NULL; if(szParameters && *szParameters && *szParameters != ':') pChannel = getChannel(ircExtractPar(&szParameters).getData()); // Go over other parameters const char *pMsg = szParameters; while(pMsg && *pMsg && *pMsg != ':') pMsg = SSearch(pMsg, " "); // Show it if(pMsg && *pMsg) if(!pChannel) PushMessage(MSG_Server, szSender, Nick.getData(), pMsg + 1); else PushMessage(MSG_Status, szSender, pChannel->getName(), pMsg + 1); } }
void C4Network2IRCClient::OnCommand(const char *szSender, const char *szCommand, const char *szParameters) { CStdLock Lock(&CSec); // Numeric command? if(isdigit((unsigned char)*szCommand) && SLen(szCommand) == 3) { OnNumericCommand(szSender, atoi(szCommand), szParameters); return; } // Sender's nick StdStrBuf SenderNick; if(szSender) SenderNick.CopyUntil(szSender, '!'); // Ping? if(SEqualNoCase(szCommand, "PING")) Send("PONG", szParameters); // Message? if(SEqualNoCase(szCommand, "NOTICE") || SEqualNoCase(szCommand, "PRIVMSG")) { // Get target StdStrBuf Target = ircExtractPar(&szParameters); // Get text StdStrBuf Text = ircExtractPar(&szParameters); // Process message OnMessage(SEqualNoCase(szCommand, "NOTICE"), szSender, Target.getData(), Text.getData()); } // Channel join? if(SEqualNoCase(szCommand, "JOIN")) { // Get channel StdStrBuf Channel = ircExtractPar(&szParameters); C4Network2IRCChannel *pChan = AddChannel(Channel.getData()); // Add user pChan->OnJoin(SenderNick.getData()); // Myself? if(SenderNick == Nick) PushMessage(MSG_Status, szSender, Channel.getData(), FormatString(LoadResStr("IDS_MSG_YOUHAVEJOINEDCHANNEL"), Channel.getData()).getData()); else PushMessage(MSG_Status, szSender, Channel.getData(), FormatString(LoadResStr("IDS_MSG_HASJOINEDTHECHANNEL"), SenderNick.getData()).getData()); } // Channel part? if(SEqualNoCase(szCommand, "PART")) { // Get channel StdStrBuf Channel = ircExtractPar(&szParameters); C4Network2IRCChannel *pChan = AddChannel(Channel.getData()); // Get message StdStrBuf Comment = ircExtractPar(&szParameters); // Remove user pChan->OnPart(SenderNick.getData(), Comment.getData()); // Myself? if(SenderNick == Nick) { DeleteChannel(pChan); PushMessage(MSG_Status, szSender, Nick.getData(), FormatString(LoadResStr("IDS_MSG_YOUHAVELEFTCHANNEL"), Channel.getData(), Comment.getData()).getData()); } else PushMessage(MSG_Status, szSender, Channel.getData(), FormatString(LoadResStr("IDS_MSG_HASLEFTTHECHANNEL"), SenderNick.getData(), Comment.getData()).getData()); } // Kick? if(SEqualNoCase(szCommand, "KICK")) { // Get channel StdStrBuf Channel = ircExtractPar(&szParameters); C4Network2IRCChannel *pChan = AddChannel(Channel.getData()); // Get kicked user StdStrBuf Kicked = ircExtractPar(&szParameters); // Get message StdStrBuf Comment = ircExtractPar(&szParameters); // Remove user pChan->OnKick(Kicked.getData(), Comment.getData()); // Myself? if(Kicked == Nick) { DeleteChannel(pChan); PushMessage(MSG_Status, szSender, Nick.getData(), FormatString(LoadResStr("IDS_MSG_YOUWEREKICKEDFROMCHANNEL"), Channel.getData(), Comment.getData()).getData()); } else PushMessage(MSG_Status, szSender, Channel.getData(), FormatString(LoadResStr("IDS_MSG_WASKICKEDFROMTHECHANNEL"), Kicked.getData(), Comment.getData()).getData()); } // Quit? if(SEqualNoCase(szCommand, "QUIT")) { // Get comment StdStrBuf Comment = ircExtractPar(&szParameters); // Format status message StdStrBuf Message = FormatString(LoadResStr("IDS_MSG_HASDISCONNECTED"), SenderNick.getData(), Comment.getData()); // Remove him from all channels for(C4Network2IRCChannel *pChan = pChannels; pChan; pChan = pChan->Next) if(pChan->getUser(SenderNick.getData())) { pChan->OnPart(SenderNick.getData(), "Quit"); PushMessage(MSG_Status, szSender, pChan->getName(), Message.getData()); } } // Topic change? if(SEqualNoCase(szCommand, "TOPIC")) { // Get channel and topic StdStrBuf Channel = ircExtractPar(&szParameters); StdStrBuf Topic = ircExtractPar(&szParameters); // Set topic AddChannel(Channel.getData())->OnTopic(Topic.getData()); // Message PushMessage(MSG_Status, szSender, Channel.getData(), FormatString(LoadResStr("IDS_MSG_CHANGESTHETOPICTO"), SenderNick.getData(), Topic.getData()).getData()); } // Mode? if(SEqualNoCase(szCommand, "MODE")) { // Get all data StdStrBuf Channel = ircExtractPar(&szParameters); StdStrBuf Flags = ircExtractPar(&szParameters); StdStrBuf What = ircExtractPar(&szParameters); // Make sure it's a channel C4Network2IRCChannel *pChan = getChannel(Channel.getData()); if(pChan) // Ask for names, because user prefixes might be out of sync Send("NAMES", Channel.getData()); // Show Message PushMessage(MSG_Status, szSender, Channel.getData(), FormatString(LoadResStr("IDS_MSG_SETSMODE"), SenderNick.getData(), Flags.getData(), What.getData()).getData()); } // Error? if(SEqualNoCase(szCommand, "ERROR")) { // Get message StdStrBuf Message = ircExtractPar(&szParameters); // Push it PushMessage(MSG_Server, szSender, Nick.getData(), Message.getData()); } // Nickchange? if(SEqualNoCase(szCommand, "NICK")) { // Get new nick StdStrBuf NewNick = ircExtractPar(&szParameters); // Format status message StdStrBuf Message = FormatString(LoadResStr("IDS_MSG_ISNOWKNOWNAS"), SenderNick.getData(), NewNick.getData()); // Rename on all channels for(C4Network2IRCChannel *pChan = pChannels; pChan; pChan = pChan->Next) if(pChan->getUser(SenderNick.getData())) { pChan->OnPart(SenderNick.getData(), "Nickchange"); pChan->OnJoin(NewNick.getData()); PushMessage(MSG_Status, szSender, pChan->getName(), Message.getData()); } // Self? if(SenderNick == Nick) Nick = NewNick; } }
void C4ChatControl::Update() { CStdLock Lock(pIRCClient->getCSec()); // update channels for (C4Network2IRCChannel *pChan = pIRCClient->getFirstChannel(); pChan; pChan = pIRCClient->getNextChannel(pChan)) { ChatSheet *pChanSheet = GetSheetByIdent(pChan->getName(), ChatSheet::CS_Channel); if (!pChanSheet) { // new channel! Create sheet for it pTabChats->AddCustomSheet( pChanSheet = new ChatSheet(this, pChan->getName(), pChan->getName(), ChatSheet::CS_Channel)); // and show immediately pTabChats->SelectSheet(pChanSheet, false); } } // remove parted channels int32_t i = 0; C4GUI::Tabular::Sheet *pSheet; while (pSheet = pTabChats->GetSheet(i++)) { C4Network2IRCChannel *pIRCChan; ChatSheet *pChatSheet = static_cast<ChatSheet *>(pSheet); if (pChatSheet->GetSheetType() == ChatSheet::CS_Channel) if (!(pIRCChan = pIRCClient->getChannel(pChatSheet->GetTitle()))) { delete pChatSheet; --i; } } // retrieve messages: All messages in initial update; only unread in // subsequent calls C4Network2IRCMessage *pMsg; if (fInitialMessagesReceived) { pMsg = pIRCClient->getUnreadMessageLog(); } else { pMsg = pIRCClient->getMessageLog(); fInitialMessagesReceived = true; } // update messages for (; pMsg; pMsg = pMsg->getNext()) { // get target sheet to put message into ChatSheet *pChatSheet; StdStrBuf sUser, sIdent; bool fMsgToService = false; if (pMsg->getType() == MSG_Server) { // server messages in server sheet pChatSheet = GetServerSheet(); } else { if (pMsg->getType() != MSG_Status) sUser.Copy(pMsg->getSource()); if (!sUser.SplitAtChar('!', &sIdent)) sIdent.Ref(sUser); // message: Either channel or user message (or channel notify). Get // correct sheet. if (pMsg->isChannel()) { // if no sheet is found, don't create - assume it's an outdated message // with the cahnnel window already closed pChatSheet = GetSheetByIdent(pMsg->getTarget(), ChatSheet::CS_Channel); } else if (IsServiceName(sUser.getData())) { // notices and messages by services always in server sheet pChatSheet = GetServerSheet(); } else if (pMsg->getType() == MSG_Notice) { // notifies in current sheet; default to server sheet pChatSheet = GetActiveChatSheet(); if (!pChatSheet) pChatSheet = GetServerSheet(); } else if (pMsg->getType() == MSG_Status || !sUser.getLength()) { // server message pChatSheet = GetServerSheet(); } else if (sUser == pIRCClient->getUserName()) { // private message by myself // message to a service into service window; otherwise (new) query if (IsServiceName(pMsg->getTarget())) { pChatSheet = GetServerSheet(); fMsgToService = true; } else { pChatSheet = OpenQuery(pMsg->getTarget(), true, NULL); if (pChatSheet) pChatSheet->SetChatTitle(pMsg->getTarget()); } } else { // private message pChatSheet = OpenQuery(sUser.getData(), false, sIdent.getData()); if (pChatSheet) pChatSheet->SetChatTitle(pMsg->getSource()); } } if (pChatSheet) { // get message formatting and color StdStrBuf sMsg; uint32_t dwClr = C4GUI_MessageFontClr; switch (pMsg->getType()) { case MSG_Server: sMsg.Format("- %s", pMsg->getData()); break; case MSG_Status: sMsg.Format("- %s", pMsg->getData()); dwClr = C4GUI_InactMessageFontClr; break; case MSG_Notice: if (sUser.getLength()) if (sUser != pIRCClient->getUserName()) sMsg.Format("-%s- %s", sUser.getData(), pMsg->getData()); else sMsg.Format("-> -%s- %s", pMsg->getTarget(), pMsg->getData()); else sMsg.Format("* %s", pMsg->getData()); dwClr = C4GUI_NotifyFontClr; break; case MSG_Message: if (fMsgToService) sMsg.Format("-> *%s* %s", pMsg->getTarget(), pMsg->getData()); else if (sUser.getLength()) sMsg.Format("<%s> %s", sUser.getData(), pMsg->getData()); else sMsg.Format("* %s", pMsg->getData()); break; case MSG_Action: if (sUser.getLength()) sMsg.Format("* %s %s", sUser.getData(), pMsg->getData()); else sMsg.Format("* %s", pMsg->getData()); break; default: sMsg.Format("??? %s", pMsg->getData()); dwClr = C4GUI_ErrorFontClr; break; } pChatSheet->AddTextLine(sMsg.getData(), dwClr); } } // OK; all messages processed. Delete overflow messages. pIRCClient->MarkMessageLogRead(); // update selected channel (users, topic) ChatSheet *pActiveSheet = GetActiveChatSheet(); if (pActiveSheet) pActiveSheet->Update(false); // update title UpdateTitle(); }