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)))
582 user->WriteNumeric(481, "%s :Permission Denied - Oper type %s does not have access to %sset %s mode %c",
586 type == MODETYPE_CHANNEL ? "channel" : "user",
587 modehandlers[handler_id]->GetModeChar());
591 /* Call the handler for the mode */
592 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding, servermode);
594 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
596 /* The handler nuked the parameter and they are supposed to have one.
597 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
598 * so we bail to the next mode character.
603 if (ma == MODEACTION_ALLOW)
605 /* We're about to output a valid mode letter - was there previously a pending state-change? */
608 if (adding != last_successful_state_change)
609 output_sequence.append(adding ? "+" : "-");
610 last_successful_state_change = adding;
613 /* Add the mode letter */
614 output_sequence.push_back(modechar);
616 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
618 /* Is there a valid parameter for this mode? If so add it to the parameter list */
619 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
621 parameter_list << " " << parameter;
623 /* Does this mode have a prefix? */
624 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
626 User* user_to_prefix = ServerInstance->FindNick(parameter);
628 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
629 modehandlers[handler_id]->GetPrefixRank(), adding);
633 /* Call all the AfterMode events in the mode watchers for this mode */
634 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
635 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type, servermode);
637 /* Reset the state change flag */
638 state_change = false;
640 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
641 || (parameter_count > MAXMODES))
643 /* We cant have a mode sequence this long */
644 letter = mode_sequence.end() - 1;
652 /* No mode handler? Unknown mode character then. */
653 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
659 /* Was there at least one valid mode in the sequence? */
660 if (!output_sequence.empty())
664 if (type == MODETYPE_CHANNEL)
666 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
667 this->LastParse = targetchannel->name;
671 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
672 this->LastParse = targetuser->nick;
677 if (type == MODETYPE_CHANNEL)
679 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
680 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
681 this->LastParse = targetchannel->name;
685 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
686 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
687 this->LastParse = targetuser->nick;
691 LastParse.append(" ");
692 LastParse.append(output_sequence);
693 LastParse.append(parameter_list.str());
698 const std::string& ModeParser::GetLastParse()
703 void ModeParser::CleanMask(std::string &mask)
705 std::string::size_type pos_of_pling = mask.find_first_of('!');
706 std::string::size_type pos_of_at = mask.find_first_of('@');
707 std::string::size_type pos_of_dot = mask.find_first_of('.');
708 std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
710 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
712 /* Just a nick, or just a host */
713 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
715 /* It has no '.' in it, it must be a nick. */
720 /* Got a dot in it? Has to be a host */
721 mask = "*!*@" + mask;
724 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
726 /* Has an @ but no !, its a user@host */
729 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
731 /* Has a ! but no @, it must be a nick!ident */
736 bool ModeParser::AddMode(ModeHandler* mh)
738 unsigned char mask = 0;
739 unsigned char pos = 0;
741 /* Yes, i know, this might let people declare modes like '_' or '^'.
742 * If they do that, thats their problem, and if i ever EVER see an
743 * official InspIRCd developer do that, i'll beat them with a paddle!
745 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
748 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
749 * A mode prefix of ':' will fuck up both server to server, and client to server.
750 * A mode prefix of '#' will mess up /whois and /privmsg
752 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
755 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
756 pos = (mh->GetModeChar()-65) | mask;
758 if (modehandlers[pos])
761 modehandlers[pos] = mh;
765 bool ModeParser::DelMode(ModeHandler* mh)
767 unsigned char mask = 0;
768 unsigned char pos = 0;
770 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
773 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
774 pos = (mh->GetModeChar()-65) | mask;
776 if (!modehandlers[pos])
779 switch (mh->GetModeType())
782 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
784 mh->RemoveMode(i->second);
787 case MODETYPE_CHANNEL:
788 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
790 mh->RemoveMode(i->second);
795 modehandlers[pos] = NULL;
800 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
802 unsigned char mask = 0;
803 unsigned char pos = 0;
805 if ((modeletter < 'A') || (modeletter > 'z'))
808 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
809 pos = (modeletter-65) | mask;
811 return modehandlers[pos];
814 std::string ModeParser::UserModeList()
819 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
821 unsigned char pos = (mode-65) | MASK_USER;
823 if (modehandlers[pos])
824 modestr[pointer++] = mode;
826 modestr[pointer++] = 0;
830 std::string ModeParser::ChannelModeList()
835 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
837 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
840 unsigned char pos = (mode-65) | MASK_CHANNEL;
842 if (modehandlers[pos])
843 modestr[pointer++] = mode;
845 modestr[pointer++] = 0;
849 std::string ModeParser::ParaModeList()
854 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
856 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
859 unsigned char pos = (mode-65) | MASK_CHANNEL;
861 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
862 modestr[pointer++] = mode;
864 modestr[pointer++] = 0;
868 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
870 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
872 unsigned char pos = (mode-65) | MASK_CHANNEL;
874 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
876 return modehandlers[pos];
882 std::string ModeParser::ModeString(User* user, Channel* channel)
887 if (!channel || !user)
890 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
892 unsigned char pos = (mode-65) | MASK_CHANNEL;
893 ModeHandler* mh = modehandlers[pos];
894 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
897 ret = mh->ModeSet(NULL, user, channel, user->nick);
898 if ((ret.first) && (ret.second == user->nick))
901 pars.append(user->nick);
902 types.push_back(mh->GetModeChar());
910 std::string ModeParser::ChanModes()
912 std::string type1; /* Listmodes EXCEPT those with a prefix */
913 std::string type2; /* Modes that take a param when adding or removing */
914 std::string type3; /* Modes that only take a param when adding */
915 std::string type4; /* Modes that dont take a param */
917 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
919 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
922 unsigned char pos = (mode-65) | MASK_CHANNEL;
923 /* One parameter when adding */
924 if (modehandlers[pos])
926 if (modehandlers[pos]->GetNumParams(true))
928 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
930 type1 += modehandlers[pos]->GetModeChar();
934 /* ... and one parameter when removing */
935 if (modehandlers[pos]->GetNumParams(false))
937 /* But not a list mode */
938 if (!modehandlers[pos]->GetPrefix())
940 type2 += modehandlers[pos]->GetModeChar();
945 /* No parameters when removing */
946 type3 += modehandlers[pos]->GetModeChar();
952 type4 += modehandlers[pos]->GetModeChar();
958 return type1 + "," + type2 + "," + type3 + "," + type4;
961 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
963 return one.second > two.second;
966 std::string ModeParser::BuildPrefixes()
968 std::string mletters;
969 std::string mprefixes;
971 std::map<char,char> prefix_to_mode;
973 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
975 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
978 unsigned char pos = (mode-65) | MASK_CHANNEL;
980 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
982 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
983 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
987 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
989 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
991 mletters = mletters + n->first;
992 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
995 return "(" + mprefixes + ")" + mletters;
998 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
1000 unsigned char mask = 0;
1001 unsigned char pos = 0;
1006 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1009 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1010 pos = (mw->GetModeChar()-65) | mask;
1012 modewatchers[pos].push_back(mw);
1017 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1019 unsigned char mask = 0;
1020 unsigned char pos = 0;
1025 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1028 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1029 pos = (mw->GetModeChar()-65) | mask;
1031 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1033 if (a == modewatchers[pos].end())
1038 modewatchers[pos].erase(a);
1043 /** This default implementation can remove simple user modes
1045 void ModeHandler::RemoveMode(User* user)
1047 char moderemove[MAXBUF];
1048 const char* parameters[] = { user->nick, moderemove };
1050 if (user->IsModeSet(this->GetModeChar()))
1052 sprintf(moderemove,"-%c",this->GetModeChar());
1053 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1057 /** This default implementation can remove simple channel modes
1060 void ModeHandler::RemoveMode(Channel* channel)
1062 char moderemove[MAXBUF];
1063 const char* parameters[] = { channel->name, moderemove };
1065 if (channel->IsModeSet(this->GetModeChar()))
1067 sprintf(moderemove,"-%c",this->GetModeChar());
1068 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1072 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1074 ModeHandler* modes[] =
1076 new ModeChannelSecret(Instance),
1077 new ModeChannelPrivate(Instance),
1078 new ModeChannelModerated(Instance),
1079 new ModeChannelTopicOps(Instance),
1080 new ModeChannelNoExternal(Instance),
1081 new ModeChannelInviteOnly(Instance),
1082 new ModeChannelKey(Instance),
1083 new ModeChannelLimit(Instance),
1084 new ModeChannelBan(Instance),
1085 new ModeChannelOp(Instance),
1086 new ModeChannelHalfOp(Instance),
1087 new ModeChannelVoice(Instance),
1088 new ModeUserServerNotice(Instance),
1089 new ModeUserWallops(Instance),
1090 new ModeUserInvisible(Instance),
1091 new ModeUserOperator(Instance),
1092 new ModeUserServerNoticeMask(Instance),
1096 /* Clear mode list */
1097 memset(modehandlers, 0, sizeof(modehandlers));
1098 memset(modewatchers, 0, sizeof(modewatchers));
1100 /* Last parse string */
1103 /* Initialise the RFC mode letters */
1104 for (int index = 0; modes[index]; index++)
1105 this->AddMode(modes[index]);