]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/commands/cmd_kill.cpp
This fixes issue #39 reported by @attilamolnar.
[user/henk/code/inspircd.git] / src / commands / cmd_kill.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15
16 /** Handle /KILL. These command handlers can be reloaded by the core,
17  * and handle basic RFC1459 commands. Commands within modules work
18  * the same way, however, they can be fully unloaded, where these
19  * may not.
20  */
21 class CommandKill : public Command
22 {
23  public:
24         /** Constructor for kill.
25          */
26         CommandKill ( Module* parent) : Command(parent,"KILL",2,2) {
27                 flags_needed = 'o';
28                 syntax = "<nickname> <reason>";
29                 TRANSLATE3(TR_NICK, TR_TEXT, TR_END);
30         }
31         /** Handle command.
32          * @param parameters The parameters to the comamnd
33          * @param pcnt The number of parameters passed to teh command
34          * @param user The user issuing the command
35          * @return A value from CmdResult to indicate command success or failure.
36          */
37         CmdResult Handle(const std::vector<std::string>& parameters, User *user);
38         RouteDescriptor GetRouting(User* user, const std::vector<std::string>& parameters)
39         {
40                 // local kills of remote users are routed via the OnRemoteKill hook
41                 if (IS_LOCAL(user))
42                         return ROUTE_LOCALONLY;
43                 return ROUTE_BROADCAST;
44         }
45 };
46
47 /** Handle /KILL
48  */
49 CmdResult CommandKill::Handle (const std::vector<std::string>& parameters, User *user)
50 {
51         /* Allow comma seperated lists of users for /KILL (thanks w00t) */
52         if (ServerInstance->Parser->LoopCall(user, this, parameters, 0))
53                 return CMD_SUCCESS;
54
55         User *u = ServerInstance->FindNick(parameters[0]);
56         char killreason[MAXBUF];
57         ModResult MOD_RESULT;
58
59         if (u)
60         {
61                 /*
62                  * Here, we need to decide how to munge kill messages. Whether to hide killer, what to show opers, etc.
63                  * We only do this when the command is being issued LOCALLY, for remote KILL, we just copy the message we got.
64                  *
65                  * This conditional is so that we only append the "Killed (" prefix ONCE. If killer is remote, then the kill
66                  * just gets processed and passed on, otherwise, if they are local, it gets prefixed. Makes sense :-) -- w00t
67                  */
68                 if (IS_LOCAL(user))
69                 {
70                         /*
71                          * Moved this event inside the IS_LOCAL check also, we don't want half the network killing a user
72                          * and the other half not. This would be a bad thing. ;p -- w00t
73                          */
74                         FIRST_MOD_RESULT(OnKill, MOD_RESULT, (user, u, parameters[1]));
75
76                         if (MOD_RESULT == MOD_RES_DENY)
77                                 return CMD_FAILURE;
78
79                         if (!ServerInstance->Config->HideKillsServer.empty())
80                         {
81                                 // hidekills is on, use it
82                                 snprintf(killreason, ServerInstance->Config->Limits.MaxQuit, "Killed (%s (%s))", ServerInstance->Config->HideKillsServer.c_str(), parameters[1].c_str());
83                         }
84                         else
85                         {
86                                 // hidekills is off, do nothing
87                                 snprintf(killreason, ServerInstance->Config->Limits.MaxQuit, "Killed (%s (%s))", user->nick.c_str(), parameters[1].c_str());
88                         }
89                 }
90                 else
91                 {
92                         /* Leave it alone, remote server has already formatted it */
93                         strlcpy(killreason, parameters[1].c_str(), ServerInstance->Config->Limits.MaxQuit);
94                 }
95
96                 /*
97                  * Now we need to decide whether or not to send a local or remote snotice. Currently this checking is a little flawed.
98                  * No time to fix it right now, so left a note. -- w00t
99                  */
100                 if (!IS_LOCAL(u))
101                 {
102                         // remote kill
103                         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());
104                         FOREACH_MOD(I_OnRemoteKill, OnRemoteKill(user, u, killreason, killreason));
105                 }
106                 else
107                 {
108                         // local kill
109                         /*
110                          * 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
111                          * snotices, C will get a local kill snotice. this isn't accurate, and needs fixing at some stage. -- w00t
112                          */
113                         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());
114                         ServerInstance->Logs->Log("KILL",DEFAULT,"LOCAL KILL: %s :%s!%s!%s (%s)", u->nick.c_str(), ServerInstance->Config->ServerName.c_str(), user->dhost.c_str(), user->nick.c_str(), parameters[1].c_str());
115                         /* 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
116                          * hidekillsserver as source if possible
117                          */
118                         if (!u->quitting)
119                         {
120                                 u->Write(":%s KILL %s :%s!%s!%s (%s)", ServerInstance->Config->HideKillsServer.empty() ? user->GetFullHost().c_str() : ServerInstance->Config->HideKillsServer.c_str(),
121                                                 u->nick.c_str(),
122                                                 ServerInstance->Config->ServerName.c_str(),
123                                                 user->dhost.c_str(),
124                                                 ServerInstance->Config->HideKillsServer.empty() ? user->nick.c_str() : ServerInstance->Config->HideKillsServer.c_str(),
125                                                 parameters[1].c_str());
126                         }
127                 }
128
129                 // send the quit out
130                 ServerInstance->Users->QuitUser(u, killreason);
131         }
132         else
133         {
134                 user->WriteServ( "401 %s %s :No such nick/channel", user->nick.c_str(), parameters[0].c_str());
135                 return CMD_FAILURE;
136         }
137
138         return CMD_SUCCESS;
139 }
140
141
142 COMMAND_INIT(CommandKill)