1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2007 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;
315 /* Ensure the user doesnt request the same mode twice,
316 * so they cant flood themselves off out of idiocy.
320 sent[mletter] = true;
328 ModeHandler *mh = this->FindMode(*mode, MODETYPE_CHANNEL);
331 if ((mh) && (mh->IsListMode()))
333 if (ServerInstance->Config->HideModeLists[mletter] && (targetchannel->GetStatus(user) < STATUS_HOP))
335 user->WriteServ("482 %s %s :Only half-operators and above may view the +%c list",user->nick, targetchannel->name, *mode++);
336 mh->DisplayEmptyList(user, targetchannel);
340 /** See below for a description of what craq this is :D
342 unsigned char handler_id = (*mode - 65) | mask;
344 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
346 std::string dummyparam;
348 if (!((*watchers)->BeforeMode(user, NULL, targetchannel, dummyparam, true, MODETYPE_CHANNEL)))
353 mh->DisplayList(user, targetchannel);
356 nonlistmodes_found++;
361 /* We didnt have any modes that were non-list, we can return here */
362 if (!nonlistmodes_found)
368 this->DisplayCurrentModes(user, targetuser, targetchannel, parameters[0]);
374 type = MODETYPE_CHANNEL;
377 /* Extra security checks on channel modes
378 * (e.g. are they a (half)op?
381 if ((IS_LOCAL(user)) && (targetchannel->GetStatus(user) < STATUS_HOP))
383 /* We don't have halfop */
385 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
386 if (MOD_RESULT == ACR_DENY)
389 if (MOD_RESULT == ACR_DEFAULT)
391 /* Are we a uline or is it a servermode? */
392 if ((!ServerInstance->ULine(user->server)) && (!servermode))
394 /* Not enough permission:
395 * NOT a uline and NOT a servermode,
396 * OR, NOT halfop or above.
398 user->WriteServ("482 %s %s :You're not a channel (half)operator",user->nick, targetchannel->name);
406 type = MODETYPE_USER;
408 if ((user != targetuser) && (!ServerInstance->ULine(user->server)))
410 user->WriteServ("502 %s :Can't change mode for other users", user->nick);
416 /* No such nick/channel */
417 user->WriteServ("401 %s %s :No such nick/channel",user->nick, parameters[0]);
421 std::string mode_sequence = parameters[1];
422 std::string parameter;
423 std::ostringstream parameter_list;
424 std::string output_sequence;
425 bool adding = true, state_change = false;
426 unsigned char handler_id = 0;
427 int parameter_counter = 2; /* Index of first parameter */
428 int parameter_count = 0;
429 bool last_successful_state_change = false;
431 /* A mode sequence that doesnt start with + or -. Assume +. - Thanks for the suggestion spike (bug#132) */
432 if ((*mode_sequence.begin() != '+') && (*mode_sequence.begin() != '-'))
433 mode_sequence.insert(0, "+");
435 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
437 unsigned char modechar = *letter;
442 * For + and - mode characters, we don't just stick the character into the output sequence.
443 * This is because the user may do something dumb, like: +-+ooo or +oo-+. To prevent this
444 * appearing in the output sequence, we store a flag which says there was a state change,
445 * which is set on any + or -, however, the + or - that we finish on is only appended to
446 * the output stream in the event it is followed by a non "+ or -" character, such as o or v.
449 /* The following expression prevents: +o+o nick nick, compressing it to +oo nick nick,
450 * however, will allow the + if it is the first item in the sequence, regardless.
452 if ((!adding) || (!output_sequence.length()))
455 if (!output_sequence.length())
456 last_successful_state_change = false;
460 if ((adding) || (!output_sequence.length()))
463 if (!output_sequence.length())
464 last_successful_state_change = true;
470 * Watch carefully for the sleight of hand trick.
471 * 65 is the ascii value of 'A'. We take this from
472 * the char we're looking at to get a number between
473 * 1 and 127. We then logic-or it to get the hashed
474 * position, dependent on wether its a channel or
475 * a user mode. This is a little stranger, but a lot
476 * faster, than using a map of pairs.
478 handler_id = (modechar - 65) | mask;
480 if (modehandlers[handler_id])
484 if (modehandlers[handler_id]->GetModeType() == type)
486 if (modehandlers[handler_id]->GetNumParams(adding))
488 /* This mode expects a parameter, do we have any parameters left in our list to use? */
489 if (parameter_counter < pcnt)
491 parameter = parameters[parameter_counter++];
494 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
499 /* No parameter, continue to the next mode */
503 bool had_parameter = !parameter.empty();
505 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
507 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
512 /* A module whacked the parameter completely, and there was one. abort. */
513 if ((had_parameter) && (parameter.empty()))
525 /* Fix by brain: mode watchers not being called for parameterless modes */
526 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
528 if ((*watchers)->BeforeMode(user, targetuser, targetchannel, parameter, adding, type) == false)
539 /* It's an oper only mode, check if theyre an oper. If they arent,
540 * eat any parameter that came with the mode, and continue to next
542 if ((IS_LOCAL(user)) && (modehandlers[handler_id]->NeedsOper()) && (!IS_OPER(user)))
544 user->WriteServ("481 %s :Permission Denied - Only IRC operators may %sset %s mode %c", user->nick,
545 adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user",
546 modehandlers[handler_id]->GetModeChar());
550 /* Call the handler for the mode */
551 ModeAction ma = modehandlers[handler_id]->OnModeChange(user, targetuser, targetchannel, parameter, adding);
553 if ((modehandlers[handler_id]->GetNumParams(adding)) && (parameter.empty()))
555 /* The handler nuked the parameter and they are supposed to have one.
556 * We CANT continue now, even if they actually returned MODEACTION_ALLOW,
557 * so we bail to the next mode character.
562 if (ma == MODEACTION_ALLOW)
564 /* We're about to output a valid mode letter - was there previously a pending state-change? */
567 if (adding != last_successful_state_change)
568 output_sequence.append(adding ? "+" : "-");
569 last_successful_state_change = adding;
572 /* Add the mode letter */
573 output_sequence.push_back(modechar);
575 modehandlers[handler_id]->ChangeCount(adding ? 1 : -1);
577 /* Is there a valid parameter for this mode? If so add it to the parameter list */
578 if ((modehandlers[handler_id]->GetNumParams(adding)) && (!parameter.empty()))
580 parameter_list << " " << parameter;
582 /* Does this mode have a prefix? */
583 if (modehandlers[handler_id]->GetPrefix() && targetchannel)
585 User* user_to_prefix = ServerInstance->FindNick(parameter);
587 targetchannel->SetPrefix(user_to_prefix, modehandlers[handler_id]->GetPrefix(),
588 modehandlers[handler_id]->GetPrefixRank(), adding);
592 /* Call all the AfterMode events in the mode watchers for this mode */
593 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
594 (*watchers)->AfterMode(user, targetuser, targetchannel, parameter, adding, type);
596 /* Reset the state change flag */
597 state_change = false;
599 if ((output_sequence.length() + parameter_list.str().length() > 450) || (output_sequence.length() > 100)
600 || (parameter_count > MAXMODES))
602 /* We cant have a mode sequence this long */
603 letter = mode_sequence.end() - 1;
611 /* No mode handler? Unknown mode character then. */
612 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick, modechar);
618 /* Was there at least one valid mode in the sequence? */
619 if (!output_sequence.empty())
623 if (type == MODETYPE_CHANNEL)
625 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s %s%s", targetchannel->name, output_sequence.c_str(), parameter_list.str().c_str());
626 this->LastParse = targetchannel->name;
630 targetuser->WriteServ("MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
631 this->LastParse = targetuser->nick;
636 if (type == MODETYPE_CHANNEL)
638 targetchannel->WriteChannel(user,"MODE %s %s%s",targetchannel->name,output_sequence.c_str(),parameter_list.str().c_str());
639 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, output_sequence + parameter_list.str()));
640 this->LastParse = targetchannel->name;
644 user->WriteTo(targetuser,"MODE %s %s%s",targetuser->nick,output_sequence.c_str(), parameter_list.str().c_str());
645 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, output_sequence + parameter_list.str()));
646 this->LastParse = targetuser->nick;
650 LastParse.append(" ");
651 LastParse.append(output_sequence);
652 LastParse.append(parameter_list.str());
657 const std::string& ModeParser::GetLastParse()
662 void ModeParser::CleanMask(std::string &mask)
664 std::string::size_type pos_of_pling = mask.find_first_of('!');
665 std::string::size_type pos_of_at = mask.find_first_of('@');
666 std::string::size_type pos_of_dot = mask.find_first_of('.');
667 std::string::size_type pos_of_colon = mask.find_first_of(':'); /* Because ipv6 addresses are colon delimited */
669 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
671 /* Just a nick, or just a host */
672 if ((pos_of_dot == std::string::npos) && (pos_of_colon == std::string::npos))
674 /* It has no '.' in it, it must be a nick. */
679 /* Got a dot in it? Has to be a host */
680 mask = "*!*@" + mask;
683 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
685 /* Has an @ but no !, its a user@host */
688 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
690 /* Has a ! but no @, it must be a nick!ident */
695 bool ModeParser::AddMode(ModeHandler* mh)
697 unsigned char mask = 0;
698 unsigned char pos = 0;
700 /* Yes, i know, this might let people declare modes like '_' or '^'.
701 * If they do that, thats their problem, and if i ever EVER see an
702 * official InspIRCd developer do that, i'll beat them with a paddle!
704 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
707 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
708 * A mode prefix of ':' will fuck up both server to server, and client to server.
709 * A mode prefix of '#' will mess up /whois and /privmsg
711 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
714 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
715 pos = (mh->GetModeChar()-65) | mask;
717 if (modehandlers[pos])
720 modehandlers[pos] = mh;
724 bool ModeParser::DelMode(ModeHandler* mh)
726 unsigned char mask = 0;
727 unsigned char pos = 0;
729 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
732 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
733 pos = (mh->GetModeChar()-65) | mask;
735 if (!modehandlers[pos])
738 switch (mh->GetModeType())
741 for (user_hash::iterator i = ServerInstance->clientlist->begin(); i != ServerInstance->clientlist->end(); i++)
743 mh->RemoveMode(i->second);
746 case MODETYPE_CHANNEL:
747 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
749 mh->RemoveMode(i->second);
754 modehandlers[pos] = NULL;
759 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
761 unsigned char mask = 0;
762 unsigned char pos = 0;
764 if ((modeletter < 'A') || (modeletter > 'z'))
767 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
768 pos = (modeletter-65) | mask;
770 return modehandlers[pos];
773 std::string ModeParser::UserModeList()
778 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
780 unsigned char pos = (mode-65) | MASK_USER;
782 if (modehandlers[pos])
783 modestr[pointer++] = mode;
785 modestr[pointer++] = 0;
789 std::string ModeParser::ChannelModeList()
794 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
796 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
799 unsigned char pos = (mode-65) | MASK_CHANNEL;
801 if (modehandlers[pos])
802 modestr[pointer++] = mode;
804 modestr[pointer++] = 0;
808 std::string ModeParser::ParaModeList()
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]) && (modehandlers[pos]->GetNumParams(true)))
821 modestr[pointer++] = mode;
823 modestr[pointer++] = 0;
827 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
829 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
831 unsigned char pos = (mode-65) | MASK_CHANNEL;
833 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
835 return modehandlers[pos];
841 std::string ModeParser::ModeString(User* user, Channel* channel)
846 if (!channel || !user)
849 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
851 unsigned char pos = (mode-65) | MASK_CHANNEL;
852 ModeHandler* mh = modehandlers[pos];
853 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
856 ret = mh->ModeSet(NULL, user, channel, user->nick);
857 if ((ret.first) && (ret.second == user->nick))
860 pars.append(user->nick);
861 types.push_back(mh->GetModeChar());
869 std::string ModeParser::ChanModes()
871 std::string type1; /* Listmodes EXCEPT those with a prefix */
872 std::string type2; /* Modes that take a param when adding or removing */
873 std::string type3; /* Modes that only take a param when adding */
874 std::string type4; /* Modes that dont take a param */
876 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
878 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
881 unsigned char pos = (mode-65) | MASK_CHANNEL;
882 /* One parameter when adding */
883 if (modehandlers[pos])
885 if (modehandlers[pos]->GetNumParams(true))
887 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
889 type1 += modehandlers[pos]->GetModeChar();
893 /* ... and one parameter when removing */
894 if (modehandlers[pos]->GetNumParams(false))
896 /* But not a list mode */
897 if (!modehandlers[pos]->GetPrefix())
899 type2 += modehandlers[pos]->GetModeChar();
904 /* No parameters when removing */
905 type3 += modehandlers[pos]->GetModeChar();
911 type4 += modehandlers[pos]->GetModeChar();
917 return type1 + "," + type2 + "," + type3 + "," + type4;
920 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
922 return one.second > two.second;
925 std::string ModeParser::BuildPrefixes()
927 std::string mletters;
928 std::string mprefixes;
930 std::map<char,char> prefix_to_mode;
932 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
934 if ((!ServerInstance->Config->AllowHalfop) && (mode == 'h'))
937 unsigned char pos = (mode-65) | MASK_CHANNEL;
939 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
941 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
942 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
946 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
948 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
950 mletters = mletters + n->first;
951 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
954 return "(" + mprefixes + ")" + mletters;
957 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
959 unsigned char mask = 0;
960 unsigned char pos = 0;
965 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
968 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
969 pos = (mw->GetModeChar()-65) | mask;
971 modewatchers[pos].push_back(mw);
976 bool ModeParser::DelModeWatcher(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 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
992 if (a == modewatchers[pos].end())
997 modewatchers[pos].erase(a);
1002 /** This default implementation can remove simple user modes
1004 void ModeHandler::RemoveMode(User* user)
1006 char moderemove[MAXBUF];
1007 const char* parameters[] = { user->nick, moderemove };
1009 if (user->IsModeSet(this->GetModeChar()))
1011 sprintf(moderemove,"-%c",this->GetModeChar());
1012 ServerInstance->Parser->CallHandler("MODE", parameters, 2, user);
1016 /** This default implementation can remove simple channel modes
1019 void ModeHandler::RemoveMode(Channel* channel)
1021 char moderemove[MAXBUF];
1022 const char* parameters[] = { channel->name, moderemove };
1024 if (channel->IsModeSet(this->GetModeChar()))
1026 sprintf(moderemove,"-%c",this->GetModeChar());
1027 ServerInstance->SendMode(parameters, 2, ServerInstance->FakeClient);
1031 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1033 ModeHandler* modes[] =
1035 new ModeChannelSecret(Instance),
1036 new ModeChannelPrivate(Instance),
1037 new ModeChannelModerated(Instance),
1038 new ModeChannelTopicOps(Instance),
1039 new ModeChannelNoExternal(Instance),
1040 new ModeChannelInviteOnly(Instance),
1041 new ModeChannelKey(Instance),
1042 new ModeChannelLimit(Instance),
1043 new ModeChannelBan(Instance),
1044 new ModeChannelOp(Instance),
1045 new ModeChannelHalfOp(Instance),
1046 new ModeChannelVoice(Instance),
1047 new ModeUserServerNotice(Instance),
1048 new ModeUserWallops(Instance),
1049 new ModeUserInvisible(Instance),
1050 new ModeUserOperator(Instance),
1051 new ModeUserServerNoticeMask(Instance),
1055 /* Clear mode list */
1056 memset(modehandlers, 0, sizeof(modehandlers));
1057 memset(modewatchers, 0, sizeof(modewatchers));
1059 /* Last parse string */
1062 /* Initialise the RFC mode letters */
1063 for (int index = 0; modes[index]; index++)
1064 this->AddMode(modes[index]);