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