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 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
156 ModeWatcher::~ModeWatcher()
160 char ModeWatcher::GetModeChar()
165 ModeType ModeWatcher::GetModeType()
170 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
175 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
179 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
182 if ((!user) || (!dest) || (!chan) || (!*dest))
186 d = ServerInstance->FindNick(dest);
189 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, dest);
195 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
200 UCListIter n = d->chans.find(chan);
201 if (n != d->chans.end())
203 if (n->second & MASK)
207 n->second = n->second | MASK;
211 n->first->AddOppedUser(d);
214 n->first->AddHalfoppedUser(d);
217 n->first->AddVoicedUser(d);
225 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
230 UCListIter n = d->chans.find(chan);
231 if (n != d->chans.end())
233 if ((n->second & MASK) == 0)
241 n->first->DelOppedUser(d);
244 n->first->DelHalfoppedUser(d);
247 n->first->DelVoicedUser(d);
255 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
259 /* Display channel's current mode string */
260 user->WriteNumeric(324, "%s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
261 user->WriteNumeric(329, "%s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);
266 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
268 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, text);
272 if ((targetuser == user) || (IS_OPER(user)))
274 /* Display user's current mode string */
275 user->WriteNumeric(221, "%s :+%s",targetuser->nick,targetuser->FormatModes());
276 if (IS_OPER(targetuser))
277 user->WriteNumeric(8, "%s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
282 user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick);
287 /* No such nick/channel */
288 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, text);
292 void ModeParser::Process(const char* const* parameters, int pcnt, User *user, bool servermode)
294 std::string target = parameters[0];
295 ModeType type = MODETYPE_USER;
296 unsigned char mask = 0;
297 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
298 User* targetuser = ServerInstance->FindNick(parameters[0]);
302 /* Special case for displaying the list for listmodes,
303 * e.g. MODE #chan b, or MODE #chan +b without a parameter
305 if ((targetchannel) && (pcnt == 2))
307 const char* mode = parameters[1];
308 int nonlistmodes_found = 0;
313 memset(&sent, 0, 256);
315 while (mode && *mode)
317 unsigned char mletter = *mode;
325 /* Ensure the user doesnt request the same mode twice,
326 * so they cant flood themselves off out of idiocy.
330 sent[mletter] = true;
338 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
341 if ((mh) && (mh->IsListMode()))
344 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
345 if (MOD_RESULT == ACR_DENY)
351 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
353 user->WriteNumeric(482, "%s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
354 mh->DisplayEmptyList(user, targetchannel);
358 /** See below for a description of what craq this is :D
360 unsigned char handler_id = (*mode - 65) | mask;
362 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
364 std::string dummyparam;
366 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
371 mh->DisplayList(user, targetchannel);
374 nonlistmodes_found++;
379 /* We didnt have any modes that were non-list, we can return here */
380 if (!nonlistmodes_found)
386 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
390 bool SkipAccessChecks = false;
394 type = MODETYPE_CHANNEL;
397 /* Extra security checks on channel modes
398 * (e.g. are they a (half)op?
401 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
403 /* We don't have halfop */
405 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
406 if (MOD_RESULT == ACR_DENY)
408 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
413 type = MODETYPE_USER;
415 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
417 user->WriteNumeric(502, "%s :Can't change mode for other users", user->nick);
423 /* No such nick/channel */
424 user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick, parameters[0]);
428 std::string mode_sequence = parameters[1];
429 std::string parameter;
430 std::ostringstream parameter_list;
431 std::string output_sequence;
432 bool adding = true, state_change = false;
433 unsigned char handler_id = 0;
434 int parameter_counter = 2; /* Index of first parameter */
435 int parameter_count = 0;
436 bool last_successful_state_change = false;
438 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
439 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
440 mode_sequence.insert(0, "+");
442 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
444 unsigned char modechar = *letter;
449 * For + and - mode characters, we don't just stick the character into the output sequence.
450 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
451 * appearing in the output sequence, we store a flag which says there was a state change,
452 * which is set on any + or -, however, the + or - that we finish on is only appended to
453 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
456 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
457 * however, will allow the + if it is the first item in the sequence, regardless.
459 if ((!adding) || (!output_sequence.length()))
462 if (!output_sequence.length())
463 last_successful_state_change = false;
467 if ((adding) || (!output_sequence.length()))
470 if (!output_sequence.length())
471 last_successful_state_change = true;
477 * Watch carefully for the sleight of hand trick.
478 * 65 is the ascii value of 'A'. We take this from
479 * the char we're looking at to get a number between
480 * 1 and 127. We then logic-or it to get the hashed
481 * position, dependent on wether its a channel or
482 * a user mode. This is a little stranger, but a lot
483 * faster, than using a map of pairs.
485 handler_id = (modechar - 65) | mask;
487 if (modehandlers[handler_id])
491 if (modehandlers[handler_id]->GetModeType() == type)
495 if (modehandlers[handler_id]->GetNumParams(adding))
497 /* This mode expects a parameter, do we have any parameters left in our list to use? */
498 if (parameter_counter < pcnt)
500 parameter = parameters[parameter_counter++];
503 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
508 /* No parameter, continue to the next mode */
512 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1, servermode));
516 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0, servermode));
519 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
522 if (!SkipAccessChecks && IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
524 /* Check access to this mode character */
525 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
527 char needed = modehandlers[handler_id]->GetNeededPrefix();
528 ModeHandler* prefixmode = FindPrefix(needed);
530 /* If the mode defined by the handler is not '\0', but the handler for it
531 * cannot be found, they probably dont have the right module loaded to implement
532 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
533 * Revert to checking against the minimum core prefix, '%'.
535 if (needed && !prefixmode)
536 prefixmode = FindPrefix('%');
538 unsigned int neededrank = prefixmode->GetPrefixRank();
539 /* Compare our rank on the channel against the rank of the required prefix,
540 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
541 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
542 * first, so we don't need to iterate, we just look up the first instead.
544 std::string modestring = targetchannel->GetAllPrefixChars(user);
545 char ml = (modestring.empty() ? '\0' : modestring[0]);
546 ModeHandler* ourmode = FindPrefix(ml);
547 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
550 user->WriteNumeric(482, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
551 user->nick, targetchannel->name, needed, adding ? "" : "un", modechar);
557 bool had_parameter = !parameter.empty();
559 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
561 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type, servermode) == false)
566 /* A module whacked the parameter completely, and there was one. abort. */
567 if ((had_parameter) && (parameter.empty()))
577 /* It's an oper only mode, check if theyre an oper. If they arent,
578 * eat any parameter that came with the mode, and continue to next
580 if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!user->HasModePermission(modehandlers[handler_id]->GetModeChar(), type)))
584 user->WriteNumeric(481, "%s :Permission Denied - Oper type %s does not have access to %sset %s mode %c",
588 type == MODETYPE_CHANNEL ? "channel" : "user",
589 modehandlers[handler_id]->GetModeChar());
593 user->WriteNumeric(481, "%s :Permission Denied - Only operators may %sset %s mode %c",
596 type == MODETYPE_CHANNEL ? "channel" : "user",
597 modehandlers[handler_id]->GetModeChar());
602 /* Call the handler for the mode */
603 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
605 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
607 /* The handler nuked the parameter and they are supposed to have one.
608 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
609 * so we bail to the next mode character.
614 if (ma == MODEACTION_ALLOW)
616 /* We're about to output a valid mode letter - was there previously a pending state-change? */
619 if (adding != last_successful_state_change)
620 output_sequence.append(adding ? "+" : "-");
621 last_successful_state_change = adding;
624 /* Add the mode letter */
625 output_sequence.push_back(modechar);
627 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
629 /* Is there a valid parameter for this mode? If so add it to the parameter list */
630 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
632 parameter_list << " " << parameter;
634 /* Does this mode have a prefix? */
635 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
637 User* user_to_prefix = ServerInstance->FindNick(parameter);
639 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
640 modehandlers[handler_id]->GetPrefixRank(), adding);
644 /* Call all the AfterMode events in the mode watchers for this mode */
645 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
646 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
648 /* Reset the state change flag */
649 state_change = false;
651 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
652 || (parameter_count > MAXMODES))
654 /* We cant have a mode sequence this long */
655 letter = mode_sequence.end() - 1;
663 /* No mode handler? Unknown mode character then. */
664 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
670 /* Was there at least one valid mode in the sequence? */
671 if (!output_sequence.empty())
675 if (type == MODETYPE_CHANNEL)
677 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
678 this->LastParse = targetchannel->name;
682 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
683 this->LastParse = targetuser->nick;
688 if (type == MODETYPE_CHANNEL)
690 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
691 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
692 this->LastParse = targetchannel->name;
696 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
697 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
698 this->LastParse = targetuser->nick;
702 LastParse.append(" ");
703 LastParse.append(output_sequence);
704 LastParse.append(parameter_list.str());
709 const std::string& ModeParser::GetLastParse()
714 void ModeParser::CleanMask(std::string &mask)
716 std::string::size_type pos_of_pling = mask.find_first_of('!');
717 std::string::size_type pos_of_at = mask.find_first_of('@');
718 std::string::size_type pos_of_dot = mask.find_first_of('.');
719 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
721 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
723 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
724 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
726 /* It has no '.' in it, it must be a nick. */
731 /* Got a dot in it? Has to be a host */
732 mask = "*!*@" + mask;
735 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
737 /* Has an @ but no !, its a user@host */
740 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
742 /* Has a ! but no @, it must be a nick!ident */
747 bool ModeParser::AddMode(ModeHandler* mh)
749 unsigned char mask = 0;
750 unsigned char pos = 0;
752 /* Yes, i know, this might let people declare modes like '_' or '^'.
753 * If they do that, thats their problem, and if i ever EVER see an
754 * official InspIRCd developer do that, i'll beat them with a paddle!
756 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
759 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
760 * A mode prefix of ':' will fuck up both server to server, and client to server.
761 * A mode prefix of '#' will mess up /whois and /privmsg
763 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
766 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
767 pos = (mh->GetModeChar()-65) | mask;
769 if (modehandlers[pos])
772 modehandlers[pos] = mh;
776 bool ModeParser::DelMode(ModeHandler* mh)
778 unsigned char mask = 0;
779 unsigned char pos = 0;
781 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
784 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
785 pos = (mh->GetModeChar()-65) | mask;
787 if (!modehandlers[pos])
790 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
791 * To stack here we have to make the algorithm slower. Discuss.
793 switch (mh->GetModeType())
796 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
798 mh->RemoveMode(i->second);
801 case MODETYPE_CHANNEL:
802 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
804 mh->RemoveMode(i->second);
809 modehandlers[pos] = NULL;
814 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
816 unsigned char mask = 0;
817 unsigned char pos = 0;
819 if ((modeletter < 'A') || (modeletter > 'z'))
822 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
823 pos = (modeletter-65) | mask;
825 return modehandlers[pos];
828 std::string ModeParser::UserModeList()
833 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
835 unsigned char pos = (mode-65) | MASK_USER;
837 if (modehandlers[pos])
838 modestr[pointer++] = mode;
840 modestr[pointer++] = 0;
844 std::string ModeParser::ChannelModeList()
849 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
851 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
854 unsigned char pos = (mode-65) | MASK_CHANNEL;
856 if (modehandlers[pos])
857 modestr[pointer++] = mode;
859 modestr[pointer++] = 0;
863 std::string ModeParser::ParaModeList()
868 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
870 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
873 unsigned char pos = (mode-65) | MASK_CHANNEL;
875 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
876 modestr[pointer++] = mode;
878 modestr[pointer++] = 0;
882 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
884 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
886 unsigned char pos = (mode-65) | MASK_CHANNEL;
888 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
890 return modehandlers[pos];
896 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
901 if (!channel || !user)
904 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
906 unsigned char pos = (mode-65) | MASK_CHANNEL;
907 ModeHandler* mh = modehandlers[pos];
908 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
911 ret = mh->ModeSet(NULL, user, channel, user->nick);
912 if ((ret.first) && (ret.second == user->nick))
917 pars.append(user->nick);
919 types.push_back(mh->GetModeChar());
930 std::string ModeParser::ChanModes()
932 std::string type1; /* Listmodes EXCEPT those with a prefix */
933 std::string type2; /* Modes that take a param when adding or removing */
934 std::string type3; /* Modes that only take a param when adding */
935 std::string type4; /* Modes that dont take a param */
937 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
939 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
942 unsigned char pos = (mode-65) | MASK_CHANNEL;
943 /* One parameter when adding */
944 if (modehandlers[pos])
946 if (modehandlers[pos]->GetNumParams(true))
948 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
950 type1 += modehandlers[pos]->GetModeChar();
954 /* ... and one parameter when removing */
955 if (modehandlers[pos]->GetNumParams(false))
957 /* But not a list mode */
958 if (!modehandlers[pos]->GetPrefix())
960 type2 += modehandlers[pos]->GetModeChar();
965 /* No parameters when removing */
966 type3 += modehandlers[pos]->GetModeChar();
972 type4 += modehandlers[pos]->GetModeChar();
978 return type1 + "," + type2 + "," + type3 + "," + type4;
981 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
983 return one.second > two.second;
986 std::string ModeParser::BuildPrefixes()
988 std::string mletters;
989 std::string mprefixes;
991 std::map<char,char> prefix_to_mode;
993 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
995 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
998 unsigned char pos = (mode-65) | MASK_CHANNEL;
1000 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1002 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1003 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1007 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1009 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1011 mletters = mletters + n->first;
1012 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1015 return "(" + mprefixes + ")" + mletters;
1018 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1020 unsigned char mask = 0;
1021 unsigned char pos = 0;
1026 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1029 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1030 pos = (mw->GetModeChar()-65) | mask;
1032 modewatchers[pos].push_back(mw);
1037 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1039 unsigned char mask = 0;
1040 unsigned char pos = 0;
1045 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1048 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1049 pos = (mw->GetModeChar()-65) | mask;
1051 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1053 if (a == modewatchers[pos].end())
1058 modewatchers[pos].erase(a);
1063 /** This default implementation can remove simple user modes
1065 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1067 char moderemove[MAXBUF];
1068 const char* parameters[] = { user->nick, moderemove };
1070 if (user->IsModeSet(this->GetModeChar()))
1074 stack->Push(this->GetModeChar());
1078 sprintf(moderemove,"-%c",this->GetModeChar());
1079 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1084 /** This default implementation can remove simple channel modes
1087 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1089 char moderemove[MAXBUF];
1090 const char* parameters[] = { channel->name, moderemove };
1092 if (channel->IsModeSet(this->GetModeChar()))
1096 stack->Push(this->GetModeChar());
1100 sprintf(moderemove,"-%c",this->GetModeChar());
1101 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1106 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1108 ModeHandler* modes[] =
1110 new ModeChannelSecret(Instance),
1111 new ModeChannelPrivate(Instance),
1112 new ModeChannelModerated(Instance),
1113 new ModeChannelTopicOps(Instance),
1114 new ModeChannelNoExternal(Instance),
1115 new ModeChannelInviteOnly(Instance),
1116 new ModeChannelKey(Instance),
1117 new ModeChannelLimit(Instance),
1118 new ModeChannelBan(Instance),
1119 new ModeChannelOp(Instance),
1120 new ModeChannelHalfOp(Instance),
1121 new ModeChannelVoice(Instance),
1122 new ModeUserServerNotice(Instance),
1123 new ModeUserWallops(Instance),
1124 new ModeUserInvisible(Instance),
1125 new ModeUserOperator(Instance),
1126 new ModeUserServerNoticeMask(Instance),
1130 /* Clear mode list */
1131 memset(modehandlers, 0, sizeof(modehandlers));
1132 memset(modewatchers, 0, sizeof(modewatchers));
1134 /* Last parse string */
1137 /* Initialise the RFC mode letters */
1138 for (int index = 0; modes[index]; index++)
1139 this->AddMode(modes[index]);