]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Change SERVICE_{CMODE,UMODE} to SERVICE_MODE, which makes more sense
[user/henk/code/inspircd.git] / src / mode.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 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, SERVICE_MODE), 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", DEFAULT, "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                                 ModeHandler* neededmh = NULL;
292                                 for(char c='A'; c <= 'z'; c++)
293                                 {
294                                         ModeHandler *privmh = FindMode(c, MODETYPE_CHANNEL);
295                                         if (privmh && privmh->GetPrefixRank() >= neededrank)
296                                         {
297                                                 // this mode is sufficient to allow this action
298                                                 if (!neededmh || privmh->GetPrefixRank() < neededmh->GetPrefixRank())
299                                                         neededmh = privmh;
300                                         }
301                                 }
302                                 if (neededmh)
303                                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel %s access or above to %sset channel mode %c",
304                                                 user->nick.c_str(), chan->name.c_str(), neededmh->name.c_str(), adding ? "" : "un", modechar);
305                                 else
306                                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You cannot %sset channel mode %c",
307                                                 user->nick.c_str(), chan->name.c_str(), adding ? "" : "un", modechar);
308                                 return MODEACTION_DENY;
309                         }
310                 }
311         }
312
313         unsigned char handler_id = (modechar - 'A') | mask;
314
315         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
316         {
317                 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
318                         return MODEACTION_DENY;
319                 /* A module whacked the parameter completely, and there was one. abort. */
320                 if (pcnt && parameter.empty())
321                         return MODEACTION_DENY;
322         }
323
324         if (IS_LOCAL(user) && !IS_OPER(user))
325         {
326                 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
327                 if (disabled[modechar - 'A'])
328                 {
329                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
330                                 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
331                         return MODEACTION_DENY;
332                 }
333         }
334
335         if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
336         {
337                 /* It's an oper only mode, and they don't have access to it. */
338                 if (IS_OPER(user))
339                 {
340                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
341                                         user->nick.c_str(), user->oper->NameStr(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
342                 }
343                 else
344                 {
345                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
346                                         user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
347                 }
348                 return MODEACTION_DENY;
349         }
350
351         if (mh->GetTranslateType() == TR_NICK && !ServerInstance->FindNick(parameter))
352         {
353                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameter.c_str());
354                 return MODEACTION_DENY;
355         }
356
357         if (mh->GetPrefixRank() && chan)
358         {
359                 User* user_to_prefix = ServerInstance->FindNick(parameter);
360                 if (!user_to_prefix)
361                         return MODEACTION_DENY;
362                 if (!chan->SetPrefix(user_to_prefix, modechar, adding))
363                         return MODEACTION_DENY;
364         }
365
366         /* Call the handler for the mode */
367         ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
368
369         if (pcnt && parameter.empty())
370                 return MODEACTION_DENY;
371
372         if (ma != MODEACTION_ALLOW)
373                 return ma;
374
375         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
376                 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
377
378         return MODEACTION_ALLOW;
379 }
380
381 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
382 {
383         std::string target = parameters[0];
384         Channel* targetchannel = ServerInstance->FindChan(target);
385         User* targetuser  = ServerInstance->FindNick(target);
386         ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
387
388         LastParse.clear();
389         LastParseParams.clear();
390         LastParseTranslate.clear();
391
392         if (!targetchannel && !targetuser)
393         {
394                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
395                 return;
396         }
397         if (parameters.size() == 1)
398         {
399                 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
400                 return;
401         }
402
403         ModResult MOD_RESULT;
404         FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters));
405
406         bool SkipAccessChecks = false;
407
408         if (!IS_LOCAL(user) || ServerInstance->ULine(user->server) || MOD_RESULT == MOD_RES_ALLOW)
409                 SkipAccessChecks = true;
410         else if (MOD_RESULT == MOD_RES_DENY)
411                 return;
412
413         if (targetuser && !SkipAccessChecks && user != targetuser)
414         {
415                 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
416                 return;
417         }
418
419         std::string mode_sequence = parameters[1];
420
421         std::string output_mode;
422         std::ostringstream output_parameters;
423         LastParseParams.push_back(output_mode);
424         LastParseTranslate.push_back(TR_TEXT);
425
426         bool adding = true;
427         char output_pm = '\0'; // current output state, '+' or '-'
428         unsigned int param_at = 2;
429
430         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
431         {
432                 unsigned char modechar = *letter;
433                 if (modechar == '+' || modechar == '-')
434                 {
435                         adding = (modechar == '+');
436                         continue;
437                 }
438
439                 ModeHandler *mh = this->FindMode(modechar, type);
440                 if (!mh)
441                 {
442                         /* No mode handler? Unknown mode character then. */
443                         user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
444                         continue;
445                 }
446
447                 std::string parameter = "";
448                 int pcnt = mh->GetNumParams(adding);
449                 if (pcnt && param_at == parameters.size())
450                 {
451                         /* No parameter, continue to the next mode */
452                         mh->OnParameterMissing(user, targetuser, targetchannel);
453                         continue;
454                 }
455                 else if (pcnt)
456                 {
457                         parameter = parameters[param_at++];
458                         /* Make sure the user isn't trying to slip in an invalid parameter */
459                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
460                                 continue;
461                         if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
462                         {
463                                 std::string ours = targetchannel->GetModeParameter(modechar);
464                                 if (!mh->ResolveModeConflict(parameter, ours, targetchannel))
465                                         /* we won the mode merge, don't apply this mode */
466                                         continue;
467                         }
468                 }
469
470                 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
471
472                 if (ma != MODEACTION_ALLOW)
473                         continue;
474
475                 char needed_pm = adding ? '+' : '-';
476                 if (needed_pm != output_pm)
477                 {
478                         output_pm = needed_pm;
479                         output_mode.append(1, output_pm);
480                 }
481                 output_mode.append(1, modechar);
482
483                 if (pcnt)
484                 {
485                         TranslateType tt = mh->GetTranslateType();
486                         if (tt == TR_NICK)
487                         {
488                                 User* u = ServerInstance->FindNick(parameter);
489                                 if (u)
490                                         parameter = u->nick;
491                         }
492                         output_parameters << " " << parameter;
493                         LastParseParams.push_back(parameter);
494                         LastParseTranslate.push_back(tt);
495                 }
496
497                 if ( (output_mode.length() + output_parameters.str().length() > 450)
498                                 || (output_mode.length() > 100)
499                                 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
500                 {
501                         /* mode sequence is getting too long */
502                         break;
503                 }
504         }
505
506         LastParseParams[0] = output_mode;
507
508         if (!output_mode.empty())
509         {
510                 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
511                 LastParse.append(" ");
512                 LastParse.append(output_mode);
513                 LastParse.append(output_parameters.str());
514
515                 if (targetchannel)
516                 {
517                         targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
518                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
519                 }
520                 else
521                 {
522                         targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
523                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
524                 }
525         }
526         else if (targetchannel && parameters.size() == 2)
527         {
528                 /* Special case for displaying the list for listmodes,
529                  * e.g. MODE #chan b, or MODE #chan +b without a parameter
530                  */
531                 this->DisplayListModes(user, targetchannel, mode_sequence);
532         }
533 }
534
535 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
536 {
537         seq++;
538
539         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
540         {
541                 unsigned char mletter = *letter;
542                 if (mletter == '+')
543                         continue;
544
545                 /* Ensure the user doesnt request the same mode twice,
546                  * so they cant flood themselves off out of idiocy.
547                  */
548                 if (sent[mletter] == seq)
549                         continue;
550
551                 sent[mletter] = seq;
552
553                 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
554
555                 if (!mh || !mh->IsListMode())
556                         return;
557
558                 ModResult MOD_RESULT;
559                 FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
560                 if (MOD_RESULT == MOD_RES_DENY)
561                         continue;
562
563                 bool display = true;
564                 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
565                 {
566                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You do not have access to view the +%c list",
567                                 user->nick.c_str(), chan->name.c_str(), mletter);
568                         display = false;
569                 }
570
571                 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
572
573                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
574                 {
575                         std::string dummyparam;
576
577                         if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
578                                 display = false;
579                 }
580                 if (display)
581                         mh->DisplayList(user, chan);
582                 else
583                         mh->DisplayEmptyList(user, chan);
584         }
585 }
586
587 const std::string& ModeParser::GetLastParse()
588 {
589         return LastParse;
590 }
591
592 void ModeParser::CleanMask(std::string &mask)
593 {
594         std::string::size_type pos_of_pling = mask.find_first_of('!');
595         std::string::size_type pos_of_at = mask.find_first_of('@');
596         std::string::size_type pos_of_dot = mask.find_first_of('.');
597         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
598
599         if (mask.length() >= 2 && mask[1] == ':')
600                 return; // if it's an extban, don't even try guess how it needs to be formed.
601
602         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
603         {
604                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
605                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
606                 {
607                         /* It has no '.' in it, it must be a nick. */
608                         mask.append("!*@*");
609                 }
610                 else
611                 {
612                         /* Got a dot in it? Has to be a host */
613                         mask = "*!*@" + mask;
614                 }
615         }
616         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
617         {
618                 /* Has an @ but no !, its a user@host */
619                  mask = "*!" + mask;
620         }
621         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
622         {
623                 /* Has a ! but no @, it must be a nick!ident */
624                 mask.append("@*");
625         }
626 }
627
628 bool ModeParser::AddMode(ModeHandler* mh)
629 {
630         unsigned char mask = 0;
631         unsigned char pos = 0;
632
633         /* Yes, i know, this might let people declare modes like '_' or '^'.
634          * If they do that, thats their problem, and if i ever EVER see an
635          * official InspIRCd developer do that, i'll beat them with a paddle!
636          */
637         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
638                 return false;
639
640         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
641          * A mode prefix of ':' will fuck up both server to server, and client to server.
642          * A mode prefix of '#' will mess up /whois and /privmsg
643          */
644         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
645                 return false;
646
647         if (mh->GetPrefix() && FindPrefix(mh->GetPrefix()))
648                 return false;
649
650         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
651         pos = (mh->GetModeChar()-65) | mask;
652
653         if (modehandlers[pos])
654                 return false;
655
656         modehandlers[pos] = mh;
657         return true;
658 }
659
660 bool ModeParser::DelMode(ModeHandler* mh)
661 {
662         unsigned char mask = 0;
663         unsigned char pos = 0;
664
665         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
666                 return false;
667
668         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
669         pos = (mh->GetModeChar()-65) | mask;
670
671         if (modehandlers[pos] != mh)
672                 return false;
673
674         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
675          * To stack here we have to make the algorithm slower. Discuss.
676          */
677         switch (mh->GetModeType())
678         {
679                 case MODETYPE_USER:
680                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
681                         {
682                                 mh->RemoveMode(i->second);
683                         }
684                 break;
685                 case MODETYPE_CHANNEL:
686                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
687                         {
688                                 mh->RemoveMode(i->second);
689                         }
690                 break;
691         }
692
693         modehandlers[pos] = NULL;
694
695         return true;
696 }
697
698 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
699 {
700         unsigned char mask = 0;
701         unsigned char pos = 0;
702
703         if ((modeletter < 'A') || (modeletter > 'z'))
704                 return NULL;
705
706         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
707         pos = (modeletter-65) | mask;
708
709         return modehandlers[pos];
710 }
711
712 std::string ModeParser::UserModeList()
713 {
714         char modestr[256];
715         int pointer = 0;
716
717         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
718         {
719                 unsigned char pos = (mode-65) | MASK_USER;
720
721                 if (modehandlers[pos])
722                         modestr[pointer++] = mode;
723         }
724         modestr[pointer++] = 0;
725         return modestr;
726 }
727
728 std::string ModeParser::ChannelModeList()
729 {
730         char modestr[256];
731         int pointer = 0;
732
733         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
734         {
735                 unsigned char pos = (mode-65) | MASK_CHANNEL;
736
737                 if (modehandlers[pos])
738                         modestr[pointer++] = mode;
739         }
740         modestr[pointer++] = 0;
741         return modestr;
742 }
743
744 std::string ModeParser::ParaModeList()
745 {
746         char modestr[256];
747         int pointer = 0;
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]->GetNumParams(true)))
754                         modestr[pointer++] = mode;
755         }
756         modestr[pointer++] = 0;
757         return modestr;
758 }
759
760 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
761 {
762         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
763         {
764                 unsigned char pos = (mode-65) | MASK_CHANNEL;
765
766                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
767                 {
768                         return modehandlers[pos];
769                 }
770         }
771         return NULL;
772 }
773
774 std::string ModeParser::GiveModeList(ModeMasks m)
775 {
776         std::string type1;      /* Listmodes EXCEPT those with a prefix */
777         std::string type2;      /* Modes that take a param when adding or removing */
778         std::string type3;      /* Modes that only take a param when adding */
779         std::string type4;      /* Modes that dont take a param */
780
781         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
782         {
783                 unsigned char pos = (mode-65) | m;
784                  /* One parameter when adding */
785                 if (modehandlers[pos])
786                 {
787                         if (modehandlers[pos]->GetNumParams(true))
788                         {
789                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
790                                 {
791                                         type1 += modehandlers[pos]->GetModeChar();
792                                 }
793                                 else
794                                 {
795                                         /* ... and one parameter when removing */
796                                         if (modehandlers[pos]->GetNumParams(false))
797                                         {
798                                                 /* But not a list mode */
799                                                 if (!modehandlers[pos]->GetPrefix())
800                                                 {
801                                                         type2 += modehandlers[pos]->GetModeChar();
802                                                 }
803                                         }
804                                         else
805                                         {
806                                                 /* No parameters when removing */
807                                                 type3 += modehandlers[pos]->GetModeChar();
808                                         }
809                                 }
810                         }
811                         else
812                         {
813                                 type4 += modehandlers[pos]->GetModeChar();
814                         }
815                 }
816         }
817
818         return type1 + "," + type2 + "," + type3 + "," + type4;
819 }
820
821 std::string ModeParser::BuildPrefixes(bool lettersAndModes)
822 {
823         std::string mletters;
824         std::string mprefixes;
825         std::map<int,std::pair<char,char> > prefixes;
826
827         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
828         {
829                 unsigned char pos = (mode-65) | MASK_CHANNEL;
830
831                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
832                 {
833                         prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
834                                 modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
835                 }
836         }
837
838         for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
839         {
840                 mletters = mletters + n->second.first;
841                 mprefixes = mprefixes + n->second.second;
842         }
843
844         return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters;
845 }
846
847 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
848 {
849         unsigned char mask = 0;
850         unsigned char pos = 0;
851
852         if (!mw)
853                 return false;
854
855         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
856                 return false;
857
858         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
859         pos = (mw->GetModeChar()-65) | mask;
860
861         modewatchers[pos].push_back(mw);
862
863         return true;
864 }
865
866 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
867 {
868         unsigned char mask = 0;
869         unsigned char pos = 0;
870
871         if (!mw)
872                 return false;
873
874         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
875                 return false;
876
877         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
878         pos = (mw->GetModeChar()-65) | mask;
879
880         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
881
882         if (a == modewatchers[pos].end())
883         {
884                 return false;
885         }
886
887         modewatchers[pos].erase(a);
888
889         return true;
890 }
891
892 /** This default implementation can remove simple user modes
893  */
894 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
895 {
896         char moderemove[MAXBUF];
897         std::vector<std::string> parameters;
898
899         if (user->IsModeSet(this->GetModeChar()))
900         {
901                 if (stack)
902                 {
903                         stack->Push(this->GetModeChar());
904                 }
905                 else
906                 {
907                         sprintf(moderemove,"-%c",this->GetModeChar());
908                         parameters.push_back(user->nick);
909                         parameters.push_back(moderemove);
910                         ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
911                 }
912         }
913 }
914
915 /** This default implementation can remove simple channel modes
916  * (no parameters)
917  */
918 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
919 {
920         char moderemove[MAXBUF];
921         std::vector<std::string> parameters;
922
923         if (channel->IsModeSet(this->GetModeChar()))
924         {
925                 if (stack)
926                 {
927                         stack->Push(this->GetModeChar());
928                 }
929                 else
930                 {
931                         sprintf(moderemove,"-%c",this->GetModeChar());
932                         parameters.push_back(channel->name);
933                         parameters.push_back(moderemove);
934                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
935                 }
936         }
937 }
938
939 struct builtin_modes
940 {
941         ModeChannelSecret s;
942         ModeChannelPrivate p;
943         ModeChannelModerated m;
944         ModeChannelTopicOps t;
945
946         ModeChannelNoExternal n;
947         ModeChannelInviteOnly i;
948         ModeChannelKey k;
949         ModeChannelLimit l;
950
951         ModeChannelBan b;
952         ModeChannelOp o;
953         ModeChannelVoice v;
954
955         ModeUserWallops uw;
956         ModeUserInvisible ui;
957         ModeUserOperator uo;
958         ModeUserServerNoticeMask us;
959
960         void init(ModeParser* modes)
961         {
962                 modes->AddMode(&s);
963                 modes->AddMode(&p);
964                 modes->AddMode(&m);
965                 modes->AddMode(&t);
966                 modes->AddMode(&n);
967                 modes->AddMode(&i);
968                 modes->AddMode(&k);
969                 modes->AddMode(&l);
970                 modes->AddMode(&b);
971                 modes->AddMode(&o);
972                 modes->AddMode(&v);
973                 modes->AddMode(&uw);
974                 modes->AddMode(&ui);
975                 modes->AddMode(&uo);
976                 modes->AddMode(&us);
977         }
978 };
979
980 static builtin_modes static_modes;
981
982 ModeParser::ModeParser()
983 {
984         /* Clear mode handler list */
985         memset(modehandlers, 0, sizeof(modehandlers));
986
987         /* Last parse string */
988         LastParse.clear();
989
990         seq = 0;
991         memset(&sent, 0, sizeof(sent));
992
993         static_modes.init(this);
994 }
995
996 ModeParser::~ModeParser()
997 {
998 }