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(t_s(
                    "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(m_pNetwork->GetUser()->GetNoTrafficTimeout(), 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(
                t_f("Server {1} redirects us to {2}:{3} with reason: {4}")(
                    m_pNetwork->GetCurrentServer()->GetString(false), sHost,
                    sPort, sInfo));
            m_pNetwork->PutStatus(
                t_s("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.GetParamsColon(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);

            // A nick can only have one ident and hostname. Yes, you can query
            // this information per-channel, but it is still global. For
            // example, if the client supports UHNAMES, but the IRC server does
            // not, then AFAIR "passive snooping of WHO replies" is the only way
            // that ZNC can figure out the ident and host for the UHNAMES
            // replies.
            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(
                    t_f("Channel {1} is linked to another channel and was thus "
                        "disabled.")(pChan->GetName()));
            }
            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(t_s("Switched to SSL (STARTTLS)"));
            }

            return true;
    }

    return false;
}