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