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