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))
520 if (IS_LOCAL(user) && (MOD_RESULT != ACR_ALLOW))
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);
529 unsigned int neededrank = prefixmode->GetPrefixRank();
530 /* Compare our rank on the channel against the rank of the required prefix,
531 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
532 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
533 * first, so we don't need to iterate, we just look up the first instead.
535 std::string modestring = targetchannel->GetAllPrefixChars(user);
536 if (!modestring.empty())
538 ModeHandler* ourmode = FindPrefix(modestring[0]);
539 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
542 user->WriteServ("482 %s %s :You require channel privilege '%c' or above to execute channel mode '%c'",
543 user->nick, targetchannel->name, needed, modechar);
551 bool had_parameter = !parameter.empty();
553 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
555 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
560 /* A module whacked the parameter completely, and there was one. abort. */
561 if ((had_parameter) && (parameter.empty()))
571 /* It's an oper only mode, check if theyre an oper. If they arent,
572 * eat any parameter that came with the mode, and continue to next
574 if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
576 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
577 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
578 modehandlers[handler_id]->GetModeChar());
582 /* Call the handler for the mode */
583 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
585 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
587 /* The handler nuked the parameter and they are supposed to have one.
588 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
589 * so we bail to the next mode character.
594 if (ma == MODEACTION_ALLOW)
596 /* We're about to output a valid mode letter - was there previously a pending state-change? */
599 if (adding != last_successful_state_change)
600 output_sequence.append(adding ? "+" : "-");
601 last_successful_state_change = adding;
604 /* Add the mode letter */
605 output_sequence.push_back(modechar);
607 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
609 /* Is there a valid parameter for this mode? If so add it to the parameter list */
610 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
612 parameter_list << " " << parameter;
614 /* Does this mode have a prefix? */
615 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
617 User* user_to_prefix = ServerInstance->FindNick(parameter);
619 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
620 modehandlers[handler_id]->GetPrefixRank(), adding);
624 /* Call all the AfterMode events in the mode watchers for this mode */
625 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
626 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);
628 /* Reset the state change flag */
629 state_change = false;
631 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
632 || (parameter_count > MAXMODES))
634 /* We cant have a mode sequence this long */
635 letter = mode_sequence.end() - 1;
643 /* No mode handler? Unknown mode character then. */
644 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
650 /* Was there at least one valid mode in the sequence? */
651 if (!output_sequence.empty())
655 if (type == MODETYPE_CHANNEL)
657 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
658 this->LastParse = targetchannel->name;
662 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
663 this->LastParse = targetuser->nick;
668 if (type == MODETYPE_CHANNEL)
670 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
671 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
672 this->LastParse = targetchannel->name;
676 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
677 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
678 this->LastParse = targetuser->nick;
682 LastParse.append(" ");
683 LastParse.append(output_sequence);
684 LastParse.append(parameter_list.str());
689 const std::string& ModeParser::GetLastParse()
694 void ModeParser::CleanMask(std::string &mask)
696 std::string::size_type pos_of_pling = mask.find_first_of('!');
697 std::string::size_type pos_of_at = mask.find_first_of('@');
698 std::string::size_type pos_of_dot = mask.find_first_of('.');
699 std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
701 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
703 /* Just a nick, or just a host */
704 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
706 /* It has no '.' in it, it must be a nick. */
711 /* Got a dot in it? Has to be a host */
712 mask = "*!*@" + mask;
715 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
717 /* Has an @ but no !, its a user@host */
720 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
722 /* Has a ! but no @, it must be a nick!ident */
727 bool ModeParser::AddMode(ModeHandler* mh)
729 unsigned char mask = 0;
730 unsigned char pos = 0;
732 /* Yes, i know, this might let people declare modes like '_' or '^'.
733 * If they do that, thats their problem, and if i ever EVER see an
734 * official InspIRCd developer do that, i'll beat them with a paddle!
736 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
739 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
740 * A mode prefix of ':' will fuck up both server to server, and client to server.
741 * A mode prefix of '#' will mess up /whois and /privmsg
743 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
746 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
747 pos = (mh->GetModeChar()-65) | mask;
749 if (modehandlers[pos])
752 modehandlers[pos] = mh;
756 bool ModeParser::DelMode(ModeHandler* mh)
758 unsigned char mask = 0;
759 unsigned char pos = 0;
761 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
764 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
765 pos = (mh->GetModeChar()-65) | mask;
767 if (!modehandlers[pos])
770 switch (mh->GetModeType())
773 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
775 mh->RemoveMode(i->second);
778 case MODETYPE_CHANNEL:
779 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
781 mh->RemoveMode(i->second);
786 modehandlers[pos] = NULL;
791 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
793 unsigned char mask = 0;
794 unsigned char pos = 0;
796 if ((modeletter < 'A') || (modeletter > 'z'))
799 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
800 pos = (modeletter-65) | mask;
802 return modehandlers[pos];
805 std::string ModeParser::UserModeList()
810 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
812 unsigned char pos = (mode-65) | MASK_USER;
814 if (modehandlers[pos])
815 modestr[pointer++] = mode;
817 modestr[pointer++] = 0;
821 std::string ModeParser::ChannelModeList()
826 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
828 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
831 unsigned char pos = (mode-65) | MASK_CHANNEL;
833 if (modehandlers[pos])
834 modestr[pointer++] = mode;
836 modestr[pointer++] = 0;
840 std::string ModeParser::ParaModeList()
845 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
847 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
850 unsigned char pos = (mode-65) | MASK_CHANNEL;
852 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
853 modestr[pointer++] = mode;
855 modestr[pointer++] = 0;
859 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
861 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
863 unsigned char pos = (mode-65) | MASK_CHANNEL;
865 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
867 return modehandlers[pos];
873 std::string ModeParser::ModeString(User* user, Channel* channel)
878 if (!channel || !user)
881 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
883 unsigned char pos = (mode-65) | MASK_CHANNEL;
884 ModeHandler* mh = modehandlers[pos];
885 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
888 ret = mh->ModeSet(NULL, user, channel, user->nick);
889 if ((ret.first) && (ret.second == user->nick))
892 pars.append(user->nick);
893 types.push_back(mh->GetModeChar());
901 std::string ModeParser::ChanModes()
903 std::string type1; /* Listmodes EXCEPT those with a prefix */
904 std::string type2; /* Modes that take a param when adding or removing */
905 std::string type3; /* Modes that only take a param when adding */
906 std::string type4; /* Modes that dont take a param */
908 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
910 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
913 unsigned char pos = (mode-65) | MASK_CHANNEL;
914 /* One parameter when adding */
915 if (modehandlers[pos])
917 if (modehandlers[pos]->GetNumParams(true))
919 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
921 type1 += modehandlers[pos]->GetModeChar();
925 /* ... and one parameter when removing */
926 if (modehandlers[pos]->GetNumParams(false))
928 /* But not a list mode */
929 if (!modehandlers[pos]->GetPrefix())
931 type2 += modehandlers[pos]->GetModeChar();
936 /* No parameters when removing */
937 type3 += modehandlers[pos]->GetModeChar();
943 type4 += modehandlers[pos]->GetModeChar();
949 return type1 + "," + type2 + "," + type3 + "," + type4;
952 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
954 return one.second > two.second;
957 std::string ModeParser::BuildPrefixes()
959 std::string mletters;
960 std::string mprefixes;
962 std::map<char,char> prefix_to_mode;
964 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
966 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
969 unsigned char pos = (mode-65) | MASK_CHANNEL;
971 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
973 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
974 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
978 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
980 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
982 mletters = mletters + n->first;
983 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
986 return "(" + mprefixes + ")" + mletters;
989 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
991 unsigned char mask = 0;
992 unsigned char pos = 0;
997 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1000 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1001 pos = (mw->GetModeChar()-65) | mask;
1003 modewatchers[pos].push_back(mw);
1008 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1010 unsigned char mask = 0;
1011 unsigned char pos = 0;
1016 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1019 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1020 pos = (mw->GetModeChar()-65) | mask;
1022 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1024 if (a == modewatchers[pos].end())
1029 modewatchers[pos].erase(a);
1034 /** This default implementation can remove simple user modes
1036 void ModeHandler::RemoveMode(User* user)
1038 char moderemove[MAXBUF];
1039 const char* parameters[] = { user->nick, moderemove };
1041 if (user->IsModeSet(this->GetModeChar()))
1043 sprintf(moderemove,"-%c",this->GetModeChar());
1044 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1048 /** This default implementation can remove simple channel modes
1051 void ModeHandler::RemoveMode(Channel* channel)
1053 char moderemove[MAXBUF];
1054 const char* parameters[] = { channel->name, moderemove };
1056 if (channel->IsModeSet(this->GetModeChar()))
1058 sprintf(moderemove,"-%c",this->GetModeChar());
1059 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1063 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1065 ModeHandler* modes[] =
1067 new ModeChannelSecret(Instance),
1068 new ModeChannelPrivate(Instance),
1069 new ModeChannelModerated(Instance),
1070 new ModeChannelTopicOps(Instance),
1071 new ModeChannelNoExternal(Instance),
1072 new ModeChannelInviteOnly(Instance),
1073 new ModeChannelKey(Instance),
1074 new ModeChannelLimit(Instance),
1075 new ModeChannelBan(Instance),
1076 new ModeChannelOp(Instance),
1077 new ModeChannelHalfOp(Instance),
1078 new ModeChannelVoice(Instance),
1079 new ModeUserServerNotice(Instance),
1080 new ModeUserWallops(Instance),
1081 new ModeUserInvisible(Instance),
1082 new ModeUserOperator(Instance),
1083 new ModeUserServerNoticeMask(Instance),
1087 /* Clear mode list */
1088 memset(modehandlers, 0, sizeof(modehandlers));
1089 memset(modewatchers, 0, sizeof(modewatchers));
1091 /* Last parse string */
1094 /* Initialise the RFC mode letters */
1095 for (int index = 0; modes[index]; index++)
1096 this->AddMode(modes[index]);