diff options
author | danieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7> | 2009-09-16 22:42:36 +0000 |
---|---|---|
committer | danieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7> | 2009-09-16 22:42:36 +0000 |
commit | 3841c4b04a96389a4661535d12d5215a621d8736 (patch) | |
tree | 62098e63cc622d9889a9ed205a1c4487c8c20c84 /src/commands | |
parent | 558a44bf47370b68b14d0837bfae13c651ecf5c4 (diff) |
Attempt to revert r11734
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@11735 e03df62e-2008-0410-955e-edbf42e46eb7
Diffstat (limited to 'src/commands')
52 files changed, 4998 insertions, 0 deletions
diff --git a/src/commands/cmd_admin.cpp b/src/commands/cmd_admin.cpp new file mode 100644 index 000000000..1f2641e67 --- /dev/null +++ b/src/commands/cmd_admin.cpp @@ -0,0 +1,58 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_ADMIN_H__ +#define __CMD_ADMIN_H__ + +#include "users.h" +#include "channels.h" + +/** Handle /ADMIN. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandAdmin : public Command +{ + public: + /** Constructor for admin. + */ + CommandAdmin(Module* parent) : Command(parent,"ADMIN",0,0) { syntax = "[<servername>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + + +/** Handle /ADMIN + */ +CmdResult CommandAdmin::Handle (const std::vector<std::string>& parameters, User *user) +{ + user->WriteNumeric(RPL_ADMINME, "%s :Administrative info for %s",user->nick.c_str(),ServerInstance->Config->ServerName); + if (*ServerInstance->Config->AdminName) + user->WriteNumeric(RPL_ADMINLOC1, "%s :Name - %s",user->nick.c_str(),ServerInstance->Config->AdminName); + user->WriteNumeric(RPL_ADMINLOC2, "%s :Nickname - %s",user->nick.c_str(),ServerInstance->Config->AdminNick); + user->WriteNumeric(RPL_ADMINEMAIL, "%s :E-Mail - %s",user->nick.c_str(),ServerInstance->Config->AdminEmail); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandAdmin) diff --git a/src/commands/cmd_away.cpp b/src/commands/cmd_away.cpp new file mode 100644 index 000000000..d93f74559 --- /dev/null +++ b/src/commands/cmd_away.cpp @@ -0,0 +1,79 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_AWAY_H__ +#define __CMD_AWAY_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /AWAY. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandAway : public Command +{ + public: + /** Constructor for away. + */ + CommandAway ( Module* parent) : Command(parent,"AWAY",0,0) { syntax = "[<message>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /AWAY + */ +CmdResult CommandAway::Handle (const std::vector<std::string>& parameters, User *user) +{ + ModResult MOD_RESULT; + + if ((parameters.size()) && (!parameters[0].empty())) + { + FIRST_MOD_RESULT(ServerInstance, 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, "%s :You have been marked as being away",user->nick.c_str()); + } + else + { + FIRST_MOD_RESULT(ServerInstance, OnSetAway, MOD_RESULT, (user, "")); + + if (MOD_RESULT == MOD_RES_DENY && IS_LOCAL(user)) + return CMD_FAILURE; + + user->awaymsg.clear(); + user->WriteNumeric(RPL_UNAWAY, "%s :You are no longer marked as being away",user->nick.c_str()); + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandAway) diff --git a/src/commands/cmd_clearcache.cpp b/src/commands/cmd_clearcache.cpp new file mode 100644 index 000000000..2334e597c --- /dev/null +++ b/src/commands/cmd_clearcache.cpp @@ -0,0 +1,55 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_ADMIN_H__ +#define __CMD_ADMIN_H__ + +#include "users.h" +#include "channels.h" +#include "ctables.h" + +/** Handle /ADMIN. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandClearcache : public Command +{ + public: + /** Constructor for clearcache. + */ + CommandClearcache ( Module* parent) : Command(parent,"CLEARCACHE",0) { flags_needed = 'o'; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /CLEARCACHE + */ +CmdResult CommandClearcache::Handle (const std::vector<std::string>& parameters, User *user) +{ + int n = ServerInstance->Res->ClearCache(); + user->WriteServ("NOTICE %s :*** Cleared DNS cache of %d items.", user->nick.c_str(), n); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandClearcache) diff --git a/src/commands/cmd_commands.cpp b/src/commands/cmd_commands.cpp new file mode 100644 index 000000000..63b4b24fb --- /dev/null +++ b/src/commands/cmd_commands.cpp @@ -0,0 +1,65 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_COMMANDS_H__ +#define __CMD_COMMANDS_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /COMMANDS. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandCommands : public Command +{ + public: + /** Constructor for commands. + */ + CommandCommands ( Module* parent) : Command(parent,"COMMANDS",0,0) { } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /COMMANDS + */ +CmdResult CommandCommands::Handle (const std::vector<std::string>&, User *user) +{ + for (Commandtable::iterator i = ServerInstance->Parser->cmdlist.begin(); i != ServerInstance->Parser->cmdlist.end(); i++) + { + Module* src = i->second->creator; + user->WriteNumeric(RPL_COMMANDS, "%s :%s %s %d %d", + user->nick.c_str(), + i->second->command.c_str(), + src ? src->ModuleSourceFile.c_str() : "<core>", + i->second->min_params, + i->second->Penalty); + } + user->WriteNumeric(RPL_COMMANDSEND, "%s :End of COMMANDS list",user->nick.c_str()); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandCommands) diff --git a/src/commands/cmd_connect.cpp b/src/commands/cmd_connect.cpp new file mode 100644 index 000000000..65cc4bd6b --- /dev/null +++ b/src/commands/cmd_connect.cpp @@ -0,0 +1,48 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /CONNECT. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandConnect : public Command +{ + public: + /** Constructor for connect. + */ + CommandConnect ( Module* parent) : Command(parent,"CONNECT",1) { flags_needed = 'o'; syntax = "<servername> [<remote-server>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +/* + * This is handled by the server linking module, if necessary. Do not remove this stub. + */ + +/** Handle /CONNECT + */ +CmdResult CommandConnect::Handle (const std::vector<std::string>&, User *user) +{ + user->WriteServ( "NOTICE %s :Look into loading a linking module (like m_spanningtree) if you want this to do anything useful.", user->nick.c_str()); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandConnect) diff --git a/src/commands/cmd_die.cpp b/src/commands/cmd_die.cpp new file mode 100644 index 000000000..658240de8 --- /dev/null +++ b/src/commands/cmd_die.cpp @@ -0,0 +1,74 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_DIE_H__ +#define __CMD_DIE_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /DIE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandDie : public Command +{ + public: + /** Constructor for die. + */ + CommandDie ( Module* parent) : Command(parent,"DIE",1) { flags_needed = 'o'; syntax = "<password>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + +#include "exitcodes.h" + +/** Handle /DIE + */ +CmdResult CommandDie::Handle (const std::vector<std::string>& parameters, User *user) +{ + if (!ServerInstance->PassCompare(user, ServerInstance->Config->diepass, parameters[0].c_str(), ServerInstance->Config->powerhash)) + { + { + std::string diebuf = std::string("*** DIE command from ") + user->nick + "!" + user->ident + "@" + user->dhost + ". Terminating in " + ConvToStr(ServerInstance->Config->DieDelay) + " seconds."; + ServerInstance->Logs->Log("COMMAND",SPARSE, diebuf); + ServerInstance->SendError(diebuf); + } + + if (ServerInstance->Config->DieDelay) + sleep(ServerInstance->Config->DieDelay); + + ServerInstance->Exit(EXIT_STATUS_DIE); + } + else + { + ServerInstance->Logs->Log("COMMAND",SPARSE, "Failed /DIE command from %s!%s@%s", user->nick.c_str(), user->ident.c_str(), user->host.c_str()); + ServerInstance->SNO->WriteGlobalSno('a', "Failed DIE Command from %s!%s@%s.",user->nick.c_str(),user->ident.c_str(),user->host.c_str()); + return CMD_FAILURE; + } + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandDie) diff --git a/src/commands/cmd_eline.cpp b/src/commands/cmd_eline.cpp new file mode 100644 index 000000000..7845fa2f1 --- /dev/null +++ b/src/commands/cmd_eline.cpp @@ -0,0 +1,125 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "xline.h" +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#ifndef __CMD_ELINE_H__ +#define __CMD_ELINE_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /ELINE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandEline : public Command +{ + public: + /** Constructor for eline. + */ + CommandEline ( Module* parent) : Command(parent,"ELINE",1,3) { flags_needed = 'o'; syntax = "<ident@host> [<duration> :<reason>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /ELINE + */ +CmdResult CommandEline::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::string target = parameters[0]; + + if (parameters.size() >= 3) + { + IdentHostPair ih; + User* find = ServerInstance->FindNick(target.c_str()); + if (find) + { + ih.first = "*"; + ih.second = find->GetIPString(); + target = std::string("*@") + find->GetIPString(); + } + else + ih = ServerInstance->XLines->IdentSplit(target.c_str()); + + if (ih.first.empty()) + { + user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str()); + return CMD_FAILURE; + } + + if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user)) + return CMD_FAILURE; + + long duration = ServerInstance->Duration(parameters[1].c_str()); + + ELine* el = new ELine(ServerInstance, ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); + if (ServerInstance->XLines->AddLine(el, user)) + { + if (!duration) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent E-line for %s: %s", user->nick.c_str(), target.c_str(), parameters[2].c_str()); + } + else + { + time_t c_requires_crap = duration + ServerInstance->Time(); + ServerInstance->SNO->WriteToSnoMask('x',"%s added timed E-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(), + ServerInstance->TimeString(c_requires_crap).c_str(), parameters[2].c_str()); + } + } + else + { + delete el; + user->WriteServ("NOTICE %s :*** E-Line for %s already exists",user->nick.c_str(),target.c_str()); + } + } + else + { + if (ServerInstance->XLines->DelLine(target.c_str(), "E", user)) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s removed E-line on %s",user->nick.c_str(),target.c_str()); + } + else + { + user->WriteServ("NOTICE %s :*** E-Line %s not found in list, try /stats e.",user->nick.c_str(),target.c_str()); + } + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandEline) diff --git a/src/commands/cmd_gline.cpp b/src/commands/cmd_gline.cpp new file mode 100644 index 000000000..ad3067428 --- /dev/null +++ b/src/commands/cmd_gline.cpp @@ -0,0 +1,111 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "xline.h" + +/** Handle /GLINE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandGline : public Command +{ + public: + /** Constructor for gline. + */ + CommandGline (Module* parent) : Command(parent,"GLINE",1,3) { flags_needed = 'o'; Penalty = 0; syntax = "<ident@host> [<duration> :<reason>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + + +/** Handle /GLINE + */ +CmdResult CommandGline::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::string target = parameters[0]; + + if (parameters.size() >= 3) + { + IdentHostPair ih; + User* find = ServerInstance->FindNick(target.c_str()); + if (find) + { + ih.first = "*"; + ih.second = find->GetIPString(); + target = std::string("*@") + find->GetIPString(); + } + else + ih = ServerInstance->XLines->IdentSplit(target.c_str()); + + if (ih.first.empty()) + { + user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str()); + return CMD_FAILURE; + } + + if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user)) + return CMD_FAILURE; + + else if (target.find('!') != std::string::npos) + { + user->WriteServ("NOTICE %s :*** G-Line cannot operate on nick!user@host masks",user->nick.c_str()); + return CMD_FAILURE; + } + + long duration = ServerInstance->Duration(parameters[1].c_str()); + GLine* gl = new GLine(ServerInstance, ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); + if (ServerInstance->XLines->AddLine(gl, user)) + { + if (!duration) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent G-line for %s: %s",user->nick.c_str(),target.c_str(), parameters[2].c_str()); + } + else + { + time_t c_requires_crap = duration + ServerInstance->Time(); + ServerInstance->SNO->WriteToSnoMask('x',"%s added timed G-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(), + ServerInstance->TimeString(c_requires_crap).c_str(), parameters[2].c_str()); + } + + ServerInstance->XLines->ApplyLines(); + } + else + { + delete gl; + user->WriteServ("NOTICE %s :*** G-Line for %s already exists",user->nick.c_str(),target.c_str()); + } + + } + else + { + if (ServerInstance->XLines->DelLine(target.c_str(),"G",user)) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s removed G-line on %s",user->nick.c_str(),target.c_str()); + } + else + { + user->WriteServ("NOTICE %s :*** G-line %s not found in list, try /stats g.",user->nick.c_str(),target.c_str()); + } + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandGline) diff --git a/src/commands/cmd_info.cpp b/src/commands/cmd_info.cpp new file mode 100644 index 000000000..f239b9f78 --- /dev/null +++ b/src/commands/cmd_info.cpp @@ -0,0 +1,91 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_INFO_H__ +#define __CMD_INFO_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /INFO. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandInfo : public Command +{ + public: + /** Constructor for info. + */ + CommandInfo ( Module* parent) : Command(parent,"INFO",0,0) { syntax = "[<servermask>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /INFO + */ +CmdResult CommandInfo::Handle (const std::vector<std::string>&, User *user) +{ + user->WriteNumeric(RPL_INFO, "%s : -/\\- \2InspIRCd\2 -\\/-", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : November 2002 - Present", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : ", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s :\2Core Developers\2:", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Craig Edwards, Brain, <brain@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Craig McLure, Craig, <craig@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Robin Burchell, w00t, <w00t@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Oliver Lupton, Om, <om@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : John Brooks, Special, <special@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Dennis Friis, peavey, <peavey@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Thomas Stagner, aquanight, <aquanight@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Uli Schlachter, psychon, <psychon@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Matt Smith, dz, <dz@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Daniel De Graaf danieldg, <danieldg@inspircd.org>", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : ", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s :\2Regular Contributors\2:", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Majic MacGyver Namegduf Ankit", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Phoenix Taros", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : ", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s :\2Other Contributors\2:", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : dmb Zaba skenmy GreenReaper", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Dan Jason satmd owine", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Adremelech John2 jilles HiroP", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : eggy Bricker AnMaster djGrrr", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : nenolod Quension praetorian pippijn", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : ", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s :\2Former Contributors\2:", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : CC jamie typobox43 Burlex (win32)", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Stskeeps ThaPrince BuildSmart Thunderhacker", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Skip LeaChim", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : ", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s :\2Thanks To\2:", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : searchirc.com irc-junkie.org Brik", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : ", user->nick.c_str()); + user->WriteNumeric(RPL_INFO, "%s : Best experienced with: \2An IRC client\2", user->nick.c_str()); + FOREACH_MOD(I_OnInfo,OnInfo(user)); + user->WriteNumeric(RPL_ENDOFINFO, "%s :End of /INFO list", user->nick.c_str()); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandInfo) diff --git a/src/commands/cmd_invite.cpp b/src/commands/cmd_invite.cpp new file mode 100644 index 000000000..89437e252 --- /dev/null +++ b/src/commands/cmd_invite.cpp @@ -0,0 +1,131 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /INVITE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandInvite : public Command +{ + public: + /** Constructor for invite. + */ + CommandInvite ( Module* parent) : Command(parent,"INVITE", 0, 0) { Penalty = 4; syntax = "[<nick> <channel>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +/** Handle /INVITE + */ +CmdResult CommandInvite::Handle (const std::vector<std::string>& parameters, User *user) +{ + ModResult MOD_RESULT; + + if (parameters.size() == 2 || parameters.size() == 3) + { + User* u = ServerInstance->FindNick(parameters[0]); + Channel* c = ServerInstance->FindChan(parameters[1]); + time_t timeout = 0; + if (parameters.size() == 3) + { + if (IS_LOCAL(user)) + timeout = ServerInstance->Time() + ServerInstance->Duration(parameters[2]); + else + timeout = ConvToInt(parameters[2]); + } + + if ((!c) || (!u)) + { + user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel",user->nick.c_str(), c ? parameters[0].c_str() : parameters[1].c_str()); + return CMD_FAILURE; + } + + if (c->HasUser(u)) + { + user->WriteNumeric(ERR_USERONCHANNEL, "%s %s %s :is already on channel",user->nick.c_str(),u->nick.c_str(),c->name.c_str()); + return CMD_FAILURE; + } + + if ((IS_LOCAL(user)) && (!c->HasUser(user))) + { + user->WriteNumeric(ERR_NOTONCHANNEL, "%s %s :You're not on that channel!",user->nick.c_str(), c->name.c_str()); + return CMD_FAILURE; + } + + FIRST_MOD_RESULT(ServerInstance, OnUserPreInvite, MOD_RESULT, (user,u,c,timeout)); + + if (MOD_RESULT == MOD_RES_DENY) + { + return CMD_FAILURE; + } + else if (MOD_RESULT == MOD_RES_PASSTHRU) + { + if (IS_LOCAL(user)) + { + int rank = c->GetPrefixValue(user); + if (rank < HALFOP_VALUE) + { + user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :You must be a channel %soperator", + user->nick.c_str(), c->name.c_str(), rank >= HALFOP_VALUE ? "" : "half-"); + return CMD_FAILURE; + } + } + } + + u->InviteTo(c->name.c_str(), timeout); + u->WriteFrom(user,"INVITE %s :%s",u->nick.c_str(),c->name.c_str()); + user->WriteNumeric(RPL_INVITING, "%s %s %s",user->nick.c_str(),u->nick.c_str(),c->name.c_str()); + switch (ServerInstance->Config->AnnounceInvites) + { + case ServerConfig::INVITE_ANNOUNCE_ALL: + c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s invited %s into the channel", c->name.c_str(), user->nick.c_str(), u->nick.c_str()); + break; + case ServerConfig::INVITE_ANNOUNCE_OPS: + c->WriteAllExceptSender(user, true, '@', "NOTICE %s :*** %s invited %s into the channel", c->name.c_str(), user->nick.c_str(), u->nick.c_str()); + break; + case ServerConfig::INVITE_ANNOUNCE_DYNAMIC: + if (c->IsModeSet('i')) + c->WriteAllExceptSender(user, true, '@', "NOTICE %s :*** %s invited %s into the channel", c->name.c_str(), user->nick.c_str(), u->nick.c_str()); + else + c->WriteChannelWithServ(ServerInstance->Config->ServerName, "NOTICE %s :*** %s invited %s into the channel", c->name.c_str(), user->nick.c_str(), u->nick.c_str()); + break; + default: + /* Nobody */ + break; + } + FOREACH_MOD(I_OnUserInvite,OnUserInvite(user,u,c,timeout)); + } + else + { + // pinched from ircu - invite with not enough parameters shows channels + // youve been invited to but haven't joined yet. + InvitedList* il = user->GetInviteList(); + for (InvitedList::iterator i = il->begin(); i != il->end(); i++) + { + user->WriteNumeric(RPL_INVITELIST, "%s :%s",user->nick.c_str(),i->first.c_str()); + } + user->WriteNumeric(RPL_ENDOFINVITELIST, "%s :End of INVITE list",user->nick.c_str()); + } + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandInvite) diff --git a/src/commands/cmd_ison.cpp b/src/commands/cmd_ison.cpp new file mode 100644 index 000000000..ca7639b58 --- /dev/null +++ b/src/commands/cmd_ison.cpp @@ -0,0 +1,108 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_ISON_H__ +#define __CMD_ISON_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /ISON. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandIson : public Command +{ + public: + /** Constructor for ison. + */ + CommandIson ( Module* parent) : Command(parent,"ISON",0,0) { syntax = "<nick> {nick}"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /ISON + */ +CmdResult CommandIson::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::map<User*,User*> ison_already; + User *u; + std::string reply = std::string("303 ") + user->nick + " :"; + + for (unsigned int i = 0; i < parameters.size(); i++) + { + u = ServerInstance->FindNick(parameters[i]); + if (ison_already.find(u) != ison_already.end()) + continue; + + if (u) + { + reply.append(u->nick).append(" "); + if (reply.length() > 450) + { + user->WriteServ(reply); + reply = std::string("303 ") + user->nick + " :"; + } + ison_already[u] = u; + } + else + { + if ((i == parameters.size() - 1) && (parameters[i].find(' ') != std::string::npos)) + { + /* Its a space seperated list of nicks (RFC1459 says to support this) + */ + irc::spacesepstream list(parameters[i]); + std::string item; + + while (list.GetToken(item)) + { + u = ServerInstance->FindNick(item); + if (ison_already.find(u) != ison_already.end()) + continue; + + if (u) + { + reply.append(u->nick).append(" "); + if (reply.length() > 450) + { + user->WriteServ(reply); + reply = std::string("303 ") + user->nick + " :"; + } + ison_already[u] = u; + } + } + } + } + } + + if (!reply.empty()) + user->WriteServ(reply); + + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandIson) diff --git a/src/commands/cmd_join.cpp b/src/commands/cmd_join.cpp new file mode 100644 index 000000000..73cae4746 --- /dev/null +++ b/src/commands/cmd_join.cpp @@ -0,0 +1,78 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_JOIN_H__ +#define __CMD_JOIN_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /JOIN. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandJoin : public Command +{ + public: + /** Constructor for join. + */ + CommandJoin ( Module* parent) : Command(parent,"JOIN", 1, 2) { syntax = "<channel>{,<channel>} {<key>{,<key>}}"; Penalty = 2; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /JOIN + */ +CmdResult CommandJoin::Handle (const std::vector<std::string>& parameters, User *user) +{ + if (parameters.size() > 1) + { + if (ServerInstance->Parser->LoopCall(user, this, parameters, 0, 1)) + return CMD_SUCCESS; + + if (ServerInstance->IsChannel(parameters[0].c_str(), ServerInstance->Config->Limits.ChanMax)) + { + Channel::JoinUser(ServerInstance, user, parameters[0].c_str(), false, parameters[1].c_str(), false); + return CMD_SUCCESS; + } + } + else + { + if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + return CMD_SUCCESS; + + if (ServerInstance->IsChannel(parameters[0].c_str(), ServerInstance->Config->Limits.ChanMax)) + { + Channel::JoinUser(ServerInstance, user, parameters[0].c_str(), false, "", false); + return CMD_SUCCESS; + } + } + + user->WriteNumeric(ERR_NOSUCHCHANNEL, "%s %s :Invalid channel name",user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; +} + +COMMAND_INIT(CommandJoin) diff --git a/src/commands/cmd_kick.cpp b/src/commands/cmd_kick.cpp new file mode 100644 index 000000000..d07d53836 --- /dev/null +++ b/src/commands/cmd_kick.cpp @@ -0,0 +1,86 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_KICK_H__ +#define __CMD_KICK_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /KICK. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandKick : public Command +{ + public: + /** Constructor for kick. + */ + CommandKick ( Module* parent) : Command(parent,"KICK",2,3) { syntax = "<channel> <nick>{,<nick>} [<reason>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /KICK + */ +CmdResult CommandKick::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::string reason; + Channel* c = ServerInstance->FindChan(parameters[0]); + User* u = ServerInstance->FindNick(parameters[1]); + + if (ServerInstance->Parser->LoopCall(user, this, parameters, 1)) + return CMD_SUCCESS; + + if (!u || !c) + { + user->WriteServ( "401 %s %s :No such nick/channel", user->nick.c_str(), u ? parameters[0].c_str() : parameters[1].c_str()); + return CMD_FAILURE; + } + + if ((IS_LOCAL(user)) && (!c->HasUser(user)) && (!ServerInstance->ULine(user->server))) + { + user->WriteServ( "442 %s %s :You're not on that channel!", user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + + if (parameters.size() > 2) + { + reason.assign(parameters[2], 0, ServerInstance->Config->Limits.MaxKick); + } + else + { + reason.assign(user->nick, 0, ServerInstance->Config->Limits.MaxKick); + } + + if (!c->KickUser(user, u, reason.c_str())) + /* Nobody left here, delete the Channel */ + delete c; + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandKick) diff --git a/src/commands/cmd_kill.cpp b/src/commands/cmd_kill.cpp new file mode 100644 index 000000000..1001d4c8a --- /dev/null +++ b/src/commands/cmd_kill.cpp @@ -0,0 +1,131 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /KILL. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandKill : public Command +{ + public: + /** Constructor for kill. + */ + CommandKill ( Module* parent) : Command(parent,"KILL",2,2) { flags_needed = 'o'; syntax = "<nickname> <reason>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +/** Handle /KILL + */ +CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User *user) +{ + /* Allow comma seperated lists of users for /KILL (thanks w00t) */ + if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + return CMD_SUCCESS; + + User *u = ServerInstance->FindNick(parameters[0]); + char killreason[MAXBUF]; + ModResult MOD_RESULT; + + if (u) + { + /* + * Here, we need to decide how to munge kill messages. Whether to hide killer, what to show opers, etc. + * We only do this when the command is being issued LOCALLY, for remote KILL, we just copy the message we got. + * + * This conditional is so that we only append the "Killed (" prefix ONCE. If killer is remote, then the kill + * just gets processed and passed on, otherwise, if they are local, it gets prefixed. Makes sense :-) -- w00t + */ + if (IS_LOCAL(user)) + { + /* + * Moved this event inside the IS_LOCAL check also, we don't want half the network killing a user + * and the other half not. This would be a bad thing. ;p -- w00t + */ + FIRST_MOD_RESULT(ServerInstance, OnKill, MOD_RESULT, (user, u, parameters[1])); + + if (MOD_RESULT == MOD_RES_DENY) + return CMD_FAILURE; + + if (*ServerInstance->Config->HideKillsServer) + { + // hidekills is on, use it + snprintf(killreason, ServerInstance->Config->Limits.MaxQuit, "Killed (%s (%s))", ServerInstance->Config->HideKillsServer, parameters[1].c_str()); + } + else + { + // hidekills is off, do nothing + snprintf(killreason, ServerInstance->Config->Limits.MaxQuit, "Killed (%s (%s))", user->nick.c_str(), parameters[1].c_str()); + } + } + else + { + /* Leave it alone, remote server has already formatted it */ + strlcpy(killreason, parameters[1].c_str(), ServerInstance->Config->Limits.MaxQuit); + } + + /* + * Now we need to decide whether or not to send a local or remote snotice. Currently this checking is a little flawed. + * No time to fix it right now, so left a note. -- w00t + */ + if (!IS_LOCAL(u)) + { + // remote kill + ServerInstance->SNO->WriteToSnoMask('K', "Remote kill by %s: %s!%s@%s (%s)", user->nick.c_str(), u->nick.c_str(), u->ident.c_str(), u->host.c_str(), parameters[1].c_str()); + FOREACH_MOD(I_OnRemoteKill, OnRemoteKill(user, u, killreason, killreason)); + } + else + { + // local kill + /* + * XXX - this isn't entirely correct, servers A - B - C, oper on A, client on C. Oper kills client, A and B will get remote kill + * snotices, C will get a local kill snotice. this isn't accurate, and needs fixing at some stage. -- w00t + */ + ServerInstance->SNO->WriteToSnoMask('k',"Local Kill by %s: %s!%s@%s (%s)", user->nick.c_str(), u->nick.c_str(), u->ident.c_str(), u->host.c_str(), parameters[1].c_str()); + ServerInstance->Logs->Log("KILL",DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick.c_str(), ServerInstance->Config->ServerName, user->dhost.c_str(), user->nick.c_str(), parameters[1].c_str()); + /* Bug #419, make sure this message can only occur once even in the case of multiple KILL messages crossing the network, and change to show + * hidekillsserver as source if possible + */ + if (!u->quitting) + { + u->Write(":%s KILL %s :%s!%s!%s (%s)", *ServerInstance->Config->HideKillsServer ? ServerInstance->Config->HideKillsServer : user->GetFullHost().c_str(), + u->nick.c_str(), + ServerInstance->Config->ServerName, + user->dhost.c_str(), + *ServerInstance->Config->HideKillsServer ? ServerInstance->Config->HideKillsServer : user->nick.c_str(), + parameters[1].c_str()); + } + } + + // send the quit out + ServerInstance->Users->QuitUser(u, killreason); + } + else + { + user->WriteServ( "401 %s %s :No such nick/channel", user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandKill) diff --git a/src/commands/cmd_kline.cpp b/src/commands/cmd_kline.cpp new file mode 100644 index 000000000..3ec2461b4 --- /dev/null +++ b/src/commands/cmd_kline.cpp @@ -0,0 +1,110 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "xline.h" + +/** Handle /KLINE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandKline : public Command +{ + public: + /** Constructor for kline. + */ + CommandKline ( Module* parent) : Command(parent,"KLINE",1,3) { flags_needed = 'o'; Penalty = 0; syntax = "<ident@host> [<duration> :<reason>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + + +/** Handle /KLINE + */ +CmdResult CommandKline::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::string target = parameters[0]; + + if (parameters.size() >= 3) + { + IdentHostPair ih; + User* find = ServerInstance->FindNick(target.c_str()); + if (find) + { + ih.first = "*"; + ih.second = find->GetIPString(); + target = std::string("*@") + find->GetIPString(); + } + else + ih = ServerInstance->XLines->IdentSplit(target.c_str()); + + if (ih.first.empty()) + { + user->WriteServ("NOTICE %s :*** Target not found", user->nick.c_str()); + return CMD_FAILURE; + } + + if (ServerInstance->HostMatchesEveryone(ih.first+"@"+ih.second,user)) + return CMD_FAILURE; + + if (target.find('!') != std::string::npos) + { + user->WriteServ("NOTICE %s :*** K-Line cannot operate on nick!user@host masks",user->nick.c_str()); + return CMD_FAILURE; + } + + long duration = ServerInstance->Duration(parameters[1].c_str()); + KLine* kl = new KLine(ServerInstance, ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ih.first.c_str(), ih.second.c_str()); + if (ServerInstance->XLines->AddLine(kl,user)) + { + if (!duration) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent K-line for %s: %s",user->nick.c_str(),target.c_str(), parameters[2].c_str()); + } + else + { + time_t c_requires_crap = duration + ServerInstance->Time(); + ServerInstance->SNO->WriteToSnoMask('x',"%s added timed K-line for %s, expires on %s: %s",user->nick.c_str(),target.c_str(), + ServerInstance->TimeString(c_requires_crap).c_str(), parameters[2].c_str()); + } + + ServerInstance->XLines->ApplyLines(); + } + else + { + delete kl; + user->WriteServ("NOTICE %s :*** K-Line for %s already exists",user->nick.c_str(),target.c_str()); + } + } + else + { + if (ServerInstance->XLines->DelLine(target.c_str(),"K",user)) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s removed K-line on %s",user->nick.c_str(),target.c_str()); + } + else + { + user->WriteServ("NOTICE %s :*** K-Line %s not found in list, try /stats k.",user->nick.c_str(),target.c_str()); + } + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandKline) diff --git a/src/commands/cmd_links.cpp b/src/commands/cmd_links.cpp new file mode 100644 index 000000000..d722fa65d --- /dev/null +++ b/src/commands/cmd_links.cpp @@ -0,0 +1,56 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_LINKS_H__ +#define __CMD_LINKS_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /LINKS. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandLinks : public Command +{ + public: + /** Constructor for links. + */ + CommandLinks ( Module* parent) : Command(parent,"LINKS",0,0) { } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /LINKS + */ +CmdResult CommandLinks::Handle (const std::vector<std::string>&, User *user) +{ + user->WriteNumeric(364, "%s %s %s :0 %s",user->nick.c_str(),ServerInstance->Config->ServerName,ServerInstance->Config->ServerName,ServerInstance->Config->ServerDesc); + user->WriteNumeric(365, "%s * :End of /LINKS list.",user->nick.c_str()); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandLinks) diff --git a/src/commands/cmd_list.cpp b/src/commands/cmd_list.cpp new file mode 100644 index 000000000..b7023072b --- /dev/null +++ b/src/commands/cmd_list.cpp @@ -0,0 +1,98 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /LIST. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandList : public Command +{ + public: + /** Constructor for list. + */ + CommandList ( Module* parent) : Command(parent,"LIST", 0, 0) { Penalty = 5; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + + +/** Handle /LIST + */ +CmdResult CommandList::Handle (const std::vector<std::string>& parameters, User *user) +{ + int minusers = 0, maxusers = 0; + + user->WriteNumeric(321, "%s Channel :Users Name",user->nick.c_str()); + + /* Work around mIRC suckyness. YOU SUCK, KHALED! */ + if (parameters.size() == 1) + { + if (parameters[0][0] == '<') + { + maxusers = atoi((parameters[0].c_str())+1); + } + else if (parameters[0][0] == '>') + { + minusers = atoi((parameters[0].c_str())+1); + } + } + + for (chan_hash::const_iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); i++) + { + // attempt to match a glob pattern + long users = i->second->GetUserCounter(); + + bool too_few = (minusers && (users <= minusers)); + bool too_many = (maxusers && (users >= maxusers)); + + if (too_many || too_few) + continue; + + if (parameters.size() && (parameters[0][0] != '<' && parameters[0][0] != '>')) + { + if (!InspIRCd::Match(i->second->name, parameters[0]) && !InspIRCd::Match(i->second->topic, parameters[0])) + continue; + } + + // if the channel is not private/secret, OR the user is on the channel anyway + bool n = (i->second->HasUser(user) || user->HasPrivPermission("channels/auspex")); + + if (!n && i->second->IsModeSet('p')) + { + /* Channel is +p and user is outside/not privileged */ + user->WriteNumeric(322, "%s * %ld :",user->nick.c_str(), users); + } + else + { + if (n || !i->second->IsModeSet('s')) + { + /* User is in the channel/privileged, channel is not +s */ + user->WriteNumeric(322, "%s %s %ld :[+%s] %s",user->nick.c_str(),i->second->name.c_str(),users,i->second->ChanModes(n),i->second->topic.c_str()); + } + } + } + user->WriteNumeric(323, "%s :End of channel list.",user->nick.c_str()); + + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandList) diff --git a/src/commands/cmd_loadmodule.cpp b/src/commands/cmd_loadmodule.cpp new file mode 100644 index 000000000..d4cda20ab --- /dev/null +++ b/src/commands/cmd_loadmodule.cpp @@ -0,0 +1,54 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /LOADMODULE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandLoadmodule : public Command +{ + public: + /** Constructor for loadmodule. + */ + CommandLoadmodule ( Module* parent) : Command(parent,"LOADMODULE",1,1) { flags_needed='o'; syntax = "<modulename>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + + +/** Handle /LOADMODULE + */ +CmdResult CommandLoadmodule::Handle (const std::vector<std::string>& parameters, User *user) +{ + if (ServerInstance->Modules->Load(parameters[0].c_str())) + { + ServerInstance->SNO->WriteToSnoMask('a', "NEW MODULE: %s loaded %s",user->nick.c_str(), parameters[0].c_str()); + user->WriteNumeric(975, "%s %s :Module successfully loaded.",user->nick.c_str(), parameters[0].c_str()); + return CMD_SUCCESS; + } + else + { + user->WriteNumeric(974, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str()); + return CMD_FAILURE; + } +} + +COMMAND_INIT(CommandLoadmodule) diff --git a/src/commands/cmd_lusers.cpp b/src/commands/cmd_lusers.cpp new file mode 100644 index 000000000..a79466ae4 --- /dev/null +++ b/src/commands/cmd_lusers.cpp @@ -0,0 +1,67 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_LUSERS_H__ +#define __CMD_LUSERS_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /LUSERS. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandLusers : public Command +{ + public: + /** Constructor for lusers. + */ + CommandLusers ( Module* parent) : Command(parent,"LUSERS",0,0) { } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /LUSERS + */ +CmdResult CommandLusers::Handle (const std::vector<std::string>&, User *user) +{ + // this lusers command shows one server at all times because + // a protocol module must override it to show those stats. + user->WriteNumeric(251, "%s :There are %d users and %d invisible on 1 server",user->nick.c_str(),ServerInstance->Users->UserCount()-ServerInstance->Users->ModeCount('i'),ServerInstance->Users->ModeCount('i')); + if (ServerInstance->Users->OperCount()) + user->WriteNumeric(252, "%s %d :operator(s) online",user->nick.c_str(),ServerInstance->Users->OperCount()); + if (ServerInstance->Users->UnregisteredUserCount()) + user->WriteNumeric(253, "%s %d :unknown connections",user->nick.c_str(),ServerInstance->Users->UnregisteredUserCount()); + if (ServerInstance->ChannelCount()) + user->WriteNumeric(254, "%s %ld :channels formed",user->nick.c_str(),ServerInstance->ChannelCount()); + if (ServerInstance->Users->LocalUserCount()) + user->WriteNumeric(255, "%s :I have %d clients and 0 servers",user->nick.c_str(),ServerInstance->Users->LocalUserCount()); + + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandLusers) diff --git a/src/commands/cmd_map.cpp b/src/commands/cmd_map.cpp new file mode 100644 index 000000000..edc8aa124 --- /dev/null +++ b/src/commands/cmd_map.cpp @@ -0,0 +1,44 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +class CommandMap : public Command +{ + public: + /** Constructor for map. + */ + CommandMap ( Module* parent) : Command(parent,"MAP",0,0) { Penalty=2; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +/** Handle /MAP + */ +CmdResult CommandMap::Handle (const std::vector<std::string>&, User *user) +{ + // as with /LUSERS this does nothing without a linking + // module to override its behaviour and display something + // better. + user->WriteNumeric(006, "%s :%s",user->nick.c_str(),ServerInstance->Config->ServerName); + user->WriteNumeric(007, "%s :End of /MAP",user->nick.c_str()); + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandMap) diff --git a/src/commands/cmd_mode.cpp b/src/commands/cmd_mode.cpp new file mode 100644 index 000000000..3cfc58263 --- /dev/null +++ b/src/commands/cmd_mode.cpp @@ -0,0 +1,55 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_ADMIN_H__ +#define __CMD_ADMIN_H__ + +#include "users.h" +#include "channels.h" +#include "ctables.h" + +/** Handle /MODE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandMode : public Command +{ + public: + /** Constructor for mode. + */ + CommandMode ( Module* parent) : Command(parent,"MODE",1) { syntax = "<target> <modes> {<mode-parameters>}"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /MODE + */ +CmdResult CommandMode::Handle (const std::vector<std::string>& parameters, User *user) +{ + ServerInstance->Modes->Process(parameters, user, false); + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandMode) diff --git a/src/commands/cmd_modules.cpp b/src/commands/cmd_modules.cpp new file mode 100644 index 000000000..599eb611b --- /dev/null +++ b/src/commands/cmd_modules.cpp @@ -0,0 +1,78 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_MODULES_H__ +#define __CMD_MODULES_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /MODULES. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandModules : public Command +{ + public: + /** Constructor for modules. + */ + CommandModules ( Module* parent) : Command(parent,"MODULES",0,0) { syntax = "[debug]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /MODULES + */ +CmdResult CommandModules::Handle (const std::vector<std::string>&, User *user) +{ + std::vector<std::string> module_names = ServerInstance->Modules->GetAllModuleNames(0); + + for (unsigned int i = 0; i < module_names.size(); i++) + { + Module* m = ServerInstance->Modules->Find(module_names[i]); + Version V = m->GetVersion(); + + if (user->HasPrivPermission("servers/auspex")) + { + std::string flags("Svsc"); + int pos = 0; + for (int mult = 1; mult <= VF_SERVICEPROVIDER; mult *= 2, ++pos) + if (!(V.Flags & mult)) + flags[pos] = '-'; + + user->WriteNumeric(702, "%s :0x%08lx %s %s :%s", user->nick.c_str(), (unsigned long)m, module_names[i].c_str(), flags.c_str(), V.version.c_str()); + } + else + { + user->WriteNumeric(702, "%s :%s",user->nick.c_str(), module_names[i].c_str()); + } + } + user->WriteNumeric(703, "%s :End of MODULES list",user->nick.c_str()); + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandModules) diff --git a/src/commands/cmd_motd.cpp b/src/commands/cmd_motd.cpp new file mode 100644 index 000000000..0e0785e93 --- /dev/null +++ b/src/commands/cmd_motd.cpp @@ -0,0 +1,58 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_MOTD_H__ +#define __CMD_MOTD_H__ + +// include the common header files + +#include <string> +#include <vector> +#include "inspircd.h" +#include "users.h" +#include "channels.h" + +/** Handle /MOTD. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandMotd : public Command +{ + public: + /** Constructor for motd. + */ + CommandMotd ( Module* parent) : Command(parent,"MOTD",0,1) { syntax = "[<servername>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /MOTD + */ +CmdResult CommandMotd::Handle (const std::vector<std::string>&, User *user) +{ + user->ShowMOTD(); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandMotd) diff --git a/src/commands/cmd_names.cpp b/src/commands/cmd_names.cpp new file mode 100644 index 000000000..537c477c8 --- /dev/null +++ b/src/commands/cmd_names.cpp @@ -0,0 +1,80 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_NAMES_H__ +#define __CMD_NAMES_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /NAMES. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandNames : public Command +{ + public: + /** Constructor for names. + */ + CommandNames ( Module* parent) : Command(parent,"NAMES",0,0) { syntax = "{<channel>{,<channel>}}"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +/** Handle /NAMES + */ +CmdResult CommandNames::Handle (const std::vector<std::string>& parameters, User *user) +{ + Channel* c; + + if (!parameters.size()) + { + user->WriteNumeric(366, "%s * :End of /NAMES list.",user->nick.c_str()); + return CMD_SUCCESS; + } + + if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + return CMD_SUCCESS; + + c = ServerInstance->FindChan(parameters[0]); + if (c) + { + if ((c->IsModeSet('s')) && (!c->HasUser(user))) + { + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), c->name.c_str()); + return CMD_FAILURE; + } + c->UserList(user); + } + else + { + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandNames) diff --git a/src/commands/cmd_nick.cpp b/src/commands/cmd_nick.cpp new file mode 100644 index 000000000..99b8348ab --- /dev/null +++ b/src/commands/cmd_nick.cpp @@ -0,0 +1,214 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "xline.h" + +/** Handle /NICK. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandNick : public Command +{ + public: + /** Constructor for nick. + */ + CommandNick ( Module* parent) : Command(parent,"NICK", 1, 1) { works_before_reg = true; syntax = "<newnick>"; Penalty = 3; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +/** 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::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::string oldnick; + + if (parameters[0].empty()) + { + /* We cant put blanks in the parameters, so for this (extremely rare) issue we just put '*' here. */ + user->WriteNumeric(432, "%s * :Erroneous Nickname", user->nick.empty() ? user->nick.c_str() : "*"); + return CMD_FAILURE; + } + + if (((!ServerInstance->IsNick(parameters[0].c_str(), ServerInstance->Config->Limits.NickMax))) && (IS_LOCAL(user))) + { + if (!User::NICKForced.get(user)) + { + if (parameters[0] == "0") + { + // Special case, Fake a /nick UIDHERE. Useful for evading "ERR: NICK IN USE" on connect etc. + std::vector<std::string> p2; + p2.push_back(user->uuid); + User::NICKForced.set(user, 1); + this->Handle(p2, user); + User::NICKForced.set(user, 0); + return CMD_SUCCESS; + } + + user->WriteNumeric(432, "%s %s :Erroneous Nickname", user->nick.c_str(),parameters[0].c_str()); + return CMD_FAILURE; + } + } + + if (assign(user->nick) == parameters[0]) + { + /* If its exactly the same, even case, dont do anything. */ + if (parameters[0] == user->nick) + { + return CMD_SUCCESS; + } + + /* Its a change of case. People insisted that they should be + * able to do silly things like this even though the RFC says + * the nick AAA is the same as the nick aaa. + */ + oldnick.assign(user->nick, 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); + ModResult MOD_RESULT; + FIRST_MOD_RESULT(ServerInstance, OnUserPreNick, MOD_RESULT, (user,parameters[0])); + if (MOD_RESULT == MOD_RES_DENY) + return CMD_FAILURE; + if (user->registered == REG_ALL) + user->WriteCommon("NICK %s",parameters[0].c_str()); + user->nick.assign(parameters[0], 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); + user->InvalidateCache(); + FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user,oldnick)); + return CMD_SUCCESS; + } + else + { + /* + * Don't check Q:Lines if it's a server-enforced change, just on the off-chance some fucking *moron* + * tries to Q:Line SIDs, also, this means we just get our way period, as it really should be. + * Thanks Kein for finding this. -- w00t + * + * Also don't check Q:Lines for remote nickchanges, they should have our Q:Lines anyway to enforce themselves. + * -- w00t + */ + if (!IS_LOCAL(user)) + { + XLine* mq = ServerInstance->XLines->MatchesLine("Q",parameters[0]); + if (mq) + { + if (user->registered == REG_ALL) + { + ServerInstance->SNO->WriteGlobalSno('a', "Q-Lined nickname %s from %s!%s@%s: %s", + parameters[0].c_str(), user->nick.c_str(), user->ident.c_str(), user->host.c_str(), mq->reason.c_str()); + } + user->WriteNumeric(432, "%s %s :Invalid nickname: %s",user->nick.c_str(), parameters[0].c_str(), mq->reason.c_str()); + return CMD_FAILURE; + } + + if (ServerInstance->Config->RestrictBannedUsers) + { + for (UCListIter i = user->chans.begin(); i != user->chans.end(); i++) + { + Channel *chan = *i; + if (chan->GetPrefixValue(user) < VOICE_VALUE && chan->IsBanned(user)) + { + user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str()); + return CMD_FAILURE; + } + } + } + } + + /* + * Uh oh.. if the nickname is in use, and it's not in use by the person using it (doh) -- + * then we have a potential collide. Check whether someone else is camping on the nick + * (i.e. connect -> send NICK, don't send USER.) If they are camping, force-change the + * camper to their UID, and allow the incoming nick change. + * + * If the guy using the nick is already using it, tell the incoming nick change to gtfo, + * because the nick is already (rightfully) in use. -- w00t + */ + User* InUse = ServerInstance->FindNickOnly(parameters[0]); + if (InUse && (InUse != user)) + { + if (InUse->registered != REG_ALL) + { + /* force the camper to their UUID, and ask them to re-send a NICK. */ + InUse->WriteTo(InUse, "NICK %s", InUse->uuid.c_str()); + InUse->WriteNumeric(433, "%s %s :Nickname overruled.", InUse->nick.c_str(), InUse->nick.c_str()); + InUse->UpdateNickHash(InUse->uuid.c_str()); + InUse->nick.assign(InUse->uuid, 0, IS_LOCAL(InUse) ? ServerInstance->Config->Limits.NickMax : MAXBUF); + InUse->InvalidateCache(); + InUse->registered &= ~REG_NICK; + } + else + { + /* No camping, tell the incoming user to stop trying to change nick ;p */ + user->WriteNumeric(433, "%s %s :Nickname is already in use.", user->registered >= REG_NICK ? user->nick.c_str() : "*", parameters[0].c_str()); + return CMD_FAILURE; + } + } + } + + + ModResult MOD_RESULT; + FIRST_MOD_RESULT(ServerInstance, OnUserPreNick, MOD_RESULT, (user, parameters[0])); + if (MOD_RESULT == MOD_RES_DENY) + // if a module returns true, the nick change is silently forbidden. + return CMD_FAILURE; + + if (user->registered == REG_ALL) + user->WriteCommon("NICK %s", parameters[0].c_str()); + + oldnick.assign(user->nick, 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); + + /* change the nick of the user in the users_hash */ + user = user->UpdateNickHash(parameters[0].c_str()); + + /* actually change the nick within the record */ + if (!user) + return CMD_FAILURE; + + user->nick.assign(parameters[0], 0, IS_LOCAL(user) ? ServerInstance->Config->Limits.NickMax : MAXBUF); + user->InvalidateCache(); + + if (user->registered < REG_NICKUSER) + { + user->registered = (user->registered | REG_NICK); + if (user->registered == REG_NICKUSER) + { + /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */ + FIRST_MOD_RESULT(ServerInstance, OnUserRegister, MOD_RESULT, (user)); + if (MOD_RESULT == MOD_RES_DENY) + return CMD_FAILURE; + + // return early to not penalize new users + return CMD_SUCCESS; + } + } + + if (user->registered == REG_ALL) + { + user->IncreasePenalty(10); + FOREACH_MOD(I_OnUserPostNick,OnUserPostNick(user, oldnick)); + } + + return CMD_SUCCESS; + +} + + +COMMAND_INIT(CommandNick) diff --git a/src/commands/cmd_notice.cpp b/src/commands/cmd_notice.cpp new file mode 100644 index 000000000..ced17072f --- /dev/null +++ b/src/commands/cmd_notice.cpp @@ -0,0 +1,203 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +/** Handle /NOTICE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandNotice : public Command +{ + public: + /** Constructor for notice. + */ + CommandNotice ( Module* parent) : Command(parent,"NOTICE",2,2) { syntax = "<target>{,<target>} <message>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + + +CmdResult CommandNotice::Handle (const std::vector<std::string>& parameters, User *user) +{ + User *dest; + Channel *chan; + + CUList exempt_list; + + user->idle_lastmsg = ServerInstance->Time(); + + if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + return CMD_SUCCESS; + if (parameters[0][0] == '$') + { + if (!user->HasPrivPermission("users/mass-message")) + return CMD_SUCCESS; + + ModResult MOD_RESULT; + std::string temp = parameters[1]; + FIRST_MOD_RESULT(ServerInstance, OnUserPreNotice, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, exempt_list)); + if (MOD_RESULT == MOD_RES_DENY) + return CMD_FAILURE; + const char* text = temp.c_str(); + const char* servermask = (parameters[0].c_str()) + 1; + + FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list)); + if (InspIRCd::Match(ServerInstance->Config->ServerName,servermask, NULL)) + { + user->SendAll("NOTICE", "%s", text); + } + FOREACH_MOD(I_OnUserNotice,OnUserNotice(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, exempt_list)); + return CMD_SUCCESS; + } + char status = 0; + const char* target = parameters[0].c_str(); + + if (ServerInstance->Modes->FindPrefix(*target)) + { + status = *target; + target++; + } + if (*target == '#') + { + chan = ServerInstance->FindChan(target); + + exempt_list.insert(user); + + if (chan) + { + if (IS_LOCAL(user)) + { + if ((chan->IsModeSet('n')) && (!chan->HasUser(user))) + { + user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str()); + return CMD_FAILURE; + } + if ((chan->IsModeSet('m')) && (chan->GetPrefixValue(user) < VOICE_VALUE)) + { + user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str()); + return CMD_FAILURE; + } + } + ModResult MOD_RESULT; + + std::string temp = parameters[1]; + FIRST_MOD_RESULT(ServerInstance, OnUserPreNotice, MOD_RESULT, (user,chan,TYPE_CHANNEL,temp,status, exempt_list)); + if (MOD_RESULT == MOD_RES_DENY) + return CMD_FAILURE; + + const char* text = temp.c_str(); + + if (temp.empty()) + { + user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); + return CMD_FAILURE; + } + + FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,exempt_list)); + + if (status) + { + if (ServerInstance->Config->UndernetMsgPrefix) + { + chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%c %s", status, chan->name.c_str(), status, text); + } + else + { + chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %c%s :%s", status, chan->name.c_str(), text); + } + } + else + { + chan->WriteAllExcept(user, false, status, exempt_list, "NOTICE %s :%s", chan->name.c_str(), text); + } + + FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,chan,TYPE_CHANNEL,text,status,exempt_list)); + } + else + { + /* no such nick/channel */ + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), target); + return CMD_FAILURE; + } + return CMD_SUCCESS; + } + + const char* destnick = parameters[0].c_str(); + + if (IS_LOCAL(user)) + { + const char* targetserver = strchr(destnick, '@'); + + if (targetserver) + { + std::string nickonly; + + nickonly.assign(destnick, 0, targetserver - destnick); + dest = ServerInstance->FindNickOnly(nickonly); + if (dest && strcasecmp(dest->server, targetserver + 1)) + { + /* Incorrect server for user */ + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + } + else + dest = ServerInstance->FindNickOnly(destnick); + } + else + dest = ServerInstance->FindNick(destnick); + + if (dest) + { + if (parameters[1].empty()) + { + user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); + return CMD_FAILURE; + } + + ModResult MOD_RESULT; + std::string temp = parameters[1]; + FIRST_MOD_RESULT(ServerInstance, OnUserPreNotice, MOD_RESULT, (user,dest,TYPE_USER,temp,0,exempt_list)); + if (MOD_RESULT == MOD_RES_DENY) { + return CMD_FAILURE; + } + const char* text = temp.c_str(); + + FOREACH_MOD(I_OnText,OnText(user,dest,TYPE_USER,text,0,exempt_list)); + + if (IS_LOCAL(dest)) + { + // direct write, same server + user->WriteTo(dest, "NOTICE %s :%s", dest->nick.c_str(), text); + } + + FOREACH_MOD(I_OnUserNotice,OnUserNotice(user,dest,TYPE_USER,text,0,exempt_list)); + } + else + { + /* no such nick/channel */ + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + + return CMD_SUCCESS; + +} + +COMMAND_INIT(CommandNotice) diff --git a/src/commands/cmd_oper.cpp b/src/commands/cmd_oper.cpp new file mode 100644 index 000000000..da53d2b1a --- /dev/null +++ b/src/commands/cmd_oper.cpp @@ -0,0 +1,170 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "hashcomp.h" + +bool OneOfMatches(const char* host, const char* ip, const char* hostlist); + +/** Handle /OPER. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandOper : public Command +{ + public: + /** Constructor for oper. + */ + CommandOper ( Module* parent) : Command(parent,"OPER",2,2) { syntax = "<username> <password>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +bool OneOfMatches(const char* host, const char* ip, const char* hostlist) +{ + std::stringstream hl(hostlist); + std::string xhost; + while (hl >> xhost) + { + if (InspIRCd::Match(host, xhost, ascii_case_insensitive_map) || InspIRCd::MatchCIDR(ip, xhost, ascii_case_insensitive_map)) + { + return true; + } + } + return false; +} + +CmdResult CommandOper::Handle (const std::vector<std::string>& parameters, User *user) +{ + char LoginName[MAXBUF]; + char Password[MAXBUF]; + char OperType[MAXBUF]; + char TypeName[MAXBUF]; + char HostName[MAXBUF]; + char ClassName[MAXBUF]; + char TheHost[MAXBUF]; + char TheIP[MAXBUF]; + char HashType[MAXBUF]; + int j; + bool found = false; + bool type_invalid = false; + + bool match_login = false; + bool match_pass = false; + bool match_hosts = false; + + snprintf(TheHost,MAXBUF,"%s@%s",user->ident.c_str(),user->host.c_str()); + snprintf(TheIP, MAXBUF,"%s@%s",user->ident.c_str(),user->GetIPString()); + + for (int i = 0; i < ServerInstance->Config->ConfValueEnum("oper"); i++) + { + ServerInstance->Config->ConfValue("oper", "name", i, LoginName, MAXBUF); + ServerInstance->Config->ConfValue("oper", "password", i, Password, MAXBUF); + ServerInstance->Config->ConfValue("oper", "type", i, OperType, MAXBUF); + ServerInstance->Config->ConfValue("oper", "host", i, HostName, MAXBUF); + ServerInstance->Config->ConfValue("oper", "hash", i, HashType, MAXBUF); + + match_login = (LoginName == parameters[0]); + match_pass = !ServerInstance->PassCompare(user, Password, parameters[1], HashType); + match_hosts = OneOfMatches(TheHost,TheIP,HostName); + + if (match_login && match_pass && match_hosts) + { + type_invalid = true; + for (j =0; j < ServerInstance->Config->ConfValueEnum("type"); j++) + { + ServerInstance->Config->ConfValue("type", "name", j, TypeName, MAXBUF); + ServerInstance->Config->ConfValue("type", "class", j, ClassName, MAXBUF); + + if (!strcmp(TypeName,OperType)) + { + /* found this oper's opertype */ + if (!ServerInstance->IsNick(TypeName, ServerInstance->Config->Limits.NickMax)) + { + user->WriteNumeric(491, "%s :Invalid oper type (oper types must follow the same syntax as nicknames)",user->nick.c_str()); + ServerInstance->SNO->WriteToSnoMask('o',"CONFIGURATION ERROR! Oper type '%s' contains invalid characters",OperType); + ServerInstance->Logs->Log("OPER",DEFAULT,"OPER: Failed oper attempt by %s!%s@%s: credentials valid, but oper type erroneous.", user->nick.c_str(), user->ident.c_str(), user->host.c_str()); + return CMD_FAILURE; + } + ServerInstance->Config->ConfValue("type","host", j, HostName, MAXBUF); + if (*HostName) + user->ChangeDisplayedHost(HostName); + if (*ClassName) + { + user->SetClass(ClassName); + user->CheckClass(); + } + found = true; + type_invalid = false; + break; + } + } + } + if (match_login || found) + break; + } + if (found) + { + /* correct oper credentials */ + user->Oper(OperType, LoginName); + } + else + { + char broadcast[MAXBUF]; + + if (!type_invalid) + { + std::string fields; + if (!match_login) + fields.append("login "); + else + { + if (!match_pass) + fields.append("password "); + if (!match_hosts) + fields.append("hosts"); + } + + // tell them they suck, and lag them up to help prevent brute-force attacks + user->WriteNumeric(491, "%s :Invalid oper credentials",user->nick.c_str()); + user->IncreasePenalty(10); + + snprintf(broadcast, MAXBUF, "WARNING! Failed oper attempt by %s!%s@%s using login '%s': The following fields do not match: %s", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), parameters[0].c_str(), fields.c_str()); + ServerInstance->SNO->WriteToSnoMask('o',std::string(broadcast)); + ServerInstance->PI->SendSNONotice("o", std::string("OPER: ") + broadcast); + + ServerInstance->Logs->Log("OPER",DEFAULT,"OPER: Failed oper attempt by %s!%s@%s using login '%s': The following fields did not match: %s", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), parameters[0].c_str(), fields.c_str()); + return CMD_FAILURE; + } + else + { + user->WriteNumeric(491, "%s :Your oper block does not have a valid opertype associated with it",user->nick.c_str()); + + snprintf(broadcast, MAXBUF, "CONFIGURATION ERROR! Oper block '%s': missing OperType %s",parameters[0].c_str(),OperType); + + ServerInstance->SNO->WriteToSnoMask('o', std::string(broadcast)); + + ServerInstance->Logs->Log("OPER",DEFAULT,"OPER: Failed oper attempt by %s!%s@%s using login '%s': credentials valid, but oper type nonexistent.", user->nick.c_str(), user->ident.c_str(), user->host.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + } + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandOper) diff --git a/src/commands/cmd_part.cpp b/src/commands/cmd_part.cpp new file mode 100644 index 000000000..e2e4e59a0 --- /dev/null +++ b/src/commands/cmd_part.cpp @@ -0,0 +1,77 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /PART. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandPart : public Command +{ + public: + /** Constructor for part. + */ + CommandPart (Module* parent) : Command(parent,"PART", 1, 2) { Penalty = 5; syntax = "<channel>{,<channel>} [<reason>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandPart::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::string reason; + + if (IS_LOCAL(user)) + { + if (*ServerInstance->Config->FixedPart) + reason = ServerInstance->Config->FixedPart; + else + { + if (parameters.size() > 1) + reason = ServerInstance->Config->PrefixPart + std::string(parameters[1]) + ServerInstance->Config->SuffixPart; + else + reason = ""; + } + } + else + { + reason = parameters.size() > 1 ? parameters[1] : ""; + } + + if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + return CMD_SUCCESS; + + Channel* c = ServerInstance->FindChan(parameters[0]); + + if (c) + { + if (!c->PartUser(user, reason)) + /* Arse, who stole our channel! :/ */ + delete c; + } + else + { + user->WriteServ( "401 %s %s :No such channel", user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandPart) diff --git a/src/commands/cmd_pass.cpp b/src/commands/cmd_pass.cpp new file mode 100644 index 000000000..6219118ee --- /dev/null +++ b/src/commands/cmd_pass.cpp @@ -0,0 +1,56 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /PASS. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandPass : public Command +{ + public: + /** Constructor for pass. + */ + CommandPass ( Module* parent) : Command(parent,"PASS",1,1) { works_before_reg = true; Penalty = 0; syntax = "<password>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + + +CmdResult CommandPass::Handle (const std::vector<std::string>& parameters, User *user) +{ + // Check to make sure they havnt registered -- Fix by FCS + if (user->registered == REG_ALL) + { + user->WriteNumeric(ERR_ALREADYREGISTERED, "%s :You may not reregister",user->nick.c_str()); + return CMD_FAILURE; + } + ConnectClass* a = user->GetClass(); + if (!a) + return CMD_FAILURE; + + user->password.assign(parameters[0], 0, 63); + if (!ServerInstance->PassCompare(user, a->pass.c_str(), parameters[0].c_str(), a->hash.c_str())) + user->haspassed = true; + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandPass) diff --git a/src/commands/cmd_ping.cpp b/src/commands/cmd_ping.cpp new file mode 100644 index 000000000..e7898921a --- /dev/null +++ b/src/commands/cmd_ping.cpp @@ -0,0 +1,42 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /PING. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandPing : public Command +{ + public: + /** Constructor for ping. + */ + CommandPing ( Module* parent) : Command(parent,"PING", 1, 2) { Penalty = 0; syntax = "<servername> [:<servername>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandPing::Handle (const std::vector<std::string>& parameters, User *user) +{ + user->WriteServ("PONG %s :%s", ServerInstance->Config->ServerName, parameters[0].c_str()); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandPing) diff --git a/src/commands/cmd_pong.cpp b/src/commands/cmd_pong.cpp new file mode 100644 index 000000000..225be147a --- /dev/null +++ b/src/commands/cmd_pong.cpp @@ -0,0 +1,43 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /PONG. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +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 comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandPong::Handle (const std::vector<std::string>&, User *user) +{ + // set the user as alive so they survive to next ping + user->lastping = 1; + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandPong) diff --git a/src/commands/cmd_privmsg.cpp b/src/commands/cmd_privmsg.cpp new file mode 100644 index 000000000..781ad8bac --- /dev/null +++ b/src/commands/cmd_privmsg.cpp @@ -0,0 +1,220 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /PRIVMSG. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandPrivmsg : public Command +{ + public: + /** Constructor for privmsg. + */ + CommandPrivmsg ( Module* parent) : Command(parent,"PRIVMSG",2,2) { syntax = "<target>{,<target>} <message>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandPrivmsg::Handle (const std::vector<std::string>& parameters, User *user) +{ + User *dest; + Channel *chan; + CUList except_list; + + user->idle_lastmsg = ServerInstance->Time(); + + if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + return CMD_SUCCESS; + + if (parameters[0][0] == '$') + { + if (!user->HasPrivPermission("users/mass-message")) + return CMD_SUCCESS; + + ModResult MOD_RESULT; + std::string temp = parameters[1]; + FIRST_MOD_RESULT(ServerInstance, OnUserPreMessage, MOD_RESULT, (user, (void*)parameters[0].c_str(), TYPE_SERVER, temp, 0, except_list)); + if (MOD_RESULT == MOD_RES_DENY) + return CMD_FAILURE; + + const char* text = temp.c_str(); + const char* servermask = (parameters[0].c_str()) + 1; + + FOREACH_MOD(I_OnText,OnText(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list)); + if (InspIRCd::Match(ServerInstance->Config->ServerName, servermask, NULL)) + { + user->SendAll("PRIVMSG", "%s", text); + } + FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, (void*)parameters[0].c_str(), TYPE_SERVER, text, 0, except_list)); + return CMD_SUCCESS; + } + char status = 0; + const char* target = parameters[0].c_str(); + + if (ServerInstance->Modes->FindPrefix(*target)) + { + status = *target; + target++; + } + if (*target == '#') + { + chan = ServerInstance->FindChan(target); + + except_list.insert(user); + + if (chan) + { + if (IS_LOCAL(user) && chan->GetPrefixValue(user) < VOICE_VALUE) + { + if (chan->IsModeSet('n') && !chan->HasUser(user)) + { + user->WriteNumeric(404, "%s %s :Cannot send to channel (no external messages)", user->nick.c_str(), chan->name.c_str()); + return CMD_FAILURE; + } + + if (chan->IsModeSet('m')) + { + user->WriteNumeric(404, "%s %s :Cannot send to channel (+m)", user->nick.c_str(), chan->name.c_str()); + return CMD_FAILURE; + } + + if (ServerInstance->Config->RestrictBannedUsers) + { + if (chan->IsBanned(user)) + { + user->WriteNumeric(404, "%s %s :Cannot send to channel (you're banned)", user->nick.c_str(), chan->name.c_str()); + return CMD_FAILURE; + } + } + } + ModResult MOD_RESULT; + + std::string temp = parameters[1]; + FIRST_MOD_RESULT(ServerInstance, OnUserPreMessage, MOD_RESULT, (user,chan,TYPE_CHANNEL,temp,status,except_list)); + if (MOD_RESULT == MOD_RES_DENY) + return CMD_FAILURE; + + const char* text = temp.c_str(); + + /* Check again, a module may have zapped the input string */ + if (temp.empty()) + { + user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); + return CMD_FAILURE; + } + + FOREACH_MOD(I_OnText,OnText(user,chan,TYPE_CHANNEL,text,status,except_list)); + + if (status) + { + if (ServerInstance->Config->UndernetMsgPrefix) + { + chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%c %s", status, chan->name.c_str(), status, text); + } + else + { + chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %c%s :%s", status, chan->name.c_str(), text); + } + } + else + { + chan->WriteAllExcept(user, false, status, except_list, "PRIVMSG %s :%s", chan->name.c_str(), text); + } + + FOREACH_MOD(I_OnUserMessage,OnUserMessage(user,chan,TYPE_CHANNEL,text,status,except_list)); + } + else + { + /* no such nick/channel */ + user->WriteNumeric(401, "%s %s :No such nick/channel", user->nick.c_str(), target); + return CMD_FAILURE; + } + return CMD_SUCCESS; + } + + const char* destnick = parameters[0].c_str(); + + if (IS_LOCAL(user)) + { + const char* targetserver = strchr(destnick, '@'); + + if (targetserver) + { + std::string nickonly; + + nickonly.assign(destnick, 0, targetserver - destnick); + dest = ServerInstance->FindNickOnly(nickonly); + if (dest && strcasecmp(dest->server, targetserver + 1)) + { + /* Incorrect server for user */ + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + } + else + dest = ServerInstance->FindNickOnly(destnick); + } + else + dest = ServerInstance->FindNick(destnick); + + if (dest) + { + if (parameters[1].empty()) + { + user->WriteNumeric(412, "%s :No text to send", user->nick.c_str()); + return CMD_FAILURE; + } + + if (IS_AWAY(dest)) + { + /* auto respond with aweh msg */ + user->WriteNumeric(301, "%s %s :%s", user->nick.c_str(), dest->nick.c_str(), dest->awaymsg.c_str()); + } + + ModResult MOD_RESULT; + + std::string temp = parameters[1]; + FIRST_MOD_RESULT(ServerInstance, OnUserPreMessage, MOD_RESULT, (user, dest, TYPE_USER, temp, 0, except_list)); + if (MOD_RESULT == MOD_RES_DENY) + return CMD_FAILURE; + + const char* text = temp.c_str(); + + FOREACH_MOD(I_OnText,OnText(user, dest, TYPE_USER, text, 0, except_list)); + + if (IS_LOCAL(dest)) + { + // direct write, same server + user->WriteTo(dest, "PRIVMSG %s :%s", dest->nick.c_str(), text); + } + + FOREACH_MOD(I_OnUserMessage,OnUserMessage(user, dest, TYPE_USER, text, 0, except_list)); + } + else + { + /* no such nick/channel */ + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandPrivmsg) diff --git a/src/commands/cmd_qline.cpp b/src/commands/cmd_qline.cpp new file mode 100644 index 000000000..ffe8c5ee6 --- /dev/null +++ b/src/commands/cmd_qline.cpp @@ -0,0 +1,86 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "xline.h" + +/** Handle /QLINE. */ +class CommandQline : public Command +{ + public: + /** Constructor for qline. + */ + CommandQline ( Module* parent) : Command(parent,"QLINE",1,3) { flags_needed = 'o'; Penalty = 0; syntax = "<nick> [<duration> :<reason>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed 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); +}; + + +CmdResult CommandQline::Handle (const std::vector<std::string>& parameters, User *user) +{ + if (parameters.size() >= 3) + { + if (ServerInstance->NickMatchesEveryone(parameters[0],user)) + return CMD_FAILURE; + + if (parameters[0].find('@') != std::string::npos || parameters[0].find('!') != std::string::npos || parameters[0].find('.') != std::string::npos) + { + user->WriteServ("NOTICE %s :*** A Q-Line only bans a nick pattern, not a nick!user@host pattern.",user->nick.c_str()); + return CMD_FAILURE; + } + + long duration = ServerInstance->Duration(parameters[1].c_str()); + QLine* ql = new QLine(ServerInstance, ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str()); + if (ServerInstance->XLines->AddLine(ql,user)) + { + if (!duration) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent Q-line for %s: %s",user->nick.c_str(), parameters[0].c_str(), parameters[2].c_str()); + } + else + { + time_t c_requires_crap = duration + ServerInstance->Time(); + ServerInstance->SNO->WriteToSnoMask('x',"%s added timed Q-line for %s, expires on %s: %s",user->nick.c_str(),parameters[0].c_str(), + ServerInstance->TimeString(c_requires_crap).c_str(), parameters[2].c_str()); + } + ServerInstance->XLines->ApplyLines(); + } + else + { + delete ql; + user->WriteServ("NOTICE %s :*** Q-Line for %s already exists",user->nick.c_str(),parameters[0].c_str()); + } + } + else + { + if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "Q", user)) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s removed Q-line on %s",user->nick.c_str(),parameters[0].c_str()); + } + else + { + user->WriteServ("NOTICE %s :*** Q-Line %s not found in list, try /stats q.",user->nick.c_str(),parameters[0].c_str()); + return CMD_FAILURE; + } + } + + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandQline) diff --git a/src/commands/cmd_quit.cpp b/src/commands/cmd_quit.cpp new file mode 100644 index 000000000..d041fc031 --- /dev/null +++ b/src/commands/cmd_quit.cpp @@ -0,0 +1,68 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /QUIT. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandQuit : public Command +{ + public: + /** Constructor for quit. + */ + CommandQuit ( Module* parent) : Command(parent,"QUIT",0,1) { works_before_reg = true; syntax = "[<message>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + + +CmdResult CommandQuit::Handle (const std::vector<std::string>& parameters, User *user) +{ + + std::string quitmsg; + + if (IS_LOCAL(user)) + { + if (*ServerInstance->Config->FixedQuit) + quitmsg = ServerInstance->Config->FixedQuit; + else + quitmsg = parameters.size() ? + ServerInstance->Config->PrefixQuit + std::string(parameters[0]) + ServerInstance->Config->SuffixQuit + : "Client exited"; + } + else + quitmsg = parameters.size() ? parameters[0] : "Client exited"; + + std::string* operquit = User::OperQuit.get(user); + if (operquit) + { + ServerInstance->Users->QuitUser(user, quitmsg, operquit->c_str()); + } + else + { + ServerInstance->Users->QuitUser(user, quitmsg); + } + + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandQuit) diff --git a/src/commands/cmd_rehash.cpp b/src/commands/cmd_rehash.cpp new file mode 100644 index 000000000..a689801aa --- /dev/null +++ b/src/commands/cmd_rehash.cpp @@ -0,0 +1,109 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "xline.h" +/** Handle /REHASH. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandRehash : public Command +{ + public: + /** Constructor for rehash. + */ + CommandRehash ( Module* parent) : Command(parent,"REHASH",0) { flags_needed = 'o'; Penalty = 2; syntax = "[<servermask>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandRehash::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::string param = parameters.size() ? parameters[0] : ""; + + FOREACH_MOD(I_OnPreRehash,OnPreRehash(user, param)); + + if (param.empty()) + { + // standard rehash of local server + } + else if (param.find_first_of("*.") != std::string::npos) + { + // rehash of servers by server name (with wildcard) + if (!InspIRCd::Match(ServerInstance->Config->ServerName, parameters[0])) + { + // Doesn't match us. PreRehash is already done, nothing left to do + return CMD_SUCCESS; + } + } + else + { + // parameterized rehash + + // the leading "-" is optional; remove it if present. + if (param[0] == '-') + param = param.substr(1); + + FOREACH_MOD(I_OnModuleRehash,OnModuleRehash(user, param)); + return CMD_SUCCESS; + } + + // Rehash for me. Try to start the rehash thread + if (!ServerInstance->ConfigThread) + { + std::string m = user->nick + " is rehashing config file " + ServerConfig::CleanFilename(ServerInstance->ConfigFileName) + " on " + ServerInstance->Config->ServerName; + ServerInstance->SNO->WriteGlobalSno('a', m); + + if (IS_LOCAL(user)) + user->WriteNumeric(RPL_REHASHING, "%s %s :Rehashing", + user->nick.c_str(),ServerConfig::CleanFilename(ServerInstance->ConfigFileName)); + else + ServerInstance->PI->SendUserNotice(user, std::string("*** Rehashing server ") + + ServerConfig::CleanFilename(ServerInstance->ConfigFileName)); + + /* Don't do anything with the logs here -- logs are restarted + * after the config thread has completed. + */ + + ServerInstance->RehashUsersAndChans(); + FOREACH_MOD(I_OnGarbageCollect, OnGarbageCollect()); + + + ServerInstance->ConfigThread = new ConfigReaderThread(ServerInstance, user->uuid); + ServerInstance->Threads->Start(ServerInstance->ConfigThread); + + return CMD_SUCCESS; + } + else + { + /* + * A rehash is already in progress! ahh shit. + * XXX, todo: we should find some way to kill runaway rehashes that are blocking, this is a major problem for unrealircd users + */ + if (IS_LOCAL(user)) + user->WriteServ("NOTICE %s :*** Could not rehash: A rehash is already in progress.", user->nick.c_str()); + else + ServerInstance->PI->SendUserNotice(user, "*** Could not rehash: A rehash is already in progress."); + + return CMD_FAILURE; + } +} + + +COMMAND_INIT(CommandRehash) diff --git a/src/commands/cmd_reloadmodule.cpp b/src/commands/cmd_reloadmodule.cpp new file mode 100644 index 000000000..3e3a3a617 --- /dev/null +++ b/src/commands/cmd_reloadmodule.cpp @@ -0,0 +1,56 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +class CommandReloadmodule : public Command +{ + public: + /** Constructor for reloadmodule. + */ + CommandReloadmodule ( Module* parent) : Command( parent, "RELOADMODULE",1) { flags_needed = 'o'; syntax = "<modulename>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandReloadmodule::Handle (const std::vector<std::string>& parameters, User *user) +{ + if (parameters[0] == "cmd_reloadmodule.so") + { + user->WriteNumeric(975, "%s %s :You cannot reload cmd_reloadmodule.so (unload and load it)", + user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + + if (ServerInstance->Modules->Unload(parameters[0].c_str())) + { + ServerInstance->SNO->WriteToSnoMask('a', "RELOAD MODULE: %s unloaded %s",user->nick.c_str(), parameters[0].c_str()); + if (ServerInstance->Modules->Load(parameters[0].c_str())) + { + ServerInstance->SNO->WriteToSnoMask('a', "RELOAD MODULE: %s reloaded %s",user->nick.c_str(), parameters[0].c_str()); + user->WriteNumeric(975, "%s %s :Module successfully reloaded.",user->nick.c_str(), parameters[0].c_str()); + return CMD_SUCCESS; + } + } + + ServerInstance->SNO->WriteToSnoMask('a', "RELOAD MODULE: %s unsuccessfully reloaded %s",user->nick.c_str(), parameters[0].c_str()); + user->WriteNumeric(975, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str()); + return CMD_FAILURE; +} + +COMMAND_INIT(CommandReloadmodule) diff --git a/src/commands/cmd_restart.cpp b/src/commands/cmd_restart.cpp new file mode 100644 index 000000000..e83f3f381 --- /dev/null +++ b/src/commands/cmd_restart.cpp @@ -0,0 +1,60 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /RESTART + */ +class CommandRestart : public Command +{ + public: + /** Constructor for restart. + */ + CommandRestart(Module* parent) : Command(parent,"RESTART",1,1) { flags_needed = 'o'; syntax = "<password>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandRestart::Handle (const std::vector<std::string>& parameters, User *user) +{ + ServerInstance->Logs->Log("COMMAND",DEFAULT,"Restart: %s",user->nick.c_str()); + if (!ServerInstance->PassCompare(user, ServerInstance->Config->restartpass, parameters[0].c_str(), ServerInstance->Config->powerhash)) + { + ServerInstance->SNO->WriteGlobalSno('a', "RESTART command from %s!%s@%s, restarting server.", user->nick.c_str(), user->ident.c_str(), user->host.c_str()); + + try + { + ServerInstance->Restart("Server restarting."); + } + catch (...) + { + /* We dont actually get here unless theres some fatal and unrecoverable error. */ + exit(0); + } + } + else + { + ServerInstance->SNO->WriteGlobalSno('a', "Failed RESTART Command from %s!%s@%s.", user->nick.c_str(), user->ident.c_str(), user->host.c_str()); + return CMD_FAILURE; + } + + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandRestart) diff --git a/src/commands/cmd_rules.cpp b/src/commands/cmd_rules.cpp new file mode 100644 index 000000000..3cc5c15f4 --- /dev/null +++ b/src/commands/cmd_rules.cpp @@ -0,0 +1,56 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_RULES_H__ +#define __CMD_RULES_H__ + +// include the common header files + +#include <string> +#include <vector> +#include "inspircd.h" +#include "users.h" +#include "channels.h" + +/** Handle /RULES. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandRules : public Command +{ + public: + /** Constructor for rules. + */ + CommandRules ( Module* parent) : Command(parent,"RULES",0,0) { syntax = "[<servername>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +CmdResult CommandRules::Handle (const std::vector<std::string>& parameters, User *user) +{ + user->ShowRULES(); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandRules) diff --git a/src/commands/cmd_server.cpp b/src/commands/cmd_server.cpp new file mode 100644 index 000000000..e5a7622b8 --- /dev/null +++ b/src/commands/cmd_server.cpp @@ -0,0 +1,49 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /SERVER. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandServer : public Command +{ + public: + /** Constructor for server. + */ + CommandServer ( Module* parent) : Command(parent,"SERVER") { works_before_reg = true;} + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandServer::Handle (const std::vector<std::string>&, User *user) +{ + if (user->registered == REG_ALL) + { + user->WriteNumeric(ERR_ALREADYREGISTERED, "%s :You are already registered. (Perhaps your IRC client does not have a /SERVER command).",user->nick.c_str()); + } + else + { + user->WriteNumeric(ERR_NOTREGISTERED, "%s :You may not register as a server (servers have seperate ports from clients, change your config)",command.c_str()); + } + return CMD_FAILURE; +} + +COMMAND_INIT(CommandServer) diff --git a/src/commands/cmd_squit.cpp b/src/commands/cmd_squit.cpp new file mode 100644 index 000000000..f742dd964 --- /dev/null +++ b/src/commands/cmd_squit.cpp @@ -0,0 +1,48 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /SQUIT. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandSquit : public Command +{ + public: + /** Constructor for squit. + */ + CommandSquit ( Module* parent) : Command(parent,"SQUIT",1,2) { flags_needed = 'o'; syntax = "<servername> [<reason>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + + +/* + * This is handled by the server linking module, if necessary. Do not remove this stub. + */ + + +CmdResult CommandSquit::Handle (const std::vector<std::string>&, User *user) +{ + user->WriteServ( "NOTICE %s :Look into loading a linking module (like m_spanningtree) if you want this to do anything useful.", user->nick.c_str()); + return CMD_FAILURE; +} + +COMMAND_INIT(CommandSquit) diff --git a/src/commands/cmd_stats.cpp b/src/commands/cmd_stats.cpp new file mode 100644 index 000000000..7ffa4a93c --- /dev/null +++ b/src/commands/cmd_stats.cpp @@ -0,0 +1,68 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#ifndef WIN32 + #include <sys/resource.h> + /* This is just to be completely certain that the change which fixed getrusage on RH7 doesn't break anything else -- Om */ + #ifndef RUSAGE_SELF + #define RUSAGE_SELF 0 + #endif +#else + #include <psapi.h> + #include "inspircd_win32wrapper.h" + #pragma comment(lib, "psapi.lib") +#endif + +#include "xline.h" + +/** Handle /STATS. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandStats : public Command +{ + public: + /** Constructor for stats. + */ + CommandStats ( Module* parent) : Command(parent,"STATS",1,2) { syntax = "<stats-symbol> [<servername>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandStats::Handle (const std::vector<std::string>& parameters, User *user) +{ + if (IS_LOCAL(user)) + { + string_list values; + if (parameters[0].empty()) + { + user->WriteNumeric(ERR_NEEDMOREPARAMS, "%s STATS :Not enough parameters.", user->nick.c_str()); + return CMD_FAILURE; + } + char search = parameters[0][0]; + ServerInstance->DoStats(search, user, values); + for (size_t i = 0; i < values.size(); i++) + user->Write(":%s", values[i].c_str()); + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandStats) diff --git a/src/commands/cmd_time.cpp b/src/commands/cmd_time.cpp new file mode 100644 index 000000000..8ff588c2d --- /dev/null +++ b/src/commands/cmd_time.cpp @@ -0,0 +1,65 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_TIME_H__ +#define __CMD_TIME_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /TIME. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandTime : public Command +{ + public: + /** Constructor for time. + */ + CommandTime ( Module* parent) : Command(parent,"TIME",0,0) { syntax = "[<servername>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + + + +CmdResult CommandTime::Handle (const std::vector<std::string>&, User *user) +{ + struct tm* timeinfo; + time_t local = ServerInstance->Time(); + + timeinfo = localtime(&local); + + char tms[26]; + snprintf(tms,26,"%s",asctime(timeinfo)); + tms[24] = 0; + + user->WriteNumeric(RPL_TIME, "%s %s :%s",user->nick.c_str(),ServerInstance->Config->ServerName,tms); + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandTime) diff --git a/src/commands/cmd_topic.cpp b/src/commands/cmd_topic.cpp new file mode 100644 index 000000000..e0fa79d1c --- /dev/null +++ b/src/commands/cmd_topic.cpp @@ -0,0 +1,79 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /TOPIC. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandTopic : public Command +{ + public: + /** Constructor for topic. + */ + CommandTopic ( Module* parent) : Command(parent,"TOPIC",1, 2) { syntax = "<channel> [<topic>]"; Penalty = 2; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandTopic::Handle (const std::vector<std::string>& parameters, User *user) +{ + Channel* c; + + c = ServerInstance->FindChan(parameters[0]); + if (!c) + { + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + + if (parameters.size() == 1) + { + if (c) + { + if ((c->IsModeSet('s')) && (!c->HasUser(user))) + { + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), c->name.c_str()); + return CMD_FAILURE; + } + + if (c->topic.length()) + { + user->WriteNumeric(332, "%s %s :%s", user->nick.c_str(), c->name.c_str(), c->topic.c_str()); + user->WriteNumeric(333, "%s %s %s %lu", user->nick.c_str(), c->name.c_str(), c->setby.c_str(), (unsigned long)c->topicset); + } + else + { + user->WriteNumeric(RPL_NOTOPICSET, "%s %s :No topic is set.", user->nick.c_str(), c->name.c_str()); + } + } + return CMD_SUCCESS; + } + else if (parameters.size()>1) + { + std::string t = parameters[1]; // needed, in case a module wants to change it + c->SetTopic(user, t); + } + + return CMD_SUCCESS; +} + + +COMMAND_INIT(CommandTopic) diff --git a/src/commands/cmd_unloadmodule.cpp b/src/commands/cmd_unloadmodule.cpp new file mode 100644 index 000000000..bdc516aac --- /dev/null +++ b/src/commands/cmd_unloadmodule.cpp @@ -0,0 +1,58 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /UNLOADMODULE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandUnloadmodule : public Command +{ + public: + /** Constructor for unloadmodule. + */ + CommandUnloadmodule ( Module* parent) : Command(parent,"UNLOADMODULE",1) { flags_needed = 'o'; syntax = "<modulename>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandUnloadmodule::Handle (const std::vector<std::string>& parameters, User *user) +{ + if (parameters[0] == "cmd_unloadmodule.so" || parameters[0] == "cmd_loadmodule.so") + { + user->WriteNumeric(972, "%s %s :You cannot unload module loading commands!", user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } + + if (ServerInstance->Modules->Unload(parameters[0].c_str())) + { + ServerInstance->SNO->WriteToSnoMask('a', "MODULE UNLOADED: %s unloaded %s", user->nick.c_str(), parameters[0].c_str()); + user->WriteNumeric(973, "%s %s :Module successfully unloaded.",user->nick.c_str(), parameters[0].c_str()); + } + else + { + user->WriteNumeric(972, "%s %s :%s",user->nick.c_str(), parameters[0].c_str(), ServerInstance->Modules->LastError().c_str()); + return CMD_FAILURE; + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandUnloadmodule) diff --git a/src/commands/cmd_user.cpp b/src/commands/cmd_user.cpp new file mode 100644 index 000000000..e2f81f33c --- /dev/null +++ b/src/commands/cmd_user.cpp @@ -0,0 +1,83 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /USER. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandUser : public Command +{ + public: + /** Constructor for user. + */ + CommandUser ( Module* parent) : Command(parent,"USER",4,4) { works_before_reg = true; Penalty = 0; syntax = "<username> <localhost> <remotehost> <GECOS>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandUser::Handle (const std::vector<std::string>& parameters, User *user) +{ + /* A user may only send the USER command once */ + if (!(user->registered & REG_USER)) + { + if (!ServerInstance->IsIdent(parameters[0].c_str())) + { + /* + * RFC says we must use this numeric, so we do. Let's make it a little more nub friendly though. :) + * -- Craig, and then w00t. + */ + user->WriteNumeric(461, "%s USER :Your username is not valid",user->nick.c_str()); + return CMD_FAILURE; + } + else + { + /* + * The ident field is IDENTMAX+2 in size to account for +1 for the optional + * ~ character, and +1 for null termination, therefore we can safely use up to + * IDENTMAX here. + */ + user->ChangeIdent(parameters[0].c_str()); + user->fullname.assign(parameters[3].empty() ? std::string("No info") : parameters[3], 0, ServerInstance->Config->Limits.MaxGecos); + user->registered = (user->registered | REG_USER); + } + } + else + { + user->WriteNumeric(462, "%s :You may not reregister", user->nick.c_str()); + return CMD_FAILURE; + } + + /* parameters 2 and 3 are local and remote hosts, and are ignored */ + if (user->registered == REG_NICKUSER) + { + ModResult MOD_RESULT; + + /* user is registered now, bit 0 = USER command, bit 1 = sent a NICK command */ + FIRST_MOD_RESULT(ServerInstance, OnUserRegister, MOD_RESULT, (user)); + if (MOD_RESULT == MOD_RES_DENY) + return CMD_FAILURE; + + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandUser) diff --git a/src/commands/cmd_userhost.cpp b/src/commands/cmd_userhost.cpp new file mode 100644 index 000000000..2833d56ba --- /dev/null +++ b/src/commands/cmd_userhost.cpp @@ -0,0 +1,93 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_USERHOST_H__ +#define __CMD_USERHOST_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /USERHOST. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandUserhost : public Command +{ + public: + /** Constructor for userhost. + */ + CommandUserhost ( Module* parent) : Command(parent,"USERHOST",0,1) { syntax = "<nick>{,<nick>}"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + +CmdResult CommandUserhost::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::string retbuf = std::string("302 ") + user->nick + " :"; + + for (unsigned int i = 0; i < parameters.size(); i++) + { + User *u = ServerInstance->FindNick(parameters[i]); + + if ((u) && (u->registered == REG_ALL)) + { + retbuf = retbuf + u->nick; + + if (IS_OPER(u)) + { + retbuf = retbuf + "*="; + } + else + { + retbuf = retbuf + "="; + } + + if (IS_AWAY(u)) + retbuf += "-"; + else + retbuf += "+"; + + retbuf = retbuf + u->ident + "@"; + + if (user->HasPrivPermission("users/auspex")) + { + retbuf = retbuf + u->host; + } + else + { + retbuf = retbuf + u->dhost; + } + + retbuf = retbuf + " "; + } + } + + user->WriteServ(retbuf); + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandUserhost) diff --git a/src/commands/cmd_version.cpp b/src/commands/cmd_version.cpp new file mode 100644 index 000000000..bfe82d4d9 --- /dev/null +++ b/src/commands/cmd_version.cpp @@ -0,0 +1,56 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_VERSION_H__ +#define __CMD_VERSION_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /VERSION. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandVersion : public Command +{ + public: + /** Constructor for version. + */ + CommandVersion ( Module* parent) : Command(parent,"VERSION",0,0) { syntax = "[<servername>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + + + +CmdResult CommandVersion::Handle (const std::vector<std::string>&, User *user) +{ + user->WriteNumeric(RPL_VERSION, "%s :%s",user->nick.c_str(),ServerInstance->GetVersionString().c_str()); + ServerInstance->Config->Send005(user); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandVersion) diff --git a/src/commands/cmd_wallops.cpp b/src/commands/cmd_wallops.cpp new file mode 100644 index 000000000..7894419c1 --- /dev/null +++ b/src/commands/cmd_wallops.cpp @@ -0,0 +1,56 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +#ifndef __CMD_WALLOPS_H__ +#define __CMD_WALLOPS_H__ + +// include the common header files + +#include "users.h" +#include "channels.h" + +/** Handle /WALLOPS. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandWallops : public Command +{ + public: + /** Constructor for wallops. + */ + CommandWallops ( Module* parent) : Command(parent,"WALLOPS",1,1) { flags_needed = 'o'; syntax = "<any-text>"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +#endif + + + + +CmdResult CommandWallops::Handle (const std::vector<std::string>& parameters, User *user) +{ + user->WriteWallOps(std::string(parameters[0])); + FOREACH_MOD(I_OnWallops,OnWallops(user,parameters[0])); + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandWallops) diff --git a/src/commands/cmd_who.cpp b/src/commands/cmd_who.cpp new file mode 100644 index 000000000..89ca60d02 --- /dev/null +++ b/src/commands/cmd_who.cpp @@ -0,0 +1,403 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /WHO. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandWho : public Command +{ + bool CanView(Channel* chan, User* user); + bool opt_viewopersonly; + bool opt_showrealhost; + bool opt_unlimit; + bool opt_realname; + bool opt_mode; + bool opt_ident; + bool opt_metadata; + bool opt_port; + bool opt_away; + bool opt_local; + bool opt_far; + bool opt_time; + + public: + /** Constructor for who. + */ + CommandWho ( Module* parent) : Command(parent,"WHO", 1) { Penalty = 2; syntax = "<server>|<nickname>|<channel>|<realname>|<host>|0 [ohurmMiaplf]"; } + void SendWhoLine(User* user, const std::string &initial, Channel* ch, User* u, std::vector<std::string> &whoresults); + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); + bool whomatch(User* cuser, User* user, const char* matchtext); +}; + + +static const std::string star = "*"; + +static const std::string& get_first_visible_channel(User *u) +{ + UCListIter i = u->chans.begin(); + while (i != u->chans.end()) + { + Channel* c = *i++; + if (!c->IsModeSet('s')) + return c->name; + } + + return star; +} + +bool CommandWho::whomatch(User* cuser, User* user, const char* matchtext) +{ + bool match = false; + bool positive = false; + + if (user->registered != REG_ALL) + return false; + + if (opt_local && !IS_LOCAL(user)) + return false; + else if (opt_far && IS_LOCAL(user)) + return false; + + if (opt_mode) + { + for (const char* n = matchtext; *n; n++) + { + if (*n == '+') + { + positive = true; + continue; + } + else if (*n == '-') + { + positive = false; + continue; + } + if (user->IsModeSet(*n) != positive) + return false; + } + return true; + } + else + { + /* + * This was previously one awesome pile of ugly nested if, when really, it didn't need + * to be, since only one condition was ever checked, a chained if works just fine. + * -- w00t + */ + if (opt_metadata) + match = user->GetExtList().find(matchtext) != user->GetExtList().end(); + else if (opt_realname) + match = InspIRCd::Match(user->fullname, matchtext); + else if (opt_showrealhost) + match = InspIRCd::Match(user->host, matchtext, ascii_case_insensitive_map); + else if (opt_ident) + match = InspIRCd::Match(user->ident, matchtext, ascii_case_insensitive_map); + else if (opt_port) + { + irc::portparser portrange(matchtext, false); + long portno = -1; + while ((portno = portrange.GetToken())) + if (portno == user->GetServerPort()) + { + match = true; + break; + } + } + else if (opt_away) + match = InspIRCd::Match(user->awaymsg, matchtext); + else if (opt_time) + { + long seconds = ServerInstance->Duration(matchtext); + + // Okay, so time matching, we want all users connected `seconds' ago + if (user->age >= ServerInstance->Time() - seconds) + match = true; + } + + /* + * Once the conditionals have been checked, only check dhost/nick/server + * if they didn't match this user -- and only match if we don't find a match. + * + * This should make things minutely faster, and again, less ugly. + * -- w00t + */ + if (!match) + match = InspIRCd::Match(user->dhost, matchtext, ascii_case_insensitive_map); + + if (!match) + match = InspIRCd::Match(user->nick, matchtext); + + /* Don't allow server name matches if HideWhoisServer is enabled, unless the command user has the priv */ + if (!match && (!*ServerInstance->Config->HideWhoisServer || cuser->HasPrivPermission("users/auspex"))) + match = InspIRCd::Match(user->server, matchtext); + + return match; + } +} + + + +bool CommandWho::CanView(Channel* chan, User* user) +{ + if (!user || !chan) + return false; + + /* Bug #383 - moved higher up the list, because if we are in the channel + * we can see all its users + */ + if (chan->HasUser(user)) + return true; + /* Opers see all */ + if (user->HasPrivPermission("users/auspex")) + return true; + /* Cant see inside a +s or a +p channel unless we are a member (see above) */ + else if (!chan->IsModeSet('s') && !chan->IsModeSet('p')) + return true; + + return false; +} + +void CommandWho::SendWhoLine(User* user, const std::string &initial, Channel* ch, User* u, std::vector<std::string> &whoresults) +{ + const std::string& lcn = get_first_visible_channel(u); + Channel* chlast = ServerInstance->FindChan(lcn); + + std::string wholine = initial + (ch ? ch->name : lcn) + " " + u->ident + " " + (opt_showrealhost ? u->host : u->dhost) + " " + + ((*ServerInstance->Config->HideWhoisServer && !user->HasPrivPermission("servers/auspex")) ? ServerInstance->Config->HideWhoisServer : u->server) + + " " + u->nick + " "; + + /* away? */ + if (IS_AWAY(u)) + { + wholine.append("G"); + } + else + { + wholine.append("H"); + } + + /* oper? */ + if (IS_OPER(u)) + { + wholine.append("*"); + } + + wholine = wholine + (ch ? ch->GetPrefixChar(u) : (chlast ? chlast->GetPrefixChar(u) : "")) + " :0 " + u->fullname; + + FOREACH_MOD(I_OnSendWhoLine, OnSendWhoLine(user, u, ch, wholine)); + + if (!wholine.empty()) + whoresults.push_back(wholine); +} + +CmdResult CommandWho::Handle (const std::vector<std::string>& parameters, User *user) +{ + /* + * XXX - RFC says: + * The <name> passed to WHO is matched against users' host, server, real + * name and nickname + * Currently, we support WHO #chan, WHO nick, WHO 0, WHO *, and the addition of a 'o' flag, as per RFC. + */ + + /* WHO options */ + opt_viewopersonly = false; + opt_showrealhost = false; + opt_unlimit = false; + opt_realname = false; + opt_mode = false; + opt_ident = false; + opt_metadata = false; + opt_port = false; + opt_away = false; + opt_local = false; + opt_far = false; + opt_time = false; + + Channel *ch = NULL; + std::vector<std::string> whoresults; + std::string initial = "352 " + std::string(user->nick) + " "; + + char matchtext[MAXBUF]; + bool usingwildcards = false; + + /* Change '0' into '*' so the wildcard matcher can grok it */ + if (parameters[0] == "0") + strlcpy(matchtext, "*", MAXBUF); + else + strlcpy(matchtext, parameters[0].c_str(), MAXBUF); + + for (const char* check = matchtext; *check; check++) + { + if (*check == '*' || *check == '?') + { + usingwildcards = true; + break; + } + } + + if (ServerInstance->FindServerName(matchtext)) + usingwildcards = true; + + if (parameters.size() > 1) + { + /* Fix for bug #444, WHO flags count as a wildcard */ + usingwildcards = true; + + for (std::string::const_iterator iter = parameters[1].begin(); iter != parameters[1].end(); ++iter) + { + switch (*iter) + { + case 'o': + opt_viewopersonly = true; + break; + case 'h': + if (user->HasPrivPermission("users/auspex")) + opt_showrealhost = true; + break; + case 'u': + if (user->HasPrivPermission("users/auspex")) + opt_unlimit = true; + break; + case 'r': + opt_realname = true; + break; + case 'm': + if (user->HasPrivPermission("users/auspex")) + opt_mode = true; + break; + case 'M': + if (user->HasPrivPermission("users/auspex")) + opt_metadata = true; + break; + case 'i': + opt_ident = true; + break; + case 'p': + if (user->HasPrivPermission("users/auspex")) + opt_port = true; + break; + case 'a': + opt_away = true; + break; + case 'l': + if (user->HasPrivPermission("users/auspex") || !*ServerInstance->Config->HideWhoisServer) + opt_local = true; + break; + case 'f': + if (user->HasPrivPermission("users/auspex") || !*ServerInstance->Config->HideWhoisServer) + opt_far = true; + break; + case 't': + opt_time = true; + break; + } + } + } + + + /* who on a channel? */ + ch = ServerInstance->FindChan(matchtext); + + if (ch) + { + if (CanView(ch,user)) + { + bool inside = ch->HasUser(user); + + /* who on a channel. */ + const UserMembList *cu = ch->GetUsers(); + + for (UserMembCIter i = cu->begin(); i != cu->end(); i++) + { + /* None of this applies if we WHO ourselves */ + if (user != i->first) + { + /* opers only, please */ + if (opt_viewopersonly && !IS_OPER(i->first)) + continue; + + /* If we're not inside the channel, hide +i users */ + if (i->first->IsModeSet('i') && !inside && !user->HasPrivPermission("users/auspex")) + continue; + } + + SendWhoLine(user, initial, ch, i->first, whoresults); + } + } + } + else + { + /* Match against wildcard of nick, server or host */ + if (opt_viewopersonly) + { + /* Showing only opers */ + for (std::list<User*>::iterator i = ServerInstance->Users->all_opers.begin(); i != ServerInstance->Users->all_opers.end(); i++) + { + User* oper = *i; + + if (whomatch(user, oper, matchtext)) + { + if (!user->SharesChannelWith(oper)) + { + if (usingwildcards && (!oper->IsModeSet('i')) && (!user->HasPrivPermission("users/auspex"))) + continue; + } + + SendWhoLine(user, initial, NULL, oper, whoresults); + } + } + } + else + { + for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); i++) + { + if (whomatch(user, i->second, matchtext)) + { + if (!user->SharesChannelWith(i->second)) + { + if (usingwildcards && (i->second->IsModeSet('i')) && (!user->HasPrivPermission("users/auspex"))) + continue; + } + + SendWhoLine(user, initial, NULL, i->second, whoresults); + } + } + } + } + /* Send the results out */ + if ((ServerInstance->Config->MaxWhoResults && (whoresults.size() <= (size_t)ServerInstance->Config->MaxWhoResults)) || opt_unlimit) + { + for (std::vector<std::string>::const_iterator n = whoresults.begin(); n != whoresults.end(); n++) + user->WriteServ(*n); + user->WriteNumeric(315, "%s %s :End of /WHO list.",user->nick.c_str(), *parameters[0].c_str() ? parameters[0].c_str() : "*"); + return CMD_SUCCESS; + } + else + { + /* BZZT! Too many results. */ + user->WriteNumeric(315, "%s %s :Too many results",user->nick.c_str(), parameters[0].c_str()); + return CMD_FAILURE; + } +} + +COMMAND_INIT(CommandWho) diff --git a/src/commands/cmd_whois.cpp b/src/commands/cmd_whois.cpp new file mode 100644 index 000000000..972b0439e --- /dev/null +++ b/src/commands/cmd_whois.cpp @@ -0,0 +1,90 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" + +/** Handle /WHOIS. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandWhois : public Command +{ + public: + /** Constructor for whois. + */ + CommandWhois ( Module* parent) : Command(parent,"WHOIS",1) { Penalty = 2; syntax = "<nick>{,<nick>}"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + + +CmdResult CommandWhois::Handle (const std::vector<std::string>& parameters, User *user) +{ + User *dest; + int userindex = 0; + unsigned long idle = 0, signon = 0; + + if (ServerInstance->Parser->LoopCall(user, this, parameters, 0)) + return CMD_SUCCESS; + + + /* + * If 2 paramters are specified (/whois nick nick), ignore the first one like spanningtree + * does, and use the second one, otherwise, use the only paramter. -- djGrrr + */ + if (parameters.size() > 1) + userindex = 1; + + if (IS_LOCAL(user)) + dest = ServerInstance->FindNickOnly(parameters[userindex]); + else + dest = ServerInstance->FindNick(parameters[userindex]); + + if (dest) + { + /* + * Okay. Umpteenth attempt at doing this, so let's re-comment... + * For local users (/w localuser), we show idletime if hidewhois is disabled + * For local users (/w localuser localuser), we always show idletime, hence parameters.size() > 1 check. + * For remote users (/w remoteuser), we do NOT show idletime + * For remote users (/w remoteuser remoteuser), spanningtree will handle calling do_whois, so we can ignore this case. + * Thanks to djGrrr for not being impatient while I have a crap day coding. :p -- w00t + */ + if (IS_LOCAL(dest) && (!*ServerInstance->Config->HideWhoisServer || parameters.size() > 1)) + { + idle = abs((long)((dest->idle_lastmsg)-ServerInstance->Time())); + signon = dest->signon; + } + + ServerInstance->DoWhois(user,dest,signon,idle,parameters[userindex].c_str()); + } + else + { + /* no such nick/channel */ + user->WriteNumeric(401, "%s %s :No such nick/channel",user->nick.c_str(), !parameters[userindex].empty() ? parameters[userindex].c_str() : "*"); + user->WriteNumeric(318, "%s %s :End of /WHOIS list.",user->nick.c_str(), parameters[userindex].empty() ? parameters[userindex].c_str() : "*"); + return CMD_FAILURE; + } + + return CMD_SUCCESS; +} + + + +COMMAND_INIT(CommandWhois) diff --git a/src/commands/cmd_whowas.cpp b/src/commands/cmd_whowas.cpp new file mode 100644 index 000000000..78a7e7544 --- /dev/null +++ b/src/commands/cmd_whowas.cpp @@ -0,0 +1,344 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "commands/cmd_whowas.h" + +WhoWasMaintainTimer * timer; + +CommandWhowas::CommandWhowas( Module* parent) : Command(parent, "WHOWAS", 1) +{ + syntax = "<nick>{,<nick>}"; + Penalty = 2; + timer = new WhoWasMaintainTimer(ServerInstance, 3600); + ServerInstance->Timers->AddTimer(timer); +} + +CmdResult CommandWhowas::Handle (const std::vector<std::string>& parameters, User* user) +{ + /* if whowas disabled in config */ + if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0) + { + user->WriteNumeric(421, "%s %s :This command has been disabled.",user->nick.c_str(),command.c_str()); + return CMD_FAILURE; + } + + whowas_users::iterator i = whowas.find(assign(parameters[0])); + + if (i == whowas.end()) + { + user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str()); + user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str()); + return CMD_FAILURE; + } + else + { + whowas_set* grp = i->second; + if (grp->size()) + { + for (whowas_set::iterator ux = grp->begin(); ux != grp->end(); ux++) + { + WhoWasGroup* u = *ux; + time_t rawtime = u->signon; + tm *timeinfo; + char b[25]; + + timeinfo = localtime(&rawtime); + + strncpy(b,asctime(timeinfo),24); + b[24] = 0; + + user->WriteNumeric(314, "%s %s %s %s * :%s",user->nick.c_str(),parameters[0].c_str(), + u->ident.c_str(),u->dhost.c_str(),u->gecos.c_str()); + + if (user->HasPrivPermission("users/auspex")) + user->WriteNumeric(379, "%s %s :was connecting from *@%s", + user->nick.c_str(), parameters[0].c_str(), u->host.c_str()); + + if (*ServerInstance->Config->HideWhoisServer && !user->HasPrivPermission("servers/auspex")) + user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), ServerInstance->Config->HideWhoisServer, b); + else + user->WriteNumeric(312, "%s %s %s :%s",user->nick.c_str(),parameters[0].c_str(), u->server, b); + } + } + else + { + user->WriteNumeric(406, "%s %s :There was no such nickname",user->nick.c_str(),parameters[0].c_str()); + user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str()); + return CMD_FAILURE; + } + } + + user->WriteNumeric(369, "%s %s :End of WHOWAS",user->nick.c_str(),parameters[0].c_str()); + return CMD_SUCCESS; +} + +std::string CommandWhowas::GetStats() +{ + int whowas_size = 0; + int whowas_bytes = 0; + whowas_users_fifo::iterator iter; + for (iter = whowas_fifo.begin(); iter != whowas_fifo.end(); iter++) + { + whowas_set* n = (whowas_set*)whowas.find(iter->second)->second; + if (n->size()) + { + whowas_size += n->size(); + whowas_bytes += (sizeof(whowas_set) + ( sizeof(WhoWasGroup) * n->size() ) ); + } + } + stats.assign("Whowas(MAPSETS) " +ConvToStr(whowas_size)+" ("+ConvToStr(whowas_bytes)+" bytes)"); + return stats; +} + +void CommandWhowas::AddToWhoWas(User* user) +{ + /* if whowas disabled */ + if (ServerInstance->Config->WhoWasGroupSize == 0 || ServerInstance->Config->WhoWasMaxGroups == 0) + { + return; + } + + whowas_users::iterator iter = whowas.find(irc::string(user->nick.c_str())); + + if (iter == whowas.end()) + { + whowas_set* n = new whowas_set; + WhoWasGroup *a = new WhoWasGroup(user); + n->push_back(a); + whowas[user->nick.c_str()] = n; + whowas_fifo.push_back(std::make_pair(ServerInstance->Time(),user->nick.c_str())); + + if ((int)(whowas.size()) > ServerInstance->Config->WhoWasMaxGroups) + { + whowas_users::iterator iter2 = whowas.find(whowas_fifo[0].second); + if (iter2 != whowas.end()) + { + whowas_set* n2 = (whowas_set*)iter2->second; + + if (n2->size()) + { + while (n2->begin() != n2->end()) + { + WhoWasGroup *a2 = *(n2->begin()); + delete a2; + n2->pop_front(); + } + } + + delete n2; + whowas.erase(iter2); + } + whowas_fifo.pop_front(); + } + } + else + { + whowas_set* group = (whowas_set*)iter->second; + WhoWasGroup *a = new WhoWasGroup(user); + group->push_back(a); + + if ((int)(group->size()) > ServerInstance->Config->WhoWasGroupSize) + { + WhoWasGroup *a2 = (WhoWasGroup*)*(group->begin()); + delete a2; + group->pop_front(); + } + } +} + +/* on rehash, refactor maps according to new conf values */ +void CommandWhowas::PruneWhoWas(time_t t) +{ + /* config values */ + int groupsize = ServerInstance->Config->WhoWasGroupSize; + int maxgroups = ServerInstance->Config->WhoWasMaxGroups; + int maxkeep = ServerInstance->Config->WhoWasMaxKeep; + + /* first cut the list to new size (maxgroups) and also prune entries that are timed out. */ + whowas_users::iterator iter; + int fifosize; + while ((fifosize = (int)whowas_fifo.size()) > 0) + { + if (fifosize > maxgroups || whowas_fifo[0].first < t - maxkeep) + { + iter = whowas.find(whowas_fifo[0].second); + + /* hopefully redundant integrity check, but added while debugging r6216 */ + if (iter == whowas.end()) + { + /* this should never happen, if it does maps are corrupt */ + ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (1)"); + return; + } + + whowas_set* n = (whowas_set*)iter->second; + + if (n->size()) + { + while (n->begin() != n->end()) + { + WhoWasGroup *a = *(n->begin()); + delete a; + n->pop_front(); + } + } + + delete n; + whowas.erase(iter); + whowas_fifo.pop_front(); + } + else + break; + } + + /* Then cut the whowas sets to new size (groupsize) */ + fifosize = (int)whowas_fifo.size(); + for (int i = 0; i < fifosize; i++) + { + iter = whowas.find(whowas_fifo[0].second); + /* hopefully redundant integrity check, but added while debugging r6216 */ + if (iter == whowas.end()) + { + /* this should never happen, if it does maps are corrupt */ + ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (2)"); + return; + } + whowas_set* n = (whowas_set*)iter->second; + if (n->size()) + { + int nickcount = n->size(); + while (n->begin() != n->end() && nickcount > groupsize) + { + WhoWasGroup *a = *(n->begin()); + delete a; + n->pop_front(); + nickcount--; + } + } + } +} + +/* call maintain once an hour to remove expired nicks */ +void CommandWhowas::MaintainWhoWas(time_t t) +{ + for (whowas_users::iterator iter = whowas.begin(); iter != whowas.end(); iter++) + { + whowas_set* n = (whowas_set*)iter->second; + if (n->size()) + { + while ((n->begin() != n->end()) && ((*n->begin())->signon < t - ServerInstance->Config->WhoWasMaxKeep)) + { + WhoWasGroup *a = *(n->begin()); + delete a; + n->erase(n->begin()); + } + } + } +} + +CommandWhowas::~CommandWhowas() +{ + if (timer) + { + ServerInstance->Timers->DelTimer(timer); + } + + whowas_users::iterator iter; + int fifosize; + while ((fifosize = (int)whowas_fifo.size()) > 0) + { + iter = whowas.find(whowas_fifo[0].second); + + /* hopefully redundant integrity check, but added while debugging r6216 */ + if (iter == whowas.end()) + { + /* this should never happen, if it does maps are corrupt */ + ServerInstance->Logs->Log("WHOWAS",DEFAULT, "BUG: Whowas maps got corrupted! (3)"); + return; + } + + whowas_set* n = (whowas_set*)iter->second; + + if (n->size()) + { + while (n->begin() != n->end()) + { + WhoWasGroup *a = *(n->begin()); + delete a; + n->pop_front(); + } + } + + delete n; + whowas.erase(iter); + whowas_fifo.pop_front(); + } +} + +WhoWasGroup::WhoWasGroup(User* user) : host(user->host), dhost(user->dhost), ident(user->ident), + server(user->server), gecos(user->fullname), signon(user->signon) +{ +} + +WhoWasGroup::~WhoWasGroup() +{ +} + +/* every hour, run this function which removes all entries older than Config->WhoWasMaxKeep */ +void WhoWasMaintainTimer::Tick(time_t) +{ + Module* whowas = ServerInstance->Modules->Find("cmd_whowas.so"); + if (whowas) + { + WhowasRequest(whowas, whowas, WhowasRequest::WHOWAS_MAINTAIN).Send(); + } +} + +class ModuleWhoWas : public Module +{ + CommandWhowas cmd; + public: + ModuleWhoWas(InspIRCd *Me) : Module(Me), cmd(this) + { + ServerInstance->AddCommand(&cmd); + } + + const char* OnRequest(Request* request) + { + WhowasRequest* req = static_cast<WhowasRequest*>(request); + switch (req->type) + { + case WhowasRequest::WHOWAS_ADD: + cmd.AddToWhoWas(req->user); + break; + case WhowasRequest::WHOWAS_STATS: + req->value = cmd.GetStats(); + break; + case WhowasRequest::WHOWAS_PRUNE: + cmd.PruneWhoWas(ServerInstance->Time()); + break; + case WhowasRequest::WHOWAS_MAINTAIN: + cmd.MaintainWhoWas(ServerInstance->Time()); + break; + } + return NULL; + } + + Version GetVersion() + { + return Version("WHOWAS Command", VF_VENDOR); + } +}; + +MODULE_INIT(ModuleWhoWas) diff --git a/src/commands/cmd_zline.cpp b/src/commands/cmd_zline.cpp new file mode 100644 index 000000000..e2cca7649 --- /dev/null +++ b/src/commands/cmd_zline.cpp @@ -0,0 +1,106 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "xline.h" +/** Handle /ZLINE. These command handlers can be reloaded by the core, + * and handle basic RFC1459 commands. Commands within modules work + * the same way, however, they can be fully unloaded, where these + * may not. + */ +class CommandZline : public Command +{ + public: + /** Constructor for zline. + */ + CommandZline ( Module* parent) : Command(parent,"ZLINE",1,3) { flags_needed = 'o'; Penalty = 0; syntax = "<ipmask> [<duration> :<reason>]"; } + /** Handle command. + * @param parameters The parameters to the comamnd + * @param pcnt The number of parameters passed to teh 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); +}; + +CmdResult CommandZline::Handle (const std::vector<std::string>& parameters, User *user) +{ + std::string target = parameters[0]; + + if (parameters.size() >= 3) + { + if (target.find('!') != std::string::npos) + { + user->WriteServ("NOTICE %s :*** You cannot include a nickname in a zline, a zline must ban only an IP mask",user->nick.c_str()); + return CMD_FAILURE; + } + + User *u = ServerInstance->FindNick(target.c_str()); + + if (u) + { + target = u->GetIPString(); + } + + const char* ipaddr = target.c_str(); + + if (strchr(ipaddr,'@')) + { + while (*ipaddr != '@') + ipaddr++; + ipaddr++; + } + + if (ServerInstance->IPMatchesEveryone(ipaddr,user)) + return CMD_FAILURE; + + long duration = ServerInstance->Duration(parameters[1].c_str()); + + ZLine* zl = new ZLine(ServerInstance, ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), ipaddr); + if (ServerInstance->XLines->AddLine(zl,user)) + { + if (!duration) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent Z-line for %s: %s", user->nick.c_str(), ipaddr, parameters[2].c_str()); + } + else + { + time_t c_requires_crap = duration + ServerInstance->Time(); + ServerInstance->SNO->WriteToSnoMask('x',"%s added timed Z-line for %s, expires on %s: %s",user->nick.c_str(),ipaddr, + ServerInstance->TimeString(c_requires_crap).c_str(), parameters[2].c_str()); + } + ServerInstance->XLines->ApplyLines(); + } + else + { + delete zl; + user->WriteServ("NOTICE %s :*** Z-Line for %s already exists",user->nick.c_str(),ipaddr); + } + } + else + { + if (ServerInstance->XLines->DelLine(target.c_str(),"Z",user)) + { + ServerInstance->SNO->WriteToSnoMask('x',"%s removed Z-line on %s",user->nick.c_str(),target.c_str()); + } + else + { + user->WriteServ("NOTICE %s :*** Z-Line %s not found in list, try /stats Z.",user->nick.c_str(),target.c_str()); + return CMD_FAILURE; + } + } + + return CMD_SUCCESS; +} + +COMMAND_INIT(CommandZline) |