#include "inspircd.h"
-#include "builtinmodes.h"
ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modeletter, ParamSpec Params, ModeType type, Class mclass)
- : ServiceProvider(Creator, Name, SERVICE_MODE), modeid(ModeParser::MODEID_MAX),
- parameters_taken(Params), mode(modeletter), oper(false),
- list(false), m_type(type), type_id(mclass), levelrequired(HALFOP_VALUE)
+ : ServiceProvider(Creator, Name, SERVICE_MODE)
+ , modeid(ModeParser::MODEID_MAX)
+ , parameters_taken(Params)
+ , mode(modeletter)
+ , oper(false)
+ , list(false)
+ , m_type(type)
+ , type_id(mclass)
+ , ranktoset(HALFOP_VALUE)
+ , ranktounset(HALFOP_VALUE)
{
}
void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
{
+ std::string message = InspIRCd::Format("You must specify a parameter for the %s mode.", name.c_str());
+ if (!syntax.empty())
+ message.append(InspIRCd::Format(" Syntax: %s.", syntax.c_str()));
+
+ if (channel)
+ user->WriteNumeric(Numerics::InvalidModeParameter(channel, this, "*", message));
+ else
+ user->WriteNumeric(Numerics::InvalidModeParameter(dest, this, "*", message));
}
bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ours, Channel*)
PrefixMode::PrefixMode(Module* Creator, const std::string& Name, char ModeLetter, unsigned int Rank, char PrefixChar)
: ModeHandler(Creator, Name, ModeLetter, PARAM_ALWAYS, MODETYPE_CHANNEL, MC_PREFIX)
- , prefix(PrefixChar), prefixrank(Rank)
+ , prefix(PrefixChar)
+ , prefixrank(Rank)
+ , selfremove(true)
{
list = true;
+ syntax = "<nick>";
+}
+
+ModResult PrefixMode::AccessCheck(User* src, Channel*, std::string& value, bool adding)
+{
+ if (!adding && src->nick == value && selfremove)
+ return MOD_RES_ALLOW;
+ return MOD_RES_PASSTHRU;
}
ModeAction PrefixMode::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding)
return (memb->SetPrefix(this, adding) ? MODEACTION_ALLOW : MODEACTION_DENY);
}
+void PrefixMode::Update(unsigned int rank, unsigned int setrank, unsigned int unsetrank, bool selfrm)
+{
+ prefixrank = rank;
+ ranktoset = setrank;
+ ranktounset = unsetrank;
+ selfremove = selfrm;
+}
+
ModeAction ParamModeBase::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding)
{
if (adding)
const bool needs_param = mh->NeedsParam(adding);
std::string& parameter = mcitem.param;
- // crop mode parameter size to 250 characters
- if (parameter.length() > 250 && adding)
- parameter.erase(250);
+ // crop mode parameter size to MODE_PARAM_MAX characters
+ if (parameter.length() > MODE_PARAM_MAX && adding)
+ parameter.erase(MODE_PARAM_MAX);
ModResult MOD_RESULT;
FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mh, parameter, adding));
return MODEACTION_DENY;
if (MOD_RESULT == MOD_RES_PASSTHRU)
{
- unsigned int neededrank = mh->GetLevelRequired();
+ unsigned int neededrank = mh->GetLevelRequired(adding);
/* Compare our rank on the channel against the rank of the required prefix,
* allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
* in NAMES(X) are not in rank order, we know the most powerful mode is listed
}
}
- if (IS_LOCAL(user) && !user->IsOper())
- {
- char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
- if (disabled[modechar - 'A'])
- {
- user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - %s mode %c has been locked by the administrator",
- type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
- return MODEACTION_DENY;
- }
- }
-
- if ((adding) && (IS_LOCAL(user)) && (mh->NeedsOper()) && (!user->HasModePermission(mh)))
+ if ((chan || (!chan && adding)) && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(mh))
{
/* It's an oper only mode, and they don't have access to it. */
if (user->IsOper())
{
- user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to set %s mode %c",
- user->oper->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
+ user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to %sset %s mode %c",
+ user->oper->name.c_str(), adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
}
else
{
- user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Only operators may set %s mode %c",
- type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
+ user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Only operators may %sset %s mode %c",
+ adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
}
return MODEACTION_DENY;
}
if (!mh)
{
/* No mode handler? Unknown mode character then. */
- user->WriteNumeric(type == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK, modechar, "is unknown mode char to me");
+ user->WriteNumeric(type == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK, modechar, "is an unknown mode character");
continue;
}
unsigned int ModeParser::ProcessSingle(User* user, Channel* targetchannel, User* targetuser, Modes::ChangeList& changelist, ModeProcessFlag flags, unsigned int beginindex)
{
- LastParse.clear();
LastChangeList.clear();
unsigned int modes_processed = 0;
- std::string output_mode;
- std::string output_parameters;
-
- char output_pm = '\0'; // current output state, '+' or '-'
Modes::ChangeList::List& list = changelist.getlist();
for (Modes::ChangeList::List::iterator i = list.begin()+beginindex; i != list.end(); ++i)
{
Modes::Change& item = *i;
ModeHandler* mh = item.mh;
+ // If a mode change has been given for a mode that does not exist then reject
+ // it. This can happen when core_reloadmodule attempts to restore a mode that
+ // no longer exists.
+ if (!mh)
+ continue;
+
// If the mode is supposed to have a parameter then we first take a look at item.param
// and, if we were asked to, also handle mode merges now
if (mh->NeedsParam(item.adding))
if (ma != MODEACTION_ALLOW)
continue;
- char needed_pm = item.adding ? '+' : '-';
- if (needed_pm != output_pm)
- {
- output_pm = needed_pm;
- output_mode.append(1, output_pm);
- }
- output_mode.push_back(mh->GetModeChar());
-
- if (!item.param.empty())
- {
- output_parameters.push_back(' ');
- output_parameters.append(item.param);
- }
LastChangeList.push(mh, item.adding, item.param);
- if ((output_mode.length() + output_parameters.length() > 450)
- || (output_mode.length() > 100)
- || (LastChangeList.size() >= ServerInstance->Config->Limits.MaxModes))
+ if (LastChangeList.size() >= ServerInstance->Config->Limits.MaxModes)
{
/* mode sequence is getting too long */
break;
}
}
- if (!output_mode.empty())
+ if (!LastChangeList.empty())
{
- LastParse = targetchannel ? targetchannel->name : targetuser->nick;
- LastParse.append(" ");
- LastParse.append(output_mode);
- LastParse.append(output_parameters);
-
+ ClientProtocol::Events::Mode modeevent(user, targetchannel, targetuser, LastChangeList);
if (targetchannel)
- targetchannel->WriteChannel(user, "MODE " + LastParse);
+ {
+ targetchannel->Write(modeevent);
+ }
else
- targetuser->WriteFrom(user, "MODE " + LastParse);
+ {
+ LocalUser* localtarget = IS_LOCAL(targetuser);
+ if (localtarget)
+ localtarget->Send(modeevent);
+ }
- FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastChangeList, flags, output_mode));
+ FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastChangeList, flags));
}
return modes_processed;
void ModeParser::AddMode(ModeHandler* mh)
{
- /* Yes, i know, this might let people declare modes like '_' or '^'.
- * If they do that, thats their problem, and if i ever EVER see an
- * official InspIRCd developer do that, i'll beat them with a paddle!
- */
- if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
- throw ModuleException("Invalid letter for mode " + mh->name);
+ if (!ModeParser::IsModeChar(mh->GetModeChar()))
+ throw ModuleException(InspIRCd::Format("Mode letter for %s is invalid: %c",
+ mh->name.c_str(), mh->GetModeChar()));
/* A mode prefix of ',' is not acceptable, it would fuck up server to server.
* A mode prefix of ':' will fuck up both server to server, and client to server.
if (pm)
{
if ((pm->GetPrefix() > 126) || (pm->GetPrefix() == ',') || (pm->GetPrefix() == ':') || (pm->GetPrefix() == '#'))
- throw ModuleException("Invalid prefix for mode " + mh->name);
+ throw ModuleException(InspIRCd::Format("Mode prefix for %s is invalid: %c",
+ mh->name.c_str(), pm->GetPrefix()));
- if (FindPrefix(pm->GetPrefix()))
- throw ModuleException("Prefix already exists for mode " + mh->name);
+ PrefixMode* otherpm = FindPrefix(pm->GetPrefix());
+ if (otherpm)
+ throw ModuleException(InspIRCd::Format("Mode prefix for %s already used by %s from %s: %c",
+ mh->name.c_str(), otherpm->name.c_str(), otherpm->creator->ModuleSourceFile.c_str(), pm->GetPrefix()));
}
ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65];
if (slot)
- throw ModuleException("Letter is already in use for mode " + mh->name);
+ throw ModuleException(InspIRCd::Format("Mode letter for %s already used by %s from %s: %c",
+ mh->name.c_str(), slot->name.c_str(), slot->creator->ModuleSourceFile.c_str(), mh->GetModeChar()));
// The mode needs an id if it is either a user mode, a simple mode (flag) or a parameter mode.
// Otherwise (for listmodes and prefix modes) the id remains MODEID_MAX, which is invalid.
if ((mh->GetModeType() == MODETYPE_USER) || (mh->IsParameterMode()) || (!mh->IsListMode()))
modeid = AllocateModeId(mh->GetModeType());
- if (!modehandlersbyname[mh->GetModeType()].insert(std::make_pair(mh->name, mh)).second)
- throw ModuleException("Mode name already in use: " + mh->name);
+ std::pair<ModeHandlerMap::iterator, bool> res = modehandlersbyname[mh->GetModeType()].insert(std::make_pair(mh->name, mh));
+ if (!res.second)
+ {
+ ModeHandler* othermh = res.first->second;
+ throw ModuleException(InspIRCd::Format("Mode name %s already used by %c from %s",
+ mh->name.c_str(), othermh->GetModeChar(), othermh->creator->ModuleSourceFile.c_str()));
+ }
// Everything is fine, add the mode
mhlist.prefix.push_back(pm);
else if (mh->IsListModeBase())
mhlist.list.push_back(mh->IsListModeBase());
-
- RecreateModeListFor004Numeric();
}
bool ModeParser::DelMode(ModeHandler* mh)
{
- if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
+ if (!ModeParser::IsModeChar(mh->GetModeChar()))
return false;
ModeHandlerMap& mhmap = modehandlersbyname[mh->GetModeType()];
mhlist.prefix.erase(std::find(mhlist.prefix.begin(), mhlist.prefix.end(), mh->IsPrefixMode()));
else if (mh->IsListModeBase())
mhlist.list.erase(std::find(mhlist.list.begin(), mhlist.list.end(), mh->IsListModeBase()));
-
- RecreateModeListFor004Numeric();
return true;
}
ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
{
- if ((modeletter < 'A') || (modeletter > 'z'))
+ if (!ModeParser::IsModeChar(modeletter))
return NULL;
return modehandlers[mt][modeletter-65];
return mh->IsPrefixMode();
}
-std::string ModeParser::CreateModeList(ModeType mt, bool needparam)
-{
- std::string modestr;
-
- for (unsigned char mode = 'A'; mode <= 'z'; mode++)
- {
- ModeHandler* mh = modehandlers[mt][mode-65];
- if ((mh) && ((!needparam) || (mh->NeedsParam(true))))
- modestr.push_back(mode);
- }
-
- return modestr;
-}
-
-void ModeParser::RecreateModeListFor004Numeric()
-{
- Cached004ModeList = CreateModeList(MODETYPE_USER) + " " + CreateModeList(MODETYPE_CHANNEL) + " " + CreateModeList(MODETYPE_CHANNEL, true);
-}
-
PrefixMode* ModeParser::FindPrefix(unsigned const char pfxletter)
{
const PrefixModeList& list = GetPrefixModes();
}
}
-struct builtin_modes
-{
- SimpleChannelModeHandler s;
- SimpleChannelModeHandler p;
- SimpleChannelModeHandler m;
- SimpleChannelModeHandler t;
-
- SimpleChannelModeHandler n;
- SimpleChannelModeHandler i;
- ModeChannelKey k;
- ModeChannelLimit l;
-
- ModeChannelBan b;
- ModeChannelOp o;
- ModeChannelVoice v;
-
- SimpleUserModeHandler ui;
- ModeUserOperator uo;
- ModeUserServerNoticeMask us;
-
- builtin_modes()
- : s(NULL, "secret", 's')
- , p(NULL, "private", 'p')
- , m(NULL, "moderated", 'm')
- , t(NULL, "topiclock", 't')
- , n(NULL, "noextmsg", 'n')
- , i(NULL, "inviteonly", 'i')
- , ui(NULL, "invisible", 'i')
- {
- }
-
- void init()
- {
- ServiceProvider* modes[] = { &s, &p, &m, &t, &n, &i, &k, &l, &b, &o, &v,
- &ui, &uo, &us };
- ServerInstance->Modules->AddServices(modes, sizeof(modes)/sizeof(ServiceProvider*));
- }
-};
-
-static builtin_modes static_modes;
-
-void ModeParser::InitBuiltinModes()
+bool ModeParser::IsModeChar(char chr)
{
- static_modes.init();
- static_modes.b.DoRehash();
+ return ((chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z'));
}
ModeParser::ModeParser()