]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Add names for all modes (part 1 of named channel mode list)
[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, const std::string& Name, 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), name(Name)
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 struct builtin_modes
985 {
986         ModeChannelSecret s;
987         ModeChannelPrivate p;
988         ModeChannelModerated m;
989         ModeChannelTopicOps t;
990
991         ModeChannelNoExternal n;
992         ModeChannelInviteOnly i;
993         ModeChannelKey k;
994         ModeChannelLimit l;
995
996         ModeChannelBan b;
997         ModeChannelOp o;
998         // halfop is added by configreader
999         ModeChannelVoice v;
1000
1001         ModeUserWallops uw;
1002         ModeUserInvisible ui;
1003         ModeUserOperator uo;
1004         ModeUserServerNoticeMask us;
1005
1006         void init(ModeParser* modes)
1007         {
1008                 modes->AddMode(&s);
1009                 modes->AddMode(&p);
1010                 modes->AddMode(&m);
1011                 modes->AddMode(&t);
1012                 modes->AddMode(&n);
1013                 modes->AddMode(&i);
1014                 modes->AddMode(&k);
1015                 modes->AddMode(&l);
1016                 modes->AddMode(&b);
1017                 modes->AddMode(&o);
1018                 modes->AddMode(&v);
1019                 modes->AddMode(&uw);
1020                 modes->AddMode(&ui);
1021                 modes->AddMode(&uo);
1022                 modes->AddMode(&us);
1023         }
1024 };
1025
1026 static builtin_modes static_modes;
1027
1028 ModeParser::ModeParser()
1029 {
1030         /* Clear mode handler list */
1031         memset(modehandlers, 0, sizeof(modehandlers));
1032
1033         /* Last parse string */
1034         LastParse.clear();
1035
1036         seq = 0;
1037         memset(&sent, 0, sizeof(sent));
1038
1039         static_modes.init(this);
1040 }
1041
1042 ModeParser::~ModeParser()
1043 {
1044         ModeHandler* mh = ServerInstance->Modes->FindMode('h', MODETYPE_CHANNEL);
1045         if (mh)
1046                 delete mh;
1047 }