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