1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2009 InspIRCd Development Team
6 * See: http://wiki.inspircd.org/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
17 #include "inspstring.h"
20 #include "modes/cmode_s.h"
22 #include "modes/cmode_p.h"
24 #include "modes/cmode_b.h"
26 #include "modes/cmode_m.h"
27 /* +t (only (half) ops can change topic) */
28 #include "modes/cmode_t.h"
29 /* +n (no external messages) */
30 #include "modes/cmode_n.h"
31 /* +i (invite only) */
32 #include "modes/cmode_i.h"
33 /* +k (keyed channel) */
34 #include "modes/cmode_k.h"
35 /* +l (channel user limit) */
36 #include "modes/cmode_l.h"
38 #include "modes/cmode_o.h"
39 /* +h (channel halfop) */
40 #include "modes/cmode_h.h"
41 /* +v (channel voice) */
42 #include "modes/cmode_v.h"
43 /* +w (see wallops) */
44 #include "modes/umode_w.h"
46 #include "modes/umode_i.h"
48 #include "modes/umode_o.h"
49 /* +s (server notice masks) */
50 #include "modes/umode_s.h"
52 ModeHandler::ModeHandler(Module* Creator, char modeletter, ParamSpec Params, ModeType type)
53 : mode(modeletter), parameters_taken(Params), list(false), m_type(type), m_paramtype(TR_TEXT),
54 oper(false), prefix(0), count(0), levelrequired(HALFOP_VALUE), creator(Creator)
58 ModeHandler::~ModeHandler()
62 bool ModeHandler::IsListMode()
67 unsigned int ModeHandler::GetPrefixRank()
72 unsigned int ModeHandler::GetCount()
77 void ModeHandler::ChangeCount(int modifier)
80 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
83 int ModeHandler::GetNumParams(bool adding)
85 switch (parameters_taken)
90 return adding ? 1 : 0;
97 char ModeHandler::GetModeChar()
102 std::string ModeHandler::GetUserParameter(User* user)
107 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool)
109 return MODEACTION_DENY;
112 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
116 return std::make_pair(dest->IsModeSet(this->mode), "");
120 return std::make_pair(channel->IsModeSet(this->mode), "");
124 void ModeHandler::DisplayList(User*, Channel*)
128 void ModeHandler::DisplayEmptyList(User*, Channel*)
132 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
136 bool ModeHandler::CheckTimeStamp(std::string& theirs, const std::string& ours, Channel*)
138 return (theirs < ours);
141 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
145 if (!dest->IsModeSet(this->GetModeChar()))
147 dest->SetMode(this->GetModeChar(),true);
148 return MODEACTION_ALLOW;
153 if (dest->IsModeSet(this->GetModeChar()))
155 dest->SetMode(this->GetModeChar(),false);
156 return MODEACTION_ALLOW;
160 return MODEACTION_DENY;
164 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
168 if (!channel->IsModeSet(this->GetModeChar()))
170 channel->SetMode(this->GetModeChar(),true);
171 return MODEACTION_ALLOW;
176 if (channel->IsModeSet(this->GetModeChar()))
178 channel->SetMode(this->GetModeChar(),false);
179 return MODEACTION_ALLOW;
183 return MODEACTION_DENY;
186 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
190 ModeWatcher::~ModeWatcher()
194 char ModeWatcher::GetModeChar()
199 ModeType ModeWatcher::GetModeType()
204 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
209 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
213 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
216 if ((!user) || (!dest) || (!chan) || (!*dest))
220 d = ServerInstance->FindNick(dest);
223 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
229 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
233 /* Display channel's current mode string */
234 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
235 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
240 if (targetuser == user || user->HasPrivPermission("users/auspex"))
242 /* Display user's current mode string */
243 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
244 if (IS_OPER(targetuser))
245 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
250 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't view modes for other users", user->nick.c_str());
256 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
257 std::string ¶meter, bool SkipACL)
259 ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
260 unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
262 ModeHandler *mh = FindMode(modechar, type);
263 int pcnt = mh->GetNumParams(adding);
265 ModResult MOD_RESULT;
266 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt));
268 if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY))
269 return MODEACTION_DENY;
271 if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW))
273 unsigned int neededrank = mh->GetLevelRequired();
274 /* Compare our rank on the channel against the rank of the required prefix,
275 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
276 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
277 * first, so we don't need to iterate, we just look up the first instead.
279 unsigned int ourrank = chan->GetPrefixValue(user);
280 if (ourrank < neededrank)
283 // TODO replace with a real search for the proper prefix
284 char needed = neededrank > HALFOP_VALUE ? '@' : '%';
285 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
286 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
287 return MODEACTION_DENY;
291 unsigned char handler_id = (modechar - 'A') | mask;
293 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
295 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
296 return MODEACTION_DENY;
297 /* A module whacked the parameter completely, and there was one. abort. */
298 if (pcnt && parameter.empty())
299 return MODEACTION_DENY;
302 if (IS_LOCAL(user) && !IS_OPER(user))
304 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
305 if (disabled[modechar - 'A'])
307 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
308 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
309 return MODEACTION_DENY;
313 if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
315 /* It's an oper only mode, and they don't have access to it. */
318 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
319 user->nick.c_str(), user->oper.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
323 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
324 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
326 return MODEACTION_DENY;
329 /* Call the handler for the mode */
330 ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
332 if (pcnt && parameter.empty())
333 return MODEACTION_DENY;
335 if (ma != MODEACTION_ALLOW)
338 mh->ChangeCount(adding ? 1 : -1);
340 if (mh->GetPrefixRank() && chan)
342 User* user_to_prefix = ServerInstance->FindNick(parameter);
344 chan->SetPrefix(user_to_prefix, modechar, adding);
347 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
348 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
350 return MODEACTION_ALLOW;
353 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
355 std::string target = parameters[0];
356 Channel* targetchannel = ServerInstance->FindChan(target);
357 User* targetuser = ServerInstance->FindNick(target);
358 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
361 LastParseParams.clear();
362 LastParseTranslate.clear();
364 if (!targetchannel && !targetuser)
366 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
369 if (parameters.size() == 1)
371 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
375 std::string mode_sequence = parameters[1];
377 bool SkipAccessChecks = false;
379 if (!IS_LOCAL(user) || ServerInstance->ULine(user->server))
381 SkipAccessChecks = true;
385 ModResult MOD_RESULT;
386 FIRST_MOD_RESULT(ServerInstance, OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters));
387 if (MOD_RESULT == MOD_RES_DENY)
389 SkipAccessChecks = (MOD_RESULT == MOD_RES_ALLOW);
392 if (targetuser && !SkipAccessChecks && user != targetuser)
394 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
398 std::string output_mode;
399 std::ostringstream output_parameters;
400 LastParseParams.push_back(output_mode);
401 LastParseTranslate.push_back(TR_TEXT);
404 char output_pm = '\0'; // current output state, '+' or '-'
405 unsigned int param_at = 2;
407 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
409 unsigned char modechar = *letter;
410 if (modechar == '+' || modechar == '-')
412 adding = (modechar == '+');
416 ModeHandler *mh = this->FindMode(modechar, type);
419 /* No mode handler? Unknown mode character then. */
420 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
424 std::string parameter = "";
425 int pcnt = mh->GetNumParams(adding);
426 if (pcnt && param_at == parameters.size())
428 /* No parameter, continue to the next mode */
429 mh->OnParameterMissing(user, targetuser, targetchannel);
434 parameter = parameters[param_at++];
435 /* Make sure the user isn't trying to slip in an invalid parameter */
436 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
438 if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
440 std::string ours = targetchannel->GetModeParameter(modechar);
441 if (!mh->CheckTimeStamp(parameter, ours, targetchannel))
442 /* we won the mode merge, don't apply this mode */
447 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
449 if (ma != MODEACTION_ALLOW)
452 char needed_pm = adding ? '+' : '-';
453 if (needed_pm != output_pm)
455 output_pm = needed_pm;
456 output_mode.append(1, output_pm);
458 output_mode.append(1, modechar);
462 output_parameters << " " << parameter;
463 LastParseParams.push_back(parameter);
464 LastParseTranslate.push_back(mh->GetTranslateType());
467 if ( (output_mode.length() + output_parameters.str().length() > 450)
468 || (output_mode.length() > 100)
469 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
471 /* mode sequence is getting too long */
476 LastParseParams[0] = output_mode;
478 if (!output_mode.empty())
480 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
481 LastParse.append(" ");
482 LastParse.append(output_mode);
483 LastParse.append(output_parameters.str());
487 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
488 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
492 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
493 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
496 else if (targetchannel && parameters.size() == 2)
498 /* Special case for displaying the list for listmodes,
499 * e.g. MODE #chan b, or MODE #chan +b without a parameter
501 this->DisplayListModes(user, targetchannel, mode_sequence);
505 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
509 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
511 unsigned char mletter = *letter;
515 /* Ensure the user doesnt request the same mode twice,
516 * so they cant flood themselves off out of idiocy.
518 if (sent[mletter] == seq)
523 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
525 if (!mh || !mh->IsListMode())
528 ModResult MOD_RESULT;
529 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
530 if (MOD_RESULT == MOD_RES_DENY)
534 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
536 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
537 user->nick.c_str(), chan->name.c_str(), mletter);
541 /** See below for a description of what craq this is :D
543 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
545 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
547 std::string dummyparam;
549 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
553 mh->DisplayList(user, chan);
555 mh->DisplayEmptyList(user, chan);
559 const std::string& ModeParser::GetLastParse()
564 void ModeParser::CleanMask(std::string &mask)
566 std::string::size_type pos_of_pling = mask.find_first_of('!');
567 std::string::size_type pos_of_at = mask.find_first_of('@');
568 std::string::size_type pos_of_dot = mask.find_first_of('.');
569 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
571 if (mask.length() >= 2 && mask[1] == ':')
572 return; // if it's an extban, don't even try guess how it needs to be formed.
574 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
576 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
577 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
579 /* It has no '.' in it, it must be a nick. */
584 /* Got a dot in it? Has to be a host */
585 mask = "*!*@" + mask;
588 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
590 /* Has an @ but no !, its a user@host */
593 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
595 /* Has a ! but no @, it must be a nick!ident */
600 bool ModeParser::AddMode(ModeHandler* mh)
602 unsigned char mask = 0;
603 unsigned char pos = 0;
605 /* Yes, i know, this might let people declare modes like '_' or '^'.
606 * If they do that, thats their problem, and if i ever EVER see an
607 * official InspIRCd developer do that, i'll beat them with a paddle!
609 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
612 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
613 * A mode prefix of ':' will fuck up both server to server, and client to server.
614 * A mode prefix of '#' will mess up /whois and /privmsg
616 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
619 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
620 pos = (mh->GetModeChar()-65) | mask;
622 if (modehandlers[pos])
625 modehandlers[pos] = mh;
629 bool ModeParser::DelMode(ModeHandler* mh)
631 unsigned char mask = 0;
632 unsigned char pos = 0;
634 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
637 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
638 pos = (mh->GetModeChar()-65) | mask;
640 if (!modehandlers[pos])
643 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
644 * To stack here we have to make the algorithm slower. Discuss.
646 switch (mh->GetModeType())
649 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
651 mh->RemoveMode(i->second);
654 case MODETYPE_CHANNEL:
655 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
657 mh->RemoveMode(i->second);
662 modehandlers[pos] = NULL;
667 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
669 unsigned char mask = 0;
670 unsigned char pos = 0;
672 if ((modeletter < 'A') || (modeletter > 'z'))
675 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
676 pos = (modeletter-65) | mask;
678 return modehandlers[pos];
681 std::string ModeParser::UserModeList()
686 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
688 unsigned char pos = (mode-65) | MASK_USER;
690 if (modehandlers[pos])
691 modestr[pointer++] = mode;
693 modestr[pointer++] = 0;
697 std::string ModeParser::ChannelModeList()
702 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
704 unsigned char pos = (mode-65) | MASK_CHANNEL;
706 if (modehandlers[pos])
707 modestr[pointer++] = mode;
709 modestr[pointer++] = 0;
713 std::string ModeParser::ParaModeList()
718 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
720 unsigned char pos = (mode-65) | MASK_CHANNEL;
722 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
723 modestr[pointer++] = mode;
725 modestr[pointer++] = 0;
729 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
731 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
733 unsigned char pos = (mode-65) | MASK_CHANNEL;
735 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
737 return modehandlers[pos];
743 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
748 if (!channel || !user)
751 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
753 unsigned char pos = (mode-65) | MASK_CHANNEL;
754 ModeHandler* mh = modehandlers[pos];
755 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
758 ret = mh->ModeSet(NULL, user, channel, user->nick);
759 if ((ret.first) && (ret.second == user->nick))
764 pars.append(user->nick);
766 types.push_back(mh->GetModeChar());
777 std::string ModeParser::GiveModeList(ModeMasks m)
779 std::string type1; /* Listmodes EXCEPT those with a prefix */
780 std::string type2; /* Modes that take a param when adding or removing */
781 std::string type3; /* Modes that only take a param when adding */
782 std::string type4; /* Modes that dont take a param */
784 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
786 unsigned char pos = (mode-65) | m;
787 /* One parameter when adding */
788 if (modehandlers[pos])
790 if (modehandlers[pos]->GetNumParams(true))
792 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
794 type1 += modehandlers[pos]->GetModeChar();
798 /* ... and one parameter when removing */
799 if (modehandlers[pos]->GetNumParams(false))
801 /* But not a list mode */
802 if (!modehandlers[pos]->GetPrefix())
804 type2 += modehandlers[pos]->GetModeChar();
809 /* No parameters when removing */
810 type3 += modehandlers[pos]->GetModeChar();
816 type4 += modehandlers[pos]->GetModeChar();
821 return type1 + "," + type2 + "," + type3 + "," + type4;
824 std::string ModeParser::BuildPrefixes()
826 std::string mletters;
827 std::string mprefixes;
828 std::map<int,std::pair<char,char> > prefixes;
830 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
832 unsigned char pos = (mode-65) | MASK_CHANNEL;
834 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
836 prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
837 modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
841 for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
843 mletters = mletters + n->second.first;
844 mprefixes = mprefixes + n->second.second;
847 return "(" + mprefixes + ")" + mletters;
850 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
852 unsigned char mask = 0;
853 unsigned char pos = 0;
858 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
861 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
862 pos = (mw->GetModeChar()-65) | mask;
864 modewatchers[pos].push_back(mw);
869 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
871 unsigned char mask = 0;
872 unsigned char pos = 0;
877 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
880 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
881 pos = (mw->GetModeChar()-65) | mask;
883 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
885 if (a == modewatchers[pos].end())
890 modewatchers[pos].erase(a);
895 /** This default implementation can remove simple user modes
897 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
899 char moderemove[MAXBUF];
900 std::vector<std::string> parameters;
902 if (user->IsModeSet(this->GetModeChar()))
906 stack->Push(this->GetModeChar());
910 sprintf(moderemove,"-%c",this->GetModeChar());
911 parameters.push_back(user->nick);
912 parameters.push_back(moderemove);
913 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
918 /** This default implementation can remove simple channel modes
921 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
923 char moderemove[MAXBUF];
924 std::vector<std::string> parameters;
926 if (channel->IsModeSet(this->GetModeChar()))
930 stack->Push(this->GetModeChar());
934 sprintf(moderemove,"-%c",this->GetModeChar());
935 parameters.push_back(channel->name);
936 parameters.push_back(moderemove);
937 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
942 ModeParser::ModeParser(InspIRCd* Instance)
944 ModeHandler* modes[] =
946 new ModeChannelSecret(Instance),
947 new ModeChannelPrivate(Instance),
948 new ModeChannelModerated(Instance),
949 new ModeChannelTopicOps(Instance),
951 new ModeChannelNoExternal(Instance),
952 new ModeChannelInviteOnly(Instance),
953 new ModeChannelKey(Instance),
954 new ModeChannelLimit(Instance),
956 new ModeChannelBan(Instance),
957 new ModeChannelOp(Instance),
958 new ModeChannelHalfOp(Instance),
959 new ModeChannelVoice(Instance),
961 new ModeUserWallops(Instance),
962 new ModeUserInvisible(Instance),
963 new ModeUserOperator(Instance),
964 new ModeUserServerNoticeMask(Instance),
965 #define BUILTIN_MODE_COUNT 16
968 /* Clear mode handler list */
969 memset(modehandlers, 0, sizeof(modehandlers));
971 /* Last parse string */
974 /* Initialise the RFC mode letters */
975 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
976 this->AddMode(modes[index]);
979 memset(&sent, 0, sizeof(sent));
982 ModeParser::~ModeParser()
985 for(int i=0; i < 256; i++)
987 ModeHandler* mh = modehandlers[i];
994 if (count != BUILTIN_MODE_COUNT)
995 throw CoreException("Mode handler found non-core modes remaining at deallocation");