From 6deae62c5bc65be734d6ef972aba2354fc9a40c7 Mon Sep 17 00:00:00 2001 From: Uli Schlachter Date: Sun, 15 May 2011 13:15:51 +0200 Subject: [PATCH] autoattach: Allow limiting by hostmask This adds hostmasks to autoattach. E.g. if you don't like me, you add an entry of "! * psychon!*" and autoattach won't attach you to channels just because I said something. The same can be done in the non-negated case, "only attach when foo says something". Signed-off-by: Uli Schlachter --- modules/autoattach.cpp | 249 ++++++++++++++++++++++++----------------- 1 file changed, 146 insertions(+), 103 deletions(-) diff --git a/modules/autoattach.cpp b/modules/autoattach.cpp index e6d43514..bd54863b 100644 --- a/modules/autoattach.cpp +++ b/modules/autoattach.cpp @@ -9,41 +9,108 @@ #include "Chan.h" #include "Modules.h" -class CChanAttach : public CModule { - void HandleAdd(const CString& sLine) { - CString sChan = sLine.Token(1); +class CAttachMatch { +public: + CAttachMatch(const CString& sChannels, const CString& sHostmasks, bool bNegated) + { + m_sChannelWildcard = sChannels; + m_sHostmaskWildcard = sHostmasks; + m_bNegated = bNegated; - if (AlreadyAdded(sChan)) { - PutModule(sChan + " is already added"); - } else if (Add(sChan)) { - PutModule("Added " + sChan + " to list"); + if (m_sChannelWildcard.empty()) + m_sChannelWildcard = "*"; + if (m_sHostmaskWildcard.empty()) + m_sHostmaskWildcard = "*!*@*"; + } + + bool IsMatch(const CString& sChan, const CString& sHost) const { + if (!sHost.WildCmp(m_sHostmaskWildcard)) + return false; + if (!sChan.WildCmp(m_sChannelWildcard)) + return false; + return true; + } + + bool IsNegated() const { + return m_bNegated; + } + + const CString& GetHostMask() const { + return m_sHostmaskWildcard; + } + + const CString& GetChans() const { + return m_sChannelWildcard; + } + + CString ToString() { + CString sRes; + if (m_bNegated) + sRes += "!"; + sRes += m_sChannelWildcard; + sRes += " "; + sRes += m_sHostmaskWildcard; + return sRes; + } + +private: + bool m_bNegated; + CString m_sChannelWildcard; + CString m_sHostmaskWildcard; +}; + +class CChanAttach : public CModule { +public: + typedef vector VAttachMatch; + typedef VAttachMatch::iterator VAttachIter; + +private: + void HandleAdd(const CString& sLine) { + CString sMsg = sLine.Token(1, true); + bool bHelp = false; + bool bNegated = sMsg.TrimPrefix("!"); + CString sChan = sMsg.Token(0); + CString sHost = sMsg.Token(1, true); + + if (sChan.empty()) { + bHelp = true; + } else if (Add(bNegated, sChan, sHost)) { + PutModule("Added to list"); } else { - PutModule("Usage: Add [!]<#chan>"); + PutModule(sLine.Token(1, true) + " is already added"); + bHelp = true; + } + if (bHelp) { + PutModule("Usage: Add [!]<#chan> "); + PutModule("Wildcards are allowed"); } } void HandleDel(const CString& sLine) { - CString sChan = sLine.Token(1); + CString sMsg = sLine.Token(1, true); + bool bNegated = sMsg.TrimPrefix("!"); + CString sChan = sMsg.Token(0); + CString sHost = sMsg.Token(1, true); - if (Del(sChan)) { + if (Del(bNegated, sChan, sHost)) { PutModule("Removed " + sChan + " from list"); } else { - PutModule("Usage: Del [!]<#chan>"); + PutModule("Usage: Del [!]<#chan> "); } } void HandleList(const CString& sLine) { CTable Table; + Table.AddColumn("Neg"); Table.AddColumn("Chan"); + Table.AddColumn("Host"); - for (unsigned int a = 0; a < m_vsChans.size(); a++) { + VAttachIter it = m_vMatches.begin(); + for (; it != m_vMatches.end(); ++it) { 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]); + Table.SetCell("Neg", it->IsNegated() ? "!" : ""); + Table.SetCell("Chan", it->GetChans()); + Table.SetCell("Host", it->GetHostMask()); } if (Table.size()) { @@ -57,9 +124,9 @@ public: MODCONSTRUCTOR(CChanAttach) { AddHelpCommand(); AddCommand("Add", static_cast(&CChanAttach::HandleAdd), - "[!]<#chan>", "Add an entry, use !#chan to negate and * for wildcards"); + "[!]<#chan> ", "Add an entry, use !#chan to negate and * for wildcards"); AddCommand("Del", static_cast(&CChanAttach::HandleDel), - "[!]<#chan>", "Remove an entry, needs to be an exact match"); + "[!]<#chan> ", "Remove an entry, needs to be an exact match"); AddCommand("List", static_cast(&CChanAttach::HandleList), "", "List all entries"); } @@ -72,7 +139,12 @@ public: sArgs.Split(" ", vsChans, false); for (VCString::const_iterator it = vsChans.begin(); it != vsChans.end(); ++it) { - if (!Add(*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 + "]"); } } @@ -80,127 +152,98 @@ public: // Load our saved settings, ignore errors MCString::iterator it; for (it = BeginNV(); it != EndNV(); ++it) { - Add(it->first); + 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; } - void TryAttach(CChan& Channel) { + void TryAttach(const CNick& Nick, CChan& Channel) { const CString& sChan = Channel.GetName(); + const CString& sHost = Nick.GetHostMask(); + VAttachIter it; - if (Channel.IsDetached() && IsAutoAttach(sChan)) { - Channel.JoinUser(); + if (!Channel.IsDetached()) + return; + + // Any negated match? + for (it = m_vMatches.begin(); it != m_vMatches.end(); ++it) { + if (it->IsNegated() && it->IsMatch(sChan, sHost)) + return; + } + + // Now check for a positive match + for (it = m_vMatches.begin(); it != m_vMatches.end(); ++it) { + if (!it->IsNegated() && it->IsMatch(sChan, sHost)) { + Channel.JoinUser(); + return; + } } } virtual EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { - TryAttach(Channel); + TryAttach(Nick, Channel); return CONTINUE; } virtual EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { - TryAttach(Channel); + TryAttach(Nick, Channel); return CONTINUE; } virtual EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { - TryAttach(Channel); + TryAttach(Nick, Channel); return CONTINUE; } - 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; - } + VAttachIter FindEntry(const CString& sChan, const CString& sHost) { + VAttachIter it = m_vMatches.begin(); + for (; it != m_vMatches.end(); ++it) { + if (sHost.empty() || it->GetHostMask() != sHost) + continue; + if (sChan.empty() || it->GetChans() != sChan) + continue; + return it; } - return false; + return m_vMatches.end(); } - bool Add(const CString& sChan) { - if (sChan.empty() || sChan == "!") { - return false; + bool Add(bool bNegated, const CString& sChan, const CString& sHost) { + CAttachMatch attach(sChan, sHost, bNegated); + + // Check for duplicates + VAttachIter it = m_vMatches.begin(); + for (; it != m_vMatches.end(); ++it) { + if (it->GetHostMask() == attach.GetHostMask() + && it->GetChans() == attach.GetChans()) + return false; } - if (sChan.Left(1) == "!") { - m_vsNegChans.push_back(sChan.substr(1)); - } else { - m_vsChans.push_back(sChan); - } + m_vMatches.push_back(attach); // Also save it for next module load - SetNV(sChan, ""); + SetNV(attach.ToString(), ""); return true; } - bool Del(const CString& sChan) { - vector::iterator it, end; - - if (sChan.empty() || sChan == "!") + bool Del(bool bNegated, const CString& sChan, const CString& sHost) { + VAttachIter it = FindEntry(sChan, sHost); + if (it == m_vMatches.end() || it->IsNegated() != bNegated) 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); + DelNV(it->ToString()); + m_vMatches.erase(it); return true; } - - bool IsAutoAttach(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; + VAttachMatch m_vMatches; }; MODULEDEFS(CChanAttach, "Reattaches you to channels on activity.")