]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Remove mode counter, not reliable and only used for umode +i
[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 #include "inspircd.h"
15 #include "inspstring.h"
16
17 /* +s (secret) */
18 #include "modes/cmode_s.h"
19 /* +p (private) */
20 #include "modes/cmode_p.h"
21 /* +b (bans) */
22 #include "modes/cmode_b.h"
23 /* +m (moderated) */
24 #include "modes/cmode_m.h"
25 /* +t (only (half) ops can change topic) */
26 #include "modes/cmode_t.h"
27 /* +n (no external messages) */
28 #include "modes/cmode_n.h"
29 /* +i (invite only) */
30 #include "modes/cmode_i.h"
31 /* +k (keyed channel) */
32 #include "modes/cmode_k.h"
33 /* +l (channel user limit) */
34 #include "modes/cmode_l.h"
35 /* +o (channel op) */
36 #include "modes/cmode_o.h"
37 /* +v (channel voice) */
38 #include "modes/cmode_v.h"
39 /* +w (see wallops) */
40 #include "modes/umode_w.h"
41 /* +i (invisible) */
42 #include "modes/umode_i.h"
43 /* +o (operator) */
44 #include "modes/umode_o.h"
45 /* +s (server notice masks) */
46 #include "modes/umode_s.h"
47
48 ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modeletter, ParamSpec Params, ModeType type)
49         : ServiceProvider(Creator, Name, type == MODETYPE_CHANNEL ? SERVICE_CMODE : SERVICE_UMODE), m_paramtype(TR_TEXT),
50         parameters_taken(Params), mode(modeletter), prefix(0), oper(false),
51         list(false), m_type(type), levelrequired(HALFOP_VALUE)
52 {
53 }
54
55 CullResult ModeHandler::cull()
56 {
57         if (ServerInstance->Modes)
58                 ServerInstance->Modes->DelMode(this);
59         return classbase::cull();
60 }
61
62 ModeHandler::~ModeHandler()
63 {
64         if (ServerInstance && ServerInstance->Modes && ServerInstance->Modes->FindMode(mode, m_type) == this)
65                 ServerInstance->Logs->Log("MODE", ERROR, "ERROR: Destructor for mode %c called while still registered", mode);
66 }
67
68 bool ModeHandler::IsListMode()
69 {
70         return list;
71 }
72
73 unsigned int ModeHandler::GetPrefixRank()
74 {
75         return 0;
76 }
77
78 int ModeHandler::GetNumParams(bool adding)
79 {
80         switch (parameters_taken)
81         {
82                 case PARAM_ALWAYS:
83                         return 1;
84                 case PARAM_SETONLY:
85                         return adding ? 1 : 0;
86                 case PARAM_NONE:
87                         break;
88         }
89         return 0;
90 }
91
92 std::string ModeHandler::GetUserParameter(User* user)
93 {
94         return "";
95 }
96
97 ModResult ModeHandler::AccessCheck(User*, Channel*, std::string &, bool)
98 {
99         return MOD_RES_PASSTHRU;
100 }
101
102 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool)
103 {
104         return MODEACTION_DENY;
105 }
106
107 void ModeHandler::DisplayList(User*, Channel*)
108 {
109 }
110
111 void ModeHandler::DisplayEmptyList(User*, Channel*)
112 {
113 }
114
115 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
116 {
117 }
118
119 bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ours, Channel*)
120 {
121         return (theirs < ours);
122 }
123
124 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
125 {
126         if (adding)
127         {
128                 if (!dest->IsModeSet(this->GetModeChar()))
129                 {
130                         dest->SetMode(this->GetModeChar(),true);
131                         return MODEACTION_ALLOW;
132                 }
133         }
134         else
135         {
136                 if (dest->IsModeSet(this->GetModeChar()))
137                 {
138                         dest->SetMode(this->GetModeChar(),false);
139                         return MODEACTION_ALLOW;
140                 }
141         }
142
143         return MODEACTION_DENY;
144 }
145
146
147 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
148 {
149         if (adding)
150         {
151                 if (!channel->IsModeSet(this->GetModeChar()))
152                 {
153                         channel->SetMode(this->GetModeChar(),true);
154                         return MODEACTION_ALLOW;
155                 }
156         }
157         else
158         {
159                 if (channel->IsModeSet(this->GetModeChar()))
160                 {
161                         channel->SetMode(this->GetModeChar(),false);
162                         return MODEACTION_ALLOW;
163                 }
164         }
165
166         return MODEACTION_DENY;
167 }
168
169 ModeAction ParamChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
170 {
171         if (adding && !ParamValidate(parameter))
172                 return MODEACTION_DENY;
173         std::string now = channel->GetModeParameter(this);
174         if (parameter == now)
175                 return MODEACTION_DENY;
176         if (adding)
177                 channel->SetModeParam(this, parameter);
178         else
179                 channel->SetModeParam(this, "");
180         return MODEACTION_ALLOW;
181 }
182
183 bool ParamChannelModeHandler::ParamValidate(std::string& parameter)
184 {
185         return true;
186 }
187
188 ModeWatcher::ModeWatcher(Module* Creator, char modeletter, ModeType type)
189         : mode(modeletter), m_type(type), creator(Creator)
190 {
191 }
192
193 ModeWatcher::~ModeWatcher()
194 {
195 }
196
197 char ModeWatcher::GetModeChar()
198 {
199         return mode;
200 }
201
202 ModeType ModeWatcher::GetModeType()
203 {
204         return m_type;
205 }
206
207 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
208 {
209         return true;
210 }
211
212 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
213 {
214 }
215
216 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
217 {
218         User *d;
219         if ((!user) || (!dest) || (!chan) || (!*dest))
220         {
221                 return NULL;
222         }
223         d = ServerInstance->FindNick(dest);
224         if (!d)
225         {
226                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
227                 return NULL;
228         }
229         return d;
230 }
231
232 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
233 {
234         if (targetchannel)
235         {
236                 /* Display channel's current mode string */
237                 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
238                 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
239                 return;
240         }
241         else
242         {
243                 if (targetuser == user || user->HasPrivPermission("users/auspex"))
244                 {
245                         /* Display user's current mode string */
246                         user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
247                         if (IS_OPER(targetuser))
248                                 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
249                         return;
250                 }
251                 else
252                 {
253                         user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't view modes for other users", user->nick.c_str());
254                         return;
255                 }
256         }
257 }
258
259 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
260                 std::string &parameter, bool SkipACL)
261 {
262         ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
263         unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
264
265         ModeHandler *mh = FindMode(modechar, type);
266         int pcnt = mh->GetNumParams(adding);
267
268         ModResult MOD_RESULT;
269         FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt));
270
271         if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY))
272                 return MODEACTION_DENY;
273
274         if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW))
275         {
276                 MOD_RESULT = mh->AccessCheck(user, chan, parameter, adding);
277
278                 if (MOD_RESULT == MOD_RES_DENY)
279                         return MODEACTION_DENY;
280                 if (MOD_RESULT == MOD_RES_PASSTHRU)
281                 {
282                         unsigned int neededrank = mh->GetLevelRequired();
283                         /* Compare our rank on the channel against the rank of the required prefix,
284                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
285                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
286                          * first, so we don't need to iterate, we just look up the first instead.
287                          */
288                         unsigned int ourrank = chan->GetPrefixValue(user);
289                         if (ourrank < neededrank)
290                         {
291                                 /* Bog off */
292                                 // TODO replace with a real search for the proper prefix
293                                 char needed = neededrank > HALFOP_VALUE ? '@' : '%';
294                                 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
295                                                 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
296                                 return MODEACTION_DENY;
297                         }
298                 }
299         }
300
301         unsigned char handler_id = (modechar - 'A') | mask;
302
303         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
304         {
305                 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
306                         return MODEACTION_DENY;
307                 /* A module whacked the parameter completely, and there was one. abort. */
308                 if (pcnt && parameter.empty())
309                         return MODEACTION_DENY;
310         }
311
312         if (IS_LOCAL(user) && !IS_OPER(user))
313         {
314                 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
315                 if (disabled[modechar - 'A'])
316                 {
317                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
318                                 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
319                         return MODEACTION_DENY;
320                 }
321         }
322
323         if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
324         {
325                 /* It's an oper only mode, and they don't have access to it. */
326                 if (IS_OPER(user))
327                 {
328                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
329                                         user->nick.c_str(), user->oper->NameStr(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
330                 }
331                 else
332                 {
333                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
334                                         user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
335                 }
336                 return MODEACTION_DENY;
337         }
338
339         if (mh->GetTranslateType() == TR_NICK && !ServerInstance->FindNick(parameter))
340         {
341                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameter.c_str());
342                 return MODEACTION_DENY;
343         }
344
345         if (mh->GetPrefixRank() && chan)
346         {
347                 User* user_to_prefix = ServerInstance->FindNick(parameter);
348                 if (!user_to_prefix)
349                         return MODEACTION_DENY;
350                 if (!chan->SetPrefix(user_to_prefix, modechar, adding))
351                         return MODEACTION_DENY;
352         }
353
354         /* Call the handler for the mode */
355         ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
356
357         if (pcnt && parameter.empty())
358                 return MODEACTION_DENY;
359
360         if (ma != MODEACTION_ALLOW)
361                 return ma;
362
363         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
364                 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
365
366         return MODEACTION_ALLOW;
367 }
368
369 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
370 {
371         std::string target = parameters[0];
372         Channel* targetchannel = ServerInstance->FindChan(target);
373         User* targetuser  = ServerInstance->FindNick(target);
374         ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
375
376         LastParse.clear();
377         LastParseParams.clear();
378         LastParseTranslate.clear();
379
380         if (!targetchannel && !targetuser)
381         {
382                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
383                 return;
384         }
385         if (parameters.size() == 1)
386         {
387                 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
388                 return;
389         }
390
391         ModResult MOD_RESULT;
392         FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters));
393
394         bool SkipAccessChecks = false;
395
396         if (!IS_LOCAL(user) || ServerInstance->ULine(user->server) || MOD_RESULT == MOD_RES_ALLOW)
397                 SkipAccessChecks = true;
398         else if (MOD_RESULT == MOD_RES_DENY)
399                 return;
400
401         if (targetuser && !SkipAccessChecks && user != targetuser)
402         {
403                 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
404                 return;
405         }
406
407         std::string mode_sequence = parameters[1];
408
409         std::string output_mode;
410         std::ostringstream output_parameters;
411         LastParseParams.push_back(output_mode);
412         LastParseTranslate.push_back(TR_TEXT);
413
414         bool adding = true;
415         char output_pm = '\0'; // current output state, '+' or '-'
416         unsigned int param_at = 2;
417
418         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
419         {
420                 unsigned char modechar = *letter;
421                 if (modechar == '+' || modechar == '-')
422                 {
423                         adding = (modechar == '+');
424                         continue;
425                 }
426
427                 ModeHandler *mh = this->FindMode(modechar, type);
428                 if (!mh)
429                 {
430                         /* No mode handler? Unknown mode character then. */
431                         user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
432                         continue;
433                 }
434
435                 std::string parameter = "";
436                 int pcnt = mh->GetNumParams(adding);
437                 if (pcnt && param_at == parameters.size())
438                 {
439                         /* No parameter, continue to the next mode */
440                         mh->OnParameterMissing(user, targetuser, targetchannel);
441                         continue;
442                 }
443                 else if (pcnt)
444                 {
445                         parameter = parameters[param_at++];
446                         /* Make sure the user isn't trying to slip in an invalid parameter */
447                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
448                                 continue;
449                         if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
450                         {
451                                 std::string ours = targetchannel->GetModeParameter(modechar);
452                                 if (!mh->ResolveModeConflict(parameter, ours, targetchannel))
453                                         /* we won the mode merge, don't apply this mode */
454                                         continue;
455                         }
456                 }
457
458                 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
459
460                 if (ma != MODEACTION_ALLOW)
461                         continue;
462
463                 char needed_pm = adding ? '+' : '-';
464                 if (needed_pm != output_pm)
465                 {
466                         output_pm = needed_pm;
467                         output_mode.append(1, output_pm);
468                 }
469                 output_mode.append(1, modechar);
470
471                 if (pcnt)
472                 {
473                         TranslateType tt = mh->GetTranslateType();
474                         if (tt == TR_NICK)
475                         {
476                                 User* u = ServerInstance->FindNick(parameter);
477                                 if (u)
478                                         parameter = u->nick;
479                         }
480                         output_parameters << " " << parameter;
481                         LastParseParams.push_back(parameter);
482                         LastParseTranslate.push_back(tt);
483                 }
484
485                 if ( (output_mode.length() + output_parameters.str().length() > 450)
486                                 || (output_mode.length() > 100)
487                                 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
488                 {
489                         /* mode sequence is getting too long */
490                         break;
491                 }
492         }
493
494         LastParseParams[0] = output_mode;
495
496         if (!output_mode.empty())
497         {
498                 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
499                 LastParse.append(" ");
500                 LastParse.append(output_mode);
501                 LastParse.append(output_parameters.str());
502
503                 if (targetchannel)
504                 {
505                         targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
506                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
507                 }
508                 else
509                 {
510                         targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
511                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
512                 }
513         }
514         else if (targetchannel && parameters.size() == 2)
515         {
516                 /* Special case for displaying the list for listmodes,
517                  * e.g. MODE #chan b, or MODE #chan +b without a parameter
518                  */
519                 this->DisplayListModes(user, targetchannel, mode_sequence);
520         }
521 }
522
523 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
524 {
525         seq++;
526
527         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
528         {
529                 unsigned char mletter = *letter;
530                 if (mletter == '+')
531                         continue;
532
533                 /* Ensure the user doesnt request the same mode twice,
534                  * so they cant flood themselves off out of idiocy.
535                  */
536                 if (sent[mletter] == seq)
537                         continue;
538
539                 sent[mletter] = seq;
540
541                 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
542
543                 if (!mh || !mh->IsListMode())
544                         return;
545
546                 ModResult MOD_RESULT;
547                 FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
548                 if (MOD_RESULT == MOD_RES_DENY)
549                         continue;
550
551                 bool display = true;
552                 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
553                 {
554                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
555                                 user->nick.c_str(), chan->name.c_str(), mletter);
556                         display = false;
557                 }
558
559                 /** See below for a description of what craq this is :D
560                  */
561                 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
562
563                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
564                 {
565                         std::string dummyparam;
566
567                         if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
568                                 display = false;
569                 }
570                 if (display)
571                         mh->DisplayList(user, chan);
572                 else
573                         mh->DisplayEmptyList(user, chan);
574         }
575 }
576
577 const std::string& ModeParser::GetLastParse()
578 {
579         return LastParse;
580 }
581
582 void ModeParser::CleanMask(std::string &mask)
583 {
584         std::string::size_type pos_of_pling = mask.find_first_of('!');
585         std::string::size_type pos_of_at = mask.find_first_of('@');
586         std::string::size_type pos_of_dot = mask.find_first_of('.');
587         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
588
589         if (mask.length() >= 2 && mask[1] == ':')
590                 return; // if it's an extban, don't even try guess how it needs to be formed.
591
592         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
593         {
594                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
595                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
596                 {
597                         /* It has no '.' in it, it must be a nick. */
598                         mask.append("!*@*");
599                 }
600                 else
601                 {
602                         /* Got a dot in it? Has to be a host */
603                         mask = "*!*@" + mask;
604                 }
605         }
606         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
607         {
608                 /* Has an @ but no !, its a user@host */
609                  mask = "*!" + mask;
610         }
611         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
612         {
613                 /* Has a ! but no @, it must be a nick!ident */
614                 mask.append("@*");
615         }
616 }
617
618 bool ModeParser::AddMode(ModeHandler* mh)
619 {
620         unsigned char mask = 0;
621         unsigned char pos = 0;
622
623         /* Yes, i know, this might let people declare modes like '_' or '^'.
624          * If they do that, thats their problem, and if i ever EVER see an
625          * official InspIRCd developer do that, i'll beat them with a paddle!
626          */
627         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
628                 return false;
629
630         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
631          * A mode prefix of ':' will fuck up both server to server, and client to server.
632          * A mode prefix of '#' will mess up /whois and /privmsg
633          */
634         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
635                 return false;
636
637         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
638         pos = (mh->GetModeChar()-65) | mask;
639
640         if (modehandlers[pos])
641                 return false;
642
643         modehandlers[pos] = mh;
644         return true;
645 }
646
647 bool ModeParser::DelMode(ModeHandler* mh)
648 {
649         unsigned char mask = 0;
650         unsigned char pos = 0;
651
652         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
653                 return false;
654
655         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
656         pos = (mh->GetModeChar()-65) | mask;
657
658         if (modehandlers[pos] != mh)
659                 return false;
660
661         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
662          * To stack here we have to make the algorithm slower. Discuss.
663          */
664         switch (mh->GetModeType())
665         {
666                 case MODETYPE_USER:
667                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
668                         {
669                                 mh->RemoveMode(i->second);
670                         }
671                 break;
672                 case MODETYPE_CHANNEL:
673                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
674                         {
675                                 mh->RemoveMode(i->second);
676                         }
677                 break;
678         }
679
680         modehandlers[pos] = NULL;
681
682         return true;
683 }
684
685 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
686 {
687         unsigned char mask = 0;
688         unsigned char pos = 0;
689
690         if ((modeletter < 'A') || (modeletter > 'z'))
691                 return NULL;
692
693         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
694         pos = (modeletter-65) | mask;
695
696         return modehandlers[pos];
697 }
698
699 std::string ModeParser::UserModeList()
700 {
701         char modestr[256];
702         int pointer = 0;
703
704         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
705         {
706                 unsigned char pos = (mode-65) | MASK_USER;
707
708                 if (modehandlers[pos])
709                         modestr[pointer++] = mode;
710         }
711         modestr[pointer++] = 0;
712         return modestr;
713 }
714
715 std::string ModeParser::ChannelModeList()
716 {
717         char modestr[256];
718         int pointer = 0;
719
720         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
721         {
722                 unsigned char pos = (mode-65) | MASK_CHANNEL;
723
724                 if (modehandlers[pos])
725                         modestr[pointer++] = mode;
726         }
727         modestr[pointer++] = 0;
728         return modestr;
729 }
730
731 std::string ModeParser::ParaModeList()
732 {
733         char modestr[256];
734         int pointer = 0;
735
736         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
737         {
738                 unsigned char pos = (mode-65) | MASK_CHANNEL;
739
740                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
741                         modestr[pointer++] = mode;
742         }
743         modestr[pointer++] = 0;
744         return modestr;
745 }
746
747 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
748 {
749         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
750         {
751                 unsigned char pos = (mode-65) | MASK_CHANNEL;
752
753                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
754                 {
755                         return modehandlers[pos];
756                 }
757         }
758         return NULL;
759 }
760
761 std::string ModeParser::GiveModeList(ModeMasks m)
762 {
763         std::string type1;      /* Listmodes EXCEPT those with a prefix */
764         std::string type2;      /* Modes that take a param when adding or removing */
765         std::string type3;      /* Modes that only take a param when adding */
766         std::string type4;      /* Modes that dont take a param */
767
768         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
769         {
770                 unsigned char pos = (mode-65) | m;
771                  /* One parameter when adding */
772                 if (modehandlers[pos])
773                 {
774                         if (modehandlers[pos]->GetNumParams(true))
775                         {
776                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
777                                 {
778                                         type1 += modehandlers[pos]->GetModeChar();
779                                 }
780                                 else
781                                 {
782                                         /* ... and one parameter when removing */
783                                         if (modehandlers[pos]->GetNumParams(false))
784                                         {
785                                                 /* But not a list mode */
786                                                 if (!modehandlers[pos]->GetPrefix())
787                                                 {
788                                                         type2 += modehandlers[pos]->GetModeChar();
789                                                 }
790                                         }
791                                         else
792                                         {
793                                                 /* No parameters when removing */
794                                                 type3 += modehandlers[pos]->GetModeChar();
795                                         }
796                                 }
797                         }
798                         else
799                         {
800                                 type4 += modehandlers[pos]->GetModeChar();
801                         }
802                 }
803         }
804
805         return type1 + "," + type2 + "," + type3 + "," + type4;
806 }
807
808 std::string ModeParser::BuildPrefixes(bool lettersAndModes)
809 {
810         std::string mletters;
811         std::string mprefixes;
812         std::map<int,std::pair<char,char> > prefixes;
813
814         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
815         {
816                 unsigned char pos = (mode-65) | MASK_CHANNEL;
817
818                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
819                 {
820                         prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
821                                 modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
822                 }
823         }
824
825         for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
826         {
827                 mletters = mletters + n->second.first;
828                 mprefixes = mprefixes + n->second.second;
829         }
830
831         return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters;
832 }
833
834 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
835 {
836         unsigned char mask = 0;
837         unsigned char pos = 0;
838
839         if (!mw)
840                 return false;
841
842         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
843                 return false;
844
845         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
846         pos = (mw->GetModeChar()-65) | mask;
847
848         modewatchers[pos].push_back(mw);
849
850         return true;
851 }
852
853 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
854 {
855         unsigned char mask = 0;
856         unsigned char pos = 0;
857
858         if (!mw)
859                 return false;
860
861         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
862                 return false;
863
864         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
865         pos = (mw->GetModeChar()-65) | mask;
866
867         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
868
869         if (a == modewatchers[pos].end())
870         {
871                 return false;
872         }
873
874         modewatchers[pos].erase(a);
875
876         return true;
877 }
878
879 /** This default implementation can remove simple user modes
880  */
881 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
882 {
883         char moderemove[MAXBUF];
884         std::vector<std::string> parameters;
885
886         if (user->IsModeSet(this->GetModeChar()))
887         {
888                 if (stack)
889                 {
890                         stack->Push(this->GetModeChar());
891                 }
892                 else
893                 {
894                         sprintf(moderemove,"-%c",this->GetModeChar());
895                         parameters.push_back(user->nick);
896                         parameters.push_back(moderemove);
897                         ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
898                 }
899         }
900 }
901
902 /** This default implementation can remove simple channel modes
903  * (no parameters)
904  */
905 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
906 {
907         char moderemove[MAXBUF];
908         std::vector<std::string> parameters;
909
910         if (channel->IsModeSet(this->GetModeChar()))
911         {
912                 if (stack)
913                 {
914                         stack->Push(this->GetModeChar());
915                 }
916                 else
917                 {
918                         sprintf(moderemove,"-%c",this->GetModeChar());
919                         parameters.push_back(channel->name);
920                         parameters.push_back(moderemove);
921                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
922                 }
923         }
924 }
925
926 struct builtin_modes
927 {
928         ModeChannelSecret s;
929         ModeChannelPrivate p;
930         ModeChannelModerated m;
931         ModeChannelTopicOps t;
932
933         ModeChannelNoExternal n;
934         ModeChannelInviteOnly i;
935         ModeChannelKey k;
936         ModeChannelLimit l;
937
938         ModeChannelBan b;
939         ModeChannelOp o;
940         // halfop is added by configreader
941         ModeChannelVoice v;
942
943         ModeUserWallops uw;
944         ModeUserInvisible ui;
945         ModeUserOperator uo;
946         ModeUserServerNoticeMask us;
947
948         void init(ModeParser* modes)
949         {
950                 modes->AddMode(&s);
951                 modes->AddMode(&p);
952                 modes->AddMode(&m);
953                 modes->AddMode(&t);
954                 modes->AddMode(&n);
955                 modes->AddMode(&i);
956                 modes->AddMode(&k);
957                 modes->AddMode(&l);
958                 modes->AddMode(&b);
959                 modes->AddMode(&o);
960                 modes->AddMode(&v);
961                 modes->AddMode(&uw);
962                 modes->AddMode(&ui);
963                 modes->AddMode(&uo);
964                 modes->AddMode(&us);
965         }
966 };
967
968 static builtin_modes static_modes;
969
970 ModeParser::ModeParser()
971 {
972         /* Clear mode handler list */
973         memset(modehandlers, 0, sizeof(modehandlers));
974
975         /* Last parse string */
976         LastParse.clear();
977
978         seq = 0;
979         memset(&sent, 0, sizeof(sent));
980
981         static_modes.init(this);
982 }
983
984 ModeParser::~ModeParser()
985 {
986 }