From fa57b9eb54e740a61b054c566322c8bf567e93d9 Mon Sep 17 00:00:00 2001 From: kroimon Date: Sun, 7 Sep 2008 11:50:43 +0000 Subject: [PATCH] Added module 'autocycle' to replace the old core's functionality. Credits to both psychon and kroimon git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@1192 726aef4b-f618-498e-8847-2d620e286838 --- modules/autocycle.cpp | 229 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 modules/autocycle.cpp diff --git a/modules/autocycle.cpp b/modules/autocycle.cpp new file mode 100644 index 00000000..c84c16a8 --- /dev/null +++ b/modules/autocycle.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2004-2008 See the AUTHORS file for details. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include "Chan.h" +#include "User.h" + +class CAutoCycleMod : public CModule { +public: + MODCONSTRUCTOR(CAutoCycleMod) {} + virtual ~CAutoCycleMod() {} + + virtual bool OnLoad(const CString& sArgs, CString& sMessage) { + unsigned int a = 0; + CString sChan = sArgs.Token(a++); + + while (!sChan.empty()) { + if (!Add(sChan)) { + PutModule("Unable to add [" + sChan + "]"); + } + + sChan = sArgs.Token(a++); + } + + // 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; + } + + virtual void OnModCommand(const CString& sLine) { + CString sCommand = sLine.Token(0); + + if (sCommand.CaseCmp("ADD") == 0) { + CString sChan = sLine.Token(1); + + if (AlreadyAdded(sChan)) { + PutModule(sChan + " is already added"); + } else if (Add(sChan)) { + PutModule("Added " + sChan + " to list"); + } else { + PutModule("Usage: Add [!]<#chan>"); + } + } else if (sCommand.CaseCmp("DEL") == 0) { + CString sChan = sLine.Token(1); + + if (Del(sChan)) + PutModule("Removed " + sChan + " from list"); + else + PutModule("Usage: Del [!]<#chan>"); + } else if (sCommand.CaseCmp("LIST") == 0) { + CTable Table; + Table.AddColumn("Chan"); + + for (unsigned int a = 0; a < m_vsChans.size(); a++) { + Table.AddRow(); + Table.SetCell("Chan", m_vsChans[a]); + } + + for (unsigned int b = 0; b < m_vsNegChans.size(); b++) { + Table.AddRow(); + Table.SetCell("Chan", "!" + m_vsNegChans[b]); + } + + if (Table.size()) { + PutModule(Table); + } else { + PutModule("You have no entries."); + } + } else if (sCommand.CaseCmp("HELP") == 0) { + CTable Table; + Table.AddColumn("Command"); + Table.AddColumn("Description"); + + Table.AddRow(); + Table.SetCell("Command", "Add"); + Table.SetCell("Description", "Add an entry, use !#chan to negate and * for wildcards"); + + Table.AddRow(); + Table.SetCell("Command", "Del"); + Table.SetCell("Description", "Remove an entry, needs to be an exact match"); + + Table.AddRow(); + Table.SetCell("Command", "List"); + Table.SetCell("Description", "List all entries"); + + if (Table.size()) { + PutModule(Table); + } else { + PutModule("You have no entries."); + } + } + } + + virtual void OnPart(const CNick& Nick, CChan& Channel) { + AutoCycle(Channel); + } + + virtual void OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) { + for (unsigned int i = 0; i < vChans.size(); i++) + AutoCycle(*vChans[i]); + } + + virtual void OnKick(const CNick& Nick, const CString& sOpNick, CChan& Channel, const CString& sMessage) { + AutoCycle(Channel); + } + +protected: + void AutoCycle(CChan& Channel) { + if (!IsAutoCycle(Channel.GetName())) + return; + + // Is there only one person left in the channel? + if (Channel.GetNickCount() != 1) + return; + + // Is that person us and we don't have op? + const CNick* pNick = Channel.GetNicks().begin()->second; + if (!pNick->HasPerm(CChan::Op) && pNick->GetNick().CaseCmp(m_pUser->GetCurNick()) == 0) + Channel.Cycle(); + } + + bool AlreadyAdded(const CString& sInput) { + vector::iterator it; + + if (sInput.Left(1) == "!") { + CString sChan = sInput.substr(1); + for (it = m_vsNegChans.begin(); it != m_vsNegChans.end(); + it++) { + if (*it == sChan) + return true; + } + } else { + for (it = m_vsChans.begin(); it != m_vsChans.end(); it++) { + if (*it == sInput) + return true; + } + } + return false; + } + + bool Add(const CString& sChan) { + if (sChan.empty() || sChan == "!") { + return false; + } + + if (sChan.Left(1) == "!") { + m_vsNegChans.push_back(sChan.substr(1)); + } else { + m_vsChans.push_back(sChan); + } + + // Also save it for next module load + SetNV(sChan, ""); + + return true; + } + + bool Del(const CString& sChan) { + vector::iterator it, end; + + if (sChan.empty() || sChan == "!") + return false; + + if (sChan.Left(1) == "!") { + CString sTmp = sChan.substr(1); + it = m_vsNegChans.begin(); + end = m_vsNegChans.end(); + + for (; it != end; ++it) + if (*it == sTmp) + break; + + if (it == end) + return false; + + m_vsNegChans.erase(it); + } else { + it = m_vsChans.begin(); + end = m_vsChans.end(); + + for (; it != end; ++it) + if (*it == sChan) + break; + + if (it == end) + return false; + + m_vsChans.erase(it); + } + + DelNV(sChan); + + return true; + } + + bool IsAutoCycle(const CString& sChan) { + for (unsigned int a = 0; a < m_vsNegChans.size(); a++) { + if (sChan.WildCmp(m_vsNegChans[a])) { + return false; + } + } + + for (unsigned int b = 0; b < m_vsChans.size(); b++) { + if (sChan.WildCmp(m_vsChans[b])) { + return true; + } + } + + return false; + } + +private: + vector m_vsChans; + vector m_vsNegChans; +}; + +MODULEDEFS(CAutoCycleMod, "Rejoins channels to gain Op if you're the only user left")