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)
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)
62 ModeHandler::~ModeHandler()
66 bool ModeHandler::IsListMode()
71 unsigned int ModeHandler::GetPrefixRank()
76 unsigned int ModeHandler::GetCount()
81 void ModeHandler::ChangeCount(int modifier)
84 ServerInstance->Log(DEBUG,"Change count for mode %c is now %d", mode, count);
87 ModeType ModeHandler::GetModeType()
92 bool ModeHandler::NeedsOper()
97 char ModeHandler::GetPrefix()
102 int ModeHandler::GetNumParams(bool adding)
104 return adding ? n_params_on : n_params_off;
107 char ModeHandler::GetModeChar()
112 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool)
114 return MODEACTION_DENY;
117 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
121 return std::make_pair(dest->IsModeSet(this->mode), "");
125 return std::make_pair(channel->IsModeSet(this->mode), "");
129 void ModeHandler::DisplayList(User*, Channel*)
133 void ModeHandler::DisplayEmptyList(User*, Channel*)
137 bool ModeHandler::CheckTimeStamp(time_t theirs, time_t ours, const std::string&, const std::string&, Channel*)
139 return (ours < theirs);
142 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
146 ModeWatcher::~ModeWatcher()
150 char ModeWatcher::GetModeChar()
155 ModeType ModeWatcher::GetModeType()
160 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
165 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
169 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
172 if ((!user) || (!dest) || (!chan) || (!*dest))
176 d = ServerInstance->FindNick(dest);
179 user->WriteServ("401 %s %s :No such nick/channel",user->nick, dest);
185 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
190 UCListIter n = d->chans.find(chan);
191 if (n != d->chans.end())
193 if (n->second & MASK)
197 n->second = n->second | MASK;
201 n->first->AddOppedUser(d);
204 n->first->AddHalfoppedUser(d);
207 n->first->AddVoicedUser(d);
215 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
220 UCListIter n = d->chans.find(chan);
221 if (n != d->chans.end())
223 if ((n->second & MASK) == 0)
231 n->first->DelOppedUser(d);
234 n->first->DelHalfoppedUser(d);
237 n->first->DelVoicedUser(d);
245 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
249 /* Display channel's current mode string */
250 user->WriteServ("324 %s %s +%s",user->nick, targetchannel->name, targetchannel->ChanModes(targetchannel->HasUser(user)));
251 user->WriteServ("329 %s %s %lu", user->nick, targetchannel->name, (unsigned long)targetchannel->age);
256 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
258 user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
262 if ((targetuser == user) || (IS_OPER(user)))
264 /* Display user's current mode string */
265 user->WriteServ("221 %s :+%s",targetuser->nick,targetuser->FormatModes());
266 if (IS_OPER(targetuser))
267 user->WriteServ("008 %s +%s :Server notice mask", targetuser->nick, targetuser->FormatNoticeMasks());
272 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
277 /* No such nick/channel */
278 user->WriteServ("401 %s %s :No such nick/channel",user->nick, text);
282 void ModeParser::Process(const char** parameters, int pcnt, User *user, bool servermode)
284 std::string target = parameters[0];
285 ModeType type = MODETYPE_USER;
286 unsigned char mask = 0;
287 Channel* targetchannel = ServerInstance->FindChan(parameters[0]);
288 User* targetuser = ServerInstance->FindNick(parameters[0]);
292 /* Special case for displaying the list for listmodes,
293 * e.g. MODE #chan b, or MODE #chan +b without a parameter
295 if ((targetchannel) && (pcnt == 2))
297 const char* mode = parameters[1];
298 int nonlistmodes_found = 0;
303 memset(&sent, 0, 256);
305 while (mode && *mode)
307 unsigned char mletter = *mode;
310 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, *mode, "", true, 0));
311 if (MOD_RESULT == ACR_DENY)
323 /* Ensure the user doesnt request the same mode twice,
324 * so they cant flood themselves off out of idiocy.
328 sent[mletter] = true;
336 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
339 if ((mh) && (mh->IsListMode()))
341 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
343 user->WriteServ("482 %s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
344 mh->DisplayEmptyList(user, targetchannel);
348 /** See below for a description of what craq this is :D
350 unsigned char handler_id = (*mode - 65) | mask;
352 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
354 std::string dummyparam;
356 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
361 mh->DisplayList(user, targetchannel);
364 nonlistmodes_found++;
369 /* We didnt have any modes that were non-list, we can return here */
370 if (!nonlistmodes_found)
376 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
382 type = MODETYPE_CHANNEL;
385 /* Extra security checks on channel modes
386 * (e.g. are they a (half)op?
389 if ((IS_LOCAL(user)) && (targetchannel->GetStatus(user) < STATUS_HOP))
391 /* We don't have halfop */
393 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
394 if (MOD_RESULT == ACR_DENY)
397 if (MOD_RESULT == ACR_DEFAULT)
399 /* Are we a uline or is it a servermode? */
400 if ((!ServerInstance->ULine(user->server)) && (!servermode))
402 /* Not enough permission:
403 * NOT a uline and NOT a servermode,
404 * OR, NOT halfop or above.
406 user->WriteServ("482 %s %s :You're not a channel %soperator",user->nick, targetchannel->name,
407 ServerInstance->Config->AllowHalfop ? "(half)" : "");
415 type = MODETYPE_USER;
417 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
419 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
425 /* No such nick/channel */
426 user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
430 std::string mode_sequence = parameters[1];
431 std::string parameter;
432 std::ostringstream parameter_list;
433 std::string output_sequence;
434 bool adding = true, state_change = false;
435 unsigned char handler_id = 0;
436 int parameter_counter = 2; /* Index of first parameter */
437 int parameter_count = 0;
438 bool last_successful_state_change = false;
440 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
441 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
442 mode_sequence.insert(0, "+");
444 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
446 unsigned char modechar = *letter;
451 * For + and - mode characters, we don't just stick the character into the output sequence.
452 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
453 * appearing in the output sequence, we store a flag which says there was a state change,
454 * which is set on any + or -, however, the + or - that we finish on is only appended to
455 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
458 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
459 * however, will allow the + if it is the first item in the sequence, regardless.
461 if ((!adding) || (!output_sequence.length()))
464 if (!output_sequence.length())
465 last_successful_state_change = false;
469 if ((adding) || (!output_sequence.length()))
472 if (!output_sequence.length())
473 last_successful_state_change = true;
479 * Watch carefully for the sleight of hand trick.
480 * 65 is the ascii value of 'A'. We take this from
481 * the char we're looking at to get a number between
482 * 1 and 127. We then logic-or it to get the hashed
483 * position, dependent on wether its a channel or
484 * a user mode. This is a little stranger, but a lot
485 * faster, than using a map of pairs.
487 handler_id = (modechar - 65) | mask;
489 if (modehandlers[handler_id])
493 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 */
513 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, parameter, adding, 1));
514 if (MOD_RESULT == ACR_DENY)
517 bool had_parameter = !parameter.empty();
519 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
521 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
526 /* A module whacked the parameter completely, and there was one. abort. */
527 if ((had_parameter) && (parameter.empty()))
540 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, targetchannel, modechar, "", adding, 0));
541 if (MOD_RESULT == ACR_DENY)
544 /* Fix by brain: mode watchers not being called for parameterless modes */
545 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
547 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
558 /* It's an oper only mode, check if theyre an oper. If they arent,
559 * eat any parameter that came with the mode, and continue to next
561 if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
563 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
564 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
565 modehandlers[handler_id]->GetModeChar());
569 /* Call the handler for the mode */
570 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
572 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
574 /* The handler nuked the parameter and they are supposed to have one.
575 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
576 * so we bail to the next mode character.
581 if (ma == MODEACTION_ALLOW)
583 /* We're about to output a valid mode letter - was there previously a pending state-change? */
586 if (adding != last_successful_state_change)
587 output_sequence.append(adding ? "+" : "-");
588 last_successful_state_change = adding;
591 /* Add the mode letter */
592 output_sequence.push_back(modechar);
594 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
596 /* Is there a valid parameter for this mode? If so add it to the parameter list */
597 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
599 parameter_list << " " << parameter;
601 /* Does this mode have a prefix? */
602 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
604 User* user_to_prefix = ServerInstance->FindNick(parameter);
606 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
607 modehandlers[handler_id]->GetPrefixRank(), adding);
611 /* Call all the AfterMode events in the mode watchers for this mode */
612 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
613 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);
615 /* Reset the state change flag */
616 state_change = false;
618 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
619 || (parameter_count > MAXMODES))
621 /* We cant have a mode sequence this long */
622 letter = mode_sequence.end() - 1;
630 /* No mode handler? Unknown mode character then. */
631 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
637 /* Was there at least one valid mode in the sequence? */
638 if (!output_sequence.empty())
642 if (type == MODETYPE_CHANNEL)
644 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
645 this->LastParse = targetchannel->name;
649 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
650 this->LastParse = targetuser->nick;
655 if (type == MODETYPE_CHANNEL)
657 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
658 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
659 this->LastParse = targetchannel->name;
663 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
664 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
665 this->LastParse = targetuser->nick;
669 LastParse.append(" ");
670 LastParse.append(output_sequence);
671 LastParse.append(parameter_list.str());
676 const std::string& ModeParser::GetLastParse()
681 void ModeParser::CleanMask(std::string &mask)
683 std::string::size_type pos_of_pling = mask.find_first_of('!');
684 std::string::size_type pos_of_at = mask.find_first_of('@');
685 std::string::size_type pos_of_dot = mask.find_first_of('.');
686 std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
688 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
690 /* Just a nick, or just a host */
691 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
693 /* It has no '.' in it, it must be a nick. */
698 /* Got a dot in it? Has to be a host */
699 mask = "*!*@" + mask;
702 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
704 /* Has an @ but no !, its a user@host */
707 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
709 /* Has a ! but no @, it must be a nick!ident */
714 bool ModeParser::AddMode(ModeHandler* mh)
716 unsigned char mask = 0;
717 unsigned char pos = 0;
719 /* Yes, i know, this might let people declare modes like '_' or '^'.
720 * If they do that, thats their problem, and if i ever EVER see an
721 * official InspIRCd developer do that, i'll beat them with a paddle!
723 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
726 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
727 * A mode prefix of ':' will fuck up both server to server, and client to server.
728 * A mode prefix of '#' will mess up /whois and /privmsg
730 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
733 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
734 pos = (mh->GetModeChar()-65) | mask;
736 if (modehandlers[pos])
739 modehandlers[pos] = mh;
743 bool ModeParser::DelMode(ModeHandler* mh)
745 unsigned char mask = 0;
746 unsigned char pos = 0;
748 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
751 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
752 pos = (mh->GetModeChar()-65) | mask;
754 if (!modehandlers[pos])
757 switch (mh->GetModeType())
760 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
762 mh->RemoveMode(i->second);
765 case MODETYPE_CHANNEL:
766 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
768 mh->RemoveMode(i->second);
773 modehandlers[pos] = NULL;
778 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
780 unsigned char mask = 0;
781 unsigned char pos = 0;
783 if ((modeletter < 'A') || (modeletter > 'z'))
786 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
787 pos = (modeletter-65) | mask;
789 return modehandlers[pos];
792 std::string ModeParser::UserModeList()
797 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
799 unsigned char pos = (mode-65) | MASK_USER;
801 if (modehandlers[pos])
802 modestr[pointer++] = mode;
804 modestr[pointer++] = 0;
808 std::string ModeParser::ChannelModeList()
813 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
815 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
818 unsigned char pos = (mode-65) | MASK_CHANNEL;
820 if (modehandlers[pos])
821 modestr[pointer++] = mode;
823 modestr[pointer++] = 0;
827 std::string ModeParser::ParaModeList()
832 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
834 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
837 unsigned char pos = (mode-65) | MASK_CHANNEL;
839 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
840 modestr[pointer++] = mode;
842 modestr[pointer++] = 0;
846 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
848 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
850 unsigned char pos = (mode-65) | MASK_CHANNEL;
852 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
854 return modehandlers[pos];
860 std::string ModeParser::ModeString(User* user, Channel* channel)
865 if (!channel || !user)
868 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
870 unsigned char pos = (mode-65) | MASK_CHANNEL;
871 ModeHandler* mh = modehandlers[pos];
872 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
875 ret = mh->ModeSet(NULL, user, channel, user->nick);
876 if ((ret.first) && (ret.second == user->nick))
879 pars.append(user->nick);
880 types.push_back(mh->GetModeChar());
888 std::string ModeParser::ChanModes()
890 std::string type1; /* Listmodes EXCEPT those with a prefix */
891 std::string type2; /* Modes that take a param when adding or removing */
892 std::string type3; /* Modes that only take a param when adding */
893 std::string type4; /* Modes that dont take a param */
895 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
897 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
900 unsigned char pos = (mode-65) | MASK_CHANNEL;
901 /* One parameter when adding */
902 if (modehandlers[pos])
904 if (modehandlers[pos]->GetNumParams(true))
906 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
908 type1 += modehandlers[pos]->GetModeChar();
912 /* ... and one parameter when removing */
913 if (modehandlers[pos]->GetNumParams(false))
915 /* But not a list mode */
916 if (!modehandlers[pos]->GetPrefix())
918 type2 += modehandlers[pos]->GetModeChar();
923 /* No parameters when removing */
924 type3 += modehandlers[pos]->GetModeChar();
930 type4 += modehandlers[pos]->GetModeChar();
936 return type1 + "," + type2 + "," + type3 + "," + type4;
939 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
941 return one.second > two.second;
944 std::string ModeParser::BuildPrefixes()
946 std::string mletters;
947 std::string mprefixes;
949 std::map<char,char> prefix_to_mode;
951 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
953 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
956 unsigned char pos = (mode-65) | MASK_CHANNEL;
958 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
960 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
961 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
965 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
967 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
969 mletters = mletters + n->first;
970 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
973 return "(" + mprefixes + ")" + mletters;
976 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
978 unsigned char mask = 0;
979 unsigned char pos = 0;
984 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
987 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
988 pos = (mw->GetModeChar()-65) | mask;
990 modewatchers[pos].push_back(mw);
995 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
997 unsigned char mask = 0;
998 unsigned char pos = 0;
1003 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1006 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1007 pos = (mw->GetModeChar()-65) | mask;
1009 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1011 if (a == modewatchers[pos].end())
1016 modewatchers[pos].erase(a);
1021 /** This default implementation can remove simple user modes
1023 void ModeHandler::RemoveMode(User* user)
1025 char moderemove[MAXBUF];
1026 const char* parameters[] = { user->nick, moderemove };
1028 if (user->IsModeSet(this->GetModeChar()))
1030 sprintf(moderemove,"-%c",this->GetModeChar());
1031 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1035 /** This default implementation can remove simple channel modes
1038 void ModeHandler::RemoveMode(Channel* channel)
1040 char moderemove[MAXBUF];
1041 const char* parameters[] = { channel->name, moderemove };
1043 if (channel->IsModeSet(this->GetModeChar()))
1045 sprintf(moderemove,"-%c",this->GetModeChar());
1046 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1050 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1052 ModeHandler* modes[] =
1054 new ModeChannelSecret(Instance),
1055 new ModeChannelPrivate(Instance),
1056 new ModeChannelModerated(Instance),
1057 new ModeChannelTopicOps(Instance),
1058 new ModeChannelNoExternal(Instance),
1059 new ModeChannelInviteOnly(Instance),
1060 new ModeChannelKey(Instance),
1061 new ModeChannelLimit(Instance),
1062 new ModeChannelBan(Instance),
1063 new ModeChannelOp(Instance),
1064 new ModeChannelHalfOp(Instance),
1065 new ModeChannelVoice(Instance),
1066 new ModeUserServerNotice(Instance),
1067 new ModeUserWallops(Instance),
1068 new ModeUserInvisible(Instance),
1069 new ModeUserOperator(Instance),
1070 new ModeUserServerNoticeMask(Instance),
1074 /* Clear mode list */
1075 memset(modehandlers, 0, sizeof(modehandlers));
1076 memset(modewatchers, 0, sizeof(modewatchers));
1078 /* Last parse string */
1081 /* Initialise the RFC mode letters */
1082 for (int index = 0; modes[index]; index++)
1083 this->AddMode(modes[index]);