1 /* Mode support
2  *
3  * (C) 2008-2011 Adam <Adam@anope.org>
4  * (C) 2008-2020 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 
StackerInfoStackerInfo51 	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 
ChannelStatus()61 ChannelStatus::ChannelStatus()
62 {
63 }
64 
ChannelStatus(const Anope::string & m)65 ChannelStatus::ChannelStatus(const Anope::string &m) : modes(m)
66 {
67 }
68 
AddMode(char c)69 void ChannelStatus::AddMode(char c)
70 {
71 	if (modes.find(c) == Anope::string::npos)
72 		modes.append(c);
73 }
74 
DelMode(char c)75 void ChannelStatus::DelMode(char c)
76 {
77 	modes = modes.replace_all_cs(c, "");
78 }
79 
HasMode(char c) const80 bool ChannelStatus::HasMode(char c) const
81 {
82 	return modes.find(c) != Anope::string::npos;
83 }
84 
Empty() const85 bool ChannelStatus::Empty() const
86 {
87 	return modes.empty();
88 }
89 
Clear()90 void ChannelStatus::Clear()
91 {
92 	modes.clear();
93 }
94 
Modes() const95 const Anope::string &ChannelStatus::Modes() const
96 {
97 	return modes;
98 }
99 
BuildModePrefixList() const100 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 
Mode(const Anope::string & mname,ModeClass mcl,char mch,ModeType mt)117 Mode::Mode(const Anope::string &mname, ModeClass mcl, char mch, ModeType mt) : name(mname), mclass(mcl), mchar(mch), type(mt)
118 {
119 }
120 
~Mode()121 Mode::~Mode()
122 {
123 }
124 
CanSet(User * u) const125 bool Mode::CanSet(User *u) const
126 {
127 	return true;
128 }
129 
UserMode(const Anope::string & un,char mch)130 UserMode::UserMode(const Anope::string &un, char mch) : Mode(un, MC_USER, mch, MODE_REGULAR)
131 {
132 }
133 
UserModeParam(const Anope::string & un,char mch)134 UserModeParam::UserModeParam(const Anope::string &un, char mch) : UserMode(un, mch)
135 {
136 	this->type = MODE_PARAM;
137 }
138 
ChannelMode(const Anope::string & cm,char mch)139 ChannelMode::ChannelMode(const Anope::string &cm, char mch) : Mode(cm, MC_CHANNEL, mch, MODE_REGULAR)
140 {
141 }
142 
CanSet(User * u) const143 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 
Wrap(Anope::string & param)150 ChannelMode *ChannelMode::Wrap(Anope::string &param)
151 {
152 	return this;
153 }
154 
Unwrap(Anope::string & param)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 
Unwrap(ChannelMode *,Anope::string & param)167 ChannelMode *ChannelMode::Unwrap(ChannelMode *, Anope::string &param)
168 {
169 	throw CoreException("Unwrap in channel mode");
170 }
171 
ChannelModeList(const Anope::string & cm,char mch)172 ChannelModeList::ChannelModeList(const Anope::string &cm, char mch) : ChannelMode(cm, mch)
173 {
174 	this->type = MODE_LIST;
175 }
176 
IsValid(Anope::string & mask) const177 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 
ChannelModeParam(const Anope::string & cm,char mch,bool ma)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 
ChannelModeStatus(const Anope::string & mname,char modeChar,char msymbol,unsigned mlevel)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>
ChannelModeVirtual(const Anope::string & mname,const Anope::string & basename)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>
~ChannelModeVirtual()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>
Check()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>
Wrap(Anope::string & param)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 
CanSet(User * u) const234 bool UserModeOperOnly::CanSet(User *u) const
235 {
236 	return u && u->HasMode("OPER");
237 }
238 
CanSet(User * u) const239 bool UserModeNoone::CanSet(User *u) const
240 {
241 	return false;
242 }
243 
IsValid(Anope::string & value) const244 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 
CanSet(User * u) const252 bool ChannelModeOperOnly::CanSet(User *u) const
253 {
254 	return u && u->HasMode("OPER");
255 }
256 
CanSet(User * u) const257 bool ChannelModeNoone::CanSet(User *u) const
258 {
259 	return false;
260 }
261 
AddMode(Mode * mode,bool set,const Anope::string & param)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:
OnNotify()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>
GetInfo(List & l,Object * o)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  */
BuildModeStrings(StackerInfo * info)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 
AddUserMode(UserMode * um)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 
AddChannelMode(ChannelMode * cm)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 
RemoveUserMode(UserMode * um)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 
RemoveChannelMode(ChannelMode * cm)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 
FindChannelModeByChar(char mode)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 
FindUserModeByChar(char mode)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 
FindChannelModeByName(const Anope::string & name)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 
FindUserModeByName(const Anope::string & name)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 
GetStatusChar(char value)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 
GetChannelModes()577 const std::vector<ChannelMode *> &ModeManager::GetChannelModes()
578 {
579 	return ChannelModes;
580 }
581 
GetUserModes()582 const std::vector<UserMode *> &ModeManager::GetUserModes()
583 {
584 	return UserModes;
585 }
586 
GetStatusChannelModesByRank()587 const std::vector<ChannelModeStatus *> &ModeManager::GetStatusChannelModesByRank()
588 {
589 	return ChannelModesByStatus;
590 }
591 
592 static struct StatusSort
593 {
operator ()StatusSort594 	bool operator()(ChannelModeStatus *cm1, ChannelModeStatus *cm2) const
595 	{
596 		return cm1->level > cm2->level;
597 	}
598 } statuscmp;
599 
RebuildStatusModes()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 
StackerAdd(BotInfo * bi,Channel * c,ChannelMode * cm,bool Set,const Anope::string & Param)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 
StackerAdd(BotInfo * bi,User * u,UserMode * um,bool Set,const Anope::string & Param)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 
ProcessModes()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>
StackerDel(std::map<T *,StackerInfo * > & map,T * obj)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 
StackerDel(User * u)688 void ModeManager::StackerDel(User *u)
689 {
690 	::StackerDel(UserStackerObjects, u);
691 }
692 
StackerDel(Channel * c)693 void ModeManager::StackerDel(Channel *c)
694 {
695 	::StackerDel(ChannelStackerObjects, c);
696 }
697 
StackerDel(Mode * m)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 
Entry(const Anope::string & m,const Anope::string & fh)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 
GetMask() const822 const Anope::string Entry::GetMask() const
823 {
824 	return this->mask;
825 }
826 
GetNUHMask() const827 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 
Matches(User * u,bool full) const849 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 }
897