]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/modules/m_banredirect.cpp
Fix the cloaking module on C++98 compilers.
[user/henk/code/inspircd.git] / src / modules / m_banredirect.cpp
index 332e625e0c50dd3e4a6a5cd27e5f550f05d9b05c..579bf9d32ae9df4d889cacb05941f656823ebee1 100644 (file)
@@ -1,12 +1,19 @@
 /*
  * InspIRCd -- Internet Relay Chat Daemon
  *
- *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
- *   Copyright (C) 2007, 2009 Robin Burchell <robin+git@viroteck.net>
- *   Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
+ *   Copyright (C) 2018 linuxdaemon <linuxdaemon.irc@gmail.com>
+ *   Copyright (C) 2014 Adam <Adam@anope.org>
+ *   Copyright (C) 2013-2016 Attila Molnar <attilamolnar@hush.com>
+ *   Copyright (C) 2013, 2017-2018 Sadie Powell <sadie@witchery.services>
+ *   Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org>
+ *   Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
+ *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ *   Copyright (C) 2009 Matt Smith <dz@inspircd.org>
+ *   Copyright (C) 2008, 2010 Craig Edwards <brain@inspircd.org>
+ *   Copyright (C) 2008 Uli Schlachter <psychon@inspircd.org>
+ *   Copyright (C) 2007-2009 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2007 Oliver Lupton <om@inspircd.org>
  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
- *   Copyright (C) 2007 Craig Edwards <craigedwards@brainbox.cc>
- *   Copyright (C) 2007 Oliver Lupton <oliverlupton@gmail.com>
  *
  * This file is part of InspIRCd.  InspIRCd is free software: you can
  * redistribute it and/or modify it under the terms of the GNU General Public
@@ -25,8 +32,6 @@
 #include "inspircd.h"
 #include "listmode.h"
 
-/* $ModDesc: Allows an extended ban (+b) syntax redirecting banned users to another channel */
-
 /* Originally written by Om, January 2009
  */
 
@@ -46,17 +51,17 @@ typedef std::vector<BanRedirectEntry> BanRedirectList;
 
 class BanRedirect : public ModeWatcher
 {
-       ModeReference ban;
+       ChanModeReference ban;
  public:
        SimpleExtItem<BanRedirectList> extItem;
        BanRedirect(Module* parent)
-               : ModeWatcher(parent, 'b', MODETYPE_CHANNEL)
+               : ModeWatcher(parent, "ban", MODETYPE_CHANNEL)
                , ban(parent, "ban")
-               , extItem("banredirect", parent)
+               , extItem("banredirect", ExtensionItem::EXT_CHANNEL, parent)
        {
        }
 
-       bool BeforeMode(User* source, User* dest, Channel* channel, std::string &param, bool adding, ModeType type)
+       bool BeforeMode(User* source, User* dest, Channel* channel, std::string& param, bool adding) CXX11_OVERRIDE
        {
                /* nick!ident@host -> nick!ident@host
                 * nick!ident@host#chan -> nick!ident@host#chan
@@ -65,7 +70,7 @@ class BanRedirect : public ModeWatcher
                 * nick#chan -> nick!*@*#chan
                 */
 
-               if(channel && (type == MODETYPE_CHANNEL) && param.length())
+               if ((channel) && !param.empty())
                {
                        BanRedirectList* redirects;
 
@@ -76,12 +81,15 @@ class BanRedirect : public ModeWatcher
                        if (param.length() >= 2 && param[1] == ':')
                                return true;
 
+                       if (param.find('#') == std::string::npos)
+                               return true;
+
                        ListModeBase* banlm = static_cast<ListModeBase*>(*ban);
                        unsigned int maxbans = banlm->GetLimit(channel);
                        ListModeBase::ModeList* list = banlm->GetList(channel);
                        if ((list) && (adding) && (maxbans <= list->size()))
                        {
-                               source->WriteNumeric(478, "%s %s :Channel ban list for %s is full (maximum entries for this channel is %u)", source->nick.c_str(), channel->name.c_str(), channel->name.c_str(), maxbans);
+                               source->WriteNumeric(ERR_BANLISTFULL, channel->name, banlm->GetModeChar(), InspIRCd::Format("Channel ban list for %s is full (maximum entries for this channel is %u)", channel->name.c_str(), maxbans));
                                return false;
                        }
 
@@ -90,23 +98,25 @@ class BanRedirect : public ModeWatcher
                                switch(*curr)
                                {
                                        case '!':
+                                               if (current != NICK)
+                                                       break;
                                                mask[current].assign(start_pos, curr);
                                                current = IDENT;
                                                start_pos = curr+1;
                                                break;
                                        case '@':
+                                               if (current != IDENT)
+                                                       break;
                                                mask[current].assign(start_pos, curr);
                                                current = HOST;
                                                start_pos = curr+1;
                                                break;
                                        case '#':
-                                               /* bug #921: don't barf when redirecting to ## channels */
-                                               if (current != CHAN)
-                                               {
-                                                       mask[current].assign(start_pos, curr);
-                                                       current = CHAN;
-                                                       start_pos = curr;
-                                               }
+                                               if (current == CHAN)
+                                                       break;
+                                               mask[current].assign(start_pos, curr);
+                                               current = CHAN;
+                                               start_pos = curr;
                                                break;
                                }
                        }
@@ -123,6 +133,14 @@ class BanRedirect : public ModeWatcher
                                mask[NICK].swap(mask[IDENT]);
                        }
 
+                       if (!mask[NICK].empty() && mask[IDENT].empty() && mask[HOST].empty())
+                       {
+                               if (mask[NICK].find('.') != std::string::npos || mask[NICK].find(':') != std::string::npos)
+                               {
+                                       mask[NICK].swap(mask[HOST]);
+                               }
+                       }
+
                        for(int i = 0; i < 3; i++)
                        {
                                if(mask[i].empty())
@@ -139,25 +157,25 @@ class BanRedirect : public ModeWatcher
                                {
                                        if (!ServerInstance->IsChannel(mask[CHAN]))
                                        {
-                                               source->WriteNumeric(403, "%s %s :Invalid channel name in redirection (%s)", source->nick.c_str(), channel->name.c_str(), mask[CHAN].c_str());
+                                               source->WriteNumeric(ERR_NOSUCHCHANNEL, channel->name, InspIRCd::Format("Invalid channel name in redirection (%s)", mask[CHAN].c_str()));
                                                return false;
                                        }
 
                                        Channel *c = ServerInstance->FindChan(mask[CHAN]);
                                        if (!c)
                                        {
-                                               source->WriteNumeric(690, "%s :Target channel %s must exist to be set as a redirect.",source->nick.c_str(),mask[CHAN].c_str());
+                                               source->WriteNumeric(690, InspIRCd::Format("Target channel %s must exist to be set as a redirect.", mask[CHAN].c_str()));
                                                return false;
                                        }
                                        else if (adding && c->GetPrefixValue(source) < OP_VALUE)
                                        {
-                                               source->WriteNumeric(690, "%s :You must be opped on %s to set it as a redirect.",source->nick.c_str(), mask[CHAN].c_str());
+                                               source->WriteNumeric(690, InspIRCd::Format("You must be opped on %s to set it as a redirect.", mask[CHAN].c_str()));
                                                return false;
                                        }
 
-                                       if (assign(channel->name) == mask[CHAN])
+                                       if (irc::equals(channel->name, mask[CHAN]))
                                        {
-                                               source->WriteNumeric(690, "%s %s :You cannot set a ban redirection to the channel the ban is on", source->nick.c_str(), channel->name.c_str());
+                                               source->WriteNumeric(690, channel->name, "You cannot set a ban redirection to the channel the ban is on");
                                                return false;
                                        }
                                }
@@ -171,6 +189,21 @@ class BanRedirect : public ModeWatcher
                                                redirects = new BanRedirectList;
                                                extItem.set(channel, redirects);
                                        }
+                                       else
+                                       {
+                                               for (BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); ++redir)
+                                               {
+                                                       // Mimic the functionality used when removing the mode
+                                                       if (irc::equals(redir->targetchan, mask[CHAN]) && irc::equals(redir->banmask, param))
+                                                       {
+                                                               // Make sure the +b handler will still set the right ban
+                                                               param.append(mask[CHAN]);
+                                                               // Silently ignore the duplicate and don't set metadata
+                                                               // This still allows channel ops to set/unset a redirect ban to clear "ghost" redirects
+                                                               return true;
+                                                       }
+                                               }
+                                       }
 
                                        /* Here 'param' doesn't have the channel on it yet */
                                        redirects->push_back(BanRedirectEntry(mask[CHAN], param));
@@ -188,8 +221,7 @@ class BanRedirect : public ModeWatcher
 
                                                for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)
                                                {
-                                                       /* Ugly as fuck */
-                                                       if((irc::string(redir->targetchan.c_str()) == irc::string(mask[CHAN].c_str())) && (irc::string(redir->banmask.c_str()) == irc::string(param.c_str())))
+                                                       if ((irc::equals(redir->targetchan, mask[CHAN])) && (irc::equals(redir->banmask, param)))
                                                        {
                                                                redirects->erase(redir);
 
@@ -217,56 +249,37 @@ class ModuleBanRedirect : public Module
 {
        BanRedirect re;
        bool nofollow;
+       ChanModeReference limitmode;
+       ChanModeReference redirectmode;
 
  public:
        ModuleBanRedirect()
-       : re(this)
-       {
-               nofollow = false;
-       }
-
-
-       void init() CXX11_OVERRIDE
+               : re(this)
+               , nofollow(false)
+               , limitmode(this, "limit")
+               , redirectmode(this, "redirect")
        {
-               if(!ServerInstance->Modes->AddModeWatcher(&re))
-                       throw ModuleException("Could not add mode watcher");
-
-               ServerInstance->Modules->AddService(re.extItem);
-               Implementation list[] = { I_OnUserPreJoin };
-               ServerInstance->Modules->Attach(list, this, sizeof(list)/sizeof(Implementation));
        }
 
-       void OnCleanup(int target_type, void* item) CXX11_OVERRIDE
+       void OnCleanup(ExtensionItem::ExtensibleType type, Extensible* item) CXX11_OVERRIDE
        {
-               if(target_type == TYPE_CHANNEL)
+               if (type == ExtensionItem::EXT_CHANNEL)
                {
                        Channel* chan = static_cast<Channel*>(item);
                        BanRedirectList* redirects = re.extItem.get(chan);
 
                        if(redirects)
                        {
-                               irc::modestacker modestack(false);
-                               std::vector<std::string> stackresult;
-                               std::vector<std::string> mode_junk;
-                               mode_junk.push_back(chan->name);
+                               ModeHandler* ban = ServerInstance->Modes->FindMode('b', MODETYPE_CHANNEL);
+                               Modes::ChangeList changelist;
 
                                for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)
-                               {
-                                       modestack.Push('b', i->targetchan.insert(0, i->banmask));
-                               }
+                                       changelist.push_remove(ban, i->targetchan.insert(0, i->banmask));
 
                                for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)
-                               {
-                                       modestack.PushPlus();
-                                       modestack.Push('b', i->banmask);
-                               }
+                                       changelist.push_add(ban, i->banmask);
 
-                               while(modestack.GetStackedLine(stackresult))
-                               {
-                                       mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end());
-                                       ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient);
-                                       mode_junk.erase(mode_junk.begin() + 1, mode_junk.end());
-                               }
+                               ServerInstance->Modes->Process(ServerInstance->FakeClient, chan, NULL, changelist, ModeParser::MODE_LOCALONLY);
                        }
                }
        }
@@ -315,17 +328,17 @@ class ModuleBanRedirect : public Module
                                                std::string destlimit;
 
                                                if (destchan)
-                                                       destlimit = destchan->GetModeParameter('l');
+                                                       destlimit = destchan->GetModeParameter(limitmode);
 
-                                               if(destchan && ServerInstance->Modules->Find("m_redirect.so") && destchan->IsModeSet('L') && !destlimit.empty() && (destchan->GetUserCounter() >= atoi(destlimit.c_str())))
+                                               if(destchan && destchan->IsModeSet(redirectmode) && !destlimit.empty() && (destchan->GetUserCounter() >= ConvToNum<size_t>(destlimit)))
                                                {
-                                                       user->WriteNumeric(474, "%s %s :Cannot join channel (You are banned)", user->nick.c_str(), chan->name.c_str());
+                                                       user->WriteNumeric(ERR_BANNEDFROMCHAN, chan->name, "Cannot join channel (you're banned)");
                                                        return MOD_RES_DENY;
                                                }
                                                else
                                                {
-                                                       user->WriteNumeric(474, "%s %s :Cannot join channel (You are banned)", user->nick.c_str(), chan->name.c_str());
-                                                       user->WriteNumeric(470, "%s %s %s :You are banned from this channel, so you are automatically transfered to the redirected channel.", user->nick.c_str(), chan->name.c_str(), redir->targetchan.c_str());
+                                                       user->WriteNumeric(ERR_BANNEDFROMCHAN, chan->name, "Cannot join channel (you're banned)");
+                                                       user->WriteNumeric(470, chan->name, redir->targetchan, "You are banned from this channel, so you are automatically being transferred to the redirected channel.");
                                                        nofollow = true;
                                                        Channel::JoinUser(user, redir->targetchan);
                                                        nofollow = false;
@@ -338,16 +351,9 @@ class ModuleBanRedirect : public Module
                return MOD_RES_PASSTHRU;
        }
 
-       ~ModuleBanRedirect()
-       {
-               /* XXX is this the best place to do this? */
-               if (!ServerInstance->Modes->DelModeWatcher(&re))
-                       ServerInstance->Logs->Log("m_banredirect.so", LOG_DEBUG, "Failed to delete modewatcher!");
-       }
-
        Version GetVersion() CXX11_OVERRIDE
        {
-               return Version("Allows an extended ban (+b) syntax redirecting banned users to another channel", VF_COMMON|VF_VENDOR);
+               return Version("Allows specifying a channel to redirect a banned user to in the ban mask.", VF_COMMON|VF_VENDOR);
        }
 };