anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

modes.cpp (21521B)

      1 /* Mode support
      2  *
      3  * (C) 2008-2011 Adam <Adam@anope.org>
      4  * (C) 2008-2022 Anope Team <team@anope.org>
      5  *
      6  * Please read COPYING and README for further details.
      7  */
      8 
      9 #include "services.h"
     10 #include "modules.h"
     11 #include "config.h"
     12 #include "sockets.h"
     13 #include "protocol.h"
     14 #include "channels.h"
     15 #include "uplink.h"
     16 
     17 struct StackerInfo;
     18 
     19 /* List of pairs of user/channels and their stacker info */
     20 static std::map<User *, StackerInfo *> UserStackerObjects;
     21 static std::map<Channel *, StackerInfo *> ChannelStackerObjects;
     22 
     23 /* Array of all modes Anope knows about.*/
     24 static std::vector<ChannelMode *> ChannelModes;
     25 static std::vector<UserMode *> UserModes;
     26 
     27 /* Modes are in this array are at position
     28  * modechar. Additionally, status modes are in this array (again) at statuschar.
     29  */
     30 static std::vector<ChannelMode *> ChannelModesIdx;
     31 static std::vector<UserMode *> UserModesIdx;
     32 
     33 static std::map<Anope::string, ChannelMode *> ChannelModesByName;
     34 static std::map<Anope::string, UserMode *> UserModesByName;
     35 
     36 /* Sorted by status */
     37 static std::vector<ChannelModeStatus *> ChannelModesByStatus;
     38 
     39 /* Number of generic modes we support */
     40 unsigned ModeManager::GenericChannelModes = 0, ModeManager::GenericUserModes = 0;
     41 
     42 struct StackerInfo
     43 {
     44 	/* Modes to be added */
     45 	std::list<std::pair<Mode *, Anope::string> > AddModes;
     46 	/* Modes to be deleted */
     47 	std::list<std::pair<Mode *, Anope::string> > DelModes;
     48 	/* Bot this is sent from */
     49 	BotInfo *bi;
     50 
     51 	StackerInfo() : bi(NULL) { }
     52 
     53 	/** Add a mode to this object
     54 	 * @param mode The mode
     55 	 * @param set true if setting, false if unsetting
     56 	 * @param param The param for the mode
     57 	 */
     58 	void AddMode(Mode *mode, bool set, const Anope::string &param);
     59 };
     60 
     61 ChannelStatus::ChannelStatus()
     62 {
     63 }
     64 
     65 ChannelStatus::ChannelStatus(const Anope::string &m) : modes(m)
     66 {
     67 }
     68 
     69 void ChannelStatus::AddMode(char c)
     70 {
     71 	if (modes.find(c) == Anope::string::npos)
     72 		modes.append(c);
     73 }
     74 
     75 void ChannelStatus::DelMode(char c)
     76 {
     77 	modes = modes.replace_all_cs(c, "");
     78 }
     79 
     80 bool ChannelStatus::HasMode(char c) const
     81 {
     82 	return modes.find(c) != Anope::string::npos;
     83 }
     84 
     85 bool ChannelStatus::Empty() const
     86 {
     87 	return modes.empty();
     88 }
     89 
     90 void ChannelStatus::Clear()
     91 {
     92 	modes.clear();
     93 }
     94 
     95 const Anope::string &ChannelStatus::Modes() const
     96 {
     97 	return modes;
     98 }
     99 
    100 Anope::string ChannelStatus::BuildModePrefixList() const
    101 {
    102 	Anope::string ret;
    103 
    104 	for (size_t i = 0; i < modes.length(); ++i)
    105 	{
    106 		ChannelMode *cm = ModeManager::FindChannelModeByChar(modes[i]);
    107 		if (cm != NULL && cm->type == MODE_STATUS)
    108 		{
    109 			ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm);
    110 			ret += cms->symbol;
    111 		}
    112 	}
    113 
    114 	return ret;
    115 }
    116 
    117 Mode::Mode(const Anope::string &mname, ModeClass mcl, char mch, ModeType mt) : name(mname), mclass(mcl), mchar(mch), type(mt)
    118 {
    119 }
    120 
    121 Mode::~Mode()
    122 {
    123 }
    124 
    125 bool Mode::CanSet(User *u) const
    126 {
    127 	return true;
    128 }
    129 
    130 UserMode::UserMode(const Anope::string &un, char mch) : Mode(un, MC_USER, mch, MODE_REGULAR)
    131 {
    132 }
    133 
    134 UserModeParam::UserModeParam(const Anope::string &un, char mch) : UserMode(un, mch)
    135 {
    136 	this->type = MODE_PARAM;
    137 }
    138 
    139 ChannelMode::ChannelMode(const Anope::string &cm, char mch) : Mode(cm, MC_CHANNEL, mch, MODE_REGULAR)
    140 {
    141 }
    142 
    143 bool ChannelMode::CanSet(User *u) const
    144 {
    145 	EventReturn MOD_RESULT;
    146 	FOREACH_RESULT(OnCanSet, MOD_RESULT, (u, this));
    147 	return MOD_RESULT != EVENT_STOP;
    148 }
    149 
    150 ChannelMode *ChannelMode::Wrap(Anope::string &param)
    151 {
    152 	return this;
    153 }
    154 
    155 ChannelMode *ChannelMode::Unwrap(Anope::string &param)
    156 {
    157 	for (unsigned i = 0; i < listeners.size(); ++i)
    158 	{
    159 		ChannelMode *cm = listeners[i]->Unwrap(this, param);
    160 		if (cm != this)
    161 			return cm;
    162 	}
    163 
    164 	return this;
    165 }
    166 
    167 ChannelMode *ChannelMode::Unwrap(ChannelMode *, Anope::string &param)
    168 {
    169 	throw CoreException("Unwrap in channel mode");
    170 }
    171 
    172 ChannelModeList::ChannelModeList(const Anope::string &cm, char mch) : ChannelMode(cm, mch)
    173 {
    174 	this->type = MODE_LIST;
    175 }
    176 
    177 bool ChannelModeList::IsValid(Anope::string &mask) const
    178 {
    179 	if (name == "BAN" || name == "EXCEPT" || name == "INVITEOVERRIDE")
    180 		mask = IRCD->NormalizeMask(mask);
    181 	return true;
    182 }
    183 
    184 ChannelModeParam::ChannelModeParam(const Anope::string &cm, char mch, bool ma) : ChannelMode(cm, mch), minus_no_arg(ma)
    185 {
    186 	this->type = MODE_PARAM;
    187 }
    188 
    189 ChannelModeStatus::ChannelModeStatus(const Anope::string &mname, char modeChar, char msymbol, unsigned mlevel) : ChannelMode(mname, modeChar), symbol(msymbol), level(mlevel)
    190 {
    191 	this->type = MODE_STATUS;
    192 }
    193 
    194 template<typename T>
    195 ChannelModeVirtual<T>::ChannelModeVirtual(const Anope::string &mname, const Anope::string &basename) : T(mname, 0)
    196 	, base(basename)
    197 {
    198 	basech = ModeManager::FindChannelModeByName(base);
    199 	if (basech)
    200 		basech->listeners.push_back(this);
    201 }
    202 
    203 template<typename T>
    204 ChannelModeVirtual<T>::~ChannelModeVirtual()
    205 {
    206 	if (basech)
    207 	{
    208 		std::vector<ChannelMode *>::iterator it = std::find(basech->listeners.begin(), basech->listeners.end(), this);
    209 		if (it != basech->listeners.end())
    210 			basech->listeners.erase(it);
    211 	}
    212 }
    213 
    214 template<typename T>
    215 void ChannelModeVirtual<T>::Check()
    216 {
    217 	if (basech == NULL)
    218 	{
    219 		basech = ModeManager::FindChannelModeByName(base);
    220 		if (basech)
    221 			basech->listeners.push_back(this);
    222 	}
    223 }
    224 
    225 template<typename T>
    226 ChannelMode *ChannelModeVirtual<T>::Wrap(Anope::string &param)
    227 {
    228 	return basech;
    229 }
    230 
    231 template class ChannelModeVirtual<ChannelMode>;
    232 template class ChannelModeVirtual<ChannelModeList>;
    233 
    234 bool UserModeOperOnly::CanSet(User *u) const
    235 {
    236 	return u && u->HasMode("OPER");
    237 }
    238 
    239 bool UserModeNoone::CanSet(User *u) const
    240 {
    241 	return false;
    242 }
    243 
    244 bool ChannelModeKey::IsValid(Anope::string &value) const
    245 {
    246 	if (!value.empty() && value.find(':') == Anope::string::npos && value.find(',') == Anope::string::npos)
    247 		return true;
    248 
    249 	return false;
    250 }
    251 
    252 bool ChannelModeOperOnly::CanSet(User *u) const
    253 {
    254 	return u && u->HasMode("OPER");
    255 }
    256 
    257 bool ChannelModeNoone::CanSet(User *u) const
    258 {
    259 	return false;
    260 }
    261 
    262 void StackerInfo::AddMode(Mode *mode, bool set, const Anope::string &param)
    263 {
    264 	bool is_param = mode->type == MODE_PARAM;
    265 
    266 	std::list<std::pair<Mode *, Anope::string> > *list, *otherlist;
    267 	if (set)
    268 	{
    269 		list = &AddModes;
    270 		otherlist = &DelModes;
    271 	}
    272 	else
    273 	{
    274 		list = &DelModes;
    275 		otherlist = &AddModes;
    276 	}
    277 
    278 	/* Loop through the list and find if this mode is already on here */
    279 	std::list<std::pair<Mode *, Anope::string > >::iterator it, it_end;
    280 	for (it = list->begin(), it_end = list->end(); it != it_end; ++it)
    281 	{
    282 		/* The param must match too (can have multiple status or list modes), but
    283 		 * if it is a param mode it can match no matter what the param is
    284 		 */
    285 		if (it->first == mode && (is_param || param.equals_cs(it->second)))
    286 		{
    287 			list->erase(it);
    288 			/* It can only be on this list once */
    289 			break;
    290 		}
    291 	}
    292 	/* If the mode is on the other list, remove it from there (eg, we don't want +o-o Adam Adam) */
    293 	for (it = otherlist->begin(), it_end = otherlist->end(); it != it_end; ++it)
    294 	{
    295 		/* The param must match too (can have multiple status or list modes), but
    296 		 * if it is a param mode it can match no matter what the param is
    297 		 */
    298 		if (it->first == mode && (is_param || param.equals_cs(it->second)))
    299 		{
    300 			otherlist->erase(it);
    301 			return;
    302 			/* Note that we return here because this is like setting + and - on the same mode within the same
    303 			 * cycle, no change is made. This causes no problems with something like - + and -, because after the
    304 			 * second mode change the list is empty, and the third mode change starts fresh.
    305 			 */
    306 		}
    307 	}
    308 
    309 	/* Add this mode and its param to our list */
    310 	list->push_back(std::make_pair(mode, param));
    311 }
    312 
    313 static class ModePipe : public Pipe
    314 {
    315  public:
    316 	void OnNotify()
    317 	{
    318 		ModeManager::ProcessModes();
    319 	}
    320 } *modePipe;
    321 
    322 /** Get the stacker info for an item, if one doesn't exist it is created
    323  * @param Item The user/channel etc
    324  * @return The stacker info
    325  */
    326 template<typename List, typename Object>
    327 static StackerInfo *GetInfo(List &l, Object *o)
    328 {
    329 	typename List::const_iterator it = l.find(o);
    330 	if (it != l.end())
    331 		return it->second;
    332 
    333 	StackerInfo *s = new StackerInfo();
    334 	l[o] = s;
    335 	return s;
    336 }
    337 
    338 /** Build a list of mode strings to send to the IRCd from the mode stacker
    339  * @param info The stacker info for a channel or user
    340  * @return a list of strings
    341  */
    342 static std::list<Anope::string> BuildModeStrings(StackerInfo *info)
    343 {
    344 	std::list<Anope::string> ret;
    345 	std::list<std::pair<Mode *, Anope::string> >::iterator it, it_end;
    346 	Anope::string buf = "+", parambuf;
    347 	unsigned NModes = 0;
    348 
    349 	for (it = info->AddModes.begin(), it_end = info->AddModes.end(); it != it_end; ++it)
    350 	{
    351 		if (++NModes > IRCD->MaxModes || (buf.length() + parambuf.length() > IRCD->MaxLine - 100)) // Leave room for command, channel, etc
    352 		{
    353 			ret.push_back(buf + parambuf);
    354 			buf = "+";
    355 			parambuf.clear();
    356 			NModes = 1;
    357 		}
    358 
    359 		buf += it->first->mchar;
    360 
    361 		if (!it->second.empty())
    362 			parambuf += " " + it->second;
    363 	}
    364 
    365 	if (buf[buf.length() - 1] == '+')
    366 		buf.erase(buf.length() - 1);
    367 
    368 	buf += "-";
    369 	for (it = info->DelModes.begin(), it_end = info->DelModes.end(); it != it_end; ++it)
    370 	{
    371 		if (++NModes > IRCD->MaxModes || (buf.length() + parambuf.length() > IRCD->MaxLine - 100)) // Leave room for command, channel, etc
    372 		{
    373 			ret.push_back(buf + parambuf);
    374 			buf = "-";
    375 			parambuf.clear();
    376 			NModes = 1;
    377 		}
    378 
    379 		buf += it->first->mchar;
    380 
    381 		if (!it->second.empty())
    382 			parambuf += " " + it->second;
    383 	}
    384 
    385 	if (buf[buf.length() - 1] == '-')
    386 		buf.erase(buf.length() - 1);
    387 
    388 	if (!buf.empty())
    389 		ret.push_back(buf + parambuf);
    390 
    391 	return ret;
    392 }
    393 
    394 bool ModeManager::AddUserMode(UserMode *um)
    395 {
    396 	if (ModeManager::FindUserModeByChar(um->mchar) != NULL)
    397 		return false;
    398 	if (ModeManager::FindUserModeByName(um->name) != NULL)
    399 		return false;
    400 
    401 	if (um->name.empty())
    402 	{
    403 		um->name = stringify(++GenericUserModes);
    404 		Log() << "ModeManager: Added generic support for user mode " << um->mchar;
    405 	}
    406 
    407 	unsigned want = um->mchar;
    408 	if (want >= UserModesIdx.size())
    409 		UserModesIdx.resize(want + 1);
    410 	UserModesIdx[want] = um;
    411 
    412 	UserModesByName[um->name] = um;
    413 
    414 	UserModes.push_back(um);
    415 
    416 	FOREACH_MOD(OnUserModeAdd, (um));
    417 
    418 	return true;
    419 }
    420 
    421 bool ModeManager::AddChannelMode(ChannelMode *cm)
    422 {
    423 	if (cm->mchar && ModeManager::FindChannelModeByChar(cm->mchar) != NULL)
    424 		return false;
    425 	if (ModeManager::FindChannelModeByName(cm->name) != NULL)
    426 		return false;
    427 
    428 	if (cm->name.empty())
    429 	{
    430 		cm->name = stringify(++GenericChannelModes);
    431 		Log() << "ModeManager: Added generic support for channel mode " << cm->mchar;
    432 	}
    433 
    434 	if (cm->mchar)
    435 	{
    436 		unsigned want = cm->mchar;
    437 		if (want >= ChannelModesIdx.size())
    438 			ChannelModesIdx.resize(want + 1);
    439 		ChannelModesIdx[want] = cm;
    440 	}
    441 
    442 	if (cm->type == MODE_STATUS)
    443 	{
    444 		ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm);
    445 		unsigned want = cms->symbol;
    446 		if (want >= ChannelModesIdx.size())
    447 			ChannelModesIdx.resize(want + 1);
    448 		ChannelModesIdx[want] = cms;
    449 
    450 		RebuildStatusModes();
    451 	}
    452 
    453 	ChannelModesByName[cm->name] = cm;
    454 
    455 	ChannelModes.push_back(cm);
    456 
    457 	FOREACH_MOD(OnChannelModeAdd, (cm));
    458 
    459 	for (unsigned int i = 0; i < ChannelModes.size(); ++i)
    460 		ChannelModes[i]->Check();
    461 
    462 	return true;
    463 }
    464 
    465 void ModeManager::RemoveUserMode(UserMode *um)
    466 {
    467 	if (!um)
    468 		return;
    469 
    470 	unsigned want = um->mchar;
    471 	if (want >= UserModesIdx.size())
    472 		return;
    473 
    474 	if (UserModesIdx[want] != um)
    475 		return;
    476 
    477 	UserModesIdx[want] = NULL;
    478 
    479 	UserModesByName.erase(um->name);
    480 
    481 	std::vector<UserMode *>::iterator it = std::find(UserModes.begin(), UserModes.end(), um);
    482 	if (it != UserModes.end())
    483 		UserModes.erase(it);
    484 
    485 	StackerDel(um);
    486 }
    487 
    488 void ModeManager::RemoveChannelMode(ChannelMode *cm)
    489 {
    490 	if (!cm)
    491 		return;
    492 
    493 	if (cm->mchar)
    494 	{
    495 		unsigned want = cm->mchar;
    496 		if (want >= ChannelModesIdx.size())
    497 			return;
    498 
    499 		if (ChannelModesIdx[want] != cm)
    500 			return;
    501 
    502 		ChannelModesIdx[want] = NULL;
    503 	}
    504 
    505 	if (cm->type == MODE_STATUS)
    506 	{
    507 		ChannelModeStatus *cms = anope_dynamic_static_cast<ChannelModeStatus *>(cm);
    508 		unsigned want = cms->symbol;
    509 
    510 		if (want >= ChannelModesIdx.size())
    511 			return;
    512 
    513 		if (ChannelModesIdx[want] != cm)
    514 			return;
    515 
    516 		ChannelModesIdx[want] = NULL;
    517 
    518 		RebuildStatusModes();
    519 	}
    520 
    521 	ChannelModesByName.erase(cm->name);
    522 
    523 	std::vector<ChannelMode *>::iterator it = std::find(ChannelModes.begin(), ChannelModes.end(), cm);
    524 	if (it != ChannelModes.end())
    525 		ChannelModes.erase(it);
    526 
    527 	StackerDel(cm);
    528 }
    529 
    530 ChannelMode *ModeManager::FindChannelModeByChar(char mode)
    531 {
    532 	unsigned want = mode;
    533 	if (want >= ChannelModesIdx.size())
    534 		return NULL;
    535 
    536 	return ChannelModesIdx[want];
    537 }
    538 
    539 UserMode *ModeManager::FindUserModeByChar(char mode)
    540 {
    541 	unsigned want = mode;
    542 	if (want >= UserModesIdx.size())
    543 		return NULL;
    544 
    545 	return UserModesIdx[want];
    546 }
    547 
    548 ChannelMode *ModeManager::FindChannelModeByName(const Anope::string &name)
    549 {
    550 	std::map<Anope::string, ChannelMode *>::iterator it = ChannelModesByName.find(name);
    551 	if (it != ChannelModesByName.end())
    552 		return it->second;
    553 	return NULL;
    554 }
    555 
    556 UserMode *ModeManager::FindUserModeByName(const Anope::string &name)
    557 {
    558 	std::map<Anope::string, UserMode *>::iterator it = UserModesByName.find(name);
    559 	if (it != UserModesByName.end())
    560 		return it->second;
    561 	return NULL;
    562 }
    563 
    564 char ModeManager::GetStatusChar(char value)
    565 {
    566 	unsigned want = value;
    567 	if (want >= ChannelModesIdx.size())
    568 		return 0;
    569 
    570 	ChannelMode *cm = ChannelModesIdx[want];
    571 	if (cm == NULL || cm->type != MODE_STATUS || cm->mchar == value)
    572 		return 0;
    573 
    574 	return cm->mchar;
    575 }
    576 
    577 const std::vector<ChannelMode *> &ModeManager::GetChannelModes()
    578 {
    579 	return ChannelModes;
    580 }
    581 
    582 const std::vector<UserMode *> &ModeManager::GetUserModes()
    583 {
    584 	return UserModes;
    585 }
    586 
    587 const std::vector<ChannelModeStatus *> &ModeManager::GetStatusChannelModesByRank()
    588 {
    589 	return ChannelModesByStatus;
    590 }
    591 
    592 static struct StatusSort
    593 {
    594 	bool operator()(ChannelModeStatus *cm1, ChannelModeStatus *cm2) const
    595 	{
    596 		return cm1->level > cm2->level;
    597 	}
    598 } statuscmp;
    599 
    600 void ModeManager::RebuildStatusModes()
    601 {
    602 	ChannelModesByStatus.clear();
    603 	for (unsigned j = 0; j < ChannelModesIdx.size(); ++j)
    604 	{
    605 		ChannelMode *cm = ChannelModesIdx[j];
    606 
    607 		if (cm && cm->type == MODE_STATUS && std::find(ChannelModesByStatus.begin(), ChannelModesByStatus.end(), cm) == ChannelModesByStatus.end())
    608 			ChannelModesByStatus.push_back(anope_dynamic_static_cast<ChannelModeStatus *>(cm));
    609 	}
    610 	std::sort(ChannelModesByStatus.begin(), ChannelModesByStatus.end(), statuscmp);
    611 }
    612 
    613 void ModeManager::StackerAdd(BotInfo *bi, Channel *c, ChannelMode *cm, bool Set, const Anope::string &Param)
    614 {
    615 	StackerInfo *s = GetInfo(ChannelStackerObjects, c);
    616 	s->AddMode(cm, Set, Param);
    617 	if (bi)
    618 		s->bi = bi;
    619 	else
    620 		s->bi = c->ci->WhoSends();
    621 
    622 	if (!modePipe)
    623 		modePipe = new ModePipe();
    624 	modePipe->Notify();
    625 }
    626 
    627 void ModeManager::StackerAdd(BotInfo *bi, User *u, UserMode *um, bool Set, const Anope::string &Param)
    628 {
    629 	StackerInfo *s = GetInfo(UserStackerObjects, u);
    630 	s->AddMode(um, Set, Param);
    631 	if (bi)
    632 		s->bi = bi;
    633 
    634 	if (!modePipe)
    635 		modePipe = new ModePipe();
    636 	modePipe->Notify();
    637 }
    638 
    639 void ModeManager::ProcessModes()
    640 {
    641 	if (!UserStackerObjects.empty())
    642 	{
    643 		for (std::map<User *, StackerInfo *>::const_iterator it = UserStackerObjects.begin(), it_end = UserStackerObjects.end(); it != it_end; ++it)
    644 		{
    645 			User *u = it->first;
    646 			StackerInfo *s = it->second;
    647 
    648 			std::list<Anope::string> ModeStrings = BuildModeStrings(s);
    649 			for (std::list<Anope::string>::iterator lit = ModeStrings.begin(), lit_end = ModeStrings.end(); lit != lit_end; ++lit)
    650 				IRCD->SendMode(s->bi, u, "%s", lit->c_str());
    651 			delete it->second;
    652 		}
    653 		UserStackerObjects.clear();
    654 	}
    655 
    656 	if (!ChannelStackerObjects.empty())
    657 	{
    658 		for (std::map<Channel *, StackerInfo *>::const_iterator it = ChannelStackerObjects.begin(), it_end = ChannelStackerObjects.end(); it != it_end; ++it)
    659 		{
    660 			Channel *c = it->first;
    661 			StackerInfo *s = it->second;
    662 
    663 			std::list<Anope::string> ModeStrings = BuildModeStrings(s);
    664 			for (std::list<Anope::string>::iterator lit = ModeStrings.begin(), lit_end = ModeStrings.end(); lit != lit_end; ++lit)
    665 				IRCD->SendMode(s->bi, c, "%s", lit->c_str());
    666 			delete it->second;
    667 		}
    668 		ChannelStackerObjects.clear();
    669 	}
    670 }
    671 
    672 template<typename T>
    673 static void StackerDel(std::map<T *, StackerInfo *> &map, T *obj)
    674 {
    675 	typename std::map<T *, StackerInfo *>::iterator it = map.find(obj);
    676 	if (it != map.end())
    677 	{
    678 		StackerInfo *si = it->second;
    679 		std::list<Anope::string> ModeStrings = BuildModeStrings(si);
    680 		for (std::list<Anope::string>::iterator lit = ModeStrings.begin(), lit_end = ModeStrings.end(); lit != lit_end; ++lit)
    681 			IRCD->SendMode(si->bi, obj, "%s", lit->c_str());
    682 
    683 		delete si;
    684 		map.erase(it);
    685 	}
    686 }
    687 
    688 void ModeManager::StackerDel(User *u)
    689 {
    690 	::StackerDel(UserStackerObjects, u);
    691 }
    692 
    693 void ModeManager::StackerDel(Channel *c)
    694 {
    695 	::StackerDel(ChannelStackerObjects, c);
    696 }
    697 
    698 void ModeManager::StackerDel(Mode *m)
    699 {
    700 	for (std::map<User *, StackerInfo *>::const_iterator it = UserStackerObjects.begin(), it_end = UserStackerObjects.end(); it != it_end;)
    701 	{
    702 		StackerInfo *si = it->second;
    703 		++it;
    704 
    705 		for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->AddModes.begin(), it2_end = si->AddModes.end(); it2 != it2_end;)
    706 		{
    707 			if (it2->first == m)
    708 				it2 = si->AddModes.erase(it2);
    709 			else
    710 				++it2;
    711 		}
    712 
    713 		for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->DelModes.begin(), it2_end = si->DelModes.end(); it2 != it2_end;)
    714 		{
    715 			if (it2->first == m)
    716 				it2 = si->DelModes.erase(it2);
    717 			else
    718 				++it2;
    719 		}
    720 	}
    721 
    722 	for (std::map<Channel *, StackerInfo *>::const_iterator it = ChannelStackerObjects.begin(), it_end = ChannelStackerObjects.end(); it != it_end;)
    723 	{
    724 		StackerInfo *si = it->second;
    725 		++it;
    726 
    727 		for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->AddModes.begin(), it2_end = si->AddModes.end(); it2 != it2_end;)
    728 		{
    729 			if (it2->first == m)
    730 				it2 = si->AddModes.erase(it2);
    731 			else
    732 				++it2;
    733 		}
    734 
    735 		for (std::list<std::pair<Mode *, Anope::string> >::iterator it2 = si->DelModes.begin(), it2_end = si->DelModes.end(); it2 != it2_end;)
    736 		{
    737 			if (it2->first == m)
    738 				it2 = si->DelModes.erase(it2);
    739 			else
    740 				++it2;
    741 		}
    742 	}
    743 }
    744 
    745 Entry::Entry(const Anope::string &m, const Anope::string &fh) : name(m), mask(fh), cidr_len(0), family(0)
    746 {
    747 	Anope::string n, u, h;
    748 
    749 	size_t at = fh.find('@');
    750 	if (at != Anope::string::npos)
    751 	{
    752 		this->host = fh.substr(at + 1);
    753 
    754 		const Anope::string &nu = fh.substr(0, at);
    755 
    756 		size_t ex = nu.find('!');
    757 		if (ex != Anope::string::npos)
    758 		{
    759 			this->user = nu.substr(ex + 1);
    760 			this->nick = nu.substr(0, ex);
    761 		}
    762 		else
    763 			this->user = nu;
    764 	}
    765 	else
    766 	{
    767 		if (fh.find('.') != Anope::string::npos || fh.find(':') != Anope::string::npos)
    768 			this->host = fh;
    769 		else
    770 			this->nick = fh;
    771 	}
    772 
    773 	at = this->host.find('#');
    774 	if (at != Anope::string::npos)
    775 	{
    776 		this->real = this->host.substr(at + 1);
    777 		this->host = this->host.substr(0, at);
    778 	}
    779 
    780 	/* If the mask is all *'s it will match anything, so just clear it */
    781 	if (this->nick.find_first_not_of("*") == Anope::string::npos)
    782 		this->nick.clear();
    783 
    784 	if (this->user.find_first_not_of("*") == Anope::string::npos)
    785 		this->user.clear();
    786 
    787 	if (this->host.find_first_not_of("*") == Anope::string::npos)
    788 		this->host.clear();
    789 	else
    790 	{
    791 		/* Host might be a CIDR range */
    792 		size_t sl = this->host.find_last_of('/');
    793 		if (sl != Anope::string::npos)
    794 		{
    795 			const Anope::string &cidr_ip = this->host.substr(0, sl),
    796 						&cidr_range = this->host.substr(sl + 1);
    797 
    798 			sockaddrs addr(cidr_ip);
    799 
    800 			try
    801 			{
    802 				if (addr.valid() && cidr_range.is_pos_number_only())
    803 				{
    804 					this->cidr_len = convertTo<unsigned short>(cidr_range);
    805 
    806 					/* If we got here, cidr_len is a valid number. */
    807 
    808 					this->host = cidr_ip;
    809 					this->family = addr.family();
    810 
    811 					Log(LOG_DEBUG) << "Ban " << mask << " has cidr " << this->cidr_len;
    812 				}
    813 			}
    814 			catch (const ConvertException &) { }
    815 		}
    816 	}
    817 
    818 	if (this->real.find_first_not_of("*") == Anope::string::npos)
    819 		this->real.clear();
    820 }
    821 
    822 const Anope::string Entry::GetMask() const
    823 {
    824 	return this->mask;
    825 }
    826 
    827 const Anope::string Entry::GetNUHMask() const
    828 {
    829 	Anope::string n = nick.empty() ? "*" : nick,
    830 			u = user.empty() ? "*" : user,
    831 			h = host.empty() ? "*" : host,
    832 			r = real.empty() ? "" : "#" + real,
    833 			c;
    834 	switch (family)
    835 	{
    836 		case AF_INET:
    837 			if (cidr_len <= 32)
    838 				c = "/" + stringify(cidr_len);
    839 			break;
    840 		case AF_INET6:
    841 			if (cidr_len <= 128)
    842 				c = "/" + stringify(cidr_len);
    843 			break;
    844 	}
    845 
    846 	return n + "!" + u + "@" + h + c + r;
    847 }
    848 
    849 bool Entry::Matches(User *u, bool full) const
    850 {
    851 	/* First check if this mode has defined any matches (usually for extbans). */
    852 	if (IRCD->IsExtbanValid(this->mask))
    853 	{
    854 		ChannelMode *cm = ModeManager::FindChannelModeByName(this->name);
    855 		if (cm != NULL && cm->type == MODE_LIST)
    856 		{
    857 			ChannelModeList *cml = anope_dynamic_static_cast<ChannelModeList *>(cm);
    858 			if (cml->Matches(u, this))
    859 				return true;
    860 		}
    861 	}
    862 
    863 	/* If the user's displayed host is their real host, then we can do a full match without
    864 	 * having to worry about exposing a user's IP
    865 	 */
    866 	full |= u->GetDisplayedHost() == u->host;
    867 
    868 	bool ret = true;
    869 
    870 	if (!this->nick.empty() && !Anope::Match(u->nick, this->nick))
    871 		ret = false;
    872 
    873 	if (!this->user.empty() && !Anope::Match(u->GetVIdent(), this->user) && (!full || !Anope::Match(u->GetIdent(), this->user)))
    874 		ret = false;
    875 
    876 	if (this->cidr_len && full)
    877 	{
    878 		try
    879 		{
    880 			if (!cidr(this->host, this->cidr_len).match(u->ip))
    881 				ret = false;
    882 		}
    883 		catch (const SocketException &)
    884 		{
    885 			ret = false;
    886 		}
    887 	}
    888 	else if (!this->host.empty() && !Anope::Match(u->GetDisplayedHost(), this->host) && !Anope::Match(u->GetCloakedHost(), this->host) &&
    889 		(!full || (!Anope::Match(u->host, this->host) && !Anope::Match(u->ip.addr(), this->host))))
    890 		ret = false;
    891 
    892 	if (!this->real.empty() && !Anope::Match(u->realname, this->real))
    893 		ret = false;
    894 
    895 	return ret;
    896 }