diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/channels.cpp | 53 | ||||
-rw-r--r-- | src/configreader.cpp | 14 | ||||
-rw-r--r-- | src/inspircd.cpp | 6 | ||||
-rw-r--r-- | src/listmode.cpp | 262 | ||||
-rw-r--r-- | src/mode.cpp | 1 | ||||
-rw-r--r-- | src/modes/cmode_b.cpp | 177 | ||||
-rw-r--r-- | src/modules/m_autoop.cpp | 6 | ||||
-rw-r--r-- | src/modules/m_banexception.cpp | 12 | ||||
-rw-r--r-- | src/modules/m_banredirect.cpp | 17 | ||||
-rw-r--r-- | src/modules/m_chanfilter.cpp | 9 | ||||
-rw-r--r-- | src/modules/m_check.cpp | 23 | ||||
-rw-r--r-- | src/modules/m_exemptchanops.cpp | 9 | ||||
-rw-r--r-- | src/modules/m_inviteexception.cpp | 8 | ||||
-rw-r--r-- | src/modules/m_spanningtree/netburst.cpp | 29 | ||||
-rw-r--r-- | src/modules/m_timedbans.cpp | 17 | ||||
-rw-r--r-- | src/modules/u_listmode.h | 415 |
16 files changed, 337 insertions, 721 deletions
diff --git a/src/channels.cpp b/src/channels.cpp index 6bd021d61..0bbb5c56f 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -26,9 +26,12 @@ /* $Core */ #include "inspircd.h" +#include "listmode.h" #include <cstdarg> #include "mode.h" +static ModeReference ban(NULL, "ban"); + Channel::Channel(const std::string &cname, time_t ts) { chan_hash::iterator findchan = ServerInstance->chanlist->find(cname); @@ -39,7 +42,7 @@ Channel::Channel(const std::string &cname, time_t ts) this->name.assign(cname, 0, ServerInstance->Config->Limits.ChanMax); this->age = ts ? ts : ServerInstance->Time(); - maxbans = topicset = 0; + topicset = 0; modes.reset(); } @@ -434,10 +437,15 @@ bool Channel::IsBanned(User* user) if (result != MOD_RES_PASSTHRU) return (result == MOD_RES_DENY); - for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++) + ListModeBase* banlm = static_cast<ListModeBase*>(*ban); + const ListModeBase::ModeList* bans = banlm->GetList(this); + if (bans) { - if (CheckBan(user, i->data)) - return true; + for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); it++) + { + if (CheckBan(user, it->mask)) + return true; + } } return false; } @@ -477,12 +485,15 @@ ModResult Channel::GetExtBanStatus(User *user, char type) FIRST_MOD_RESULT(OnExtBanCheck, rv, (user, this, type)); if (rv != MOD_RES_PASSTHRU) return rv; - for (BanList::iterator i = this->bans.begin(); i != this->bans.end(); i++) + + ListModeBase* banlm = static_cast<ListModeBase*>(*ban); + const ListModeBase::ModeList* bans = banlm->GetList(this); + if (bans) + { - if (i->data[0] == type && i->data[1] == ':') + for (ListModeBase::ModeList::const_iterator it = bans->begin(); it != bans->end(); ++it) { - std::string val = i->data.substr(2); - if (CheckBan(user, val)) + if (CheckBan(user, it->mask)) return MOD_RES_DENY; } } @@ -845,32 +856,6 @@ void Channel::UserList(User *user) user->WriteNumeric(RPL_ENDOFNAMES, "%s %s :End of /NAMES list.", user->nick.c_str(), this->name.c_str()); } -long Channel::GetMaxBans() -{ - /* Return the cached value if there is one */ - if (this->maxbans) - return this->maxbans; - - /* If there isnt one, we have to do some O(n) hax to find it the first time. (ick) */ - for (std::map<std::string,int>::iterator n = ServerInstance->Config->maxbans.begin(); n != ServerInstance->Config->maxbans.end(); n++) - { - if (InspIRCd::Match(this->name, n->first, NULL)) - { - this->maxbans = n->second; - return n->second; - } - } - - /* Screw it, just return the default of 64 */ - this->maxbans = 64; - return this->maxbans; -} - -void Channel::ResetMaxBans() -{ - this->maxbans = 0; -} - /* returns the status character for a given user on a channel, e.g. @ for op, * % for halfop etc. If the user has several modes set, the highest mode * the user has must be returned. diff --git a/src/configreader.cpp b/src/configreader.cpp index f440fca26..804463309 100644 --- a/src/configreader.cpp +++ b/src/configreader.cpp @@ -25,6 +25,7 @@ #include "inspircd.h" #include <fstream> #include "xline.h" +#include "listmode.h" #include "exitcodes.h" #include "configparser.h" #include <iostream> @@ -568,16 +569,6 @@ void ServerConfig::Fill() ulines[assign(server)] = tag->getBool("silent"); } - tags = ConfTags("banlist"); - for(ConfigIter i = tags.first; i != tags.second; ++i) - { - ConfigTag* tag = i->second; - std::string chan; - if (!tag->readString("chan", chan)) - throw CoreException("<banlist> tag missing chan at " + tag->getTagLocation()); - maxbans[chan] = tag->getInt("limit"); - } - ReadXLine(this, "badip", "ipmask", ServerInstance->XLines->GetFactory("Z")); ReadXLine(this, "badnick", "nick", ServerInstance->XLines->GetFactory("Q")); ReadXLine(this, "badhost", "host", ServerInstance->XLines->GetFactory("K")); @@ -936,7 +927,8 @@ void ConfigReaderThread::Finish() ServerInstance->XLines->CheckELines(); ServerInstance->XLines->ApplyLines(); ServerInstance->Res->Rehash(); - ServerInstance->ResetMaxBans(); + ModeReference ban(NULL, "ban"); + static_cast<ListModeBase*>(*ban)->DoRehash(); Config->ApplyDisabledCommands(Config->DisabledCommands); User* user = ServerInstance->FindNick(TheUserUID); FOREACH_MOD(I_OnRehash, OnRehash(user)); diff --git a/src/inspircd.cpp b/src/inspircd.cpp index bac96b2d6..ea30924a8 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -184,12 +184,6 @@ void InspIRCd::Restart(const std::string &reason) } } -void InspIRCd::ResetMaxBans() -{ - for (chan_hash::const_iterator i = chanlist->begin(); i != chanlist->end(); i++) - i->second->ResetMaxBans(); -} - void InspIRCd::SetSignals() { #ifndef _WIN32 diff --git a/src/listmode.cpp b/src/listmode.cpp new file mode 100644 index 000000000..adae627f1 --- /dev/null +++ b/src/listmode.cpp @@ -0,0 +1,262 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> + * + * 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 + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "inspircd.h" +#include "listmode.h" + +ListModeBase::ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string &eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy, const std::string &ctag) + : ModeHandler(Creator, Name, modechar, PARAM_ALWAYS, MODETYPE_CHANNEL), + listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy), + configtag(ctag), extItem("listbase_mode_" + name + "_list", Creator) +{ + list = true; +} + +void ListModeBase::DisplayList(User* user, Channel* channel) +{ + ModeList* el = extItem.get(channel); + if (el) + { + for (ModeList::reverse_iterator it = el->rbegin(); it != el->rend(); ++it) + { + user->WriteNumeric(listnumeric, "%s %s %s %s %s", user->nick.c_str(), channel->name.c_str(), it->mask.c_str(), (it->nick.length() ? it->nick.c_str() : ServerInstance->Config->ServerName.c_str()), it->time.c_str()); + } + } + user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str()); +} + +void ListModeBase::DisplayEmptyList(User* user, Channel* channel) +{ + user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str()); +} + +void ListModeBase::RemoveMode(Channel* channel, irc::modestacker* stack) +{ + ModeList* el = extItem.get(channel); + if (el) + { + irc::modestacker modestack(false); + + for (ModeList::iterator it = el->begin(); it != el->end(); it++) + { + if (stack) + stack->Push(this->GetModeChar(), it->mask); + else + modestack.Push(this->GetModeChar(), it->mask); + } + + if (stack) + return; + + std::vector<std::string> stackresult; + stackresult.push_back(channel->name); + while (modestack.GetStackedLine(stackresult)) + { + ServerInstance->SendMode(stackresult, ServerInstance->FakeClient); + stackresult.clear(); + stackresult.push_back(channel->name); + } + } +} + +void ListModeBase::RemoveMode(User*, irc::modestacker* stack) +{ + /* Listmodes dont get set on users */ +} + +void ListModeBase::DoRehash() +{ + ConfigTagList tags = ServerInstance->Config->ConfTags(configtag); + + chanlimits.clear(); + + for (ConfigIter i = tags.first; i != tags.second; i++) + { + // For each <banlist> tag + ConfigTag* c = i->second; + ListLimit limit; + limit.mask = c->getString("chan"); + limit.limit = c->getInt("limit"); + + if (limit.mask.size() && limit.limit > 0) + chanlimits.push_back(limit); + } + if (chanlimits.size() == 0) + { + ListLimit limit; + limit.mask = "*"; + limit.limit = 64; + chanlimits.push_back(limit); + } +} + +void ListModeBase::DoImplements(Module* m) +{ + ServerInstance->Modules->AddService(extItem); + this->DoRehash(); + Implementation eventlist[] = { I_OnSyncChannel, I_OnRehash }; + ServerInstance->Modules->Attach(eventlist, m, sizeof(eventlist)/sizeof(Implementation)); +} + +unsigned int ListModeBase::GetLimit(Channel* channel) +{ + for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); ++it) + { + if (InspIRCd::Match(channel->name, it->mask)) + { + // We have a pattern matching the channel + return it->limit; + } + } + return 64; +} + +ModeAction ListModeBase::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) +{ + // Try and grab the list + ModeList* el = extItem.get(channel); + + if (adding) + { + if (tidy) + ModeParser::CleanMask(parameter); + + if (parameter.length() > 250) + return MODEACTION_DENY; + + // If there was no list + if (!el) + { + // Make one + el = new ModeList; + extItem.set(channel, el); + } + + // Check if the item already exists in the list + for (ModeList::iterator it = el->begin(); it != el->end(); it++) + { + if (parameter == it->mask) + { + /* Give a subclass a chance to error about this */ + TellAlreadyOnList(source, channel, parameter); + + // it does, deny the change + return MODEACTION_DENY; + } + } + + if ((IS_LOCAL(source)) && (el->size() >= GetLimit(channel))) + { + /* List is full, give subclass a chance to send a custom message */ + TellListTooLong(source, channel, parameter); + parameter.clear(); + return MODEACTION_DENY; + } + + /* Ok, it *could* be allowed, now give someone subclassing us + * a chance to validate the parameter. + * The param is passed by reference, so they can both modify it + * and tell us if we allow it or not. + * + * eg, the subclass could: + * 1) allow + * 2) 'fix' parameter and then allow + * 3) deny + */ + if (ValidateParam(source, channel, parameter)) + { + // And now add the mask onto the list... + ListItem e; + e.mask = parameter; + e.nick = source->nick; + e.time = ConvToStr(ServerInstance->Time()); + + el->push_back(e); + return MODEACTION_ALLOW; + } + else + { + /* If they deny it they have the job of giving an error message */ + return MODEACTION_DENY; + } + } + else + { + // We're taking the mode off + if (el) + { + for (ModeList::iterator it = el->begin(); it != el->end(); it++) + { + if (parameter == it->mask) + { + el->erase(it); + if (el->size() == 0) + { + extItem.unset(channel); + } + return MODEACTION_ALLOW; + } + } + } + + /* Tried to remove something that wasn't set */ + TellNotSet(source, channel, parameter); + parameter.clear(); + return MODEACTION_DENY; + } +} + +void ListModeBase::DoSyncChannel(Channel* chan, Module* proto, void* opaque) +{ + ModeList* mlist = extItem.get(chan); + irc::modestacker modestack(true); + std::vector<std::string> stackresult; + std::vector<TranslateType> types; + types.push_back(TR_TEXT); + if (mlist) + { + for (ModeList::iterator it = mlist->begin(); it != mlist->end(); it++) + { + modestack.Push(std::string(1, mode)[0], it->mask); + } + } + while (modestack.GetStackedLine(stackresult)) + { + types.assign(stackresult.size(), this->GetTranslateType()); + proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, stackresult, types); + stackresult.clear(); + } +} + +bool ListModeBase::ValidateParam(User*, Channel*, std::string&) +{ + return true; +} + +void ListModeBase::TellListTooLong(User* source, Channel* channel, std::string& parameter) +{ + source->WriteNumeric(478, "%s %s %s :Channel ban list is full", source->nick.c_str(), channel->name.c_str(), parameter.c_str()); +} + +void ListModeBase::TellAlreadyOnList(User*, Channel*, std::string&) +{ +} + +void ListModeBase::TellNotSet(User*, Channel*, std::string&) +{ +} diff --git a/src/mode.cpp b/src/mode.cpp index 8cf04ef08..417707ee9 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -946,6 +946,7 @@ static builtin_modes static_modes; void ModeParser::InitBuiltinModes() { static_modes.init(); + static_modes.b.DoRehash(); } ModeParser::ModeParser() diff --git a/src/modes/cmode_b.cpp b/src/modes/cmode_b.cpp deleted file mode 100644 index efc24d189..000000000 --- a/src/modes/cmode_b.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org> - * Copyright (C) 2006 Craig Edwards <craigedwards@brainbox.cc> - * - * 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 - * License as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "inspircd.h" -#include <string> -#include <vector> -#include "inspircd.h" -#include "configreader.h" -#include "mode.h" -#include "channels.h" -#include "users.h" -#include "modules.h" -#include "inspstring.h" -#include "hashcomp.h" -#include "builtinmodes.h" - -ModeChannelBan::ModeChannelBan() : ModeHandler(NULL, "ban", 'b', PARAM_ALWAYS, MODETYPE_CHANNEL) -{ - list = true; -} - -ModeAction ModeChannelBan::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) -{ - int status = channel->GetPrefixValue(source); - /* Call the correct method depending on wether we're adding or removing the mode */ - if (adding) - { - this->AddBan(source, parameter, channel, status); - } - else - { - this->DelBan(source, parameter, channel, status); - } - /* If the method above 'ate' the parameter by reducing it to an empty string, then - * it won't matter wether we return ALLOW or DENY here, as an empty string overrides - * the return value and is always MODEACTION_DENY if the mode is supposed to have - * a parameter. - */ - return MODEACTION_ALLOW; -} - -void ModeChannelBan::RemoveMode(Channel* channel, irc::modestacker* stack) -{ - BanList copy; - - for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++) - { - copy.push_back(*i); - } - - for (BanList::iterator i = copy.begin(); i != copy.end(); i++) - { - if (stack) - { - stack->Push(this->GetModeChar(), i->data); - } - else - { - std::vector<std::string> parameters; parameters.push_back(channel->name); parameters.push_back("-b"); parameters.push_back(i->data); - ServerInstance->SendMode(parameters, ServerInstance->FakeClient); - } - } -} - -void ModeChannelBan::RemoveMode(User*, irc::modestacker* stack) -{ -} - -void ModeChannelBan::DisplayList(User* user, Channel* channel) -{ - /* Display the channel banlist */ - for (BanList::reverse_iterator i = channel->bans.rbegin(); i != channel->bans.rend(); ++i) - { - user->WriteServ("367 %s %s %s %s %lu",user->nick.c_str(), channel->name.c_str(), i->data.c_str(), i->set_by.c_str(), (unsigned long)i->set_time); - } - user->WriteServ("368 %s %s :End of channel ban list",user->nick.c_str(), channel->name.c_str()); - return; -} - -void ModeChannelBan::DisplayEmptyList(User* user, Channel* channel) -{ - user->WriteServ("368 %s %s :End of channel ban list",user->nick.c_str(), channel->name.c_str()); -} - -std::string& ModeChannelBan::AddBan(User *user, std::string &dest, Channel *chan, int) -{ - if ((!user) || (!chan)) - { - ServerInstance->Logs->Log("MODE",DEFAULT,"*** BUG *** AddBan was given an invalid parameter"); - dest.clear(); - return dest; - } - - /* Attempt to tidy the mask */ - ModeParser::CleanMask(dest); - /* If the mask was invalid, we exit */ - if (dest.empty() || dest.length() > 250) - return dest; - - long maxbans = chan->GetMaxBans(); - if (IS_LOCAL(user) && ((unsigned)chan->bans.size() >= (unsigned)maxbans)) - { - user->WriteServ("478 %s %s :Channel ban list for %s is full (maximum entries for this channel is %ld)",user->nick.c_str(), chan->name.c_str(), chan->name.c_str(), maxbans); - dest.clear(); - return dest; - } - - ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnAddBan, MOD_RESULT, (user,chan,dest)); - if (MOD_RESULT == MOD_RES_DENY) - { - dest.clear(); - return dest; - } - - for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++) - { - if (i->data == dest) - { - /* dont allow a user to set the same ban twice */ - dest.clear(); - return dest; - } - } - - b.set_time = ServerInstance->Time(); - b.data.assign(dest, 0, MAXBUF); - b.set_by.assign(user->nick, 0, 64); - chan->bans.push_back(b); - return dest; -} - -std::string& ModeChannelBan::DelBan(User *user, std::string& dest, Channel *chan, int) -{ - if ((!user) || (!chan)) - { - ServerInstance->Logs->Log("MODE",DEFAULT,"*** BUG *** TakeBan was given an invalid parameter"); - dest.clear(); - return dest; - } - - for (BanList::iterator i = chan->bans.begin(); i != chan->bans.end(); i++) - { - if (!strcasecmp(i->data.c_str(), dest.c_str())) - { - ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnDelBan, MOD_RESULT, (user, chan, dest)); - if (MOD_RESULT == MOD_RES_DENY) - { - dest.clear(); - return dest; - } - chan->bans.erase(i); - return dest; - } - } - dest.clear(); - return dest; -} - diff --git a/src/modules/m_autoop.cpp b/src/modules/m_autoop.cpp index a8f6f8d1e..93f641661 100644 --- a/src/modules/m_autoop.cpp +++ b/src/modules/m_autoop.cpp @@ -19,7 +19,7 @@ #include "inspircd.h" -#include "u_listmode.h" +#include "listmode.h" /* $ModDesc: Provides support for the +w channel mode, autoop list */ @@ -101,13 +101,13 @@ class ModuleAutoOp : public Module if (!IS_LOCAL(memb->user)) return; - modelist* list = mh.extItem.get(memb->chan); + ListModeBase::ModeList* list = mh.GetList(memb->chan); if (list) { std::string modeline("+"); std::vector<std::string> modechange; modechange.push_back(memb->chan->name); - for (modelist::iterator it = list->begin(); it != list->end(); it++) + for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { std::string::size_type colon = it->mask.find(':'); if (colon == std::string::npos) diff --git a/src/modules/m_banexception.cpp b/src/modules/m_banexception.cpp index ab195a68e..c521c5405 100644 --- a/src/modules/m_banexception.cpp +++ b/src/modules/m_banexception.cpp @@ -22,10 +22,10 @@ #include "inspircd.h" -#include "u_listmode.h" +#include "listmode.h" /* $ModDesc: Provides support for the +e channel mode */ -/* $ModDep: ../../include/u_listmode.h */ +/* $ModDep: ../../include/listmode.h */ /* Written by Om<om@inspircd.org>, April 2005. */ /* Rewritten to use the listmode utility by Om, December 2005 */ @@ -72,12 +72,12 @@ class ModuleBanException : public Module { if (chan != NULL) { - modelist *list = be.extItem.get(chan); + ListModeBase::ModeList *list = be.GetList(chan); if (!list) return MOD_RES_PASSTHRU; - for (modelist::iterator it = list->begin(); it != list->end(); it++) + for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (it->mask[0] != type || it->mask[1] != ':') continue; @@ -97,7 +97,7 @@ class ModuleBanException : public Module { if (chan) { - modelist *list = be.extItem.get(chan); + ListModeBase::ModeList *list = be.GetList(chan); if (!list) { @@ -105,7 +105,7 @@ class ModuleBanException : public Module return MOD_RES_PASSTHRU; } - for (modelist::iterator it = list->begin(); it != list->end(); it++) + for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (chan->CheckBan(user, it->mask)) { diff --git a/src/modules/m_banredirect.cpp b/src/modules/m_banredirect.cpp index 512c9b64e..ffd47d793 100644 --- a/src/modules/m_banredirect.cpp +++ b/src/modules/m_banredirect.cpp @@ -23,7 +23,7 @@ #include "inspircd.h" -#include "u_listmode.h" +#include "listmode.h" /* $ModDesc: Allows an extended ban (+b) syntax redirecting banned users to another channel */ @@ -46,10 +46,13 @@ typedef std::vector<BanRedirectEntry> BanRedirectList; class BanRedirect : public ModeWatcher { + ModeReference ban; public: SimpleExtItem<BanRedirectList> extItem; - BanRedirect(Module* parent) : ModeWatcher(parent, 'b', MODETYPE_CHANNEL), - extItem("banredirect", parent) + BanRedirect(Module* parent) + : ModeWatcher(parent, 'b', MODETYPE_CHANNEL) + , ban(parent, "ban") + , extItem("banredirect", parent) { } @@ -69,14 +72,16 @@ class BanRedirect : public ModeWatcher std::string mask[4]; enum { NICK, IDENT, HOST, CHAN } current = NICK; std::string::iterator start_pos = param.begin(); - long maxbans = channel->GetMaxBans(); if (param.length() >= 2 && param[1] == ':') return true; - if(adding && (channel->bans.size() > static_cast<unsigned>(maxbans))) + 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 %ld)", source->nick.c_str(), channel->name.c_str(), channel->name.c_str(), maxbans); + 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); return false; } diff --git a/src/modules/m_chanfilter.cpp b/src/modules/m_chanfilter.cpp index db406dd87..c90d76540 100644 --- a/src/modules/m_chanfilter.cpp +++ b/src/modules/m_chanfilter.cpp @@ -29,7 +29,7 @@ #define _SCL_SECURE_NO_DEPRECATE #include "inspircd.h" -#include "u_listmode.h" +#include "listmode.h" /** Handles channel mode +g */ @@ -49,10 +49,9 @@ class ChanFilter : public ListModeBase return true; } - virtual bool TellListTooLong(User* user, Channel* chan, std::string &word) + virtual void TellListTooLong(User* user, Channel* chan, std::string &word) { user->WriteNumeric(939, "%s %s %s :Channel spamfilter list is full", user->nick.c_str(), chan->name.c_str(), word.c_str()); - return true; } virtual void TellAlreadyOnList(User* user, Channel* chan, std::string &word) @@ -102,11 +101,11 @@ class ModuleChanFilter : public Module if (!IS_LOCAL(user) || res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; - modelist* list = cf.extItem.get(chan); + ListModeBase::ModeList* list = cf.GetList(chan); if (list) { - for (modelist::iterator i = list->begin(); i != list->end(); i++) + for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); i++) { if (InspIRCd::Match(text, i->mask)) { diff --git a/src/modules/m_check.cpp b/src/modules/m_check.cpp index a19b20477..662e512f9 100644 --- a/src/modules/m_check.cpp +++ b/src/modules/m_check.cpp @@ -23,13 +23,17 @@ /* $ModDesc: Provides the /CHECK command to retrieve information on a user, channel, hostname or IP address */ #include "inspircd.h" +#include "listmode.h" /** Handle /CHECK */ class CommandCheck : public Command { + ModeReference ban; public: - CommandCheck(Module* parent) : Command(parent,"CHECK", 1) + CommandCheck(Module* parent) + : Command(parent,"CHECK", 1) + , ban(parent, "ban") { flags_needed = 'o'; syntax = "<nickname>|<ip>|<hostmask>|<channel> <server>"; } @@ -198,18 +202,11 @@ class CommandCheck : public Command user->SendText(checkstr + " member " + tmpbuf); } - irc::modestacker modestack(true); - for(BanList::iterator b = targchan->bans.begin(); b != targchan->bans.end(); ++b) - { - modestack.Push('b', b->data); - } - std::vector<std::string> stackresult; - std::vector<TranslateType> dummy; - while (modestack.GetStackedLine(stackresult)) - { - creator->ProtoSendMode(user, TYPE_CHANNEL, targchan, stackresult, dummy); - stackresult.clear(); - } + // We know that the mode handler for bans is in the core and is derived from ListModeBase + ListModeBase* banlm = static_cast<ListModeBase*>(*ban); + banlm->DoSyncChannel(targchan, creator, user); + + // Show other listmodes as well FOREACH_MOD(I_OnSyncChannel,OnSyncChannel(targchan,creator,user)); dumpExt(user, checkstr, targchan); } diff --git a/src/modules/m_exemptchanops.cpp b/src/modules/m_exemptchanops.cpp index eec452df1..1f3dd3afb 100644 --- a/src/modules/m_exemptchanops.cpp +++ b/src/modules/m_exemptchanops.cpp @@ -18,7 +18,7 @@ #include "inspircd.h" -#include "u_listmode.h" +#include "listmode.h" /* $ModDesc: Provides the ability to allow channel operators to be exempt from certain modes. */ @@ -41,10 +41,9 @@ class ExemptChanOps : public ListModeBase return true; } - bool TellListTooLong(User* user, Channel* chan, std::string &word) + void TellListTooLong(User* user, Channel* chan, std::string &word) { user->WriteNumeric(959, "%s %s %s :Channel exemptchanops list is full", user->nick.c_str(), chan->name.c_str(), word.c_str()); - return true; } void TellAlreadyOnList(User* user, Channel* chan, std::string &word) @@ -82,11 +81,11 @@ class ExemptHandler : public HandlerBase3<ModResult, User*, Channel*, const std: unsigned int mypfx = chan->GetPrefixValue(user); std::string minmode; - modelist* list = ec.extItem.get(chan); + ListModeBase::ModeList* list = ec.GetList(chan); if (list) { - for (modelist::iterator i = list->begin(); i != list->end(); ++i) + for (ListModeBase::ModeList::iterator i = list->begin(); i != list->end(); ++i) { std::string::size_type pos = (*i).mask.find(':'); if (pos == std::string::npos) diff --git a/src/modules/m_inviteexception.cpp b/src/modules/m_inviteexception.cpp index 747a3b30a..aa5da086b 100644 --- a/src/modules/m_inviteexception.cpp +++ b/src/modules/m_inviteexception.cpp @@ -22,10 +22,10 @@ #include "inspircd.h" -#include "u_listmode.h" +#include "listmode.h" /* $ModDesc: Provides support for the +I channel mode */ -/* $ModDep: ../../include/u_listmode.h */ +/* $ModDep: ../../include/listmode.h */ /* * Written by Om <om@inspircd.org>, April 2005. @@ -71,10 +71,10 @@ public: ModResult OnCheckInvite(User* user, Channel* chan) { - modelist* list = ie.extItem.get(chan); + ListModeBase::ModeList* list = ie.GetList(chan); if (list) { - for (modelist::iterator it = list->begin(); it != list->end(); it++) + for (ListModeBase::ModeList::iterator it = list->begin(); it != list->end(); it++) { if (chan->CheckBan(user, it->mask)) { diff --git a/src/modules/m_spanningtree/netburst.cpp b/src/modules/m_spanningtree/netburst.cpp index 2f43c92a1..978886be6 100644 --- a/src/modules/m_spanningtree/netburst.cpp +++ b/src/modules/m_spanningtree/netburst.cpp @@ -21,6 +21,7 @@ #include "inspircd.h" #include "xline.h" +#include "listmode.h" #include "treesocket.h" #include "treeserver.h" @@ -140,32 +141,8 @@ void TreeSocket::SendFJoins(Channel* c) buffer.append(list).append("\r\n"); } - int linesize = 1; - for (BanList::iterator b = c->bans.begin(); b != c->bans.end(); b++) - { - int size = b->data.length() + 2; - int currsize = linesize + size; - if (currsize <= 350) - { - modes.append("b"); - params.append(" ").append(b->data); - linesize += size; - } - if ((modes.length() >= ServerInstance->Config->Limits.MaxModes) || (currsize > 350)) - { - /* Wrap at MAXMODES */ - buffer.append(":").append(ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params).append("\r\n"); - modes.clear(); - params.clear(); - linesize = 1; - } - } - - /* Only send these if there are any */ - if (!modes.empty()) - buffer.append(":").append(ServerInstance->Config->GetSID()).append(" FMODE ").append(c->name).append(" ").append(ConvToStr(c->age)).append(" +").append(modes).append(params); - - this->WriteLine(buffer); + ModeReference ban(NULL, "ban"); + static_cast<ListModeBase*>(*ban)->DoSyncChannel(c, Utils->Creator, this); } /** Send all XLines we know about */ diff --git a/src/modules/m_timedbans.cpp b/src/modules/m_timedbans.cpp index 81b12d881..a3ee9b525 100644 --- a/src/modules/m_timedbans.cpp +++ b/src/modules/m_timedbans.cpp @@ -80,20 +80,17 @@ class CommandTban : public Command bool isextban = ((mask.size() > 2) && (mask[1] == ':')); if (!isextban && !ServerInstance->IsValidMask(mask)) mask.append("!*@*"); - if ((mask.length() > 250) || (!ServerInstance->IsValidMask(mask) && !isextban)) - { - user->WriteServ("NOTICE "+user->nick+" :Invalid ban mask"); - return CMD_FAILURE; - } + setban.push_back(mask); // use CallHandler to make it so that the user sets the mode // themselves ServerInstance->Parser->CallHandler("MODE",setban,user); - for (BanList::iterator i = channel->bans.begin(); i != channel->bans.end(); i++) - if (!strcasecmp(i->data.c_str(), mask.c_str())) - goto found; - return CMD_FAILURE; -found: + if (ServerInstance->Modes->GetLastParse().empty()) + { + user->WriteServ("NOTICE "+user->nick+" :Invalid ban mask"); + return CMD_FAILURE; + } + CUList tmp; T.channel = channelname; T.mask = mask; diff --git a/src/modules/u_listmode.h b/src/modules/u_listmode.h deleted file mode 100644 index 31ef8a185..000000000 --- a/src/modules/u_listmode.h +++ /dev/null @@ -1,415 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org> - * - * 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 - * License as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - - -#ifndef INSPIRCD_LISTMODE_PROVIDER -#define INSPIRCD_LISTMODE_PROVIDER - -/** Get the time as a string - */ -inline std::string stringtime() -{ - std::ostringstream TIME; - TIME << ServerInstance->Time(); - return TIME.str(); -} - -/** An item in a listmode's list - */ -class ListItem -{ -public: - std::string nick; - std::string mask; - std::string time; -}; - -/** The number of items a listmode's list may contain - */ -class ListLimit -{ -public: - std::string mask; - unsigned int limit; -}; - -/** Items stored in the channel's list - */ -typedef std::list<ListItem> modelist; -/** Max items per channel by name - */ -typedef std::list<ListLimit> limitlist; - -/** The base class for list modes, should be inherited. - */ -class ListModeBase : public ModeHandler -{ - protected: - /** Numeric to use when outputting the list - */ - unsigned int listnumeric; - /** Numeric to indicate end of list - */ - unsigned int endoflistnumeric; - /** String to send for end of list - */ - std::string endofliststring; - /** Automatically tidy up entries - */ - bool tidy; - /** Config tag to check for max items per channel - */ - std::string configtag; - /** Limits on a per-channel basis read from the tag - * specified in ListModeBase::configtag - */ - limitlist chanlimits; - - public: - /** Storage key - */ - SimpleExtItem<modelist> extItem; - - /** Constructor. - * @param Instance The creator of this class - * @param modechar Mode character - * @param eolstr End of list string - * @pram lnum List numeric - * @param eolnum End of list numeric - * @param autotidy Automatically tidy list entries on add - * @param ctag Configuration tag to get limits from - */ - ListModeBase(Module* Creator, const std::string& Name, char modechar, const std::string &eolstr, unsigned int lnum, unsigned int eolnum, bool autotidy, const std::string &ctag = "banlist") - : ModeHandler(Creator, Name, modechar, PARAM_ALWAYS, MODETYPE_CHANNEL), - listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy), - configtag(ctag), extItem("listbase_mode_" + name + "_list", Creator) - { - list = true; - } - - /** See mode.h - */ - std::pair<bool,std::string> ModeSet(User*, User*, Channel* channel, const std::string ¶meter) - { - modelist* el = extItem.get(channel); - if (el) - { - for (modelist::iterator it = el->begin(); it != el->end(); it++) - { - if(parameter == it->mask) - { - return std::make_pair(true, parameter); - } - } - } - return std::make_pair(false, parameter); - } - - /** Display the list for this mode - * @param user The user to send the list to - * @param channel The channel the user is requesting the list for - */ - virtual void DisplayList(User* user, Channel* channel) - { - modelist* el = extItem.get(channel); - if (el) - { - for (modelist::reverse_iterator it = el->rbegin(); it != el->rend(); ++it) - { - user->WriteNumeric(listnumeric, "%s %s %s %s %s", user->nick.c_str(), channel->name.c_str(), it->mask.c_str(), (it->nick.length() ? it->nick.c_str() : ServerInstance->Config->ServerName.c_str()), it->time.c_str()); - } - } - user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str()); - } - - virtual void DisplayEmptyList(User* user, Channel* channel) - { - user->WriteNumeric(endoflistnumeric, "%s %s :%s", user->nick.c_str(), channel->name.c_str(), endofliststring.c_str()); - } - - /** Remove all instances of the mode from a channel. - * See mode.h - * @param channel The channel to remove all instances of the mode from - */ - virtual void RemoveMode(Channel* channel, irc::modestacker* stack) - { - modelist* el = extItem.get(channel); - if (el) - { - irc::modestacker modestack(false); - - for (modelist::iterator it = el->begin(); it != el->end(); it++) - { - if (stack) - stack->Push(this->GetModeChar(), it->mask); - else - modestack.Push(this->GetModeChar(), it->mask); - } - - if (stack) - return; - - std::vector<std::string> stackresult; - stackresult.push_back(channel->name); - while (modestack.GetStackedLine(stackresult)) - { - ServerInstance->SendMode(stackresult, ServerInstance->FakeClient); - stackresult.clear(); - stackresult.push_back(channel->name); - } - } - } - - /** See mode.h - */ - virtual void RemoveMode(User*, irc::modestacker* stack) - { - /* Listmodes dont get set on users */ - } - - /** Perform a rehash of this mode's configuration data - */ - virtual void DoRehash() - { - ConfigTagList tags = ServerInstance->Config->ConfTags(configtag); - - chanlimits.clear(); - - for (ConfigIter i = tags.first; i != tags.second; i++) - { - // For each <banlist> tag - ConfigTag* c = i->second; - ListLimit limit; - limit.mask = c->getString("chan"); - limit.limit = c->getInt("limit"); - - if (limit.mask.size() && limit.limit > 0) - chanlimits.push_back(limit); - } - if (chanlimits.size() == 0) - { - ListLimit limit; - limit.mask = "*"; - limit.limit = 64; - chanlimits.push_back(limit); - } - } - - /** Populate the Implements list with the correct events for a List Mode - */ - virtual void DoImplements(Module* m) - { - ServerInstance->Modules->AddService(extItem); - this->DoRehash(); - Implementation eventlist[] = { I_OnSyncChannel, I_OnRehash }; - ServerInstance->Modules->Attach(eventlist, m, sizeof(eventlist)/sizeof(Implementation)); - } - - /** Handle the list mode. - * See mode.h - */ - virtual ModeAction OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) - { - // Try and grab the list - modelist* el = extItem.get(channel); - - if (adding) - { - if (tidy) - ModeParser::CleanMask(parameter); - - if (parameter.length() > 250) - return MODEACTION_DENY; - - // If there was no list - if (!el) - { - // Make one - el = new modelist; - extItem.set(channel, el); - } - - // Check if the item already exists in the list - for (modelist::iterator it = el->begin(); it != el->end(); it++) - { - if (parameter == it->mask) - { - /* Give a subclass a chance to error about this */ - TellAlreadyOnList(source, channel, parameter); - - // it does, deny the change - return MODEACTION_DENY; - } - } - - unsigned int maxsize = 0; - - for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++) - { - if (InspIRCd::Match(channel->name, it->mask)) - { - // We have a pattern matching the channel... - maxsize = el->size(); - if (!IS_LOCAL(source) || (maxsize < it->limit)) - { - /* Ok, it *could* be allowed, now give someone subclassing us - * a chance to validate the parameter. - * The param is passed by reference, so they can both modify it - * and tell us if we allow it or not. - * - * eg, the subclass could: - * 1) allow - * 2) 'fix' parameter and then allow - * 3) deny - */ - if (ValidateParam(source, channel, parameter)) - { - // And now add the mask onto the list... - ListItem e; - e.mask = parameter; - e.nick = source->nick; - e.time = stringtime(); - - el->push_back(e); - return MODEACTION_ALLOW; - } - else - { - /* If they deny it they have the job of giving an error message */ - return MODEACTION_DENY; - } - } - } - } - - /* List is full, give subclass a chance to send a custom message */ - if (!TellListTooLong(source, channel, parameter)) - { - source->WriteNumeric(478, "%s %s %s :Channel ban/ignore list is full", source->nick.c_str(), channel->name.c_str(), parameter.c_str()); - } - - parameter.clear(); - return MODEACTION_DENY; - } - else - { - // We're taking the mode off - if (el) - { - for (modelist::iterator it = el->begin(); it != el->end(); it++) - { - if (parameter == it->mask) - { - el->erase(it); - if (el->size() == 0) - { - extItem.unset(channel); - } - return MODEACTION_ALLOW; - } - } - /* Tried to remove something that wasn't set */ - TellNotSet(source, channel, parameter); - parameter.clear(); - return MODEACTION_DENY; - } - else - { - /* Hmm, taking an exception off a non-existant list, DIE */ - TellNotSet(source, channel, parameter); - parameter.clear(); - return MODEACTION_DENY; - } - } - return MODEACTION_DENY; - } - - /** Syncronize channel item list with another server. - * See modules.h - * @param chan Channel to syncronize - * @param proto Protocol module pointer - * @param opaque Opaque connection handle - */ - virtual void DoSyncChannel(Channel* chan, Module* proto, void* opaque) - { - modelist* mlist = extItem.get(chan); - irc::modestacker modestack(true); - std::vector<std::string> stackresult; - std::vector<TranslateType> types; - types.push_back(TR_TEXT); - if (mlist) - { - for (modelist::iterator it = mlist->begin(); it != mlist->end(); it++) - { - modestack.Push(std::string(1, mode)[0], it->mask); - } - } - while (modestack.GetStackedLine(stackresult)) - { - types.assign(stackresult.size(), this->GetTranslateType()); - proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, stackresult, types); - stackresult.clear(); - } - } - - /** Validate parameters. - * Overridden by implementing module. - * @param source Source user adding the parameter - * @param channel Channel the parameter is being added to - * @param parameter The actual parameter being added - * @return true if the parameter is valid - */ - virtual bool ValidateParam(User*, Channel*, std::string&) - { - return true; - } - - /** Tell the user the list is too long. - * Overridden by implementing module. - * @param source Source user adding the parameter - * @param channel Channel the parameter is being added to - * @param parameter The actual parameter being added - * @return Ignored - */ - virtual bool TellListTooLong(User*, Channel*, std::string&) - { - return false; - } - - /** Tell the user an item is already on the list. - * Overridden by implementing module. - * @param source Source user adding the parameter - * @param channel Channel the parameter is being added to - * @param parameter The actual parameter being added - */ - virtual void TellAlreadyOnList(User*, Channel*, std::string&) - { - } - - /** Tell the user that the parameter is not in the list. - * Overridden by implementing module. - * @param source Source user removing the parameter - * @param channel Channel the parameter is being removed from - * @param parameter The actual parameter being removed - */ - virtual void TellNotSet(User*, Channel*, std::string&) - { - } -}; - -#endif |