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(InspIRCd* Instance, Module* Creator, char modeletter, int parameters_on, int parameters_off, bool listmode, ModeType type, bool operonly, char mprefix, char prefixrequired, TranslateType translate)
53 : ServerInstance(Instance), mode(modeletter), n_params_on(parameters_on), n_params_off(parameters_off), list(listmode), m_type(type), m_paramtype(translate), oper(operonly), prefix(mprefix), count(0), prefixneeded(prefixrequired), creator(Creator)
57 ModeHandler::~ModeHandler()
61 bool ModeHandler::IsListMode()
66 char ModeHandler::GetNeededPrefix()
68 if (prefixneeded == '%' && !ServerInstance->Config->AllowHalfop)
73 void ModeHandler::SetNeededPrefix(char needsprefix)
75 prefixneeded = needsprefix;
78 unsigned int ModeHandler::GetPrefixRank()
83 unsigned int ModeHandler::GetCount()
88 void ModeHandler::ChangeCount(int modifier)
91 ServerInstance->Logs->Log("MODE", DEBUG,"Change count for mode %c is now %d", mode, count);
94 ModeType ModeHandler::GetModeType()
99 TranslateType ModeHandler::GetTranslateType()
104 bool ModeHandler::NeedsOper()
109 char ModeHandler::GetPrefix()
114 int ModeHandler::GetNumParams(bool adding)
116 return adding ? n_params_on : n_params_off;
119 char ModeHandler::GetModeChar()
124 std::string ModeHandler::GetUserParameter(User* user)
129 ModeAction ModeHandler::OnModeChange(User*, User*, Channel*, std::string&, bool)
131 return MODEACTION_DENY;
134 ModePair ModeHandler::ModeSet(User*, User* dest, Channel* channel, const std::string&)
138 return std::make_pair(dest->IsModeSet(this->mode), "");
142 return std::make_pair(channel->IsModeSet(this->mode), "");
146 void ModeHandler::DisplayList(User*, Channel*)
150 void ModeHandler::DisplayEmptyList(User*, Channel*)
154 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
158 bool ModeHandler::CheckTimeStamp(std::string& theirs, const std::string& ours, Channel*)
160 return (theirs < ours);
163 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
167 if (!dest->IsModeSet(this->GetModeChar()))
169 dest->SetMode(this->GetModeChar(),true);
170 return MODEACTION_ALLOW;
175 if (dest->IsModeSet(this->GetModeChar()))
177 dest->SetMode(this->GetModeChar(),false);
178 return MODEACTION_ALLOW;
182 return MODEACTION_DENY;
186 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding)
190 if (!channel->IsModeSet(this->GetModeChar()))
192 channel->SetMode(this->GetModeChar(),true);
193 return MODEACTION_ALLOW;
198 if (channel->IsModeSet(this->GetModeChar()))
200 channel->SetMode(this->GetModeChar(),false);
201 return MODEACTION_ALLOW;
205 return MODEACTION_DENY;
208 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
212 ModeWatcher::~ModeWatcher()
216 char ModeWatcher::GetModeChar()
221 ModeType ModeWatcher::GetModeType()
226 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType)
231 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType)
235 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
238 if ((!user) || (!dest) || (!chan) || (!*dest))
242 d = ServerInstance->FindNick(dest);
245 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
251 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
255 /* Display channel's current mode string */
256 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
257 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
262 if (targetuser == user || user->HasPrivPermission("users/auspex"))
264 /* Display user's current mode string */
265 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
266 if (IS_OPER(targetuser))
267 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
272 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't view modes for other users", user->nick.c_str());
278 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
279 std::string ¶meter, bool SkipACL)
281 ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
282 unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
284 ModeHandler *mh = FindMode(modechar, type);
285 int pcnt = mh->GetNumParams(adding);
287 ModResult MOD_RESULT;
288 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt));
290 if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY))
291 return MODEACTION_DENY;
293 if (chan && !SkipACL && (MOD_RESULT != MOD_RES_ALLOW))
295 char needed = mh->GetNeededPrefix();
296 ModeHandler* prefixmode = FindPrefix(needed);
298 /* If the mode defined by the handler is not '\0', but the handler for it
299 * cannot be found, they probably dont have the right module loaded to implement
300 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
301 * Revert to checking against the minimum core prefix, '%'.
303 if (needed && !prefixmode)
305 needed = ServerInstance->Config->AllowHalfop ? '%' : '@';
306 prefixmode = FindPrefix(needed);
311 unsigned int neededrank = prefixmode->GetPrefixRank();
312 /* Compare our rank on the channel against the rank of the required prefix,
313 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
314 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
315 * first, so we don't need to iterate, we just look up the first instead.
317 unsigned int ourrank = chan->GetPrefixValue(user);
318 if (ourrank < neededrank)
321 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
322 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
323 return MODEACTION_DENY;
328 unsigned char handler_id = (modechar - 'A') | mask;
330 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
332 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type) == false)
333 return MODEACTION_DENY;
334 /* A module whacked the parameter completely, and there was one. abort. */
335 if (pcnt && parameter.empty())
336 return MODEACTION_DENY;
339 if (IS_LOCAL(user) && !IS_OPER(user))
341 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
342 if (disabled[modechar - 'A'])
344 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
345 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
346 return MODEACTION_DENY;
350 if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
352 /* It's an oper only mode, and they don't have access to it. */
355 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
356 user->nick.c_str(), user->oper.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
360 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
361 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
363 return MODEACTION_DENY;
366 /* Call the handler for the mode */
367 ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
369 if (pcnt && parameter.empty())
370 return MODEACTION_DENY;
372 if (ma != MODEACTION_ALLOW)
375 mh->ChangeCount(adding ? 1 : -1);
377 if (mh->GetPrefixRank() && chan)
379 User* user_to_prefix = ServerInstance->FindNick(parameter);
381 chan->SetPrefix(user_to_prefix, modechar, mh->GetPrefixRank(), adding);
384 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
385 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type);
387 return MODEACTION_ALLOW;
390 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool merge)
392 std::string target = parameters[0];
393 Channel* targetchannel = ServerInstance->FindChan(target);
394 User* targetuser = ServerInstance->FindNick(target);
395 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
398 LastParseParams.clear();
399 LastParseTranslate.clear();
401 if (!targetchannel && !targetuser)
403 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
406 if (parameters.size() == 1)
408 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
412 std::string mode_sequence = parameters[1];
414 bool SkipAccessChecks = false;
416 if (!IS_LOCAL(user) || ServerInstance->ULine(user->server))
418 SkipAccessChecks = true;
422 ModResult MOD_RESULT;
423 FIRST_MOD_RESULT(ServerInstance, OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, parameters));
424 if (MOD_RESULT == MOD_RES_DENY)
426 SkipAccessChecks = (MOD_RESULT == MOD_RES_ALLOW);
429 if (targetuser && !SkipAccessChecks && user != targetuser)
431 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
435 std::string output_mode;
436 std::ostringstream output_parameters;
437 LastParseParams.push_back(output_mode);
438 LastParseTranslate.push_back(TR_TEXT);
441 char output_pm = '\0'; // current output state, '+' or '-'
442 unsigned int param_at = 2;
444 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
446 unsigned char modechar = *letter;
447 if (modechar == '+' || modechar == '-')
449 adding = (modechar == '+');
453 ModeHandler *mh = this->FindMode(modechar, type);
456 /* No mode handler? Unknown mode character then. */
457 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
461 std::string parameter = "";
462 int pcnt = mh->GetNumParams(adding);
463 if (pcnt && param_at == parameters.size())
465 /* No parameter, continue to the next mode */
466 mh->OnParameterMissing(user, targetuser, targetchannel);
471 parameter = parameters[param_at++];
472 /* Make sure the user isn't trying to slip in an invalid parameter */
473 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
475 if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
477 std::string ours = targetchannel->GetModeParameter(modechar);
478 if (!mh->CheckTimeStamp(parameter, ours, targetchannel))
479 /* we won the mode merge, don't apply this mode */
484 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
486 if (ma != MODEACTION_ALLOW)
489 char needed_pm = adding ? '+' : '-';
490 if (needed_pm != output_pm)
492 output_pm = needed_pm;
493 output_mode.append(1, output_pm);
495 output_mode.append(1, modechar);
499 output_parameters << " " << parameter;
500 LastParseParams.push_back(parameter);
501 LastParseTranslate.push_back(mh->GetTranslateType());
504 if ( (output_mode.length() + output_parameters.str().length() > 450)
505 || (output_mode.length() > 100)
506 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
508 /* mode sequence is getting too long */
513 LastParseParams[0] = output_mode;
515 if (!output_mode.empty())
517 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
518 LastParse.append(" ");
519 LastParse.append(output_mode);
520 LastParse.append(output_parameters.str());
524 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
525 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
529 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
530 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
533 else if (targetchannel && parameters.size() == 2)
535 /* Special case for displaying the list for listmodes,
536 * e.g. MODE #chan b, or MODE #chan +b without a parameter
538 this->DisplayListModes(user, targetchannel, mode_sequence);
542 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
546 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
548 unsigned char mletter = *letter;
552 /* Ensure the user doesnt request the same mode twice,
553 * so they cant flood themselves off out of idiocy.
555 if (sent[mletter] == seq)
560 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
562 if (!mh || !mh->IsListMode())
565 ModResult MOD_RESULT;
566 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
567 if (MOD_RESULT == MOD_RES_DENY)
571 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
573 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
574 user->nick.c_str(), chan->name.c_str(), mletter);
578 /** See below for a description of what craq this is :D
580 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
582 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
584 std::string dummyparam;
586 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
590 mh->DisplayList(user, chan);
592 mh->DisplayEmptyList(user, chan);
596 const std::string& ModeParser::GetLastParse()
601 void ModeParser::CleanMask(std::string &mask)
603 std::string::size_type pos_of_pling = mask.find_first_of('!');
604 std::string::size_type pos_of_at = mask.find_first_of('@');
605 std::string::size_type pos_of_dot = mask.find_first_of('.');
606 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
608 if (mask.length() >= 2 && mask[1] == ':')
609 return; // if it's an extban, don't even try guess how it needs to be formed.
611 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
613 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
614 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
616 /* It has no '.' in it, it must be a nick. */
621 /* Got a dot in it? Has to be a host */
622 mask = "*!*@" + mask;
625 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
627 /* Has an @ but no !, its a user@host */
630 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
632 /* Has a ! but no @, it must be a nick!ident */
637 bool ModeParser::AddMode(ModeHandler* mh)
639 unsigned char mask = 0;
640 unsigned char pos = 0;
642 /* Yes, i know, this might let people declare modes like '_' or '^'.
643 * If they do that, thats their problem, and if i ever EVER see an
644 * official InspIRCd developer do that, i'll beat them with a paddle!
646 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
649 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
650 * A mode prefix of ':' will fuck up both server to server, and client to server.
651 * A mode prefix of '#' will mess up /whois and /privmsg
653 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
656 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
657 pos = (mh->GetModeChar()-65) | mask;
659 if (modehandlers[pos])
662 modehandlers[pos] = mh;
666 bool ModeParser::DelMode(ModeHandler* mh)
668 unsigned char mask = 0;
669 unsigned char pos = 0;
671 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
674 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
675 pos = (mh->GetModeChar()-65) | mask;
677 if (!modehandlers[pos])
680 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
681 * To stack here we have to make the algorithm slower. Discuss.
683 switch (mh->GetModeType())
686 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
688 mh->RemoveMode(i->second);
691 case MODETYPE_CHANNEL:
692 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
694 mh->RemoveMode(i->second);
699 modehandlers[pos] = NULL;
704 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
706 unsigned char mask = 0;
707 unsigned char pos = 0;
709 if ((modeletter < 'A') || (modeletter > 'z'))
712 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
713 pos = (modeletter-65) | mask;
715 return modehandlers[pos];
718 std::string ModeParser::UserModeList()
723 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
725 unsigned char pos = (mode-65) | MASK_USER;
727 if (modehandlers[pos])
728 modestr[pointer++] = mode;
730 modestr[pointer++] = 0;
734 std::string ModeParser::ChannelModeList()
739 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
741 unsigned char pos = (mode-65) | MASK_CHANNEL;
743 if (modehandlers[pos])
744 modestr[pointer++] = mode;
746 modestr[pointer++] = 0;
750 std::string ModeParser::ParaModeList()
755 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
757 unsigned char pos = (mode-65) | MASK_CHANNEL;
759 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
760 modestr[pointer++] = mode;
762 modestr[pointer++] = 0;
766 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
768 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
770 unsigned char pos = (mode-65) | MASK_CHANNEL;
772 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
774 return modehandlers[pos];
780 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
785 if (!channel || !user)
788 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
790 unsigned char pos = (mode-65) | MASK_CHANNEL;
791 ModeHandler* mh = modehandlers[pos];
792 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
795 ret = mh->ModeSet(NULL, user, channel, user->nick);
796 if ((ret.first) && (ret.second == user->nick))
801 pars.append(user->nick);
803 types.push_back(mh->GetModeChar());
814 std::string ModeParser::GiveModeList(ModeMasks m)
816 std::string type1; /* Listmodes EXCEPT those with a prefix */
817 std::string type2; /* Modes that take a param when adding or removing */
818 std::string type3; /* Modes that only take a param when adding */
819 std::string type4; /* Modes that dont take a param */
821 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
823 unsigned char pos = (mode-65) | m;
824 /* One parameter when adding */
825 if (modehandlers[pos])
827 if (modehandlers[pos]->GetNumParams(true))
829 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
831 type1 += modehandlers[pos]->GetModeChar();
835 /* ... and one parameter when removing */
836 if (modehandlers[pos]->GetNumParams(false))
838 /* But not a list mode */
839 if (!modehandlers[pos]->GetPrefix())
841 type2 += modehandlers[pos]->GetModeChar();
846 /* No parameters when removing */
847 type3 += modehandlers[pos]->GetModeChar();
853 type4 += modehandlers[pos]->GetModeChar();
858 return type1 + "," + type2 + "," + type3 + "," + type4;
861 std::string ModeParser::BuildPrefixes()
863 std::string mletters;
864 std::string mprefixes;
865 std::map<int,std::pair<char,char> > prefixes;
867 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
869 unsigned char pos = (mode-65) | MASK_CHANNEL;
871 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
873 prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
874 modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
878 for(std::map<int,std::pair<char,char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++)
880 mletters = mletters + n->second.first;
881 mprefixes = mprefixes + n->second.second;
884 return "(" + mprefixes + ")" + mletters;
887 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
889 unsigned char mask = 0;
890 unsigned char pos = 0;
895 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
898 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
899 pos = (mw->GetModeChar()-65) | mask;
901 modewatchers[pos].push_back(mw);
906 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
908 unsigned char mask = 0;
909 unsigned char pos = 0;
914 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
917 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
918 pos = (mw->GetModeChar()-65) | mask;
920 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
922 if (a == modewatchers[pos].end())
927 modewatchers[pos].erase(a);
932 /** This default implementation can remove simple user modes
934 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
936 char moderemove[MAXBUF];
937 std::vector<std::string> parameters;
939 if (user->IsModeSet(this->GetModeChar()))
943 stack->Push(this->GetModeChar());
947 sprintf(moderemove,"-%c",this->GetModeChar());
948 parameters.push_back(user->nick);
949 parameters.push_back(moderemove);
950 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
955 /** This default implementation can remove simple channel modes
958 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
960 char moderemove[MAXBUF];
961 std::vector<std::string> parameters;
963 if (channel->IsModeSet(this->GetModeChar()))
967 stack->Push(this->GetModeChar());
971 sprintf(moderemove,"-%c",this->GetModeChar());
972 parameters.push_back(channel->name);
973 parameters.push_back(moderemove);
974 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
979 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
981 ModeHandler* modes[] =
983 new ModeChannelSecret(Instance),
984 new ModeChannelPrivate(Instance),
985 new ModeChannelModerated(Instance),
986 new ModeChannelTopicOps(Instance),
988 new ModeChannelNoExternal(Instance),
989 new ModeChannelInviteOnly(Instance),
990 new ModeChannelKey(Instance),
991 new ModeChannelLimit(Instance),
993 new ModeChannelBan(Instance),
994 new ModeChannelOp(Instance),
995 new ModeChannelHalfOp(Instance),
996 new ModeChannelVoice(Instance),
998 new ModeUserWallops(Instance),
999 new ModeUserInvisible(Instance),
1000 new ModeUserOperator(Instance),
1001 new ModeUserServerNoticeMask(Instance),
1002 #define BUILTIN_MODE_COUNT 16
1005 /* Clear mode handler list */
1006 memset(modehandlers, 0, sizeof(modehandlers));
1008 /* Last parse string */
1011 /* Initialise the RFC mode letters */
1012 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1013 this->AddMode(modes[index]);
1016 memset(&sent, 0, sizeof(sent));
1019 ModeParser::~ModeParser()
1022 for(int i=0; i < 256; i++)
1024 ModeHandler* mh = modehandlers[i];
1031 if (count != BUILTIN_MODE_COUNT)
1032 throw CoreException("Mode handler found non-core modes remaining at deallocation");