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