]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Remove double prefix conversion from Channel::RawWriteAllExcept
[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                 /* Overall access control hook for mode change */
423                 int hook = targetchannel ? AC_GENERAL_MODE : AC_GENERAL_UMODE;
424
425                 LastParse = mode_sequence;
426                 ModResult MOD_RESULT;
427                 FIRST_MOD_RESULT(ServerInstance, OnAccessCheck, MOD_RESULT, (user, targetuser, targetchannel, hook));
428                 LastParse.clear();
429                 if (MOD_RESULT == MOD_RES_DENY)
430                         return;
431                 SkipAccessChecks = (MOD_RESULT == MOD_RES_ALLOW);
432         }
433
434         if (targetuser && !SkipAccessChecks && user != targetuser)
435         {
436                 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
437                 return;
438         }
439
440         std::string output_mode;
441         std::ostringstream output_parameters;
442         LastParseParams.push_back(output_mode);
443         LastParseTranslate.push_back(TR_TEXT);
444
445         bool adding = true;
446         char output_pm = '\0'; // current output state, '+' or '-'
447         unsigned int param_at = 2;
448
449         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
450         {
451                 unsigned char modechar = *letter;
452                 if (modechar == '+' || modechar == '-')
453                 {
454                         adding = (modechar == '+');
455                         continue;
456                 }
457
458                 ModeHandler *mh = this->FindMode(modechar, type);
459                 if (!mh)
460                 {
461                         /* No mode handler? Unknown mode character then. */
462                         user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
463                         continue;
464                 }
465
466                 std::string parameter = "";
467                 int pcnt = mh->GetNumParams(adding);
468                 if (pcnt && param_at == parameters.size())
469                 {
470                         /* No parameter, continue to the next mode */
471                         mh->OnParameterMissing(user, targetuser, targetchannel);
472                         continue;
473                 }
474                 else if (pcnt)
475                 {
476                         parameter = parameters[param_at++];
477                         /* Make sure the user isn't trying to slip in an invalid parameter */
478                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
479                                 continue;
480                         if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
481                         {
482                                 std::string ours = targetchannel->GetModeParameter(modechar);
483                                 if (!mh->CheckTimeStamp(parameter, ours, targetchannel))
484                                         /* we won the mode merge, don't apply this mode */
485                                         continue;
486                         }
487                 }
488
489                 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
490
491                 if (ma != MODEACTION_ALLOW)
492                         continue;
493
494                 char needed_pm = adding ? '+' : '-';
495                 if (needed_pm != output_pm)
496                 {
497                         output_pm = needed_pm;
498                         output_mode.append(1, output_pm);
499                 }
500                 output_mode.append(1, modechar);
501
502                 if (pcnt)
503                 {
504                         output_parameters << " " << parameter;
505                         LastParseParams.push_back(parameter);
506                         LastParseTranslate.push_back(mh->GetTranslateType());
507                 }
508
509                 if ( (output_mode.length() + output_parameters.str().length() > 450)
510                                 || (output_mode.length() > 100)
511                                 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
512                 {
513                         /* mode sequence is getting too long */
514                         break;
515                 }
516         }
517
518         LastParseParams[0] = output_mode;
519
520         if (!output_mode.empty())
521         {
522                 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
523                 LastParse.append(" ");
524                 LastParse.append(output_mode);
525                 LastParse.append(output_parameters.str());
526
527                 if (targetchannel)
528                 {
529                         targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
530                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
531                 }
532                 else
533                 {
534                         targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
535                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
536                 }
537         }
538         else if (targetchannel && parameters.size() == 2)
539         {
540                 /* Special case for displaying the list for listmodes,
541                  * e.g. MODE #chan b, or MODE #chan +b without a parameter
542                  */
543                 this->DisplayListModes(user, targetchannel, mode_sequence);
544         }
545 }
546
547 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
548 {
549         seq++;
550
551         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
552         {
553                 unsigned char mletter = *letter;
554                 if (mletter == '+')
555                         continue;
556
557                 /* Ensure the user doesnt request the same mode twice,
558                  * so they cant flood themselves off out of idiocy.
559                  */
560                 if (sent[mletter] == seq)
561                         continue;
562
563                 sent[mletter] = seq;
564
565                 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
566
567                 if (!mh || !mh->IsListMode())
568                         return;
569
570                 ModResult MOD_RESULT;
571                 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
572                 if (MOD_RESULT == MOD_RES_DENY)
573                         continue;
574
575                 bool display = true;
576                 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
577                 {
578                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
579                                 user->nick.c_str(), chan->name.c_str(), mletter);
580                         display = false;
581                 }
582
583                 /** See below for a description of what craq this is :D
584                  */
585                 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
586
587                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
588                 {
589                         std::string dummyparam;
590
591                         if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
592                                 display = false;
593                 }
594                 if (display)
595                         mh->DisplayList(user, chan);
596                 else
597                         mh->DisplayEmptyList(user, chan);
598         }
599 }
600
601 const std::string& ModeParser::GetLastParse()
602 {
603         return LastParse;
604 }
605
606 void ModeParser::CleanMask(std::string &mask)
607 {
608         std::string::size_type pos_of_pling = mask.find_first_of('!');
609         std::string::size_type pos_of_at = mask.find_first_of('@');
610         std::string::size_type pos_of_dot = mask.find_first_of('.');
611         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
612
613         if (mask.length() >= 2 && mask[1] == ':')
614                 return; // if it's an extban, don't even try guess how it needs to be formed.
615
616         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
617         {
618                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
619                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
620                 {
621                         /* It has no '.' in it, it must be a nick. */
622                         mask.append("!*@*");
623                 }
624                 else
625                 {
626                         /* Got a dot in it? Has to be a host */
627                         mask = "*!*@" + mask;
628                 }
629         }
630         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
631         {
632                 /* Has an @ but no !, its a user@host */
633                  mask = "*!" + mask;
634         }
635         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
636         {
637                 /* Has a ! but no @, it must be a nick!ident */
638                 mask.append("@*");
639         }
640 }
641
642 bool ModeParser::AddMode(ModeHandler* mh)
643 {
644         unsigned char mask = 0;
645         unsigned char pos = 0;
646
647         /* Yes, i know, this might let people declare modes like '_' or '^'.
648          * If they do that, thats their problem, and if i ever EVER see an
649          * official InspIRCd developer do that, i'll beat them with a paddle!
650          */
651         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
652                 return false;
653
654         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
655          * A mode prefix of ':' will fuck up both server to server, and client to server.
656          * A mode prefix of '#' will mess up /whois and /privmsg
657          */
658         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
659                 return false;
660
661         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
662         pos = (mh->GetModeChar()-65) | mask;
663
664         if (modehandlers[pos])
665                 return false;
666
667         modehandlers[pos] = mh;
668         return true;
669 }
670
671 bool ModeParser::DelMode(ModeHandler* mh)
672 {
673         unsigned char mask = 0;
674         unsigned char pos = 0;
675
676         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
677                 return false;
678
679         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
680         pos = (mh->GetModeChar()-65) | mask;
681
682         if (!modehandlers[pos])
683                 return false;
684
685         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
686          * To stack here we have to make the algorithm slower. Discuss.
687          */
688         switch (mh->GetModeType())
689         {
690                 case MODETYPE_USER:
691                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
692                         {
693                                 mh->RemoveMode(i->second);
694                         }
695                 break;
696                 case MODETYPE_CHANNEL:
697                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
698                         {
699                                 mh->RemoveMode(i->second);
700                         }
701                 break;
702         }
703
704         modehandlers[pos] = NULL;
705
706         return true;
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> >::iterator n = prefixes.begin(); n != prefixes.end(); n++)
884         {
885                 mletters = mletters + n->second.first;
886                 mprefixes = mprefixes + n->second.second;
887         }
888
889         return "(" + mprefixes + ")" + mletters;
890 }
891
892 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
893 {
894         unsigned char mask = 0;
895         unsigned char pos = 0;
896
897         if (!mw)
898                 return false;
899
900         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
901                 return false;
902
903         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
904         pos = (mw->GetModeChar()-65) | mask;
905
906         modewatchers[pos].push_back(mw);
907
908         return true;
909 }
910
911 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
912 {
913         unsigned char mask = 0;
914         unsigned char pos = 0;
915
916         if (!mw)
917                 return false;
918
919         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
920                 return false;
921
922         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
923         pos = (mw->GetModeChar()-65) | mask;
924
925         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
926
927         if (a == modewatchers[pos].end())
928         {
929                 return false;
930         }
931
932         modewatchers[pos].erase(a);
933
934         return true;
935 }
936
937 /** This default implementation can remove simple user modes
938  */
939 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
940 {
941         char moderemove[MAXBUF];
942         std::vector<std::string> parameters;
943
944         if (user->IsModeSet(this->GetModeChar()))
945         {
946                 if (stack)
947                 {
948                         stack->Push(this->GetModeChar());
949                 }
950                 else
951                 {
952                         sprintf(moderemove,"-%c",this->GetModeChar());
953                         parameters.push_back(user->nick);
954                         parameters.push_back(moderemove);
955                         ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
956                 }
957         }
958 }
959
960 /** This default implementation can remove simple channel modes
961  * (no parameters)
962  */
963 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
964 {
965         char moderemove[MAXBUF];
966         std::vector<std::string> parameters;
967
968         if (channel->IsModeSet(this->GetModeChar()))
969         {
970                 if (stack)
971                 {
972                         stack->Push(this->GetModeChar());
973                 }
974                 else
975                 {
976                         sprintf(moderemove,"-%c",this->GetModeChar());
977                         parameters.push_back(channel->name);
978                         parameters.push_back(moderemove);
979                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
980                 }
981         }
982 }
983
984 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
985 {
986         ModeHandler* modes[] =
987         {
988                 new ModeChannelSecret(Instance),
989                 new ModeChannelPrivate(Instance),
990                 new ModeChannelModerated(Instance),
991                 new ModeChannelTopicOps(Instance),
992
993                 new ModeChannelNoExternal(Instance),
994                 new ModeChannelInviteOnly(Instance),
995                 new ModeChannelKey(Instance),
996                 new ModeChannelLimit(Instance),
997
998                 new ModeChannelBan(Instance),
999                 new ModeChannelOp(Instance),
1000                 new ModeChannelHalfOp(Instance),
1001                 new ModeChannelVoice(Instance),
1002
1003                 new ModeUserWallops(Instance),
1004                 new ModeUserInvisible(Instance),
1005                 new ModeUserOperator(Instance),
1006                 new ModeUserServerNoticeMask(Instance),
1007 #define BUILTIN_MODE_COUNT 16
1008         };
1009
1010         /* Clear mode handler list */
1011         memset(modehandlers, 0, sizeof(modehandlers));
1012
1013         /* Last parse string */
1014         LastParse.clear();
1015
1016         /* Initialise the RFC mode letters */
1017         for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1018                 this->AddMode(modes[index]);
1019
1020         seq = 0;
1021         memset(&sent, 0, sizeof(sent));
1022 }
1023
1024 ModeParser::~ModeParser()
1025 {
1026         int count = 0;
1027         for(int i=0; i < 256; i++)
1028         {
1029                 ModeHandler* mh = modehandlers[i];
1030                 if (mh)
1031                 {
1032                         count++;
1033                         delete mh;
1034                 }
1035         }
1036         if (count != BUILTIN_MODE_COUNT)
1037                 throw CoreException("Mode handler found non-core modes remaining at deallocation");
1038 }