EModRet OnNumericMessage(CNumericMessage &Message) override { unsigned int uCode = Message.GetCode(); if (uCode == 375 /* RPL_MOTDSTART */ || uCode == 372 /* RPL_MOTD */) return HALT; if (uCode == 376 /* RPL_ENDOFMOTD */) { Message.SetCommand("422"); /* ERR_NOMOTD */ Message.SetParams({Message.GetParam(0), "MOTD blocked by ZNC"}); } return CONTINUE; }
EModRet OnNumericMessage(CNumericMessage& msg) override { if (m_pTimer) { // Are we trying to get our primary nick and we caused this error? // :irc.server.net 433 mynick badnick :Nickname is already in use. if (msg.GetCode() == 433 && msg.GetParam(1).Equals(GetNick())) { return HALT; } // clang-format off // :leguin.freenode.net 435 mynick badnick #chan :Cannot change nickname while banned on channel // clang-format on if (msg.GetCode() == 435) { PutModule("Unable to obtain nick " + msg.GetParam(1) + ": " + msg.GetParam(3) + ", " + msg.GetParam(2)); Disable(); } // clang-format off // :irc1.unrealircd.org 447 mynick :Can not change nickname while on #chan (+N) // clang-format on if (msg.GetCode() == 447) { PutModule("Unable to obtain nick: " + msg.GetParam(1)); Disable(); } } return CONTINUE; }
static CMessage BufferMessage(const CNumericMessage& Message) { CMessage Format(Message); Format.SetNick(CNick(_NAMEDFMT(Message.GetNick().GetHostMask()))); Format.SetParam(0, "{target}"); unsigned uParams = Format.GetParams().size(); for (unsigned int i = 1; i < uParams; ++i) { Format.SetParam(i, _NAMEDFMT(Format.GetParam(i))); } return Format; }
TEST(MessageTest, Numeric) { CNumericMessage msg; msg.Parse(":server 123 user :foo bar"); EXPECT_EQ("server", msg.GetNick().GetNick()); EXPECT_EQ("123", msg.GetCommand()); EXPECT_EQ(123u, msg.GetCode()); EXPECT_EQ(CMessage::Type::Numeric, msg.GetType()); EXPECT_EQ(":server 123 user :foo bar", msg.ToString()); }
EModRet OnNumericMessage(CNumericMessage& msg) override { if (msg.GetCode() == 903) { /* SASL success! */ if (m_bVerbose) { PutModule(m_Mechanisms.GetCurrent() + " mechanism succeeded."); } GetNetwork()->GetIRCSock()->ResumeCap(); m_bAuthenticated = true; DEBUG("sasl: Authenticated with mechanism [" << m_Mechanisms.GetCurrent() << "]"); } else if (msg.GetCode() == 904 || msg.GetCode() == 905) { DEBUG("sasl: Mechanism [" << m_Mechanisms.GetCurrent() << "] failed."); if (m_bVerbose) { PutModule(m_Mechanisms.GetCurrent() + " mechanism failed."); } if (m_Mechanisms.HasNext()) { m_Mechanisms.IncrementIndex(); PutIRC("AUTHENTICATE " + m_Mechanisms.GetCurrent()); } else { CheckRequireAuth(); GetNetwork()->GetIRCSock()->ResumeCap(); } } else if (msg.GetCode() == 906) { /* CAP wasn't paused? */ DEBUG("sasl: Reached 906."); CheckRequireAuth(); } else if (msg.GetCode() == 907) { m_bAuthenticated = true; GetNetwork()->GetIRCSock()->ResumeCap(); DEBUG("sasl: Received 907 -- We are already registered"); } else { return CONTINUE; } return HALT; }
bool CIRCSock::OnNumericMessage(CNumericMessage& Message) { const CString& sCmd = Message.GetCommand(); CString sServer = Message.GetNick().GetHostMask(); unsigned int uRaw = Message.GetCode(); CString sNick = Message.GetParam(0); bool bResult = false; IRCSOCKMODULECALL(OnNumericMessage(Message), &bResult); if (bResult) return true; switch (uRaw) { case 1: { // :irc.server.com 001 nick :Welcome to the Internet Relay if (m_bAuthed && sServer == "irc.znc.in") { // m_bAuthed == true => we already received another 001 => we // might be in a traffic loop m_pNetwork->PutStatus( "ZNC seems to be connected to itself, disconnecting..."); Quit(); return true; } m_pNetwork->SetIRCServer(sServer); // Now that we are connected, let nature take its course SetTimeout(CIRCNetwork::NO_TRAFFIC_TIMEOUT, TMO_READ); PutIRC("WHO " + sNick); m_bAuthed = true; m_pNetwork->PutStatus("Connected!"); const vector<CClient*>& vClients = m_pNetwork->GetClients(); for (CClient* pClient : vClients) { CString sClientNick = pClient->GetNick(false); if (!sClientNick.Equals(sNick)) { // If they connected with a nick that doesn't match the one // we got on irc, then we need to update them pClient->PutClient(":" + sClientNick + "!" + m_Nick.GetIdent() + "@" + m_Nick.GetHost() + " NICK :" + sNick); } } SetNick(sNick); IRCSOCKMODULECALL(OnIRCConnected(), NOTHING); m_pNetwork->ClearRawBuffer(); m_pNetwork->AddRawBuffer(BufferMessage(Message)); m_pNetwork->IRCConnected(); break; } case 5: ParseISupport(Message); m_pNetwork->UpdateExactRawBuffer(BufferMessage(Message)); break; case 10: { // :irc.server.com 010 nick <hostname> <port> :<info> CString sHost = Message.GetParam(1); CString sPort = Message.GetParam(2); CString sInfo = Message.GetParam(3); m_pNetwork->PutStatus( "Server [" + m_pNetwork->GetCurrentServer()->GetString(false) + "] redirects us to [" + sHost + ":" + sPort + "] with reason [" + sInfo + "]"); m_pNetwork->PutStatus( "Perhaps you want to add it as a new server."); // Don't send server redirects to the client return true; } case 2: case 3: case 4: case 250: // highest connection count case 251: // user count case 252: // oper count case 254: // channel count case 255: // client count case 265: // local users case 266: // global users m_pNetwork->UpdateRawBuffer(sCmd, BufferMessage(Message)); break; case 305: m_pNetwork->SetIRCAway(false); break; case 306: m_pNetwork->SetIRCAway(true); break; case 324: { // MODE // :irc.server.com 324 nick #chan +nstk key CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { pChan->SetModes(Message.GetParams(2)); // We don't SetModeKnown(true) here, // because a 329 will follow if (!pChan->IsModeKnown()) { // When we JOIN, we send a MODE // request. This makes sure the // reply isn't forwarded. return true; } if (pChan->IsDetached()) { return true; } } } break; case 329: { // :irc.server.com 329 nick #chan 1234567890 CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { unsigned long ulDate = Message.GetParam(2).ToULong(); pChan->SetCreationDate(ulDate); if (!pChan->IsModeKnown()) { pChan->SetModeKnown(true); // When we JOIN, we send a MODE // request. This makes sure the // reply isn't forwarded. return true; } if (pChan->IsDetached()) { return true; } } } break; case 331: { // :irc.server.com 331 yournick #chan :No topic is set. CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { pChan->SetTopic(""); if (pChan->IsDetached()) { return true; } } break; } case 332: { // :irc.server.com 332 yournick #chan :This is a topic CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { CString sTopic = Message.GetParam(2); pChan->SetTopic(sTopic); if (pChan->IsDetached()) { return true; } } break; } case 333: { // :irc.server.com 333 yournick #chan setternick 1112320796 CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { sNick = Message.GetParam(2); unsigned long ulDate = Message.GetParam(3).ToULong(); pChan->SetTopicOwner(sNick); pChan->SetTopicDate(ulDate); if (pChan->IsDetached()) { return true; } } break; } case 352: { // WHO // :irc.yourserver.com 352 yournick #chan ident theirhost.com irc.theirserver.com theirnick H :0 Real Name sNick = Message.GetParam(5); CString sChan = Message.GetParam(1); CString sIdent = Message.GetParam(2); CString sHost = Message.GetParam(3); if (sNick.Equals(GetNick())) { m_Nick.SetIdent(sIdent); m_Nick.SetHost(sHost); } m_pNetwork->SetIRCNick(m_Nick); m_pNetwork->SetIRCServer(sServer); const vector<CChan*>& vChans = m_pNetwork->GetChans(); for (CChan* pChan : vChans) { pChan->OnWho(sNick, sIdent, sHost); } CChan* pChan = m_pNetwork->FindChan(sChan); if (pChan && pChan->IsDetached()) { return true; } break; } case 353: { // NAMES // :irc.server.com 353 nick @ #chan :nick1 nick2 // Todo: allow for non @+= server msgs CChan* pChan = m_pNetwork->FindChan(Message.GetParam(2)); // If we don't know that channel, some client might have // requested a /names for it and we really should forward this. if (pChan) { CString sNicks = Message.GetParam(3); pChan->AddNicks(sNicks); if (pChan->IsDetached()) { return true; } } break; } case 366: { // end of names list // :irc.server.com 366 nick #chan :End of /NAMES list. CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (pChan) { if (pChan->IsOn()) { // If we are the only one in the chan, set our default modes if (pChan->GetNickCount() == 1) { CString sModes = pChan->GetDefaultModes(); if (sModes.empty()) { sModes = m_pNetwork->GetUser()->GetDefaultChanModes(); } if (!sModes.empty()) { PutIRC("MODE " + pChan->GetName() + " " + sModes); } } } if (pChan->IsDetached()) { // don't put it to clients return true; } } break; } case 375: // begin motd case 422: // MOTD File is missing if (m_pNetwork->GetIRCServer().Equals(sServer)) { m_pNetwork->ClearMotdBuffer(); } case 372: // motd case 376: // end motd if (m_pNetwork->GetIRCServer().Equals(sServer)) { m_pNetwork->AddMotdBuffer(BufferMessage(Message)); } break; case 437: // :irc.server.net 437 * badnick :Nick/channel is temporarily unavailable // :irc.server.net 437 mynick badnick :Nick/channel is temporarily unavailable // :irc.server.net 437 mynick badnick :Cannot change nickname while banned on channel if (m_pNetwork->IsChan(Message.GetParam(1)) || sNick != "*") break; case 432: // :irc.server.com 432 * nick :Erroneous Nickname: Illegal chars case 433: { CString sBadNick = Message.GetParam(1); if (!m_bAuthed) { SendAltNick(sBadNick); return true; } break; } case 451: // :irc.server.com 451 CAP :You have not registered // Servers that don't support CAP will give us this error, don't send // it to the client if (sNick.Equals("CAP")) return true; case 470: { // :irc.unreal.net 470 mynick [Link] #chan1 has become full, so you are automatically being transferred to the linked channel #chan2 // :mccaffrey.freenode.net 470 mynick #electronics ##electronics :Forwarding to another channel // freenode style numeric CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1)); if (!pChan) { // unreal style numeric pChan = m_pNetwork->FindChan(Message.GetParam(2)); } if (pChan) { pChan->Disable(); m_pNetwork->PutStatus("Channel [" + pChan->GetName() + "] is linked to " "another channel and was thus disabled."); } break; } case 670: // :hydra.sector5d.org 670 kylef :STARTTLS successful, go ahead with TLS handshake // // 670 is a response to `STARTTLS` telling the client to switch to // TLS if (!GetSSL()) { StartTLS(); m_pNetwork->PutStatus("Switched to SSL (STARTTLS)"); } return true; } return false; }
EModRet OnNumericMessage(CNumericMessage& msg) override { vsHooks.push_back("OnNumericMessage"); vsMessages.push_back(msg.ToString()); vNetworks.push_back(msg.GetNetwork()); vChannels.push_back(msg.GetChan()); return eAction; }