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 * ---------------------------------------------------
17 #include "inspstring.h"
20 #include "modes/cmode_s.h"
22 #include "modes/cmode_p.h"
24 #include "modes/cmode_b.h"
26 #include "modes/cmode_m.h"
27 /* +t (only (half) ops can change topic) */
28 #include "modes/cmode_t.h"
29 /* +n (no external messages) */
30 #include "modes/cmode_n.h"
31 /* +i (invite only) */
32 #include "modes/cmode_i.h"
33 /* +k (keyed channel) */
34 #include "modes/cmode_k.h"
35 /* +l (channel user limit) */
36 #include "modes/cmode_l.h"
38 #include "modes/cmode_o.h"
39 /* +h (channel halfop) */
40 #include "modes/cmode_h.h"
41 /* +v (channel voice) */
42 #include "modes/cmode_v.h"
43 /* +w (see wallops) */
44 #include "modes/umode_w.h"
46 #include "modes/umode_i.h"
48 #include "modes/umode_o.h"
49 /* +s (server notice masks) */
50 #include "modes/umode_s.h"
52 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired, TranslateType translate)
53 : 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)
57 ModeHandler::~ModeHandler()
61 bool ModeHandler::IsListMode()
66 char ModeHandler::GetNeededPrefix()
68 if (prefixneeded == '%' && !ServerInstance->Config->AllowHalfop)
73 void ModeHandler::SetNeededPrefix(char needsprefix)
75 prefixneeded = needsprefix;
78 unsigned int ModeHandler::GetPrefixRank()
83 unsigned int ModeHandler::GetCount()
88 void ModeHandler::ChangeCount(int modifier)
91 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
94 ModeType ModeHandler::GetModeType()
99 TranslateType ModeHandler::GetTranslateType()
104 bool ModeHandler::NeedsOper()
109 char ModeHandler::GetPrefix()
114 int ModeHandler::GetNumParams(bool adding)
116 return adding ? n_params_on : n_params_off;
119 char ModeHandler::GetModeChar()
124 std::string ModeHandler::GetUserParameter(User* user)
129 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
131 return MODEACTION_DENY;
134 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
138 return std::make_pair(dest->IsModeSet(this->mode), "");
142 return std::make_pair(channel->IsModeSet(this->mode), "");
146 void ModeHandler::DisplayList(User*, Channel*)
150 void ModeHandler::DisplayEmptyList(User*, Channel*)
154 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
158 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
160 return (ours < theirs);
163 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
167 SimpleUserModeHandler::~SimpleUserModeHandler()
171 SimpleChannelModeHandler::~SimpleChannelModeHandler()
175 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
179 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
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 || user->HasPrivPermission("users/auspex"))
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]);
373 LastParseParams.clear();
374 LastParseTranslate.clear();
376 /* Special case for displaying the list for listmodes,
377 * e.g. MODE #chan b, or MODE #chan +b without a parameter
379 if ((targetchannel) && (parameters.size() == 2))
381 const char* mode = parameters[1].c_str();
382 int nonlistmodes_found = 0;
388 while (mode && *mode)
390 unsigned char mletter = *mode;
398 /* Ensure the user doesnt request the same mode twice,
399 * so they cant flood themselves off out of idiocy.
401 if (sent[mletter] != seq)
411 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
414 if ((mh) && (mh->IsListMode()))
417 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
418 if (MOD_RESULT == ACR_DENY)
424 if (!user->HasPrivPermission("channels/auspex"))
426 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
428 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++);
429 mh->DisplayEmptyList(user, targetchannel);
434 /** See below for a description of what craq this is :D
436 unsigned char handler_id = (*mode - 65) | mask;
438 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
440 std::string dummyparam;
442 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
447 mh->DisplayList(user, targetchannel);
450 nonlistmodes_found++;
455 /* We didnt have any modes that were non-list, we can return here */
456 if (!nonlistmodes_found)
460 if (parameters.size() == 1)
462 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
464 else if (parameters.size() > 1)
466 bool SkipAccessChecks = false;
470 type = MODETYPE_CHANNEL;
473 /* Extra security checks on channel modes
474 * (e.g. are they a (half)op?
477 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
479 /* Make modes that are being changed visible to OnAccessCheck */
480 LastParse = parameters[1];
481 /* We don't have halfop */
483 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
485 if (MOD_RESULT == ACR_DENY)
487 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
492 type = MODETYPE_USER;
494 if (user != targetuser && IS_LOCAL(user) && !ServerInstance->ULine(user->server))
496 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
502 /* No such nick/channel */
503 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
507 std::string mode_sequence = parameters[1];
508 std::string parameter;
509 std::ostringstream parameter_list;
510 std::string output_sequence;
511 bool adding = true, state_change = false;
512 unsigned char handler_id = 0;
513 unsigned int parameter_counter = 2; /* Index of first parameter */
514 unsigned int parameter_count = 0;
515 bool last_successful_state_change = false;
516 LastParseParams.push_back(output_sequence);
517 LastParseTranslate.push_back(TR_TEXT);
519 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
520 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
521 mode_sequence.insert(0, "+");
523 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
525 unsigned char modechar = *letter;
530 * For + and - mode characters, we don't just stick the character into the output sequence.
531 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
532 * appearing in the output sequence, we store a flag which says there was a state change,
533 * which is set on any + or -, however, the + or - that we finish on is only appended to
534 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
537 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
538 * however, will allow the + if it is the first item in the sequence, regardless.
540 if ((!adding) || (!output_sequence.length()))
543 if (!output_sequence.length())
544 last_successful_state_change = false;
548 if ((adding) || (!output_sequence.length()))
551 if (!output_sequence.length())
552 last_successful_state_change = true;
558 * Watch carefully for the sleight of hand trick.
559 * 65 is the ascii value of 'A'. We take this from
560 * the char we're looking at to get a number between
561 * 1 and 127. We then logic-or it to get the hashed
562 * position, dependent on wether its a channel or
563 * a user mode. This is a little stranger, but a lot
564 * faster, than using a map of pairs.
566 handler_id = (modechar - 65) | mask;
568 if (modehandlers[handler_id])
572 if (modehandlers[handler_id]->GetModeType() == type)
576 if (modehandlers[handler_id]->GetNumParams(adding))
578 /* This mode expects a parameter, do we have any parameters left in our list to use? */
579 if (parameter_counter < parameters.size())
581 parameter = parameters[parameter_counter++];
584 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
589 /* No parameter, continue to the next mode */
590 modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
594 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
598 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
601 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
604 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
606 /* Check access to this mode character */
607 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
609 char needed = modehandlers[handler_id]->GetNeededPrefix();
610 ModeHandler* prefixmode = FindPrefix(needed);
612 /* If the mode defined by the handler is not '\0', but the handler for it
613 * cannot be found, they probably dont have the right module loaded to implement
614 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
615 * Revert to checking against the minimum core prefix, '%' or '@'.
617 if (needed && !prefixmode)
618 prefixmode = ServerInstance->Config->AllowHalfop ? FindPrefix('%') : FindPrefix('@');
620 unsigned int neededrank = prefixmode->GetPrefixRank();
621 /* Compare our rank on the channel against the rank of the required prefix,
622 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
623 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
624 * first, so we don't need to iterate, we just look up the first instead.
626 std::string modestring = targetchannel->GetAllPrefixChars(user);
627 char ml = (modestring.empty() ? '\0' : modestring[0]);
628 ModeHandler* ourmode = FindPrefix(ml);
629 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
632 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
633 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
639 bool had_parameter = !parameter.empty();
641 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
643 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
648 /* A module whacked the parameter completely, and there was one. abort. */
649 if ((had_parameter) && (parameter.empty()))
659 /* If it's disabled, they have to be an oper.
661 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
663 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
665 type == MODETYPE_CHANNEL ? "channel" : "user",
666 modehandlers[handler_id]->GetModeChar());
670 /* It's an oper only mode, check if theyre an oper. If they arent,
671 * eat any parameter that came with the mode, and continue to next
673 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
677 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
680 type == MODETYPE_CHANNEL ? "channel" : "user",
681 modehandlers[handler_id]->GetModeChar());
685 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
687 type == MODETYPE_CHANNEL ? "channel" : "user",
688 modehandlers[handler_id]->GetModeChar());
693 /* Call the handler for the mode */
694 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
696 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
698 /* The handler nuked the parameter and they are supposed to have one.
699 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
700 * so we bail to the next mode character.
705 if (ma == MODEACTION_ALLOW)
707 /* We're about to output a valid mode letter - was there previously a pending state-change? */
710 if (adding != last_successful_state_change)
711 output_sequence.append(adding ? "+" : "-");
712 last_successful_state_change = adding;
715 /* Add the mode letter */
716 output_sequence.push_back(modechar);
718 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
720 /* Is there a valid parameter for this mode? If so add it to the parameter list */
721 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
723 parameter_list << " " << parameter;
724 LastParseParams.push_back(parameter);
725 LastParseTranslate.push_back(modehandlers[handler_id]->GetTranslateType());
727 /* Does this mode have a prefix? */
728 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
730 User* user_to_prefix = ServerInstance->FindNick(parameter);
732 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
733 modehandlers[handler_id]->GetPrefixRank(), adding);
737 /* Call all the AfterMode events in the mode watchers for this mode */
738 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
739 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
741 /* Reset the state change flag */
742 state_change = false;
744 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
745 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
747 /* We cant have a mode sequence this long */
748 letter = mode_sequence.end() - 1;
756 /* No mode handler? Unknown mode character then. */
757 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
763 /* Was there at least one valid mode in the sequence? */
764 if (!output_sequence.empty())
766 LastParseParams[0] = output_sequence;
769 if (type == MODETYPE_CHANNEL)
771 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
772 this->LastParse = targetchannel->name;
776 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
777 this->LastParse = targetuser->nick;
782 if (type == MODETYPE_CHANNEL)
784 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
785 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
786 this->LastParse = targetchannel->name;
790 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
791 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
792 this->LastParse = targetuser->nick;
796 LastParse.append(" ");
797 LastParse.append(output_sequence);
798 LastParse.append(parameter_list.str());
803 const std::string& ModeParser::GetLastParse()
808 void ModeParser::CleanMask(std::string &mask)
810 std::string::size_type pos_of_pling = mask.find_first_of('!');
811 std::string::size_type pos_of_at = mask.find_first_of('@');
812 std::string::size_type pos_of_dot = mask.find_first_of('.');
813 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
815 if (mask.length() >= 2 && mask[1] == ':')
816 return; // if it's an extban, don't even try guess how it needs to be formed.
818 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
820 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
821 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
823 /* It has no '.' in it, it must be a nick. */
828 /* Got a dot in it? Has to be a host */
829 mask = "*!*@" + mask;
832 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
834 /* Has an @ but no !, its a user@host */
837 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
839 /* Has a ! but no @, it must be a nick!ident */
844 bool ModeParser::AddMode(ModeHandler* mh)
846 unsigned char mask = 0;
847 unsigned char pos = 0;
849 /* Yes, i know, this might let people declare modes like '_' or '^'.
850 * If they do that, thats their problem, and if i ever EVER see an
851 * official InspIRCd developer do that, i'll beat them with a paddle!
853 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
856 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
857 * A mode prefix of ':' will fuck up both server to server, and client to server.
858 * A mode prefix of '#' will mess up /whois and /privmsg
860 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
863 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
864 pos = (mh->GetModeChar()-65) | mask;
866 if (modehandlers[pos])
869 modehandlers[pos] = mh;
873 bool ModeParser::DelMode(ModeHandler* mh)
875 unsigned char mask = 0;
876 unsigned char pos = 0;
878 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
881 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
882 pos = (mh->GetModeChar()-65) | mask;
884 if (!modehandlers[pos])
887 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
888 * To stack here we have to make the algorithm slower. Discuss.
890 switch (mh->GetModeType())
893 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
895 mh->RemoveMode(i->second);
898 case MODETYPE_CHANNEL:
899 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
901 mh->RemoveMode(i->second);
906 modehandlers[pos] = NULL;
911 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
913 unsigned char mask = 0;
914 unsigned char pos = 0;
916 if ((modeletter < 'A') || (modeletter > 'z'))
919 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
920 pos = (modeletter-65) | mask;
922 return modehandlers[pos];
925 std::string ModeParser::UserModeList()
930 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
932 unsigned char pos = (mode-65) | MASK_USER;
934 if (modehandlers[pos])
935 modestr[pointer++] = mode;
937 modestr[pointer++] = 0;
941 std::string ModeParser::ChannelModeList()
946 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
948 unsigned char pos = (mode-65) | MASK_CHANNEL;
950 if (modehandlers[pos])
951 modestr[pointer++] = mode;
953 modestr[pointer++] = 0;
957 std::string ModeParser::ParaModeList()
962 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
964 unsigned char pos = (mode-65) | MASK_CHANNEL;
966 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
967 modestr[pointer++] = mode;
969 modestr[pointer++] = 0;
973 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
975 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
977 unsigned char pos = (mode-65) | MASK_CHANNEL;
979 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
981 return modehandlers[pos];
987 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
992 if (!channel || !user)
995 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
997 unsigned char pos = (mode-65) | MASK_CHANNEL;
998 ModeHandler* mh = modehandlers[pos];
999 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
1002 ret = mh->ModeSet(NULL, user, channel, user->nick);
1003 if ((ret.first) && (ret.second == user->nick))
1008 pars.append(user->nick);
1010 types.push_back(mh->GetModeChar());
1021 std::string ModeParser::GiveModeList(ModeMasks m)
1023 std::string type1; /* Listmodes EXCEPT those with a prefix */
1024 std::string type2; /* Modes that take a param when adding or removing */
1025 std::string type3; /* Modes that only take a param when adding */
1026 std::string type4; /* Modes that dont take a param */
1028 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1030 unsigned char pos = (mode-65) | m;
1031 /* One parameter when adding */
1032 if (modehandlers[pos])
1034 if (modehandlers[pos]->GetNumParams(true))
1036 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1038 type1 += modehandlers[pos]->GetModeChar();
1042 /* ... and one parameter when removing */
1043 if (modehandlers[pos]->GetNumParams(false))
1045 /* But not a list mode */
1046 if (!modehandlers[pos]->GetPrefix())
1048 type2 += modehandlers[pos]->GetModeChar();
1053 /* No parameters when removing */
1054 type3 += modehandlers[pos]->GetModeChar();
1060 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 unsigned char pos = (mode-65) | MASK_CHANNEL;
1084 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1086 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1087 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1091 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1093 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1095 mletters = mletters + n->first;
1096 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1099 return "(" + mprefixes + ")" + mletters;
1102 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1104 unsigned char mask = 0;
1105 unsigned char pos = 0;
1110 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1113 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1114 pos = (mw->GetModeChar()-65) | mask;
1116 modewatchers[pos].push_back(mw);
1121 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1123 unsigned char mask = 0;
1124 unsigned char pos = 0;
1129 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1132 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1133 pos = (mw->GetModeChar()-65) | mask;
1135 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1137 if (a == modewatchers[pos].end())
1142 modewatchers[pos].erase(a);
1147 /** This default implementation can remove simple user modes
1149 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1151 char moderemove[MAXBUF];
1152 std::vector<std::string> parameters;
1154 if (user->IsModeSet(this->GetModeChar()))
1158 stack->Push(this->GetModeChar());
1162 sprintf(moderemove,"-%c",this->GetModeChar());
1163 parameters.push_back(user->nick);
1164 parameters.push_back(moderemove);
1165 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, true);
1170 /** This default implementation can remove simple channel modes
1173 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1175 char moderemove[MAXBUF];
1176 std::vector<std::string> parameters;
1178 if (channel->IsModeSet(this->GetModeChar()))
1182 stack->Push(this->GetModeChar());
1186 sprintf(moderemove,"-%c",this->GetModeChar());
1187 parameters.push_back(channel->name);
1188 parameters.push_back(moderemove);
1189 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1194 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1196 ModeHandler* modes[] =
1198 new ModeChannelSecret(Instance),
1199 new ModeChannelPrivate(Instance),
1200 new ModeChannelModerated(Instance),
1201 new ModeChannelTopicOps(Instance),
1202 new ModeChannelNoExternal(Instance),
1203 new ModeChannelInviteOnly(Instance),
1204 new ModeChannelKey(Instance),
1205 new ModeChannelLimit(Instance),
1206 new ModeChannelBan(Instance),
1207 new ModeChannelOp(Instance),
1208 new ModeChannelHalfOp(Instance),
1209 new ModeChannelVoice(Instance),
1210 new ModeUserWallops(Instance),
1211 new ModeUserInvisible(Instance),
1212 new ModeUserOperator(Instance),
1213 new ModeUserServerNoticeMask(Instance),
1217 /* Clear mode handler list */
1218 memset(modehandlers, 0, sizeof(modehandlers));
1220 /* Last parse string */
1223 /* Initialise the RFC mode letters */
1224 for (int index = 0; modes[index]; index++)
1225 this->AddMode(modes[index]);
1228 memset(&sent, 0, sizeof(sent));