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