X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fcoremods%2Fcore_user%2Fcmd_mode.cpp;h=190983d13047b28d9f2cd6568d3d9ae933148d2b;hb=0ec19b7ac91eedc83b31c3da733e237bfe28fc48;hp=d2e9b4f63016a0f6fe47f7e9c4af522e6d052284;hpb=c67d3103e9f7397f0ab9631bf07a5e5547deb2c3;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/coremods/core_user/cmd_mode.cpp b/src/coremods/core_user/cmd_mode.cpp index d2e9b4f63..190983d13 100644 --- a/src/coremods/core_user/cmd_mode.cpp +++ b/src/coremods/core_user/cmd_mode.cpp @@ -1,8 +1,10 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2009 Daniel De Graaf - * Copyright (C) 2007 Robin Burchell + * Copyright (C) 2014 Attila Molnar + * Copyright (C) 2009-2010 Daniel De Graaf + * Copyright (C) 2006-2008 Robin Burchell + * Copyright (C) 2004-2008 Craig Edwards * * 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 @@ -17,37 +19,145 @@ * along with this program. If not, see . */ - #include "inspircd.h" +#include "core_user.h" -/** Handle /MODE. - */ -class CommandMode : public Command +CommandMode::CommandMode(Module* parent) + : Command(parent, "MODE", 1) + , seq(0) +{ + syntax = " {}"; + memset(&sent, 0, sizeof(sent)); +} + +CmdResult CommandMode::Handle(const std::vector& parameters, User* user) { - public: - /** Constructor for mode. - */ - CommandMode ( Module* parent) : Command(parent,"MODE",1) { syntax = " {}"; } - /** 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& parameters, User *user); - RouteDescriptor GetRouting(User* user, const std::vector& parameters) + const std::string& target = parameters[0]; + Channel* targetchannel = ServerInstance->FindChan(target); + User* targetuser = NULL; + if (!targetchannel) { - return (IS_LOCAL(user) ? ROUTE_LOCALONLY : ROUTE_BROADCAST); + 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; + + 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]); + } -/** Handle /MODE - */ -CmdResult CommandMode::Handle (const std::vector& parameters, User *user) -{ - ServerInstance->Modes->Process(parameters, user, (IS_LOCAL(user) ? ModeParser::MODE_NONE : ModeParser::MODE_LOCALONLY)); return CMD_SUCCESS; } +RouteDescriptor CommandMode::GetRouting(User* user, const std::vector& 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; -COMMAND_INIT(CommandMode) + 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 + // XXX: Use WriteServ() because WriteNumeric() assumes the target (i.e. next word after the number) + // is 'user' and puts his nick there which is not what we want + user->WriteServ("%03d %s :+%s", RPL_UMODEIS, targetuser->nick.c_str(), targetuser->FormatModes()); + if (targetuser->IsOper()) + { + ModeHandler* 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. + user->WriteServ("%03d %s %s%s :Server notice mask", RPL_SNOMASKIS, targetuser->nick.c_str(), (snomaskstr.empty() ? "+" : ""), snomaskstr.c_str()); + } + } + else + { + user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't view modes for other users"); + } + } +}