]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/mode.cpp
Add Module* creator to Command and ModeHandler
[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, 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, bool servermode)
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, bool servermode)
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, bool)
227 {
228         return true;
229 }
230
231 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
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 servermode, 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, servermode));
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, servermode) == 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, servermode);
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, servermode);
454
455         return MODEACTION_ALLOW;
456 }
457
458 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode, 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 (servermode || !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, servermode, 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 (!user && targetchannel)
597                         targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s", LastParse.c_str());
598                 else if (!user && targetuser)
599                         targetuser->WriteServ("MODE %s", LastParse.c_str());
600                 else if (targetchannel)
601                 {
602                         targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
603                         FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
604                 }
605                 else if (targetuser)
606                 {
607                         targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
608                         FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
609                 }
610         }
611         else if (targetchannel && parameters.size() == 2)
612         {
613                 /* Special case for displaying the list for listmodes,
614                  * e.g. MODE #chan b, or MODE #chan +b without a parameter
615                  */
616                 this->DisplayListModes(user, targetchannel, mode_sequence);
617         }
618 }
619
620 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
621 {
622         seq++;
623
624         for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
625         {
626                 unsigned char mletter = *letter;
627                 if (mletter == '+')
628                         continue;
629
630                 /* Ensure the user doesnt request the same mode twice,
631                  * so they cant flood themselves off out of idiocy.
632                  */
633                 if (sent[mletter] == seq)
634                         continue;
635
636                 sent[mletter] = seq;
637
638                 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
639
640                 if (!mh || !mh->IsListMode())
641                         return;
642
643                 int MOD_RESULT = 0;
644                 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, chan, mletter, "", true, 0));
645                 if (MOD_RESULT == ACR_DENY)
646                         continue;
647
648                 bool display = true;
649                 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetStatus(user) < STATUS_HOP))
650                 {
651                         user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
652                                 user->nick.c_str(), chan->name.c_str(), mletter);
653                         display = false;
654                 }
655
656                 /** See below for a description of what craq this is :D
657                  */
658                 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
659
660                 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
661                 {
662                         std::string dummyparam;
663
664                         if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
665                                 display = false;
666                 }
667                 if (display)
668                         mh->DisplayList(user, chan);
669                 else
670                         mh->DisplayEmptyList(user, chan);
671         }
672 }
673
674 const std::string& ModeParser::GetLastParse()
675 {
676         return LastParse;
677 }
678
679 void ModeParser::CleanMask(std::string &mask)
680 {
681         std::string::size_type pos_of_pling = mask.find_first_of('!');
682         std::string::size_type pos_of_at = mask.find_first_of('@');
683         std::string::size_type pos_of_dot = mask.find_first_of('.');
684         std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
685
686         if (mask.length() >= 2 && mask[1] == ':')
687                 return; // if it's an extban, don't even try guess how it needs to be formed.
688
689         if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
690         {
691                 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
692                 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
693                 {
694                         /* It has no '.' in it, it must be a nick. */
695                         mask.append("!*@*");
696                 }
697                 else
698                 {
699                         /* Got a dot in it? Has to be a host */
700                         mask = "*!*@" + mask;
701                 }
702         }
703         else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
704         {
705                 /* Has an @ but no !, its a user@host */
706                  mask = "*!" + mask;
707         }
708         else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
709         {
710                 /* Has a ! but no @, it must be a nick!ident */
711                 mask.append("@*");
712         }
713 }
714
715 bool ModeParser::AddMode(ModeHandler* mh)
716 {
717         unsigned char mask = 0;
718         unsigned char pos = 0;
719
720         /* Yes, i know, this might let people declare modes like '_' or '^'.
721          * If they do that, thats their problem, and if i ever EVER see an
722          * official InspIRCd developer do that, i'll beat them with a paddle!
723          */
724         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
725                 return false;
726
727         /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
728          * A mode prefix of ':' will fuck up both server to server, and client to server.
729          * A mode prefix of '#' will mess up /whois and /privmsg
730          */
731         if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
732                 return false;
733
734         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
735         pos = (mh->GetModeChar()-65) | mask;
736
737         if (modehandlers[pos])
738                 return false;
739
740         modehandlers[pos] = mh;
741         return true;
742 }
743
744 bool ModeParser::DelMode(ModeHandler* mh)
745 {
746         unsigned char mask = 0;
747         unsigned char pos = 0;
748
749         if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
750                 return false;
751
752         mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
753         pos = (mh->GetModeChar()-65) | mask;
754
755         if (!modehandlers[pos])
756                 return false;
757
758         /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
759          * To stack here we have to make the algorithm slower. Discuss.
760          */
761         switch (mh->GetModeType())
762         {
763                 case MODETYPE_USER:
764                         for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
765                         {
766                                 mh->RemoveMode(i->second);
767                         }
768                 break;
769                 case MODETYPE_CHANNEL:
770                         for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
771                         {
772                                 mh->RemoveMode(i->second);
773                         }
774                 break;
775         }
776
777         modehandlers[pos] = NULL;
778
779         return true;
780 }
781
782 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
783 {
784         unsigned char mask = 0;
785         unsigned char pos = 0;
786
787         if ((modeletter < 'A') || (modeletter > 'z'))
788                 return NULL;
789
790         mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
791         pos = (modeletter-65) | mask;
792
793         return modehandlers[pos];
794 }
795
796 std::string ModeParser::UserModeList()
797 {
798         char modestr[256];
799         int pointer = 0;
800
801         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
802         {
803                 unsigned char pos = (mode-65) | MASK_USER;
804
805                 if (modehandlers[pos])
806                         modestr[pointer++] = mode;
807         }
808         modestr[pointer++] = 0;
809         return modestr;
810 }
811
812 std::string ModeParser::ChannelModeList()
813 {
814         char modestr[256];
815         int pointer = 0;
816
817         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
818         {
819                 unsigned char pos = (mode-65) | MASK_CHANNEL;
820
821                 if (modehandlers[pos])
822                         modestr[pointer++] = mode;
823         }
824         modestr[pointer++] = 0;
825         return modestr;
826 }
827
828 std::string ModeParser::ParaModeList()
829 {
830         char modestr[256];
831         int pointer = 0;
832
833         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
834         {
835                 unsigned char pos = (mode-65) | MASK_CHANNEL;
836
837                 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
838                         modestr[pointer++] = mode;
839         }
840         modestr[pointer++] = 0;
841         return modestr;
842 }
843
844 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
845 {
846         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
847         {
848                 unsigned char pos = (mode-65) | MASK_CHANNEL;
849
850                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
851                 {
852                         return modehandlers[pos];
853                 }
854         }
855         return NULL;
856 }
857
858 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
859 {
860         std::string types;
861         std::string pars;
862
863         if (!channel || !user)
864                 return "";
865
866         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
867         {
868                 unsigned char pos = (mode-65) | MASK_CHANNEL;
869                 ModeHandler* mh = modehandlers[pos];
870                 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
871                 {
872                         ModePair ret;
873                         ret = mh->ModeSet(NULL, user, channel, user->nick);
874                         if ((ret.first) && (ret.second == user->nick))
875                         {
876                                 if (nick_suffix)
877                                 {
878                                         pars.append(" ");
879                                         pars.append(user->nick);
880                                 }
881                                 types.push_back(mh->GetModeChar());
882                         }
883                 }
884         }
885
886         if (nick_suffix)
887                 return types+pars;
888         else
889                 return types;
890 }
891
892 std::string ModeParser::GiveModeList(ModeMasks m)
893 {
894         std::string type1;      /* Listmodes EXCEPT those with a prefix */
895         std::string type2;      /* Modes that take a param when adding or removing */
896         std::string type3;      /* Modes that only take a param when adding */
897         std::string type4;      /* Modes that dont take a param */
898
899         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
900         {
901                 unsigned char pos = (mode-65) | m;
902                  /* One parameter when adding */
903                 if (modehandlers[pos])
904                 {
905                         if (modehandlers[pos]->GetNumParams(true))
906                         {
907                                 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
908                                 {
909                                         type1 += modehandlers[pos]->GetModeChar();
910                                 }
911                                 else
912                                 {
913                                         /* ... and one parameter when removing */
914                                         if (modehandlers[pos]->GetNumParams(false))
915                                         {
916                                                 /* But not a list mode */
917                                                 if (!modehandlers[pos]->GetPrefix())
918                                                 {
919                                                         type2 += modehandlers[pos]->GetModeChar();
920                                                 }
921                                         }
922                                         else
923                                         {
924                                                 /* No parameters when removing */
925                                                 type3 += modehandlers[pos]->GetModeChar();
926                                         }
927                                 }
928                         }
929                         else
930                         {
931                                 type4 += modehandlers[pos]->GetModeChar();
932                         }
933                 }
934         }
935
936         return type1 + "," + type2 + "," + type3 + "," + type4;
937 }
938
939 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
940 {
941         return one.second > two.second;
942 }
943
944 std::string ModeParser::BuildPrefixes()
945 {
946         std::string mletters;
947         std::string mprefixes;
948         pfxcontainer pfx;
949         std::map<char,char> prefix_to_mode;
950
951         for (unsigned char mode = 'A'; mode <= 'z'; mode++)
952         {
953                 unsigned char pos = (mode-65) | MASK_CHANNEL;
954
955                 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
956                 {
957                         pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
958                         prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
959                 }
960         }
961
962         sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
963
964         for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
965         {
966                 mletters = mletters + n->first;
967                 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
968         }
969
970         return "(" + mprefixes + ")" + mletters;
971 }
972
973 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
974 {
975         unsigned char mask = 0;
976         unsigned char pos = 0;
977
978         if (!mw)
979                 return false;
980
981         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
982                 return false;
983
984         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
985         pos = (mw->GetModeChar()-65) | mask;
986
987         modewatchers[pos].push_back(mw);
988
989         return true;
990 }
991
992 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
993 {
994         unsigned char mask = 0;
995         unsigned char pos = 0;
996
997         if (!mw)
998                 return false;
999
1000         if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1001                 return false;
1002
1003         mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1004         pos = (mw->GetModeChar()-65) | mask;
1005
1006         ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1007
1008         if (a == modewatchers[pos].end())
1009         {
1010                 return false;
1011         }
1012
1013         modewatchers[pos].erase(a);
1014
1015         return true;
1016 }
1017
1018 /** This default implementation can remove simple user modes
1019  */
1020 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1021 {
1022         char moderemove[MAXBUF];
1023         std::vector<std::string> parameters;
1024
1025         if (user->IsModeSet(this->GetModeChar()))
1026         {
1027                 if (stack)
1028                 {
1029                         stack->Push(this->GetModeChar());
1030                 }
1031                 else
1032                 {
1033                         sprintf(moderemove,"-%c",this->GetModeChar());
1034                         parameters.push_back(user->nick);
1035                         parameters.push_back(moderemove);
1036                         ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, true);
1037                 }
1038         }
1039 }
1040
1041 /** This default implementation can remove simple channel modes
1042  * (no parameters)
1043  */
1044 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1045 {
1046         char moderemove[MAXBUF];
1047         std::vector<std::string> parameters;
1048
1049         if (channel->IsModeSet(this->GetModeChar()))
1050         {
1051                 if (stack)
1052                 {
1053                         stack->Push(this->GetModeChar());
1054                 }
1055                 else
1056                 {
1057                         sprintf(moderemove,"-%c",this->GetModeChar());
1058                         parameters.push_back(channel->name);
1059                         parameters.push_back(moderemove);
1060                         ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1061                 }
1062         }
1063 }
1064
1065 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1066 {
1067         ModeHandler* modes[] =
1068         {
1069                 new ModeChannelSecret(Instance),
1070                 new ModeChannelPrivate(Instance),
1071                 new ModeChannelModerated(Instance),
1072                 new ModeChannelTopicOps(Instance),
1073
1074                 new ModeChannelNoExternal(Instance),
1075                 new ModeChannelInviteOnly(Instance),
1076                 new ModeChannelKey(Instance),
1077                 new ModeChannelLimit(Instance),
1078
1079                 new ModeChannelBan(Instance),
1080                 new ModeChannelOp(Instance),
1081                 new ModeChannelHalfOp(Instance),
1082                 new ModeChannelVoice(Instance),
1083
1084                 new ModeUserWallops(Instance),
1085                 new ModeUserInvisible(Instance),
1086                 new ModeUserOperator(Instance),
1087                 new ModeUserServerNoticeMask(Instance),
1088 #define BUILTIN_MODE_COUNT 16
1089         };
1090
1091         /* Clear mode handler list */
1092         memset(modehandlers, 0, sizeof(modehandlers));
1093
1094         /* Last parse string */
1095         LastParse.clear();
1096
1097         /* Initialise the RFC mode letters */
1098         for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1099                 this->AddMode(modes[index]);
1100
1101         seq = 0;
1102         memset(&sent, 0, sizeof(sent));
1103 }
1104
1105 ModeParser::~ModeParser()
1106 {
1107         int count = 0;
1108         for(int i=0; i < 256; i++)
1109         {
1110                 ModeHandler* mh = modehandlers[i];
1111                 if (mh)
1112                 {
1113                         count++;
1114                         delete mh;
1115                 }
1116         }
1117         if (count != BUILTIN_MODE_COUNT)
1118                 throw CoreException("Mode handler found non-core modes remaining at deallocation");
1119 }