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