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 std::string ModeHandler::GetUserParameter(User* user)
125 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
127 return MODEACTION_DENY;
130 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
134 return std::make_pair(dest->IsModeSet(this->mode), "");
138 return std::make_pair(channel->IsModeSet(this->mode), "");
142 void ModeHandler::DisplayList(User*, Channel*)
146 void ModeHandler::DisplayEmptyList(User*, Channel*)
150 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
154 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
156 return (ours < theirs);
159 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
163 SimpleUserModeHandler::~SimpleUserModeHandler()
167 SimpleChannelModeHandler::~SimpleChannelModeHandler()
171 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
175 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
177 /* Only opers can change other users modes */
179 return MODEACTION_DENY;
183 if (!dest->IsModeSet(this->GetModeChar()))
185 dest->SetMode(this->GetModeChar(),true);
186 return MODEACTION_ALLOW;
191 if (dest->IsModeSet(this->GetModeChar()))
193 dest->SetMode(this->GetModeChar(),false);
194 return MODEACTION_ALLOW;
198 return MODEACTION_DENY;
202 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
206 if (!channel->IsModeSet(this->GetModeChar()))
208 channel->SetMode(this->GetModeChar(),true);
209 return MODEACTION_ALLOW;
214 if (channel->IsModeSet(this->GetModeChar()))
216 channel->SetMode(this->GetModeChar(),false);
217 return MODEACTION_ALLOW;
221 return MODEACTION_DENY;
224 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
228 ModeWatcher::~ModeWatcher()
232 char ModeWatcher::GetModeChar()
237 ModeType ModeWatcher::GetModeType()
242 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
247 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
251 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
254 if ((!user) || (!dest) || (!chan) || (!*dest))
258 d = ServerInstance->FindNick(dest);
261 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
267 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
272 UCListIter n = d->chans.find(chan);
273 if (n != d->chans.end())
275 if (n->second & MASK)
279 n->second = n->second | MASK;
283 n->first->AddOppedUser(d);
286 n->first->AddHalfoppedUser(d);
289 n->first->AddVoicedUser(d);
292 return d->nick.c_str();
297 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
302 UCListIter n = d->chans.find(chan);
303 if (n != d->chans.end())
305 if ((n->second & MASK) == 0)
313 n->first->DelOppedUser(d);
316 n->first->DelHalfoppedUser(d);
319 n->first->DelVoicedUser(d);
322 return d->nick.c_str();
327 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
331 /* Display channel's current mode string */
332 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
333 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
338 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
340 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
344 if ((targetuser == user) || (IS_OPER(user)))
346 /* Display user's current mode string */
347 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
348 if (IS_OPER(targetuser))
349 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
354 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
359 /* No such nick/channel */
360 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
364 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
366 std::string target = parameters[0];
367 ModeType type = MODETYPE_USER;
368 unsigned char mask = 0;
369 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
370 User* targetuser = ServerInstance->FindNick(parameters[0]);
374 /* Special case for displaying the list for listmodes,
375 * e.g. MODE #chan b, or MODE #chan +b without a parameter
377 if ((targetchannel) && (parameters.size() == 2))
379 const char* mode = parameters[1].c_str();
380 int nonlistmodes_found = 0;
386 while (mode && *mode)
388 unsigned char mletter = *mode;
396 /* Ensure the user doesnt request the same mode twice,
397 * so they cant flood themselves off out of idiocy.
399 if (sent[mletter] != seq)
409 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
412 if ((mh) && (mh->IsListMode()))
415 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
416 if (MOD_RESULT == ACR_DENY)
424 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
426 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++);
427 mh->DisplayEmptyList(user, targetchannel);
432 /** See below for a description of what craq this is :D
434 unsigned char handler_id = (*mode - 65) | mask;
436 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
438 std::string dummyparam;
440 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
445 mh->DisplayList(user, targetchannel);
448 nonlistmodes_found++;
453 /* We didnt have any modes that were non-list, we can return here */
454 if (!nonlistmodes_found)
458 if (parameters.size() == 1)
460 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
462 else if (parameters.size() > 1)
464 bool SkipAccessChecks = false;
468 type = MODETYPE_CHANNEL;
471 /* Extra security checks on channel modes
472 * (e.g. are they a (half)op?
475 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
477 /* We don't have halfop */
479 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
480 if (MOD_RESULT == ACR_DENY)
482 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
487 type = MODETYPE_USER;
489 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
491 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
497 /* No such nick/channel */
498 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
502 std::string mode_sequence = parameters[1];
503 std::string parameter;
504 std::ostringstream parameter_list;
505 std::string output_sequence;
506 bool adding = true, state_change = false;
507 unsigned char handler_id = 0;
508 unsigned int parameter_counter = 2; /* Index of first parameter */
509 unsigned int parameter_count = 0;
510 bool last_successful_state_change = false;
512 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
513 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
514 mode_sequence.insert(0, "+");
516 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
518 unsigned char modechar = *letter;
523 * For + and - mode characters, we don't just stick the character into the output sequence.
524 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
525 * appearing in the output sequence, we store a flag which says there was a state change,
526 * which is set on any + or -, however, the + or - that we finish on is only appended to
527 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
530 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
531 * however, will allow the + if it is the first item in the sequence, regardless.
533 if ((!adding) || (!output_sequence.length()))
536 if (!output_sequence.length())
537 last_successful_state_change = false;
541 if ((adding) || (!output_sequence.length()))
544 if (!output_sequence.length())
545 last_successful_state_change = true;
551 * Watch carefully for the sleight of hand trick.
552 * 65 is the ascii value of 'A'. We take this from
553 * the char we're looking at to get a number between
554 * 1 and 127. We then logic-or it to get the hashed
555 * position, dependent on wether its a channel or
556 * a user mode. This is a little stranger, but a lot
557 * faster, than using a map of pairs.
559 handler_id = (modechar - 65) | mask;
561 if (modehandlers[handler_id])
565 if (modehandlers[handler_id]->GetModeType() == type)
569 if (modehandlers[handler_id]->GetNumParams(adding))
571 /* This mode expects a parameter, do we have any parameters left in our list to use? */
572 if (parameter_counter < parameters.size())
574 parameter = parameters[parameter_counter++];
577 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
582 /* No parameter, continue to the next mode */
583 modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
587 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
591 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
594 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
597 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
599 /* Check access to this mode character */
600 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
602 char needed = modehandlers[handler_id]->GetNeededPrefix();
603 ModeHandler* prefixmode = FindPrefix(needed);
605 /* If the mode defined by the handler is not '\0', but the handler for it
606 * cannot be found, they probably dont have the right module loaded to implement
607 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
608 * Revert to checking against the minimum core prefix, '%'.
610 if (needed && !prefixmode)
611 prefixmode = FindPrefix('%');
613 unsigned int neededrank = prefixmode->GetPrefixRank();
614 /* Compare our rank on the channel against the rank of the required prefix,
615 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
616 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
617 * first, so we don't need to iterate, we just look up the first instead.
619 std::string modestring = targetchannel->GetAllPrefixChars(user);
620 char ml = (modestring.empty() ? '\0' : modestring[0]);
621 ModeHandler* ourmode = FindPrefix(ml);
622 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
625 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
626 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
632 bool had_parameter = !parameter.empty();
634 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
636 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
641 /* A module whacked the parameter completely, and there was one. abort. */
642 if ((had_parameter) && (parameter.empty()))
652 /* If it's disabled, they have to be an oper.
654 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
656 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
658 type == MODETYPE_CHANNEL ? "channel" : "user",
659 modehandlers[handler_id]->GetModeChar());
663 /* It's an oper only mode, check if theyre an oper. If they arent,
664 * eat any parameter that came with the mode, and continue to next
666 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
670 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
673 type == MODETYPE_CHANNEL ? "channel" : "user",
674 modehandlers[handler_id]->GetModeChar());
678 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
680 type == MODETYPE_CHANNEL ? "channel" : "user",
681 modehandlers[handler_id]->GetModeChar());
686 /* Call the handler for the mode */
687 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
689 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
691 /* The handler nuked the parameter and they are supposed to have one.
692 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
693 * so we bail to the next mode character.
698 if (ma == MODEACTION_ALLOW)
700 /* We're about to output a valid mode letter - was there previously a pending state-change? */
703 if (adding != last_successful_state_change)
704 output_sequence.append(adding ? "+" : "-");
705 last_successful_state_change = adding;
708 /* Add the mode letter */
709 output_sequence.push_back(modechar);
711 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
713 /* Is there a valid parameter for this mode? If so add it to the parameter list */
714 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
716 parameter_list << " " << parameter;
718 /* Does this mode have a prefix? */
719 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
721 User* user_to_prefix = ServerInstance->FindNick(parameter);
723 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
724 modehandlers[handler_id]->GetPrefixRank(), adding);
728 /* Call all the AfterMode events in the mode watchers for this mode */
729 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
730 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
732 /* Reset the state change flag */
733 state_change = false;
735 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
736 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
738 /* We cant have a mode sequence this long */
739 letter = mode_sequence.end() - 1;
747 /* No mode handler? Unknown mode character then. */
748 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
754 /* Was there at least one valid mode in the sequence? */
755 if (!output_sequence.empty())
759 if (type == MODETYPE_CHANNEL)
761 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
762 this->LastParse = targetchannel->name;
766 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
767 this->LastParse = targetuser->nick;
772 if (type == MODETYPE_CHANNEL)
774 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
775 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
776 this->LastParse = targetchannel->name;
780 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
781 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
782 this->LastParse = targetuser->nick;
786 LastParse.append(" ");
787 LastParse.append(output_sequence);
788 LastParse.append(parameter_list.str());
793 const std::string& ModeParser::GetLastParse()
798 void ModeParser::CleanMask(std::string &mask)
800 std::string::size_type pos_of_pling = mask.find_first_of('!');
801 std::string::size_type pos_of_at = mask.find_first_of('@');
802 std::string::size_type pos_of_dot = mask.find_first_of('.');
803 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
805 if (mask.length() >= 2 && mask[1] == ':')
806 return; // if it's an extban, don't even try guess how it needs to be formed.
808 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
810 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
811 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
813 /* It has no '.' in it, it must be a nick. */
818 /* Got a dot in it? Has to be a host */
819 mask = "*!*@" + mask;
822 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
824 /* Has an @ but no !, its a user@host */
827 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
829 /* Has a ! but no @, it must be a nick!ident */
834 bool ModeParser::AddMode(ModeHandler* mh)
836 unsigned char mask = 0;
837 unsigned char pos = 0;
839 /* Yes, i know, this might let people declare modes like '_' or '^'.
840 * If they do that, thats their problem, and if i ever EVER see an
841 * official InspIRCd developer do that, i'll beat them with a paddle!
843 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
846 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
847 * A mode prefix of ':' will fuck up both server to server, and client to server.
848 * A mode prefix of '#' will mess up /whois and /privmsg
850 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
853 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
854 pos = (mh->GetModeChar()-65) | mask;
856 if (modehandlers[pos])
859 modehandlers[pos] = mh;
863 bool ModeParser::DelMode(ModeHandler* mh)
865 unsigned char mask = 0;
866 unsigned char pos = 0;
868 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
871 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
872 pos = (mh->GetModeChar()-65) | mask;
874 if (!modehandlers[pos])
877 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
878 * To stack here we have to make the algorithm slower. Discuss.
880 switch (mh->GetModeType())
883 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
885 mh->RemoveMode(i->second);
888 case MODETYPE_CHANNEL:
889 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
891 mh->RemoveMode(i->second);
896 modehandlers[pos] = NULL;
901 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
903 unsigned char mask = 0;
904 unsigned char pos = 0;
906 if ((modeletter < 'A') || (modeletter > 'z'))
909 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
910 pos = (modeletter-65) | mask;
912 return modehandlers[pos];
915 std::string ModeParser::UserModeList()
920 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
922 unsigned char pos = (mode-65) | MASK_USER;
924 if (modehandlers[pos])
925 modestr[pointer++] = mode;
927 modestr[pointer++] = 0;
931 std::string ModeParser::ChannelModeList()
936 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
938 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
941 unsigned char pos = (mode-65) | MASK_CHANNEL;
943 if (modehandlers[pos])
944 modestr[pointer++] = mode;
946 modestr[pointer++] = 0;
950 std::string ModeParser::ParaModeList()
955 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
957 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
960 unsigned char pos = (mode-65) | MASK_CHANNEL;
962 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
963 modestr[pointer++] = mode;
965 modestr[pointer++] = 0;
969 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
971 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
973 unsigned char pos = (mode-65) | MASK_CHANNEL;
975 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
977 return modehandlers[pos];
983 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
988 if (!channel || !user)
991 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
993 unsigned char pos = (mode-65) | MASK_CHANNEL;
994 ModeHandler* mh = modehandlers[pos];
995 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
998 ret = mh->ModeSet(NULL, user, channel, user->nick);
999 if ((ret.first) && (ret.second == user->nick))
1004 pars.append(user->nick);
1006 types.push_back(mh->GetModeChar());
1017 std::string ModeParser::ChanModes()
1019 std::string type1; /* Listmodes EXCEPT those with a prefix */
1020 std::string type2; /* Modes that take a param when adding or removing */
1021 std::string type3; /* Modes that only take a param when adding */
1022 std::string type4; /* Modes that dont take a param */
1024 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1026 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1029 unsigned char pos = (mode-65) | MASK_CHANNEL;
1030 /* One parameter when adding */
1031 if (modehandlers[pos])
1033 if (modehandlers[pos]->GetNumParams(true))
1035 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1037 type1 += modehandlers[pos]->GetModeChar();
1041 /* ... and one parameter when removing */
1042 if (modehandlers[pos]->GetNumParams(false))
1044 /* But not a list mode */
1045 if (!modehandlers[pos]->GetPrefix())
1047 type2 += modehandlers[pos]->GetModeChar();
1052 /* No parameters when removing */
1053 type3 += modehandlers[pos]->GetModeChar();
1059 type4 += modehandlers[pos]->GetModeChar();
1065 return type1 + "," + type2 + "," + type3 + "," + type4;
1068 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1070 return one.second > two.second;
1073 std::string ModeParser::BuildPrefixes()
1075 std::string mletters;
1076 std::string mprefixes;
1078 std::map<char,char> prefix_to_mode;
1080 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1082 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1085 unsigned char pos = (mode-65) | MASK_CHANNEL;
1087 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1089 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1090 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1094 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1096 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1098 mletters = mletters + n->first;
1099 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1102 return "(" + mprefixes + ")" + mletters;
1105 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1107 unsigned char mask = 0;
1108 unsigned char pos = 0;
1113 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1116 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1117 pos = (mw->GetModeChar()-65) | mask;
1119 modewatchers[pos].push_back(mw);
1124 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1126 unsigned char mask = 0;
1127 unsigned char pos = 0;
1132 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1135 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1136 pos = (mw->GetModeChar()-65) | mask;
1138 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1140 if (a == modewatchers[pos].end())
1145 modewatchers[pos].erase(a);
1150 /** This default implementation can remove simple user modes
1152 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1154 char moderemove[MAXBUF];
1155 std::vector<std::string> parameters;
1157 if (user->IsModeSet(this->GetModeChar()))
1161 stack->Push(this->GetModeChar());
1165 sprintf(moderemove,"-%c",this->GetModeChar());
1166 parameters.push_back(user->nick);
1167 parameters.push_back(moderemove);
1168 ServerInstance->Parser->CallHandler("MODE", parameters, user);
1173 /** This default implementation can remove simple channel modes
1176 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1178 char moderemove[MAXBUF];
1179 std::vector<std::string> parameters;
1181 if (channel->IsModeSet(this->GetModeChar()))
1185 stack->Push(this->GetModeChar());
1189 sprintf(moderemove,"-%c",this->GetModeChar());
1190 parameters.push_back(channel->name);
1191 parameters.push_back(moderemove);
1192 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1197 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1199 ModeHandler* modes[] =
1201 new ModeChannelSecret(Instance),
1202 new ModeChannelPrivate(Instance),
1203 new ModeChannelModerated(Instance),
1204 new ModeChannelTopicOps(Instance),
1205 new ModeChannelNoExternal(Instance),
1206 new ModeChannelInviteOnly(Instance),
1207 new ModeChannelKey(Instance),
1208 new ModeChannelLimit(Instance),
1209 new ModeChannelBan(Instance),
1210 new ModeChannelOp(Instance),
1211 new ModeChannelHalfOp(Instance),
1212 new ModeChannelVoice(Instance),
1213 new ModeUserWallops(Instance),
1214 new ModeUserInvisible(Instance),
1215 new ModeUserOperator(Instance),
1216 new ModeUserServerNoticeMask(Instance),
1220 /* Clear mode handler list */
1221 memset(modehandlers, 0, sizeof(modehandlers));
1223 /* Last parse string */
1226 /* Initialise the RFC mode letters */
1227 for (int index = 0; modes[index]; index++)
1228 this->AddMode(modes[index]);
1231 memset(&sent, 0, sizeof(sent));