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 (adding && (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 set %s mode %c",
587 type == MODETYPE_CHANNEL ? "channel" : "user",
588 modehandlers[handler_id]->GetModeChar());
592 user->WriteNumeric(481, "%s :Permission Denied - Only operators may set %s mode %c",
594 type == MODETYPE_CHANNEL ? "channel" : "user",
595 modehandlers[handler_id]->GetModeChar());
600 /* Call the handler for the mode */
601 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
603 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
605 /* The handler nuked the parameter and they are supposed to have one.
606 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
607 * so we bail to the next mode character.
612 if (ma == MODEACTION_ALLOW)
614 /* We're about to output a valid mode letter - was there previously a pending state-change? */
617 if (adding != last_successful_state_change)
618 output_sequence.append(adding ? "+" : "-");
619 last_successful_state_change = adding;
622 /* Add the mode letter */
623 output_sequence.push_back(modechar);
625 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
627 /* Is there a valid parameter for this mode? If so add it to the parameter list */
628 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
630 parameter_list << " " << parameter;
632 /* Does this mode have a prefix? */
633 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
635 User* user_to_prefix = ServerInstance->FindNick(parameter);
637 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
638 modehandlers[handler_id]->GetPrefixRank(), adding);
642 /* Call all the AfterMode events in the mode watchers for this mode */
643 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
644 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
646 /* Reset the state change flag */
647 state_change = false;
649 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
650 || (parameter_count > MAXMODES))
652 /* We cant have a mode sequence this long */
653 letter = mode_sequence.end() - 1;
661 /* No mode handler? Unknown mode character then. */
662 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
668 /* Was there at least one valid mode in the sequence? */
669 if (!output_sequence.empty())
673 if (type == MODETYPE_CHANNEL)
675 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
676 this->LastParse = targetchannel->name;
680 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
681 this->LastParse = targetuser->nick;
686 if (type == MODETYPE_CHANNEL)
688 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
689 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
690 this->LastParse = targetchannel->name;
694 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
695 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
696 this->LastParse = targetuser->nick;
700 LastParse.append(" ");
701 LastParse.append(output_sequence);
702 LastParse.append(parameter_list.str());
707 const std::string& ModeParser::GetLastParse()
712 void ModeParser::CleanMask(std::string &mask)
714 std::string::size_type pos_of_pling = mask.find_first_of('!');
715 std::string::size_type pos_of_at = mask.find_first_of('@');
716 std::string::size_type pos_of_dot = mask.find_first_of('.');
717 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
719 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
721 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
722 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
724 /* It has no '.' in it, it must be a nick. */
729 /* Got a dot in it? Has to be a host */
730 mask = "*!*@" + mask;
733 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
735 /* Has an @ but no !, its a user@host */
738 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
740 /* Has a ! but no @, it must be a nick!ident */
745 bool ModeParser::AddMode(ModeHandler* mh)
747 unsigned char mask = 0;
748 unsigned char pos = 0;
750 /* Yes, i know, this might let people declare modes like '_' or '^'.
751 * If they do that, thats their problem, and if i ever EVER see an
752 * official InspIRCd developer do that, i'll beat them with a paddle!
754 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
757 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
758 * A mode prefix of ':' will fuck up both server to server, and client to server.
759 * A mode prefix of '#' will mess up /whois and /privmsg
761 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
764 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
765 pos = (mh->GetModeChar()-65) | mask;
767 if (modehandlers[pos])
770 modehandlers[pos] = mh;
774 bool ModeParser::DelMode(ModeHandler* mh)
776 unsigned char mask = 0;
777 unsigned char pos = 0;
779 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
782 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
783 pos = (mh->GetModeChar()-65) | mask;
785 if (!modehandlers[pos])
788 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
789 * To stack here we have to make the algorithm slower. Discuss.
791 switch (mh->GetModeType())
794 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
796 mh->RemoveMode(i->second);
799 case MODETYPE_CHANNEL:
800 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
802 mh->RemoveMode(i->second);
807 modehandlers[pos] = NULL;
812 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
814 unsigned char mask = 0;
815 unsigned char pos = 0;
817 if ((modeletter < 'A') || (modeletter > 'z'))
820 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
821 pos = (modeletter-65) | mask;
823 return modehandlers[pos];
826 std::string ModeParser::UserModeList()
831 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
833 unsigned char pos = (mode-65) | MASK_USER;
835 if (modehandlers[pos])
836 modestr[pointer++] = mode;
838 modestr[pointer++] = 0;
842 std::string ModeParser::ChannelModeList()
847 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
849 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
852 unsigned char pos = (mode-65) | MASK_CHANNEL;
854 if (modehandlers[pos])
855 modestr[pointer++] = mode;
857 modestr[pointer++] = 0;
861 std::string ModeParser::ParaModeList()
866 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
868 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
871 unsigned char pos = (mode-65) | MASK_CHANNEL;
873 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
874 modestr[pointer++] = mode;
876 modestr[pointer++] = 0;
880 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
882 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
884 unsigned char pos = (mode-65) | MASK_CHANNEL;
886 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
888 return modehandlers[pos];
894 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
899 if (!channel || !user)
902 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
904 unsigned char pos = (mode-65) | MASK_CHANNEL;
905 ModeHandler* mh = modehandlers[pos];
906 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
909 ret = mh->ModeSet(NULL, user, channel, user->nick);
910 if ((ret.first) && (ret.second == user->nick))
915 pars.append(user->nick);
917 types.push_back(mh->GetModeChar());
928 std::string ModeParser::ChanModes()
930 std::string type1; /* Listmodes EXCEPT those with a prefix */
931 std::string type2; /* Modes that take a param when adding or removing */
932 std::string type3; /* Modes that only take a param when adding */
933 std::string type4; /* Modes that dont take a param */
935 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
937 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
940 unsigned char pos = (mode-65) | MASK_CHANNEL;
941 /* One parameter when adding */
942 if (modehandlers[pos])
944 if (modehandlers[pos]->GetNumParams(true))
946 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
948 type1 += modehandlers[pos]->GetModeChar();
952 /* ... and one parameter when removing */
953 if (modehandlers[pos]->GetNumParams(false))
955 /* But not a list mode */
956 if (!modehandlers[pos]->GetPrefix())
958 type2 += modehandlers[pos]->GetModeChar();
963 /* No parameters when removing */
964 type3 += modehandlers[pos]->GetModeChar();
970 type4 += modehandlers[pos]->GetModeChar();
976 return type1 + "," + type2 + "," + type3 + "," + type4;
979 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
981 return one.second > two.second;
984 std::string ModeParser::BuildPrefixes()
986 std::string mletters;
987 std::string mprefixes;
989 std::map<char,char> prefix_to_mode;
991 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
993 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
996 unsigned char pos = (mode-65) | MASK_CHANNEL;
998 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
1000 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
1001 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
1005 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
1007 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
1009 mletters = mletters + n->first;
1010 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
1013 return "(" + mprefixes + ")" + mletters;
1016 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1018 unsigned char mask = 0;
1019 unsigned char pos = 0;
1024 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1027 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1028 pos = (mw->GetModeChar()-65) | mask;
1030 modewatchers[pos].push_back(mw);
1035 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1037 unsigned char mask = 0;
1038 unsigned char pos = 0;
1043 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1046 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1047 pos = (mw->GetModeChar()-65) | mask;
1049 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1051 if (a == modewatchers[pos].end())
1056 modewatchers[pos].erase(a);
1061 /** This default implementation can remove simple user modes
1063 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1065 char moderemove[MAXBUF];
1066 const char* parameters[] = { user->nick, moderemove };
1068 if (user->IsModeSet(this->GetModeChar()))
1072 stack->Push(this->GetModeChar());
1076 sprintf(moderemove,"-%c",this->GetModeChar());
1077 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1082 /** This default implementation can remove simple channel modes
1085 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1087 char moderemove[MAXBUF];
1088 const char* parameters[] = { channel->name, moderemove };
1090 if (channel->IsModeSet(this->GetModeChar()))
1094 stack->Push(this->GetModeChar());
1098 sprintf(moderemove,"-%c",this->GetModeChar());
1099 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1104 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1106 ModeHandler* modes[] =
1108 new ModeChannelSecret(Instance),
1109 new ModeChannelPrivate(Instance),
1110 new ModeChannelModerated(Instance),
1111 new ModeChannelTopicOps(Instance),
1112 new ModeChannelNoExternal(Instance),
1113 new ModeChannelInviteOnly(Instance),
1114 new ModeChannelKey(Instance),
1115 new ModeChannelLimit(Instance),
1116 new ModeChannelBan(Instance),
1117 new ModeChannelOp(Instance),
1118 new ModeChannelHalfOp(Instance),
1119 new ModeChannelVoice(Instance),
1120 new ModeUserServerNotice(Instance),
1121 new ModeUserWallops(Instance),
1122 new ModeUserInvisible(Instance),
1123 new ModeUserOperator(Instance),
1124 new ModeUserServerNoticeMask(Instance),
1128 /* Clear mode list */
1129 memset(modehandlers, 0, sizeof(modehandlers));
1130 memset(modewatchers, 0, sizeof(modewatchers));
1132 /* Last parse string */
1135 /* Initialise the RFC mode letters */
1136 for (int index = 0; modes[index]; index++)
1137 this->AddMode(modes[index]);