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 * ---------------------------------------------------
14 /* $Core: libIRCDmode */
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 /* +s (server notices) */
47 #include "modes/umode_s.h"
48 /* +w (see wallops) */
49 #include "modes/umode_w.h"
51 #include "modes/umode_i.h"
53 #include "modes/umode_o.h"
54 /* +n (notice mask - our implementation of snomasks) */
55 #include "modes/umode_n.h"
57 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired)
58 : 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)
62 ModeHandler::~ModeHandler()
66 bool ModeHandler::IsListMode()
71 char ModeHandler::GetNeededPrefix()
76 void ModeHandler::SetNeededPrefix(char needsprefix)
78 prefixneeded = needsprefix;
81 unsigned int ModeHandler::GetPrefixRank()
86 unsigned int ModeHandler::GetCount()
91 void ModeHandler::ChangeCount(int modifier)
94 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
97 ModeType ModeHandler::GetModeType()
102 bool ModeHandler::NeedsOper()
107 char ModeHandler::GetPrefix()
112 int ModeHandler::GetNumParams(bool adding)
114 return adding ? n_params_on : n_params_off;
117 char ModeHandler::GetModeChar()
122 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
124 return MODEACTION_DENY;
127 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
131 return std::make_pair(dest->IsModeSet(this->mode), "");
135 return std::make_pair(channel->IsModeSet(this->mode), "");
139 void ModeHandler::DisplayList(User*, Channel*)
143 void ModeHandler::DisplayEmptyList(User*, Channel*)
147 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
149 return (ours < theirs);
152 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
156 SimpleUserModeHandler::~SimpleUserModeHandler()
160 SimpleChannelModeHandler::~SimpleChannelModeHandler()
164 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
168 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
170 /* Only opers can change other users modes */
172 return MODEACTION_DENY;
176 if (!dest->IsModeSet(this->GetModeChar()))
178 dest->SetMode(this->GetModeChar(),true);
179 return MODEACTION_ALLOW;
184 if (dest->IsModeSet(this->GetModeChar()))
186 dest->SetMode(this->GetModeChar(),false);
187 return MODEACTION_ALLOW;
191 return MODEACTION_DENY;
195 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
199 if (!channel->IsModeSet(this->GetModeChar()))
201 channel->SetMode(this->GetModeChar(),true);
202 return MODEACTION_ALLOW;
207 if (channel->IsModeSet(this->GetModeChar()))
209 channel->SetMode(this->GetModeChar(),false);
210 return MODEACTION_ALLOW;
214 return MODEACTION_DENY;
217 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
221 ModeWatcher::~ModeWatcher()
225 char ModeWatcher::GetModeChar()
230 ModeType ModeWatcher::GetModeType()
235 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
240 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
244 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
247 if ((!user) || (!dest) || (!chan) || (!*dest))
251 d = ServerInstance->FindNick(dest);
254 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
260 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
265 UCListIter n = d->chans.find(chan);
266 if (n != d->chans.end())
268 if (n->second & MASK)
272 n->second = n->second | MASK;
276 n->first->AddOppedUser(d);
279 n->first->AddHalfoppedUser(d);
282 n->first->AddVoicedUser(d);
285 return d->nick.c_str();
290 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
295 UCListIter n = d->chans.find(chan);
296 if (n != d->chans.end())
298 if ((n->second & MASK) == 0)
306 n->first->DelOppedUser(d);
309 n->first->DelHalfoppedUser(d);
312 n->first->DelVoicedUser(d);
315 return d->nick.c_str();
320 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
324 /* Display channel's current mode string */
325 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
326 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
331 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
333 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
337 if ((targetuser == user) || (IS_OPER(user)))
339 /* Display user's current mode string */
340 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
341 if (IS_OPER(targetuser))
342 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
347 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
352 /* No such nick/channel */
353 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
357 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
359 std::string target = parameters[0];
360 ModeType type = MODETYPE_USER;
361 unsigned char mask = 0;
362 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
363 User* targetuser = ServerInstance->FindNick(parameters[0]);
367 /* Special case for displaying the list for listmodes,
368 * e.g. MODE #chan b, or MODE #chan +b without a parameter
370 if ((targetchannel) && (parameters.size() == 2))
372 const char* mode = parameters[1].c_str();
373 int nonlistmodes_found = 0;
379 while (mode && *mode)
381 unsigned char mletter = *mode;
389 /* Ensure the user doesnt request the same mode twice,
390 * so they cant flood themselves off out of idiocy.
392 if (sent[mletter] != seq)
402 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
405 if ((mh) && (mh->IsListMode()))
408 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
409 if (MOD_RESULT == ACR_DENY)
417 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
419 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++);
420 mh->DisplayEmptyList(user, targetchannel);
425 /** See below for a description of what craq this is :D
427 unsigned char handler_id = (*mode - 65) | mask;
429 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
431 std::string dummyparam;
433 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
438 mh->DisplayList(user, targetchannel);
441 nonlistmodes_found++;
446 /* We didnt have any modes that were non-list, we can return here */
447 if (!nonlistmodes_found)
451 if (parameters.size() == 1)
453 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
455 else if (parameters.size() > 1)
457 bool SkipAccessChecks = false;
461 type = MODETYPE_CHANNEL;
464 /* Extra security checks on channel modes
465 * (e.g. are they a (half)op?
468 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
470 /* We don't have halfop */
472 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
473 if (MOD_RESULT == ACR_DENY)
475 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
480 type = MODETYPE_USER;
482 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
484 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
490 /* No such nick/channel */
491 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
495 std::string mode_sequence = parameters[1];
496 std::string parameter;
497 std::ostringstream parameter_list;
498 std::string output_sequence;
499 bool adding = true, state_change = false;
500 unsigned char handler_id = 0;
501 unsigned int parameter_counter = 2; /* Index of first parameter */
502 unsigned int parameter_count = 0;
503 bool last_successful_state_change = false;
505 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
506 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
507 mode_sequence.insert(0, "+");
509 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
511 unsigned char modechar = *letter;
516 * For + and - mode characters, we don't just stick the character into the output sequence.
517 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
518 * appearing in the output sequence, we store a flag which says there was a state change,
519 * which is set on any + or -, however, the + or - that we finish on is only appended to
520 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
523 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
524 * however, will allow the + if it is the first item in the sequence, regardless.
526 if ((!adding) || (!output_sequence.length()))
529 if (!output_sequence.length())
530 last_successful_state_change = false;
534 if ((adding) || (!output_sequence.length()))
537 if (!output_sequence.length())
538 last_successful_state_change = true;
544 * Watch carefully for the sleight of hand trick.
545 * 65 is the ascii value of 'A'. We take this from
546 * the char we're looking at to get a number between
547 * 1 and 127. We then logic-or it to get the hashed
548 * position, dependent on wether its a channel or
549 * a user mode. This is a little stranger, but a lot
550 * faster, than using a map of pairs.
552 handler_id = (modechar - 65) | mask;
554 if (modehandlers[handler_id])
558 if (modehandlers[handler_id]->GetModeType() == type)
562 if (modehandlers[handler_id]->GetNumParams(adding))
564 /* This mode expects a parameter, do we have any parameters left in our list to use? */
565 if (parameter_counter < parameters.size())
567 parameter = parameters[parameter_counter++];
570 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
575 /* No parameter, continue to the next mode */
579 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
583 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
586 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
589 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
591 /* Check access to this mode character */
592 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
594 char needed = modehandlers[handler_id]->GetNeededPrefix();
595 ModeHandler* prefixmode = FindPrefix(needed);
597 /* If the mode defined by the handler is not '\0', but the handler for it
598 * cannot be found, they probably dont have the right module loaded to implement
599 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
600 * Revert to checking against the minimum core prefix, '%'.
602 if (needed && !prefixmode)
603 prefixmode = FindPrefix('%');
605 unsigned int neededrank = prefixmode->GetPrefixRank();
606 /* Compare our rank on the channel against the rank of the required prefix,
607 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
608 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
609 * first, so we don't need to iterate, we just look up the first instead.
611 std::string modestring = targetchannel->GetAllPrefixChars(user);
612 char ml = (modestring.empty() ? '\0' : modestring[0]);
613 ModeHandler* ourmode = FindPrefix(ml);
614 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
617 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
618 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
624 bool had_parameter = !parameter.empty();
626 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
628 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
633 /* A module whacked the parameter completely, and there was one. abort. */
634 if ((had_parameter) && (parameter.empty()))
644 /* If it's disabled, they have to be an oper.
646 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
648 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
650 type == MODETYPE_CHANNEL ? "channel" : "user",
651 modehandlers[handler_id]->GetModeChar());
655 /* It's an oper only mode, check if theyre an oper. If they arent,
656 * eat any parameter that came with the mode, and continue to next
658 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
662 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
665 type == MODETYPE_CHANNEL ? "channel" : "user",
666 modehandlers[handler_id]->GetModeChar());
670 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
672 type == MODETYPE_CHANNEL ? "channel" : "user",
673 modehandlers[handler_id]->GetModeChar());
678 /* Call the handler for the mode */
679 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
681 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
683 /* The handler nuked the parameter and they are supposed to have one.
684 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
685 * so we bail to the next mode character.
690 if (ma == MODEACTION_ALLOW)
692 /* We're about to output a valid mode letter - was there previously a pending state-change? */
695 if (adding != last_successful_state_change)
696 output_sequence.append(adding ? "+" : "-");
697 last_successful_state_change = adding;
700 /* Add the mode letter */
701 output_sequence.push_back(modechar);
703 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
705 /* Is there a valid parameter for this mode? If so add it to the parameter list */
706 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
708 parameter_list << " " << parameter;
710 /* Does this mode have a prefix? */
711 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
713 User* user_to_prefix = ServerInstance->FindNick(parameter);
715 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
716 modehandlers[handler_id]->GetPrefixRank(), adding);
720 /* Call all the AfterMode events in the mode watchers for this mode */
721 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
722 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
724 /* Reset the state change flag */
725 state_change = false;
727 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
728 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
730 /* We cant have a mode sequence this long */
731 letter = mode_sequence.end() - 1;
739 /* No mode handler? Unknown mode character then. */
740 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
746 /* Was there at least one valid mode in the sequence? */
747 if (!output_sequence.empty())
751 if (type == MODETYPE_CHANNEL)
753 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
754 this->LastParse = targetchannel->name;
758 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
759 this->LastParse = targetuser->nick;
764 if (type == MODETYPE_CHANNEL)
766 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
767 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
768 this->LastParse = targetchannel->name;
772 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
773 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
774 this->LastParse = targetuser->nick;
778 LastParse.append(" ");
779 LastParse.append(output_sequence);
780 LastParse.append(parameter_list.str());
785 const std::string& ModeParser::GetLastParse()
790 void ModeParser::CleanMask(std::string &mask)
792 std::string::size_type pos_of_pling = mask.find_first_of('!');
793 std::string::size_type pos_of_at = mask.find_first_of('@');
794 std::string::size_type pos_of_dot = mask.find_first_of('.');
795 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
797 if (mask.length() >= 2 && mask[1] == ':')
798 return; // if it's an extban, don't even try guess how it needs to be formed.
800 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
802 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
803 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
805 /* It has no '.' in it, it must be a nick. */
810 /* Got a dot in it? Has to be a host */
811 mask = "*!*@" + mask;
814 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
816 /* Has an @ but no !, its a user@host */
819 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
821 /* Has a ! but no @, it must be a nick!ident */
826 bool ModeParser::AddMode(ModeHandler* mh)
828 unsigned char mask = 0;
829 unsigned char pos = 0;
831 /* Yes, i know, this might let people declare modes like '_' or '^'.
832 * If they do that, thats their problem, and if i ever EVER see an
833 * official InspIRCd developer do that, i'll beat them with a paddle!
835 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
838 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
839 * A mode prefix of ':' will fuck up both server to server, and client to server.
840 * A mode prefix of '#' will mess up /whois and /privmsg
842 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
845 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
846 pos = (mh->GetModeChar()-65) | mask;
848 if (modehandlers[pos])
851 modehandlers[pos] = mh;
855 bool ModeParser::DelMode(ModeHandler* mh)
857 unsigned char mask = 0;
858 unsigned char pos = 0;
860 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
863 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
864 pos = (mh->GetModeChar()-65) | mask;
866 if (!modehandlers[pos])
869 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
870 * To stack here we have to make the algorithm slower. Discuss.
872 switch (mh->GetModeType())
875 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
877 mh->RemoveMode(i->second);
880 case MODETYPE_CHANNEL:
881 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
883 mh->RemoveMode(i->second);
888 modehandlers[pos] = NULL;
893 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
895 unsigned char mask = 0;
896 unsigned char pos = 0;
898 if ((modeletter < 'A') || (modeletter > 'z'))
901 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
902 pos = (modeletter-65) | mask;
904 return modehandlers[pos];
907 std::string ModeParser::UserModeList()
912 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
914 unsigned char pos = (mode-65) | MASK_USER;
916 if (modehandlers[pos])
917 modestr[pointer++] = mode;
919 modestr[pointer++] = 0;
923 std::string ModeParser::ChannelModeList()
928 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
930 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
933 unsigned char pos = (mode-65) | MASK_CHANNEL;
935 if (modehandlers[pos])
936 modestr[pointer++] = mode;
938 modestr[pointer++] = 0;
942 std::string ModeParser::ParaModeList()
947 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
949 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
952 unsigned char pos = (mode-65) | MASK_CHANNEL;
954 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
955 modestr[pointer++] = mode;
957 modestr[pointer++] = 0;
961 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
963 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
965 unsigned char pos = (mode-65) | MASK_CHANNEL;
967 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
969 return modehandlers[pos];
975 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
980 if (!channel || !user)
983 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
985 unsigned char pos = (mode-65) | MASK_CHANNEL;
986 ModeHandler* mh = modehandlers[pos];
987 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
990 ret = mh->ModeSet(NULL, user, channel, user->nick);
991 if ((ret.first) && (ret.second == user->nick))
996 pars.append(user->nick);
998 types.push_back(mh->GetModeChar());
1009 std::string ModeParser::ChanModes()
1011 std::string type1; /* Listmodes EXCEPT those with a prefix */
1012 std::string type2; /* Modes that take a param when adding or removing */
1013 std::string type3; /* Modes that only take a param when adding */
1014 std::string type4; /* Modes that dont take a param */
1016 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1018 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1021 unsigned char pos = (mode-65) | MASK_CHANNEL;
1022 /* One parameter when adding */
1023 if (modehandlers[pos])
1025 if (modehandlers[pos]->GetNumParams(true))
1027 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1029 type1 += modehandlers[pos]->GetModeChar();
1033 /* ... and one parameter when removing */
1034 if (modehandlers[pos]->GetNumParams(false))
1036 /* But not a list mode */
1037 if (!modehandlers[pos]->GetPrefix())
1039 type2 += modehandlers[pos]->GetModeChar();
1044 /* No parameters when removing */
1045 type3 += modehandlers[pos]->GetModeChar();
1051 type4 += modehandlers[pos]->GetModeChar();
1057 return type1 + "," + type2 + "," + type3 + "," + type4;
1060 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1062 return one.second > two.second;
1065 std::string ModeParser::BuildPrefixes()
1067 std::string mletters;
1068 std::string mprefixes;
1070 std::map<char,char> prefix_to_mode;
1072 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1074 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1077 unsigned char pos = (mode-65) | MASK_CHANNEL;
1079 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1081 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1082 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1086 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1088 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1090 mletters = mletters + n->first;
1091 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1094 return "(" + mprefixes + ")" + mletters;
1097 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1099 unsigned char mask = 0;
1100 unsigned char pos = 0;
1105 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1108 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1109 pos = (mw->GetModeChar()-65) | mask;
1111 modewatchers[pos].push_back(mw);
1116 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1118 unsigned char mask = 0;
1119 unsigned char pos = 0;
1124 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1127 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1128 pos = (mw->GetModeChar()-65) | mask;
1130 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1132 if (a == modewatchers[pos].end())
1137 modewatchers[pos].erase(a);
1142 /** This default implementation can remove simple user modes
1144 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1146 char moderemove[MAXBUF];
1147 std::vector<std::string> parameters;
1149 if (user->IsModeSet(this->GetModeChar()))
1153 stack->Push(this->GetModeChar());
1157 sprintf(moderemove,"-%c",this->GetModeChar());
1158 parameters.push_back(user->nick);
1159 parameters.push_back(moderemove);
1160 ServerInstance->Parser->CallHandler("MODE", parameters, user);
1165 /** This default implementation can remove simple channel modes
1168 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1170 char moderemove[MAXBUF];
1171 std::vector<std::string> parameters;
1173 if (channel->IsModeSet(this->GetModeChar()))
1177 stack->Push(this->GetModeChar());
1181 sprintf(moderemove,"-%c",this->GetModeChar());
1182 parameters.push_back(channel->name);
1183 parameters.push_back(moderemove);
1184 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1189 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1191 ModeHandler* modes[] =
1193 new ModeChannelSecret(Instance),
1194 new ModeChannelPrivate(Instance),
1195 new ModeChannelModerated(Instance),
1196 new ModeChannelTopicOps(Instance),
1197 new ModeChannelNoExternal(Instance),
1198 new ModeChannelInviteOnly(Instance),
1199 new ModeChannelKey(Instance),
1200 new ModeChannelLimit(Instance),
1201 new ModeChannelBan(Instance),
1202 new ModeChannelOp(Instance),
1203 new ModeChannelHalfOp(Instance),
1204 new ModeChannelVoice(Instance),
1205 new ModeUserServerNotice(Instance),
1206 new ModeUserWallops(Instance),
1207 new ModeUserInvisible(Instance),
1208 new ModeUserOperator(Instance),
1209 new ModeUserServerNoticeMask(Instance),
1213 /* Clear mode handler list */
1214 memset(modehandlers, 0, sizeof(modehandlers));
1216 /* Last parse string */
1219 /* Initialise the RFC mode letters */
1220 for (int index = 0; modes[index]; index++)
1221 this->AddMode(modes[index]);
1224 memset(&sent, 0, 256);