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, 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)
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, 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 SimpleUserModeHandler::SimpleUserModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_USER, false)
167 SimpleUserModeHandler::~SimpleUserModeHandler()
171 SimpleChannelModeHandler::~SimpleChannelModeHandler()
175 SimpleChannelModeHandler::SimpleChannelModeHandler(InspIRCd* Instance, char modeletter) : ModeHandler(Instance, modeletter, 0, 0, false, MODETYPE_CHANNEL, false)
179 ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
183 if (!dest->IsModeSet(this->GetModeChar()))
185 dest->SetMode(this->GetModeChar(),true);
186 return MODEACTION_ALLOW;
191 if (dest->IsModeSet(this->GetModeChar()))
193 dest->SetMode(this->GetModeChar(),false);
194 return MODEACTION_ALLOW;
198 return MODEACTION_DENY;
202 ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding, bool servermode)
206 if (!channel->IsModeSet(this->GetModeChar()))
208 channel->SetMode(this->GetModeChar(),true);
209 return MODEACTION_ALLOW;
214 if (channel->IsModeSet(this->GetModeChar()))
216 channel->SetMode(this->GetModeChar(),false);
217 return MODEACTION_ALLOW;
221 return MODEACTION_DENY;
224 ModeWatcher::ModeWatcher(InspIRCd* Instance, char modeletter, ModeType type) : ServerInstance(Instance), mode(modeletter), m_type(type)
228 ModeWatcher::~ModeWatcher()
232 char ModeWatcher::GetModeChar()
237 ModeType ModeWatcher::GetModeType()
242 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool, ModeType, bool)
247 void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool, ModeType, bool)
251 User* ModeParser::SanityChecks(User *user, const char *dest, Channel *chan, int)
254 if ((!user) || (!dest) || (!chan) || (!*dest))
258 d = ServerInstance->FindNick(dest);
261 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), dest);
267 const char* ModeParser::Grant(User *d,Channel *chan,int MASK)
272 UCListIter n = d->chans.find(chan);
273 if (n != d->chans.end())
275 if (n->second & MASK)
279 n->second = n->second | MASK;
283 n->first->AddOppedUser(d);
286 n->first->AddHalfoppedUser(d);
289 n->first->AddVoicedUser(d);
292 return d->nick.c_str();
297 const char* ModeParser::Revoke(User *d,Channel *chan,int MASK)
302 UCListIter n = d->chans.find(chan);
303 if (n != d->chans.end())
305 if ((n->second & MASK) == 0)
313 n->first->DelOppedUser(d);
316 n->first->DelHalfoppedUser(d);
319 n->first->DelVoicedUser(d);
322 return d->nick.c_str();
327 void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targetchannel, const char* text)
331 /* Display channel's current mode string */
332 user->WriteNumeric(RPL_CHANNELMODEIS, "%s %s +%s",user->nick.c_str(), targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
333 user->WriteNumeric(RPL_CHANNELCREATED, "%s %s %lu", user->nick.c_str(), targetchannel->name.c_str(), (unsigned long)targetchannel->age);
338 if (targetuser->Visibility && !targetuser->Visibility->VisibleTo(user))
340 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), text);
344 if (targetuser == user || user->HasPrivPermission("users/auspex"))
346 /* Display user's current mode string */
347 user->WriteNumeric(RPL_UMODEIS, "%s :+%s",targetuser->nick.c_str(),targetuser->FormatModes());
348 if (IS_OPER(targetuser))
349 user->WriteNumeric(RPL_SNOMASKIS, "%s +%s :Server notice mask", targetuser->nick.c_str(), targetuser->FormatNoticeMasks());
354 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
360 ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar,
361 std::string ¶meter, bool servermode, bool SkipACL)
363 ModeType type = chan ? MODETYPE_CHANNEL : MODETYPE_USER;
364 unsigned char mask = chan ? MASK_CHANNEL : MASK_USER;
366 ModeHandler *mh = FindMode(modechar, type);
367 int pcnt = mh->GetNumParams(adding);
370 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, chan, modechar, parameter, adding, pcnt, servermode));
372 if (IS_LOCAL(user) && (MOD_RESULT == ACR_DENY))
373 return MODEACTION_DENY;
375 if (chan && !SkipACL && (MOD_RESULT != ACR_ALLOW))
377 char needed = mh->GetNeededPrefix();
378 ModeHandler* prefixmode = FindPrefix(needed);
380 /* If the mode defined by the handler is not '\0', but the handler for it
381 * cannot be found, they probably dont have the right module loaded to implement
382 * the prefix they want to compare the mode against, e.g. '&' for m_chanprotect.
383 * Revert to checking against the minimum core prefix, '%'.
385 if (needed && !prefixmode)
387 needed = ServerInstance->Config->AllowHalfop ? '%' : '@';
388 prefixmode = FindPrefix(needed);
393 unsigned int neededrank = prefixmode->GetPrefixRank();
394 /* Compare our rank on the channel against the rank of the required prefix,
395 * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
396 * in NAMES(X) are not in rank order, we know the most powerful mode is listed
397 * first, so we don't need to iterate, we just look up the first instead.
399 std::string modestring = chan->GetAllPrefixChars(user);
400 char ml = (modestring.empty() ? '\0' : modestring[0]);
401 ModeHandler* ourmode = FindPrefix(ml);
402 if (!ourmode || ourmode->GetPrefixRank() < neededrank)
405 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must have channel privilege %c or above to %sset channel mode %c",
406 user->nick.c_str(), chan->name.c_str(), needed, adding ? "" : "un", modechar);
407 return MODEACTION_DENY;
412 unsigned char handler_id = (modechar - 'A') | mask;
414 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
416 if ((*watchers)->BeforeMode(user, targetuser, chan, parameter, adding, type, servermode) == false)
417 return MODEACTION_DENY;
418 /* A module whacked the parameter completely, and there was one. abort. */
419 if (pcnt && parameter.empty())
420 return MODEACTION_DENY;
423 if (IS_LOCAL(user) && !IS_OPER(user))
425 char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
426 if (disabled[modechar - 'A'])
428 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - %s mode %c has been locked by the administrator",
429 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
430 return MODEACTION_DENY;
434 if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
436 /* It's an oper only mode, and they don't have access to it. */
439 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Oper type %s does not have access to set %s mode %c",
440 user->nick.c_str(), user->oper.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
444 user->WriteNumeric(ERR_NOPRIVILEGES, "%s :Permission Denied - Only operators may set %s mode %c",
445 user->nick.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
447 return MODEACTION_DENY;
450 /* Call the handler for the mode */
451 ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding, servermode);
453 if (pcnt && parameter.empty())
454 return MODEACTION_DENY;
456 if (ma != MODEACTION_ALLOW)
459 mh->ChangeCount(adding ? 1 : -1);
461 if (mh->GetPrefix() && chan)
463 User* user_to_prefix = ServerInstance->FindNick(parameter);
465 chan->SetPrefix(user_to_prefix, mh->GetPrefix(), mh->GetPrefixRank(), adding);
468 for (ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
469 (*watchers)->AfterMode(user, targetuser, chan, parameter, adding, type, servermode);
471 return MODEACTION_ALLOW;
474 void ModeParser::Process(const std::vector<std::string>& parameters, User *user, bool servermode, bool merge)
476 std::string target = parameters[0];
477 Channel* targetchannel = ServerInstance->FindChan(target);
478 User* targetuser = ServerInstance->FindNick(target);
479 ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
482 LastParseParams.clear();
483 LastParseTranslate.clear();
485 if (!targetchannel && !targetuser)
487 user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(),target.c_str());
490 if (parameters.size() == 1)
492 this->DisplayCurrentModes(user, targetuser, targetchannel, target.c_str());
496 std::string mode_sequence = parameters[1];
498 bool SkipAccessChecks = false;
500 if (servermode || !IS_LOCAL(user) || ServerInstance->ULine(user->server))
502 SkipAccessChecks = true;
504 else if (targetchannel)
506 /* Overall access control hook for mode change */
507 LastParse = mode_sequence;
509 FOREACH_RESULT(I_OnAccessCheck,OnAccessCheck(user, NULL, targetchannel, AC_GENERAL_MODE));
511 if (MOD_RESULT == ACR_DENY)
513 SkipAccessChecks = (MOD_RESULT == ACR_ALLOW);
517 if (user != targetuser)
519 user->WriteNumeric(ERR_USERSDONTMATCH, "%s :Can't change mode for other users", user->nick.c_str());
525 std::string output_mode;
526 std::ostringstream output_parameters;
527 LastParseParams.push_back(output_mode);
528 LastParseTranslate.push_back(TR_TEXT);
531 char output_pm = '\0'; // current output state, '+' or '-'
532 unsigned int param_at = 2;
534 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
536 unsigned char modechar = *letter;
537 if (modechar == '+' || modechar == '-')
539 adding = (modechar == '+');
543 ModeHandler *mh = this->FindMode(modechar, type);
546 /* No mode handler? Unknown mode character then. */
547 user->WriteServ("%d %s %c :is unknown mode char to me", type == MODETYPE_CHANNEL ? 472 : 501, user->nick.c_str(), modechar);
551 std::string parameter = "";
552 int pcnt = mh->GetNumParams(adding);
553 if (pcnt && param_at == parameters.size())
555 /* No parameter, continue to the next mode */
556 mh->OnParameterMissing(user, targetuser, targetchannel);
561 parameter = parameters[param_at++];
562 /* Make sure the user isn't trying to slip in an invalid parameter */
563 if ((parameter.find(':') == 0) || (parameter.rfind(' ') != std::string::npos))
565 if (merge && targetchannel && targetchannel->IsModeSet(modechar) && !mh->IsListMode())
567 std::string ours = targetchannel->GetModeParameter(modechar);
568 if (!mh->CheckTimeStamp(parameter, ours, targetchannel))
569 /* we won the mode merge, don't apply this mode */
574 ModeAction ma = TryMode(user, targetuser, targetchannel, adding, modechar, parameter, servermode, SkipAccessChecks);
576 if (ma != MODEACTION_ALLOW)
579 char needed_pm = adding ? '+' : '-';
580 if (needed_pm != output_pm)
582 output_pm = needed_pm;
583 output_mode.append(1, output_pm);
585 output_mode.append(1, modechar);
589 output_parameters << " " << parameter;
590 LastParseParams.push_back(parameter);
591 LastParseTranslate.push_back(mh->GetTranslateType());
594 if ( (output_mode.length() + output_parameters.str().length() > 450)
595 || (output_mode.length() > 100)
596 || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes))
598 /* mode sequence is getting too long */
603 LastParseParams[0] = output_mode;
605 if (!output_mode.empty())
607 LastParse = targetchannel ? targetchannel->name : targetuser->nick;
608 LastParse.append(" ");
609 LastParse.append(output_mode);
610 LastParse.append(output_parameters.str());
612 if (!user && targetchannel)
613 targetchannel->WriteChannelWithServ(ServerInstance->Config->ServerName, "MODE %s", LastParse.c_str());
614 else if (!user && targetuser)
615 targetuser->WriteServ("MODE %s", LastParse.c_str());
616 else if (targetchannel)
618 targetchannel->WriteChannel(user, "MODE %s", LastParse.c_str());
619 FOREACH_MOD(I_OnMode,OnMode(user, targetchannel, TYPE_CHANNEL, LastParseParams, LastParseTranslate));
623 targetuser->WriteFrom(user, "MODE %s", LastParse.c_str());
624 FOREACH_MOD(I_OnMode,OnMode(user, targetuser, TYPE_USER, LastParseParams, LastParseTranslate));
627 else if (targetchannel && parameters.size() == 2)
629 /* Special case for displaying the list for listmodes,
630 * e.g. MODE #chan b, or MODE #chan +b without a parameter
632 this->DisplayListModes(user, targetchannel, mode_sequence);
636 void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence)
640 for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
642 unsigned char mletter = *letter;
646 /* Ensure the user doesnt request the same mode twice,
647 * so they cant flood themselves off out of idiocy.
649 if (sent[mletter] == seq)
654 ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
656 if (!mh || !mh->IsListMode())
660 FOREACH_RESULT(I_OnRawMode, OnRawMode(user, chan, mletter, "", true, 0));
661 if (MOD_RESULT == ACR_DENY)
665 if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetStatus(user) < STATUS_HOP))
667 user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only half-operators and above may view the +%c list",
668 user->nick.c_str(), chan->name.c_str(), mletter);
672 /** See below for a description of what craq this is :D
674 unsigned char handler_id = (mletter - 'A') | MASK_CHANNEL;
676 for(ModeWatchIter watchers = modewatchers[handler_id].begin(); watchers != modewatchers[handler_id].end(); watchers++)
678 std::string dummyparam;
680 if (!((*watchers)->BeforeMode(user, NULL, chan, dummyparam, true, MODETYPE_CHANNEL)))
684 mh->DisplayList(user, chan);
686 mh->DisplayEmptyList(user, chan);
690 const std::string& ModeParser::GetLastParse()
695 void ModeParser::CleanMask(std::string &mask)
697 std::string::size_type pos_of_pling = mask.find_first_of('!');
698 std::string::size_type pos_of_at = mask.find_first_of('@');
699 std::string::size_type pos_of_dot = mask.find_first_of('.');
700 std::string::size_type pos_of_colons = mask.find("::"); /* Because ipv6 addresses are colon delimited -- double so it treats extban as nick */
702 if (mask.length() >= 2 && mask[1] == ':')
703 return; // if it's an extban, don't even try guess how it needs to be formed.
705 if ((pos_of_pling == std::string::npos) && (pos_of_at == std::string::npos))
707 /* Just a nick, or just a host - or clearly ipv6 (starting with :) */
708 if ((pos_of_dot == std::string::npos) && (pos_of_colons == std::string::npos) && mask[0] != ':')
710 /* It has no '.' in it, it must be a nick. */
715 /* Got a dot in it? Has to be a host */
716 mask = "*!*@" + mask;
719 else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos))
721 /* Has an @ but no !, its a user@host */
724 else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos))
726 /* Has a ! but no @, it must be a nick!ident */
731 bool ModeParser::AddMode(ModeHandler* mh)
733 unsigned char mask = 0;
734 unsigned char pos = 0;
736 /* Yes, i know, this might let people declare modes like '_' or '^'.
737 * If they do that, thats their problem, and if i ever EVER see an
738 * official InspIRCd developer do that, i'll beat them with a paddle!
740 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z') || (mh->GetPrefix() > 126))
743 /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
744 * A mode prefix of ':' will fuck up both server to server, and client to server.
745 * A mode prefix of '#' will mess up /whois and /privmsg
747 if ((mh->GetPrefix() == ',') || (mh->GetPrefix() == ':') || (mh->GetPrefix() == '#'))
750 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
751 pos = (mh->GetModeChar()-65) | mask;
753 if (modehandlers[pos])
756 modehandlers[pos] = mh;
760 bool ModeParser::DelMode(ModeHandler* mh)
762 unsigned char mask = 0;
763 unsigned char pos = 0;
765 if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
768 mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
769 pos = (mh->GetModeChar()-65) | mask;
771 if (!modehandlers[pos])
774 /* Note: We can't stack here, as we have modes potentially being removed across many different channels.
775 * To stack here we have to make the algorithm slower. Discuss.
777 switch (mh->GetModeType())
780 for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++)
782 mh->RemoveMode(i->second);
785 case MODETYPE_CHANNEL:
786 for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++)
788 mh->RemoveMode(i->second);
793 modehandlers[pos] = NULL;
798 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
800 unsigned char mask = 0;
801 unsigned char pos = 0;
803 if ((modeletter < 'A') || (modeletter > 'z'))
806 mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
807 pos = (modeletter-65) | mask;
809 return modehandlers[pos];
812 std::string ModeParser::UserModeList()
817 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
819 unsigned char pos = (mode-65) | MASK_USER;
821 if (modehandlers[pos])
822 modestr[pointer++] = mode;
824 modestr[pointer++] = 0;
828 std::string ModeParser::ChannelModeList()
833 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
835 unsigned char pos = (mode-65) | MASK_CHANNEL;
837 if (modehandlers[pos])
838 modestr[pointer++] = mode;
840 modestr[pointer++] = 0;
844 std::string ModeParser::ParaModeList()
849 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
851 unsigned char pos = (mode-65) | MASK_CHANNEL;
853 if ((modehandlers[pos]) && (modehandlers[pos]->GetNumParams(true)))
854 modestr[pointer++] = mode;
856 modestr[pointer++] = 0;
860 ModeHandler* ModeParser::FindPrefix(unsigned const char pfxletter)
862 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
864 unsigned char pos = (mode-65) | MASK_CHANNEL;
866 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix() == pfxletter))
868 return modehandlers[pos];
874 std::string ModeParser::ModeString(User* user, Channel* channel, bool nick_suffix)
879 if (!channel || !user)
882 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
884 unsigned char pos = (mode-65) | MASK_CHANNEL;
885 ModeHandler* mh = modehandlers[pos];
886 if ((mh) && (mh->GetNumParams(true)) && (mh->GetNumParams(false)))
889 ret = mh->ModeSet(NULL, user, channel, user->nick);
890 if ((ret.first) && (ret.second == user->nick))
895 pars.append(user->nick);
897 types.push_back(mh->GetModeChar());
908 std::string ModeParser::GiveModeList(ModeMasks m)
910 std::string type1; /* Listmodes EXCEPT those with a prefix */
911 std::string type2; /* Modes that take a param when adding or removing */
912 std::string type3; /* Modes that only take a param when adding */
913 std::string type4; /* Modes that dont take a param */
915 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
917 unsigned char pos = (mode-65) | m;
918 /* One parameter when adding */
919 if (modehandlers[pos])
921 if (modehandlers[pos]->GetNumParams(true))
923 if ((modehandlers[pos]->IsListMode()) && (!modehandlers[pos]->GetPrefix()))
925 type1 += modehandlers[pos]->GetModeChar();
929 /* ... and one parameter when removing */
930 if (modehandlers[pos]->GetNumParams(false))
932 /* But not a list mode */
933 if (!modehandlers[pos]->GetPrefix())
935 type2 += modehandlers[pos]->GetModeChar();
940 /* No parameters when removing */
941 type3 += modehandlers[pos]->GetModeChar();
947 type4 += modehandlers[pos]->GetModeChar();
952 return type1 + "," + type2 + "," + type3 + "," + type4;
955 bool ModeParser::PrefixComparison(prefixtype one, prefixtype two)
957 return one.second > two.second;
960 std::string ModeParser::BuildPrefixes()
962 std::string mletters;
963 std::string mprefixes;
965 std::map<char,char> prefix_to_mode;
967 for (unsigned char mode = 'A'; mode <= 'z'; mode++)
969 unsigned char pos = (mode-65) | MASK_CHANNEL;
971 if ((modehandlers[pos]) && (modehandlers[pos]->GetPrefix()))
973 pfx.push_back(std::make_pair<char,unsigned int>(modehandlers[pos]->GetPrefix(), modehandlers[pos]->GetPrefixRank()));
974 prefix_to_mode[modehandlers[pos]->GetPrefix()] = modehandlers[pos]->GetModeChar();
978 sort(pfx.begin(), pfx.end(), ModeParser::PrefixComparison);
980 for (pfxcontainer::iterator n = pfx.begin(); n != pfx.end(); n++)
982 mletters = mletters + n->first;
983 mprefixes = mprefixes + prefix_to_mode.find(n->first)->second;
986 return "(" + mprefixes + ")" + mletters;
989 bool ModeParser::AddModeWatcher(ModeWatcher* mw)
991 unsigned char mask = 0;
992 unsigned char pos = 0;
997 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1000 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1001 pos = (mw->GetModeChar()-65) | mask;
1003 modewatchers[pos].push_back(mw);
1008 bool ModeParser::DelModeWatcher(ModeWatcher* mw)
1010 unsigned char mask = 0;
1011 unsigned char pos = 0;
1016 if ((mw->GetModeChar() < 'A') || (mw->GetModeChar() > 'z'))
1019 mw->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL;
1020 pos = (mw->GetModeChar()-65) | mask;
1022 ModeWatchIter a = find(modewatchers[pos].begin(),modewatchers[pos].end(),mw);
1024 if (a == modewatchers[pos].end())
1029 modewatchers[pos].erase(a);
1034 /** This default implementation can remove simple user modes
1036 void ModeHandler::RemoveMode(User* user, irc::modestacker* stack)
1038 char moderemove[MAXBUF];
1039 std::vector<std::string> parameters;
1041 if (user->IsModeSet(this->GetModeChar()))
1045 stack->Push(this->GetModeChar());
1049 sprintf(moderemove,"-%c",this->GetModeChar());
1050 parameters.push_back(user->nick);
1051 parameters.push_back(moderemove);
1052 ServerInstance->Modes->Process(parameters, ServerInstance->FakeClient, true);
1057 /** This default implementation can remove simple channel modes
1060 void ModeHandler::RemoveMode(Channel* channel, irc::modestacker* stack)
1062 char moderemove[MAXBUF];
1063 std::vector<std::string> parameters;
1065 if (channel->IsModeSet(this->GetModeChar()))
1069 stack->Push(this->GetModeChar());
1073 sprintf(moderemove,"-%c",this->GetModeChar());
1074 parameters.push_back(channel->name);
1075 parameters.push_back(moderemove);
1076 ServerInstance->SendMode(parameters, ServerInstance->FakeClient);
1081 ModeParser::ModeParser(InspIRCd* Instance) : ServerInstance(Instance)
1083 ModeHandler* modes[] =
1085 new ModeChannelSecret(Instance),
1086 new ModeChannelPrivate(Instance),
1087 new ModeChannelModerated(Instance),
1088 new ModeChannelTopicOps(Instance),
1090 new ModeChannelNoExternal(Instance),
1091 new ModeChannelInviteOnly(Instance),
1092 new ModeChannelKey(Instance),
1093 new ModeChannelLimit(Instance),
1095 new ModeChannelBan(Instance),
1096 new ModeChannelOp(Instance),
1097 new ModeChannelHalfOp(Instance),
1098 new ModeChannelVoice(Instance),
1100 new ModeUserWallops(Instance),
1101 new ModeUserInvisible(Instance),
1102 new ModeUserOperator(Instance),
1103 new ModeUserServerNoticeMask(Instance),
1104 #define BUILTIN_MODE_COUNT 16
1107 /* Clear mode handler list */
1108 memset(modehandlers, 0, sizeof(modehandlers));
1110 /* Last parse string */
1113 /* Initialise the RFC mode letters */
1114 for (int index = 0; index < BUILTIN_MODE_COUNT; index++)
1115 this->AddMode(modes[index]);
1118 memset(&sent, 0, sizeof(sent));
1121 ModeParser::~ModeParser()
1124 for(int i=0; i < 256; i++)
1126 ModeHandler* mh = modehandlers[i];
1133 if (count != BUILTIN_MODE_COUNT)
1134 throw CoreException("Mode handler found non-core modes remaining at deallocation");