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