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 unsigned char pos = (mode-65) | MASK_CHANNEL;
936 if (modehandlers[pos])
937 modestr[pointer++] = mode;
939 modestr[pointer++] = 0;
943 std::string ModeParser::ParaModeList()
948 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
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::GiveModeList(ModeMasks m)
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 unsigned char pos = (mode-65) | m;
1017 /* One parameter when adding */
1018 if (modehandlers[pos])
1020 if (modehandlers[pos]->GetNumParams(true))
1022 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
1024 type1 += modehandlers[pos]->GetModeChar();
1028 /* ... and one parameter when removing */
1029 if (modehandlers[pos]->GetNumParams(false))
1031 /* But not a list mode */
1032 if (!modehandlers[pos]->GetPrefix())
1034 type2 += modehandlers[pos]->GetModeChar();
1039 /* No parameters when removing */
1040 type3 += modehandlers[pos]->GetModeChar();
1046 type4 += modehandlers[pos]->GetModeChar();
1051 return type1 + "," + type2 + "," + type3 + "," + type4;
1054 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
1056 return one.second > two.second;
1059 std::string ModeParser::BuildPrefixes()
1061 std::string mletters;
1062 std::string mprefixes;
1064 std::map<char,char> prefix_to_mode;
1066 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
1068 unsigned char pos = (mode-65) | MASK_CHANNEL;
1070 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1072 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1073 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1077 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1079 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1081 mletters = mletters + n->first;
1082 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1085 return "(" + mprefixes + ")" + mletters;
1088 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1090 unsigned char mask = 0;
1091 unsigned char pos = 0;
1096 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1099 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1100 pos = (mw->GetModeChar()-65) | mask;
1102 modewatchers[pos].push_back(mw);
1107 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1109 unsigned char mask = 0;
1110 unsigned char pos = 0;
1115 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1118 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1119 pos = (mw->GetModeChar()-65) | mask;
1121 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1123 if (a == modewatchers[pos].end())
1128 modewatchers[pos].erase(a);
1133 /** This default implementation can remove simple user modes
1135 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1137 char moderemove[MAXBUF];
1138 std::vector<std::string> parameters;
1140 if (user->IsModeSet(this->GetModeChar()))
1144 stack->Push(this->GetModeChar());
1148 sprintf(moderemove,"-%c",this->GetModeChar());
1149 parameters.push_back(user->nick);
1150 parameters.push_back(moderemove);
1151 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, false);
1156 /** This default implementation can remove simple channel modes
1159 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1161 char moderemove[MAXBUF];
1162 std::vector<std::string> parameters;
1164 if (channel->IsModeSet(this->GetModeChar()))
1168 stack->Push(this->GetModeChar());
1172 sprintf(moderemove,"-%c",this->GetModeChar());
1173 parameters.push_back(channel->name);
1174 parameters.push_back(moderemove);
1175 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1180 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1182 ModeHandler* modes[] =
1184 new ModeChannelSecret(Instance),
1185 new ModeChannelPrivate(Instance),
1186 new ModeChannelModerated(Instance),
1187 new ModeChannelTopicOps(Instance),
1188 new ModeChannelNoExternal(Instance),
1189 new ModeChannelInviteOnly(Instance),
1190 new ModeChannelKey(Instance),
1191 new ModeChannelLimit(Instance),
1192 new ModeChannelBan(Instance),
1193 new ModeChannelOp(Instance),
1194 new ModeChannelHalfOp(Instance),
1195 new ModeChannelVoice(Instance),
1196 new ModeUserWallops(Instance),
1197 new ModeUserInvisible(Instance),
1198 new ModeUserOperator(Instance),
1199 new ModeUserServerNoticeMask(Instance),
1203 /* Clear mode handler list */
1204 memset(modehandlers, 0, sizeof(modehandlers));
1206 /* Last parse string */
1209 /* Initialise the RFC mode letters */
1210 for (int index = 0; modes[index]; index++)
1211 this->AddMode(modes[index]);
1214 memset(&sent, 0, sizeof(sent));