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->Log(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)
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)
175 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
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->WriteServ("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->WriteServ("324 %s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
261 user->WriteServ("329 %s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);
266 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
268 user->WriteServ("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->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes());
276 if (IS_OPER(targetuser))
277 user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
282 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
287 /* No such nick/channel */
288 user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
292 void ModeParser::Process(const char** 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->WriteServ("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]);
392 type = MODETYPE_CHANNEL;
395 /* Extra security checks on channel modes
396 * (e.g. are they a (half)op?
399 if ((IS_LOCAL(user)) && (!ServerInstance->ULine(user->server)) && (!servermode))
401 /* We don't have halfop */
403 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
404 if (MOD_RESULT == ACR_DENY)
410 type = MODETYPE_USER;
412 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
414 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
420 /* No such nick/channel */
421 user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
425 std::string mode_sequence = parameters[1];
426 std::string parameter;
427 std::ostringstream parameter_list;
428 std::string output_sequence;
429 bool adding = true, state_change = false;
430 unsigned char handler_id = 0;
431 int parameter_counter = 2; /* Index of first parameter */
432 int parameter_count = 0;
433 bool last_successful_state_change = false;
435 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
436 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
437 mode_sequence.insert(0, "+");
439 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
441 unsigned char modechar = *letter;
446 * For + and - mode characters, we don't just stick the character into the output sequence.
447 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
448 * appearing in the output sequence, we store a flag which says there was a state change,
449 * which is set on any + or -, however, the + or - that we finish on is only appended to
450 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
453 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
454 * however, will allow the + if it is the first item in the sequence, regardless.
456 if ((!adding) || (!output_sequence.length()))
459 if (!output_sequence.length())
460 last_successful_state_change = false;
464 if ((adding) || (!output_sequence.length()))
467 if (!output_sequence.length())
468 last_successful_state_change = true;
474 * Watch carefully for the sleight of hand trick.
475 * 65 is the ascii value of 'A'. We take this from
476 * the char we're looking at to get a number between
477 * 1 and 127. We then logic-or it to get the hashed
478 * position, dependent on wether its a channel or
479 * a user mode. This is a little stranger, but a lot
480 * faster, than using a map of pairs.
482 handler_id = (modechar - 65) | mask;
484 if (modehandlers[handler_id])
488 if (modehandlers[handler_id]->GetModeType() == type)
492 if (modehandlers[handler_id]->GetNumParams(adding))
494 /* This mode expects a parameter, do we have any parameters left in our list to use? */
495 if (parameter_counter < pcnt)
497 parameter = parameters[parameter_counter++];
500 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
505 /* No parameter, continue to the next mode */
509 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1));
513 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0));
516 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
519 if (IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
521 ServerInstance->Log(DEBUG,"Enter minimum prefix check");
522 /* Check access to this mode character */
523 if ((type == MODETYPE_CHANNEL) && (modehandlers[handler_id]->GetNeededPrefix()))
525 char needed = modehandlers[handler_id]->GetNeededPrefix();
526 ModeHandler* prefixmode = FindPrefix(needed);
527 ServerInstance->Log(DEBUG,"Needed prefix: %c", needed);
529 /* If the mode defined by the handler is not '\0', but the handler for it
530 * cannot be found, they probably dont have the right module loaded to implement
531 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
532 * Revert to checking against the minimum core prefix, '%'.
534 if (needed && !prefixmode)
535 prefixmode = FindPrefix('%');
537 unsigned int neededrank = prefixmode->GetPrefixRank();
538 /* Compare our rank on the channel against the rank of the required prefix,
539 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
540 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
541 * first, so we don't need to iterate, we just look up the first instead.
543 std::string modestring = targetchannel->GetAllPrefixChars(user);
544 char ml = (modestring.empty() ? '\0' : modestring[0]);
545 ModeHandler* ourmode = FindPrefix(ml);
546 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
549 user->WriteServ("482 %s %s :You require channel privilege %c or above to %sset channel mode %c",
550 user->nick, targetchannel->name, needed, adding ? "" : "un", modechar);
556 bool had_parameter = !parameter.empty();
558 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
560 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
565 /* A module whacked the parameter completely, and there was one. abort. */
566 if ((had_parameter) && (parameter.empty()))
576 /* It's an oper only mode, check if theyre an oper. If they arent,
577 * eat any parameter that came with the mode, and continue to next
579 if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
581 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
582 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
583 modehandlers[handler_id]->GetModeChar());
587 /* Call the handler for the mode */
588 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
590 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
592 /* The handler nuked the parameter and they are supposed to have one.
593 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
594 * so we bail to the next mode character.
599 if (ma == MODEACTION_ALLOW)
601 /* We're about to output a valid mode letter - was there previously a pending state-change? */
604 if (adding != last_successful_state_change)
605 output_sequence.append(adding ? "+" : "-");
606 last_successful_state_change = adding;
609 /* Add the mode letter */
610 output_sequence.push_back(modechar);
612 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
614 /* Is there a valid parameter for this mode? If so add it to the parameter list */
615 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
617 parameter_list << " " << parameter;
619 /* Does this mode have a prefix? */
620 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
622 User* user_to_prefix = ServerInstance->FindNick(parameter);
624 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
625 modehandlers[handler_id]->GetPrefixRank(), adding);
629 /* Call all the AfterMode events in the mode watchers for this mode */
630 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
631 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);
633 /* Reset the state change flag */
634 state_change = false;
636 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
637 || (parameter_count > MAXMODES))
639 /* We cant have a mode sequence this long */
640 letter = mode_sequence.end() - 1;
648 /* No mode handler? Unknown mode character then. */
649 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
655 /* Was there at least one valid mode in the sequence? */
656 if (!output_sequence.empty())
660 if (type == MODETYPE_CHANNEL)
662 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
663 this->LastParse = targetchannel->name;
667 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
668 this->LastParse = targetuser->nick;
673 if (type == MODETYPE_CHANNEL)
675 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
676 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
677 this->LastParse = targetchannel->name;
681 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
682 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
683 this->LastParse = targetuser->nick;
687 LastParse.append(" ");
688 LastParse.append(output_sequence);
689 LastParse.append(parameter_list.str());
694 const std::string& ModeParser::GetLastParse()
699 void ModeParser::CleanMask(std::string &mask)
701 std::string::size_type pos_of_pling = mask.find_first_of('!');
702 std::string::size_type pos_of_at = mask.find_first_of('@');
703 std::string::size_type pos_of_dot = mask.find_first_of('.');
704 std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
706 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
708 /* Just a nick, or just a host */
709 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
711 /* It has no '.' in it, it must be a nick. */
716 /* Got a dot in it? Has to be a host */
717 mask = "*!*@" + mask;
720 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
722 /* Has an @ but no !, its a user@host */
725 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
727 /* Has a ! but no @, it must be a nick!ident */
732 bool ModeParser::AddMode(ModeHandler* mh)
734 unsigned char mask = 0;
735 unsigned char pos = 0;
737 /* Yes, i know, this might let people declare modes like '_' or '^'.
738 * If they do that, thats their problem, and if i ever EVER see an
739 * official InspIRCd developer do that, i'll beat them with a paddle!
741 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
744 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
745 * A mode prefix of ':' will fuck up both server to server, and client to server.
746 * A mode prefix of '#' will mess up /whois and /privmsg
748 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
751 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
752 pos = (mh->GetModeChar()-65) | mask;
754 if (modehandlers[pos])
757 modehandlers[pos] = mh;
761 bool ModeParser::DelMode(ModeHandler* mh)
763 unsigned char mask = 0;
764 unsigned char pos = 0;
766 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
769 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
770 pos = (mh->GetModeChar()-65) | mask;
772 if (!modehandlers[pos])
775 switch (mh->GetModeType())
778 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
780 mh->RemoveMode(i->second);
783 case MODETYPE_CHANNEL:
784 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
786 mh->RemoveMode(i->second);
791 modehandlers[pos] = NULL;
796 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
798 unsigned char mask = 0;
799 unsigned char pos = 0;
801 if ((modeletter < 'A') || (modeletter > 'z'))
804 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
805 pos = (modeletter-65) | mask;
807 return modehandlers[pos];
810 std::string ModeParser::UserModeList()
815 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
817 unsigned char pos = (mode-65) | MASK_USER;
819 if (modehandlers[pos])
820 modestr[pointer++] = mode;
822 modestr[pointer++] = 0;
826 std::string ModeParser::ChannelModeList()
831 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
833 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
836 unsigned char pos = (mode-65) | MASK_CHANNEL;
838 if (modehandlers[pos])
839 modestr[pointer++] = mode;
841 modestr[pointer++] = 0;
845 std::string ModeParser::ParaModeList()
850 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
852 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
855 unsigned char pos = (mode-65) | MASK_CHANNEL;
857 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
858 modestr[pointer++] = mode;
860 modestr[pointer++] = 0;
864 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
866 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
868 unsigned char pos = (mode-65) | MASK_CHANNEL;
870 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
872 return modehandlers[pos];
878 std::string ModeParser::ModeString(User* user, Channel* channel)
883 if (!channel || !user)
886 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
888 unsigned char pos = (mode-65) | MASK_CHANNEL;
889 ModeHandler* mh = modehandlers[pos];
890 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
893 ret = mh->ModeSet(NULL, user, channel, user->nick);
894 if ((ret.first) && (ret.second == user->nick))
897 pars.append(user->nick);
898 types.push_back(mh->GetModeChar());
906 std::string ModeParser::ChanModes()
908 std::string type1; /* Listmodes EXCEPT those with a prefix */
909 std::string type2; /* Modes that take a param when adding or removing */
910 std::string type3; /* Modes that only take a param when adding */
911 std::string type4; /* Modes that dont take a param */
913 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
915 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
918 unsigned char pos = (mode-65) | MASK_CHANNEL;
919 /* One parameter when adding */
920 if (modehandlers[pos])
922 if (modehandlers[pos]->GetNumParams(true))
924 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
926 type1 += modehandlers[pos]->GetModeChar();
930 /* ... and one parameter when removing */
931 if (modehandlers[pos]->GetNumParams(false))
933 /* But not a list mode */
934 if (!modehandlers[pos]->GetPrefix())
936 type2 += modehandlers[pos]->GetModeChar();
941 /* No parameters when removing */
942 type3 += modehandlers[pos]->GetModeChar();
948 type4 += modehandlers[pos]->GetModeChar();
954 return type1 + "," + type2 + "," + type3 + "," + type4;
957 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
959 return one.second > two.second;
962 std::string ModeParser::BuildPrefixes()
964 std::string mletters;
965 std::string mprefixes;
967 std::map<char,char> prefix_to_mode;
969 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
971 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
974 unsigned char pos = (mode-65) | MASK_CHANNEL;
976 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
978 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
979 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
983 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
985 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
987 mletters = mletters + n->first;
988 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
991 return "(" + mprefixes + ")" + mletters;
994 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
996 unsigned char mask = 0;
997 unsigned char pos = 0;
1002 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1005 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1006 pos = (mw->GetModeChar()-65) | mask;
1008 modewatchers[pos].push_back(mw);
1013 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1015 unsigned char mask = 0;
1016 unsigned char pos = 0;
1021 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1024 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1025 pos = (mw->GetModeChar()-65) | mask;
1027 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1029 if (a == modewatchers[pos].end())
1034 modewatchers[pos].erase(a);
1039 /** This default implementation can remove simple user modes
1041 void ModeHandler::RemoveMode(User* user)
1043 char moderemove[MAXBUF];
1044 const char* parameters[] = { user->nick, moderemove };
1046 if (user->IsModeSet(this->GetModeChar()))
1048 sprintf(moderemove,"-%c",this->GetModeChar());
1049 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1053 /** This default implementation can remove simple channel modes
1056 void ModeHandler::RemoveMode(Channel* channel)
1058 char moderemove[MAXBUF];
1059 const char* parameters[] = { channel->name, moderemove };
1061 if (channel->IsModeSet(this->GetModeChar()))
1063 sprintf(moderemove,"-%c",this->GetModeChar());
1064 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1068 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1070 ModeHandler* modes[] =
1072 new ModeChannelSecret(Instance),
1073 new ModeChannelPrivate(Instance),
1074 new ModeChannelModerated(Instance),
1075 new ModeChannelTopicOps(Instance),
1076 new ModeChannelNoExternal(Instance),
1077 new ModeChannelInviteOnly(Instance),
1078 new ModeChannelKey(Instance),
1079 new ModeChannelLimit(Instance),
1080 new ModeChannelBan(Instance),
1081 new ModeChannelOp(Instance),
1082 new ModeChannelHalfOp(Instance),
1083 new ModeChannelVoice(Instance),
1084 new ModeUserServerNotice(Instance),
1085 new ModeUserWallops(Instance),
1086 new ModeUserInvisible(Instance),
1087 new ModeUserOperator(Instance),
1088 new ModeUserServerNoticeMask(Instance),
1092 /* Clear mode list */
1093 memset(modehandlers, 0, sizeof(modehandlers));
1094 memset(modewatchers, 0, sizeof(modewatchers));
1096 /* Last parse string */
1099 /* Initialise the RFC mode letters */
1100 for (int index = 0; modes[index]; index++)
1101 this->AddMode(modes[index]);