1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2008 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)
56 : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), 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 bool ModeHandler::NeedsOper()
105 char ModeHandler::GetPrefix()
110 int ModeHandler::GetNumParams(bool adding)
112 return adding ? n_params_on : n_params_off;
115 char ModeHandler::GetModeChar()
120 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
122 return MODEACTION_DENY;
125 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
129 return std::make_pair(dest->IsModeSet(this->mode), "");
133 return std::make_pair(channel->IsModeSet(this->mode), "");
137 void ModeHandler::DisplayList(User*, Channel*)
141 void ModeHandler::DisplayEmptyList(User*, Channel*)
145 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
149 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
151 return (ours < theirs);
154 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
158 SimpleUserModeHandler::~SimpleUserModeHandler()
162 SimpleChannelModeHandler::~SimpleChannelModeHandler()
166 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
170 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
172 /* Only opers can change other users modes */
174 return MODEACTION_DENY;
178 if (!dest->IsModeSet(this->GetModeChar()))
180 dest->SetMode(this->GetModeChar(),true);
181 return MODEACTION_ALLOW;
186 if (dest->IsModeSet(this->GetModeChar()))
188 dest->SetMode(this->GetModeChar(),false);
189 return MODEACTION_ALLOW;
193 return MODEACTION_DENY;
197 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
201 if (!channel->IsModeSet(this->GetModeChar()))
203 channel->SetMode(this->GetModeChar(),true);
204 return MODEACTION_ALLOW;
209 if (channel->IsModeSet(this->GetModeChar()))
211 channel->SetMode(this->GetModeChar(),false);
212 return MODEACTION_ALLOW;
216 return MODEACTION_DENY;
219 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
223 ModeWatcher::~ModeWatcher()
227 char ModeWatcher::GetModeChar()
232 ModeType ModeWatcher::GetModeType()
237 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
242 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
246 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
249 if ((!user) || (!dest) || (!chan) || (!*dest))
253 d = ServerInstance->FindNick(dest);
256 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
262 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
267 UCListIter n = d->chans.find(chan);
268 if (n != d->chans.end())
270 if (n->second & MASK)
274 n->second = n->second | MASK;
278 n->first->AddOppedUser(d);
281 n->first->AddHalfoppedUser(d);
284 n->first->AddVoicedUser(d);
287 return d->nick.c_str();
292 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
297 UCListIter n = d->chans.find(chan);
298 if (n != d->chans.end())
300 if ((n->second & MASK) == 0)
308 n->first->DelOppedUser(d);
311 n->first->DelHalfoppedUser(d);
314 n->first->DelVoicedUser(d);
317 return d->nick.c_str();
322 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
326 /* Display channel's current mode string */
327 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
328 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
333 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
335 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
339 if ((targetuser == user) || (IS_OPER(user)))
341 /* Display user's current mode string */
342 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
343 if (IS_OPER(targetuser))
344 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
349 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
354 /* No such nick/channel */
355 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
359 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
361 std::string target = parameters[0];
362 ModeType type = MODETYPE_USER;
363 unsigned char mask = 0;
364 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
365 User* targetuser = ServerInstance->FindNick(parameters[0]);
369 /* Special case for displaying the list for listmodes,
370 * e.g. MODE #chan b, or MODE #chan +b without a parameter
372 if ((targetchannel) && (parameters.size() == 2))
374 const char* mode = parameters[1].c_str();
375 int nonlistmodes_found = 0;
381 while (mode && *mode)
383 unsigned char mletter = *mode;
391 /* Ensure the user doesnt request the same mode twice,
392 * so they cant flood themselves off out of idiocy.
394 if (sent[mletter] != seq)
404 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
407 if ((mh) && (mh->IsListMode()))
410 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
411 if (MOD_RESULT == ACR_DENY)
419 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
421 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++);
422 mh->DisplayEmptyList(user, targetchannel);
427 /** See below for a description of what craq this is :D
429 unsigned char handler_id = (*mode - 65) | mask;
431 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
433 std::string dummyparam;
435 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
440 mh->DisplayList(user, targetchannel);
443 nonlistmodes_found++;
448 /* We didnt have any modes that were non-list, we can return here */
449 if (!nonlistmodes_found)
453 if (parameters.size() == 1)
455 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
457 else if (parameters.size() > 1)
459 bool SkipAccessChecks = false;
463 type = MODETYPE_CHANNEL;
466 /* Extra security checks on channel modes
467 * (e.g. are they a (half)op?
470 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
472 /* We don't have halfop */
474 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
475 if (MOD_RESULT == ACR_DENY)
477 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
482 type = MODETYPE_USER;
484 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
486 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
492 /* No such nick/channel */
493 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
497 std::string mode_sequence = parameters[1];
498 std::string parameter;
499 std::ostringstream parameter_list;
500 std::string output_sequence;
501 bool adding = true, state_change = false;
502 unsigned char handler_id = 0;
503 unsigned int parameter_counter = 2; /* Index of first parameter */
504 unsigned int parameter_count = 0;
505 bool last_successful_state_change = false;
507 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
508 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
509 mode_sequence.insert(0, "+");
511 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
513 unsigned char modechar = *letter;
518 * For + and - mode characters, we don't just stick the character into the output sequence.
519 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
520 * appearing in the output sequence, we store a flag which says there was a state change,
521 * which is set on any + or -, however, the + or - that we finish on is only appended to
522 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
525 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
526 * however, will allow the + if it is the first item in the sequence, regardless.
528 if ((!adding) || (!output_sequence.length()))
531 if (!output_sequence.length())
532 last_successful_state_change = false;
536 if ((adding) || (!output_sequence.length()))
539 if (!output_sequence.length())
540 last_successful_state_change = true;
546 * Watch carefully for the sleight of hand trick.
547 * 65 is the ascii value of 'A'. We take this from
548 * the char we're looking at to get a number between
549 * 1 and 127. We then logic-or it to get the hashed
550 * position, dependent on wether its a channel or
551 * a user mode. This is a little stranger, but a lot
552 * faster, than using a map of pairs.
554 handler_id = (modechar - 65) | mask;
556 if (modehandlers[handler_id])
560 if (modehandlers[handler_id]->GetModeType() == type)
564 if (modehandlers[handler_id]->GetNumParams(adding))
566 /* This mode expects a parameter, do we have any parameters left in our list to use? */
567 if (parameter_counter < parameters.size())
569 parameter = parameters[parameter_counter++];
572 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
577 /* No parameter, continue to the next mode */
578 modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
582 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
586 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
589 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
592 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
594 /* Check access to this mode character */
595 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
597 char needed = modehandlers[handler_id]->GetNeededPrefix();
598 ModeHandler* prefixmode = FindPrefix(needed);
600 /* If the mode defined by the handler is not '\0', but the handler for it
601 * cannot be found, they probably dont have the right module loaded to implement
602 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
603 * Revert to checking against the minimum core prefix, '%'.
605 if (needed && !prefixmode)
606 prefixmode = FindPrefix('%');
608 unsigned int neededrank = prefixmode->GetPrefixRank();
609 /* Compare our rank on the channel against the rank of the required prefix,
610 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
611 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
612 * first, so we don't need to iterate, we just look up the first instead.
614 std::string modestring = targetchannel->GetAllPrefixChars(user);
615 char ml = (modestring.empty() ? '\0' : modestring[0]);
616 ModeHandler* ourmode = FindPrefix(ml);
617 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
620 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
621 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
627 bool had_parameter = !parameter.empty();
629 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
631 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
636 /* A module whacked the parameter completely, and there was one. abort. */
637 if ((had_parameter) && (parameter.empty()))
647 /* If it's disabled, they have to be an oper.
649 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
651 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
653 type == MODETYPE_CHANNEL ? "channel" : "user",
654 modehandlers[handler_id]->GetModeChar());
658 /* It's an oper only mode, check if theyre an oper. If they arent,
659 * eat any parameter that came with the mode, and continue to next
661 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
665 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
668 type == MODETYPE_CHANNEL ? "channel" : "user",
669 modehandlers[handler_id]->GetModeChar());
673 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
675 type == MODETYPE_CHANNEL ? "channel" : "user",
676 modehandlers[handler_id]->GetModeChar());
681 /* Call the handler for the mode */
682 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
684 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
686 /* The handler nuked the parameter and they are supposed to have one.
687 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
688 * so we bail to the next mode character.
693 if (ma == MODEACTION_ALLOW)
695 /* We're about to output a valid mode letter - was there previously a pending state-change? */
698 if (adding != last_successful_state_change)
699 output_sequence.append(adding ? "+" : "-");
700 last_successful_state_change = adding;
703 /* Add the mode letter */
704 output_sequence.push_back(modechar);
706 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
708 /* Is there a valid parameter for this mode? If so add it to the parameter list */
709 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
711 parameter_list << " " << parameter;
713 /* Does this mode have a prefix? */
714 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
716 User* user_to_prefix = ServerInstance->FindNick(parameter);
718 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
719 modehandlers[handler_id]->GetPrefixRank(), adding);
723 /* Call all the AfterMode events in the mode watchers for this mode */
724 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
725 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
727 /* Reset the state change flag */
728 state_change = false;
730 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
731 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
733 /* We cant have a mode sequence this long */
734 letter = mode_sequence.end() - 1;
742 /* No mode handler? Unknown mode character then. */
743 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
749 /* Was there at least one valid mode in the sequence? */
750 if (!output_sequence.empty())
754 if (type == MODETYPE_CHANNEL)
756 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
757 this->LastParse = targetchannel->name;
761 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
762 this->LastParse = targetuser->nick;
767 if (type == MODETYPE_CHANNEL)
769 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
770 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
771 this->LastParse = targetchannel->name;
775 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
776 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
777 this->LastParse = targetuser->nick;
781 LastParse.append(" ");
782 LastParse.append(output_sequence);
783 LastParse.append(parameter_list.str());
788 const std::string& ModeParser::GetLastParse()
793 void ModeParser::CleanMask(std::string &mask)
795 std::string::size_type pos_of_pling = mask.find_first_of('!');
796 std::string::size_type pos_of_at = mask.find_first_of('@');
797 std::string::size_type pos_of_dot = mask.find_first_of('.');
798 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
800 if (mask.length() >= 2 && mask[1] == ':')
801 return; // if it's an extban, don't even try guess how it needs to be formed.
803 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
805 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
806 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
808 /* It has no '.' in it, it must be a nick. */
813 /* Got a dot in it? Has to be a host */
814 mask = "*!*@" + mask;
817 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
819 /* Has an @ but no !, its a user@host */
822 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
824 /* Has a ! but no @, it must be a nick!ident */
829 bool ModeParser::AddMode(ModeHandler* mh)
831 unsigned char mask = 0;
832 unsigned char pos = 0;
834 /* Yes, i know, this might let people declare modes like '_' or '^'.
835 * If they do that, thats their problem, and if i ever EVER see an
836 * official InspIRCd developer do that, i'll beat them with a paddle!
838 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
841 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
842 * A mode prefix of ':' will fuck up both server to server, and client to server.
843 * A mode prefix of '#' will mess up /whois and /privmsg
845 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
848 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
849 pos = (mh->GetModeChar()-65) | mask;
851 if (modehandlers[pos])
854 modehandlers[pos] = mh;
858 bool ModeParser::DelMode(ModeHandler* mh)
860 unsigned char mask = 0;
861 unsigned char pos = 0;
863 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
866 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
867 pos = (mh->GetModeChar()-65) | mask;
869 if (!modehandlers[pos])
872 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
873 * To stack here we have to make the algorithm slower. Discuss.
875 switch (mh->GetModeType())
878 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
880 mh->RemoveMode(i->second);
883 case MODETYPE_CHANNEL:
884 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
886 mh->RemoveMode(i->second);
891 modehandlers[pos] = NULL;
896 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
898 unsigned char mask = 0;
899 unsigned char pos = 0;
901 if ((modeletter < 'A') || (modeletter > 'z'))
904 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
905 pos = (modeletter-65) | mask;
907 return modehandlers[pos];
910 std::string ModeParser::UserModeList()
915 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
917 unsigned char pos = (mode-65) | MASK_USER;
919 if (modehandlers[pos])
920 modestr[pointer++] = mode;
922 modestr[pointer++] = 0;
926 std::string ModeParser::ChannelModeList()
931 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
933 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
936 unsigned char pos = (mode-65) | MASK_CHANNEL;
938 if (modehandlers[pos])
939 modestr[pointer++] = mode;
941 modestr[pointer++] = 0;
945 std::string ModeParser::ParaModeList()
950 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
952 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
955 unsigned char pos = (mode-65) | MASK_CHANNEL;
957 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
958 modestr[pointer++] = mode;
960 modestr[pointer++] = 0;
964 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
966 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
968 unsigned char pos = (mode-65) | MASK_CHANNEL;
970 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
972 return modehandlers[pos];
978 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
983 if (!channel || !user)
986 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
988 unsigned char pos = (mode-65) | MASK_CHANNEL;
989 ModeHandler* mh = modehandlers[pos];
990 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
993 ret = mh->ModeSet(NULL, user, channel, user->nick);
994 if ((ret.first) && (ret.second == user->nick))
999 pars.append(user->nick);
1001 types.push_back(mh->GetModeChar());
1012 std::string ModeParser::ChanModes()
1014 std::string type1; /* Listmodes EXCEPT those with a prefix */
1015 std::string type2; /* Modes that take a param when adding or removing */
1016 std::string type3; /* Modes that only take a param when adding */
1017 std::string type4; /* Modes that dont take a param */
1019 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1021 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1024 unsigned char pos = (mode-65) | MASK_CHANNEL;
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();
1060 return type1 + "," + type2 + "," + type3 + "," + type4;
1063 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1065 return one.second > two.second;
1068 std::string ModeParser::BuildPrefixes()
1070 std::string mletters;
1071 std::string mprefixes;
1073 std::map<char,char> prefix_to_mode;
1075 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1077 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1080 unsigned char pos = (mode-65) | MASK_CHANNEL;
1082 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1084 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1085 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1089 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1091 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1093 mletters = mletters + n->first;
1094 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1097 return "(" + mprefixes + ")" + mletters;
1100 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1102 unsigned char mask = 0;
1103 unsigned char pos = 0;
1108 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1111 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1112 pos = (mw->GetModeChar()-65) | mask;
1114 modewatchers[pos].push_back(mw);
1119 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1121 unsigned char mask = 0;
1122 unsigned char pos = 0;
1127 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1130 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1131 pos = (mw->GetModeChar()-65) | mask;
1133 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1135 if (a == modewatchers[pos].end())
1140 modewatchers[pos].erase(a);
1145 /** This default implementation can remove simple user modes
1147 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1149 char moderemove[MAXBUF];
1150 std::vector<std::string> parameters;
1152 if (user->IsModeSet(this->GetModeChar()))
1156 stack->Push(this->GetModeChar());
1160 sprintf(moderemove,"-%c",this->GetModeChar());
1161 parameters.push_back(user->nick);
1162 parameters.push_back(moderemove);
1163 ServerInstance->Parser->CallHandler("MODE", parameters, user);
1168 /** This default implementation can remove simple channel modes
1171 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1173 char moderemove[MAXBUF];
1174 std::vector<std::string> parameters;
1176 if (channel->IsModeSet(this->GetModeChar()))
1180 stack->Push(this->GetModeChar());
1184 sprintf(moderemove,"-%c",this->GetModeChar());
1185 parameters.push_back(channel->name);
1186 parameters.push_back(moderemove);
1187 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1192 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1194 ModeHandler* modes[] =
1196 new ModeChannelSecret(Instance),
1197 new ModeChannelPrivate(Instance),
1198 new ModeChannelModerated(Instance),
1199 new ModeChannelTopicOps(Instance),
1200 new ModeChannelNoExternal(Instance),
1201 new ModeChannelInviteOnly(Instance),
1202 new ModeChannelKey(Instance),
1203 new ModeChannelLimit(Instance),
1204 new ModeChannelBan(Instance),
1205 new ModeChannelOp(Instance),
1206 new ModeChannelHalfOp(Instance),
1207 new ModeChannelVoice(Instance),
1208 new ModeUserWallops(Instance),
1209 new ModeUserInvisible(Instance),
1210 new ModeUserOperator(Instance),
1211 new ModeUserServerNoticeMask(Instance),
1215 /* Clear mode handler list */
1216 memset(modehandlers, 0, sizeof(modehandlers));
1218 /* Last parse string */
1221 /* Initialise the RFC mode letters */
1222 for (int index = 0; modes[index]; index++)
1223 this->AddMode(modes[index]);
1226 memset(&sent, 0, sizeof(sent));