]> jfr.im git - irc/rizon/znc.git/commitdiff
autoattach: Allow limiting by hostmask
authorUli Schlachter <redacted>
Sun, 15 May 2011 11:15:51 +0000 (13:15 +0200)
committerUli Schlachter <redacted>
Sun, 15 May 2011 11:15:51 +0000 (13:15 +0200)
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 <redacted>
modules/autoattach.cpp

index e6d4351425fc762620390ced36d008906ea49e0a..bd54863b1ad4e938827684bc03128beba58be843 100644 (file)
 #include "Chan.h"
 #include "Modules.h"
 
+class CAttachMatch {
+public:
+       CAttachMatch(const CString& sChannels, const CString& sHostmasks, bool bNegated)
+       {
+               m_sChannelWildcard = sChannels;
+               m_sHostmaskWildcard = sHostmasks;
+               m_bNegated = bNegated;
+
+               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 {
-       void HandleAdd(const CString& sLine) {
-               CString sChan = sLine.Token(1);
+public:
+       typedef vector<CAttachMatch> VAttachMatch;
+       typedef VAttachMatch::iterator VAttachIter;
 
-               if (AlreadyAdded(sChan)) {
-                       PutModule(sChan + " is already added");
-               } else if (Add(sChan)) {
-                       PutModule("Added " + sChan + " to list");
+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> <host>");
+                       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> <host>");
                }
        }
 
        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<CModCommand::ModCmdFunc>(&CChanAttach::HandleAdd),
-                       "[!]<#chan>", "Add an entry, use !#chan to negate and * for wildcards");
+                       "[!]<#chan> <host>", "Add an entry, use !#chan to negate and * for wildcards");
                AddCommand("Del",    static_cast<CModCommand::ModCmdFunc>(&CChanAttach::HandleDel),
-                       "[!]<#chan>", "Remove an entry, needs to be an exact match");
+                       "[!]<#chan> <host>", "Remove an entry, needs to be an exact match");
                AddCommand("List",    static_cast<CModCommand::ModCmdFunc>(&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())
+                       return;
 
-               if (Channel.IsDetached() && IsAutoAttach(sChan)) {
-                       Channel.JoinUser();
+               // 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<CString>::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);
 
-               if (sChan.Left(1) == "!") {
-                       m_vsNegChans.push_back(sChan.substr(1));
-               } else {
-                       m_vsChans.push_back(sChan);
+               // 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;
                }
 
+               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<CString>::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<CString> m_vsChans;
-       vector<CString> m_vsNegChans;
+       VAttachMatch m_vMatches;
 };
 
 MODULEDEFS(CChanAttach, "Reattaches you to channels on activity.")