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]);
374 LastParseParams.clear();
375 LastParseTranslate.clear();
377 /* Special case for displaying the list for listmodes,
378 * e.g. MODE #chan b, or MODE #chan +b without a parameter
380 if ((targetchannel) && (parameters.size() == 2))
382 const char* mode = parameters[1].c_str();
383 int nonlistmodes_found = 0;
389 while (mode && *mode)
391 unsigned char mletter = *mode;
399 /* Ensure the user doesnt request the same mode twice,
400 * so they cant flood themselves off out of idiocy.
402 if (sent[mletter] != seq)
412 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
415 if ((mh) && (mh->IsListMode()))
418 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
419 if (MOD_RESULT == ACR_DENY)
425 if (!user->HasPrivPermission("channels/auspex"))
427 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
429 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++);
430 mh->DisplayEmptyList(user, targetchannel);
435 /** See below for a description of what craq this is :D
437 unsigned char handler_id = (*mode - 65) | mask;
439 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
441 std::string dummyparam;
443 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
448 mh->DisplayList(user, targetchannel);
451 nonlistmodes_found++;
456 /* We didnt have any modes that were non-list, we can return here */
457 if (!nonlistmodes_found)
461 if (parameters.size() == 1)
463 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
465 else if (parameters.size() > 1)
467 bool SkipAccessChecks = false;
471 type = MODETYPE_CHANNEL;
474 /* Extra security checks on channel modes
475 * (e.g. are they a (half)op?
478 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
480 /* We don't have halfop */
482 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
483 if (MOD_RESULT == ACR_DENY)
485 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
490 type = MODETYPE_USER;
492 if (user != targetuser && IS_LOCAL(user) && !ServerInstance->ULine(user->server))
494 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
500 /* No such nick/channel */
501 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
505 std::string mode_sequence = parameters[1];
506 std::string parameter;
507 std::ostringstream parameter_list;
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;
514 LastParseTranslate.push_back(TR_TEXT);
516 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
517 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
518 mode_sequence.insert(0, "+");
520 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
522 unsigned char modechar = *letter;
527 * For + and - mode characters, we don't just stick the character into the output sequence.
528 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
529 * appearing in the output sequence, we store a flag which says there was a state change,
530 * which is set on any + or -, however, the + or - that we finish on is only appended to
531 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
534 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
535 * however, will allow the + if it is the first item in the sequence, regardless.
537 if ((!adding) || (!output_sequence.length()))
540 if (!output_sequence.length())
541 last_successful_state_change = false;
545 if ((adding) || (!output_sequence.length()))
548 if (!output_sequence.length())
549 last_successful_state_change = true;
555 * Watch carefully for the sleight of hand trick.
556 * 65 is the ascii value of 'A'. We take this from
557 * the char we're looking at to get a number between
558 * 1 and 127. We then logic-or it to get the hashed
559 * position, dependent on wether its a channel or
560 * a user mode. This is a little stranger, but a lot
561 * faster, than using a map of pairs.
563 handler_id = (modechar - 65) | mask;
565 if (modehandlers[handler_id])
569 if (modehandlers[handler_id]->GetModeType() == type)
573 if (modehandlers[handler_id]->GetNumParams(adding))
575 /* This mode expects a parameter, do we have any parameters left in our list to use? */
576 if (parameter_counter < parameters.size())
578 parameter = parameters[parameter_counter++];
581 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
586 /* No parameter, continue to the next mode */
587 modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
591 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
595 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
598 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
601 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
603 /* Check access to this mode character */
604 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
606 char needed = modehandlers[handler_id]->GetNeededPrefix();
607 ModeHandler* prefixmode = FindPrefix(needed);
609 /* If the mode defined by the handler is not '\0', but the handler for it
610 * cannot be found, they probably dont have the right module loaded to implement
611 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
612 * Revert to checking against the minimum core prefix, '%'.
614 if (needed && !prefixmode)
615 prefixmode = FindPrefix('%');
617 unsigned int neededrank = prefixmode->GetPrefixRank();
618 /* Compare our rank on the channel against the rank of the required prefix,
619 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
620 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
621 * first, so we don't need to iterate, we just look up the first instead.
623 std::string modestring = targetchannel->GetAllPrefixChars(user);
624 char ml = (modestring.empty() ? '\0' : modestring[0]);
625 ModeHandler* ourmode = FindPrefix(ml);
626 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
629 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
630 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
636 bool had_parameter = !parameter.empty();
638 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
640 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
645 /* A module whacked the parameter completely, and there was one. abort. */
646 if ((had_parameter) && (parameter.empty()))
656 /* If it's disabled, they have to be an oper.
658 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
660 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
662 type == MODETYPE_CHANNEL ? "channel" : "user",
663 modehandlers[handler_id]->GetModeChar());
667 /* It's an oper only mode, check if theyre an oper. If they arent,
668 * eat any parameter that came with the mode, and continue to next
670 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
674 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
677 type == MODETYPE_CHANNEL ? "channel" : "user",
678 modehandlers[handler_id]->GetModeChar());
682 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
684 type == MODETYPE_CHANNEL ? "channel" : "user",
685 modehandlers[handler_id]->GetModeChar());
690 /* Call the handler for the mode */
691 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
693 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
695 /* The handler nuked the parameter and they are supposed to have one.
696 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
697 * so we bail to the next mode character.
702 if (ma == MODEACTION_ALLOW)
704 /* We're about to output a valid mode letter - was there previously a pending state-change? */
707 if (adding != last_successful_state_change)
708 output_sequence.append(adding ? "+" : "-");
709 last_successful_state_change = adding;
712 /* Add the mode letter */
713 output_sequence.push_back(modechar);
715 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
717 /* Is there a valid parameter for this mode? If so add it to the parameter list */
718 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
720 parameter_list << " " << parameter;
721 LastParseParams.push_back(parameter);
722 LastParseTranslate.push_back(modehandlers[handler_id]->GetTranslateType());
724 /* Does this mode have a prefix? */
725 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
727 User* user_to_prefix = ServerInstance->FindNick(parameter);
729 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
730 modehandlers[handler_id]->GetPrefixRank(), adding);
734 /* Call all the AfterMode events in the mode watchers for this mode */
735 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
736 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
738 /* Reset the state change flag */
739 state_change = false;
741 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
742 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
744 /* We cant have a mode sequence this long */
745 letter = mode_sequence.end() - 1;
753 /* No mode handler? Unknown mode character then. */
754 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
760 /* Was there at least one valid mode in the sequence? */
761 if (!output_sequence.empty())
765 if (type == MODETYPE_CHANNEL)
767 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
768 this->LastParse = targetchannel->name;
772 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
773 this->LastParse = targetuser->nick;
778 LastParseParams.push_front(output_sequence);
779 if (type == MODETYPE_CHANNEL)
781 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
782 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
783 this->LastParse = targetchannel->name;
787 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
788 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
789 this->LastParse = targetuser->nick;
793 LastParse.append(" ");
794 LastParse.append(output_sequence);
795 LastParse.append(parameter_list.str());
800 const std::string& ModeParser::GetLastParse()
805 void ModeParser::CleanMask(std::string &mask)
807 std::string::size_type pos_of_pling = mask.find_first_of('!');
808 std::string::size_type pos_of_at = mask.find_first_of('@');
809 std::string::size_type pos_of_dot = mask.find_first_of('.');
810 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
812 if (mask.length() >= 2 && mask[1] == ':')
813 return; // if it's an extban, don't even try guess how it needs to be formed.
815 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
817 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
818 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
820 /* It has no '.' in it, it must be a nick. */
825 /* Got a dot in it? Has to be a host */
826 mask = "*!*@" + mask;
829 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
831 /* Has an @ but no !, its a user@host */
834 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
836 /* Has a ! but no @, it must be a nick!ident */
841 bool ModeParser::AddMode(ModeHandler* mh)
843 unsigned char mask = 0;
844 unsigned char pos = 0;
846 /* Yes, i know, this might let people declare modes like '_' or '^'.
847 * If they do that, thats their problem, and if i ever EVER see an
848 * official InspIRCd developer do that, i'll beat them with a paddle!
850 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
853 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
854 * A mode prefix of ':' will fuck up both server to server, and client to server.
855 * A mode prefix of '#' will mess up /whois and /privmsg
857 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
860 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
861 pos = (mh->GetModeChar()-65) | mask;
863 if (modehandlers[pos])
866 modehandlers[pos] = mh;
870 bool ModeParser::DelMode(ModeHandler* mh)
872 unsigned char mask = 0;
873 unsigned char pos = 0;
875 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
878 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
879 pos = (mh->GetModeChar()-65) | mask;
881 if (!modehandlers[pos])
884 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
885 * To stack here we have to make the algorithm slower. Discuss.
887 switch (mh->GetModeType())
890 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
892 mh->RemoveMode(i->second);
895 case MODETYPE_CHANNEL:
896 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
898 mh->RemoveMode(i->second);
903 modehandlers[pos] = NULL;
908 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
910 unsigned char mask = 0;
911 unsigned char pos = 0;
913 if ((modeletter < 'A') || (modeletter > 'z'))
916 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
917 pos = (modeletter-65) | mask;
919 return modehandlers[pos];
922 std::string ModeParser::UserModeList()
927 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
929 unsigned char pos = (mode-65) | MASK_USER;
931 if (modehandlers[pos])
932 modestr[pointer++] = mode;
934 modestr[pointer++] = 0;
938 std::string ModeParser::ChannelModeList()
943 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
945 unsigned char pos = (mode-65) | MASK_CHANNEL;
947 if (modehandlers[pos])
948 modestr[pointer++] = mode;
950 modestr[pointer++] = 0;
954 std::string ModeParser::ParaModeList()
959 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
961 unsigned char pos = (mode-65) | MASK_CHANNEL;
963 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
964 modestr[pointer++] = mode;
966 modestr[pointer++] = 0;
970 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
972 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
974 unsigned char pos = (mode-65) | MASK_CHANNEL;
976 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
978 return modehandlers[pos];
984 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
989 if (!channel || !user)
992 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
994 unsigned char pos = (mode-65) | MASK_CHANNEL;
995 ModeHandler* mh = modehandlers[pos];
996 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
999 ret = mh->ModeSet(NULL, user, channel, user->nick);
1000 if ((ret.first) && (ret.second == user->nick))
1005 pars.append(user->nick);
1007 types.push_back(mh->GetModeChar());
1018 std::string ModeParser::GiveModeList(ModeMasks m)
1020 std::string type1; /* Listmodes EXCEPT those with a prefix */
1021 std::string type2; /* Modes that take a param when adding or removing */
1022 std::string type3; /* Modes that only take a param when adding */
1023 std::string type4; /* Modes that dont take a param */
1025 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1027 unsigned char pos = (mode-65) | m;
1028 /* One parameter when adding */
1029 if (modehandlers[pos])
1031 if (modehandlers[pos]->GetNumParams(true))
1033 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1035 type1 += modehandlers[pos]->GetModeChar();
1039 /* ... and one parameter when removing */
1040 if (modehandlers[pos]->GetNumParams(false))
1042 /* But not a list mode */
1043 if (!modehandlers[pos]->GetPrefix())
1045 type2 += modehandlers[pos]->GetModeChar();
1050 /* No parameters when removing */
1051 type3 += modehandlers[pos]->GetModeChar();
1057 type4 += modehandlers[pos]->GetModeChar();
1062 return type1 + "," + type2 + "," + type3 + "," + type4;
1065 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1067 return one.second > two.second;
1070 std::string ModeParser::BuildPrefixes()
1072 std::string mletters;
1073 std::string mprefixes;
1075 std::map<char,char> prefix_to_mode;
1077 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1079 unsigned char pos = (mode-65) | MASK_CHANNEL;
1081 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1083 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1084 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1088 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1090 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1092 mletters = mletters + n->first;
1093 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1096 return "(" + mprefixes + ")" + mletters;
1099 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1101 unsigned char mask = 0;
1102 unsigned char pos = 0;
1107 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1110 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1111 pos = (mw->GetModeChar()-65) | mask;
1113 modewatchers[pos].push_back(mw);
1118 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1120 unsigned char mask = 0;
1121 unsigned char pos = 0;
1126 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1129 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1130 pos = (mw->GetModeChar()-65) | mask;
1132 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1134 if (a == modewatchers[pos].end())
1139 modewatchers[pos].erase(a);
1144 /** This default implementation can remove simple user modes
1146 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1148 char moderemove[MAXBUF];
1149 std::vector<std::string> parameters;
1151 if (user->IsModeSet(this->GetModeChar()))
1155 stack->Push(this->GetModeChar());
1159 sprintf(moderemove,"-%c",this->GetModeChar());
1160 parameters.push_back(user->nick);
1161 parameters.push_back(moderemove);
1162 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, false);
1167 /** This default implementation can remove simple channel modes
1170 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1172 char moderemove[MAXBUF];
1173 std::vector<std::string> parameters;
1175 if (channel->IsModeSet(this->GetModeChar()))
1179 stack->Push(this->GetModeChar());
1183 sprintf(moderemove,"-%c",this->GetModeChar());
1184 parameters.push_back(channel->name);
1185 parameters.push_back(moderemove);
1186 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1191 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1193 ModeHandler* modes[] =
1195 new ModeChannelSecret(Instance),
1196 new ModeChannelPrivate(Instance),
1197 new ModeChannelModerated(Instance),
1198 new ModeChannelTopicOps(Instance),
1199 new ModeChannelNoExternal(Instance),
1200 new ModeChannelInviteOnly(Instance),
1201 new ModeChannelKey(Instance),
1202 new ModeChannelLimit(Instance),
1203 new ModeChannelBan(Instance),
1204 new ModeChannelOp(Instance),
1205 new ModeChannelHalfOp(Instance),
1206 new ModeChannelVoice(Instance),
1207 new ModeUserWallops(Instance),
1208 new ModeUserInvisible(Instance),
1209 new ModeUserOperator(Instance),
1210 new ModeUserServerNoticeMask(Instance),
1214 /* Clear mode handler list */
1215 memset(modehandlers, 0, sizeof(modehandlers));
1217 /* Last parse string */
1220 /* Initialise the RFC mode letters */
1221 for (int index = 0; modes[index]; index++)
1222 this->AddMode(modes[index]);
1225 memset(&sent, 0, sizeof(sent));