void CIRCNetwork::ClientConnected(CClient* pClient) {
    if (!m_pUser->MultiClients()) {
        BounceAllClients();
    }

    m_vClients.push_back(pClient);

    size_t uIdx, uSize;

    if (m_pIRCSock) {
        pClient->NotifyServerDependentCaps(m_pIRCSock->GetAcceptedCaps());
    }

    pClient->SetPlaybackActive(true);

    if (m_RawBuffer.IsEmpty()) {
        pClient->PutClient(":irc.znc.in 001 " + pClient->GetNick() +
                           " :" + t_s("Welcome to ZNC"));
    } else {
        const CString& sClientNick = pClient->GetNick(false);
        MCString msParams;
        msParams["target"] = sClientNick;

        uSize = m_RawBuffer.Size();
        for (uIdx = 0; uIdx < uSize; uIdx++) {
            pClient->PutClient(m_RawBuffer.GetLine(uIdx, *pClient, msParams));
        }

        const CNick& Nick = GetIRCNick();
        if (sClientNick != Nick.GetNick()) {  // case-sensitive match
            pClient->PutClient(":" + sClientNick + "!" + Nick.GetIdent() + "@" +
                               Nick.GetHost() + " NICK :" + Nick.GetNick());
            pClient->SetNick(Nick.GetNick());
        }
    }

    MCString msParams;
    msParams["target"] = GetIRCNick().GetNick();

    // Send the cached MOTD
    uSize = m_MotdBuffer.Size();
    if (uSize > 0) {
        for (uIdx = 0; uIdx < uSize; uIdx++) {
            pClient->PutClient(m_MotdBuffer.GetLine(uIdx, *pClient, msParams));
        }
    }

    if (GetIRCSock() != nullptr) {
        CString sUserMode("");
        const set<char>& scUserModes = GetIRCSock()->GetUserModes();
        for (char cMode : scUserModes) {
            sUserMode += cMode;
        }
        if (!sUserMode.empty()) {
            pClient->PutClient(":" + GetIRCNick().GetNickMask() + " MODE " +
                               GetIRCNick().GetNick() + " :+" + sUserMode);
        }
    }

    if (m_bIRCAway) {
        // If they want to know their away reason they'll have to whois
        // themselves. At least we can tell them their away status...
        pClient->PutClient(":irc.znc.in 306 " + GetIRCNick().GetNick() +
                           " :You have been marked as being away");
    }

    const vector<CChan*>& vChans = GetChans();
    for (CChan* pChan : vChans) {
        if ((pChan->IsOn()) && (!pChan->IsDetached())) {
            pChan->AttachUser(pClient);
        }
    }

    bool bClearQuery = m_pUser->AutoClearQueryBuffer();
    for (CQuery* pQuery : m_vQueries) {
        pQuery->SendBuffer(pClient);
        if (bClearQuery) {
            delete pQuery;
        }
    }
    if (bClearQuery) {
        m_vQueries.clear();
    }

    uSize = m_NoticeBuffer.Size();
    for (uIdx = 0; uIdx < uSize; uIdx++) {
        const CBufLine& BufLine = m_NoticeBuffer.GetBufLine(uIdx);
        CMessage Message(BufLine.GetLine(*pClient, msParams));
        Message.SetNetwork(this);
        Message.SetClient(pClient);
        Message.SetTime(BufLine.GetTime());
        Message.SetTags(BufLine.GetTags());
        bool bContinue = false;
        NETWORKMODULECALL(OnPrivBufferPlayMessage(Message), m_pUser, this,
                          nullptr, &bContinue);
        if (bContinue) continue;
        pClient->PutClient(Message);
    }
    m_NoticeBuffer.Clear();

    pClient->SetPlaybackActive(false);

    // Tell them why they won't connect
    if (!GetIRCConnectEnabled())
        pClient->PutStatus(
            t_s("You are currently disconnected from IRC. Use 'connect' to "
                "reconnect."));
}