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