]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Remove "servermode" parameter, replace with IS_FAKE() which is more reliable
[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 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
252 {
253         if (!chan)
254                 return "";
255
256         UCListIter n = d->chans.find(chan);
257         if (n != d->chans.end())
258         {
259                 if (n->second & MASK)
260                 {
261                         return "";
262                 }
263                 n->second = n->second | MASK;
264                 switch (MASK)
265                 {
266                         case UCMODE_OP:
267                                 n->first->AddOppedUser(d);
268                         break;
269                         case UCMODE_HOP:
270                                 n->first->AddHalfoppedUser(d);
271                         break;
272                         case UCMODE_VOICE:
273                                 n->first->AddVoicedUser(d);
274                         break;
275                 }
276                 return d->nick.c_str();
277         }
278         return "";
279 }
280
281 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
282 {
283         if (!chan)
284                 return "";
285
286         UCListIter n = d->chans.find(chan);
287         if (n != d->chans.end())
288         {
289                 if ((n->second & MASK) == 0)
290                 {
291                         return "";
292                 }
293                 n->second ^= MASK;
294                 switch (MASK)
295                 {
296                         case UCMODE_OP:
297                                 n->first->DelOppedUser(d);
298                         break;
299                         case UCMODE_HOP:
300                                 n->first->DelHalfoppedUser(d);
301                         break;
302                         case UCMODE_VOICE:
303                                 n->first->DelVoicedUser(d);
304                         break;
305                 }
306                 return d->nick.c_str();
307         }
308         return "";
309 }
310
311 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
312 {
313         if (targetchannel)
314         {
315                 /* Display channel's current mode string */
316                 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
317                 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
318                 return;
319         }
320         else
321         {
322                 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
323                 {
324                         user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
325                         return;
326                 }
327
328                 if (targetuser == user || user->HasPrivPermission("users/auspex"))
329                 {
330                         /* Display user's current mode string */
331                         user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
332                         if (IS_OPER(targetuser))
333                                 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
334                         return;
335                 }
336                 else
337                 {
338                         user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
339                         return;
340                 }
341         }
342 }
343
344 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
345                 std::string &parameter, bool SkipACL)
346 {
347         ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
348         unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
349
350         ModeHandler *mh = FindMode(modechar, type);
351         int pcnt = mh->GetNumParams(adding);
352
353         int MOD_RESULT = 0;
354         FOREACH_RESULT(I_OnRawMode, OnRawMode(user, chan, modechar, parameter, adding, pcnt));
355
356         if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
357                 return MODEACTION_DENY;
358
359         if (chan && !SkipACL && (MOD_RESULT != ACR_ALLOW))
360         {
361                 char needed = mh->GetNeededPrefix();
362                 ModeHandler* prefixmode = FindPrefix(needed);
363
364                 /* If the mode defined by the handler is not '\0', but the handler for it
365                  * cannot be found, they probably dont have the right module loaded to implement
366                  * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
367                  * Revert to checking against the minimum core prefix, '%'.
368                  */
369                 if (needed && !prefixmode)
370                 {
371                         needed = ServerInstance->Config->AllowHalfop ? '%' : '@';
372                         prefixmode = FindPrefix(needed);
373                 }
374
375                 if (needed)
376                 {
377                         unsigned int neededrank = prefixmode->GetPrefixRank();
378                         /* Compare our rank on the channel against the rank of the required prefix,
379                          * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
380                          * in NAMES(X) are not in rank order, we know the most powerful mode is listed
381                          * first, so we don't need to iterate, we just look up the first instead.
382                          */
383                         std::string modestring = chan->GetAllPrefixChars(user);
384                         char ml = (modestring.empty() ? '\0' : modestring[0]);
385                         ModeHandler* ourmode = FindPrefix(ml);
386                         if (!ourmode || ourmode->GetPrefixRank() < neededrank)
387                         {
388                                 /* Bog off */
389                                 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
390                                                 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
391                                 return MODEACTION_DENY;
392                         }
393                 }
394         }
395
396         unsigned char handler_id = (modechar - 'A') | mask;
397
398         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
399         {
400                 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
401                         return MODEACTION_DENY;
402                 /* A module whacked the parameter completely, and there was one. abort. */
403                 if (pcnt && parameter.empty())
404                         return MODEACTION_DENY;
405         }
406
407         if (IS_LOCAL(user) && !IS_OPER(user))
408         {
409                 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
410                 if (disabled[modechar - 'A'])
411                 {
412                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
413                                 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
414                         return MODEACTION_DENY;
415                 }
416         }
417
418         if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
419         {
420                 /* It's an oper only mode, and they don't have access to it. */
421                 if (IS_OPER(user))
422                 {
423                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
424                                         user->nick.c_str(), user->oper.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
425                 }
426                 else
427                 {
428                         user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
429                                         user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
430                 }
431                 return MODEACTION_DENY;
432         }
433
434         /* Call the handler for the mode */
435         ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
436
437         if (pcnt && parameter.empty())
438                 return MODEACTION_DENY;
439
440         if (ma != MODEACTION_ALLOW)
441                 return ma;
442
443         mh->ChangeCount(adding ? 1 : -1);
444
445         if (mh->GetPrefix() && chan)
446         {
447                 User* user_to_prefix = ServerInstance->FindNick(parameter);
448                 if (user_to_prefix)
449                         chan->SetPrefix(user_to_prefix, mh->GetPrefix(), mh->GetPrefixRank(), adding);
450         }
451
452         for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
453                 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
454
455         return MODEACTION_ALLOW;
456 }
457
458 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
459 {
460         std::string target = parameters[0];
461         Channel* targetchannel = ServerInstance->FindChan(target);
462         User* targetuser  = ServerInstance->FindNick(target);
463         ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
464
465         LastParse.clear();
466         LastParseParams.clear();
467         LastParseTranslate.clear();
468
469         if (!targetchannel && !targetuser)
470         {
471                 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
472                 return;
473         }
474         if (parameters.size() == 1)
475         {
476                 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
477                 return;
478         }
479
480         std::string mode_sequence = parameters[1];
481
482         bool SkipAccessChecks = false;
483
484         if (!IS_LOCAL(user) || ServerInstance->ULine(user->server))
485         {
486                 SkipAccessChecks = true;
487         }
488         else if (targetchannel)
489         {
490                 /* Overall access control hook for mode change */
491                 LastParse = mode_sequence;
492                 int MOD_RESULT = 0;
493                 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
494                 LastParse.clear();
495                 if (MOD_RESULT == ACR_DENY)
496                         return;
497                 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
498         }
499         else
500         {
501                 if (user != targetuser)
502                 {
503                         user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
504                         return;
505                 }
506         }
507
508
509         std::string output_mode;
510         std::ostringstream output_parameters;
511         LastParseParams.push_back(output_mode);
512         LastParseTranslate.push_back(TR_TEXT);
513
514         bool adding = true;
515         char output_pm = '\0'; // current output state, '+' or '-'
516         unsigned int param_at = 2;
517
518         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
519         {
520                 unsigned char modechar = *letter;
521                 if (modechar == '+' || modechar == '-')
522                 {
523                         adding = (modechar == '+');
524                         continue;
525                 }
526
527                 ModeHandler *mh = this->FindMode(modechar, type);
528                 if (!mh)
529                 {
530                         /* No mode handler? Unknown mode character then. */
531                         user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
532                         continue;
533                 }
534
535                 std::string parameter = "";
536                 int pcnt = mh->GetNumParams(adding);
537                 if (pcnt && param_at == parameters.size())
538                 {
539                         /* No parameter, continue to the next mode */
540                         mh->OnParameterMissing(user, targetuser, targetchannel);
541                         continue;
542                 }
543                 else if (pcnt)
544                 {
545                         parameter = parameters[param_at++];
546                         /* Make sure the user isn't trying to slip in an invalid parameter */
547                         if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
548                                 continue;
549                         if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
550                         {
551                                 std::string ours = targetchannel->GetModeParameter(modechar);
552                                 if (!mh->CheckTimeStamp(parameter, ours, targetchannel))
553                                         /* we won the mode merge, don't apply this mode */
554                                         continue;
555                         }
556                 }
557
558                 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
559
560                 if (ma != MODEACTION_ALLOW)
561                         continue;
562
563                 char needed_pm = adding ? '+' : '-';
564                 if (needed_pm != output_pm)
565                 {
566                         output_pm = needed_pm;
567                         output_mode.append(1, output_pm);
568                 }
569                 output_mode.append(1, modechar);
570
571                 if (pcnt)
572                 {
573                         output_parameters << " " << parameter;
574                         LastParseParams.push_back(parameter);
575                         LastParseTranslate.push_back(mh->GetTranslateType());
576                 }
577
578                 if ( (output_mode.length() + output_parameters.str().length() > 450)
579                                 || (output_mode.length() > 100)
580                                 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
581                 {
582                         /* mode sequence is getting too long */
583                         break;
584                 }
585         }
586
587         LastParseParams[0] = output_mode;
588
589         if (!output_mode.empty())
590         {
591                 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
592                 LastParse.append(" ");
593                 LastParse.append(output_mode);
594                 LastParse.append(output_parameters.str());
595
596                 if (targetchannel)
597                 {
598                         targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
599                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
600                 }
601                 else
602                 {
603                         targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
604                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
605                 }
606         }
607         else if (targetchannel && parameters.size() == 2)
608         {
609                 /* Special case for displaying the list for listmodes,
610                  * e.g. MODE #chan b, or MODE #chan +b without a parameter
611                  */
612                 this->DisplayListModes(user, targetchannel, mode_sequence);
613         }
614 }
615
616 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
617 {
618         seq++;
619
620         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
621         {
622                 unsigned char mletter = *letter;
623                 if (mletter == '+')
624                         continue;
625
626                 /* Ensure the user doesnt request the same mode twice,
627                  * so they cant flood themselves off out of idiocy.
628                  */
629                 if (sent[mletter] == seq)
630                         continue;
631
632                 sent[mletter] = seq;
633
634                 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
635
636                 if (!mh || !mh->IsListMode())
637                         return;
638
639                 int MOD_RESULT = 0;
640                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, chan, mletter, "", true, 0));
641                 if (MOD_RESULT == ACR_DENY)
642                         continue;
643
644                 bool display = true;
645                 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetStatus(user) < STATUS_HOP))
646                 {
647                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
648                                 user->nick.c_str(), chan->name.c_str(), mletter);
649                         display = false;
650                 }
651
652                 /** See below for a description of what craq this is :D
653                  */
654                 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
655
656                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
657                 {
658                         std::string dummyparam;
659
660                         if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
661                                 display = false;
662                 }
663                 if (display)
664                         mh->DisplayList(user, chan);
665                 else
666                         mh->DisplayEmptyList(user, chan);
667         }
668 }
669
670 const std::string& ModeParser::GetLastParse()
671 {
672         return LastParse;
673 }
674
675 void ModeParser::CleanMask(std::string &mask)
676 {
677         std::string::size_type pos_of_pling = mask.find_first_of('!');
678         std::string::size_type pos_of_at = mask.find_first_of('@');
679         std::string::size_type pos_of_dot = mask.find_first_of('.');
680         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
681
682         if (mask.length() >= 2 && mask[1] == ':')
683                 return; // if it's an extban, don't even try guess how it needs to be formed.
684
685         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
686         {
687                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
688                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
689                 {
690                         /* It has no '.' in it, it must be a nick. */
691                         mask.append("!*@*");
692                 }
693                 else
694                 {
695                         /* Got a dot in it? Has to be a host */
696                         mask = "*!*@" + mask;
697                 }
698         }
699         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
700         {
701                 /* Has an @ but no !, its a user@host */
702                  mask = "*!" + mask;
703         }
704         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
705         {
706                 /* Has a ! but no @, it must be a nick!ident */
707                 mask.append("@*");
708         }
709 }
710
711 bool ModeParser::AddMode(ModeHandler* mh)
712 {
713         unsigned char mask = 0;
714         unsigned char pos = 0;
715
716         /* Yes, i know, this might let people declare modes like '_' or '^'.
717          * If they do that, thats their problem, and if i ever EVER see an
718          * official InspIRCd developer do that, i'll beat them with a paddle!
719          */
720         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
721                 return false;
722
723         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
724          * A mode prefix of ':' will fuck up both server to server, and client to server.
725          * A mode prefix of '#' will mess up /whois and /privmsg
726          */
727         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
728                 return false;
729
730         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
731         pos = (mh->GetModeChar()-65) | mask;
732
733         if (modehandlers[pos])
734                 return false;
735
736         modehandlers[pos] = mh;
737         return true;
738 }
739
740 bool ModeParser::DelMode(ModeHandler* mh)
741 {
742         unsigned char mask = 0;
743         unsigned char pos = 0;
744
745         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
746                 return false;
747
748         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
749         pos = (mh->GetModeChar()-65) | mask;
750
751         if (!modehandlers[pos])
752                 return false;
753
754         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
755          * To stack here we have to make the algorithm slower. Discuss.
756          */
757         switch (mh->GetModeType())
758         {
759                 case MODETYPE_USER:
760                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
761                         {
762                                 mh->RemoveMode(i->second);
763                         }
764                 break;
765                 case MODETYPE_CHANNEL:
766                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
767                         {
768                                 mh->RemoveMode(i->second);
769                         }
770                 break;
771         }
772
773         modehandlers[pos] = NULL;
774
775         return true;
776 }
777
778 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
779 {
780         unsigned char mask = 0;
781         unsigned char pos = 0;
782
783         if ((modeletter < 'A') || (modeletter > 'z'))
784                 return NULL;
785
786         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
787         pos = (modeletter-65) | mask;
788
789         return modehandlers[pos];
790 }
791
792 std::string ModeParser::UserModeList()
793 {
794         char modestr[256];
795         int pointer = 0;
796
797         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
798         {
799                 unsigned char pos = (mode-65) | MASK_USER;
800
801                 if (modehandlers[pos])
802                         modestr[pointer++] = mode;
803         }
804         modestr[pointer++] = 0;
805         return modestr;
806 }
807
808 std::string ModeParser::ChannelModeList()
809 {
810         char modestr[256];
811         int pointer = 0;
812
813         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
814         {
815                 unsigned char pos = (mode-65) | MASK_CHANNEL;
816
817                 if (modehandlers[pos])
818                         modestr[pointer++] = mode;
819         }
820         modestr[pointer++] = 0;
821         return modestr;
822 }
823
824 std::string ModeParser::ParaModeList()
825 {
826         char modestr[256];
827         int pointer = 0;
828
829         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
830         {
831                 unsigned char pos = (mode-65) | MASK_CHANNEL;
832
833                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
834                         modestr[pointer++] = mode;
835         }
836         modestr[pointer++] = 0;
837         return modestr;
838 }
839
840 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
841 {
842         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
843         {
844                 unsigned char pos = (mode-65) | MASK_CHANNEL;
845
846                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
847                 {
848                         return modehandlers[pos];
849                 }
850         }
851         return NULL;
852 }
853
854 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
855 {
856         std::string types;
857         std::string pars;
858
859         if (!channel || !user)
860                 return "";
861
862         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
863         {
864                 unsigned char pos = (mode-65) | MASK_CHANNEL;
865                 ModeHandler* mh = modehandlers[pos];
866                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
867                 {
868                         ModePair ret;
869                         ret = mh->ModeSet(NULL, user, channel, user->nick);
870                         if ((ret.first) && (ret.second == user->nick))
871                         {
872                                 if (nick_suffix)
873                                 {
874                                         pars.append(" ");
875                                         pars.append(user->nick);
876                                 }
877                                 types.push_back(mh->GetModeChar());
878                         }
879                 }
880         }
881
882         if (nick_suffix)
883                 return types+pars;
884         else
885                 return types;
886 }
887
888 std::string ModeParser::GiveModeList(ModeMasks m)
889 {
890         std::string type1;      /* Listmodes EXCEPT those with a prefix */
891         std::string type2;      /* Modes that take a param when adding or removing */
892         std::string type3;      /* Modes that only take a param when adding */
893         std::string type4;      /* Modes that dont take a param */
894
895         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
896         {
897                 unsigned char pos = (mode-65) | m;
898                  /* One parameter when adding */
899                 if (modehandlers[pos])
900                 {
901                         if (modehandlers[pos]->GetNumParams(true))
902                         {
903                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
904                                 {
905                                         type1 += modehandlers[pos]->GetModeChar();
906                                 }
907                                 else
908                                 {
909                                         /* ... and one parameter when removing */
910                                         if (modehandlers[pos]->GetNumParams(false))
911                                         {
912                                                 /* But not a list mode */
913                                                 if (!modehandlers[pos]->GetPrefix())
914                                                 {
915                                                         type2 += modehandlers[pos]->GetModeChar();
916                                                 }
917                                         }
918                                         else
919                                         {
920                                                 /* No parameters when removing */
921                                                 type3 += modehandlers[pos]->GetModeChar();
922                                         }
923                                 }
924                         }
925                         else
926                         {
927                                 type4 += modehandlers[pos]->GetModeChar();
928                         }
929                 }
930         }
931
932         return type1 + "," + type2 + "," + type3 + "," + type4;
933 }
934
935 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
936 {
937         return one.second > two.second;
938 }
939
940 std::string ModeParser::BuildPrefixes()
941 {
942         std::string mletters;
943         std::string mprefixes;
944         pfxcontainer pfx;
945         std::map<char,char> prefix_to_mode;
946
947         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
948         {
949                 unsigned char pos = (mode-65) | MASK_CHANNEL;
950
951                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
952                 {
953                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
954                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
955                 }
956         }
957
958         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
959
960         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
961         {
962                 mletters = mletters + n->first;
963                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
964         }
965
966         return "(" + mprefixes + ")" + mletters;
967 }
968
969 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
970 {
971         unsigned char mask = 0;
972         unsigned char pos = 0;
973
974         if (!mw)
975                 return false;
976
977         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
978                 return false;
979
980         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
981         pos = (mw->GetModeChar()-65) | mask;
982
983         modewatchers[pos].push_back(mw);
984
985         return true;
986 }
987
988 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
989 {
990         unsigned char mask = 0;
991         unsigned char pos = 0;
992
993         if (!mw)
994                 return false;
995
996         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
997                 return false;
998
999         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1000         pos = (mw->GetModeChar()-65) | mask;
1001
1002         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1003
1004         if (a == modewatchers[pos].end())
1005         {
1006                 return false;
1007         }
1008
1009         modewatchers[pos].erase(a);
1010
1011         return true;
1012 }
1013
1014 /** This default implementation can remove simple user modes
1015  */
1016 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1017 {
1018         char moderemove[MAXBUF];
1019         std::vector<std::string> parameters;
1020
1021         if (user->IsModeSet(this->GetModeChar()))
1022         {
1023                 if (stack)
1024                 {
1025                         stack->Push(this->GetModeChar());
1026                 }
1027                 else
1028                 {
1029                         sprintf(moderemove,"-%c",this->GetModeChar());
1030                         parameters.push_back(user->nick);
1031                         parameters.push_back(moderemove);
1032                         ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
1033                 }
1034         }
1035 }
1036
1037 /** This default implementation can remove simple channel modes
1038  * (no parameters)
1039  */
1040 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1041 {
1042         char moderemove[MAXBUF];
1043         std::vector<std::string> parameters;
1044
1045         if (channel->IsModeSet(this->GetModeChar()))
1046         {
1047                 if (stack)
1048                 {
1049                         stack->Push(this->GetModeChar());
1050                 }
1051                 else
1052                 {
1053                         sprintf(moderemove,"-%c",this->GetModeChar());
1054                         parameters.push_back(channel->name);
1055                         parameters.push_back(moderemove);
1056                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1057                 }
1058         }
1059 }
1060
1061 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1062 {
1063         ModeHandler* modes[] =
1064         {
1065                 new ModeChannelSecret(Instance),
1066                 new ModeChannelPrivate(Instance),
1067                 new ModeChannelModerated(Instance),
1068                 new ModeChannelTopicOps(Instance),
1069
1070                 new ModeChannelNoExternal(Instance),
1071                 new ModeChannelInviteOnly(Instance),
1072                 new ModeChannelKey(Instance),
1073                 new ModeChannelLimit(Instance),
1074
1075                 new ModeChannelBan(Instance),
1076                 new ModeChannelOp(Instance),
1077                 new ModeChannelHalfOp(Instance),
1078                 new ModeChannelVoice(Instance),
1079
1080                 new ModeUserWallops(Instance),
1081                 new ModeUserInvisible(Instance),
1082                 new ModeUserOperator(Instance),
1083                 new ModeUserServerNoticeMask(Instance),
1084 #define BUILTIN_MODE_COUNT 16
1085         };
1086
1087         /* Clear mode handler list */
1088         memset(modehandlers, 0, sizeof(modehandlers));
1089
1090         /* Last parse string */
1091         LastParse.clear();
1092
1093         /* Initialise the RFC mode letters */
1094         for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1095                 this->AddMode(modes[index]);
1096
1097         seq = 0;
1098         memset(&sent, 0, sizeof(sent));
1099 }
1100
1101 ModeParser::~ModeParser()
1102 {
1103         int count = 0;
1104         for(int i=0; i < 256; i++)
1105         {
1106                 ModeHandler* mh = modehandlers[i];
1107                 if (mh)
1108                 {
1109                         count++;
1110                         delete mh;
1111                 }
1112         }
1113         if (count != BUILTIN_MODE_COUNT)
1114                 throw CoreException("Mode handler found non-core modes remaining at deallocation");
1115 }