Example #1
0
bool CClient::OnCTCPMessage(CCTCPMessage& Message) {
    CString sTargets = Message.GetTarget();

    VCString vTargets;
    sTargets.Split(",", vTargets, false);

    if (Message.IsReply()) {
        CString sCTCP = Message.GetText();
        if (sCTCP.Token(0) == "VERSION") {
            // There are 2 different scenarios:
            //
            // a) CTCP reply for VERSION is not set.
            // 1. ZNC receives CTCP VERSION from someone
            // 2. ZNC forwards CTCP VERSION to client
            // 3. Client replies with something
            // 4. ZNC adds itself to the reply
            // 5. ZNC sends the modified reply to whoever asked
            //
            // b) CTCP reply for VERSION is set.
            // 1. ZNC receives CTCP VERSION from someone
            // 2. ZNC replies with the configured reply (or just drops it if
            //    empty), without forwarding anything to client
            // 3. Client does not see any CTCP request, and does not reply
            //
            // So, if user doesn't want "via ZNC" in CTCP VERSION reply, they
            // can set custom reply.
            //
            // See more bikeshedding at github issues #820 and #1012
            Message.SetText(sCTCP + " via " + CZNC::GetTag(false));
        }
    }

    for (CString& sTarget : vTargets) {
        Message.SetTarget(sTarget);
        if (m_pNetwork) {
            // May be nullptr.
            Message.SetChan(m_pNetwork->FindChan(sTarget));
        }

        bool bContinue = false;
        if (Message.IsReply()) {
            NETWORKMODULECALL(OnUserCTCPReplyMessage(Message), m_pUser,
                              m_pNetwork, this, &bContinue);
        } else {
            NETWORKMODULECALL(OnUserCTCPMessage(Message), m_pUser, m_pNetwork,
                              this, &bContinue);
        }
        if (bContinue) continue;

        if (!GetIRCSock()) {
            // Some lagmeters do a NOTICE to their own nick, ignore those.
            if (!sTarget.Equals(m_sNick))
                PutStatus(t_f(
                    "Your CTCP to {1} got lost, you are not connected to IRC!")(
                    Message.GetTarget()));
            continue;
        }

        if (m_pNetwork) {
            PutIRC(Message.ToString(CMessage::ExcludePrefix |
                                    CMessage::ExcludeTags));
        }
    }

    return true;
}
Example #2
0
bool CIRCSock::OnCTCPMessage(CCTCPMessage& Message) {
    bool bResult = false;
    CChan* pChan = nullptr;
    CString sTarget = Message.GetTarget();
    if (sTarget.Equals(GetNick())) {
        if (Message.IsReply()) {
            IRCSOCKMODULECALL(OnCTCPReplyMessage(Message), &bResult);
            return bResult;
        } else {
            IRCSOCKMODULECALL(OnPrivCTCPMessage(Message), &bResult);
            if (bResult) return true;
        }
    } else {
        pChan = m_pNetwork->FindChan(sTarget);
        if (pChan) {
            Message.SetChan(pChan);
            FixupChanNick(Message.GetNick(), pChan);
            IRCSOCKMODULECALL(OnChanCTCPMessage(Message), &bResult);
            if (bResult) return true;
        }
    }

    const CNick& Nick = Message.GetNick();
    const CString& sMessage = Message.GetText();
    const MCString& mssCTCPReplies = m_pNetwork->GetUser()->GetCTCPReplies();
    CString sQuery = sMessage.Token(0).AsUpper();
    MCString::const_iterator it = mssCTCPReplies.find(sQuery);
    bool bHaveReply = false;
    CString sReply;

    if (it != mssCTCPReplies.end()) {
        sReply = m_pNetwork->ExpandString(it->second);
        bHaveReply = true;

        if (sReply.empty()) {
            return true;
        }
    }

    if (!bHaveReply && !m_pNetwork->IsUserAttached()) {
        if (sQuery == "VERSION") {
            sReply = CZNC::GetTag(false);
        } else if (sQuery == "PING") {
            sReply = sMessage.Token(1, true);
        }
    }

    if (!sReply.empty()) {
        time_t now = time(nullptr);
        // If the last CTCP is older than m_uCTCPFloodTime, reset the counter
        if (m_lastCTCP + m_uCTCPFloodTime < now) m_uNumCTCP = 0;
        m_lastCTCP = now;
        // If we are over the limit, don't reply to this CTCP
        if (m_uNumCTCP >= m_uCTCPFloodCount) {
            DEBUG("CTCP flood detected - not replying to query");
            return true;
        }
        m_uNumCTCP++;

        PutIRC("NOTICE " + Nick.GetNick() + " :\001" + sQuery + " " + sReply +
               "\001");
        return true;
    }

    return (pChan && pChan->IsDetached());
}