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