summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/coremods/core_user/cmd_mode.cpp120
-rw-r--r--src/coremods/core_user/core_user.h17
-rw-r--r--src/mode.cpp125
-rw-r--r--src/modules/m_samode.cpp22
4 files changed, 155 insertions, 129 deletions
diff --git a/src/coremods/core_user/cmd_mode.cpp b/src/coremods/core_user/cmd_mode.cpp
index b154f5e22..99b9ab20d 100644
--- a/src/coremods/core_user/cmd_mode.cpp
+++ b/src/coremods/core_user/cmd_mode.cpp
@@ -2,6 +2,9 @@
* InspIRCd -- Internet Relay Chat Daemon
*
* Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc>
*
* This file is part of InspIRCd. InspIRCd is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public
@@ -21,13 +24,76 @@
CommandMode::CommandMode(Module* parent)
: Command(parent, "MODE", 1)
+ , seq(0)
{
syntax = "<target> <modes> {<mode-parameters>}";
+ memset(&sent, 0, sizeof(sent));
}
CmdResult CommandMode::Handle(const std::vector<std::string>& parameters, User* user)
{
- ServerInstance->Modes->Process(parameters, user, (IS_LOCAL(user) ? ModeParser::MODE_NONE : ModeParser::MODE_LOCALONLY));
+ const std::string& target = parameters[0];
+ Channel* targetchannel = ServerInstance->FindChan(target);
+ User* targetuser = NULL;
+ if (!targetchannel)
+ {
+ if (IS_LOCAL(user))
+ targetuser = ServerInstance->FindNickOnly(target);
+ else
+ targetuser = ServerInstance->FindNick(target);
+ }
+
+ if ((!targetchannel) && ((!targetuser) || (IS_SERVER(targetuser))))
+ {
+ user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", target.c_str());
+ return CMD_FAILURE;
+ }
+ if (parameters.size() == 1)
+ {
+ this->DisplayCurrentModes(user, targetuser, targetchannel);
+ return CMD_SUCCESS;
+ }
+
+ // Populate a temporary Modes::ChangeList with the parameters
+ Modes::ChangeList changelist;
+ ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
+ ServerInstance->Modes.ModeParamsToChangeList(user, type, parameters, changelist);
+
+ ModResult MOD_RESULT;
+ FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, changelist));
+
+ ModeParser::ModeProcessFlag flags = ModeParser::MODE_NONE;
+ if (IS_LOCAL(user))
+ {
+ if (MOD_RESULT == MOD_RES_PASSTHRU)
+ {
+ if ((targetuser) && (user != targetuser))
+ {
+ // Local users may only change the modes of other users if a module explicitly allows it
+ user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't change mode for other users");
+ return CMD_FAILURE;
+ }
+
+ // This is a mode change by a local user and modules didn't explicitly allow/deny.
+ // Ensure access checks will happen for each mode being changed.
+ flags |= ModeParser::MODE_CHECKACCESS;
+ }
+ else if (MOD_RESULT == MOD_RES_DENY)
+ return CMD_FAILURE; // Entire mode change denied by a module
+ }
+ else
+ flags |= ModeParser::MODE_LOCALONLY;
+
+ ServerInstance->Modes->ProcessSingle(user, targetchannel, targetuser, changelist, flags);
+
+ if ((ServerInstance->Modes.GetLastParse().empty()) && (targetchannel) && (parameters.size() == 2))
+ {
+ /* Special case for displaying the list for listmodes,
+ * e.g. MODE #chan b, or MODE #chan +b without a parameter
+ */
+ this->DisplayListModes(user, targetchannel, parameters[1]);
+ }
+
return CMD_SUCCESS;
}
@@ -35,3 +101,55 @@ RouteDescriptor CommandMode::GetRouting(User* user, const std::vector<std::strin
{
return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
}
+
+void CommandMode::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence)
+{
+ seq++;
+
+ for (std::string::const_iterator i = mode_sequence.begin(); i != mode_sequence.end(); ++i)
+ {
+ unsigned char mletter = *i;
+ if (mletter == '+')
+ continue;
+
+ ModeHandler* mh = ServerInstance->Modes->FindMode(mletter, MODETYPE_CHANNEL);
+ if (!mh || !mh->IsListMode())
+ return;
+
+ /* Ensure the user doesnt request the same mode twice,
+ * so they can't flood themselves off out of idiocy.
+ */
+ if (sent[mletter] == seq)
+ continue;
+
+ sent[mletter] = seq;
+ ServerInstance->Modes.ShowListModeList(user, chan, mh);
+ }
+}
+
+void CommandMode::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel)
+{
+ if (targetchannel)
+ {
+ // Display channel's current mode string
+ user->WriteNumeric(RPL_CHANNELMODEIS, "%s +%s", targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
+ user->WriteNumeric(RPL_CHANNELCREATED, "%s %lu", targetchannel->name.c_str(), (unsigned long)targetchannel->age);
+ }
+ else
+ {
+ if (targetuser == user || user->HasPrivPermission("users/auspex"))
+ {
+ // Display user's current mode string
+ user->WriteNumeric(RPL_UMODEIS, ":+%s", targetuser->FormatModes());
+ if (targetuser->IsOper())
+ {
+ ModeHandler* snomask = ServerInstance->Modes->FindMode('s', MODETYPE_USER);
+ user->WriteNumeric(RPL_SNOMASKIS, "%s :Server notice mask", snomask->GetUserParameter(user).c_str());
+ }
+ }
+ else
+ {
+ user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't view modes for other users");
+ }
+ }
+}
diff --git a/src/coremods/core_user/core_user.h b/src/coremods/core_user/core_user.h
index 7cc3d1e05..0418588c1 100644
--- a/src/coremods/core_user/core_user.h
+++ b/src/coremods/core_user/core_user.h
@@ -64,6 +64,23 @@ class CommandAway : public Command
class CommandMode : public Command
{
+ unsigned int sent[256];
+ unsigned int seq;
+
+ /** Show the list of one or more list modes to a user.
+ * @param user User to send to.
+ * @param chan Channel whose lists to show.
+ * @param mode_sequence Mode letters to show the lists of.
+ */
+ void DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence);
+
+ /** Show the current modes of a channel or a user to a user.
+ * @param user User to show the modes to.
+ * @param targetuser User whose modes to show. NULL if showing the modes of a channel.
+ * @param targetchannel Channel whose modes to show. NULL if showing the modes of a user.
+ */
+ void DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel);
+
public:
/** Constructor for mode.
*/
diff --git a/src/mode.cpp b/src/mode.cpp
index 5642e35b6..c70f474f7 100644
--- a/src/mode.cpp
+++ b/src/mode.cpp
@@ -152,36 +152,6 @@ void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool)
{
}
-void ModeParser::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel)
-{
- if (targetchannel)
- {
- /* Display channel's current mode string */
- user->WriteNumeric(RPL_CHANNELMODEIS, "%s +%s", targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user)));
- user->WriteNumeric(RPL_CHANNELCREATED, "%s %lu", targetchannel->name.c_str(), (unsigned long)targetchannel->age);
- return;
- }
- else
- {
- if (targetuser == user || user->HasPrivPermission("users/auspex"))
- {
- /* Display user's current mode string */
- user->WriteNumeric(RPL_UMODEIS, ":+%s", targetuser->FormatModes());
- if ((targetuser->IsOper()))
- {
- ModeHandler* snomask = FindMode('s', MODETYPE_USER);
- user->WriteNumeric(RPL_SNOMASKIS, "%s :Server notice mask", snomask->GetUserParameter(user).c_str());
- }
- return;
- }
- else
- {
- user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't view modes for other users");
- return;
- }
- }
-}
-
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)
@@ -360,71 +330,6 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
return MODEACTION_ALLOW;
}
-void ModeParser::Process(const std::vector<std::string>& parameters, User* user, ModeProcessFlag flags)
-{
- const std::string& target = parameters[0];
- Channel* targetchannel = ServerInstance->FindChan(target);
- User* targetuser = NULL;
- if (!targetchannel)
- {
- if (IS_LOCAL(user))
- targetuser = ServerInstance->FindNickOnly(target);
- else
- targetuser = ServerInstance->FindNick(target);
- }
- ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER;
-
- LastParse.clear();
- LastChangeList.clear();
-
- if ((!targetchannel) && ((!targetuser) || (IS_SERVER(targetuser))))
- {
- user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", target.c_str());
- return;
- }
- if (parameters.size() == 1)
- {
- this->DisplayCurrentModes(user, targetuser, targetchannel);
- return;
- }
-
- // Populate a temporary Modes::ChangeList with the parameters
- Modes::ChangeList changelist;
- ModeParamsToChangeList(user, type, parameters, changelist);
-
- ModResult MOD_RESULT;
- FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, changelist));
-
- if (IS_LOCAL(user))
- {
- if (MOD_RESULT == MOD_RES_PASSTHRU)
- {
- if ((targetuser) && (user != targetuser))
- {
- // Local users may only change the modes of other users if a module explicitly allows it
- user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't change mode for other users");
- return;
- }
-
- // This is a mode change by a local user and modules didn't explicitly allow/deny.
- // Ensure access checks will happen for each mode being changed.
- flags |= MODE_CHECKACCESS;
- }
- else if (MOD_RESULT == MOD_RES_DENY)
- return; // Entire mode change denied by a module
- }
-
- ProcessSingle(user, targetchannel, targetuser, changelist, flags);
-
- if ((LastParse.empty()) && (targetchannel) && (parameters.size() == 2))
- {
- /* Special case for displaying the list for listmodes,
- * e.g. MODE #chan b, or MODE #chan +b without a parameter
- */
- this->DisplayListModes(user, targetchannel, parameters[1]);
- }
-}
-
void ModeParser::ModeParamsToChangeList(User* user, ModeType type, const std::vector<std::string>& parameters, Modes::ChangeList& changelist, unsigned int beginindex, unsigned int endindex)
{
if (endindex > parameters.size())
@@ -580,33 +485,6 @@ unsigned int ModeParser::ProcessSingle(User* user, Channel* targetchannel, User*
return modes_processed;
}
-void ModeParser::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence)
-{
- seq++;
-
- for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++)
- {
- unsigned char mletter = *letter;
- if (mletter == '+')
- continue;
-
- /* Ensure the user doesnt request the same mode twice,
- * so they cant flood themselves off out of idiocy.
- */
- if (sent[mletter] == seq)
- continue;
-
- sent[mletter] = seq;
-
- ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL);
-
- if (!mh || !mh->IsListMode())
- return;
-
- ShowListModeList(user, chan, mh);
- }
-}
-
void ModeParser::ShowListModeList(User* user, Channel* chan, ModeHandler* mh)
{
{
@@ -1043,9 +921,6 @@ ModeParser::ModeParser()
/* Clear mode handler list */
memset(modehandlers, 0, sizeof(modehandlers));
memset(modehandlersbyid, 0, sizeof(modehandlersbyid));
-
- seq = 0;
- memset(&sent, 0, sizeof(sent));
}
ModeParser::~ModeParser()
diff --git a/src/modules/m_samode.cpp b/src/modules/m_samode.cpp
index 63d4f7622..caf1f27c4 100644
--- a/src/modules/m_samode.cpp
+++ b/src/modules/m_samode.cpp
@@ -52,11 +52,27 @@ class CommandSamode : public Command
if (!user->HasPrivPermission("users/samode-usermodes", true))
return CMD_FAILURE;
}
+
+ // XXX: Make ModeParser clear LastParse
+ Modes::ChangeList emptychangelist;
+ ServerInstance->Modes->ProcessSingle(ServerInstance->FakeClient, NULL, ServerInstance->FakeClient, emptychangelist);
+
this->active = true;
- ServerInstance->Parser.CallHandler("MODE", parameters, user);
- if (ServerInstance->Modes->GetLastParse().length())
- ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SAMODE: " +ServerInstance->Modes->GetLastParse());
+ CmdResult result = ServerInstance->Parser.CallHandler("MODE", parameters, user);
this->active = false;
+
+ if (result == CMD_SUCCESS)
+ {
+ // If lastparse is empty and the MODE command handler returned CMD_SUCCESS then
+ // the client queried the list of a listmode (e.g. /SAMODE #chan b), which was
+ // handled internally by the MODE command handler.
+ //
+ // Viewing the modes of a user or a channel can also result in CMD_SUCCESS, but
+ // that is not possible with /SAMODE because we require at least 2 parameters.
+ const std::string& lastparse = ServerInstance->Modes.GetLastParse();
+ ServerInstance->SNO->WriteGlobalSno('a', user->nick + " used SAMODE: " + (lastparse.empty() ? irc::stringjoiner(parameters) : lastparse));
+ }
+
return CMD_SUCCESS;
}
};