summaryrefslogtreecommitdiff
path: root/src/coremods/core_user
diff options
context:
space:
mode:
Diffstat (limited to 'src/coremods/core_user')
-rw-r--r--src/coremods/core_user/cmd_away.cpp65
-rw-r--r--src/coremods/core_user/cmd_mode.cpp177
-rw-r--r--src/coremods/core_user/cmd_nick.cpp98
-rw-r--r--src/coremods/core_user/cmd_part.cpp65
-rw-r--r--src/coremods/core_user/cmd_quit.cpp51
-rw-r--r--src/coremods/core_user/cmd_user.cpp79
-rw-r--r--src/coremods/core_user/core_user.cpp183
-rw-r--r--src/coremods/core_user/core_user.h222
-rw-r--r--src/coremods/core_user/umode_o.cpp51
-rw-r--r--src/coremods/core_user/umode_s.cpp145
10 files changed, 1136 insertions, 0 deletions
diff --git a/src/coremods/core_user/cmd_away.cpp b/src/coremods/core_user/cmd_away.cpp
new file mode 100644
index 000000000..32d4a9d84
--- /dev/null
+++ b/src/coremods/core_user/cmd_away.cpp
@@ -0,0 +1,65 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+CommandAway::CommandAway(Module* parent)
+ : Command(parent, "AWAY", 0, 0)
+{
+ syntax = "[<message>]";
+}
+
+/** Handle /AWAY
+ */
+CmdResult CommandAway::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ ModResult MOD_RESULT;
+
+ if ((!parameters.empty()) && (!parameters[0].empty()))
+ {
+ FIRST_MOD_RESULT(OnSetAway, MOD_RESULT, (user, parameters[0]));
+
+ if (MOD_RESULT == MOD_RES_DENY && IS_LOCAL(user))
+ return CMD_FAILURE;
+
+ user->awaytime = ServerInstance->Time();
+ user->awaymsg.assign(parameters[0], 0, ServerInstance->Config->Limits.MaxAway);
+
+ user->WriteNumeric(RPL_NOWAWAY, "You have been marked as being away");
+ }
+ else
+ {
+ FIRST_MOD_RESULT(OnSetAway, MOD_RESULT, (user, ""));
+
+ if (MOD_RESULT == MOD_RES_DENY && IS_LOCAL(user))
+ return CMD_FAILURE;
+
+ user->awaymsg.clear();
+ user->WriteNumeric(RPL_UNAWAY, "You are no longer marked as being away");
+ }
+
+ return CMD_SUCCESS;
+}
+
+RouteDescriptor CommandAway::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+}
diff --git a/src/coremods/core_user/cmd_mode.cpp b/src/coremods/core_user/cmd_mode.cpp
new file mode 100644
index 000000000..ec75d6191
--- /dev/null
+++ b/src/coremods/core_user/cmd_mode.cpp
@@ -0,0 +1,177 @@
+/*
+ * 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "inspircd.h"
+#include "core_user.h"
+
+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)
+{
+ 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))
+ {
+ if (target[0] == '#')
+ user->WriteNumeric(Numerics::NoSuchChannel(target));
+ else
+ user->WriteNumeric(Numerics::NoSuchNick(target));
+ 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;
+
+ if (IS_LOCAL(user))
+ ServerInstance->Modes->ProcessSingle(user, targetchannel, targetuser, changelist, flags);
+ else
+ ServerInstance->Modes->Process(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;
+}
+
+RouteDescriptor CommandMode::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ 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);
+ }
+}
+
+static std::string GetSnomasks(const User* user)
+{
+ ModeHandler* const snomask = ServerInstance->Modes.FindMode('s', MODETYPE_USER);
+ std::string snomaskstr = snomask->GetUserParameter(user);
+ // snomaskstr is empty if the snomask mode isn't set, otherwise it begins with a '+'.
+ // In the former case output a "+", not an empty string.
+ if (snomaskstr.empty())
+ snomaskstr.push_back('+');
+ return snomaskstr;
+}
+
+void CommandMode::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel)
+{
+ if (targetchannel)
+ {
+ // Display channel's current mode string
+ user->WriteNumeric(RPL_CHANNELMODEIS, targetchannel->name, (std::string("+") + targetchannel->ChanModes(targetchannel->HasUser(user))));
+ user->WriteNumeric(RPL_CHANNELCREATED, targetchannel->name, (unsigned long)targetchannel->age);
+ }
+ else
+ {
+ if (targetuser == user)
+ {
+ // Display user's current mode string
+ user->WriteNumeric(RPL_UMODEIS, targetuser->GetModeLetters());
+ if (targetuser->IsOper())
+ user->WriteNumeric(RPL_SNOMASKIS, GetSnomasks(targetuser), "Server notice mask");
+ }
+ else if (user->HasPrivPermission("users/auspex"))
+ {
+ // Querying the modes of another user.
+ // We cannot use RPL_UMODEIS because that's only for showing the user's own modes.
+ user->WriteNumeric(RPL_OTHERUMODEIS, targetuser->nick, targetuser->GetModeLetters());
+ if (targetuser->IsOper())
+ user->WriteNumeric(RPL_OTHERSNOMASKIS, targetuser->nick, GetSnomasks(targetuser), "Server notice mask");
+ }
+ else
+ {
+ user->WriteNumeric(ERR_USERSDONTMATCH, "Can't view modes for other users");
+ }
+ }
+}
diff --git a/src/coremods/core_user/cmd_nick.cpp b/src/coremods/core_user/cmd_nick.cpp
new file mode 100644
index 000000000..80bfbe674
--- /dev/null
+++ b/src/coremods/core_user/cmd_nick.cpp
@@ -0,0 +1,98 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2008 Craig Edwards <craigedwards@brainbox.cc>
+ * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
+ * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
+ *
+ * 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+CommandNick::CommandNick(Module* parent)
+ : SplitCommand(parent, "NICK", 1, 1)
+{
+ works_before_reg = true;
+ syntax = "<newnick>";
+ Penalty = 0;
+}
+
+/** Handle nick changes from users.
+ * NOTE: If you are used to ircds based on ircd2.8, and are looking
+ * for the client introduction code in here, youre in the wrong place.
+ * You need to look in the spanningtree module for this!
+ */
+CmdResult CommandNick::HandleLocal(const std::vector<std::string>& parameters, LocalUser* user)
+{
+ std::string oldnick = user->nick;
+ std::string newnick = parameters[0];
+
+ // anything except the initial NICK gets a flood penalty
+ if (user->registered == REG_ALL)
+ user->CommandFloodPenalty += 4000;
+
+ if (newnick.empty())
+ {
+ user->WriteNumeric(ERR_NONICKNAMEGIVEN, "No nickname given");
+ return CMD_FAILURE;
+ }
+
+ if (newnick == "0")
+ {
+ newnick = user->uuid;
+ }
+ else if (!ServerInstance->IsNick(newnick))
+ {
+ user->WriteNumeric(ERR_ERRONEUSNICKNAME, newnick, "Erroneous Nickname");
+ return CMD_FAILURE;
+ }
+
+ ModResult MOD_RESULT;
+ FIRST_MOD_RESULT(OnUserPreNick, MOD_RESULT, (user, newnick));
+
+ // If a module denied the change, abort now
+ if (MOD_RESULT == MOD_RES_DENY)
+ return CMD_FAILURE;
+
+ // Disallow the nick change if <security:restrictbannedusers> is on and there is a ban matching this user in
+ // one of the channels they are on
+ if (ServerInstance->Config->RestrictBannedUsers != ServerConfig::BUT_NORMAL)
+ {
+ for (User::ChanList::iterator i = user->chans.begin(); i != user->chans.end(); ++i)
+ {
+ Channel* chan = (*i)->chan;
+ if (chan->GetPrefixValue(user) < VOICE_VALUE && chan->IsBanned(user))
+ {
+ if (ServerInstance->Config->RestrictBannedUsers == ServerConfig::BUT_RESTRICT_NOTIFY)
+ user->WriteNumeric(ERR_CANTCHANGENICK, InspIRCd::Format("Cannot change nickname while on %s (you're banned)",
+ chan->name.c_str()));
+ return CMD_FAILURE;
+ }
+ }
+ }
+
+ if (!user->ChangeNick(newnick))
+ return CMD_FAILURE;
+
+ if (user->registered < REG_NICKUSER)
+ {
+ user->registered = (user->registered | REG_NICK);
+ return CommandUser::CheckRegister(user);
+ }
+
+ return CMD_SUCCESS;
+}
diff --git a/src/coremods/core_user/cmd_part.cpp b/src/coremods/core_user/cmd_part.cpp
new file mode 100644
index 000000000..261d75a70
--- /dev/null
+++ b/src/coremods/core_user/cmd_part.cpp
@@ -0,0 +1,65 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
+ *
+ * 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+CommandPart::CommandPart(Module* parent)
+ : Command(parent, "PART", 1, 2)
+{
+ Penalty = 5;
+ syntax = "<channel>{,<channel>} [<reason>]";
+}
+
+CmdResult CommandPart::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ std::string reason;
+ if (parameters.size() > 1)
+ {
+ if (IS_LOCAL(user))
+ msgwrap.Wrap(parameters[1], reason);
+ else
+ reason = parameters[1];
+ }
+
+ if (CommandParser::LoopCall(user, this, parameters, 0))
+ return CMD_SUCCESS;
+
+ Channel* c = ServerInstance->FindChan(parameters[0]);
+
+ if (!c)
+ {
+ user->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
+ return CMD_FAILURE;
+ }
+
+ if (!c->PartUser(user, reason))
+ {
+ user->WriteNumeric(ERR_NOTONCHANNEL, c->name, "You're not on that channel");
+ return CMD_FAILURE;
+ }
+
+ return CMD_SUCCESS;
+}
+
+RouteDescriptor CommandPart::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+}
diff --git a/src/coremods/core_user/cmd_quit.cpp b/src/coremods/core_user/cmd_quit.cpp
new file mode 100644
index 000000000..f9a4e1f70
--- /dev/null
+++ b/src/coremods/core_user/cmd_quit.cpp
@@ -0,0 +1,51 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+CommandQuit::CommandQuit(Module* parent)
+ : Command(parent, "QUIT", 0, 1)
+ , operquit("operquit", ExtensionItem::EXT_USER, parent)
+{
+ works_before_reg = true;
+ syntax = "[<message>]";
+}
+
+CmdResult CommandQuit::Handle (const std::vector<std::string>& parameters, User *user)
+{
+ std::string quitmsg;
+ if (parameters.empty())
+ quitmsg = "Client exited";
+ else if (IS_LOCAL(user))
+ msgwrap.Wrap(parameters[0], quitmsg);
+ else
+ quitmsg = parameters[0];
+
+ std::string* operquitmsg = operquit.get(user);
+ ServerInstance->Users->QuitUser(user, quitmsg, operquitmsg);
+
+ return CMD_SUCCESS;
+}
+
+RouteDescriptor CommandQuit::GetRouting(User* user, const std::vector<std::string>& parameters)
+{
+ return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST);
+}
diff --git a/src/coremods/core_user/cmd_user.cpp b/src/coremods/core_user/cmd_user.cpp
new file mode 100644
index 000000000..452146adc
--- /dev/null
+++ b/src/coremods/core_user/cmd_user.cpp
@@ -0,0 +1,79 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
+ * Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
+ *
+ * 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+enum
+{
+ // From ircu.
+ ERR_INVALIDUSERNAME = 468
+};
+
+CommandUser::CommandUser(Module* parent)
+ : SplitCommand(parent, "USER", 4, 4)
+{
+ works_before_reg = true;
+ Penalty = 0;
+ syntax = "<username> <localhost> <remotehost> <realname>";
+}
+
+CmdResult CommandUser::HandleLocal(const std::vector<std::string>& parameters, LocalUser *user)
+{
+ /* A user may only send the USER command once */
+ if (!(user->registered & REG_USER))
+ {
+ if (!ServerInstance->IsIdent(parameters[0]))
+ {
+ user->WriteNumeric(ERR_INVALIDUSERNAME, name, "Your username is not valid");
+ return CMD_FAILURE;
+ }
+ else
+ {
+ user->ChangeIdent(parameters[0]);
+ user->fullname.assign(parameters[3].empty() ? "No info" : parameters[3], 0, ServerInstance->Config->Limits.MaxGecos);
+ user->registered = (user->registered | REG_USER);
+ }
+ }
+ else
+ {
+ user->WriteNumeric(ERR_ALREADYREGISTERED, "You may not reregister");
+ user->CommandFloodPenalty += 1000;
+ return CMD_FAILURE;
+ }
+
+ /* parameters 2 and 3 are local and remote hosts, and are ignored */
+ return CheckRegister(user);
+}
+
+CmdResult CommandUser::CheckRegister(LocalUser* user)
+{
+ // If the user is registered, return CMD_SUCCESS/CMD_FAILURE depending on what modules say, otherwise just
+ // return CMD_SUCCESS without doing anything, knowing the other handler will call us again
+ if (user->registered == REG_NICKUSER)
+ {
+ ModResult MOD_RESULT;
+ FIRST_MOD_RESULT(OnUserRegister, MOD_RESULT, (user));
+ if (MOD_RESULT == MOD_RES_DENY)
+ return CMD_FAILURE;
+ }
+
+ return CMD_SUCCESS;
+}
diff --git a/src/coremods/core_user/core_user.cpp b/src/coremods/core_user/core_user.cpp
new file mode 100644
index 000000000..8504de8e0
--- /dev/null
+++ b/src/coremods/core_user/core_user.cpp
@@ -0,0 +1,183 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+/** Handle /PASS.
+ */
+class CommandPass : public SplitCommand
+{
+ public:
+ /** Constructor for pass.
+ */
+ CommandPass(Module* parent)
+ : SplitCommand(parent, "PASS", 1, 1)
+ {
+ works_before_reg = true;
+ Penalty = 0;
+ syntax = "<password>";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user) CXX11_OVERRIDE
+ {
+ // Check to make sure they haven't registered -- Fix by FCS
+ if (user->registered == REG_ALL)
+ {
+ user->CommandFloodPenalty += 1000;
+ user->WriteNumeric(ERR_ALREADYREGISTERED, "You may not reregister");
+ return CMD_FAILURE;
+ }
+ user->password = parameters[0];
+
+ return CMD_SUCCESS;
+ }
+};
+
+/** Handle /PING.
+ */
+class CommandPing : public Command
+{
+ public:
+ /** Constructor for ping.
+ */
+ CommandPing(Module* parent)
+ : Command(parent, "PING", 1, 2)
+ {
+ syntax = "<servername> [:<servername>]";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user) CXX11_OVERRIDE
+ {
+ user->WriteServ("PONG %s :%s", ServerInstance->Config->ServerName.c_str(), parameters[0].c_str());
+ return CMD_SUCCESS;
+ }
+};
+
+/** Handle /PONG.
+ */
+class CommandPong : public Command
+{
+ public:
+ /** Constructor for pong.
+ */
+ CommandPong(Module* parent)
+ : Command(parent, "PONG", 0, 1)
+ {
+ Penalty = 0;
+ syntax = "<ping-text>";
+ }
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user) CXX11_OVERRIDE
+ {
+ // set the user as alive so they survive to next ping
+ LocalUser* localuser = IS_LOCAL(user);
+ if (localuser)
+ {
+ // Increase penalty unless we've sent a PING and this is the reply
+ if (localuser->lastping)
+ localuser->CommandFloodPenalty += 1000;
+ else
+ localuser->lastping = 1;
+ }
+ return CMD_SUCCESS;
+ }
+};
+
+void MessageWrapper::Wrap(const std::string& message, std::string& out)
+{
+ // If there is a fixed message, it is stored in prefix. Otherwise prefix contains
+ // only the prefix, so append the message and the suffix
+ out.assign(prefix);
+ if (!fixed)
+ out.append(message).append(suffix);
+}
+
+void MessageWrapper::ReadConfig(const char* prefixname, const char* suffixname, const char* fixedname)
+{
+ ConfigTag* tag = ServerInstance->Config->ConfValue("options");
+ prefix = tag->getString(fixedname);
+ fixed = (!prefix.empty());
+ if (!fixed)
+ {
+ prefix = tag->getString(prefixname);
+ suffix = tag->getString(suffixname);
+ }
+}
+
+class CoreModUser : public Module
+{
+ CommandAway cmdaway;
+ CommandMode cmdmode;
+ CommandNick cmdnick;
+ CommandPart cmdpart;
+ CommandPass cmdpass;
+ CommandPing cmdping;
+ CommandPong cmdpong;
+ CommandQuit cmdquit;
+ CommandUser cmduser;
+ SimpleUserModeHandler invisiblemode;
+ ModeUserOperator operatormode;
+ ModeUserServerNoticeMask snomaskmode;
+
+ public:
+ CoreModUser()
+ : cmdaway(this)
+ , cmdmode(this)
+ , cmdnick(this)
+ , cmdpart(this)
+ , cmdpass(this)
+ , cmdping(this)
+ , cmdpong(this)
+ , cmdquit(this)
+ , cmduser(this)
+ , invisiblemode(this, "invisible", 'i')
+ , operatormode(this)
+ , snomaskmode(this)
+ {
+ }
+
+ void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
+ {
+ cmdpart.msgwrap.ReadConfig("prefixpart", "suffixpart", "fixedpart");
+ cmdquit.msgwrap.ReadConfig("prefixquit", "suffixquit", "fixedquit");
+ }
+
+ Version GetVersion() CXX11_OVERRIDE
+ {
+ return Version("Provides the AWAY, MODE, NICK, PART, PASS, PING, PONG, QUIT and USER commands", VF_VENDOR|VF_CORE);
+ }
+};
+
+MODULE_INIT(CoreModUser)
diff --git a/src/coremods/core_user/core_user.h b/src/coremods/core_user/core_user.h
new file mode 100644
index 000000000..befb07ef5
--- /dev/null
+++ b/src/coremods/core_user/core_user.h
@@ -0,0 +1,222 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ * Copyright (C) 2006 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "inspircd.h"
+#include "listmode.h"
+
+class MessageWrapper
+{
+ std::string prefix;
+ std::string suffix;
+ bool fixed;
+
+ public:
+ /**
+ * Wrap the given message according to the config rules
+ * @param message The message to wrap
+ * @param out String where the result is placed
+ */
+ void Wrap(const std::string& message, std::string& out);
+
+ /**
+ * Read the settings from the given config keys (options block)
+ * @param prefixname Name of the config key to read the prefix from
+ * @param suffixname Name of the config key to read the suffix from
+ * @param fixedname Name of the config key to read the fixed string string from.
+ * If this key has a non-empty value, all messages will be replaced with it.
+ */
+ void ReadConfig(const char* prefixname, const char* suffixname, const char* fixedname);
+};
+
+/** Handle /AWAY.
+ */
+class CommandAway : public Command
+{
+ public:
+ /** Constructor for away.
+ */
+ CommandAway(Module* parent);
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user) CXX11_OVERRIDE;
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) CXX11_OVERRIDE;
+};
+
+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.
+ */
+ CommandMode(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user) CXX11_OVERRIDE;
+
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) CXX11_OVERRIDE;
+};
+
+/** Handle /NICK.
+ */
+class CommandNick : public SplitCommand
+{
+ public:
+ /** Constructor for nick.
+ */
+ CommandNick(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user) CXX11_OVERRIDE;
+};
+
+/** Handle /PART.
+ */
+class CommandPart : public Command
+{
+ public:
+ MessageWrapper msgwrap;
+
+ /** Constructor for part.
+ */
+ CommandPart(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user) CXX11_OVERRIDE;
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) CXX11_OVERRIDE;
+};
+
+/** Handle /QUIT.
+ */
+class CommandQuit : public Command
+{
+ private:
+ StringExtItem operquit;
+
+ public:
+ MessageWrapper msgwrap;
+
+ /** Constructor for quit.
+ */
+ CommandQuit(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult Handle(const std::vector<std::string>& parameters, User* user) CXX11_OVERRIDE;
+
+ RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters) CXX11_OVERRIDE;
+};
+
+/** Handle /USER.
+ */
+class CommandUser : public SplitCommand
+{
+ public:
+ /** Constructor for user.
+ */
+ CommandUser(Module* parent);
+
+ /** Handle command.
+ * @param parameters The parameters to the command
+ * @param user The user issuing the command
+ * @return A value from CmdResult to indicate command success or failure.
+ */
+ CmdResult HandleLocal(const std::vector<std::string>& parameters, LocalUser* user) CXX11_OVERRIDE;
+
+ /** Run the OnUserRegister hook if the user has sent both NICK and USER. Called after an unregistered user
+ * successfully executes the USER or the NICK command.
+ * @param user User to inspect and possibly pass to the OnUserRegister hook
+ * @return CMD_FAILURE if OnUserRegister was called and it returned MOD_RES_DENY, CMD_SUCCESS in every other case
+ * (i.e. if the hook wasn't fired because the user still needs to send NICK/USER or if it was fired and finished with
+ * a non-MOD_RES_DENY result).
+ */
+ static CmdResult CheckRegister(LocalUser* user);
+};
+
+/** User mode +s
+ */
+class ModeUserServerNoticeMask : public ModeHandler
+{
+ /** Process a snomask modifier string, e.g. +abc-de
+ * @param user The target user
+ * @param input A sequence of notice mask characters
+ * @return The cleaned mode sequence which can be output,
+ * e.g. in the above example if masks c and e are not
+ * valid, this function will return +ab-d
+ */
+ std::string ProcessNoticeMasks(User* user, const std::string& input);
+
+ public:
+ ModeUserServerNoticeMask(Module* Creator);
+ ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding) CXX11_OVERRIDE;
+ void OnParameterMissing(User* user, User* dest, Channel* channel) CXX11_OVERRIDE;
+
+ /** Create a displayable mode string of the snomasks set on a given user
+ * @param user The user whose notice masks to format
+ * @return The notice mask character sequence
+ */
+ std::string GetUserParameter(const User* user) const CXX11_OVERRIDE;
+};
+
+/** User mode +o
+ */
+class ModeUserOperator : public ModeHandler
+{
+ public:
+ ModeUserOperator(Module* Creator);
+ ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding) CXX11_OVERRIDE;
+};
diff --git a/src/coremods/core_user/umode_o.cpp b/src/coremods/core_user/umode_o.cpp
new file mode 100644
index 000000000..20668fdaa
--- /dev/null
+++ b/src/coremods/core_user/umode_o.cpp
@@ -0,0 +1,51 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ * Copyright (C) 2006 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+ModeUserOperator::ModeUserOperator(Module* Creator)
+ : ModeHandler(Creator, "oper", 'o', PARAM_NONE, MODETYPE_USER)
+{
+ oper = true;
+}
+
+ModeAction ModeUserOperator::OnModeChange(User* source, User* dest, Channel*, std::string&, bool adding)
+{
+ /* Only opers can execute this class at all */
+ if (!source->server->IsULine() && !source->IsOper())
+ return MODEACTION_DENY;
+
+ /* Not even opers can GIVE the +o mode, only take it away */
+ if (adding)
+ return MODEACTION_DENY;
+
+ /* Set the bitfields.
+ * Note that oper status is only given in User::Oper()
+ * NOT here. It is impossible to directly set +o without
+ * verifying as an oper and getting an opertype assigned
+ * to your User!
+ */
+ char snomask = IS_LOCAL(dest) ? 'o' : 'O';
+ ServerInstance->SNO->WriteToSnoMask(snomask, "User %s de-opered (by %s)", dest->nick.c_str(), source->nick.c_str());
+ dest->UnOper();
+
+ return MODEACTION_ALLOW;
+}
diff --git a/src/coremods/core_user/umode_s.cpp b/src/coremods/core_user/umode_s.cpp
new file mode 100644
index 000000000..0122ebe3e
--- /dev/null
+++ b/src/coremods/core_user/umode_s.cpp
@@ -0,0 +1,145 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
+ * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ * Copyright (C) 2006 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "inspircd.h"
+#include "core_user.h"
+
+ModeUserServerNoticeMask::ModeUserServerNoticeMask(Module* Creator)
+ : ModeHandler(Creator, "snomask", 's', PARAM_SETONLY, MODETYPE_USER)
+{
+ oper = true;
+}
+
+ModeAction ModeUserServerNoticeMask::OnModeChange(User* source, User* dest, Channel*, std::string &parameter, bool adding)
+{
+ if (adding)
+ {
+ dest->SetMode(this, true);
+ // Process the parameter (remove chars we don't understand, remove redundant chars, etc.)
+ parameter = ProcessNoticeMasks(dest, parameter);
+ return MODEACTION_ALLOW;
+ }
+ else
+ {
+ if (dest->IsModeSet(this))
+ {
+ dest->SetMode(this, false);
+ dest->snomasks.reset();
+ return MODEACTION_ALLOW;
+ }
+ }
+
+ // Mode not set and trying to unset, deny
+ return MODEACTION_DENY;
+}
+
+std::string ModeUserServerNoticeMask::GetUserParameter(const User* user) const
+{
+ std::string ret;
+ if (!user->IsModeSet(this))
+ return ret;
+
+ ret.push_back('+');
+ for (unsigned char n = 0; n < 64; n++)
+ {
+ if (user->snomasks[n])
+ ret.push_back(n + 'A');
+ }
+ return ret;
+}
+
+void ModeUserServerNoticeMask::OnParameterMissing(User* user, User* dest, Channel* channel)
+{
+ user->WriteNotice("*** The user mode +s requires a parameter (server notice mask). Please provide a parameter, e.g. '+s +*'.");
+}
+
+std::string ModeUserServerNoticeMask::ProcessNoticeMasks(User* user, const std::string& input)
+{
+ bool adding = true;
+ std::bitset<64> curr = user->snomasks;
+
+ for (std::string::const_iterator i = input.begin(); i != input.end(); ++i)
+ {
+ switch (*i)
+ {
+ case '+':
+ adding = true;
+ break;
+ case '-':
+ adding = false;
+ break;
+ case '*':
+ for (size_t j = 0; j < 64; j++)
+ {
+ if (ServerInstance->SNO->IsSnomaskUsable(j+'A'))
+ curr[j] = adding;
+ }
+ break;
+ default:
+ // For local users check whether the given snomask is valid and enabled - IsSnomaskUsable() tests both.
+ // For remote users accept what we were told, unless the snomask char is not a letter.
+ if (IS_LOCAL(user))
+ {
+ if (!ServerInstance->SNO->IsSnomaskUsable(*i))
+ {
+ user->WriteNumeric(ERR_UNKNOWNSNOMASK, *i, "is unknown snomask char to me");
+ continue;
+ }
+ }
+ else if (!(((*i >= 'a') && (*i <= 'z')) || ((*i >= 'A') && (*i <= 'Z'))))
+ continue;
+
+ size_t index = ((*i) - 'A');
+ curr[index] = adding;
+ break;
+ }
+ }
+
+ std::string plus = "+";
+ std::string minus = "-";
+
+ // Apply changes and construct two strings consisting of the newly added and the removed snomask chars
+ for (size_t i = 0; i < 64; i++)
+ {
+ bool isset = curr[i];
+ if (user->snomasks[i] != isset)
+ {
+ user->snomasks[i] = isset;
+ std::string& appendhere = (isset ? plus : minus);
+ appendhere.push_back(i+'A');
+ }
+ }
+
+ // Create the final string that will be shown to the user and sent to servers
+ // Form: "+ABc-de"
+ std::string output;
+ if (plus.length() > 1)
+ output = plus;
+
+ if (minus.length() > 1)
+ output += minus;
+
+ // Unset the snomask usermode itself if every snomask was unset
+ if (user->snomasks.none())
+ user->SetMode(this, false);
+
+ return output;
+}