1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
15 /* $ExtraDeps: $(RELCPPFILES) */
16 /* $ExtraObjects: modes/modeclasses.a */
17 /* $ExtraBuild: @${MAKE} -C "modes" DIRNAME="src/modes" CC="$(CC)" $(MAKEARGS) CPPFILES="$(CPPFILES)" */
20 #include "inspstring.h"
23 #include "modes/cmode_s.h"
25 #include "modes/cmode_p.h"
27 #include "modes/cmode_b.h"
29 #include "modes/cmode_m.h"
30 /* +t (only (half) ops can change topic) */
31 #include "modes/cmode_t.h"
32 /* +n (no external messages) */
33 #include "modes/cmode_n.h"
34 /* +i (invite only) */
35 #include "modes/cmode_i.h"
36 /* +k (keyed channel) */
37 #include "modes/cmode_k.h"
38 /* +l (channel user limit) */
39 #include "modes/cmode_l.h"
41 #include "modes/cmode_o.h"
42 /* +h (channel halfop) */
43 #include "modes/cmode_h.h"
44 /* +v (channel voice) */
45 #include "modes/cmode_v.h"
46 /* +w (see wallops) */
47 #include "modes/umode_w.h"
49 #include "modes/umode_i.h"
51 #include "modes/umode_o.h"
52 /* +s (server notice masks) */
53 #include "modes/umode_s.h"
55 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired, TranslateType translate)
56 : 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)
60 ModeHandler::~ModeHandler()
64 bool ModeHandler::IsListMode()
69 char ModeHandler::GetNeededPrefix()
74 void ModeHandler::SetNeededPrefix(char needsprefix)
76 prefixneeded = needsprefix;
79 unsigned int ModeHandler::GetPrefixRank()
84 unsigned int ModeHandler::GetCount()
89 void ModeHandler::ChangeCount(int modifier)
92 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
95 ModeType ModeHandler::GetModeType()
100 TranslateType ModeHandler::GetTranslateType()
105 bool ModeHandler::NeedsOper()
110 char ModeHandler::GetPrefix()
115 int ModeHandler::GetNumParams(bool adding)
117 return adding ? n_params_on : n_params_off;
120 char ModeHandler::GetModeChar()
125 std::string ModeHandler::GetUserParameter(User* user)
130 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
132 return MODEACTION_DENY;
135 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
139 return std::make_pair(dest->IsModeSet(this->mode), "");
143 return std::make_pair(channel->IsModeSet(this->mode), "");
147 void ModeHandler::DisplayList(User*, Channel*)
151 void ModeHandler::DisplayEmptyList(User*, Channel*)
155 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
159 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
161 return (ours < theirs);
164 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
168 SimpleUserModeHandler::~SimpleUserModeHandler()
172 SimpleChannelModeHandler::~SimpleChannelModeHandler()
176 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
180 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
184 if (!dest->IsModeSet(this->GetModeChar()))
186 dest->SetMode(this->GetModeChar(),true);
187 return MODEACTION_ALLOW;
192 if (dest->IsModeSet(this->GetModeChar()))
194 dest->SetMode(this->GetModeChar(),false);
195 return MODEACTION_ALLOW;
199 return MODEACTION_DENY;
203 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
207 if (!channel->IsModeSet(this->GetModeChar()))
209 channel->SetMode(this->GetModeChar(),true);
210 return MODEACTION_ALLOW;
215 if (channel->IsModeSet(this->GetModeChar()))
217 channel->SetMode(this->GetModeChar(),false);
218 return MODEACTION_ALLOW;
222 return MODEACTION_DENY;
225 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
229 ModeWatcher::~ModeWatcher()
233 char ModeWatcher::GetModeChar()
238 ModeType ModeWatcher::GetModeType()
243 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
248 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
252 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
255 if ((!user) || (!dest) || (!chan) || (!*dest))
259 d = ServerInstance->FindNick(dest);
262 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
268 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
273 UCListIter n = d->chans.find(chan);
274 if (n != d->chans.end())
276 if (n->second & MASK)
280 n->second = n->second | MASK;
284 n->first->AddOppedUser(d);
287 n->first->AddHalfoppedUser(d);
290 n->first->AddVoicedUser(d);
293 return d->nick.c_str();
298 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
303 UCListIter n = d->chans.find(chan);
304 if (n != d->chans.end())
306 if ((n->second & MASK) == 0)
314 n->first->DelOppedUser(d);
317 n->first->DelHalfoppedUser(d);
320 n->first->DelVoicedUser(d);
323 return d->nick.c_str();
328 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
332 /* Display channel's current mode string */
333 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
334 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
339 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
341 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
345 if (targetuser == user || user->HasPrivPermission("users/auspex"))
347 /* Display user's current mode string */
348 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
349 if (IS_OPER(targetuser))
350 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
355 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
360 /* No such nick/channel */
361 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
365 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
367 std::string target = parameters[0];
368 ModeType type = MODETYPE_USER;
369 unsigned char mask = 0;
370 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
371 User* targetuser = ServerInstance->FindNick(parameters[0]);
375 /* Special case for displaying the list for listmodes,
376 * e.g. MODE #chan b, or MODE #chan +b without a parameter
378 if ((targetchannel) && (parameters.size() == 2))
380 const char* mode = parameters[1].c_str();
381 int nonlistmodes_found = 0;
387 while (mode && *mode)
389 unsigned char mletter = *mode;
397 /* Ensure the user doesnt request the same mode twice,
398 * so they cant flood themselves off out of idiocy.
400 if (sent[mletter] != seq)
410 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
413 if ((mh) && (mh->IsListMode()))
416 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
417 if (MOD_RESULT == ACR_DENY)
423 if (!user->HasPrivPermission("channels/auspex"))
425 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
427 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++);
428 mh->DisplayEmptyList(user, targetchannel);
433 /** See below for a description of what craq this is :D
435 unsigned char handler_id = (*mode - 65) | mask;
437 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
439 std::string dummyparam;
441 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
446 mh->DisplayList(user, targetchannel);
449 nonlistmodes_found++;
454 /* We didnt have any modes that were non-list, we can return here */
455 if (!nonlistmodes_found)
459 if (parameters.size() == 1)
461 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
463 else if (parameters.size() > 1)
465 bool SkipAccessChecks = false;
469 type = MODETYPE_CHANNEL;
472 /* Extra security checks on channel modes
473 * (e.g. are they a (half)op?
476 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
478 /* We don't have halfop */
480 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
481 if (MOD_RESULT == ACR_DENY)
483 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
488 type = MODETYPE_USER;
490 if (user != targetuser && IS_LOCAL(user) && !ServerInstance->ULine(user->server))
492 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
498 /* No such nick/channel */
499 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
503 std::string mode_sequence = parameters[1];
504 std::string parameter;
505 std::ostringstream parameter_list;
506 std::vector<TranslateType> parameter_xlate;
507 parameter_xlate.push_back(TR_TEXT);
508 std::string output_sequence;
509 bool adding = true, state_change = false;
510 unsigned char handler_id = 0;
511 unsigned int parameter_counter = 2; /* Index of first parameter */
512 unsigned int parameter_count = 0;
513 bool last_successful_state_change = false;
515 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
516 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
517 mode_sequence.insert(0, "+");
519 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
521 unsigned char modechar = *letter;
526 * For + and - mode characters, we don't just stick the character into the output sequence.
527 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
528 * appearing in the output sequence, we store a flag which says there was a state change,
529 * which is set on any + or -, however, the + or - that we finish on is only appended to
530 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
533 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
534 * however, will allow the + if it is the first item in the sequence, regardless.
536 if ((!adding) || (!output_sequence.length()))
539 if (!output_sequence.length())
540 last_successful_state_change = false;
544 if ((adding) || (!output_sequence.length()))
547 if (!output_sequence.length())
548 last_successful_state_change = true;
554 * Watch carefully for the sleight of hand trick.
555 * 65 is the ascii value of 'A'. We take this from
556 * the char we're looking at to get a number between
557 * 1 and 127. We then logic-or it to get the hashed
558 * position, dependent on wether its a channel or
559 * a user mode. This is a little stranger, but a lot
560 * faster, than using a map of pairs.
562 handler_id = (modechar - 65) | mask;
564 if (modehandlers[handler_id])
568 if (modehandlers[handler_id]->GetModeType() == type)
572 if (modehandlers[handler_id]->GetNumParams(adding))
574 /* This mode expects a parameter, do we have any parameters left in our list to use? */
575 if (parameter_counter < parameters.size())
577 parameter = parameters[parameter_counter++];
580 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
585 /* No parameter, continue to the next mode */
586 modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
590 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
594 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
597 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
600 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
602 /* Check access to this mode character */
603 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
605 char needed = modehandlers[handler_id]->GetNeededPrefix();
606 ModeHandler* prefixmode = FindPrefix(needed);
608 /* If the mode defined by the handler is not '\0', but the handler for it
609 * cannot be found, they probably dont have the right module loaded to implement
610 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
611 * Revert to checking against the minimum core prefix, '%'.
613 if (needed && !prefixmode)
614 prefixmode = FindPrefix('%');
616 unsigned int neededrank = prefixmode->GetPrefixRank();
617 /* Compare our rank on the channel against the rank of the required prefix,
618 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
619 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
620 * first, so we don't need to iterate, we just look up the first instead.
622 std::string modestring = targetchannel->GetAllPrefixChars(user);
623 char ml = (modestring.empty() ? '\0' : modestring[0]);
624 ModeHandler* ourmode = FindPrefix(ml);
625 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
628 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
629 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
635 bool had_parameter = !parameter.empty();
637 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
639 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
644 /* A module whacked the parameter completely, and there was one. abort. */
645 if ((had_parameter) && (parameter.empty()))
655 /* If it's disabled, they have to be an oper.
657 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
659 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
661 type == MODETYPE_CHANNEL ? "channel" : "user",
662 modehandlers[handler_id]->GetModeChar());
666 /* It's an oper only mode, check if theyre an oper. If they arent,
667 * eat any parameter that came with the mode, and continue to next
669 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
673 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
676 type == MODETYPE_CHANNEL ? "channel" : "user",
677 modehandlers[handler_id]->GetModeChar());
681 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
683 type == MODETYPE_CHANNEL ? "channel" : "user",
684 modehandlers[handler_id]->GetModeChar());
689 /* Call the handler for the mode */
690 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
692 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
694 /* The handler nuked the parameter and they are supposed to have one.
695 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
696 * so we bail to the next mode character.
701 if (ma == MODEACTION_ALLOW)
703 /* We're about to output a valid mode letter - was there previously a pending state-change? */
706 if (adding != last_successful_state_change)
707 output_sequence.append(adding ? "+" : "-");
708 last_successful_state_change = adding;
711 /* Add the mode letter */
712 output_sequence.push_back(modechar);
714 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
716 /* Is there a valid parameter for this mode? If so add it to the parameter list */
717 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
719 parameter_list << " " << parameter;
720 parameter_xlate.push_back(modehandlers[handler_id]->GetTranslateType());
722 /* Does this mode have a prefix? */
723 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
725 User* user_to_prefix = ServerInstance->FindNick(parameter);
727 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
728 modehandlers[handler_id]->GetPrefixRank(), adding);
732 /* Call all the AfterMode events in the mode watchers for this mode */
733 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
734 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
736 /* Reset the state change flag */
737 state_change = false;
739 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
740 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
742 /* We cant have a mode sequence this long */
743 letter = mode_sequence.end() - 1;
751 /* No mode handler? Unknown mode character then. */
752 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
758 /* Was there at least one valid mode in the sequence? */
759 if (!output_sequence.empty())
763 if (type == MODETYPE_CHANNEL)
765 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
766 this->LastParse = targetchannel->name;
770 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
771 this->LastParse = targetuser->nick;
776 if (type == MODETYPE_CHANNEL)
778 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
779 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str(), parameter_xlate));
780 this->LastParse = targetchannel->name;
784 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
785 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str(), parameter_xlate));
786 this->LastParse = targetuser->nick;
790 LastParse.append(" ");
791 LastParse.append(output_sequence);
792 LastParse.append(parameter_list.str());
797 const std::string& ModeParser::GetLastParse()
802 void ModeParser::CleanMask(std::string &mask)
804 std::string::size_type pos_of_pling = mask.find_first_of('!');
805 std::string::size_type pos_of_at = mask.find_first_of('@');
806 std::string::size_type pos_of_dot = mask.find_first_of('.');
807 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
809 if (mask.length() >= 2 && mask[1] == ':')
810 return; // if it's an extban, don't even try guess how it needs to be formed.
812 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
814 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
815 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
817 /* It has no '.' in it, it must be a nick. */
822 /* Got a dot in it? Has to be a host */
823 mask = "*!*@" + mask;
826 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
828 /* Has an @ but no !, its a user@host */
831 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
833 /* Has a ! but no @, it must be a nick!ident */
838 bool ModeParser::AddMode(ModeHandler* mh)
840 unsigned char mask = 0;
841 unsigned char pos = 0;
843 /* Yes, i know, this might let people declare modes like '_' or '^'.
844 * If they do that, thats their problem, and if i ever EVER see an
845 * official InspIRCd developer do that, i'll beat them with a paddle!
847 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
850 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
851 * A mode prefix of ':' will fuck up both server to server, and client to server.
852 * A mode prefix of '#' will mess up /whois and /privmsg
854 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
857 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
858 pos = (mh->GetModeChar()-65) | mask;
860 if (modehandlers[pos])
863 modehandlers[pos] = mh;
867 bool ModeParser::DelMode(ModeHandler* mh)
869 unsigned char mask = 0;
870 unsigned char pos = 0;
872 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
875 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
876 pos = (mh->GetModeChar()-65) | mask;
878 if (!modehandlers[pos])
881 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
882 * To stack here we have to make the algorithm slower. Discuss.
884 switch (mh->GetModeType())
887 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
889 mh->RemoveMode(i->second);
892 case MODETYPE_CHANNEL:
893 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
895 mh->RemoveMode(i->second);
900 modehandlers[pos] = NULL;
905 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
907 unsigned char mask = 0;
908 unsigned char pos = 0;
910 if ((modeletter < 'A') || (modeletter > 'z'))
913 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
914 pos = (modeletter-65) | mask;
916 return modehandlers[pos];
919 std::string ModeParser::UserModeList()
924 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
926 unsigned char pos = (mode-65) | MASK_USER;
928 if (modehandlers[pos])
929 modestr[pointer++] = mode;
931 modestr[pointer++] = 0;
935 std::string ModeParser::ChannelModeList()
940 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
942 unsigned char pos = (mode-65) | MASK_CHANNEL;
944 if (modehandlers[pos])
945 modestr[pointer++] = mode;
947 modestr[pointer++] = 0;
951 std::string ModeParser::ParaModeList()
956 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
958 unsigned char pos = (mode-65) | MASK_CHANNEL;
960 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
961 modestr[pointer++] = mode;
963 modestr[pointer++] = 0;
967 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
969 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
971 unsigned char pos = (mode-65) | MASK_CHANNEL;
973 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
975 return modehandlers[pos];
981 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
986 if (!channel || !user)
989 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
991 unsigned char pos = (mode-65) | MASK_CHANNEL;
992 ModeHandler* mh = modehandlers[pos];
993 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
996 ret = mh->ModeSet(NULL, user, channel, user->nick);
997 if ((ret.first) && (ret.second == user->nick))
1002 pars.append(user->nick);
1004 types.push_back(mh->GetModeChar());
1015 std::string ModeParser::GiveModeList(ModeMasks m)
1017 std::string type1; /* Listmodes EXCEPT those with a prefix */
1018 std::string type2; /* Modes that take a param when adding or removing */
1019 std::string type3; /* Modes that only take a param when adding */
1020 std::string type4; /* Modes that dont take a param */
1022 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1024 unsigned char pos = (mode-65) | m;
1025 /* One parameter when adding */
1026 if (modehandlers[pos])
1028 if (modehandlers[pos]->GetNumParams(true))
1030 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1032 type1 += modehandlers[pos]->GetModeChar();
1036 /* ... and one parameter when removing */
1037 if (modehandlers[pos]->GetNumParams(false))
1039 /* But not a list mode */
1040 if (!modehandlers[pos]->GetPrefix())
1042 type2 += modehandlers[pos]->GetModeChar();
1047 /* No parameters when removing */
1048 type3 += modehandlers[pos]->GetModeChar();
1054 type4 += modehandlers[pos]->GetModeChar();
1059 return type1 + "," + type2 + "," + type3 + "," + type4;
1062 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1064 return one.second > two.second;
1067 std::string ModeParser::BuildPrefixes()
1069 std::string mletters;
1070 std::string mprefixes;
1072 std::map<char,char> prefix_to_mode;
1074 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1076 unsigned char pos = (mode-65) | MASK_CHANNEL;
1078 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1080 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1081 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1085 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1087 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1089 mletters = mletters + n->first;
1090 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1093 return "(" + mprefixes + ")" + mletters;
1096 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1098 unsigned char mask = 0;
1099 unsigned char pos = 0;
1104 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1107 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1108 pos = (mw->GetModeChar()-65) | mask;
1110 modewatchers[pos].push_back(mw);
1115 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1117 unsigned char mask = 0;
1118 unsigned char pos = 0;
1123 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1126 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1127 pos = (mw->GetModeChar()-65) | mask;
1129 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1131 if (a == modewatchers[pos].end())
1136 modewatchers[pos].erase(a);
1141 /** This default implementation can remove simple user modes
1143 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1145 char moderemove[MAXBUF];
1146 std::vector<std::string> parameters;
1148 if (user->IsModeSet(this->GetModeChar()))
1152 stack->Push(this->GetModeChar());
1156 sprintf(moderemove,"-%c",this->GetModeChar());
1157 parameters.push_back(user->nick);
1158 parameters.push_back(moderemove);
1159 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, false);
1164 /** This default implementation can remove simple channel modes
1167 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1169 char moderemove[MAXBUF];
1170 std::vector<std::string> parameters;
1172 if (channel->IsModeSet(this->GetModeChar()))
1176 stack->Push(this->GetModeChar());
1180 sprintf(moderemove,"-%c",this->GetModeChar());
1181 parameters.push_back(channel->name);
1182 parameters.push_back(moderemove);
1183 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1188 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1190 ModeHandler* modes[] =
1192 new ModeChannelSecret(Instance),
1193 new ModeChannelPrivate(Instance),
1194 new ModeChannelModerated(Instance),
1195 new ModeChannelTopicOps(Instance),
1196 new ModeChannelNoExternal(Instance),
1197 new ModeChannelInviteOnly(Instance),
1198 new ModeChannelKey(Instance),
1199 new ModeChannelLimit(Instance),
1200 new ModeChannelBan(Instance),
1201 new ModeChannelOp(Instance),
1202 new ModeChannelHalfOp(Instance),
1203 new ModeChannelVoice(Instance),
1204 new ModeUserWallops(Instance),
1205 new ModeUserInvisible(Instance),
1206 new ModeUserOperator(Instance),
1207 new ModeUserServerNoticeMask(Instance),
1211 /* Clear mode handler list */
1212 memset(modehandlers, 0, sizeof(modehandlers));
1214 /* Last parse string */
1217 /* Initialise the RFC mode letters */
1218 for (int index = 0; modes[index]; index++)
1219 this->AddMode(modes[index]);
1222 memset(&sent, 0, sizeof(sent));