]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Add support for ban exceptions on non-user extbans (e.g, +be r:*lol* r:lol?is?gay...
[user/henk/code/inspircd.git] / src / mode.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* $Core: libIRCDmode */
15 /* $ExtraDeps: $(RELCPPFILES) */
16 /* $ExtraObjects: modes/modeclasses.a */
17 /* $ExtraBuild: @${MAKE} -C "modes" DIRNAME="src/modes" CC="$(CC)" $(MAKEARGS) CPPFILES="$(CPPFILES)" */
18
19 #include "inspircd.h"
20 #include "inspstring.h"
21
22 /* +s (secret) */
23 #include "modes/cmode_s.h"
24 /* +p (private) */
25 #include "modes/cmode_p.h"
26 /* +b (bans) */
27 #include "modes/cmode_b.h"
28 /* +m (moderated) */
29 #include "modes/cmode_m.h"
30 /* +t (only (half) ops can change topic) */
31 #include "modes/cmode_t.h"
32 /* +n (no external messages) */
33 #include "modes/cmode_n.h"
34 /* +i (invite only) */
35 #include "modes/cmode_i.h"
36 /* +k (keyed channel) */
37 #include "modes/cmode_k.h"
38 /* +l (channel user limit) */
39 #include "modes/cmode_l.h"
40 /* +o (channel op) */
41 #include "modes/cmode_o.h"
42 /* +h (channel halfop) */
43 #include "modes/cmode_h.h"
44 /* +v (channel voice) */
45 #include "modes/cmode_v.h"
46 /* +s (server notices) */
47 #include "modes/umode_s.h"
48 /* +w (see wallops) */
49 #include "modes/umode_w.h"
50 /* +i (invisible) */
51 #include "modes/umode_i.h"
52 /* +o (operator) */
53 #include "modes/umode_o.h"
54 /* +n (notice mask - our implementation of snomasks) */
55 #include "modes/umode_n.h"
56
57 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired)
58         : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
59 {
60 }
61
62 ModeHandler::~ModeHandler()
63 {
64 }
65
66 bool ModeHandler::IsListMode()
67 {
68         return list;
69 }
70
71 char ModeHandler::GetNeededPrefix()
72 {
73         return prefixneeded;
74 }
75
76 void ModeHandler::SetNeededPrefix(char needsprefix)
77 {
78         prefixneeded = needsprefix;
79 }
80
81 unsigned int ModeHandler::GetPrefixRank()
82 {
83         return 0;
84 }
85
86 unsigned int ModeHandler::GetCount()
87 {
88         return 0;
89 }
90
91 void ModeHandler::ChangeCount(int modifier)
92 {
93         count += modifier;
94         ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
95 }
96
97 ModeType ModeHandler::GetModeType()
98 {
99         return m_type;
100 }
101
102 bool ModeHandler::NeedsOper()
103 {
104         return oper;
105 }
106
107 char ModeHandler::GetPrefix()
108 {
109         return prefix;
110 }
111
112 int ModeHandler::GetNumParams(bool adding)
113 {
114         return adding ? n_params_on : n_params_off;
115 }
116
117 char ModeHandler::GetModeChar()
118 {
119         return mode;
120 }
121
122 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
123 {
124         return MODEACTION_DENY;
125 }
126
127 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
128 {
129         if (dest)
130         {
131                 return std::make_pair(dest->IsModeSet(this->mode), "");
132         }
133         else
134         {
135                 return std::make_pair(channel->IsModeSet(this->mode), "");
136         }
137 }
138
139 void ModeHandler::DisplayList(User*, Channel*)
140 {
141 }
142
143 void ModeHandler::DisplayEmptyList(User*, Channel*)
144 {
145 }
146
147 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
148 {
149         return (ours < theirs);
150 }
151
152 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
153 {
154 }
155
156 SimpleUserModeHandler::~SimpleUserModeHandler()
157 {
158 }
159
160 SimpleChannelModeHandler::~SimpleChannelModeHandler()
161 {
162 }
163
164 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
165 {
166 }
167
168 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
169 {
170         /* Only opers can change other users modes */
171         if (source != dest)
172                 return MODEACTION_DENY;
173
174         if (adding)
175         {
176                 if (!dest->IsModeSet(this->GetModeChar()))
177                 {
178                         dest->SetMode(this->GetModeChar(),true);
179                         return MODEACTION_ALLOW;
180                 }
181         }
182         else
183         {
184                 if (dest->IsModeSet(this->GetModeChar()))
185                 {
186                         dest->SetMode(this->GetModeChar(),false);
187                         return MODEACTION_ALLOW;
188                 }
189         }
190
191         return MODEACTION_DENY;
192 }
193
194
195 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool servermode)
196 {
197         if (adding)
198         {
199                 if (!channel->IsModeSet(this->GetModeChar()))
200                 {
201                         channel->SetMode(this->GetModeChar(),true);
202                         return MODEACTION_ALLOW;
203                 }
204         }
205         else
206         {
207                 if (channel->IsModeSet(this->GetModeChar()))
208                 {
209                         channel->SetMode(this->GetModeChar(),false);
210                         return MODEACTION_ALLOW;
211                 }
212         }
213
214         return MODEACTION_DENY;
215 }
216
217 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
218 {
219 }
220
221 ModeWatcher::~ModeWatcher()
222 {
223 }
224
225 char ModeWatcher::GetModeChar()
226 {
227         return mode;
228 }
229
230 ModeType ModeWatcher::GetModeType()
231 {
232         return m_type;
233 }
234
235 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
236 {
237         return true;
238 }
239
240 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
241 {
242 }
243
244 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
245 {
246         User *d;
247         if ((!user) || (!dest) || (!chan) || (!*dest))
248         {
249                 return NULL;
250         }
251         d = ServerInstance->FindNick(dest);
252         if (!d)
253         {
254                 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), dest);
255                 return NULL;
256         }
257         return d;
258 }
259
260 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
261 {
262         if (!chan)
263                 return "";
264
265         UCListIter n = d->chans.find(chan);
266         if (n != d->chans.end())
267         {
268                 if (n->second & MASK)
269                 {
270                         return "";
271                 }
272                 n->second = n->second | MASK;
273                 switch (MASK)
274                 {
275                         case UCMODE_OP:
276                                 n->first->AddOppedUser(d);
277                         break;
278                         case UCMODE_HOP:
279                                 n->first->AddHalfoppedUser(d);
280                         break;
281                         case UCMODE_VOICE:
282                                 n->first->AddVoicedUser(d);
283                         break;
284                 }
285                 return d->nick.c_str();
286         }
287         return "";
288 }
289
290 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
291 {
292         if (!chan)
293                 return "";
294
295         UCListIter n = d->chans.find(chan);
296         if (n != d->chans.end())
297         {
298                 if ((n->second & MASK) == 0)
299                 {
300                         return "";
301                 }
302                 n->second ^= MASK;
303                 switch (MASK)
304                 {
305                         case UCMODE_OP:
306                                 n->first->DelOppedUser(d);
307                         break;
308                         case UCMODE_HOP:
309                                 n->first->DelHalfoppedUser(d);
310                         break;
311                         case UCMODE_VOICE:
312                                 n->first->DelVoicedUser(d);
313                         break;
314                 }
315                 return d->nick.c_str();
316         }
317         return "";
318 }
319
320 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
321 {
322         if (targetchannel)
323         {
324                 /* Display channel's current mode string */
325                 user->WriteNumeric(324, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
326                 user->WriteNumeric(329, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
327                 return;
328         }
329         else if (targetuser)
330         {
331                 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
332                 {
333                         user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), text);
334                         return;
335                 }
336
337                 if ((targetuser == user) || (IS_OPER(user)))
338                 {
339                         /* Display user's current mode string */
340                         user->WriteNumeric(221, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
341                         if (IS_OPER(targetuser))
342                                 user->WriteNumeric(8, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
343                         return;
344                 }
345                 else
346                 {
347                         user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick.c_str());
348                         return;
349                 }
350         }
351
352         /* No such nick/channel */
353         user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), text);
354         return;
355 }
356
357 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
358 {
359         std::string target = parameters[0];
360         ModeType type = MODETYPE_USER;
361         unsigned char mask = 0;
362         Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
363         User* targetuser  = ServerInstance->FindNick(parameters[0]);
364
365         LastParse.clear();
366
367         /* Special case for displaying the list for listmodes,
368          * e.g. MODE #chan b, or MODE #chan +b without a parameter
369          */
370         if ((targetchannel) && (parameters.size() == 2))
371         {
372                 const char* mode = parameters[1].c_str();
373                 int nonlistmodes_found = 0;
374
375                 seq++;
376
377                 mask = MASK_CHANNEL;
378                 
379                 while (mode && *mode)
380                 {
381                         unsigned char mletter = *mode;
382
383                         if (*mode == '+')
384                         {
385                                 mode++;
386                                 continue;
387                         }
388                         
389                         /* Ensure the user doesnt request the same mode twice,
390                          * so they cant flood themselves off out of idiocy.
391                          */
392                         if (sent[mletter] != seq)
393                         {
394                                 sent[mletter] = seq;
395                         }
396                         else
397                         {
398                                 mode++;
399                                 continue;
400                         }
401
402                         ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
403                         bool display = true;
404
405                         if ((mh) && (mh->IsListMode()))
406                         {
407                                 int MOD_RESULT = 0;
408                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
409                                 if (MOD_RESULT == ACR_DENY)
410                                 {
411                                         mode++;
412                                         continue;
413                                 }
414
415                                 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
416                                 {
417                                         user->WriteNumeric(482, "%s %s :Only half-operators and above may view the +%c list",user->nick.c_str(), targetchannel->name.c_str(), *mode++);
418                                         mh->DisplayEmptyList(user, targetchannel);
419                                         continue;
420                                 }
421
422                                 /** See below for a description of what craq this is :D
423                                  */
424                                 unsigned char handler_id = (*mode - 65) | mask;
425
426                                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
427                                 {
428                                         std::string dummyparam;
429                                         
430                                         if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
431                                                 display = false;
432                                 }
433
434                                 if (display)
435                                         mh->DisplayList(user, targetchannel);
436                         }
437                         else
438                                 nonlistmodes_found++;
439
440                         mode++;
441                 }
442
443                 /* We didnt have any modes that were non-list, we can return here */
444                 if (!nonlistmodes_found)
445                         return;
446         }
447
448         if (parameters.size() == 1)
449         {
450                 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
451         }
452         else if (parameters.size() > 1)
453         {
454                 bool SkipAccessChecks = false;
455
456                 if (targetchannel)
457                 {
458                         type = MODETYPE_CHANNEL;
459                         mask = MASK_CHANNEL;
460
461                         /* Extra security checks on channel modes
462                          * (e.g. are they a (half)op?
463                          */
464
465                         if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
466                         {
467                                 /* We don't have halfop */
468                                 int MOD_RESULT = 0;
469                                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
470                                 if (MOD_RESULT == ACR_DENY)
471                                         return;
472                                 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
473                         }
474                 }
475                 else if (targetuser)
476                 {
477                         type = MODETYPE_USER;
478                         mask = MASK_USER;
479                         if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
480                         {
481                                 user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick.c_str());
482                                 return;
483                         }
484                 }
485                 else
486                 {
487                         /* No such nick/channel */
488                         user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
489                         return;
490                 }
491
492                 std::string mode_sequence = parameters[1];
493                 std::string parameter;
494                 std::ostringstream parameter_list;
495                 std::string output_sequence;
496                 bool adding = true, state_change = false;
497                 unsigned char handler_id = 0;
498                 unsigned int parameter_counter = 2; /* Index of first parameter */
499                 unsigned int parameter_count = 0;
500                 bool last_successful_state_change = false;
501
502                 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
503                 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
504                         mode_sequence.insert(0, "+");
505
506                 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
507                 {
508                         unsigned char modechar = *letter;
509
510                         switch (modechar)
511                         {
512                                 /* NB:
513                                  * For + and - mode characters, we don't just stick the character into the output sequence.
514                                  * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
515                                  * appearing in the output sequence, we store a flag which says there was a state change,
516                                  * which is set on any + or -, however, the + or - that we finish on is only appended to
517                                  * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
518                                  */
519                                 case '+':
520                                         /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
521                                          * however, will allow the + if it is the first item in the sequence, regardless.
522                                          */
523                                         if ((!adding) || (!output_sequence.length()))
524                                                 state_change = true;
525                                         adding = true;
526                                         if (!output_sequence.length())
527                                                 last_successful_state_change = false;
528                                         continue;
529                                 break;
530                                 case '-':
531                                         if ((adding) || (!output_sequence.length()))
532                                                 state_change = true;
533                                         adding = false;
534                                         if (!output_sequence.length())
535                                                 last_successful_state_change = true;
536                                         continue;
537                                 break;
538                                 default:
539
540                                         /**
541                                          * Watch carefully for the sleight of hand trick.
542                                          * 65 is the ascii value of 'A'. We take this from
543                                          * the char we're looking at to get a number between
544                                          * 1 and 127. We then logic-or it to get the hashed
545                                          * position, dependent on wether its a channel or
546                                          * a user mode. This is a little stranger, but a lot
547                                          * faster, than using a map of pairs.
548                                          */
549                                         handler_id = (modechar - 65) | mask;
550
551                                         if (modehandlers[handler_id])
552                                         {
553                                                 bool abort = false;
554
555                                                 if (modehandlers[handler_id]->GetModeType() == type)
556                                                 {
557                                                         int MOD_RESULT = 0;
558
559                                                         if (modehandlers[handler_id]->GetNumParams(adding))
560                                                         {
561                                                                 /* This mode expects a parameter, do we have any parameters left in our list to use? */
562                                                                 if (parameter_counter < parameters.size())
563                                                                 {
564                                                                         parameter = parameters[parameter_counter++];
565
566                                                                         /* Yerk, invalid! */
567                                                                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
568                                                                                 parameter.clear();
569                                                                 }
570                                                                 else
571                                                                 {
572                                                                         /* No parameter, continue to the next mode */
573                                                                         continue;
574                                                                 }
575
576                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
577                                                         }
578                                                         else
579                                                         {
580                                                                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
581                                                         }
582
583                                                         if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
584                                                                 continue;
585
586                                                         if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
587                                                         {
588                                                                 /* Check access to this mode character */
589                                                                 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
590                                                                 {
591                                                                         char needed = modehandlers[handler_id]->GetNeededPrefix();
592                                                                         ModeHandler* prefixmode = FindPrefix(needed);
593
594                                                                         /* If the mode defined by the handler is not '\0', but the handler for it
595                                                                          * cannot be found, they probably dont have the right module loaded to implement
596                                                                          * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
597                                                                          * Revert to checking against the minimum core prefix, '%'.
598                                                                          */
599                                                                         if (needed && !prefixmode)
600                                                                                 prefixmode = FindPrefix('%');
601                                                 
602                                                                         unsigned int neededrank = prefixmode->GetPrefixRank();
603                                                                         /* Compare our rank on the channel against the rank of the required prefix,
604                                                                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
605                                                                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
606                                                                          * first, so we don't need to iterate, we just look up the first instead.
607                                                                          */
608                                                                         std::string modestring = targetchannel->GetAllPrefixChars(user);
609                                                                         char ml = (modestring.empty() ? '\0' : modestring[0]);
610                                                                         ModeHandler* ourmode = FindPrefix(ml);
611                                                                         if (!ourmode || ourmode->GetPrefixRank() < neededrank)
612                                                                         {
613                                                                                 /* Bog off */
614                                                                                 user->WriteNumeric(482, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
615                                                                                                 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
616                                                                                 continue;
617                                                                         }
618                                                                 }
619                                                         }
620
621                                                         bool had_parameter = !parameter.empty();
622                                                                 
623                                                         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
624                                                         {
625                                                                 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
626                                                                 {
627                                                                         abort = true;
628                                                                         break;
629                                                                 }
630                                                                 /* A module whacked the parameter completely, and there was one. abort. */
631                                                                 if ((had_parameter) && (parameter.empty()))
632                                                                 {
633                                                                         abort = true;
634                                                                         break;
635                                                                 }
636                                                         }
637
638                                                         if (abort)
639                                                                 continue;
640
641                                                         /* It's an oper only mode, check if theyre an oper. If they arent,
642                                                          * eat any parameter that  came with the mode, and continue to next
643                                                          */
644                                                         if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
645                                                         {
646                                                                 if (IS_OPER(user))
647                                                                 {
648                                                                         user->WriteNumeric(481, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
649                                                                                         user->nick.c_str(),
650                                                                                         user->oper.c_str(),
651                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
652                                                                                         modehandlers[handler_id]->GetModeChar());
653                                                                 }
654                                                                 else
655                                                                 {
656                                                                         user->WriteNumeric(481, "%s :Permission Denied - Only operators may set %s mode %c",
657                                                                                         user->nick.c_str(),
658                                                                                         type == MODETYPE_CHANNEL ? "channel" : "user",
659                                                                                         modehandlers[handler_id]->GetModeChar());
660                                                                 }
661                                                                 continue;
662                                                         }
663
664                                                         /* Call the handler for the mode */
665                                                         ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
666
667                                                         if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
668                                                         {
669                                                                 /* The handler nuked the parameter and they are supposed to have one.
670                                                                  * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
671                                                                  * so we bail to the next mode character.
672                                                                  */
673                                                                 continue;
674                                                         }
675
676                                                         if (ma == MODEACTION_ALLOW)
677                                                         {
678                                                                 /* We're about to output a valid mode letter - was there previously a pending state-change? */
679                                                                 if (state_change)
680                                                                 {
681                                                                         if (adding != last_successful_state_change)
682                                                                                 output_sequence.append(adding ? "+" : "-");
683                                                                         last_successful_state_change = adding;
684                                                                 }
685                                                                 
686                                                                 /* Add the mode letter */
687                                                                 output_sequence.push_back(modechar);
688
689                                                                 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
690
691                                                                 /* Is there a valid parameter for this mode? If so add it to the parameter list */
692                                                                 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
693                                                                 {
694                                                                         parameter_list << " " << parameter;
695                                                                         parameter_count++;
696                                                                         /* Does this mode have a prefix? */
697                                                                         if (modehandlers[handler_id]->GetPrefix() && targetchannel)
698                                                                         {
699                                                                                 User* user_to_prefix = ServerInstance->FindNick(parameter);
700                                                                                 if (user_to_prefix)
701                                                                                         targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
702                                                                                                         modehandlers[handler_id]->GetPrefixRank(), adding);
703                                                                         }
704                                                                 }
705
706                                                                 /* Call all the AfterMode events in the mode watchers for this mode */
707                                                                 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
708                                                                         (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
709
710                                                                 /* Reset the state change flag */
711                                                                 state_change = false;
712
713                                                                 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
714                                                                                 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
715                                                                 {
716                                                                         /* We cant have a mode sequence this long */
717                                                                         letter = mode_sequence.end() - 1;
718                                                                         continue;
719                                                                 }
720                                                         }
721                                                 }
722                                         }
723                                         else
724                                         {
725                                                 /* No mode handler? Unknown mode character then. */
726                                                 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
727                                         }
728                                 break;
729                         }
730                 }
731
732                 /* Was there at least one valid mode in the sequence? */
733                 if (!output_sequence.empty())
734                 {
735                         if (servermode)
736                         {
737                                 if (type == MODETYPE_CHANNEL)
738                                 {
739                                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
740                                         this->LastParse = targetchannel->name;
741                                 }
742                                 else
743                                 {
744                                         targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
745                                         this->LastParse = targetuser->nick;
746                                 }
747                         }
748                         else
749                         {
750                                 if (type == MODETYPE_CHANNEL)
751                                 {
752                                         targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
753                                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
754                                         this->LastParse = targetchannel->name;
755                                 }
756                                 else
757                                 {
758                                         user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
759                                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
760                                         this->LastParse = targetuser->nick;
761                                 }
762                         }
763
764                         LastParse.append(" ");
765                         LastParse.append(output_sequence);
766                         LastParse.append(parameter_list.str());
767                 }
768         }
769 }
770
771 const std::string& ModeParser::GetLastParse()
772 {
773         return LastParse;
774 }
775
776 void ModeParser::CleanMask(std::string &mask)
777 {
778         std::string::size_type pos_of_pling = mask.find_first_of('!');
779         std::string::size_type pos_of_at = mask.find_first_of('@');
780         std::string::size_type pos_of_dot = mask.find_first_of('.');
781         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
782
783         if (mask.length() >= 2 && mask[1] == ':')
784                 return; // if it's an extban, don't even try guess how it needs to be formed.
785
786         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
787         {
788                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
789                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
790                 {
791                         /* It has no '.' in it, it must be a nick. */
792                         mask.append("!*@*");
793                 }
794                 else
795                 {
796                         /* Got a dot in it? Has to be a host */
797                         mask = "*!*@" + mask;
798                 }
799         }
800         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
801         {
802                 /* Has an @ but no !, its a user@host */
803                  mask = "*!" + mask;
804         }
805         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
806         {
807                 /* Has a ! but no @, it must be a nick!ident */
808                 mask.append("@*");
809         }
810 }
811
812 bool ModeParser::AddMode(ModeHandler* mh)
813 {
814         unsigned char mask = 0;
815         unsigned char pos = 0;
816
817         /* Yes, i know, this might let people declare modes like '_' or '^'.
818          * If they do that, thats their problem, and if i ever EVER see an
819          * official InspIRCd developer do that, i'll beat them with a paddle!
820          */
821         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
822                 return false;
823
824         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
825          * A mode prefix of ':' will fuck up both server to server, and client to server.
826          * A mode prefix of '#' will mess up /whois and /privmsg
827          */
828         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
829                 return false;
830
831         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
832         pos = (mh->GetModeChar()-65) | mask;
833
834         if (modehandlers[pos])
835                 return false;
836
837         modehandlers[pos] = mh;
838         return true;
839 }
840
841 bool ModeParser::DelMode(ModeHandler* mh)
842 {
843         unsigned char mask = 0;
844         unsigned char pos = 0;
845
846         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
847                 return false;
848
849         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
850         pos = (mh->GetModeChar()-65) | mask;
851
852         if (!modehandlers[pos])
853                 return false;
854
855         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
856          * To stack here we have to make the algorithm slower. Discuss.
857          */
858         switch (mh->GetModeType())
859         {
860                 case MODETYPE_USER:
861                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
862                         {
863                                 mh->RemoveMode(i->second);
864                         }
865                 break;
866                 case MODETYPE_CHANNEL:
867                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
868                         {
869                                 mh->RemoveMode(i->second);
870                         }
871                 break;
872         }
873
874         modehandlers[pos] = NULL;
875
876         return true;
877 }
878
879 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
880 {
881         unsigned char mask = 0;
882         unsigned char pos = 0;
883
884         if ((modeletter < 'A') || (modeletter > 'z'))
885                 return NULL;
886
887         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
888         pos = (modeletter-65) | mask;
889
890         return modehandlers[pos];
891 }
892
893 std::string ModeParser::UserModeList()
894 {
895         char modestr[256];
896         int pointer = 0;
897
898         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
899         {
900                 unsigned char pos = (mode-65) | MASK_USER;
901
902                 if (modehandlers[pos])
903                         modestr[pointer++] = mode;
904         }
905         modestr[pointer++] = 0;
906         return modestr;
907 }
908
909 std::string ModeParser::ChannelModeList()
910 {
911         char modestr[256];
912         int pointer = 0;
913
914         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
915         {
916                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
917                         continue;
918
919                 unsigned char pos = (mode-65) | MASK_CHANNEL;
920
921                 if (modehandlers[pos])
922                         modestr[pointer++] = mode;
923         }
924         modestr[pointer++] = 0;
925         return modestr;
926 }
927
928 std::string ModeParser::ParaModeList()
929 {
930         char modestr[256];
931         int pointer = 0;
932
933         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
934         {
935                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
936                         continue;
937
938                 unsigned char pos = (mode-65) | MASK_CHANNEL;
939
940                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
941                         modestr[pointer++] = mode;
942         }
943         modestr[pointer++] = 0;
944         return modestr;
945 }
946
947 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
948 {
949         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
950         {
951                 unsigned char pos = (mode-65) | MASK_CHANNEL;
952
953                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
954                 {
955                         return modehandlers[pos];
956                 }
957         }
958         return NULL;
959 }
960
961 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
962 {
963         std::string types;
964         std::string pars;
965
966         if (!channel || !user)
967                 return "";
968
969         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
970         {
971                 unsigned char pos = (mode-65) | MASK_CHANNEL;
972                 ModeHandler* mh = modehandlers[pos];
973                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
974                 {
975                         ModePair ret;
976                         ret = mh->ModeSet(NULL, user, channel, user->nick);
977                         if ((ret.first) && (ret.second == user->nick))
978                         {
979                                 if (nick_suffix)
980                                 {
981                                         pars.append(" ");
982                                         pars.append(user->nick);
983                                 }
984                                 types.push_back(mh->GetModeChar());
985                         }
986                 }
987         }
988
989         if (nick_suffix)
990                 return types+pars;
991         else
992                 return types;
993 }
994
995 std::string ModeParser::ChanModes()
996 {
997         std::string type1;      /* Listmodes EXCEPT those with a prefix */
998         std::string type2;      /* Modes that take a param when adding or removing */
999         std::string type3;      /* Modes that only take a param when adding */
1000         std::string type4;      /* Modes that dont take a param */
1001
1002         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1003         {
1004                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1005                         continue;
1006
1007                 unsigned char pos = (mode-65) | MASK_CHANNEL;
1008                  /* One parameter when adding */
1009                 if (modehandlers[pos])
1010                 {       
1011                         if (modehandlers[pos]->GetNumParams(true))
1012                         {
1013                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1014                                 {
1015                                         type1 += modehandlers[pos]->GetModeChar();
1016                                 }
1017                                 else
1018                                 {
1019                                         /* ... and one parameter when removing */
1020                                         if (modehandlers[pos]->GetNumParams(false))
1021                                         {
1022                                                 /* But not a list mode */
1023                                                 if (!modehandlers[pos]->GetPrefix())
1024                                                 {
1025                                                         type2 += modehandlers[pos]->GetModeChar();
1026                                                 }
1027                                         }
1028                                         else
1029                                         {
1030                                                 /* No parameters when removing */
1031                                                 type3 += modehandlers[pos]->GetModeChar();
1032                                         }
1033                                 }
1034                         }
1035                         else
1036                         {
1037                                 type4 += modehandlers[pos]->GetModeChar();
1038                         }
1039                 }
1040                          
1041         }
1042
1043         return type1 + "," + type2 + "," + type3 + "," + type4;
1044 }
1045
1046 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1047 {       
1048         return one.second > two.second;
1049 }
1050
1051 std::string ModeParser::BuildPrefixes()
1052 {
1053         std::string mletters;
1054         std::string mprefixes;
1055         pfxcontainer pfx;
1056         std::map<char,char> prefix_to_mode;
1057
1058         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1059         {
1060                 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1061                         continue;
1062
1063                 unsigned char pos = (mode-65) | MASK_CHANNEL;
1064
1065                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1066                 {
1067                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1068                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1069                 }
1070         }
1071
1072         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1073
1074         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1075         {
1076                 mletters = mletters + n->first;
1077                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1078         }
1079
1080         return "(" + mprefixes + ")" + mletters;
1081 }
1082
1083 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1084 {
1085         unsigned char mask = 0;
1086         unsigned char pos = 0;
1087
1088         if (!mw)
1089                 return false;
1090
1091         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1092                 return false;
1093
1094         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1095         pos = (mw->GetModeChar()-65) | mask;
1096
1097         modewatchers[pos].push_back(mw);
1098
1099         return true;
1100 }
1101
1102 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1103 {
1104         unsigned char mask = 0;
1105         unsigned char pos = 0;
1106
1107         if (!mw)
1108                 return false;
1109
1110         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1111                 return false;
1112
1113         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1114         pos = (mw->GetModeChar()-65) | mask;
1115
1116         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1117
1118         if (a == modewatchers[pos].end())
1119         {
1120                 return false;
1121         }
1122
1123         modewatchers[pos].erase(a);
1124
1125         return true;
1126 }
1127
1128 /** This default implementation can remove simple user modes
1129  */
1130 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1131 {
1132         char moderemove[MAXBUF];
1133         std::vector<std::string> parameters;
1134
1135         if (user->IsModeSet(this->GetModeChar()))
1136         {
1137                 if (stack)
1138                 {
1139                         stack->Push(this->GetModeChar());
1140                 }
1141                 else
1142                 {
1143                         sprintf(moderemove,"-%c",this->GetModeChar());
1144                         parameters.push_back(user->nick);
1145                         parameters.push_back(moderemove);
1146                         ServerInstance->Parser->CallHandler("MODE", parameters, user);
1147                 }
1148         }
1149 }
1150
1151 /** This default implementation can remove simple channel modes
1152  * (no parameters)
1153  */
1154 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1155 {
1156         char moderemove[MAXBUF];
1157         std::vector<std::string> parameters;
1158
1159         if (channel->IsModeSet(this->GetModeChar()))
1160         {
1161                 if (stack)
1162                 {
1163                         stack->Push(this->GetModeChar());
1164                 }
1165                 else
1166                 {
1167                         sprintf(moderemove,"-%c",this->GetModeChar());
1168                         parameters.push_back(channel->name);
1169                         parameters.push_back(moderemove);
1170                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1171                 }
1172         }
1173 }
1174
1175 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1176 {
1177         ModeHandler* modes[] =
1178         {
1179                 new ModeChannelSecret(Instance),
1180                 new ModeChannelPrivate(Instance),
1181                 new ModeChannelModerated(Instance),
1182                 new ModeChannelTopicOps(Instance),
1183                 new ModeChannelNoExternal(Instance),
1184                 new ModeChannelInviteOnly(Instance),
1185                 new ModeChannelKey(Instance),
1186                 new ModeChannelLimit(Instance),
1187                 new ModeChannelBan(Instance),
1188                 new ModeChannelOp(Instance),
1189                 new ModeChannelHalfOp(Instance),
1190                 new ModeChannelVoice(Instance),
1191                 new ModeUserServerNotice(Instance),
1192                 new ModeUserWallops(Instance),
1193                 new ModeUserInvisible(Instance),
1194                 new ModeUserOperator(Instance),
1195                 new ModeUserServerNoticeMask(Instance),
1196                 NULL
1197         };
1198
1199         /* Clear mode handler list */
1200         memset(modehandlers, 0, sizeof(modehandlers));
1201
1202         /* Last parse string */
1203         LastParse.clear();
1204
1205         /* Initialise the RFC mode letters */
1206         for (int index = 0; modes[index]; index++)
1207                 this->AddMode(modes[index]);
1208
1209         seq = 0;
1210         memset(&sent, 0, 256);
1211 }