]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Release v2.0.23
[user/henk/code/inspircd.git] / src / mode.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2012 Shawn Smith <shawn@inspircd.org>
5  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
6  *   Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
7  *   Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
8  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
9  *   Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc>
10  *   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
11  *
12  * This file is part of InspIRCd.  InspIRCd is free software: you can
13  * redistribute it and/or modify it under the terms of the GNU General Public
14  * License as published by the Free Software Foundation, version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25
26 #include "inspircd.h"
27
28 /* +s (secret) */
29 /* +p (private) */
30 /* +m (moderated) */
31 /* +t (only (half) ops can change topic) */
32 /* +n (no external messages) */
33 /* +i (invite only) */
34 /* +w (see wallops) */
35 /* +i (invisible) */
36 #include "modes/simplemodes.h"
37 /* +b (bans) */
38 #include "modes/cmode_b.h"
39 /* +k (keyed channel) */
40 #include "modes/cmode_k.h"
41 /* +l (channel user limit) */
42 #include "modes/cmode_l.h"
43 /* +o (channel op) */
44 #include "modes/cmode_o.h"
45 /* +v (channel voice) */
46 #include "modes/cmode_v.h"
47 /* +o (operator) */
48 #include "modes/umode_o.h"
49 /* +s (server notice masks) */
50 #include "modes/umode_s.h"
51
52 ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modeletter, ParamSpec Params, ModeType type)
53         : ServiceProvider(Creator, Name, SERVICE_MODE), m_paramtype(TR_TEXT),
54         parameters_taken(Params), mode(modeletter), prefix(0), oper(false),
55         list(false), m_type(type), levelrequired(HALFOP_VALUE)
56 {
57 }
58
59 CullResult ModeHandler::cull()
60 {
61         if (ServerInstance->Modes)
62                 ServerInstance->Modes->DelMode(this);
63         return classbase::cull();
64 }
65
66 ModeHandler::~ModeHandler()
67 {
68 }
69
70 bool ModeHandler::IsListMode()
71 {
72         return list;
73 }
74
75 unsigned int ModeHandler::GetPrefixRank()
76 {
77         return 0;
78 }
79
80 int ModeHandler::GetNumParams(bool adding)
81 {
82         switch (parameters_taken)
83         {
84                 case PARAM_ALWAYS:
85                         return 1;
86                 case PARAM_SETONLY:
87                         return adding ? 1 : 0;
88                 case PARAM_NONE:
89                         break;
90         }
91         return 0;
92 }
93
94 std::string ModeHandler::GetUserParameter(User* user)
95 {
96         return "";
97 }
98
99 ModResult ModeHandler::AccessCheck(User*, Channel*, std::string &, bool)
100 {
101         return MOD_RES_PASSTHRU;
102 }
103
104 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool)
105 {
106         return MODEACTION_DENY;
107 }
108
109 void ModeHandler::DisplayList(User*, Channel*)
110 {
111 }
112
113 void ModeHandler::DisplayEmptyList(User*, Channel*)
114 {
115 }
116
117 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
118 {
119 }
120
121 bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ours, Channel*)
122 {
123         return (theirs < ours);
124 }
125
126 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
127 {
128         /* We're either trying to add a mode we already have or
129                 remove a mode we don't have, deny. */
130         if (dest->IsModeSet(this->GetModeChar()) == adding)
131                 return MODEACTION_DENY;
132
133         /* adding will be either true or false, depending on if we
134                 are adding or removing the mode, since we already checked
135                 to make sure we aren't adding a mode we have or that we
136                 aren't removing a mode we don't have, we don't have to do any
137                 other checks here to see if it's true or false, just add or
138                 remove the mode */
139         dest->SetMode(this->GetModeChar(), adding);
140
141         return MODEACTION_ALLOW;
142 }
143
144
145 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
146 {
147         /* We're either trying to add a mode we already have or
148                 remove a mode we don't have, deny. */
149         if (channel->IsModeSet(this->GetModeChar()) == adding)
150                 return MODEACTION_DENY;
151
152         /* adding will be either true or false, depending on if we
153                 are adding or removing the mode, since we already checked
154                 to make sure we aren't adding a mode we have or that we
155                 aren't removing a mode we don't have, we don't have to do any
156                 other checks here to see if it's true or false, just add or
157                 remove the mode */
158         channel->SetMode(this->GetModeChar(), adding);
159
160         return MODEACTION_ALLOW;
161 }
162
163 ModeAction ParamChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
164 {
165         if (adding && !ParamValidate(parameter))
166                 return MODEACTION_DENY;
167         std::string now = channel->GetModeParameter(this);
168         if (parameter == now)
169                 return MODEACTION_DENY;
170         if (adding)
171                 channel->SetModeParam(this, parameter);
172         else
173                 channel->SetModeParam(this, "");
174         return MODEACTION_ALLOW;
175 }
176
177 bool ParamChannelModeHandler::ParamValidate(std::string& parameter)
178 {
179         return true;
180 }
181
182 ModeWatcher::ModeWatcher(Module* Creator, char modeletter, ModeType type)
183         : mode(modeletter), m_type(type), creator(Creator)
184 {
185 }
186
187 ModeWatcher::~ModeWatcher()
188 {
189 }
190
191 char ModeWatcher::GetModeChar()
192 {
193         return mode;
194 }
195
196 ModeType ModeWatcher::GetModeType()
197 {
198         return m_type;
199 }
200
201 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
202 {
203         return true;
204 }
205
206 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
207 {
208 }
209
210 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
211 {
212         User *d;
213         if ((!user) || (!dest) || (!chan) || (!*dest))
214         {
215                 return NULL;
216         }
217         d = ServerInstance->FindNick(dest);
218         if (!d)
219         {
220                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
221                 return NULL;
222         }
223         return d;
224 }
225
226 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
227 {
228         if (targetchannel)
229         {
230                 /* Display channel's current mode string */
231                 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
232                 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
233                 return;
234         }
235         else
236         {
237                 if (targetuser == user || user->HasPrivPermission("users/auspex"))
238                 {
239                         /* Display user's current mode string */
240                         user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
241                         if (IS_OPER(targetuser))
242                                 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
243                         return;
244                 }
245                 else
246                 {
247                         user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't view modes for other users", user->nick.c_str());
248                         return;
249                 }
250         }
251 }
252
253 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
254                 std::string &parameter, bool SkipACL)
255 {
256         ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
257         unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
258
259         ModeHandler *mh = FindMode(modechar, type);
260         int pcnt = mh->GetNumParams(adding);
261
262         // crop mode parameter size to 250 characters
263         if (parameter.length() > 250 && adding)
264                 parameter = parameter.substr(0, 250);
265
266         ModResult MOD_RESULT;
267         FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt));
268
269         if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY))
270                 return MODEACTION_DENY;
271
272         if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW))
273         {
274                 MOD_RESULT = mh->AccessCheck(user, chan, parameter, adding);
275
276                 if (MOD_RESULT == MOD_RES_DENY)
277                         return MODEACTION_DENY;
278                 if (MOD_RESULT == MOD_RES_PASSTHRU)
279                 {
280                         unsigned int neededrank = mh->GetLevelRequired();
281                         /* Compare our rank on the channel against the rank of the required prefix,
282                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
283                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
284                          * first, so we don't need to iterate, we just look up the first instead.
285                          */
286                         unsigned int ourrank = chan->GetPrefixValue(user);
287                         if (ourrank < neededrank)
288                         {
289                                 ModeHandler* neededmh = NULL;
290                                 for(char c='A'; c <= 'z'; c++)
291                                 {
292                                         ModeHandler *privmh = FindMode(c, MODETYPE_CHANNEL);
293                                         if (privmh && privmh->GetPrefixRank() >= neededrank)
294                                         {
295                                                 // this mode is sufficient to allow this action
296                                                 if (!neededmh || privmh->GetPrefixRank() < neededmh->GetPrefixRank())
297                                                         neededmh = privmh;
298                                         }
299                                 }
300                                 if (neededmh)
301                                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel %s access or above to %sset channel mode %c",
302                                                 user->nick.c_str(), chan->name.c_str(), neededmh->name.c_str(), adding ? "" : "un", modechar);
303                                 else
304                                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You cannot %sset channel mode %c",
305                                                 user->nick.c_str(), chan->name.c_str(), adding ? "" : "un", modechar);
306                                 return MODEACTION_DENY;
307                         }
308                 }
309         }
310
311         unsigned char handler_id = (modechar - 'A') | mask;
312
313         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
314         {
315                 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
316                         return MODEACTION_DENY;
317                 /* A module whacked the parameter completely, and there was one. abort. */
318                 if (pcnt && parameter.empty())
319                         return MODEACTION_DENY;
320         }
321
322         if (IS_LOCAL(user) && !IS_OPER(user))
323         {
324                 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
325                 if (disabled[modechar - 'A'])
326                 {
327                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
328                                 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
329                         return MODEACTION_DENY;
330                 }
331         }
332
333         if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
334         {
335                 /* It's an oper only mode, and they don't have access to it. */
336                 if (IS_OPER(user))
337                 {
338                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
339                                         user->nick.c_str(), user->oper->NameStr(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
340                 }
341                 else
342                 {
343                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
344                                         user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
345                 }
346                 return MODEACTION_DENY;
347         }
348
349         if (mh->GetTranslateType() == TR_NICK)
350         {
351                 User* prefixtarget;
352                 if (IS_LOCAL(user))
353                         prefixtarget = ServerInstance->FindNickOnly(parameter);
354                 else
355                         prefixtarget = ServerInstance->FindNick(parameter);
356
357                 if (!prefixtarget)
358                 {
359                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameter.c_str());
360                         return MODEACTION_DENY;
361                 }
362         }
363
364         if (mh->GetPrefixRank() && chan)
365         {
366                 User* user_to_prefix = ServerInstance->FindNick(parameter);
367                 if (!user_to_prefix)
368                         return MODEACTION_DENY;
369                 if (!chan->SetPrefix(user_to_prefix, modechar, adding))
370                         return MODEACTION_DENY;
371         }
372
373         /* Call the handler for the mode */
374         ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
375
376         if (pcnt && parameter.empty())
377                 return MODEACTION_DENY;
378
379         if (ma != MODEACTION_ALLOW)
380                 return ma;
381
382         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
383                 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
384
385         return MODEACTION_ALLOW;
386 }
387
388 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
389 {
390         const std::string& target = parameters[0];
391         Channel* targetchannel = ServerInstance->FindChan(target);
392         User* targetuser = NULL;
393         if (!targetchannel)
394         {
395                 if (IS_LOCAL(user))
396                         targetuser = ServerInstance->FindNickOnly(target);
397                 else
398                         targetuser = ServerInstance->FindNick(target);
399         }
400         ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
401
402         LastParse.clear();
403         LastParseParams.clear();
404         LastParseTranslate.clear();
405
406         if ((!targetchannel) && ((!targetuser) || (IS_SERVER(targetuser))))
407         {
408                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
409                 return;
410         }
411         if (parameters.size() == 1)
412         {
413                 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
414                 return;
415         }
416
417         ModResult MOD_RESULT;
418         FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters));
419
420         bool SkipAccessChecks = false;
421
422         if (!IS_LOCAL(user) || ServerInstance->ULine(user->server) || MOD_RESULT == MOD_RES_ALLOW)
423                 SkipAccessChecks = true;
424         else if (MOD_RESULT == MOD_RES_DENY)
425                 return;
426
427         if (targetuser && !SkipAccessChecks && user != targetuser)
428         {
429                 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
430                 return;
431         }
432
433         std::string mode_sequence = parameters[1];
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.empty()) || (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->ResolveModeConflict(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                         TranslateType tt = mh->GetTranslateType();
500                         if (tt == TR_NICK)
501                         {
502                                 User* u = ServerInstance->FindNick(parameter);
503                                 if (u)
504                                         parameter = u->nick;
505                         }
506                         output_parameters << " " << parameter;
507                         LastParseParams.push_back(parameter);
508                         LastParseTranslate.push_back(tt);
509                 }
510
511                 if ( (output_mode.length() + output_parameters.str().length() > 450)
512                                 || (output_mode.length() > 100)
513                                 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
514                 {
515                         /* mode sequence is getting too long */
516                         break;
517                 }
518         }
519
520         LastParseParams[0] = output_mode;
521
522         if (!output_mode.empty())
523         {
524                 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
525                 LastParse.append(" ");
526                 LastParse.append(output_mode);
527                 LastParse.append(output_parameters.str());
528
529                 if (targetchannel)
530                 {
531                         targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
532                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
533                 }
534                 else
535                 {
536                         targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
537                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
538                 }
539         }
540         else if (targetchannel && parameters.size() == 2)
541         {
542                 /* Special case for displaying the list for listmodes,
543                  * e.g. MODE #chan b, or MODE #chan +b without a parameter
544                  */
545                 this->DisplayListModes(user, targetchannel, mode_sequence);
546         }
547 }
548
549 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
550 {
551         seq++;
552
553         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
554         {
555                 unsigned char mletter = *letter;
556                 if (mletter == '+')
557                         continue;
558
559                 /* Ensure the user doesnt request the same mode twice,
560                  * so they cant flood themselves off out of idiocy.
561                  */
562                 if (sent[mletter] == seq)
563                         continue;
564
565                 sent[mletter] = seq;
566
567                 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
568
569                 if (!mh || !mh->IsListMode())
570                         return;
571
572                 ModResult MOD_RESULT;
573                 FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
574                 if (MOD_RESULT == MOD_RES_DENY)
575                         continue;
576
577                 bool display = true;
578                 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
579                 {
580                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You do not have access to view the +%c list",
581                                 user->nick.c_str(), chan->name.c_str(), mletter);
582                         display = false;
583                 }
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         if (mh->GetPrefix() && FindPrefix(mh->GetPrefix()))
662                 return false;
663
664         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
665         pos = (mh->GetModeChar()-65) | mask;
666
667         if (modehandlers[pos])
668                 return false;
669
670         modehandlers[pos] = mh;
671         return true;
672 }
673
674 bool ModeParser::DelMode(ModeHandler* mh)
675 {
676         unsigned char mask = 0;
677         unsigned char pos = 0;
678
679         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
680                 return false;
681
682         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
683         pos = (mh->GetModeChar()-65) | mask;
684
685         if (modehandlers[pos] != mh)
686                 return false;
687
688         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
689          * To stack here we have to make the algorithm slower. Discuss.
690          */
691         switch (mh->GetModeType())
692         {
693                 case MODETYPE_USER:
694                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); )
695                         {
696                                 User* user = i->second;
697                                 ++i;
698                                 mh->RemoveMode(user);
699                         }
700                 break;
701                 case MODETYPE_CHANNEL:
702                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); )
703                         {
704                                 // The channel may not be in the hash after RemoveMode(), see m_permchannels
705                                 Channel* chan = i->second;
706                                 ++i;
707                                 mh->RemoveMode(chan);
708                         }
709                 break;
710         }
711
712         modehandlers[pos] = NULL;
713
714         return true;
715 }
716
717 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
718 {
719         unsigned char mask = 0;
720         unsigned char pos = 0;
721
722         if ((modeletter < 'A') || (modeletter > 'z'))
723                 return NULL;
724
725         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
726         pos = (modeletter-65) | mask;
727
728         return modehandlers[pos];
729 }
730
731 std::string ModeParser::UserModeList()
732 {
733         char modestr[256];
734         int pointer = 0;
735
736         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
737         {
738                 unsigned char pos = (mode-65) | MASK_USER;
739
740                 if (modehandlers[pos])
741                         modestr[pointer++] = mode;
742         }
743         modestr[pointer++] = 0;
744         return modestr;
745 }
746
747 std::string ModeParser::ChannelModeList()
748 {
749         char modestr[256];
750         int pointer = 0;
751
752         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
753         {
754                 unsigned char pos = (mode-65) | MASK_CHANNEL;
755
756                 if (modehandlers[pos])
757                         modestr[pointer++] = mode;
758         }
759         modestr[pointer++] = 0;
760         return modestr;
761 }
762
763 std::string ModeParser::ParaModeList()
764 {
765         char modestr[256];
766         int pointer = 0;
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]->GetNumParams(true)))
773                         modestr[pointer++] = mode;
774         }
775         modestr[pointer++] = 0;
776         return modestr;
777 }
778
779 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
780 {
781         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
782         {
783                 unsigned char pos = (mode-65) | MASK_CHANNEL;
784
785                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
786                 {
787                         return modehandlers[pos];
788                 }
789         }
790         return NULL;
791 }
792
793 std::string ModeParser::GiveModeList(ModeMasks m)
794 {
795         std::string type1;      /* Listmodes EXCEPT those with a prefix */
796         std::string type2;      /* Modes that take a param when adding or removing */
797         std::string type3;      /* Modes that only take a param when adding */
798         std::string type4;      /* Modes that dont take a param */
799
800         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
801         {
802                 unsigned char pos = (mode-65) | m;
803                  /* One parameter when adding */
804                 if (modehandlers[pos])
805                 {
806                         if (modehandlers[pos]->GetNumParams(true))
807                         {
808                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
809                                 {
810                                         type1 += modehandlers[pos]->GetModeChar();
811                                 }
812                                 else
813                                 {
814                                         /* ... and one parameter when removing */
815                                         if (modehandlers[pos]->GetNumParams(false))
816                                         {
817                                                 /* But not a list mode */
818                                                 if (!modehandlers[pos]->GetPrefix())
819                                                 {
820                                                         type2 += modehandlers[pos]->GetModeChar();
821                                                 }
822                                         }
823                                         else
824                                         {
825                                                 /* No parameters when removing */
826                                                 type3 += modehandlers[pos]->GetModeChar();
827                                         }
828                                 }
829                         }
830                         else
831                         {
832                                 type4 += modehandlers[pos]->GetModeChar();
833                         }
834                 }
835         }
836
837         return type1 + "," + type2 + "," + type3 + "," + type4;
838 }
839
840 struct PrefixModeSorter
841 {
842         bool operator()(ModeHandler* lhs, ModeHandler* rhs)
843         {
844                 return lhs->GetPrefixRank() < rhs->GetPrefixRank();
845         }
846 };
847
848 std::string ModeParser::BuildPrefixes(bool lettersAndModes)
849 {
850         std::string mletters;
851         std::string mprefixes;
852         std::vector<ModeHandler*> prefixes;
853
854         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
855         {
856                 unsigned char pos = (mode-65) | MASK_CHANNEL;
857
858                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
859                 {
860                         prefixes.push_back(modehandlers[pos]);
861                 }
862         }
863
864         std::sort(prefixes.begin(), prefixes.end(), PrefixModeSorter());
865         for (std::vector<ModeHandler*>::const_reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); ++n)
866         {
867                 mletters += (*n)->GetPrefix();
868                 mprefixes += (*n)->GetModeChar();
869         }
870
871         return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters;
872 }
873
874 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
875 {
876         unsigned char mask = 0;
877         unsigned char pos = 0;
878
879         if (!mw)
880                 return false;
881
882         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
883                 return false;
884
885         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
886         pos = (mw->GetModeChar()-65) | mask;
887
888         modewatchers[pos].push_back(mw);
889
890         return true;
891 }
892
893 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
894 {
895         unsigned char mask = 0;
896         unsigned char pos = 0;
897
898         if (!mw)
899                 return false;
900
901         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
902                 return false;
903
904         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
905         pos = (mw->GetModeChar()-65) | mask;
906
907         ModeWatchIter a = std::find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
908
909         if (a == modewatchers[pos].end())
910         {
911                 return false;
912         }
913
914         modewatchers[pos].erase(a);
915
916         return true;
917 }
918
919 /** This default implementation can remove simple user modes
920  */
921 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
922 {
923         if (user->IsModeSet(this->GetModeChar()))
924         {
925                 if (stack)
926                 {
927                         stack->Push(this->GetModeChar());
928                 }
929                 else
930                 {
931                         std::vector<std::string> parameters;
932                         parameters.push_back(user->nick);
933                         parameters.push_back("-");
934                         parameters[1].push_back(this->GetModeChar());
935                         ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
936                 }
937         }
938 }
939
940 /** This default implementation can remove simple channel modes
941  * (no parameters)
942  */
943 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
944 {
945         if (channel->IsModeSet(this->GetModeChar()))
946         {
947                 if (stack)
948                 {
949                         stack->Push(this->GetModeChar());
950                 }
951                 else
952                 {
953                         std::vector<std::string> parameters;
954                         parameters.push_back(channel->name);
955                         parameters.push_back("-");
956                         parameters[1].push_back(this->GetModeChar());
957                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
958                 }
959         }
960 }
961
962 struct builtin_modes
963 {
964         ModeChannelSecret s;
965         ModeChannelPrivate p;
966         ModeChannelModerated m;
967         ModeChannelTopicOps t;
968
969         ModeChannelNoExternal n;
970         ModeChannelInviteOnly i;
971         ModeChannelKey k;
972         ModeChannelLimit l;
973
974         ModeChannelBan b;
975         ModeChannelOp o;
976         ModeChannelVoice v;
977
978         ModeUserWallops uw;
979         ModeUserInvisible ui;
980         ModeUserOperator uo;
981         ModeUserServerNoticeMask us;
982
983         void init(ModeParser* modes)
984         {
985                 modes->AddMode(&s);
986                 modes->AddMode(&p);
987                 modes->AddMode(&m);
988                 modes->AddMode(&t);
989                 modes->AddMode(&n);
990                 modes->AddMode(&i);
991                 modes->AddMode(&k);
992                 modes->AddMode(&l);
993                 modes->AddMode(&b);
994                 modes->AddMode(&o);
995                 modes->AddMode(&v);
996                 modes->AddMode(&uw);
997                 modes->AddMode(&ui);
998                 modes->AddMode(&uo);
999                 modes->AddMode(&us);
1000         }
1001 };
1002
1003 static builtin_modes static_modes;
1004
1005 ModeParser::ModeParser()
1006 {
1007         /* Clear mode handler list */
1008         memset(modehandlers, 0, sizeof(modehandlers));
1009
1010         /* Last parse string */
1011         LastParse.clear();
1012
1013         seq = 0;
1014         memset(&sent, 0, sizeof(sent));
1015
1016         static_modes.init(this);
1017 }
1018
1019 ModeParser::~ModeParser()
1020 {
1021 }