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)
56 : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired)
60 ModeHandler::~ModeHandler()
64 bool ModeHandler::IsListMode()
69 char ModeHandler::GetNeededPrefix()
74 void ModeHandler::SetNeededPrefix(char needsprefix)
76 prefixneeded = needsprefix;
79 unsigned int ModeHandler::GetPrefixRank()
84 unsigned int ModeHandler::GetCount()
89 void ModeHandler::ChangeCount(int modifier)
92 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
95 ModeType ModeHandler::GetModeType()
100 bool ModeHandler::NeedsOper()
105 char ModeHandler::GetPrefix()
110 int ModeHandler::GetNumParams(bool adding)
112 return adding ? n_params_on : n_params_off;
115 char ModeHandler::GetModeChar()
120 std::string ModeHandler::GetUserParameter(User* user)
125 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool, bool)
127 return MODEACTION_DENY;
130 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
134 return std::make_pair(dest->IsModeSet(this->mode), "");
138 return std::make_pair(channel->IsModeSet(this->mode), "");
142 void ModeHandler::DisplayList(User*, Channel*)
146 void ModeHandler::DisplayEmptyList(User*, Channel*)
150 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
154 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
156 return (ours < theirs);
159 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
163 SimpleUserModeHandler::~SimpleUserModeHandler()
167 SimpleChannelModeHandler::~SimpleChannelModeHandler()
171 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
175 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
179 if (!dest->IsModeSet(this->GetModeChar()))
181 dest->SetMode(this->GetModeChar(),true);
182 return MODEACTION_ALLOW;
187 if (dest->IsModeSet(this->GetModeChar()))
189 dest->SetMode(this->GetModeChar(),false);
190 return MODEACTION_ALLOW;
194 return MODEACTION_DENY;
198 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
202 if (!channel->IsModeSet(this->GetModeChar()))
204 channel->SetMode(this->GetModeChar(),true);
205 return MODEACTION_ALLOW;
210 if (channel->IsModeSet(this->GetModeChar()))
212 channel->SetMode(this->GetModeChar(),false);
213 return MODEACTION_ALLOW;
217 return MODEACTION_DENY;
220 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
224 ModeWatcher::~ModeWatcher()
228 char ModeWatcher::GetModeChar()
233 ModeType ModeWatcher::GetModeType()
238 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
243 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
247 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
250 if ((!user) || (!dest) || (!chan) || (!*dest))
254 d = ServerInstance->FindNick(dest);
257 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
263 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
268 UCListIter n = d->chans.find(chan);
269 if (n != d->chans.end())
271 if (n->second & MASK)
275 n->second = n->second | MASK;
279 n->first->AddOppedUser(d);
282 n->first->AddHalfoppedUser(d);
285 n->first->AddVoicedUser(d);
288 return d->nick.c_str();
293 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
298 UCListIter n = d->chans.find(chan);
299 if (n != d->chans.end())
301 if ((n->second & MASK) == 0)
309 n->first->DelOppedUser(d);
312 n->first->DelHalfoppedUser(d);
315 n->first->DelVoicedUser(d);
318 return d->nick.c_str();
323 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
327 /* Display channel's current mode string */
328 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
329 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
334 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
336 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
340 if (targetuser == user || user->HasPrivPermission("users/auspex"))
342 /* Display user's current mode string */
343 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
344 if (IS_OPER(targetuser))
345 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
350 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
355 /* No such nick/channel */
356 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
360 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode)
362 std::string target = parameters[0];
363 ModeType type = MODETYPE_USER;
364 unsigned char mask = 0;
365 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
366 User* targetuser = ServerInstance->FindNick(parameters[0]);
370 /* Special case for displaying the list for listmodes,
371 * e.g. MODE #chan b, or MODE #chan +b without a parameter
373 if ((targetchannel) && (parameters.size() == 2))
375 const char* mode = parameters[1].c_str();
376 int nonlistmodes_found = 0;
382 while (mode && *mode)
384 unsigned char mletter = *mode;
392 /* Ensure the user doesnt request the same mode twice,
393 * so they cant flood themselves off out of idiocy.
395 if (sent[mletter] != seq)
405 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
408 if ((mh) && (mh->IsListMode()))
411 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
412 if (MOD_RESULT == ACR_DENY)
418 if (!user->HasPrivPermission("channels/auspex"))
420 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
422 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++);
423 mh->DisplayEmptyList(user, targetchannel);
428 /** See below for a description of what craq this is :D
430 unsigned char handler_id = (*mode - 65) | mask;
432 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
434 std::string dummyparam;
436 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
441 mh->DisplayList(user, targetchannel);
444 nonlistmodes_found++;
449 /* We didnt have any modes that were non-list, we can return here */
450 if (!nonlistmodes_found)
454 if (parameters.size() == 1)
456 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0].c_str());
458 else if (parameters.size() > 1)
460 bool SkipAccessChecks = false;
464 type = MODETYPE_CHANNEL;
467 /* Extra security checks on channel modes
468 * (e.g. are they a (half)op?
471 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
473 /* We don't have halfop */
475 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
476 if (MOD_RESULT == ACR_DENY)
478 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
483 type = MODETYPE_USER;
485 if (user != targetuser && IS_LOCAL(user) && !ServerInstance->ULine(user->server))
487 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
493 /* No such nick/channel */
494 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str());
498 std::string mode_sequence = parameters[1];
499 std::string parameter;
500 std::ostringstream parameter_list;
501 std::string output_sequence;
502 bool adding = true, state_change = false;
503 unsigned char handler_id = 0;
504 unsigned int parameter_counter = 2; /* Index of first parameter */
505 unsigned int parameter_count = 0;
506 bool last_successful_state_change = false;
508 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
509 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
510 mode_sequence.insert(0, "+");
512 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
514 unsigned char modechar = *letter;
519 * For + and - mode characters, we don't just stick the character into the output sequence.
520 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
521 * appearing in the output sequence, we store a flag which says there was a state change,
522 * which is set on any + or -, however, the + or - that we finish on is only appended to
523 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
526 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
527 * however, will allow the + if it is the first item in the sequence, regardless.
529 if ((!adding) || (!output_sequence.length()))
532 if (!output_sequence.length())
533 last_successful_state_change = false;
537 if ((adding) || (!output_sequence.length()))
540 if (!output_sequence.length())
541 last_successful_state_change = true;
547 * Watch carefully for the sleight of hand trick.
548 * 65 is the ascii value of 'A'. We take this from
549 * the char we're looking at to get a number between
550 * 1 and 127. We then logic-or it to get the hashed
551 * position, dependent on wether its a channel or
552 * a user mode. This is a little stranger, but a lot
553 * faster, than using a map of pairs.
555 handler_id = (modechar - 65) | mask;
557 if (modehandlers[handler_id])
561 if (modehandlers[handler_id]->GetModeType() == type)
565 if (modehandlers[handler_id]->GetNumParams(adding))
567 /* This mode expects a parameter, do we have any parameters left in our list to use? */
568 if (parameter_counter < parameters.size())
570 parameter = parameters[parameter_counter++];
573 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
578 /* No parameter, continue to the next mode */
579 modehandlers[handler_id]->OnParameterMissing(user, targetuser, targetchannel);
583 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
587 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
590 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
593 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
595 /* Check access to this mode character */
596 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
598 char needed = modehandlers[handler_id]->GetNeededPrefix();
599 ModeHandler* prefixmode = FindPrefix(needed);
601 /* If the mode defined by the handler is not '\0', but the handler for it
602 * cannot be found, they probably dont have the right module loaded to implement
603 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
604 * Revert to checking against the minimum core prefix, '%'.
606 if (needed && !prefixmode)
607 prefixmode = FindPrefix('%');
609 unsigned int neededrank = prefixmode->GetPrefixRank();
610 /* Compare our rank on the channel against the rank of the required prefix,
611 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
612 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
613 * first, so we don't need to iterate, we just look up the first instead.
615 std::string modestring = targetchannel->GetAllPrefixChars(user);
616 char ml = (modestring.empty() ? '\0' : modestring[0]);
617 ModeHandler* ourmode = FindPrefix(ml);
618 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
621 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
622 user->nick.c_str(), targetchannel->name.c_str(), needed, adding ? "" : "un", modechar);
628 bool had_parameter = !parameter.empty();
630 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
632 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
637 /* A module whacked the parameter completely, and there was one. abort. */
638 if ((had_parameter) && (parameter.empty()))
648 /* If it's disabled, they have to be an oper.
650 if (IS_LOCAL(user) && !IS_OPER(user) && ((type == MODETYPE_CHANNEL ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes)[modehandlers[handler_id]->GetModeChar() - 'A']))
652 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
654 type == MODETYPE_CHANNEL ? "channel" : "user",
655 modehandlers[handler_id]->GetModeChar());
659 /* It's an oper only mode, check if theyre an oper. If they arent,
660 * eat any parameter that came with the mode, and continue to next
662 if (adding && (IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
666 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
669 type == MODETYPE_CHANNEL ? "channel" : "user",
670 modehandlers[handler_id]->GetModeChar());
674 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
676 type == MODETYPE_CHANNEL ? "channel" : "user",
677 modehandlers[handler_id]->GetModeChar());
682 /* Call the handler for the mode */
683 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
685 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
687 /* The handler nuked the parameter and they are supposed to have one.
688 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
689 * so we bail to the next mode character.
694 if (ma == MODEACTION_ALLOW)
696 /* We're about to output a valid mode letter - was there previously a pending state-change? */
699 if (adding != last_successful_state_change)
700 output_sequence.append(adding ? "+" : "-");
701 last_successful_state_change = adding;
704 /* Add the mode letter */
705 output_sequence.push_back(modechar);
707 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
709 /* Is there a valid parameter for this mode? If so add it to the parameter list */
710 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
712 parameter_list << " " << parameter;
714 /* Does this mode have a prefix? */
715 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
717 User* user_to_prefix = ServerInstance->FindNick(parameter);
719 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
720 modehandlers[handler_id]->GetPrefixRank(), adding);
724 /* Call all the AfterMode events in the mode watchers for this mode */
725 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
726 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
728 /* Reset the state change flag */
729 state_change = false;
731 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
732 || (parameter_count > ServerInstance->Config->Limits.MaxModes))
734 /* We cant have a mode sequence this long */
735 letter = mode_sequence.end() - 1;
743 /* No mode handler? Unknown mode character then. */
744 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
750 /* Was there at least one valid mode in the sequence? */
751 if (!output_sequence.empty())
755 if (type == MODETYPE_CHANNEL)
757 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
758 this->LastParse = targetchannel->name;
762 targetuser->WriteServ("MODE %s %s%s",targetuser->nick.c_str(),output_sequence.c_str(), parameter_list.str().c_str());
763 this->LastParse = targetuser->nick;
768 if (type == MODETYPE_CHANNEL)
770 targetchannel->WriteChannel(user, "MODE %s %s%s", targetchannel->name.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
771 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
772 this->LastParse = targetchannel->name;
776 user->WriteTo(targetuser, "MODE %s %s%s", targetuser->nick.c_str(), output_sequence.c_str(), parameter_list.str().c_str());
777 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
778 this->LastParse = targetuser->nick;
782 LastParse.append(" ");
783 LastParse.append(output_sequence);
784 LastParse.append(parameter_list.str());
789 const std::string& ModeParser::GetLastParse()
794 void ModeParser::CleanMask(std::string &mask)
796 std::string::size_type pos_of_pling = mask.find_first_of('!');
797 std::string::size_type pos_of_at = mask.find_first_of('@');
798 std::string::size_type pos_of_dot = mask.find_first_of('.');
799 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
801 if (mask.length() >= 2 && mask[1] == ':')
802 return; // if it's an extban, don't even try guess how it needs to be formed.
804 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
806 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
807 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
809 /* It has no '.' in it, it must be a nick. */
814 /* Got a dot in it? Has to be a host */
815 mask = "*!*@" + mask;
818 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
820 /* Has an @ but no !, its a user@host */
823 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
825 /* Has a ! but no @, it must be a nick!ident */
830 bool ModeParser::AddMode(ModeHandler* mh)
832 unsigned char mask = 0;
833 unsigned char pos = 0;
835 /* Yes, i know, this might let people declare modes like '_' or '^'.
836 * If they do that, thats their problem, and if i ever EVER see an
837 * official InspIRCd developer do that, i'll beat them with a paddle!
839 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
842 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
843 * A mode prefix of ':' will fuck up both server to server, and client to server.
844 * A mode prefix of '#' will mess up /whois and /privmsg
846 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
849 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
850 pos = (mh->GetModeChar()-65) | mask;
852 if (modehandlers[pos])
855 modehandlers[pos] = mh;
859 bool ModeParser::DelMode(ModeHandler* mh)
861 unsigned char mask = 0;
862 unsigned char pos = 0;
864 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
867 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
868 pos = (mh->GetModeChar()-65) | mask;
870 if (!modehandlers[pos])
873 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
874 * To stack here we have to make the algorithm slower. Discuss.
876 switch (mh->GetModeType())
879 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
881 mh->RemoveMode(i->second);
884 case MODETYPE_CHANNEL:
885 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
887 mh->RemoveMode(i->second);
892 modehandlers[pos] = NULL;
897 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
899 unsigned char mask = 0;
900 unsigned char pos = 0;
902 if ((modeletter < 'A') || (modeletter > 'z'))
905 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
906 pos = (modeletter-65) | mask;
908 return modehandlers[pos];
911 std::string ModeParser::UserModeList()
916 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
918 unsigned char pos = (mode-65) | MASK_USER;
920 if (modehandlers[pos])
921 modestr[pointer++] = mode;
923 modestr[pointer++] = 0;
927 std::string ModeParser::ChannelModeList()
932 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
934 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
937 unsigned char pos = (mode-65) | MASK_CHANNEL;
939 if (modehandlers[pos])
940 modestr[pointer++] = mode;
942 modestr[pointer++] = 0;
946 std::string ModeParser::ParaModeList()
951 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
953 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
956 unsigned char pos = (mode-65) | MASK_CHANNEL;
958 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
959 modestr[pointer++] = mode;
961 modestr[pointer++] = 0;
965 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
967 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
969 unsigned char pos = (mode-65) | MASK_CHANNEL;
971 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
973 return modehandlers[pos];
979 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
984 if (!channel || !user)
987 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
989 unsigned char pos = (mode-65) | MASK_CHANNEL;
990 ModeHandler* mh = modehandlers[pos];
991 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
994 ret = mh->ModeSet(NULL, user, channel, user->nick);
995 if ((ret.first) && (ret.second == user->nick))
1000 pars.append(user->nick);
1002 types.push_back(mh->GetModeChar());
1013 std::string ModeParser::GiveModeList(ModeMasks m)
1015 std::string type1; /* Listmodes EXCEPT those with a prefix */
1016 std::string type2; /* Modes that take a param when adding or removing */
1017 std::string type3; /* Modes that only take a param when adding */
1018 std::string type4; /* Modes that dont take a param */
1020 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1022 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1025 unsigned char pos = (mode-65) | m;
1026 /* One parameter when adding */
1027 if (modehandlers[pos])
1029 if (modehandlers[pos]->GetNumParams(true))
1031 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1033 type1 += modehandlers[pos]->GetModeChar();
1037 /* ... and one parameter when removing */
1038 if (modehandlers[pos]->GetNumParams(false))
1040 /* But not a list mode */
1041 if (!modehandlers[pos]->GetPrefix())
1043 type2 += modehandlers[pos]->GetModeChar();
1048 /* No parameters when removing */
1049 type3 += modehandlers[pos]->GetModeChar();
1055 type4 += modehandlers[pos]->GetModeChar();
1061 return type1 + "," + type2 + "," + type3 + "," + type4;
1064 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1066 return one.second > two.second;
1069 std::string ModeParser::BuildPrefixes()
1071 std::string mletters;
1072 std::string mprefixes;
1074 std::map<char,char> prefix_to_mode;
1076 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1078 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
1081 unsigned char pos = (mode-65) | MASK_CHANNEL;
1083 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1085 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1086 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1090 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1092 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1094 mletters = mletters + n->first;
1095 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1098 return "(" + mprefixes + ")" + mletters;
1101 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1103 unsigned char mask = 0;
1104 unsigned char pos = 0;
1109 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1112 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1113 pos = (mw->GetModeChar()-65) | mask;
1115 modewatchers[pos].push_back(mw);
1120 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1122 unsigned char mask = 0;
1123 unsigned char pos = 0;
1128 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1131 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1132 pos = (mw->GetModeChar()-65) | mask;
1134 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1136 if (a == modewatchers[pos].end())
1141 modewatchers[pos].erase(a);
1146 /** This default implementation can remove simple user modes
1148 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1150 char moderemove[MAXBUF];
1151 std::vector<std::string> parameters;
1153 if (user->IsModeSet(this->GetModeChar()))
1157 stack->Push(this->GetModeChar());
1161 sprintf(moderemove,"-%c",this->GetModeChar());
1162 parameters.push_back(user->nick);
1163 parameters.push_back(moderemove);
1164 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, false);
1169 /** This default implementation can remove simple channel modes
1172 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1174 char moderemove[MAXBUF];
1175 std::vector<std::string> parameters;
1177 if (channel->IsModeSet(this->GetModeChar()))
1181 stack->Push(this->GetModeChar());
1185 sprintf(moderemove,"-%c",this->GetModeChar());
1186 parameters.push_back(channel->name);
1187 parameters.push_back(moderemove);
1188 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1193 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1195 ModeHandler* modes[] =
1197 new ModeChannelSecret(Instance),
1198 new ModeChannelPrivate(Instance),
1199 new ModeChannelModerated(Instance),
1200 new ModeChannelTopicOps(Instance),
1201 new ModeChannelNoExternal(Instance),
1202 new ModeChannelInviteOnly(Instance),
1203 new ModeChannelKey(Instance),
1204 new ModeChannelLimit(Instance),
1205 new ModeChannelBan(Instance),
1206 new ModeChannelOp(Instance),
1207 new ModeChannelHalfOp(Instance),
1208 new ModeChannelVoice(Instance),
1209 new ModeUserWallops(Instance),
1210 new ModeUserInvisible(Instance),
1211 new ModeUserOperator(Instance),
1212 new ModeUserServerNoticeMask(Instance),
1216 /* Clear mode handler list */
1217 memset(modehandlers, 0, sizeof(modehandlers));
1219 /* Last parse string */
1222 /* Initialise the RFC mode letters */
1223 for (int index = 0; modes[index]; index++)
1224 this->AddMode(modes[index]);
1227 memset(&sent, 0, sizeof(sent));