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 /* Overall access control hook for mode change */
423 int hook = targetchannel ? AC_GENERAL_MODE : AC_GENERAL_UMODE;
425 LastParse = mode_sequence;
426 ModResult MOD_RESULT;
427 FIRST_MOD_RESULT(ServerInstance, OnAccessCheck, MOD_RESULT, (user, targetuser, targetchannel, hook));
429 if (MOD_RESULT == MOD_RES_DENY)
431 SkipAccessChecks = (MOD_RESULT == MOD_RES_ALLOW);
434 if (targetuser && !SkipAccessChecks && user != targetuser)
436 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
440 std::string output_mode;
441 std::ostringstream output_parameters;
442 LastParseParams.push_back(output_mode);
443 LastParseTranslate.push_back(TR_TEXT);
446 char output_pm = '\0'; // current output state, '+' or '-'
447 unsigned int param_at = 2;
449 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
451 unsigned char modechar = *letter;
452 if (modechar == '+' || modechar == '-')
454 adding = (modechar == '+');
458 ModeHandler *mh = this->FindMode(modechar, type);
461 /* No mode handler? Unknown mode character then. */
462 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
466 std::string parameter = "";
467 int pcnt = mh->GetNumParams(adding);
468 if (pcnt && param_at == parameters.size())
470 /* No parameter, continue to the next mode */
471 mh->OnParameterMissing(user, targetuser, targetchannel);
476 parameter = parameters[param_at++];
477 /* Make sure the user isn't trying to slip in an invalid parameter */
478 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
480 if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
482 std::string ours = targetchannel->GetModeParameter(modechar);
483 if (!mh->CheckTimeStamp(parameter, ours, targetchannel))
484 /* we won the mode merge, don't apply this mode */
489 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, SkipAccessChecks);
491 if (ma != MODEACTION_ALLOW)
494 char needed_pm = adding ? '+' : '-';
495 if (needed_pm != output_pm)
497 output_pm = needed_pm;
498 output_mode.append(1, output_pm);
500 output_mode.append(1, modechar);
504 output_parameters << " " << parameter;
505 LastParseParams.push_back(parameter);
506 LastParseTranslate.push_back(mh->GetTranslateType());
509 if ( (output_mode.length() + output_parameters.str().length() > 450)
510 || (output_mode.length() > 100)
511 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
513 /* mode sequence is getting too long */
518 LastParseParams[0] = output_mode;
520 if (!output_mode.empty())
522 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
523 LastParse.append(" ");
524 LastParse.append(output_mode);
525 LastParse.append(output_parameters.str());
529 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
530 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
534 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
535 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
538 else if (targetchannel && parameters.size() == 2)
540 /* Special case for displaying the list for listmodes,
541 * e.g. MODE #chan b, or MODE #chan +b without a parameter
543 this->DisplayListModes(user, targetchannel, mode_sequence);
547 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
551 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
553 unsigned char mletter = *letter;
557 /* Ensure the user doesnt request the same mode twice,
558 * so they cant flood themselves off out of idiocy.
560 if (sent[mletter] == seq)
565 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
567 if (!mh || !mh->IsListMode())
570 ModResult MOD_RESULT;
571 FIRST_MOD_RESULT(ServerInstance, OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0));
572 if (MOD_RESULT == MOD_RES_DENY)
576 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE))
578 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
579 user->nick.c_str(), chan->name.c_str(), mletter);
583 /** See below for a description of what craq this is :D
585 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
587 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
589 std::string dummyparam;
591 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
595 mh->DisplayList(user, chan);
597 mh->DisplayEmptyList(user, chan);
601 const std::string& ModeParser::GetLastParse()
606 void ModeParser::CleanMask(std::string &mask)
608 std::string::size_type pos_of_pling = mask.find_first_of('!');
609 std::string::size_type pos_of_at = mask.find_first_of('@');
610 std::string::size_type pos_of_dot = mask.find_first_of('.');
611 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
613 if (mask.length() >= 2 && mask[1] == ':')
614 return; // if it's an extban, don't even try guess how it needs to be formed.
616 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
618 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
619 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
621 /* It has no '.' in it, it must be a nick. */
626 /* Got a dot in it? Has to be a host */
627 mask = "*!*@" + mask;
630 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
632 /* Has an @ but no !, its a user@host */
635 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
637 /* Has a ! but no @, it must be a nick!ident */
642 bool ModeParser::AddMode(ModeHandler* mh)
644 unsigned char mask = 0;
645 unsigned char pos = 0;
647 /* Yes, i know, this might let people declare modes like '_' or '^'.
648 * If they do that, thats their problem, and if i ever EVER see an
649 * official InspIRCd developer do that, i'll beat them with a paddle!
651 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
654 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
655 * A mode prefix of ':' will fuck up both server to server, and client to server.
656 * A mode prefix of '#' will mess up /whois and /privmsg
658 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
661 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
662 pos = (mh->GetModeChar()-65) | mask;
664 if (modehandlers[pos])
667 modehandlers[pos] = mh;
671 bool ModeParser::DelMode(ModeHandler* mh)
673 unsigned char mask = 0;
674 unsigned char pos = 0;
676 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
679 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
680 pos = (mh->GetModeChar()-65) | mask;
682 if (!modehandlers[pos])
685 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
686 * To stack here we have to make the algorithm slower. Discuss.
688 switch (mh->GetModeType())
691 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
693 mh->RemoveMode(i->second);
696 case MODETYPE_CHANNEL:
697 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
699 mh->RemoveMode(i->second);
704 modehandlers[pos] = NULL;
709 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
711 unsigned char mask = 0;
712 unsigned char pos = 0;
714 if ((modeletter < 'A') || (modeletter > 'z'))
717 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
718 pos = (modeletter-65) | mask;
720 return modehandlers[pos];
723 std::string ModeParser::UserModeList()
728 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
730 unsigned char pos = (mode-65) | MASK_USER;
732 if (modehandlers[pos])
733 modestr[pointer++] = mode;
735 modestr[pointer++] = 0;
739 std::string ModeParser::ChannelModeList()
744 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
746 unsigned char pos = (mode-65) | MASK_CHANNEL;
748 if (modehandlers[pos])
749 modestr[pointer++] = mode;
751 modestr[pointer++] = 0;
755 std::string ModeParser::ParaModeList()
760 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
762 unsigned char pos = (mode-65) | MASK_CHANNEL;
764 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
765 modestr[pointer++] = mode;
767 modestr[pointer++] = 0;
771 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
773 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
775 unsigned char pos = (mode-65) | MASK_CHANNEL;
777 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
779 return modehandlers[pos];
785 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
790 if (!channel || !user)
793 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
795 unsigned char pos = (mode-65) | MASK_CHANNEL;
796 ModeHandler* mh = modehandlers[pos];
797 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
800 ret = mh->ModeSet(NULL, user, channel, user->nick);
801 if ((ret.first) && (ret.second == user->nick))
806 pars.append(user->nick);
808 types.push_back(mh->GetModeChar());
819 std::string ModeParser::GiveModeList(ModeMasks m)
821 std::string type1; /* Listmodes EXCEPT those with a prefix */
822 std::string type2; /* Modes that take a param when adding or removing */
823 std::string type3; /* Modes that only take a param when adding */
824 std::string type4; /* Modes that dont take a param */
826 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
828 unsigned char pos = (mode-65) | m;
829 /* One parameter when adding */
830 if (modehandlers[pos])
832 if (modehandlers[pos]->GetNumParams(true))
834 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
836 type1 += modehandlers[pos]->GetModeChar();
840 /* ... and one parameter when removing */
841 if (modehandlers[pos]->GetNumParams(false))
843 /* But not a list mode */
844 if (!modehandlers[pos]->GetPrefix())
846 type2 += modehandlers[pos]->GetModeChar();
851 /* No parameters when removing */
852 type3 += modehandlers[pos]->GetModeChar();
858 type4 += modehandlers[pos]->GetModeChar();
863 return type1 + "," + type2 + "," + type3 + "," + type4;
866 std::string ModeParser::BuildPrefixes()
868 std::string mletters;
869 std::string mprefixes;
870 std::map<int,std::pair<char,char> > prefixes;
872 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
874 unsigned char pos = (mode-65) | MASK_CHANNEL;
876 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
878 prefixes[modehandlers[pos]->GetPrefixRank()] = std::make_pair(
879 modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetModeChar());
883 for(std::map<int,std::pair<char,char> >::iterator n = prefixes.begin(); n != prefixes.end(); n++)
885 mletters = mletters + n->second.first;
886 mprefixes = mprefixes + n->second.second;
889 return "(" + mprefixes + ")" + mletters;
892 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
894 unsigned char mask = 0;
895 unsigned char pos = 0;
900 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
903 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
904 pos = (mw->GetModeChar()-65) | mask;
906 modewatchers[pos].push_back(mw);
911 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
913 unsigned char mask = 0;
914 unsigned char pos = 0;
919 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
922 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
923 pos = (mw->GetModeChar()-65) | mask;
925 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
927 if (a == modewatchers[pos].end())
932 modewatchers[pos].erase(a);
937 /** This default implementation can remove simple user modes
939 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
941 char moderemove[MAXBUF];
942 std::vector<std::string> parameters;
944 if (user->IsModeSet(this->GetModeChar()))
948 stack->Push(this->GetModeChar());
952 sprintf(moderemove,"-%c",this->GetModeChar());
953 parameters.push_back(user->nick);
954 parameters.push_back(moderemove);
955 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient);
960 /** This default implementation can remove simple channel modes
963 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
965 char moderemove[MAXBUF];
966 std::vector<std::string> parameters;
968 if (channel->IsModeSet(this->GetModeChar()))
972 stack->Push(this->GetModeChar());
976 sprintf(moderemove,"-%c",this->GetModeChar());
977 parameters.push_back(channel->name);
978 parameters.push_back(moderemove);
979 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
984 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
986 ModeHandler* modes[] =
988 new ModeChannelSecret(Instance),
989 new ModeChannelPrivate(Instance),
990 new ModeChannelModerated(Instance),
991 new ModeChannelTopicOps(Instance),
993 new ModeChannelNoExternal(Instance),
994 new ModeChannelInviteOnly(Instance),
995 new ModeChannelKey(Instance),
996 new ModeChannelLimit(Instance),
998 new ModeChannelBan(Instance),
999 new ModeChannelOp(Instance),
1000 new ModeChannelHalfOp(Instance),
1001 new ModeChannelVoice(Instance),
1003 new ModeUserWallops(Instance),
1004 new ModeUserInvisible(Instance),
1005 new ModeUserOperator(Instance),
1006 new ModeUserServerNoticeMask(Instance),
1007 #define BUILTIN_MODE_COUNT 16
1010 /* Clear mode handler list */
1011 memset(modehandlers, 0, sizeof(modehandlers));
1013 /* Last parse string */
1016 /* Initialise the RFC mode letters */
1017 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1018 this->AddMode(modes[index]);
1021 memset(&sent, 0, sizeof(sent));
1024 ModeParser::~ModeParser()
1027 for(int i=0; i < 256; i++)
1029 ModeHandler* mh = modehandlers[i];
1036 if (count != BUILTIN_MODE_COUNT)
1037 throw CoreException("Mode handler found non-core modes remaining at deallocation");