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 ¶m);
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 ¶m)
151 {
152 return this;
153 }
154
Unwrap(Anope::string & param)155 ChannelMode *ChannelMode::Unwrap(Anope::string ¶m)
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 ¶m)
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 ¶m)
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 ¶m)
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