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 /* +w (see wallops) */
47 #include "modes/umode_w.h"
49 #include "modes/umode_i.h"
51 #include "modes/umode_o.h"
52 /* +n (server notice masks) */
53 #include "modes/umode_n.h"
55 ModeHandler::ModeHandler(InspIRCd* Instance, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired)
56 : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
60 ModeHandler::~ModeHandler()
64 bool ModeHandler::IsListMode()
69 char ModeHandler::GetNeededPrefix()
74 void ModeHandler::SetNeededPrefix(char needsprefix)
76 prefixneeded = needsprefix;
79 unsigned int ModeHandler::GetPrefixRank()
84 unsigned int ModeHandler::GetCount()
89 void ModeHandler::ChangeCount(int modifier)
92 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
95 ModeType ModeHandler::GetModeType()
100 bool ModeHandler::NeedsOper()
105 char ModeHandler::GetPrefix()
110 int ModeHandler::GetNumParams(bool adding)
112 return adding ? n_params_on : n_params_off;
115 char ModeHandler::GetModeChar()
120 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
122 return MODEACTION_DENY;
125 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
129 return std::make_pair(dest->IsModeSet(this->mode), "");
133 return std::make_pair(channel->IsModeSet(this->mode), "");
137 void ModeHandler::DisplayList(User*, Channel*)
141 void ModeHandler::DisplayEmptyList(User*, Channel*)
145 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
147 return (ours < theirs);
150 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
154 SimpleUserModeHandler::~SimpleUserModeHandler()
158 SimpleChannelModeHandler::~SimpleChannelModeHandler()
162 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
166 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
168 /* Only opers can change other users modes */
170 return MODEACTION_DENY;
174 if (!dest->IsModeSet(this->GetModeChar()))
176 dest->SetMode(this->GetModeChar(),true);
177 return MODEACTION_ALLOW;
182 if (dest->IsModeSet(this->GetModeChar()))
184 dest->SetMode(this->GetModeChar(),false);
185 return MODEACTION_ALLOW;
189 return MODEACTION_DENY;
193 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
197 if (!channel->IsModeSet(this->GetModeChar()))
199 channel->SetMode(this->GetModeChar(),true);
200 return MODEACTION_ALLOW;
205 if (channel->IsModeSet(this->GetModeChar()))
207 channel->SetMode(this->GetModeChar(),false);
208 return MODEACTION_ALLOW;
212 return MODEACTION_DENY;
215 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
219 ModeWatcher::~ModeWatcher()
223 char ModeWatcher::GetModeChar()
228 ModeType ModeWatcher::GetModeType()
233 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
238 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
242 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
245 if ((!user) || (!dest) || (!chan) || (!*dest))
249 d = ServerInstance->FindNick(dest);
252 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
258 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
263 UCListIter n = d->chans.find(chan);
264 if (n != d->chans.end())
266 if (n->second & MASK)
270 n->second = n->second | MASK;
274 n->first->AddOppedUser(d);
277 n->first->AddHalfoppedUser(d);
280 n->first->AddVoicedUser(d);
283 return d->nick.c_str();
288 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
293 UCListIter n = d->chans.find(chan);
294 if (n != d->chans.end())
296 if ((n->second & MASK) == 0)
304 n->first->DelOppedUser(d);
307 n->first->DelHalfoppedUser(d);
310 n->first->DelVoicedUser(d);
313 return d->nick.c_str();
318 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
322 /* Display channel's current mode string */
323 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
324 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
329 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
331 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
335 if ((targetuser == user) || (IS_OPER(user)))
337 /* Display user's current mode string */
338 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
339 if (IS_OPER(targetuser))
340 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
345 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
350 /* No such nick/channel */
351 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
355 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
357 std::string target = parameters[0];
358 ModeType type = MODETYPE_USER;
359 unsigned char mask = 0;
360 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
361 User* targetuser = ServerInstance->FindNick(parameters[0]);
365 /* Special case for displaying the list for listmodes,
366 * e.g. MODE #chan b, or MODE #chan +b without a parameter
368 if ((targetchannel) && (parameters.size() == 2))
370 const char* mode = parameters[1].c_str();
371 int nonlistmodes_found = 0;
377 while (mode && *mode)
379 unsigned char mletter = *mode;
387 /* Ensure the user doesnt request the same mode twice,
388 * so they cant flood themselves off out of idiocy.
390 if (sent[mletter] != seq)
400 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
403 if ((mh) && (mh->IsListMode()))
406 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
407 if (MOD_RESULT == ACR_DENY)
415 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
417 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++);
418 mh->DisplayEmptyList(user, targetchannel);
423 /** See below for a description of what craq this is :D
425 unsigned char handler_id = (*mode - 65) | mask;
427 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
429 std::string dummyparam;
431 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
436 mh->DisplayList(user, targetchannel);
439 nonlistmodes_found++;
444 /* We didnt have any modes that were non-list, we can return here */
445 if (!nonlistmodes_found)
449 if (parameters.size() == 1)
451 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
453 else if (parameters.size() > 1)
455 bool SkipAccessChecks = false;
459 type = MODETYPE_CHANNEL;
462 /* Extra security checks on channel modes
463 * (e.g. are they a (half)op?
466 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
468 /* We don't have halfop */
470 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
471 if (MOD_RESULT == ACR_DENY)
473 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
478 type = MODETYPE_USER;
480 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
482 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
488 /* No such nick/channel */
489 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
493 std::string mode_sequence = parameters[1];
494 std::string parameter;
495 std::ostringstream parameter_list;
496 std::string output_sequence;
497 bool adding = true, state_change = false;
498 unsigned char handler_id = 0;
499 unsigned int parameter_counter = 2; /* Index of first parameter */
500 unsigned int parameter_count = 0;
501 bool last_successful_state_change = false;
503 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
504 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
505 mode_sequence.insert(0, "+");
507 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
509 unsigned char modechar = *letter;
514 * For + and - mode characters, we don't just stick the character into the output sequence.
515 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
516 * appearing in the output sequence, we store a flag which says there was a state change,
517 * which is set on any + or -, however, the + or - that we finish on is only appended to
518 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
521 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
522 * however, will allow the + if it is the first item in the sequence, regardless.
524 if ((!adding) || (!output_sequence.length()))
527 if (!output_sequence.length())
528 last_successful_state_change = false;
532 if ((adding) || (!output_sequence.length()))
535 if (!output_sequence.length())
536 last_successful_state_change = true;
542 * Watch carefully for the sleight of hand trick.
543 * 65 is the ascii value of 'A'. We take this from
544 * the char we're looking at to get a number between
545 * 1 and 127. We then logic-or it to get the hashed
546 * position, dependent on wether its a channel or
547 * a user mode. This is a little stranger, but a lot
548 * faster, than using a map of pairs.
550 handler_id = (modechar - 65) | mask;
552 if (modehandlers[handler_id])
556 if (modehandlers[handler_id]->GetModeType() == type)
560 if (modehandlers[handler_id]->GetNumParams(adding))
562 /* This mode expects a parameter, do we have any parameters left in our list to use? */
563 if (parameter_counter < parameters.size())
565 parameter = parameters[parameter_counter++];
568 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
573 /* No parameter, continue to the next mode */
577 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
581 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
584 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
587 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
589 /* Check access to this mode character */
590 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
592 char needed = modehandlers[handler_id]->GetNeededPrefix();
593 ModeHandler* prefixmode = FindPrefix(needed);
595 /* If the mode defined by the handler is not '\0', but the handler for it
596 * cannot be found, they probably dont have the right module loaded to implement
597 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
598 * Revert to checking against the minimum core prefix, '%'.
600 if (needed && !prefixmode)
601 prefixmode = FindPrefix('%');
603 unsigned int neededrank = prefixmode->GetPrefixRank();
604 /* Compare our rank on the channel against the rank of the required prefix,
605 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
606 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
607 * first, so we don't need to iterate, we just look up the first instead.
609 std::string modestring = targetchannel->GetAllPrefixChars(user);
610 char ml = (modestring.empty() ? '\0' : modestring[0]);
611 ModeHandler* ourmode = FindPrefix(ml);
612 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
615 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
616 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
622 bool had_parameter = !parameter.empty();
624 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
626 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
631 /* A module whacked the parameter completely, and there was one. abort. */
632 if ((had_parameter) && (parameter.empty()))
642 /* If it's disabled, they have to be an oper.
644 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
646 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
648 type == MODETYPE_CHANNEL ? "channel" : "user",
649 modehandlers[handler_id]->GetModeChar());
653 /* It's an oper only mode, check if theyre an oper. If they arent,
654 * eat any parameter that came with the mode, and continue to next
656 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
660 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
663 type == MODETYPE_CHANNEL ? "channel" : "user",
664 modehandlers[handler_id]->GetModeChar());
668 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
670 type == MODETYPE_CHANNEL ? "channel" : "user",
671 modehandlers[handler_id]->GetModeChar());
676 /* Call the handler for the mode */
677 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
679 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
681 /* The handler nuked the parameter and they are supposed to have one.
682 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
683 * so we bail to the next mode character.
688 if (ma == MODEACTION_ALLOW)
690 /* We're about to output a valid mode letter - was there previously a pending state-change? */
693 if (adding != last_successful_state_change)
694 output_sequence.append(adding ? "+" : "-");
695 last_successful_state_change = adding;
698 /* Add the mode letter */
699 output_sequence.push_back(modechar);
701 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
703 /* Is there a valid parameter for this mode? If so add it to the parameter list */
704 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
706 parameter_list << " " << parameter;
708 /* Does this mode have a prefix? */
709 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
711 User* user_to_prefix = ServerInstance->FindNick(parameter);
713 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
714 modehandlers[handler_id]->GetPrefixRank(), adding);
718 /* Call all the AfterMode events in the mode watchers for this mode */
719 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
720 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
722 /* Reset the state change flag */
723 state_change = false;
725 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
726 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
728 /* We cant have a mode sequence this long */
729 letter = mode_sequence.end() - 1;
737 /* No mode handler? Unknown mode character then. */
738 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
744 /* Was there at least one valid mode in the sequence? */
745 if (!output_sequence.empty())
749 if (type == MODETYPE_CHANNEL)
751 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
752 this->LastParse = targetchannel->name;
756 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
757 this->LastParse = targetuser->nick;
762 if (type == MODETYPE_CHANNEL)
764 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
765 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
766 this->LastParse = targetchannel->name;
770 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
771 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
772 this->LastParse = targetuser->nick;
776 LastParse.append(" ");
777 LastParse.append(output_sequence);
778 LastParse.append(parameter_list.str());
783 const std::string& ModeParser::GetLastParse()
788 void ModeParser::CleanMask(std::string &mask)
790 std::string::size_type pos_of_pling = mask.find_first_of('!');
791 std::string::size_type pos_of_at = mask.find_first_of('@');
792 std::string::size_type pos_of_dot = mask.find_first_of('.');
793 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
795 if (mask.length() >= 2 && mask[1] == ':')
796 return; // if it's an extban, don't even try guess how it needs to be formed.
798 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
800 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
801 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
803 /* It has no '.' in it, it must be a nick. */
808 /* Got a dot in it? Has to be a host */
809 mask = "*!*@" + mask;
812 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
814 /* Has an @ but no !, its a user@host */
817 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
819 /* Has a ! but no @, it must be a nick!ident */
824 bool ModeParser::AddMode(ModeHandler* mh)
826 unsigned char mask = 0;
827 unsigned char pos = 0;
829 /* Yes, i know, this might let people declare modes like '_' or '^'.
830 * If they do that, thats their problem, and if i ever EVER see an
831 * official InspIRCd developer do that, i'll beat them with a paddle!
833 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
836 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
837 * A mode prefix of ':' will fuck up both server to server, and client to server.
838 * A mode prefix of '#' will mess up /whois and /privmsg
840 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
843 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
844 pos = (mh->GetModeChar()-65) | mask;
846 if (modehandlers[pos])
849 modehandlers[pos] = mh;
853 bool ModeParser::DelMode(ModeHandler* mh)
855 unsigned char mask = 0;
856 unsigned char pos = 0;
858 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
861 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
862 pos = (mh->GetModeChar()-65) | mask;
864 if (!modehandlers[pos])
867 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
868 * To stack here we have to make the algorithm slower. Discuss.
870 switch (mh->GetModeType())
873 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
875 mh->RemoveMode(i->second);
878 case MODETYPE_CHANNEL:
879 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
881 mh->RemoveMode(i->second);
886 modehandlers[pos] = NULL;
891 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
893 unsigned char mask = 0;
894 unsigned char pos = 0;
896 if ((modeletter < 'A') || (modeletter > 'z'))
899 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
900 pos = (modeletter-65) | mask;
902 return modehandlers[pos];
905 std::string ModeParser::UserModeList()
910 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
912 unsigned char pos = (mode-65) | MASK_USER;
914 if (modehandlers[pos])
915 modestr[pointer++] = mode;
917 modestr[pointer++] = 0;
921 std::string ModeParser::ChannelModeList()
926 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
928 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
931 unsigned char pos = (mode-65) | MASK_CHANNEL;
933 if (modehandlers[pos])
934 modestr[pointer++] = mode;
936 modestr[pointer++] = 0;
940 std::string ModeParser::ParaModeList()
945 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
947 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
950 unsigned char pos = (mode-65) | MASK_CHANNEL;
952 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
953 modestr[pointer++] = mode;
955 modestr[pointer++] = 0;
959 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
961 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
963 unsigned char pos = (mode-65) | MASK_CHANNEL;
965 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
967 return modehandlers[pos];
973 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
978 if (!channel || !user)
981 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
983 unsigned char pos = (mode-65) | MASK_CHANNEL;
984 ModeHandler* mh = modehandlers[pos];
985 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
988 ret = mh->ModeSet(NULL, user, channel, user->nick);
989 if ((ret.first) && (ret.second == user->nick))
994 pars.append(user->nick);
996 types.push_back(mh->GetModeChar());
1007 std::string ModeParser::ChanModes()
1009 std::string type1; /* Listmodes EXCEPT those with a prefix */
1010 std::string type2; /* Modes that take a param when adding or removing */
1011 std::string type3; /* Modes that only take a param when adding */
1012 std::string type4; /* Modes that dont take a param */
1014 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1016 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1019 unsigned char pos = (mode-65) | MASK_CHANNEL;
1020 /* One parameter when adding */
1021 if (modehandlers[pos])
1023 if (modehandlers[pos]->GetNumParams(true))
1025 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1027 type1 += modehandlers[pos]->GetModeChar();
1031 /* ... and one parameter when removing */
1032 if (modehandlers[pos]->GetNumParams(false))
1034 /* But not a list mode */
1035 if (!modehandlers[pos]->GetPrefix())
1037 type2 += modehandlers[pos]->GetModeChar();
1042 /* No parameters when removing */
1043 type3 += modehandlers[pos]->GetModeChar();
1049 type4 += modehandlers[pos]->GetModeChar();
1055 return type1 + "," + type2 + "," + type3 + "," + type4;
1058 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1060 return one.second > two.second;
1063 std::string ModeParser::BuildPrefixes()
1065 std::string mletters;
1066 std::string mprefixes;
1068 std::map<char,char> prefix_to_mode;
1070 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1072 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1075 unsigned char pos = (mode-65) | MASK_CHANNEL;
1077 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1079 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1080 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1084 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1086 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1088 mletters = mletters + n->first;
1089 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1092 return "(" + mprefixes + ")" + mletters;
1095 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1097 unsigned char mask = 0;
1098 unsigned char pos = 0;
1103 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1106 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1107 pos = (mw->GetModeChar()-65) | mask;
1109 modewatchers[pos].push_back(mw);
1114 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1116 unsigned char mask = 0;
1117 unsigned char pos = 0;
1122 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1125 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1126 pos = (mw->GetModeChar()-65) | mask;
1128 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1130 if (a == modewatchers[pos].end())
1135 modewatchers[pos].erase(a);
1140 /** This default implementation can remove simple user modes
1142 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1144 char moderemove[MAXBUF];
1145 std::vector<std::string> parameters;
1147 if (user->IsModeSet(this->GetModeChar()))
1151 stack->Push(this->GetModeChar());
1155 sprintf(moderemove,"-%c",this->GetModeChar());
1156 parameters.push_back(user->nick);
1157 parameters.push_back(moderemove);
1158 ServerInstance->Parser->CallHandler("MODE", parameters, user);
1163 /** This default implementation can remove simple channel modes
1166 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1168 char moderemove[MAXBUF];
1169 std::vector<std::string> parameters;
1171 if (channel->IsModeSet(this->GetModeChar()))
1175 stack->Push(this->GetModeChar());
1179 sprintf(moderemove,"-%c",this->GetModeChar());
1180 parameters.push_back(channel->name);
1181 parameters.push_back(moderemove);
1182 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1187 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1189 ModeHandler* modes[] =
1191 new ModeChannelSecret(Instance),
1192 new ModeChannelPrivate(Instance),
1193 new ModeChannelModerated(Instance),
1194 new ModeChannelTopicOps(Instance),
1195 new ModeChannelNoExternal(Instance),
1196 new ModeChannelInviteOnly(Instance),
1197 new ModeChannelKey(Instance),
1198 new ModeChannelLimit(Instance),
1199 new ModeChannelBan(Instance),
1200 new ModeChannelOp(Instance),
1201 new ModeChannelHalfOp(Instance),
1202 new ModeChannelVoice(Instance),
1203 new ModeUserWallops(Instance),
1204 new ModeUserInvisible(Instance),
1205 new ModeUserOperator(Instance),
1206 new ModeUserServerNoticeMask(Instance),
1210 /* Clear mode handler list */
1211 memset(modehandlers, 0, sizeof(modehandlers));
1213 /* Last parse string */
1216 /* Initialise the RFC mode letters */
1217 for (int index = 0; modes[index]; index++)
1218 this->AddMode(modes[index]);
1221 memset(&sent, 0, sizeof(sent));