Example #1
0
File: sasl.cpp Project: ConorOG/znc
	void SetMechanismCommand(const CString& sLine) {
		CString sMechanisms = sLine.Token(1, true).AsUpper();

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

			for (VCString::const_iterator it = vsMechanisms.begin(); it != vsMechanisms.end(); ++it) {
				if (!SupportsMechanism(*it)) {
					PutModule("Unsupported mechanism: " + *it);
					return;
				}
			}

			SetNV(NV_MECHANISMS, sMechanisms);
		}

		PutModule("Current mechanisms set: " + GetMechanismsString());
	}
Example #2
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);
			m_pNetwork->PutIRC(Message.ToString(CMessage::ExcludePrefix | CMessage::ExcludeTags));
		}
	}

	return true;
}
Example #3
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") {
			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);
			m_pNetwork->PutIRC(Message.ToString(CMessage::ExcludePrefix | CMessage::ExcludeTags));
		}
	}

	return true;
}
Example #4
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 #5
0
	void Replay(const CString & sBuffer)
	{
		CString sFile;
		CString sName;
		PutUser(":***[email protected] PRIVMSG " + sBuffer + " :Buffer Playback...");
		if (DecryptBuffer(GetPath(sBuffer), sFile, sName))
		{
			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(":***[email protected] PRIVMSG " + sBuffer + " :Playback Complete.");
	}
Example #6
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 #7
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 #8
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 #9
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);
        if (m_pNetwork) {
            // May be nullptr.
            Message.SetChan(m_pNetwork->FindChan(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(t_f("Removing channel {1}")(sChan));
            m_pNetwork->DelChan(sChan);
        } else {
            sChans += (sChans.empty()) ? sChan : CString("," + sChan);
        }
    }

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

    Message.SetTarget(sChans);

    return false;
}
Example #10
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 #11
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);
			m_pNetwork->PutIRC(Message.ToString(CMessage::ExcludePrefix | CMessage::ExcludeTags));
		}
	}

	return true;
}
Example #12
0
	bool BootStrap()
	{
		CString sFile;
		if (DecryptMessages(sFile))
		{
			VCString vsLines;
			VCString::iterator it;

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

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

		return(true);
	}
Example #13
0
void CUrlBufferModule::CheckLineForTrigger(const CString& sMessage, const CString& sTarget)
{
	if(GetNV("enablepublic").ToBool())
	{
		VCString words;
		sMessage.Split(" ", words, false, "", "", true, true);
		for (size_t a = 0; a < words.size(); a++) 
		{
			CString& word = words[a];
			if(word.AsLower() == "!showlinks")
			{
				if(lastUrls.empty())
					PutIRC("PRIVMSG " + sTarget + " :No links were found...");
				else 
				{
					unsigned int maxLinks = GetNV("buffersize").ToUInt();
								
					if (a+1 < words.size())
					{
						unsigned int size = words[a+1].ToUInt();
						if(size!=0 && size<UINT_MAX) //if it was a valid number
							maxLinks = size;
					}
                                        
                    unsigned int maxSize = lastUrls.size()-1;
                    for(unsigned int i=0; i<=maxSize && i<maxLinks; i++)
                    {
                          sleep(1);
                          PutIRC("PRIVMSG " + sTarget + " :" + nicks[maxSize-i] + ": "+ lastUrls[maxSize-i]);
                    }

				}
			}
		}
	}
}
Example #14
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;

    return PutClientRaw(Msg.ToString());
}
Example #15
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 #16
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;
}
Example #17
0
    void OnModCommand(const CString& command)
    {
        VCString tokens;
        int token_count = command.Split(" ", tokens, false);

        if (token_count < 1)
        {
            return;
        }

        CString action = tokens[0].AsLower();

        if (action == "email"){

            if (token_count < 2)
            {
                PutModule("Email: " + NotificationEmail);
                PutModule("Usage: email <email address>");
                return;
            }

            NotificationEmail = tokens[1].AsLower();

            SetNV("email", NotificationEmail);
            PutModule("email address set to : "+ NotificationEmail);

        } else if (action == "subject"){

            if (token_count < 2)
            {
                PutModule("Subject: " + NotificationSubject);
                PutModule("Usage: subject <email subject>");
                return;
            }

            NotificationSubject = tokens[1];
            for (int i = 2; i < token_count; i++) {
                NotificationSubject += " " + tokens[i];
            }
            SetNV("subject", NotificationSubject);
            PutModule("email subject set to : "+ NotificationSubject);

        } else if (action == "interval") {

            if (token_count < 2)
            {
                PutModule("Interval: " + GetNV("interval"));
                PutModule("Usage: interval <seconds>");
                return;
            }

            SetNV("interval", tokens[1]);
            PutModule("interval set to : "+ tokens[1] + " , will be effective after reloading mailer : '/msg *status reloadmod mailer'");
            
        } else if (action == "notifmax") {

            if (token_count < 2)
            {
                PutModule("maxNotifications: " + intToString(MaxNotifications));
                PutModule("Usage: notifmax <number>");
                return;
            }

            MaxNotifications = atoi(tokens[1].c_str());

            SetNV("maxNotifications", tokens[1]);
            PutModule("maxNotifications set to : "+ tokens[1]);
            
        } else if (action == "help") {

                PutModule("Commands :");
                PutModule("  email <email address>");
                PutModule("       set the email to sent notifications to.");
                PutModule("  subject <email subject>");
                PutModule("       set the subject of the notification, default IRC Notification.");
                PutModule("  interval <seconds>");
                PutModule("       set the time between the first message and the mail notification, default 1200 (20 minutes).");
                PutModule("       Reload module required ('/msg *status reloadmod mailer')");
                PutModule("  notifmax <number>");
                PutModule("       set the number of notification in one mail, default 50.");
                PutModule(" ");
                PutModule("View the documentation at http://znc-mailer.readthedocs.org/");

        } else {

            if (!DebugMode){
                PutModule("Error: invalid command, try `help`");
            }

        }

        DebugCommands(command);

    }
Example #18
0
    virtual bool OnLoad(const CString& sArgs, CString& sErrorMsg) {
        /*
         * On module load, check for debug being passed in as an arguement.
         *
         * Then setup the timer for batch emails and prompt the user for their
         * email address.
         */

        VCString tokens;
        int token_count = sArgs.Split(" ", tokens, false);

        if (token_count >= 1){

            CString action = tokens[0].AsLower();

            if (action == "debug"){
                PutModule("DEBUG ON");
                DebugMode = true;
            }

        }

        // Recover config vars.
        NotificationEmail = GetNV("email");
        NotificationSubject = GetNV("subject");
        unsigned int interval = atoi(GetNV("interval").c_str());
        MaxNotifications = atoi(GetNV("maxNotifications").c_str());

        if (DebugMode) {
            PutModule("NV: email: " + NotificationEmail);
            PutModule("NV: subject: " + NotificationSubject);
            PutModule("NV: interval: " + intToString(interval));
            PutModule("NV: maxNotifications: " + intToString(MaxNotifications));
        }

        // Set to default if vars are missing.
        if (interval <= 0) {
            // Default to 20 mins, debug to 60 seconds.
            interval = 1200;
            if (DebugMode){
                interval = 60;
            }
            SetNV("interval", "1200");
        }
        if (MaxNotifications <= 0) {
            // Default to 50.
            MaxNotifications = 50;
            SetNV("maxNotifications", "50");
        }
        

        AddTimer(new CMailerTimer(this, interval, 0, "Mail", "Send emails every "+intToString(interval)+" mins"));

        if (NotificationSubject == "") {
            NotificationSubject = "IRC Notification";
            SetNV("subject", "IRC Notification");
            PutModule("Default subject : 'IRC Notification' (change whith 'subject <subject>')");
        }

        if (NotificationEmail == "") {
            PutModule("Please tell me what email address you want notifications to be sent to with 'email <address>'");
        }

        return true;

    }
Example #19
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;
}