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