mirror of
https://github.com/anope/anope.git
synced 2026-06-28 11:26:37 +02:00
866f3f32ab
Cache xline nick, user, host, etc instead of rebuilding it everytime its requested. Store users ip in sockaddr form and not string form to prevent having to rebuild sockaddrs when checking xlines. Also do not try to convert empty config values in Config::Get as this can be rather common if a non string configuration value is not set, and the cost of the ConvertException is great.
879 lines
21 KiB
C++
879 lines
21 KiB
C++
/* Mode support
|
|
*
|
|
* Copyright (C) 2008-2011 Adam <Adam@anope.org>
|
|
* Copyright (C) 2008-2014 Anope Team <team@anope.org>
|
|
*
|
|
* Please read COPYING and README for further details.
|
|
*
|
|
*/
|
|
|
|
#include "services.h"
|
|
#include "modules.h"
|
|
#include "config.h"
|
|
#include "sockets.h"
|
|
#include "protocol.h"
|
|
#include "channels.h"
|
|
#include "uplink.h"
|
|
|
|
struct StackerInfo;
|
|
|
|
/* List of pairs of user/channels and their stacker info */
|
|
static std::map<User *, StackerInfo *> UserStackerObjects;
|
|
static std::map<Channel *, StackerInfo *> ChannelStackerObjects;
|
|
|
|
/* Array of all modes Anope knows about.*/
|
|
static std::vector<ChannelMode *> ChannelModes;
|
|
static std::vector<UserMode *> UserModes;
|
|
|
|
/* Modes are in this array are at position
|
|
* modechar. Additionally, status modes are in this array (again) at statuschar.
|
|
*/
|
|
static std::vector<ChannelMode *> ChannelModesIdx;
|
|
static std::vector<UserMode *> UserModesIdx;
|
|
|
|
static std::map<Anope::string, ChannelMode *> ChannelModesByName;
|
|
static std::map<Anope::string, UserMode *> UserModesByName;
|
|
|
|
/* Sorted by status */
|
|
static std::vector<ChannelModeStatus *> ChannelModesByStatus;
|
|
|
|
/* Number of generic modes we support */
|
|
unsigned ModeManager::GenericChannelModes = 0, ModeManager::GenericUserModes = 0;
|
|
|
|
struct StackerInfo
|
|
{
|
|
/* Modes to be added */
|
|
std::list<std::pair<Mode *, Anope::string> > AddModes;
|
|
/* Modes to be deleted */
|
|
std::list<std::pair<Mode *, Anope::string> > DelModes;
|
|
/* Bot this is sent from */
|
|
BotInfo *bi;
|
|
|
|
StackerInfo() : bi(NULL) { }
|
|
|
|
/** Add a mode to this object
|
|
* @param mode The mode
|
|
* @param set true if setting, false if unsetting
|
|
* @param param The param for the mode
|
|
*/
|
|
void AddMode(Mode *mode, bool set, const Anope::string ¶m);
|
|
};
|
|
|
|
ChannelStatus::ChannelStatus()
|
|
{
|
|
}
|
|
|
|
ChannelStatus::ChannelStatus(const Anope::string &m) : modes(m)
|
|
{
|
|
}
|
|
|
|
void ChannelStatus::AddMode(char c)
|
|
{
|
|
if (modes.find(c) == Anope::string::npos)
|
|
modes.append(c);
|
|
}
|
|
|
|
void ChannelStatus::DelMode(char c)
|
|
{
|
|
modes = modes.replace_all_cs(c, "");
|
|
}
|
|
|
|
bool ChannelStatus::HasMode(char c) const
|
|
{
|
|
return modes.find(c) != Anope::string::npos;
|
|
}
|
|
|
|
bool ChannelStatus::Empty() const
|
|
{
|
|
return modes.empty();
|
|
}
|
|
|
|
void ChannelStatus::Clear()
|
|
{
|
|
modes.clear();
|
|
}
|
|
|
|
const Anope::string &ChannelStatus::Modes() const
|
|
{
|
|
return modes;
|
|
}
|
|
|
|
Anope::string ChannelStatus::BuildModePrefixList() const
|
|
{
|
|
Anope::string ret;
|
|
|
|
for (size_t i = 0; i < modes.length(); ++i)
|
|
{
|
|
ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]);
|
|
if (cm != NULL && cm->type == MODE_STATUS)
|
|
{
|
|
ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm);
|
|
ret += cms->symbol;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Mode::Mode(const Anope::string &mname, ModeClass mcl, char mch, ModeType mt) : name(mname), mclass(mcl), mchar(mch), type(mt)
|
|
{
|
|
}
|
|
|
|
Mode::~Mode()
|
|
{
|
|
}
|
|
|
|
bool Mode::CanSet(User *u) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
UserMode::UserMode(const Anope::string &un, char mch) : Mode(un, MC_USER, mch, MODE_REGULAR)
|
|
{
|
|
}
|
|
|
|
UserModeParam::UserModeParam(const Anope::string &un, char mch) : UserMode(un, mch)
|
|
{
|
|
this->type = MODE_PARAM;
|
|
}
|
|
|
|
ChannelMode::ChannelMode(const Anope::string &cm, char mch) : Mode(cm, MC_CHANNEL, mch, MODE_REGULAR)
|
|
{
|
|
}
|
|
|
|
bool ChannelMode::CanSet(User *u) const
|
|
{
|
|
EventReturn MOD_RESULT;
|
|
FOREACH_RESULT(OnCanSet, MOD_RESULT, (u, this));
|
|
return MOD_RESULT != EVENT_STOP;
|
|
}
|
|
|
|
ChannelMode *ChannelMode::Wrap(Anope::string ¶m)
|
|
{
|
|
return this;
|
|
}
|
|
|
|
ChannelMode *ChannelMode::Unwrap(Anope::string ¶m)
|
|
{
|
|
for (unsigned i = 0; i < listeners.size(); ++i)
|
|
{
|
|
ChannelMode *cm = listeners[i]->Unwrap(this, param);
|
|
if (cm != this)
|
|
return cm;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
ChannelMode *ChannelMode::Unwrap(ChannelMode *, Anope::string ¶m)
|
|
{
|
|
throw CoreException("Unwrap in channel mode");
|
|
}
|
|
|
|
ChannelModeList::ChannelModeList(const Anope::string &cm, char mch) : ChannelMode(cm, mch)
|
|
{
|
|
this->type = MODE_LIST;
|
|
}
|
|
|
|
bool ChannelModeList::IsValid(Anope::string &mask) const
|
|
{
|
|
if (name == "BAN" || name == "EXCEPT" || name == "INVITEOVERRIDE")
|
|
mask = IRCD->NormalizeMask(mask);
|
|
return true;
|
|
}
|
|
|
|
ChannelModeParam::ChannelModeParam(const Anope::string &cm, char mch, bool ma) : ChannelMode(cm, mch), minus_no_arg(ma)
|
|
{
|
|
this->type = MODE_PARAM;
|
|
}
|
|
|
|
ChannelModeStatus::ChannelModeStatus(const Anope::string &mname, char modeChar, char msymbol, short mlevel) : ChannelMode(mname, modeChar), symbol(msymbol), level(mlevel)
|
|
{
|
|
this->type = MODE_STATUS;
|
|
}
|
|
|
|
template<typename T>
|
|
ChannelModeVirtual<T>::ChannelModeVirtual(const Anope::string &mname, const Anope::string &basename) : T(mname, 0)
|
|
, base(basename)
|
|
{
|
|
basech = ModeManager::FindChannelModeByName(base);
|
|
if (basech)
|
|
basech->listeners.push_back(this);
|
|
}
|
|
|
|
template<typename T>
|
|
ChannelModeVirtual<T>::~ChannelModeVirtual()
|
|
{
|
|
if (basech)
|
|
{
|
|
std::vector<ChannelMode *>::iterator it = std::find(basech->listeners.begin(), basech->listeners.end(), this);
|
|
if (it != basech->listeners.end())
|
|
basech->listeners.erase(it);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
ChannelMode *ChannelModeVirtual<T>::Wrap(Anope::string ¶m)
|
|
{
|
|
if (basech == NULL)
|
|
{
|
|
basech = ModeManager::FindChannelModeByName(base);
|
|
if (basech)
|
|
basech->listeners.push_back(this);
|
|
}
|
|
|
|
return basech;
|
|
}
|
|
|
|
template class ChannelModeVirtual<ChannelMode>;
|
|
template class ChannelModeVirtual<ChannelModeList>;
|
|
|
|
bool UserModeOperOnly::CanSet(User *u) const
|
|
{
|
|
return u && u->HasMode("OPER");
|
|
}
|
|
|
|
bool UserModeNoone::CanSet(User *u) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool ChannelModeKey::IsValid(Anope::string &value) const
|
|
{
|
|
if (!value.empty() && value.find(':') == Anope::string::npos && value.find(',') == Anope::string::npos)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ChannelModeOperOnly::CanSet(User *u) const
|
|
{
|
|
return u && u->HasMode("OPER");
|
|
}
|
|
|
|
bool ChannelModeNoone::CanSet(User *u) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void StackerInfo::AddMode(Mode *mode, bool set, const Anope::string ¶m)
|
|
{
|
|
bool is_param = mode->type == MODE_PARAM;
|
|
|
|
std::list<std::pair<Mode *, Anope::string> > *list, *otherlist;
|
|
if (set)
|
|
{
|
|
list = &AddModes;
|
|
otherlist = &DelModes;
|
|
}
|
|
else
|
|
{
|
|
list = &DelModes;
|
|
otherlist = &AddModes;
|
|
}
|
|
|
|
/* Loop through the list and find if this mode is already on here */
|
|
std::list<std::pair<Mode *, Anope::string > >::iterator it, it_end;
|
|
for (it = list->begin(), it_end = list->end(); it != it_end; ++it)
|
|
{
|
|
/* The param must match too (can have multiple status or list modes), but
|
|
* if it is a param mode it can match no matter what the param is
|
|
*/
|
|
if (it->first == mode && (is_param || param.equals_cs(it->second)))
|
|
{
|
|
list->erase(it);
|
|
/* It can only be on this list once */
|
|
break;
|
|
}
|
|
}
|
|
/* If the mode is on the other list, remove it from there (eg, we dont want +o-o Adam Adam) */
|
|
for (it = otherlist->begin(), it_end = otherlist->end(); it != it_end; ++it)
|
|
{
|
|
/* The param must match too (can have multiple status or list modes), but
|
|
* if it is a param mode it can match no matter what the param is
|
|
*/
|
|
if (it->first == mode && (is_param || param.equals_cs(it->second)))
|
|
{
|
|
otherlist->erase(it);
|
|
return;
|
|
/* Note that we return here because this is like setting + and - on the same mode within the same
|
|
* cycle, no change is made. This causes no problems with something like - + and -, because after the
|
|
* second mode change the list is empty, and the third mode change starts fresh.
|
|
*/
|
|
}
|
|
}
|
|
|
|
/* Add this mode and its param to our list */
|
|
list->push_back(std::make_pair(mode, param));
|
|
}
|
|
|
|
static class ModePipe : public Pipe
|
|
{
|
|
public:
|
|
void OnNotify()
|
|
{
|
|
ModeManager::ProcessModes();
|
|
}
|
|
} *modePipe;
|
|
|
|
/** Get the stacker info for an item, if one doesnt exist it is created
|
|
* @param Item The user/channel etc
|
|
* @return The stacker info
|
|
*/
|
|
template<typename List, typename Object>
|
|
static StackerInfo *GetInfo(List &l, Object *o)
|
|
{
|
|
typename List::const_iterator it = l.find(o);
|
|
if (it != l.end())
|
|
return it->second;
|
|
|
|
StackerInfo *s = new StackerInfo();
|
|
l[o] = s;
|
|
return s;
|
|
}
|
|
|
|
/** Build a list of mode strings to send to the IRCd from the mode stacker
|
|
* @param info The stacker info for a channel or user
|
|
* @return a list of strings
|
|
*/
|
|
static std::list<Anope::string> BuildModeStrings(StackerInfo *info)
|
|
{
|
|
std::list<Anope::string> ret;
|
|
std::list<std::pair<Mode *, Anope::string> >::iterator it, it_end;
|
|
Anope::string buf = "+", parambuf;
|
|
unsigned NModes = 0;
|
|
|
|
for (it = info->AddModes.begin(), it_end = info->AddModes.end(); it != it_end; ++it)
|
|
{
|
|
if (++NModes > IRCD->MaxModes || (buf.length() + parambuf.length() > IRCD->MaxLine - 100)) // Leave room for command, channel, etc
|
|
{
|
|
ret.push_back(buf + parambuf);
|
|
buf = "+";
|
|
parambuf.clear();
|
|
NModes = 1;
|
|
}
|
|
|
|
buf += it->first->mchar;
|
|
|
|
if (!it->second.empty())
|
|
parambuf += " " + it->second;
|
|
}
|
|
|
|
if (buf[buf.length() - 1] == '+')
|
|
buf.erase(buf.length() - 1);
|
|
|
|
buf += "-";
|
|
for (it = info->DelModes.begin(), it_end = info->DelModes.end(); it != it_end; ++it)
|
|
{
|
|
if (++NModes > IRCD->MaxModes || (buf.length() + parambuf.length() > IRCD->MaxLine - 100)) // Leave room for command, channel, etc
|
|
{
|
|
ret.push_back(buf + parambuf);
|
|
buf = "-";
|
|
parambuf.clear();
|
|
NModes = 1;
|
|
}
|
|
|
|
buf += it->first->mchar;
|
|
|
|
if (!it->second.empty())
|
|
parambuf += " " + it->second;
|
|
}
|
|
|
|
if (buf[buf.length() - 1] == '-')
|
|
buf.erase(buf.length() - 1);
|
|
|
|
if (!buf.empty())
|
|
ret.push_back(buf + parambuf);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool ModeManager::AddUserMode(UserMode *um)
|
|
{
|
|
if (ModeManager::FindUserModeByChar(um->mchar) != NULL)
|
|
return false;
|
|
if (ModeManager::FindUserModeByName(um->name) != NULL)
|
|
return false;
|
|
|
|
if (um->name.empty())
|
|
{
|
|
um->name = stringify(++GenericUserModes);
|
|
Log() << "ModeManager: Added generic support for user mode " << um->mchar;
|
|
}
|
|
|
|
unsigned want = um->mchar;
|
|
if (want >= UserModesIdx.size())
|
|
UserModesIdx.resize(want + 1);
|
|
UserModesIdx[want] = um;
|
|
|
|
UserModesByName[um->name] = um;
|
|
|
|
UserModes.push_back(um);
|
|
|
|
FOREACH_MOD(OnUserModeAdd, (um));
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ModeManager::AddChannelMode(ChannelMode *cm)
|
|
{
|
|
if (cm->mchar && ModeManager::FindChannelModeByChar(cm->mchar) != NULL)
|
|
return false;
|
|
if (ModeManager::FindChannelModeByName(cm->name) != NULL)
|
|
return false;
|
|
|
|
if (cm->name.empty())
|
|
{
|
|
cm->name = stringify(++GenericChannelModes);
|
|
Log() << "ModeManager: Added generic support for channel mode " << cm->mchar;
|
|
}
|
|
|
|
if (cm->mchar)
|
|
{
|
|
unsigned want = cm->mchar;
|
|
if (want >= ChannelModesIdx.size())
|
|
ChannelModesIdx.resize(want + 1);
|
|
ChannelModesIdx[want] = cm;
|
|
}
|
|
|
|
if (cm->type == MODE_STATUS)
|
|
{
|
|
ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm);
|
|
unsigned want = cms->symbol;
|
|
if (want >= ChannelModesIdx.size())
|
|
ChannelModesIdx.resize(want + 1);
|
|
ChannelModesIdx[want] = cms;
|
|
|
|
RebuildStatusModes();
|
|
}
|
|
|
|
ChannelModesByName[cm->name] = cm;
|
|
|
|
ChannelModes.push_back(cm);
|
|
|
|
FOREACH_MOD(OnChannelModeAdd, (cm));
|
|
|
|
return true;
|
|
}
|
|
|
|
void ModeManager::RemoveUserMode(UserMode *um)
|
|
{
|
|
if (!um)
|
|
return;
|
|
|
|
unsigned want = um->mchar;
|
|
if (want >= UserModesIdx.size())
|
|
return;
|
|
|
|
if (UserModesIdx[want] != um)
|
|
return;
|
|
|
|
UserModesIdx[want] = NULL;
|
|
|
|
UserModesByName.erase(um->name);
|
|
|
|
std::vector<UserMode *>::iterator it = std::find(UserModes.begin(), UserModes.end(), um);
|
|
if (it != UserModes.end())
|
|
UserModes.erase(it);
|
|
|
|
StackerDel(um);
|
|
}
|
|
|
|
void ModeManager::RemoveChannelMode(ChannelMode *cm)
|
|
{
|
|
if (!cm)
|
|
return;
|
|
|
|
if (cm->mchar)
|
|
{
|
|
unsigned want = cm->mchar;
|
|
if (want >= ChannelModesIdx.size())
|
|
return;
|
|
|
|
if (ChannelModesIdx[want] != cm)
|
|
return;
|
|
|
|
ChannelModesIdx[want] = NULL;
|
|
}
|
|
|
|
if (cm->type == MODE_STATUS)
|
|
{
|
|
ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm);
|
|
unsigned want = cms->symbol;
|
|
|
|
if (want >= ChannelModesIdx.size())
|
|
return;
|
|
|
|
if (ChannelModesIdx[want] != cm)
|
|
return;
|
|
|
|
ChannelModesIdx[want] = NULL;
|
|
|
|
RebuildStatusModes();
|
|
}
|
|
|
|
ChannelModesByName.erase(cm->name);
|
|
|
|
std::vector<ChannelMode *>::iterator it = std::find(ChannelModes.begin(), ChannelModes.end(), cm);
|
|
if (it != ChannelModes.end())
|
|
ChannelModes.erase(it);
|
|
|
|
StackerDel(cm);
|
|
}
|
|
|
|
ChannelMode *ModeManager::FindChannelModeByChar(char mode)
|
|
{
|
|
unsigned want = mode;
|
|
if (want >= ChannelModesIdx.size())
|
|
return NULL;
|
|
|
|
return ChannelModesIdx[want];
|
|
}
|
|
|
|
UserMode *ModeManager::FindUserModeByChar(char mode)
|
|
{
|
|
unsigned want = mode;
|
|
if (want >= UserModesIdx.size())
|
|
return NULL;
|
|
|
|
return UserModesIdx[want];
|
|
}
|
|
|
|
ChannelMode *ModeManager::FindChannelModeByName(const Anope::string &name)
|
|
{
|
|
std::map<Anope::string, ChannelMode *>::iterator it = ChannelModesByName.find(name);
|
|
if (it != ChannelModesByName.end())
|
|
return it->second;
|
|
return NULL;
|
|
}
|
|
|
|
UserMode *ModeManager::FindUserModeByName(const Anope::string &name)
|
|
{
|
|
std::map<Anope::string, UserMode *>::iterator it = UserModesByName.find(name);
|
|
if (it != UserModesByName.end())
|
|
return it->second;
|
|
return NULL;
|
|
}
|
|
|
|
char ModeManager::GetStatusChar(char value)
|
|
{
|
|
unsigned want = value;
|
|
if (want >= ChannelModesIdx.size())
|
|
return 0;
|
|
|
|
ChannelMode *cm = ChannelModesIdx[want];
|
|
if (cm == NULL || cm->type != MODE_STATUS || cm->mchar == value)
|
|
return 0;
|
|
|
|
return cm->mchar;
|
|
}
|
|
|
|
const std::vector<ChannelMode *> &ModeManager::GetChannelModes()
|
|
{
|
|
return ChannelModes;
|
|
}
|
|
|
|
const std::vector<UserMode *> &ModeManager::GetUserModes()
|
|
{
|
|
return UserModes;
|
|
}
|
|
|
|
const std::vector<ChannelModeStatus *> &ModeManager::GetStatusChannelModesByRank()
|
|
{
|
|
return ChannelModesByStatus;
|
|
}
|
|
|
|
static struct StatusSort
|
|
{
|
|
bool operator()(ChannelModeStatus *cm1, ChannelModeStatus *cm2) const
|
|
{
|
|
return cm1->level > cm2->level;
|
|
}
|
|
} statuscmp;
|
|
|
|
void ModeManager::RebuildStatusModes()
|
|
{
|
|
ChannelModesByStatus.clear();
|
|
for (unsigned j = 0; j < ChannelModesIdx.size(); ++j)
|
|
{
|
|
ChannelMode *cm = ChannelModesIdx[j];
|
|
|
|
if (cm && cm->type == MODE_STATUS && std::find(ChannelModesByStatus.begin(), ChannelModesByStatus.end(), cm) == ChannelModesByStatus.end())
|
|
ChannelModesByStatus.push_back(anope_dynamic_static_cast<ChannelModeStatus *>(cm));
|
|
}
|
|
std::sort(ChannelModesByStatus.begin(), ChannelModesByStatus.end(), statuscmp);
|
|
}
|
|
|
|
void ModeManager::StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool Set, const Anope::string &Param)
|
|
{
|
|
StackerInfo *s = GetInfo(ChannelStackerObjects, c);
|
|
s->AddMode(cm, Set, Param);
|
|
if (bi)
|
|
s->bi = bi;
|
|
else
|
|
s->bi = c->ci->WhoSends();
|
|
|
|
if (!modePipe)
|
|
modePipe = new ModePipe();
|
|
modePipe->Notify();
|
|
}
|
|
|
|
void ModeManager::StackerAdd(BotInfo *bi, User *u, UserMode *um, bool Set, const Anope::string &Param)
|
|
{
|
|
StackerInfo *s = GetInfo(UserStackerObjects, u);
|
|
s->AddMode(um, Set, Param);
|
|
if (bi)
|
|
s->bi = bi;
|
|
|
|
if (!modePipe)
|
|
modePipe = new ModePipe();
|
|
modePipe->Notify();
|
|
}
|
|
|
|
void ModeManager::ProcessModes()
|
|
{
|
|
if (!UserStackerObjects.empty())
|
|
{
|
|
for (std::map<User *, StackerInfo *>::const_iterator it = UserStackerObjects.begin(), it_end = UserStackerObjects.end(); it != it_end; ++it)
|
|
{
|
|
User *u = it->first;
|
|
StackerInfo *s = it->second;
|
|
|
|
std::list<Anope::string> ModeStrings = BuildModeStrings(s);
|
|
for (std::list<Anope::string>::iterator lit = ModeStrings.begin(), lit_end = ModeStrings.end(); lit != lit_end; ++lit)
|
|
IRCD->SendMode(s->bi, u, lit->c_str());
|
|
delete it->second;
|
|
}
|
|
UserStackerObjects.clear();
|
|
}
|
|
|
|
if (!ChannelStackerObjects.empty())
|
|
{
|
|
for (std::map<Channel *, StackerInfo *>::const_iterator it = ChannelStackerObjects.begin(), it_end = ChannelStackerObjects.end(); it != it_end; ++it)
|
|
{
|
|
Channel *c = it->first;
|
|
StackerInfo *s = it->second;
|
|
|
|
std::list<Anope::string> ModeStrings = BuildModeStrings(s);
|
|
for (std::list<Anope::string>::iterator lit = ModeStrings.begin(), lit_end = ModeStrings.end(); lit != lit_end; ++lit)
|
|
IRCD->SendMode(s->bi, c, lit->c_str());
|
|
delete it->second;
|
|
}
|
|
ChannelStackerObjects.clear();
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
static void StackerDel(std::map<T *, StackerInfo *> &map, T *obj)
|
|
{
|
|
typename std::map<T *, StackerInfo *>::iterator it = map.find(obj);
|
|
if (it != map.end())
|
|
{
|
|
StackerInfo *si = it->second;
|
|
std::list<Anope::string> ModeStrings = BuildModeStrings(si);
|
|
for (std::list<Anope::string>::iterator lit = ModeStrings.begin(), lit_end = ModeStrings.end(); lit != lit_end; ++lit)
|
|
IRCD->SendMode(si->bi, obj, lit->c_str());
|
|
|
|
delete si;
|
|
map.erase(it);
|
|
}
|
|
}
|
|
|
|
void ModeManager::StackerDel(User *u)
|
|
{
|
|
::StackerDel(UserStackerObjects, u);
|
|
}
|
|
|
|
void ModeManager::StackerDel(Channel *c)
|
|
{
|
|
::StackerDel(ChannelStackerObjects, c);
|
|
}
|
|
|
|
void ModeManager::StackerDel(Mode *m)
|
|
{
|
|
for (std::map<User *, StackerInfo *>::const_iterator it = UserStackerObjects.begin(), it_end = UserStackerObjects.end(); it != it_end;)
|
|
{
|
|
StackerInfo *si = it->second;
|
|
++it;
|
|
|
|
for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->AddModes.begin(), it2_end = si->AddModes.end(); it2 != it2_end;)
|
|
{
|
|
if (it2->first == m)
|
|
it2 = si->AddModes.erase(it2);
|
|
else
|
|
++it2;
|
|
}
|
|
|
|
for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->DelModes.begin(), it2_end = si->DelModes.end(); it2 != it2_end;)
|
|
{
|
|
if (it2->first == m)
|
|
it2 = si->DelModes.erase(it2);
|
|
else
|
|
++it2;
|
|
}
|
|
}
|
|
|
|
for (std::map<Channel *, StackerInfo *>::const_iterator it = ChannelStackerObjects.begin(), it_end = ChannelStackerObjects.end(); it != it_end;)
|
|
{
|
|
StackerInfo *si = it->second;
|
|
++it;
|
|
|
|
for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->AddModes.begin(), it2_end = si->AddModes.end(); it2 != it2_end;)
|
|
{
|
|
if (it2->first == m)
|
|
it2 = si->AddModes.erase(it2);
|
|
else
|
|
++it2;
|
|
}
|
|
|
|
for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->DelModes.begin(), it2_end = si->DelModes.end(); it2 != it2_end;)
|
|
{
|
|
if (it2->first == m)
|
|
it2 = si->DelModes.erase(it2);
|
|
else
|
|
++it2;
|
|
}
|
|
}
|
|
}
|
|
|
|
Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh), cidr_len(0)
|
|
{
|
|
Anope::string n, u, h;
|
|
|
|
size_t at = fh.find('@');
|
|
if (at != Anope::string::npos)
|
|
{
|
|
this->host = fh.substr(at + 1);
|
|
|
|
const Anope::string &nu = fh.substr(0, at);
|
|
|
|
size_t ex = nu.find('!');
|
|
if (ex != Anope::string::npos)
|
|
{
|
|
this->user = nu.substr(ex + 1);
|
|
this->nick = nu.substr(0, ex);
|
|
}
|
|
else
|
|
this->user = nu;
|
|
}
|
|
else
|
|
{
|
|
if (fh.find('.') != Anope::string::npos || fh.find(':') != Anope::string::npos)
|
|
this->host = fh;
|
|
else
|
|
this->nick = fh;
|
|
}
|
|
|
|
at = this->host.find('#');
|
|
if (at != Anope::string::npos)
|
|
{
|
|
this->real = this->host.substr(at + 1);
|
|
this->host = this->host.substr(0, at);
|
|
}
|
|
|
|
/* If the mask is all *'s it will match anything, so just clear it */
|
|
if (this->nick.find_first_not_of("*") == Anope::string::npos)
|
|
this->nick.clear();
|
|
|
|
if (this->user.find_first_not_of("*") == Anope::string::npos)
|
|
this->user.clear();
|
|
|
|
if (this->host.find_first_not_of("*") == Anope::string::npos)
|
|
this->host.clear();
|
|
else
|
|
{
|
|
/* Host might be a CIDR range */
|
|
size_t sl = this->host.find_last_of('/');
|
|
if (sl != Anope::string::npos)
|
|
{
|
|
const Anope::string &cidr_ip = this->host.substr(0, sl),
|
|
&cidr_range = this->host.substr(sl + 1);
|
|
|
|
sockaddrs addr(cidr_ip);
|
|
|
|
try
|
|
{
|
|
if (addr.valid() && cidr_range.is_pos_number_only())
|
|
{
|
|
this->cidr_len = convertTo<unsigned short>(cidr_range);
|
|
/* If we got here, cidr_len is a valid number.
|
|
* If cidr_len is >32 (or 128) it is handled later in
|
|
* cidr::match
|
|
*/
|
|
|
|
this->host = cidr_ip;
|
|
|
|
Log(LOG_DEBUG) << "Ban " << m << " has cidr " << this->cidr_len;
|
|
}
|
|
}
|
|
catch (const ConvertException &) { }
|
|
}
|
|
}
|
|
|
|
if (this->real.find_first_not_of("*") == Anope::string::npos)
|
|
this->real.clear();
|
|
}
|
|
|
|
const Anope::string Entry::GetMask() const
|
|
{
|
|
return this->mask;
|
|
}
|
|
|
|
const Anope::string Entry::GetNUHMask() const
|
|
{
|
|
Anope::string n = nick.empty() ? "*" : nick,
|
|
u = user.empty() ? "*" : user,
|
|
h = host.empty() ? "*" : host;
|
|
return n + "!" + u + "@" + h;
|
|
}
|
|
|
|
bool Entry::Matches(User *u, bool full) const
|
|
{
|
|
/* First check if this mode has defined any matches (usually for extbans). */
|
|
if (IRCD->IsExtbanValid(this->mask))
|
|
{
|
|
ChannelMode *cm = ModeManager::FindChannelModeByName(this->name);
|
|
if (cm != NULL && cm->type == MODE_LIST)
|
|
{
|
|
ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm);
|
|
if (cml->Matches(u, this))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* If the user's displayed host is their real host, then we can do a full match without
|
|
* having to worry about exposing a user's IP
|
|
*/
|
|
full |= u->GetDisplayedHost() == u->host;
|
|
|
|
bool ret = true;
|
|
|
|
if (!this->nick.empty() && !Anope::Match(u->nick, this->nick))
|
|
ret = false;
|
|
|
|
if (!this->user.empty() && !Anope::Match(u->GetVIdent(), this->user) && (!full || !Anope::Match(u->GetIdent(), this->user)))
|
|
ret = false;
|
|
|
|
if (this->cidr_len && full)
|
|
{
|
|
try
|
|
{
|
|
if (!cidr(this->host, this->cidr_len).match(u->ip))
|
|
ret = false;
|
|
}
|
|
catch (const SocketException &)
|
|
{
|
|
ret = false;
|
|
}
|
|
}
|
|
else if (!this->host.empty() && !Anope::Match(u->GetDisplayedHost(), this->host) && !Anope::Match(u->GetCloakedHost(), this->host) &&
|
|
(!full || (!Anope::Match(u->host, this->host) && !Anope::Match(u->ip.addr(), this->host))))
|
|
ret = false;
|
|
|
|
if (!this->real.empty() && !Anope::Match(u->realname, this->real))
|
|
ret = false;
|
|
|
|
return ret;
|
|
}
|
|
|