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 * ---------------------------------------------------
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()
71 if (prefixneeded == '%' && !ServerInstance->Config->AllowHalfop)
76 void ModeHandler::SetNeededPrefix(char needsprefix)
78 prefixneeded = needsprefix;
81 unsigned int ModeHandler::GetPrefixRank()
86 unsigned int ModeHandler::GetCount()
91 void ModeHandler::ChangeCount(int modifier)
94 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
97 ModeType ModeHandler::GetModeType()
102 TranslateType ModeHandler::GetTranslateType()
107 bool ModeHandler::NeedsOper()
112 char ModeHandler::GetPrefix()
117 int ModeHandler::GetNumParams(bool adding)
119 return adding ? n_params_on : n_params_off;
122 char ModeHandler::GetModeChar()
127 std::string ModeHandler::GetUserParameter(User* user)
132 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
134 return MODEACTION_DENY;
137 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
141 return std::make_pair(dest->IsModeSet(this->mode), "");
145 return std::make_pair(channel->IsModeSet(this->mode), "");
149 void ModeHandler::DisplayList(User*, Channel*)
153 void ModeHandler::DisplayEmptyList(User*, Channel*)
157 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
161 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
163 return (ours < theirs);
166 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
170 SimpleUserModeHandler::~SimpleUserModeHandler()
174 SimpleChannelModeHandler::~SimpleChannelModeHandler()
178 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
182 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
186 if (!dest->IsModeSet(this->GetModeChar()))
188 dest->SetMode(this->GetModeChar(),true);
189 return MODEACTION_ALLOW;
194 if (dest->IsModeSet(this->GetModeChar()))
196 dest->SetMode(this->GetModeChar(),false);
197 return MODEACTION_ALLOW;
201 return MODEACTION_DENY;
205 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
209 if (!channel->IsModeSet(this->GetModeChar()))
211 channel->SetMode(this->GetModeChar(),true);
212 return MODEACTION_ALLOW;
217 if (channel->IsModeSet(this->GetModeChar()))
219 channel->SetMode(this->GetModeChar(),false);
220 return MODEACTION_ALLOW;
224 return MODEACTION_DENY;
227 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
231 ModeWatcher::~ModeWatcher()
235 char ModeWatcher::GetModeChar()
240 ModeType ModeWatcher::GetModeType()
245 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
250 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
254 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
257 if ((!user) || (!dest) || (!chan) || (!*dest))
261 d = ServerInstance->FindNick(dest);
264 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
270 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
275 UCListIter n = d->chans.find(chan);
276 if (n != d->chans.end())
278 if (n->second & MASK)
282 n->second = n->second | MASK;
286 n->first->AddOppedUser(d);
289 n->first->AddHalfoppedUser(d);
292 n->first->AddVoicedUser(d);
295 return d->nick.c_str();
300 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
305 UCListIter n = d->chans.find(chan);
306 if (n != d->chans.end())
308 if ((n->second & MASK) == 0)
316 n->first->DelOppedUser(d);
319 n->first->DelHalfoppedUser(d);
322 n->first->DelVoicedUser(d);
325 return d->nick.c_str();
330 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
334 /* Display channel's current mode string */
335 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
336 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
341 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
343 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
347 if (targetuser == user || user->HasPrivPermission("users/auspex"))
349 /* Display user's current mode string */
350 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
351 if (IS_OPER(targetuser))
352 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
357 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
362 /* No such nick/channel */
363 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
367 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
369 std::string target = parameters[0];
370 ModeType type = MODETYPE_USER;
371 unsigned char mask = 0;
372 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
373 User* targetuser = ServerInstance->FindNick(parameters[0]);
376 LastParseParams.clear();
377 LastParseTranslate.clear();
379 /* Special case for displaying the list for listmodes,
380 * e.g. MODE #chan b, or MODE #chan +b without a parameter
382 if ((targetchannel) && (parameters.size() == 2))
384 const char* mode = parameters[1].c_str();
385 int nonlistmodes_found = 0;
391 while (mode && *mode)
393 unsigned char mletter = *mode;
401 /* Ensure the user doesnt request the same mode twice,
402 * so they cant flood themselves off out of idiocy.
404 if (sent[mletter] != seq)
414 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
417 if ((mh) && (mh->IsListMode()))
420 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
421 if (MOD_RESULT == ACR_DENY)
427 if (!user->HasPrivPermission("channels/auspex"))
429 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
431 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++);
432 mh->DisplayEmptyList(user, targetchannel);
437 /** See below for a description of what craq this is :D
439 unsigned char handler_id = (*mode - 65) | mask;
441 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
443 std::string dummyparam;
445 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
450 mh->DisplayList(user, targetchannel);
453 nonlistmodes_found++;
458 /* We didnt have any modes that were non-list, we can return here */
459 if (!nonlistmodes_found)
463 if (parameters.size() == 1)
465 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
467 else if (parameters.size() > 1)
469 bool SkipAccessChecks = false;
473 type = MODETYPE_CHANNEL;
476 /* Extra security checks on channel modes
477 * (e.g. are they a (half)op?
480 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
482 /* Make modes that are being changed visible to OnAccessCheck */
483 LastParse = parameters[1];
484 /* We don't have halfop */
486 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
488 if (MOD_RESULT == ACR_DENY)
490 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
495 type = MODETYPE_USER;
497 if (user != targetuser && IS_LOCAL(user) && !ServerInstance->ULine(user->server))
499 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
505 /* No such nick/channel */
506 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
510 std::string mode_sequence = parameters[1];
511 std::string parameter;
512 std::ostringstream parameter_list;
513 std::string output_sequence;
514 bool adding = true, state_change = false;
515 unsigned char handler_id = 0;
516 unsigned int parameter_counter = 2; /* Index of first parameter */
517 unsigned int parameter_count = 0;
518 bool last_successful_state_change = false;
519 LastParseTranslate.push_back(TR_TEXT);
521 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
522 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
523 mode_sequence.insert(0, "+");
525 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
527 unsigned char modechar = *letter;
532 * For + and - mode characters, we don't just stick the character into the output sequence.
533 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
534 * appearing in the output sequence, we store a flag which says there was a state change,
535 * which is set on any + or -, however, the + or - that we finish on is only appended to
536 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
539 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
540 * however, will allow the + if it is the first item in the sequence, regardless.
542 if ((!adding) || (!output_sequence.length()))
545 if (!output_sequence.length())
546 last_successful_state_change = false;
550 if ((adding) || (!output_sequence.length()))
553 if (!output_sequence.length())
554 last_successful_state_change = true;
560 * Watch carefully for the sleight of hand trick.
561 * 65 is the ascii value of 'A'. We take this from
562 * the char we're looking at to get a number between
563 * 1 and 127. We then logic-or it to get the hashed
564 * position, dependent on wether its a channel or
565 * a user mode. This is a little stranger, but a lot
566 * faster, than using a map of pairs.
568 handler_id = (modechar - 65) | mask;
570 if (modehandlers[handler_id])
574 if (modehandlers[handler_id]->GetModeType() == type)
578 if (modehandlers[handler_id]->GetNumParams(adding))
580 /* This mode expects a parameter, do we have any parameters left in our list to use? */
581 if (parameter_counter < parameters.size())
583 parameter = parameters[parameter_counter++];
586 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
591 /* No parameter, continue to the next mode */
592 modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
596 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
600 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
603 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
606 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
608 /* Check access to this mode character */
609 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
611 char needed = modehandlers[handler_id]->GetNeededPrefix();
612 ModeHandler* prefixmode = FindPrefix(needed);
614 /* If the mode defined by the handler is not '\0', but the handler for it
615 * cannot be found, they probably dont have the right module loaded to implement
616 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
617 * Revert to checking against the minimum core prefix, '%' or '@'.
619 if (needed && !prefixmode)
620 prefixmode = ServerInstance->Config->AllowHalfop ? FindPrefix('%') : FindPrefix('@');
622 unsigned int neededrank = prefixmode->GetPrefixRank();
623 /* Compare our rank on the channel against the rank of the required prefix,
624 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
625 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
626 * first, so we don't need to iterate, we just look up the first instead.
628 std::string modestring = targetchannel->GetAllPrefixChars(user);
629 char ml = (modestring.empty() ? '\0' : modestring[0]);
630 ModeHandler* ourmode = FindPrefix(ml);
631 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
634 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
635 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
641 bool had_parameter = !parameter.empty();
643 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
645 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
650 /* A module whacked the parameter completely, and there was one. abort. */
651 if ((had_parameter) && (parameter.empty()))
661 /* If it's disabled, they have to be an oper.
663 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
665 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
667 type == MODETYPE_CHANNEL ? "channel" : "user",
668 modehandlers[handler_id]->GetModeChar());
672 /* It's an oper only mode, check if theyre an oper. If they arent,
673 * eat any parameter that came with the mode, and continue to next
675 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
679 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
682 type == MODETYPE_CHANNEL ? "channel" : "user",
683 modehandlers[handler_id]->GetModeChar());
687 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
689 type == MODETYPE_CHANNEL ? "channel" : "user",
690 modehandlers[handler_id]->GetModeChar());
695 /* Call the handler for the mode */
696 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
698 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
700 /* The handler nuked the parameter and they are supposed to have one.
701 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
702 * so we bail to the next mode character.
707 if (ma == MODEACTION_ALLOW)
709 /* We're about to output a valid mode letter - was there previously a pending state-change? */
712 if (adding != last_successful_state_change)
713 output_sequence.append(adding ? "+" : "-");
714 last_successful_state_change = adding;
717 /* Add the mode letter */
718 output_sequence.push_back(modechar);
720 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
722 /* Is there a valid parameter for this mode? If so add it to the parameter list */
723 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
725 parameter_list << " " << parameter;
726 LastParseParams.push_back(parameter);
727 LastParseTranslate.push_back(modehandlers[handler_id]->GetTranslateType());
729 /* Does this mode have a prefix? */
730 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
732 User* user_to_prefix = ServerInstance->FindNick(parameter);
734 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
735 modehandlers[handler_id]->GetPrefixRank(), adding);
739 /* Call all the AfterMode events in the mode watchers for this mode */
740 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
741 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
743 /* Reset the state change flag */
744 state_change = false;
746 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
747 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
749 /* We cant have a mode sequence this long */
750 letter = mode_sequence.end() - 1;
758 /* No mode handler? Unknown mode character then. */
759 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
765 /* Was there at least one valid mode in the sequence? */
766 if (!output_sequence.empty())
768 LastParseParams.push_front(output_sequence);
771 if (type == MODETYPE_CHANNEL)
773 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
774 this->LastParse = targetchannel->name;
778 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
779 this->LastParse = targetuser->nick;
784 if (type == MODETYPE_CHANNEL)
786 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
787 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
788 this->LastParse = targetchannel->name;
792 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
793 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
794 this->LastParse = targetuser->nick;
798 LastParse.append(" ");
799 LastParse.append(output_sequence);
800 LastParse.append(parameter_list.str());
805 const std::string& ModeParser::GetLastParse()
810 void ModeParser::CleanMask(std::string &mask)
812 std::string::size_type pos_of_pling = mask.find_first_of('!');
813 std::string::size_type pos_of_at = mask.find_first_of('@');
814 std::string::size_type pos_of_dot = mask.find_first_of('.');
815 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
817 if (mask.length() >= 2 && mask[1] == ':')
818 return; // if it's an extban, don't even try guess how it needs to be formed.
820 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
822 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
823 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
825 /* It has no '.' in it, it must be a nick. */
830 /* Got a dot in it? Has to be a host */
831 mask = "*!*@" + mask;
834 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
836 /* Has an @ but no !, its a user@host */
839 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
841 /* Has a ! but no @, it must be a nick!ident */
846 bool ModeParser::AddMode(ModeHandler* mh)
848 unsigned char mask = 0;
849 unsigned char pos = 0;
851 /* Yes, i know, this might let people declare modes like '_' or '^'.
852 * If they do that, thats their problem, and if i ever EVER see an
853 * official InspIRCd developer do that, i'll beat them with a paddle!
855 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
858 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
859 * A mode prefix of ':' will fuck up both server to server, and client to server.
860 * A mode prefix of '#' will mess up /whois and /privmsg
862 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
865 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
866 pos = (mh->GetModeChar()-65) | mask;
868 if (modehandlers[pos])
871 modehandlers[pos] = mh;
875 bool ModeParser::DelMode(ModeHandler* mh)
877 unsigned char mask = 0;
878 unsigned char pos = 0;
880 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
883 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
884 pos = (mh->GetModeChar()-65) | mask;
886 if (!modehandlers[pos])
889 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
890 * To stack here we have to make the algorithm slower. Discuss.
892 switch (mh->GetModeType())
895 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
897 mh->RemoveMode(i->second);
900 case MODETYPE_CHANNEL:
901 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
903 mh->RemoveMode(i->second);
908 modehandlers[pos] = NULL;
913 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
915 unsigned char mask = 0;
916 unsigned char pos = 0;
918 if ((modeletter < 'A') || (modeletter > 'z'))
921 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
922 pos = (modeletter-65) | mask;
924 return modehandlers[pos];
927 std::string ModeParser::UserModeList()
932 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
934 unsigned char pos = (mode-65) | MASK_USER;
936 if (modehandlers[pos])
937 modestr[pointer++] = mode;
939 modestr[pointer++] = 0;
943 std::string ModeParser::ChannelModeList()
948 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
950 unsigned char pos = (mode-65) | MASK_CHANNEL;
952 if (modehandlers[pos])
953 modestr[pointer++] = mode;
955 modestr[pointer++] = 0;
959 std::string ModeParser::ParaModeList()
964 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
966 unsigned char pos = (mode-65) | MASK_CHANNEL;
968 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
969 modestr[pointer++] = mode;
971 modestr[pointer++] = 0;
975 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
977 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
979 unsigned char pos = (mode-65) | MASK_CHANNEL;
981 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
983 return modehandlers[pos];
989 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
994 if (!channel || !user)
997 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
999 unsigned char pos = (mode-65) | MASK_CHANNEL;
1000 ModeHandler* mh = modehandlers[pos];
1001 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
1004 ret = mh->ModeSet(NULL, user, channel, user->nick);
1005 if ((ret.first) && (ret.second == user->nick))
1010 pars.append(user->nick);
1012 types.push_back(mh->GetModeChar());
1023 std::string ModeParser::GiveModeList(ModeMasks m)
1025 std::string type1; /* Listmodes EXCEPT those with a prefix */
1026 std::string type2; /* Modes that take a param when adding or removing */
1027 std::string type3; /* Modes that only take a param when adding */
1028 std::string type4; /* Modes that dont take a param */
1030 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1032 unsigned char pos = (mode-65) | m;
1033 /* One parameter when adding */
1034 if (modehandlers[pos])
1036 if (modehandlers[pos]->GetNumParams(true))
1038 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1040 type1 += modehandlers[pos]->GetModeChar();
1044 /* ... and one parameter when removing */
1045 if (modehandlers[pos]->GetNumParams(false))
1047 /* But not a list mode */
1048 if (!modehandlers[pos]->GetPrefix())
1050 type2 += modehandlers[pos]->GetModeChar();
1055 /* No parameters when removing */
1056 type3 += modehandlers[pos]->GetModeChar();
1062 type4 += modehandlers[pos]->GetModeChar();
1067 return type1 + "," + type2 + "," + type3 + "," + type4;
1070 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1072 return one.second > two.second;
1075 std::string ModeParser::BuildPrefixes()
1077 std::string mletters;
1078 std::string mprefixes;
1080 std::map<char,char> prefix_to_mode;
1082 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1084 unsigned char pos = (mode-65) | MASK_CHANNEL;
1086 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1088 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1089 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1093 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1095 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1097 mletters = mletters + n->first;
1098 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1101 return "(" + mprefixes + ")" + mletters;
1104 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1106 unsigned char mask = 0;
1107 unsigned char pos = 0;
1112 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1115 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1116 pos = (mw->GetModeChar()-65) | mask;
1118 modewatchers[pos].push_back(mw);
1123 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1125 unsigned char mask = 0;
1126 unsigned char pos = 0;
1131 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1134 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1135 pos = (mw->GetModeChar()-65) | mask;
1137 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1139 if (a == modewatchers[pos].end())
1144 modewatchers[pos].erase(a);
1149 /** This default implementation can remove simple user modes
1151 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1153 char moderemove[MAXBUF];
1154 std::vector<std::string> parameters;
1156 if (user->IsModeSet(this->GetModeChar()))
1160 stack->Push(this->GetModeChar());
1164 sprintf(moderemove,"-%c",this->GetModeChar());
1165 parameters.push_back(user->nick);
1166 parameters.push_back(moderemove);
1167 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, true);
1172 /** This default implementation can remove simple channel modes
1175 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1177 char moderemove[MAXBUF];
1178 std::vector<std::string> parameters;
1180 if (channel->IsModeSet(this->GetModeChar()))
1184 stack->Push(this->GetModeChar());
1188 sprintf(moderemove,"-%c",this->GetModeChar());
1189 parameters.push_back(channel->name);
1190 parameters.push_back(moderemove);
1191 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1196 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1198 ModeHandler* modes[] =
1200 new ModeChannelSecret(Instance),
1201 new ModeChannelPrivate(Instance),
1202 new ModeChannelModerated(Instance),
1203 new ModeChannelTopicOps(Instance),
1204 new ModeChannelNoExternal(Instance),
1205 new ModeChannelInviteOnly(Instance),
1206 new ModeChannelKey(Instance),
1207 new ModeChannelLimit(Instance),
1208 new ModeChannelBan(Instance),
1209 new ModeChannelOp(Instance),
1210 new ModeChannelHalfOp(Instance),
1211 new ModeChannelVoice(Instance),
1212 new ModeUserWallops(Instance),
1213 new ModeUserInvisible(Instance),
1214 new ModeUserOperator(Instance),
1215 new ModeUserServerNoticeMask(Instance),
1219 /* Clear mode handler list */
1220 memset(modehandlers, 0, sizeof(modehandlers));
1222 /* Last parse string */
1225 /* Initialise the RFC mode letters */
1226 for (int index = 0; modes[index]; index++)
1227 this->AddMode(modes[index]);
1230 memset(&sent, 0, sizeof(sent));