1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
15 /* $ExtraDeps: $(RELCPPFILES) */
16 /* $ExtraObjects: modes/modeclasses.a */
17 /* $ExtraBuild: @${MAKE} -C "modes" DIRNAME="src/modes" CC="$(CC)" $(MAKEARGS) CPPFILES="$(CPPFILES)" */
20 #include "inspstring.h"
23 #include "modes/cmode_s.h"
25 #include "modes/cmode_p.h"
27 #include "modes/cmode_b.h"
29 #include "modes/cmode_m.h"
30 /* +t (only (half) ops can change topic) */
31 #include "modes/cmode_t.h"
32 /* +n (no external messages) */
33 #include "modes/cmode_n.h"
34 /* +i (invite only) */
35 #include "modes/cmode_i.h"
36 /* +k (keyed channel) */
37 #include "modes/cmode_k.h"
38 /* +l (channel user limit) */
39 #include "modes/cmode_l.h"
41 #include "modes/cmode_o.h"
42 /* +h (channel halfop) */
43 #include "modes/cmode_h.h"
44 /* +v (channel voice) */
45 #include "modes/cmode_v.h"
46 /* +w (see wallops) */
47 #include "modes/umode_w.h"
49 #include "modes/umode_i.h"
51 #include "modes/umode_o.h"
52 /* +s (server notice masks) */
53 #include "modes/umode_s.h"
55 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired, TranslateType translate)
56 : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), m_paramtype(translate), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
60 ModeHandler::~ModeHandler()
64 bool ModeHandler::IsListMode()
69 char ModeHandler::GetNeededPrefix()
74 void ModeHandler::SetNeededPrefix(char needsprefix)
76 prefixneeded = needsprefix;
79 unsigned int ModeHandler::GetPrefixRank()
84 unsigned int ModeHandler::GetCount()
89 void ModeHandler::ChangeCount(int modifier)
92 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
95 ModeType ModeHandler::GetModeType()
100 TranslateType ModeHandler::GetTranslateType()
105 bool ModeHandler::NeedsOper()
110 char ModeHandler::GetPrefix()
115 int ModeHandler::GetNumParams(bool adding)
117 return adding ? n_params_on : n_params_off;
120 char ModeHandler::GetModeChar()
125 std::string ModeHandler::GetUserParameter(User* user)
130 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
132 return MODEACTION_DENY;
135 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
139 return std::make_pair(dest->IsModeSet(this->mode), "");
143 return std::make_pair(channel->IsModeSet(this->mode), "");
147 void ModeHandler::DisplayList(User*, Channel*)
151 void ModeHandler::DisplayEmptyList(User*, Channel*)
155 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
159 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
161 return (ours < theirs);
164 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
168 SimpleUserModeHandler::~SimpleUserModeHandler()
172 SimpleChannelModeHandler::~SimpleChannelModeHandler()
176 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
180 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
184 if (!dest->IsModeSet(this->GetModeChar()))
186 dest->SetMode(this->GetModeChar(),true);
187 return MODEACTION_ALLOW;
192 if (dest->IsModeSet(this->GetModeChar()))
194 dest->SetMode(this->GetModeChar(),false);
195 return MODEACTION_ALLOW;
199 return MODEACTION_DENY;
203 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
207 if (!channel->IsModeSet(this->GetModeChar()))
209 channel->SetMode(this->GetModeChar(),true);
210 return MODEACTION_ALLOW;
215 if (channel->IsModeSet(this->GetModeChar()))
217 channel->SetMode(this->GetModeChar(),false);
218 return MODEACTION_ALLOW;
222 return MODEACTION_DENY;
225 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
229 ModeWatcher::~ModeWatcher()
233 char ModeWatcher::GetModeChar()
238 ModeType ModeWatcher::GetModeType()
243 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
248 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
252 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
255 if ((!user) || (!dest) || (!chan) || (!*dest))
259 d = ServerInstance->FindNick(dest);
262 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
268 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
273 UCListIter n = d->chans.find(chan);
274 if (n != d->chans.end())
276 if (n->second & MASK)
280 n->second = n->second | MASK;
284 n->first->AddOppedUser(d);
287 n->first->AddHalfoppedUser(d);
290 n->first->AddVoicedUser(d);
293 return d->nick.c_str();
298 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
303 UCListIter n = d->chans.find(chan);
304 if (n != d->chans.end())
306 if ((n->second & MASK) == 0)
314 n->first->DelOppedUser(d);
317 n->first->DelHalfoppedUser(d);
320 n->first->DelVoicedUser(d);
323 return d->nick.c_str();
328 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
332 /* Display channel's current mode string */
333 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
334 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
339 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
341 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
345 if (targetuser == user || user->HasPrivPermission("users/auspex"))
347 /* Display user's current mode string */
348 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
349 if (IS_OPER(targetuser))
350 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
355 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
360 /* No such nick/channel */
361 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
365 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
367 std::string target = parameters[0];
368 ModeType type = MODETYPE_USER;
369 unsigned char mask = 0;
370 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
371 User* targetuser = ServerInstance->FindNick(parameters[0]);
374 LastParseParams.clear();
375 LastParseTranslate.clear();
377 /* Special case for displaying the list for listmodes,
378 * e.g. MODE #chan b, or MODE #chan +b without a parameter
380 if ((targetchannel) && (parameters.size() == 2))
382 const char* mode = parameters[1].c_str();
383 int nonlistmodes_found = 0;
389 while (mode && *mode)
391 unsigned char mletter = *mode;
399 /* Ensure the user doesnt request the same mode twice,
400 * so they cant flood themselves off out of idiocy.
402 if (sent[mletter] != seq)
412 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
415 if ((mh) && (mh->IsListMode()))
418 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
419 if (MOD_RESULT == ACR_DENY)
425 if (!user->HasPrivPermission("channels/auspex"))
427 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
429 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",user->nick.c_str(), targetchannel->name.c_str(), *mode++);
430 mh->DisplayEmptyList(user, targetchannel);
435 /** See below for a description of what craq this is :D
437 unsigned char handler_id = (*mode - 65) | mask;
439 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
441 std::string dummyparam;
443 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
448 mh->DisplayList(user, targetchannel);
451 nonlistmodes_found++;
456 /* We didnt have any modes that were non-list, we can return here */
457 if (!nonlistmodes_found)
461 if (parameters.size() == 1)
463 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
465 else if (parameters.size() > 1)
467 bool SkipAccessChecks = false;
471 type = MODETYPE_CHANNEL;
474 /* Extra security checks on channel modes
475 * (e.g. are they a (half)op?
478 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
480 /* Make modes that are being changed visible to OnAccessCheck */
481 LastParse = parameters[1];
482 /* We don't have halfop */
484 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
486 if (MOD_RESULT == ACR_DENY)
488 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
493 type = MODETYPE_USER;
495 if (user != targetuser && IS_LOCAL(user) && !ServerInstance->ULine(user->server))
497 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
503 /* No such nick/channel */
504 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
508 std::string mode_sequence = parameters[1];
509 std::string parameter;
510 std::ostringstream parameter_list;
511 std::string output_sequence;
512 bool adding = true, state_change = false;
513 unsigned char handler_id = 0;
514 unsigned int parameter_counter = 2; /* Index of first parameter */
515 unsigned int parameter_count = 0;
516 bool last_successful_state_change = false;
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, '%'.
617 if (needed && !prefixmode)
618 prefixmode = 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())
768 if (type == MODETYPE_CHANNEL)
770 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
771 this->LastParse = targetchannel->name;
775 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
776 this->LastParse = targetuser->nick;
781 LastParseParams.push_front(output_sequence);
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, false);
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));