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