Example #1
0
	void OnModCommand(const CString& sCmdLine) override
	{
		CString sCommand = sCmdLine.Token(0);
		CString sArgs    = sCmdLine.Token(1, true);

		if (sCommand.Equals("dumpbuff")) {
			// for testing purposes - hidden from help
			CString sFile;
			CString sName;
			if (DecryptBuffer(GetPath(sArgs), sFile, sName))
			{
				VCString vsLines;
				VCString::iterator it;

				sFile.Split("\n", vsLines);

				for (it = vsLines.begin(); it != vsLines.end(); ++it) {
					CString sLine(*it);
					sLine.Trim();
					PutModule("[" + sLine + "]");
				}
			}
			PutModule("//!-- EOF " + sArgs);
		} else {
			HandleCommand(sCmdLine);
		}
	}
Example #2
0
	void BootStrap(T *pTarget, const CString& sContent)
	{
		if (!pTarget->GetBuffer().IsEmpty())
			return; // in this case the module was probably reloaded

		VCString vsLines;
		VCString::iterator it;

		sContent.Split("\n", vsLines);

		for (it = vsLines.begin(); it != vsLines.end(); ++it) {
			CString sLine(*it);
			sLine.Trim();
			if (sLine[0] == '@' && it+1 != vsLines.end())
			{
				CString sTimestamp = sLine.Token(0);
				sTimestamp.TrimLeft("@");
				timeval ts;
				ts.tv_sec = sTimestamp.Token(0, false, ",").ToLongLong();
				ts.tv_usec = sTimestamp.Token(1, false, ",").ToLong();

				CString sFormat = sLine.Token(1, true);

				CString sText(*++it);
				sText.Trim();

				pTarget->AddBuffer(sFormat, sText, &ts);
			} else
			{
				// Old format, escape the line and use as is.
				pTarget->AddBuffer(_NAMEDFMT(sLine));
			}
		}
	}
Example #3
0
bool CClient::OnPartMessage(CPartMessage& Message) {
    CString sChans = Message.GetTarget();

    VCString vsChans;
    sChans.Split(",", vsChans, false);
    sChans.clear();

    for (CString& sChan : vsChans) {
        bool bContinue = false;
        Message.SetTarget(sChan);
        NETWORKMODULECALL(OnUserPartMessage(Message), m_pUser, m_pNetwork, this,
                          &bContinue);
        if (bContinue) continue;

        sChan = Message.GetTarget();

        CChan* pChan = m_pNetwork ? m_pNetwork->FindChan(sChan) : nullptr;

        if (pChan && !pChan->IsOn()) {
            PutStatusNotice("Removing channel [" + sChan + "]");
            m_pNetwork->DelChan(sChan);
        } else {
            sChans += (sChans.empty()) ? sChan : CString("," + sChan);
        }
    }

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

    Message.SetTarget(sChans);

    return false;
}
Example #4
0
    virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
        // Load the chans from the command line
        unsigned int a = 0;
        VCString vsChans;
        sArgs.Split(" ", vsChans, false);

        for (VCString::const_iterator it = vsChans.begin(); it != vsChans.end(); ++it) {
            CString sName = "Args";
            sName += CString(a);
            AddUser(sName, "*", *it);
        }

        // Load the saved users
        for (MCString::iterator it = BeginNV(); it != EndNV(); it++) {
            const CString& sLine = it->second;
            CAutoVoiceUser* pUser = new CAutoVoiceUser;

            if (!pUser->FromString(sLine) || FindUser(pUser->GetUsername().AsLower())) {
                delete pUser;
            } else {
                m_msUsers[pUser->GetUsername().AsLower()] = pUser;
            }
        }

        return true;
    }
Example #5
0
	virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
		VCString vsChans;
		sArgs.Split(" ", vsChans, false);

		for (VCString::const_iterator it = vsChans.begin(); it != vsChans.end(); ++it) {
			CString sAdd = *it;
			bool bNegated = sAdd.TrimPrefix("!");
			CString sChan = sAdd.Token(0);
			CString sHost = sAdd.Token(1, true);

			if (!Add(bNegated, sChan, sHost)) {
				PutModule("Unable to add [" + *it + "]");
			}
		}

		// Load our saved settings, ignore errors
		MCString::iterator it;
		for (it = BeginNV(); it != EndNV(); ++it) {
			CString sAdd = it->first;
			bool bNegated = sAdd.TrimPrefix("!");
			CString sChan = sAdd.Token(0);
			CString sHost = sAdd.Token(1, true);

			Add(bNegated, sChan, sHost);
		}

		return true;
	}
Example #6
0
	bool BootStrap(CChan *pChan)
	{
		CString sFile;
		if (DecryptChannel(pChan->GetName(), sFile))
		{
			if (!pChan->GetBuffer().empty())
				return(true); // reloaded a module probably in this case, so just verify we can decrypt the file

			VCString vsLines;
			VCString::iterator it;

			sFile.Split("\n", vsLines);

			for (it = vsLines.begin(); it != vsLines.end(); ++it) {
				CString sLine(*it);
				sLine.Trim();
				pChan->AddBuffer(sLine);
			}
		} else
		{
			m_sPassword = "";
			CUtils::PrintError("[" + GetModName() + ".so] Failed to Decrypt [" + pChan->GetName() + "]");
			return(false);
		}

		return(true);
	}
Example #7
0
	virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
		VCString vsArgs;
		VCString::const_iterator it;
		sArgs.Split(" ", vsArgs, false);

		for (it = vsArgs.begin(); it != vsArgs.end(); ++it) {
			if (it->Equals("saslauthd") || it->Equals("auxprop")) {
				m_sMethod += *it + " ";
			} else {
				CUtils::PrintError("Ignoring invalid SASL pwcheck method: " + *it);
				sMessage = "Ignored invalid SASL pwcheck method";
			}
		}

		m_sMethod.TrimRight();

		if (m_sMethod.empty()) {
			sMessage = "Need a pwcheck method as argument (saslauthd, auxprop)";
			return false;
		}

		if (sasl_server_init(NULL, NULL) != SASL_OK) {
			sMessage = "SASL Could Not Be Initialized - Halting Startup";
			return false;
		}

		m_cbs[0].id = SASL_CB_GETOPT;
		m_cbs[0].proc = reinterpret_cast<int(*)()>(CSASLAuthMod::getopt);
		m_cbs[0].context = this;
		m_cbs[1].id = SASL_CB_LIST_END;
		m_cbs[1].proc = NULL;
		m_cbs[1].context = NULL;

		return true;
	}
Example #8
0
bool CClient::OnJoinMessage(CJoinMessage& Message) {
    CString sChans = Message.GetTarget();
    CString sKeys = Message.GetKey();

    VCString vsChans;
    sChans.Split(",", vsChans, false);
    sChans.clear();

    VCString vsKeys;
    sKeys.Split(",", vsKeys, true);
    sKeys.clear();

    for (unsigned int a = 0; a < vsChans.size(); a++) {
        Message.SetTarget(vsChans[a]);
        Message.SetKey((a < vsKeys.size()) ? vsKeys[a] : "");
        bool bContinue = false;
        NETWORKMODULECALL(OnUserJoinMessage(Message), m_pUser, m_pNetwork, this,
                          &bContinue);
        if (bContinue) continue;

        CString sChannel = Message.GetTarget();
        CString sKey = Message.GetKey();

        CChan* pChan = m_pNetwork ? m_pNetwork->FindChan(sChannel) : nullptr;
        if (pChan) {
            if (pChan->IsDetached())
                pChan->AttachUser(this);
            else
                pChan->JoinUser(sKey);
            continue;
        }

        if (!sChannel.empty()) {
            sChans += (sChans.empty()) ? sChannel : CString("," + sChannel);

            if (!vsKeys.empty()) {
                sKeys += (sKeys.empty()) ? sKey : CString("," + sKey);
            }
        }
    }

    Message.SetTarget(sChans);
    Message.SetKey(sKeys);

    return sChans.empty();
}
Example #9
0
    void AddChans(const CString& sChans) {
        VCString vsChans;
        sChans.Split(" ", vsChans);

        for (unsigned int a = 0; a < vsChans.size(); a++) {
            m_ssChans.insert(vsChans[a].AsLower());
        }
    }
Example #10
0
File: Chan.cpp Project: BtbN/znc
int CChan::AddNicks(const CString& sNicks) {
    int iRet = 0;
    VCString vsNicks;

    sNicks.Split(" ", vsNicks, false);

    for (const CString& sNick : vsNicks) {
        if (AddNick(sNick)) {
            iRet++;
        }
    }

    return iRet;
}
Example #11
0
bool CDir::MakeDir(const CString& sPath, mode_t iMode) {
#ifdef _WIN32
	if (sPath.empty())
		return false;

	CString sFixedPath = sPath;
	sFixedPath.Replace("/", "\\");

	int iResult = SHCreateDirectoryEx(0, sFixedPath.c_str(), NULL);

	return (iResult == ERROR_SUCCESS || iResult == ERROR_FILE_EXISTS || iResult == ERROR_ALREADY_EXISTS);
#else
	CString sDir;
	VCString dirs;
	VCString::iterator it;

	// Just in case someone tries this...
	if (sPath.empty())
		return false;

	// If this is an absolute path, we need to handle this now!
	if (sPath.Left(1) == "/")
		sDir = "/";

	// For every single subpath, do...
	sPath.Split("/", dirs, false);
	for (it = dirs.begin(); it != dirs.end(); ++it) {
		// Add this to the path we already created
		sDir += *it;

		int i = mkdir(sDir.c_str(), iMode);

		if (i != 0) {
			// All errors except EEXIST are fatal
			if (errno != EEXIST)
				return false;

			// If it's EEXIST we have to make sure it's a dir
			if (!CFile::IsDir(sDir))
				return false;
		}

		sDir += "/";
	}

	// All went well
	return true;
#endif
}
Example #12
0
int CChan::AddNicks(const CString& sNicks) {
	int iRet = 0;
	VCString vsNicks;
	VCString::iterator it;

	sNicks.Split(" ", vsNicks, false);

	for (it = vsNicks.begin(); it != vsNicks.end(); ++it) {
		if (AddNick(*it)) {
			iRet++;
		}
	}

	return iRet;
}
Example #13
0
void CHTTPSock::ParseParams(const CString& sParams,
                            map<CString, VCString>& msvsParams) {
    msvsParams.clear();

    VCString vsPairs;
    sParams.Split("&", vsPairs, true);

    for (const CString& sPair : vsPairs) {
        CString sName =
            sPair.Token(0, false, "=").Escape_n(CString::EURL, CString::EASCII);
        CString sValue =
            sPair.Token(1, true, "=").Escape_n(CString::EURL, CString::EASCII);

        msvsParams[sName].push_back(sValue);
    }
}
Example #14
0
	bool BootStrap(CChan *pChan)
	{
		CString sFile;
		if (DecryptChannel(pChan->GetName(), sFile))
		{
			if (!pChan->GetBuffer().IsEmpty())
				return(true); // reloaded a module probably in this case, so just verify we can decrypt the file

			VCString vsLines;
			VCString::iterator it;

			sFile.Split("\n", vsLines);

			for (it = vsLines.begin(); it != vsLines.end(); ++it) {
				CString sLine(*it);
				sLine.Trim();
				if (sLine[0] == '@' && it+1 != vsLines.end())
				{
					CString sTimestamp = sLine.Token(0);
					sTimestamp.TrimLeft("@");
					timeval ts;
					ts.tv_sec = sTimestamp.Token(0, false, ",").ToLongLong();
					ts.tv_usec = sTimestamp.Token(1, false, ",").ToLong();

					CString sFormat = sLine.Token(1, true);

					CString sText(*++it);
					sText.Trim();

					pChan->AddBuffer(sFormat, sText, &ts);
				} else
				{
					// Old format, escape the line and use as is.
					pChan->AddBuffer(_NAMEDFMT(sLine));
				}
			}
		} else
		{
			m_sPassword = "";
			CUtils::PrintError("[" + GetModName() + ".so] Failed to Decrypt [" + pChan->GetName() + "]");
			return(false);
		}

		return(true);
	}
Example #15
0
bool CClient::OnTextMessage(CTextMessage& Message) {
    CString sTargets = Message.GetTarget();

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

    for (CString& sTarget : vTargets) {
        Message.SetTarget(sTarget);

        if (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) {
            EchoMessage(Message);
            if (sTarget.Equals("status")) {
                CString sMsg = Message.GetText();
                UserCommand(sMsg);
            } else {
                CALLMOD(sTarget, this, m_pUser, m_pNetwork,
                        OnModCommand(Message.GetText()));
            }
            continue;
        }

        bool bContinue = false;
        NETWORKMODULECALL(OnUserTextMessage(Message), m_pUser, m_pNetwork, this,
                          &bContinue);
        if (bContinue) continue;

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

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

    return true;
}
Example #16
0
	void Replay(const CString & sChan)
	{
		CString sFile;
		PutUser(":***!znc@znc.in PRIVMSG " + sChan + " :Buffer Playback...");
		if (DecryptChannel(sChan, sFile))
		{
			VCString vsLines;
			VCString::iterator it;

			sFile.Split("\n", vsLines);

			for (it = vsLines.begin(); it != vsLines.end(); ++it) {
				CString sLine(*it);
				sLine.Trim();
				PutUser(sLine);
			}
		}
		PutUser(":***!znc@znc.in PRIVMSG " + sChan + " :Playback Complete.");
	}
Example #17
0
void CClient::PutModule(const CString& sModule, const CString& sLine) {
    if (!m_pUser) {
        return;
    }

    DEBUG("(" << GetFullName()
              << ") ZNC -> CLI [:" + m_pUser->GetStatusPrefix() +
                     ((sModule.empty()) ? "status" : sModule) +
                     "!znc@znc.in PRIVMSG " << GetNick() << " :" << sLine
              << "]");

    VCString vsLines;
    sLine.Split("\n", vsLines);
    for (const CString& s : vsLines) {
        Write(":" + m_pUser->GetStatusPrefix() +
              ((sModule.empty()) ? "status" : sModule) +
              "!znc@znc.in PRIVMSG " + GetNick() + " :" + s + "\r\n");
    }
}
Example #18
0
    void SetMechanismCommand(const CString& sLine) {
        CString sMechanisms = sLine.Token(1, true).AsUpper();

        if (!sMechanisms.empty()) {
            VCString vsMechanisms;
            sMechanisms.Split(" ", vsMechanisms);

            for (const CString& sMechanism : vsMechanisms) {
                if (!SupportsMechanism(sMechanism)) {
                    PutModule("Unsupported mechanism: " + sMechanism);
                    return;
                }
            }

            SetNV(NV_MECHANISMS, sMechanisms);
        }

        PutModule("Current mechanisms set: " + GetMechanismsString());
    }
Example #19
0
    void OnModCommand(const CString& sCommand) override {
        CString sResult;
        VCString vsResult;
        CString sCmd = sCommand;

        if (sCmd.Token(0).CaseCmp(".tcl") == 0) sCmd = sCmd.Token(1, true);

        if (sCmd.Left(1).CaseCmp(".") == 0)
            sCmd = "Binds::ProcessDcc - - {" + sCmd + "}";

        Tcl_Eval(interp, sCmd.c_str());

        sResult = CString(Tcl_GetStringResult(interp));
        if (!sResult.empty()) {
            sResult.Split("\n", vsResult);
            unsigned int a = 0;
            for (a = 0; a < vsResult.size(); a++)
                PutModule(vsResult[a].TrimRight_n());
        }
    }
Example #20
0
	virtual void OnModCommand(const CString& sCmdLine)
	{
		CString sCommand = sCmdLine.Token(0);
		CString sArgs    = sCmdLine.Token(1, true);

		if (sCommand.Equals("setpass"))
		{
			PutModule("Password set to [" + sArgs + "]");
			m_sPassword = CBlowfish::MD5(sArgs);

		} else if (sCommand.Equals("dumpbuff"))
		{
			CString sFile;
			if (DecryptChannel(sArgs, sFile))
			{
				VCString vsLines;
				VCString::iterator it;

				sFile.Split("\n", vsLines);

				for (it = vsLines.begin(); it != vsLines.end(); ++it) {
					CString sLine(*it);
					sLine.Trim();
					PutModule("[" + sLine + "]");
				}
			}
			PutModule("//!-- EOF " + sArgs);
		} else if (sCommand.Equals("replay"))
		{
			Replay(sArgs);
			PutModule("Replayed " + sArgs);

		} else if (sCommand.Equals("save"))
		{
			SaveBufferToDisk();
			PutModule("Done.");
		} else
			PutModule("Unknown command [" + sCommand + "]");
	}
Example #21
0
	virtual bool OnLoad(const CString& sArgs, CString& sMessage) {
		VCString vsChans;
		sArgs.Split(" ", vsChans, false);

		for (VCString::const_iterator it = vsChans.begin(); it != vsChans.end(); ++it) {
			if (!Add(*it)) {
				PutModule("Unable to add [" + *it + "]");
			}
		}

		// Load our saved settings, ignore errors
		MCString::iterator it;
		for (it = BeginNV(); it != EndNV(); ++it) {
			Add(it->first);
		}

		// Default is auto cycle for all channels
		if (m_vsChans.empty())
			Add("*");

		return true;
	}
Example #22
0
bool CDir::MakeDir(const CString& sPath, mode_t iMode) {
	CString sDir;
	VCString dirs;
	VCString::iterator it;

	// Just in case someone tries this...
	if (sPath.empty()) {
		errno = ENOENT;
		return false;
	}

	// If this is an absolute path, we need to handle this now!
	if (sPath.StartsWith("/"))
		sDir = "/";

	// For every single subpath, do...
	sPath.Split("/", dirs, false);
	for (it = dirs.begin(); it != dirs.end(); ++it) {
		// Add this to the path we already created
		sDir += *it;

		int i = mkdir(sDir.c_str(), iMode);

		if (i != 0) {
			// All errors except EEXIST are fatal
			if (errno != EEXIST)
				return false;

			// If it's EEXIST we have to make sure it's a dir
			if (!CFile::IsDir(sDir))
				return false;
		}

		sDir += "/";
	}

	// All went well
	return true;
}
Example #23
0
    bool OnLoad(const CString& sArgs, CString& sMessage) override {
        VCString vArgs;
        VCString::iterator it;
        MCString::iterator it2;

        // Load saved settings
        for (it2 = BeginNV(); it2 != EndNV(); ++it2) {
            // Ignore errors
            Block(it2->first);
        }

        // Parse arguments, each argument is a user name to block
        sArgs.Split(" ", vArgs, false);

        for (it = vArgs.begin(); it != vArgs.end(); ++it) {
            if (!Block(*it)) {
                sMessage = "Could not block [" + *it + "]";
                return false;
            }
        }

        return true;
    }
Example #24
0
bool CClient::OnActionMessage(CActionMessage& Message) {
    CString sTargets = Message.GetTarget();

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

    for (CString& sTarget : vTargets) {
        Message.SetTarget(sTarget);

        bool bContinue = false;
        NETWORKMODULECALL(OnUserActionMessage(Message), m_pUser, m_pNetwork,
                          this, &bContinue);
        if (bContinue) continue;

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

    return true;
}
Example #25
0
bool CIRCSock::OnCapabilityMessage(CMessage& Message) {
    // CAPs are supported only before authorization.
    if (!m_bAuthed) {
        // The first parameter is most likely "*". No idea why, the
        // CAP spec don't mention this, but all implementations
        // I've seen add this extra asterisk
        CString sSubCmd = Message.GetParam(1);

        // If the caplist of a reply is too long, it's split
        // into multiple replies. A "*" is prepended to show
        // that the list was split into multiple replies.
        // This is useful mainly for LS. For ACK and NAK
        // replies, there's no real need for this, because
        // we request only 1 capability per line.
        // If we will need to support broken servers or will
        // send several requests per line, need to delay ACK
        // actions until all ACK lines are received and
        // to recognize past request of NAK by 100 chars
        // of this reply.
        CString sArgs;
        if (Message.GetParam(2) == "*") {
            sArgs = Message.GetParam(3);
        } else {
            sArgs = Message.GetParam(2);
        }

        std::map<CString, std::function<void(bool bVal)>> mSupportedCaps = {
            {"multi-prefix", [this](bool bVal) {
                    m_bNamesx = bVal;
                }
            },
            {"userhost-in-names", [this](bool bVal) {
                    m_bUHNames = bVal;
                }
            },
            {"away-notify", [this](bool bVal) {
                    m_bAwayNotify = bVal;
                }
            },
            {"account-notify", [this](bool bVal) {
                    m_bAccountNotify = bVal;
                }
            },
            {"extended-join", [this](bool bVal) {
                    m_bExtendedJoin = bVal;
                }
            },
            {"server-time", [this](bool bVal) {
                    m_bServerTime = bVal;
                }
            },
            {"znc.in/server-time-iso", [this](bool bVal) {
                    m_bServerTime = bVal;
                }
            },
        };

        if (sSubCmd == "LS") {
            VCString vsTokens;
            sArgs.Split(" ", vsTokens, false);

            for (const CString& sCap : vsTokens) {
                if (OnServerCapAvailable(sCap) || mSupportedCaps.count(sCap)) {
                    m_ssPendingCaps.insert(sCap);
                }
            }
        } else if (sSubCmd == "ACK") {
            sArgs.Trim();
            IRCSOCKMODULECALL(OnServerCapResult(sArgs, true), NOTHING);
            const auto& it = mSupportedCaps.find(sArgs);
            if (it != mSupportedCaps.end()) {
                it->second(true);
            }
            m_ssAcceptedCaps.insert(sArgs);
        } else if (sSubCmd == "NAK") {
            // This should work because there's no [known]
            // capability with length of name more than 100 characters.
            sArgs.Trim();
            IRCSOCKMODULECALL(OnServerCapResult(sArgs, false), NOTHING);
        }

        SendNextCap();
    }
    // Don't forward any CAP stuff to the client
    return true;
}
Example #26
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);

        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("Your CTCP to [" + Message.GetTarget() +
                          "] got lost, "
                          "you are not connected to IRC!");
            continue;
        }

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

    return true;
}
Example #27
0
bool CClient::PutClient(const CMessage& Message) {
    if (!m_bAwayNotify && Message.GetType() == CMessage::Type::Away) {
        return false;
    } else if (!m_bAccountNotify &&
               Message.GetType() == CMessage::Type::Account) {
        return false;
    }

    CMessage Msg(Message);

    const CIRCSock* pIRCSock = GetIRCSock();
    if (pIRCSock) {
        if (Msg.GetType() == CMessage::Type::Numeric) {
            unsigned int uCode = Msg.As<CNumericMessage>().GetCode();

            if (uCode == 352) {  // RPL_WHOREPLY
                if (!m_bNamesx && pIRCSock->HasNamesx()) {
                    // The server has NAMESX, but the client doesn't, so we need
                    // to remove extra prefixes
                    CString sNick = Msg.GetParam(6);
                    if (sNick.size() > 1 && pIRCSock->IsPermChar(sNick[1])) {
                        CString sNewNick = sNick;
                        size_t pos =
                            sNick.find_first_not_of(pIRCSock->GetPerms());
                        if (pos >= 2 && pos != CString::npos) {
                            sNewNick = sNick[0] + sNick.substr(pos);
                        }
                        Msg.SetParam(6, sNewNick);
                    }
                }
            } else if (uCode == 353) {  // RPL_NAMES
                if ((!m_bNamesx && pIRCSock->HasNamesx()) ||
                    (!m_bUHNames && pIRCSock->HasUHNames())) {
                    // The server has either UHNAMES or NAMESX, but the client
                    // is missing either or both
                    CString sNicks = Msg.GetParam(3);
                    VCString vsNicks;
                    sNicks.Split(" ", vsNicks, false);

                    for (CString& sNick : vsNicks) {
                        if (sNick.empty()) break;

                        if (!m_bNamesx && pIRCSock->HasNamesx() &&
                            pIRCSock->IsPermChar(sNick[0])) {
                            // The server has NAMESX, but the client doesn't, so
                            // we just use the first perm char
                            size_t pos =
                                sNick.find_first_not_of(pIRCSock->GetPerms());
                            if (pos >= 2 && pos != CString::npos) {
                                sNick = sNick[0] + sNick.substr(pos);
                            }
                        }

                        if (!m_bUHNames && pIRCSock->HasUHNames()) {
                            // The server has UHNAMES, but the client doesn't,
                            // so we strip away ident and host
                            sNick = sNick.Token(0, false, "!");
                        }
                    }

                    Msg.SetParam(
                        3, CString(" ").Join(vsNicks.begin(), vsNicks.end()));
                }
            }
        } else if (Msg.GetType() == CMessage::Type::Join) {
            if (!m_bExtendedJoin && pIRCSock->HasExtendedJoin()) {
                Msg.SetParams({Msg.As<CJoinMessage>().GetTarget()});
            }
        }
    }

    MCString mssTags;

    for (const auto& it : Msg.GetTags()) {
        if (IsTagEnabled(it.first)) {
            mssTags[it.first] = it.second;
        }
    }

    if (HasServerTime()) {
        // If the server didn't set the time tag, manually set it
        mssTags.emplace("time", CUtils::FormatServerTime(Msg.GetTime()));
    }

    Msg.SetTags(mssTags);
    Msg.SetClient(this);
    Msg.SetNetwork(m_pNetwork);

    bool bReturn = false;
    NETWORKMODULECALL(OnSendToClientMessage(Msg), m_pUser, m_pNetwork, this,
                      &bReturn);
    if (bReturn) return false;

    CString sCopy = Msg.ToString();
    NETWORKMODULECALL(OnSendToClient(sCopy, *this), m_pUser, m_pNetwork, this,
                      &bReturn);
    if (bReturn) return false;

    DEBUG("(" << GetFullName() << ") ZNC -> CLI ["
        << CDebug::Filter(sCopy) << "]");
    Write(sCopy + "\r\n");
    return true;
}
Example #28
0
bool CClient::PutClient(const CMessage& Message) {
    if (!m_bAwayNotify && Message.GetType() == CMessage::Type::Away) {
        return false;
    } else if (!m_bAccountNotify &&
               Message.GetType() == CMessage::Type::Account) {
        return false;
    }

    CMessage Msg(Message);

    const CIRCSock* pIRCSock = GetIRCSock();
    if (pIRCSock) {
        if (Msg.GetType() == CMessage::Type::Numeric) {
            unsigned int uCode = Msg.As<CNumericMessage>().GetCode();

            if (uCode == 352) {  // RPL_WHOREPLY
                if (!m_bNamesx && pIRCSock->HasNamesx()) {
                    // The server has NAMESX, but the client doesn't, so we need
                    // to remove extra prefixes
                    CString sNick = Msg.GetParam(6);
                    if (sNick.size() > 1 && pIRCSock->IsPermChar(sNick[1])) {
                        CString sNewNick = sNick;
                        size_t pos =
                            sNick.find_first_not_of(pIRCSock->GetPerms());
                        if (pos >= 2 && pos != CString::npos) {
                            sNewNick = sNick[0] + sNick.substr(pos);
                        }
                        Msg.SetParam(6, sNewNick);
                    }
                }
            } else if (uCode == 353) {  // RPL_NAMES
                if ((!m_bNamesx && pIRCSock->HasNamesx()) ||
                    (!m_bUHNames && pIRCSock->HasUHNames())) {
                    // The server has either UHNAMES or NAMESX, but the client
                    // is missing either or both
                    CString sNicks = Msg.GetParam(3);
                    VCString vsNicks;
                    sNicks.Split(" ", vsNicks, false);

                    for (CString& sNick : vsNicks) {
                        if (sNick.empty()) break;

                        if (!m_bNamesx && pIRCSock->HasNamesx() &&
                            pIRCSock->IsPermChar(sNick[0])) {
                            // The server has NAMESX, but the client doesn't, so
                            // we just use the first perm char
                            size_t pos =
                                sNick.find_first_not_of(pIRCSock->GetPerms());
                            if (pos >= 2 && pos != CString::npos) {
                                sNick = sNick[0] + sNick.substr(pos);
                            }
                        }

                        if (!m_bUHNames && pIRCSock->HasUHNames()) {
                            // The server has UHNAMES, but the client doesn't,
                            // so we strip away ident and host
                            sNick = sNick.Token(0, false, "!");
                        }
                    }

                    Msg.SetParam(
                        3, CString(" ").Join(vsNicks.begin(), vsNicks.end()));
                }
            }
        } else if (Msg.GetType() == CMessage::Type::Join) {
            if (!m_bExtendedJoin && pIRCSock->HasExtendedJoin()) {
                Msg.SetParams({Msg.As<CJoinMessage>().GetTarget()});
            }
        }
    }

    CString sLine = Msg.ToString(CMessage::ExcludeTags);

    // TODO: introduce a module hook that gives control over the tags that are
    // sent
    MCString mssTags;

    if (HasServerTime()) {
        CString sServerTime = Msg.GetTag("time");
        if (!sServerTime.empty()) {
            mssTags["time"] = sServerTime;
        } else {
            mssTags["time"] = CUtils::FormatServerTime(Msg.GetTime());
        }
    }

    if (HasBatch()) {
        CString sBatch = Msg.GetTag("batch");
        if (!sBatch.empty()) {
            mssTags["batch"] = sBatch;
        }
    }

    if (!mssTags.empty()) {
        CUtils::SetMessageTags(sLine, mssTags);
    }

    PutClient(sLine);
    return true;
}