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