1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 * See: http://wiki.inspircd.org/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
17 #include "inspstring.h"
20 #include "modes/cmode_s.h"
22 #include "modes/cmode_p.h"
24 #include "modes/cmode_b.h"
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"
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"
46 #include "modes/umode_i.h"
48 #include "modes/umode_o.h"
49 /* +s (server notice masks) */
50 #include "modes/umode_s.h"
52 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired, TranslateType translate)
53 : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), m_paramtype(translate), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
57 ModeHandler::~ModeHandler()
61 bool ModeHandler::IsListMode()
66 char ModeHandler::GetNeededPrefix()
68 if (prefixneeded == '%' && !ServerInstance->Config->AllowHalfop)
73 void ModeHandler::SetNeededPrefix(char needsprefix)
75 prefixneeded = needsprefix;
78 unsigned int ModeHandler::GetPrefixRank()
83 unsigned int ModeHandler::GetCount()
88 void ModeHandler::ChangeCount(int modifier)
91 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
94 ModeType ModeHandler::GetModeType()
99 TranslateType ModeHandler::GetTranslateType()
104 bool ModeHandler::NeedsOper()
109 char ModeHandler::GetPrefix()
114 int ModeHandler::GetNumParams(bool adding)
116 return adding ? n_params_on : n_params_off;
119 char ModeHandler::GetModeChar()
124 std::string ModeHandler::GetUserParameter(User* user)
129 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
131 return MODEACTION_DENY;
134 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
138 return std::make_pair(dest->IsModeSet(this->mode), "");
142 return std::make_pair(channel->IsModeSet(this->mode), "");
146 void ModeHandler::DisplayList(User*, Channel*)
150 void ModeHandler::DisplayEmptyList(User*, Channel*)
154 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
158 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
160 return (ours < theirs);
163 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
167 SimpleUserModeHandler::~SimpleUserModeHandler()
171 SimpleChannelModeHandler::~SimpleChannelModeHandler()
175 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
179 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
183 if (!dest->IsModeSet(this->GetModeChar()))
185 dest->SetMode(this->GetModeChar(),true);
186 return MODEACTION_ALLOW;
191 if (dest->IsModeSet(this->GetModeChar()))
193 dest->SetMode(this->GetModeChar(),false);
194 return MODEACTION_ALLOW;
198 return MODEACTION_DENY;
202 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
206 if (!channel->IsModeSet(this->GetModeChar()))
208 channel->SetMode(this->GetModeChar(),true);
209 return MODEACTION_ALLOW;
214 if (channel->IsModeSet(this->GetModeChar()))
216 channel->SetMode(this->GetModeChar(),false);
217 return MODEACTION_ALLOW;
221 return MODEACTION_DENY;
224 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
228 ModeWatcher::~ModeWatcher()
232 char ModeWatcher::GetModeChar()
237 ModeType ModeWatcher::GetModeType()
242 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
247 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
251 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
254 if ((!user) || (!dest) || (!chan) || (!*dest))
258 d = ServerInstance->FindNick(dest);
261 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
267 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
272 UCListIter n = d->chans.find(chan);
273 if (n != d->chans.end())
275 if (n->second & MASK)
279 n->second = n->second | MASK;
283 n->first->AddOppedUser(d);
286 n->first->AddHalfoppedUser(d);
289 n->first->AddVoicedUser(d);
292 return d->nick.c_str();
297 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
302 UCListIter n = d->chans.find(chan);
303 if (n != d->chans.end())
305 if ((n->second & MASK) == 0)
313 n->first->DelOppedUser(d);
316 n->first->DelHalfoppedUser(d);
319 n->first->DelVoicedUser(d);
322 return d->nick.c_str();
327 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
331 /* Display channel's current mode string */
332 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
333 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
338 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
340 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
344 if (targetuser == user || user->HasPrivPermission("users/auspex"))
346 /* Display user's current mode string */
347 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
348 if (IS_OPER(targetuser))
349 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
354 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
359 /* No such nick/channel */
360 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
364 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
366 std::string target = parameters[0];
367 ModeType type = MODETYPE_USER;
368 unsigned char mask = 0;
369 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
370 User* targetuser = ServerInstance->FindNick(parameters[0]);
373 LastParseParams.clear();
374 LastParseTranslate.clear();
376 /* Special case for displaying the list for listmodes,
377 * e.g. MODE #chan b, or MODE #chan +b without a parameter
379 if ((targetchannel) && (parameters.size() == 2))
381 const char* mode = parameters[1].c_str();
382 int nonlistmodes_found = 0;
388 while (mode && *mode)
390 unsigned char mletter = *mode;
398 /* Ensure the user doesnt request the same mode twice,
399 * so they cant flood themselves off out of idiocy.
401 if (sent[mletter] != seq)
411 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
414 if ((mh) && (mh->IsListMode()))
417 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
418 if (MOD_RESULT == ACR_DENY)
424 if (!user->HasPrivPermission("channels/auspex"))
426 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
428 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",user->nick.c_str(), targetchannel->name.c_str(), *mode++);
429 mh->DisplayEmptyList(user, targetchannel);
434 /** See below for a description of what craq this is :D
436 unsigned char handler_id = (*mode - 65) | mask;
438 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
440 std::string dummyparam;
442 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
447 mh->DisplayList(user, targetchannel);
450 nonlistmodes_found++;
455 /* We didnt have any modes that were non-list, we can return here */
456 if (!nonlistmodes_found)
460 if (parameters.size() == 1)
462 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
464 else if (parameters.size() > 1)
466 bool SkipAccessChecks = false;
470 type = MODETYPE_CHANNEL;
473 /* Extra security checks on channel modes
474 * (e.g. are they a (half)op?
477 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
479 /* Make modes that are being changed visible to OnAccessCheck */
480 LastParse = parameters[1];
481 /* We don't have halfop */
483 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
485 if (MOD_RESULT == ACR_DENY)
487 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
492 type = MODETYPE_USER;
494 if (user != targetuser && IS_LOCAL(user) && !ServerInstance->ULine(user->server))
496 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
502 /* No such nick/channel */
503 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
507 std::string mode_sequence = parameters[1];
508 std::string parameter;
509 std::ostringstream parameter_list;
510 std::string output_sequence;
511 bool adding = true, state_change = false;
512 unsigned char handler_id = 0;
513 unsigned int parameter_counter = 2; /* Index of first parameter */
514 unsigned int parameter_count = 0;
515 bool last_successful_state_change = false;
516 LastParseTranslate.push_back(TR_TEXT);
518 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
519 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
520 mode_sequence.insert(0, "+");
522 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
524 unsigned char modechar = *letter;
529 * For + and - mode characters, we don't just stick the character into the output sequence.
530 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
531 * appearing in the output sequence, we store a flag which says there was a state change,
532 * which is set on any + or -, however, the + or - that we finish on is only appended to
533 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
536 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
537 * however, will allow the + if it is the first item in the sequence, regardless.
539 if ((!adding) || (!output_sequence.length()))
542 if (!output_sequence.length())
543 last_successful_state_change = false;
547 if ((adding) || (!output_sequence.length()))
550 if (!output_sequence.length())
551 last_successful_state_change = true;
557 * Watch carefully for the sleight of hand trick.
558 * 65 is the ascii value of 'A'. We take this from
559 * the char we're looking at to get a number between
560 * 1 and 127. We then logic-or it to get the hashed
561 * position, dependent on wether its a channel or
562 * a user mode. This is a little stranger, but a lot
563 * faster, than using a map of pairs.
565 handler_id = (modechar - 65) | mask;
567 if (modehandlers[handler_id])
571 if (modehandlers[handler_id]->GetModeType() == type)
575 if (modehandlers[handler_id]->GetNumParams(adding))
577 /* This mode expects a parameter, do we have any parameters left in our list to use? */
578 if (parameter_counter < parameters.size())
580 parameter = parameters[parameter_counter++];
583 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
588 /* No parameter, continue to the next mode */
589 modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
593 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
597 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
600 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
603 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
605 /* Check access to this mode character */
606 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
608 char needed = modehandlers[handler_id]->GetNeededPrefix();
609 ModeHandler* prefixmode = FindPrefix(needed);
611 /* If the mode defined by the handler is not '\0', but the handler for it
612 * cannot be found, they probably dont have the right module loaded to implement
613 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
614 * Revert to checking against the minimum core prefix, '%' or '@'.
616 if (needed && !prefixmode)
617 prefixmode = ServerInstance->Config->AllowHalfop ? FindPrefix('%') : FindPrefix('@');
619 unsigned int neededrank = prefixmode->GetPrefixRank();
620 /* Compare our rank on the channel against the rank of the required prefix,
621 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
622 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
623 * first, so we don't need to iterate, we just look up the first instead.
625 std::string modestring = targetchannel->GetAllPrefixChars(user);
626 char ml = (modestring.empty() ? '\0' : modestring[0]);
627 ModeHandler* ourmode = FindPrefix(ml);
628 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
631 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
632 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
638 bool had_parameter = !parameter.empty();
640 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
642 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
647 /* A module whacked the parameter completely, and there was one. abort. */
648 if ((had_parameter) && (parameter.empty()))
658 /* If it's disabled, they have to be an oper.
660 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
662 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
664 type == MODETYPE_CHANNEL ? "channel" : "user",
665 modehandlers[handler_id]->GetModeChar());
669 /* It's an oper only mode, check if theyre an oper. If they arent,
670 * eat any parameter that came with the mode, and continue to next
672 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
676 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
679 type == MODETYPE_CHANNEL ? "channel" : "user",
680 modehandlers[handler_id]->GetModeChar());
684 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
686 type == MODETYPE_CHANNEL ? "channel" : "user",
687 modehandlers[handler_id]->GetModeChar());
692 /* Call the handler for the mode */
693 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
695 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
697 /* The handler nuked the parameter and they are supposed to have one.
698 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
699 * so we bail to the next mode character.
704 if (ma == MODEACTION_ALLOW)
706 /* We're about to output a valid mode letter - was there previously a pending state-change? */
709 if (adding != last_successful_state_change)
710 output_sequence.append(adding ? "+" : "-");
711 last_successful_state_change = adding;
714 /* Add the mode letter */
715 output_sequence.push_back(modechar);
717 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
719 /* Is there a valid parameter for this mode? If so add it to the parameter list */
720 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
722 parameter_list << " " << parameter;
723 LastParseParams.push_back(parameter);
724 LastParseTranslate.push_back(modehandlers[handler_id]->GetTranslateType());
726 /* Does this mode have a prefix? */
727 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
729 User* user_to_prefix = ServerInstance->FindNick(parameter);
731 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
732 modehandlers[handler_id]->GetPrefixRank(), adding);
736 /* Call all the AfterMode events in the mode watchers for this mode */
737 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
738 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
740 /* Reset the state change flag */
741 state_change = false;
743 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
744 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
746 /* We cant have a mode sequence this long */
747 letter = mode_sequence.end() - 1;
755 /* No mode handler? Unknown mode character then. */
756 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
762 /* Was there at least one valid mode in the sequence? */
763 if (!output_sequence.empty())
765 LastParseParams.push_front(output_sequence);
768 if (type == MODETYPE_CHANNEL)
770 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
771 this->LastParse = targetchannel->name;
775 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
776 this->LastParse = targetuser->nick;
781 if (type == MODETYPE_CHANNEL)
783 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
784 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
785 this->LastParse = targetchannel->name;
789 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
790 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
791 this->LastParse = targetuser->nick;
795 LastParse.append(" ");
796 LastParse.append(output_sequence);
797 LastParse.append(parameter_list.str());
802 const std::string& ModeParser::GetLastParse()
807 void ModeParser::CleanMask(std::string &mask)
809 std::string::size_type pos_of_pling = mask.find_first_of('!');
810 std::string::size_type pos_of_at = mask.find_first_of('@');
811 std::string::size_type pos_of_dot = mask.find_first_of('.');
812 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
814 if (mask.length() >= 2 && mask[1] == ':')
815 return; // if it's an extban, don't even try guess how it needs to be formed.
817 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
819 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
820 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
822 /* It has no '.' in it, it must be a nick. */
827 /* Got a dot in it? Has to be a host */
828 mask = "*!*@" + mask;
831 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
833 /* Has an @ but no !, its a user@host */
836 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
838 /* Has a ! but no @, it must be a nick!ident */
843 bool ModeParser::AddMode(ModeHandler* mh)
845 unsigned char mask = 0;
846 unsigned char pos = 0;
848 /* Yes, i know, this might let people declare modes like '_' or '^'.
849 * If they do that, thats their problem, and if i ever EVER see an
850 * official InspIRCd developer do that, i'll beat them with a paddle!
852 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
855 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
856 * A mode prefix of ':' will fuck up both server to server, and client to server.
857 * A mode prefix of '#' will mess up /whois and /privmsg
859 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
862 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
863 pos = (mh->GetModeChar()-65) | mask;
865 if (modehandlers[pos])
868 modehandlers[pos] = mh;
872 bool ModeParser::DelMode(ModeHandler* mh)
874 unsigned char mask = 0;
875 unsigned char pos = 0;
877 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
880 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
881 pos = (mh->GetModeChar()-65) | mask;
883 if (!modehandlers[pos])
886 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
887 * To stack here we have to make the algorithm slower. Discuss.
889 switch (mh->GetModeType())
892 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
894 mh->RemoveMode(i->second);
897 case MODETYPE_CHANNEL:
898 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
900 mh->RemoveMode(i->second);
905 modehandlers[pos] = NULL;
910 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
912 unsigned char mask = 0;
913 unsigned char pos = 0;
915 if ((modeletter < 'A') || (modeletter > 'z'))
918 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
919 pos = (modeletter-65) | mask;
921 return modehandlers[pos];
924 std::string ModeParser::UserModeList()
929 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
931 unsigned char pos = (mode-65) | MASK_USER;
933 if (modehandlers[pos])
934 modestr[pointer++] = mode;
936 modestr[pointer++] = 0;
940 std::string ModeParser::ChannelModeList()
945 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
947 unsigned char pos = (mode-65) | MASK_CHANNEL;
949 if (modehandlers[pos])
950 modestr[pointer++] = mode;
952 modestr[pointer++] = 0;
956 std::string ModeParser::ParaModeList()
961 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
963 unsigned char pos = (mode-65) | MASK_CHANNEL;
965 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
966 modestr[pointer++] = mode;
968 modestr[pointer++] = 0;
972 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
974 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
976 unsigned char pos = (mode-65) | MASK_CHANNEL;
978 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
980 return modehandlers[pos];
986 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
991 if (!channel || !user)
994 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
996 unsigned char pos = (mode-65) | MASK_CHANNEL;
997 ModeHandler* mh = modehandlers[pos];
998 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
1001 ret = mh->ModeSet(NULL, user, channel, user->nick);
1002 if ((ret.first) && (ret.second == user->nick))
1007 pars.append(user->nick);
1009 types.push_back(mh->GetModeChar());
1020 std::string ModeParser::GiveModeList(ModeMasks m)
1022 std::string type1; /* Listmodes EXCEPT those with a prefix */
1023 std::string type2; /* Modes that take a param when adding or removing */
1024 std::string type3; /* Modes that only take a param when adding */
1025 std::string type4; /* Modes that dont take a param */
1027 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1029 unsigned char pos = (mode-65) | m;
1030 /* One parameter when adding */
1031 if (modehandlers[pos])
1033 if (modehandlers[pos]->GetNumParams(true))
1035 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1037 type1 += modehandlers[pos]->GetModeChar();
1041 /* ... and one parameter when removing */
1042 if (modehandlers[pos]->GetNumParams(false))
1044 /* But not a list mode */
1045 if (!modehandlers[pos]->GetPrefix())
1047 type2 += modehandlers[pos]->GetModeChar();
1052 /* No parameters when removing */
1053 type3 += modehandlers[pos]->GetModeChar();
1059 type4 += modehandlers[pos]->GetModeChar();
1064 return type1 + "," + type2 + "," + type3 + "," + type4;
1067 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1069 return one.second > two.second;
1072 std::string ModeParser::BuildPrefixes()
1074 std::string mletters;
1075 std::string mprefixes;
1077 std::map<char,char> prefix_to_mode;
1079 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1081 unsigned char pos = (mode-65) | MASK_CHANNEL;
1083 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1085 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1086 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1090 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1092 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1094 mletters = mletters + n->first;
1095 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1098 return "(" + mprefixes + ")" + mletters;
1101 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1103 unsigned char mask = 0;
1104 unsigned char pos = 0;
1109 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1112 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1113 pos = (mw->GetModeChar()-65) | mask;
1115 modewatchers[pos].push_back(mw);
1120 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1122 unsigned char mask = 0;
1123 unsigned char pos = 0;
1128 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1131 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1132 pos = (mw->GetModeChar()-65) | mask;
1134 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1136 if (a == modewatchers[pos].end())
1141 modewatchers[pos].erase(a);
1146 /** This default implementation can remove simple user modes
1148 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1150 char moderemove[MAXBUF];
1151 std::vector<std::string> parameters;
1153 if (user->IsModeSet(this->GetModeChar()))
1157 stack->Push(this->GetModeChar());
1161 sprintf(moderemove,"-%c",this->GetModeChar());
1162 parameters.push_back(user->nick);
1163 parameters.push_back(moderemove);
1164 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, true);
1169 /** This default implementation can remove simple channel modes
1172 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1174 char moderemove[MAXBUF];
1175 std::vector<std::string> parameters;
1177 if (channel->IsModeSet(this->GetModeChar()))
1181 stack->Push(this->GetModeChar());
1185 sprintf(moderemove,"-%c",this->GetModeChar());
1186 parameters.push_back(channel->name);
1187 parameters.push_back(moderemove);
1188 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1193 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1195 ModeHandler* modes[] =
1197 new ModeChannelSecret(Instance),
1198 new ModeChannelPrivate(Instance),
1199 new ModeChannelModerated(Instance),
1200 new ModeChannelTopicOps(Instance),
1201 new ModeChannelNoExternal(Instance),
1202 new ModeChannelInviteOnly(Instance),
1203 new ModeChannelKey(Instance),
1204 new ModeChannelLimit(Instance),
1205 new ModeChannelBan(Instance),
1206 new ModeChannelOp(Instance),
1207 new ModeChannelHalfOp(Instance),
1208 new ModeChannelVoice(Instance),
1209 new ModeUserWallops(Instance),
1210 new ModeUserInvisible(Instance),
1211 new ModeUserOperator(Instance),
1212 new ModeUserServerNoticeMask(Instance),
1216 /* Clear mode handler list */
1217 memset(modehandlers, 0, sizeof(modehandlers));
1219 /* Last parse string */
1222 /* Initialise the RFC mode letters */
1223 for (int index = 0; modes[index]; index++)
1224 this->AddMode(modes[index]);
1227 memset(&sent, 0, sizeof(sent));