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