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 ModResult ModeHandler::AccessCheck(User*, Channel*, std::string &, bool)
109 return MOD_RES_PASSTHRU;
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 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
141 bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ours, Channel*)
143 return (theirs < ours);
146 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
150 if (!dest->IsModeSet(this->GetModeChar()))
152 dest->SetMode(this->GetModeChar(),true);
153 return MODEACTION_ALLOW;
158 if (dest->IsModeSet(this->GetModeChar()))
160 dest->SetMode(this->GetModeChar(),false);
161 return MODEACTION_ALLOW;
165 return MODEACTION_DENY;
169 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
173 if (!channel->IsModeSet(this->GetModeChar()))
175 channel->SetMode(this->GetModeChar(),true);
176 return MODEACTION_ALLOW;
181 if (channel->IsModeSet(this->GetModeChar()))
183 channel->SetMode(this->GetModeChar(),false);
184 return MODEACTION_ALLOW;
188 return MODEACTION_DENY;
191 ModeWatcher::ModeWatcher(char modeletter, ModeType type) : mode(modeletter), m_type(type)
195 ModeWatcher::~ModeWatcher()
199 char ModeWatcher::GetModeChar()
204 ModeType ModeWatcher::GetModeType()
209 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
214 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
218 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
221 if ((!user) || (!dest) || (!chan) || (!*dest))
225 d = ServerInstance->FindNick(dest);
228 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
234 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
238 /* Display channel's current mode string */
239 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
240 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
245 if (targetuser == user || user->HasPrivPermission("users/auspex"))
247 /* Display user's current mode string */
248 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
249 if (IS_OPER(targetuser))
250 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
255 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't view modes for other users", user->nick.c_str());
261 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
262 std::string ¶meter, bool SkipACL)
264 ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
265 unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
267 ModeHandler *mh = FindMode(modechar, type);
268 int pcnt = mh->GetNumParams(adding);
270 ModResult MOD_RESULT;
271 FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt));
273 if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY))
274 return MODEACTION_DENY;
276 if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW))
278 MOD_RESULT = mh->AccessCheck(user, chan, parameter, adding);
280 if (MOD_RESULT == MOD_RES_DENY)
281 return MODEACTION_DENY;
282 if (MOD_RESULT == MOD_RES_PASSTHRU)
284 unsigned int neededrank = mh->GetLevelRequired();
285 /* Compare our rank on the channel against the rank of the required prefix,
286 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
287 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
288 * first, so we don't need to iterate, we just look up the first instead.
290 unsigned int ourrank = chan->GetPrefixValue(user);
291 if (ourrank < neededrank)
294 // TODO replace with a real search for the proper prefix
295 char needed = neededrank > HALFOP_VALUE ? '@' : '%';
296 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
297 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
298 return MODEACTION_DENY;
303 unsigned char handler_id = (modechar - 'A') | mask;
305 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
307 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
308 return MODEACTION_DENY;
309 /* A module whacked the parameter completely, and there was one. abort. */
310 if (pcnt && parameter.empty())
311 return MODEACTION_DENY;
314 if (IS_LOCAL(user) && !IS_OPER(user))
316 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
317 if (disabled[modechar - 'A'])
319 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
320 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
321 return MODEACTION_DENY;
325 if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
327 /* It's an oper only mode, and they don't have access to it. */
330 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
331 user->nick.c_str(), irc::Spacify(user->oper.c_str()), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
335 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
336 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
338 return MODEACTION_DENY;
341 /* Call the handler for the mode */
342 ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
344 if (pcnt && parameter.empty())
345 return MODEACTION_DENY;
347 if (ma != MODEACTION_ALLOW)
350 mh->ChangeCount(adding ? 1 : -1);
352 if (mh->GetPrefixRank() && chan)
354 User* user_to_prefix = ServerInstance->FindNick(parameter);
356 chan->SetPrefix(user_to_prefix, modechar, adding);
359 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
360 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
362 return MODEACTION_ALLOW;
365 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
367 std::string target = parameters[0];
368 Channel* targetchannel = ServerInstance->FindChan(target);
369 User* targetuser = ServerInstance->FindNick(target);
370 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
373 LastParseParams.clear();
374 LastParseTranslate.clear();
376 if (!targetchannel && !targetuser)
378 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
381 if (parameters.size() == 1)
383 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
387 std::string mode_sequence = parameters[1];
389 bool SkipAccessChecks = false;
391 if (!IS_LOCAL(user) || ServerInstance->ULine(user->server))
393 SkipAccessChecks = true;
397 ModResult MOD_RESULT;
398 FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters));
399 if (MOD_RESULT == MOD_RES_DENY)
401 SkipAccessChecks = (MOD_RESULT == MOD_RES_ALLOW);
404 if (targetuser && !SkipAccessChecks && user != targetuser)
406 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
410 std::string output_mode;
411 std::ostringstream output_parameters;
412 LastParseParams.push_back(output_mode);
413 LastParseTranslate.push_back(TR_TEXT);
416 char output_pm = '\0'; // current output state, '+' or '-'
417 unsigned int param_at = 2;
419 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
421 unsigned char modechar = *letter;
422 if (modechar == '+' || modechar == '-')
424 adding = (modechar == '+');
428 ModeHandler *mh = this->FindMode(modechar, type);
431 /* No mode handler? Unknown mode character then. */
432 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
436 std::string parameter = "";
437 int pcnt = mh->GetNumParams(adding);
438 if (pcnt && param_at == parameters.size())
440 /* No parameter, continue to the next mode */
441 mh->OnParameterMissing(user, targetuser, targetchannel);
446 parameter = parameters[param_at++];
447 /* Make sure the user isn't trying to slip in an invalid parameter */
448 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
450 if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
452 std::string ours = targetchannel->GetModeParameter(modechar);
453 if (!mh->ResolveModeConflict(parameter, ours, targetchannel))
454 /* we won the mode merge, don't apply this mode */
459 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
461 if (ma != MODEACTION_ALLOW)
464 char needed_pm = adding ? '+' : '-';
465 if (needed_pm != output_pm)
467 output_pm = needed_pm;
468 output_mode.append(1, output_pm);
470 output_mode.append(1, modechar);
474 TranslateType tt = mh->GetTranslateType();
477 User* u = ServerInstance->FindNick(parameter);
481 output_parameters << " " << parameter;
482 LastParseParams.push_back(parameter);
483 LastParseTranslate.push_back(tt);
486 if ( (output_mode.length() + output_parameters.str().length() > 450)
487 || (output_mode.length() > 100)
488 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
490 /* mode sequence is getting too long */
495 LastParseParams[0] = output_mode;
497 if (!output_mode.empty())
499 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
500 LastParse.append(" ");
501 LastParse.append(output_mode);
502 LastParse.append(output_parameters.str());
506 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
507 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
511 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
512 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
515 else if (targetchannel && parameters.size() == 2)
517 /* Special case for displaying the list for listmodes,
518 * e.g. MODE #chan b, or MODE #chan +b without a parameter
520 this->DisplayListModes(user, targetchannel, mode_sequence);
524 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
528 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
530 unsigned char mletter = *letter;
534 /* Ensure the user doesnt request the same mode twice,
535 * so they cant flood themselves off out of idiocy.
537 if (sent[mletter] == seq)
542 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
544 if (!mh || !mh->IsListMode())
547 ModResult MOD_RESULT;
548 FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
549 if (MOD_RESULT == MOD_RES_DENY)
553 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
555 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
556 user->nick.c_str(), chan->name.c_str(), mletter);
560 /** See below for a description of what craq this is :D
562 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
564 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
566 std::string dummyparam;
568 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
572 mh->DisplayList(user, chan);
574 mh->DisplayEmptyList(user, chan);
578 const std::string& ModeParser::GetLastParse()
583 void ModeParser::CleanMask(std::string &mask)
585 std::string::size_type pos_of_pling = mask.find_first_of('!');
586 std::string::size_type pos_of_at = mask.find_first_of('@');
587 std::string::size_type pos_of_dot = mask.find_first_of('.');
588 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
590 if (mask.length() >= 2 && mask[1] == ':')
591 return; // if it's an extban, don't even try guess how it needs to be formed.
593 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
595 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
596 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
598 /* It has no '.' in it, it must be a nick. */
603 /* Got a dot in it? Has to be a host */
604 mask = "*!*@" + mask;
607 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
609 /* Has an @ but no !, its a user@host */
612 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
614 /* Has a ! but no @, it must be a nick!ident */
619 bool ModeParser::AddMode(ModeHandler* mh)
621 unsigned char mask = 0;
622 unsigned char pos = 0;
624 /* Yes, i know, this might let people declare modes like '_' or '^'.
625 * If they do that, thats their problem, and if i ever EVER see an
626 * official InspIRCd developer do that, i'll beat them with a paddle!
628 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
631 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
632 * A mode prefix of ':' will fuck up both server to server, and client to server.
633 * A mode prefix of '#' will mess up /whois and /privmsg
635 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
638 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
639 pos = (mh->GetModeChar()-65) | mask;
641 if (modehandlers[pos])
644 modehandlers[pos] = mh;
648 bool ModeParser::DelMode(ModeHandler* mh)
650 unsigned char mask = 0;
651 unsigned char pos = 0;
653 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
656 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
657 pos = (mh->GetModeChar()-65) | mask;
659 if (!modehandlers[pos])
662 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
663 * To stack here we have to make the algorithm slower. Discuss.
665 switch (mh->GetModeType())
668 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
670 mh->RemoveMode(i->second);
673 case MODETYPE_CHANNEL:
674 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
676 mh->RemoveMode(i->second);
681 modehandlers[pos] = NULL;
686 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
688 unsigned char mask = 0;
689 unsigned char pos = 0;
691 if ((modeletter < 'A') || (modeletter > 'z'))
694 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
695 pos = (modeletter-65) | mask;
697 return modehandlers[pos];
700 std::string ModeParser::UserModeList()
705 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
707 unsigned char pos = (mode-65) | MASK_USER;
709 if (modehandlers[pos])
710 modestr[pointer++] = mode;
712 modestr[pointer++] = 0;
716 std::string ModeParser::ChannelModeList()
721 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
723 unsigned char pos = (mode-65) | MASK_CHANNEL;
725 if (modehandlers[pos])
726 modestr[pointer++] = mode;
728 modestr[pointer++] = 0;
732 std::string ModeParser::ParaModeList()
737 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
739 unsigned char pos = (mode-65) | MASK_CHANNEL;
741 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
742 modestr[pointer++] = mode;
744 modestr[pointer++] = 0;
748 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
750 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
752 unsigned char pos = (mode-65) | MASK_CHANNEL;
754 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
756 return modehandlers[pos];
762 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
767 if (!channel || !user)
770 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
772 unsigned char pos = (mode-65) | MASK_CHANNEL;
773 ModeHandler* mh = modehandlers[pos];
774 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
777 ret = mh->ModeSet(NULL, user, channel, user->nick);
778 if ((ret.first) && (ret.second == user->nick))
783 pars.append(user->nick);
785 types.push_back(mh->GetModeChar());
796 std::string ModeParser::GiveModeList(ModeMasks m)
798 std::string type1; /* Listmodes EXCEPT those with a prefix */
799 std::string type2; /* Modes that take a param when adding or removing */
800 std::string type3; /* Modes that only take a param when adding */
801 std::string type4; /* Modes that dont take a param */
803 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
805 unsigned char pos = (mode-65) | m;
806 /* One parameter when adding */
807 if (modehandlers[pos])
809 if (modehandlers[pos]->GetNumParams(true))
811 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
813 type1 += modehandlers[pos]->GetModeChar();
817 /* ... and one parameter when removing */
818 if (modehandlers[pos]->GetNumParams(false))
820 /* But not a list mode */
821 if (!modehandlers[pos]->GetPrefix())
823 type2 += modehandlers[pos]->GetModeChar();
828 /* No parameters when removing */
829 type3 += modehandlers[pos]->GetModeChar();
835 type4 += modehandlers[pos]->GetModeChar();
840 return type1 + "," + type2 + "," + type3 + "," + type4;
843 std::string ModeParser::BuildPrefixes()
845 std::string mletters;
846 std::string mprefixes;
847 std::map<int,std::pair<char,char> > prefixes;
849 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
851 unsigned char pos = (mode-65) | MASK_CHANNEL;
853 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
855 prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
856 modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
860 for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
862 mletters = mletters + n->second.first;
863 mprefixes = mprefixes + n->second.second;
866 return "(" + mprefixes + ")" + mletters;
869 bool ModeParser::AddModeWatcher(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 modewatchers[pos].push_back(mw);
888 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
890 unsigned char mask = 0;
891 unsigned char pos = 0;
896 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
899 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
900 pos = (mw->GetModeChar()-65) | mask;
902 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
904 if (a == modewatchers[pos].end())
909 modewatchers[pos].erase(a);
914 /** This default implementation can remove simple user modes
916 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
918 char moderemove[MAXBUF];
919 std::vector<std::string> parameters;
921 if (user->IsModeSet(this->GetModeChar()))
925 stack->Push(this->GetModeChar());
929 sprintf(moderemove,"-%c",this->GetModeChar());
930 parameters.push_back(user->nick);
931 parameters.push_back(moderemove);
932 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
937 /** This default implementation can remove simple channel modes
940 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
942 char moderemove[MAXBUF];
943 std::vector<std::string> parameters;
945 if (channel->IsModeSet(this->GetModeChar()))
949 stack->Push(this->GetModeChar());
953 sprintf(moderemove,"-%c",this->GetModeChar());
954 parameters.push_back(channel->name);
955 parameters.push_back(moderemove);
956 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
961 ModeParser::ModeParser()
963 ModeHandler* modes[] =
965 new ModeChannelSecret,
966 new ModeChannelPrivate,
967 new ModeChannelModerated,
968 new ModeChannelTopicOps,
970 new ModeChannelNoExternal,
971 new ModeChannelInviteOnly,
973 new ModeChannelLimit,
977 new ModeChannelHalfOp,
978 new ModeChannelVoice,
981 new ModeUserInvisible,
982 new ModeUserOperator,
983 new ModeUserServerNoticeMask,
984 #define BUILTIN_MODE_COUNT 16
987 /* Clear mode handler list */
988 memset(modehandlers, 0, sizeof(modehandlers));
990 /* Last parse string */
993 /* Initialise the RFC mode letters */
994 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
995 this->AddMode(modes[index]);
998 memset(&sent, 0, sizeof(sent));
1001 ModeParser::~ModeParser()
1004 for(int i=0; i < 256; i++)
1006 ModeHandler* mh = modehandlers[i];
1007 if (mh && mh->creator == NULL)
1013 if (count != BUILTIN_MODE_COUNT)
1014 throw CoreException("Mode handler found non-core modes remaining at deallocation");