]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | /* |
2 | * IRC - Internet Relay Chat, ircd/m_kick.c | |
3 | * Copyright (C) 1990 Jarkko Oikarinen and | |
4 | * University of Oulu, Computing Center | |
5 | * | |
6 | * See file AUTHORS in IRC package for additional names of | |
7 | * the programmers. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 1, or (at your option) | |
12 | * any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 | * | |
052b069e | 23 | * $Id: m_kick.c,v 1.19.2.4 2005/11/14 21:17:07 entrope Exp $ |
189935b1 | 24 | */ |
25 | ||
26 | /* | |
27 | * m_functions execute protocol messages on this server: | |
28 | * | |
29 | * cptr is always NON-NULL, pointing to a *LOCAL* client | |
30 | * structure (with an open socket connected!). This | |
31 | * identifies the physical socket where the message | |
32 | * originated (or which caused the m_function to be | |
33 | * executed--some m_functions may call others...). | |
34 | * | |
35 | * sptr is the source of the message, defined by the | |
36 | * prefix part of the message if present. If not | |
37 | * or prefix not found, then sptr==cptr. | |
38 | * | |
39 | * (!IsServer(cptr)) => (cptr == sptr), because | |
40 | * prefixes are taken *only* from servers... | |
41 | * | |
42 | * (IsServer(cptr)) | |
43 | * (sptr == cptr) => the message didn't | |
44 | * have the prefix. | |
45 | * | |
46 | * (sptr != cptr && IsServer(sptr) means | |
47 | * the prefix specified servername. (?) | |
48 | * | |
49 | * (sptr != cptr && !IsServer(sptr) means | |
50 | * that message originated from a remote | |
51 | * user (not local). | |
52 | * | |
53 | * combining | |
54 | * | |
55 | * (!IsServer(sptr)) means that, sptr can safely | |
56 | * taken as defining the target structure of the | |
57 | * message in this server. | |
58 | * | |
59 | * *Always* true (if 'parse' and others are working correct): | |
60 | * | |
61 | * 1) sptr->from == cptr (note: cptr->from == cptr) | |
62 | * | |
63 | * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr | |
64 | * *cannot* be a local connection, unless it's | |
65 | * actually cptr!). [MyConnect(x) should probably | |
66 | * be defined as (x == x->from) --msa ] | |
67 | * | |
68 | * parc number of variable parameter strings (if zero, | |
69 | * parv is allowed to be NULL) | |
70 | * | |
71 | * parv a NULL terminated list of parameter pointers, | |
72 | * | |
73 | * parv[0], sender (prefix string), if not present | |
74 | * this points to an empty string. | |
75 | * parv[1]...parv[parc-1] | |
76 | * pointers to additional parameters | |
77 | * parv[parc] == NULL, *always* | |
78 | * | |
79 | * note: it is guaranteed that parv[0]..parv[parc-1] are all | |
80 | * non-NULL pointers. | |
81 | */ | |
82 | #include "config.h" | |
83 | ||
84 | #include "channel.h" | |
85 | #include "client.h" | |
86 | #include "hash.h" | |
87 | #include "ircd.h" | |
88 | #include "ircd_log.h" | |
89 | #include "ircd_reply.h" | |
90 | #include "ircd_string.h" | |
91 | #include "msg.h" | |
92 | #include "numeric.h" | |
93 | #include "numnicks.h" | |
94 | #include "send.h" | |
95 | #include "ircd_features.h" | |
96 | ||
97 | /* #include <assert.h> -- Now using assert in ircd_log.h */ | |
98 | ||
99 | /* | |
100 | * m_kick - generic message handler | |
101 | * | |
102 | * parv[0] = sender prefix | |
103 | * parv[1] = channel | |
104 | * parv[2] = client to kick | |
105 | * parv[parc-1] = kick comment | |
106 | */ | |
107 | int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) | |
108 | { | |
109 | struct Client *who; | |
110 | struct Channel *chptr; | |
111 | struct Membership *member = 0; | |
112 | struct Membership* member2; | |
113 | char *name, *comment; | |
114 | ||
115 | ClrFlag(sptr, FLAG_TS8); | |
116 | ||
117 | if (parc < 3 || *parv[1] == '\0') | |
118 | return need_more_params(sptr, "KICK"); | |
119 | ||
120 | name = parv[1]; | |
121 | ||
122 | /* simple checks */ | |
123 | if (!(chptr = get_channel(sptr, name, CGT_NO_CREATE))) | |
124 | return send_reply(sptr, ERR_NOSUCHCHANNEL, name); | |
125 | ||
126 | if (!(member2 = find_member_link(chptr, sptr)) || IsZombie(member2) | |
127 | || !IsChanOp(member2)) | |
128 | return send_reply(sptr, ERR_CHANOPRIVSNEEDED, name); | |
129 | ||
130 | if (!(who = find_chasing(sptr, parv[2], 0))) | |
131 | return 0; /* find_chasing sends the reply for us */ | |
132 | ||
133 | /* Don't allow the channel service to be kicked */ | |
134 | if (IsChannelService(who)) | |
135 | return send_reply(sptr, ERR_ISCHANSERVICE, cli_name(who), chptr->chname); | |
136 | ||
137 | /* Prevent kicking opers from local channels -DM- */ | |
138 | if (IsLocalChannel(chptr->chname) && HasPriv(who, PRIV_DEOP_LCHAN)) | |
139 | return send_reply(sptr, ERR_ISOPERLCHAN, cli_name(who), chptr->chname); | |
140 | ||
141 | /* check if kicked user is actually on the channel */ | |
142 | if (!(member = find_member_link(chptr, who)) || IsZombie(member)) | |
143 | return send_reply(sptr, ERR_USERNOTINCHANNEL, cli_name(who), chptr->chname); | |
144 | ||
052b069e | 145 | /* Don't allow to kick member with a higher op-level, |
146 | * or members with the same op-level unless both are MAXOPLEVEL. | |
147 | */ | |
148 | if (OpLevel(member) < OpLevel(member2) | |
149 | || (OpLevel(member) == OpLevel(member2) | |
150 | && OpLevel(member) < MAXOPLEVEL)) | |
189935b1 | 151 | return send_reply(sptr, ERR_NOTLOWEROPLEVEL, cli_name(who), chptr->chname, |
152 | OpLevel(member2), OpLevel(member), "kick", | |
153 | OpLevel(member) == OpLevel(member2) ? "the same" : "a higher"); | |
154 | ||
155 | /* We rely on ircd_snprintf to truncate the comment */ | |
156 | comment = EmptyString(parv[parc - 1]) ? parv[0] : parv[parc - 1]; | |
157 | ||
158 | if (!IsLocalChannel(name)) | |
159 | sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, | |
160 | comment); | |
161 | ||
162 | if (IsDelayedJoin(member)) { | |
163 | /* If it's a delayed join, only send the KICK to the person doing | |
164 | * the kicking and the victim */ | |
165 | if (MyUser(who)) | |
166 | sendcmdto_one(sptr, CMD_KICK, who, "%H %C :%s", chptr, who, comment); | |
167 | sendcmdto_one(who, CMD_JOIN, sptr, "%H", chptr); | |
168 | sendcmdto_one(sptr, CMD_KICK, sptr, "%H %C :%s", chptr, who, comment); | |
169 | CheckDelayedJoins(chptr); | |
170 | } else | |
171 | sendcmdto_channel_butserv_butone(sptr, CMD_KICK, chptr, NULL, 0, "%H %C :%s", chptr, who, | |
172 | comment); | |
173 | ||
174 | make_zombie(member, who, cptr, sptr, chptr); | |
175 | ||
176 | return 0; | |
177 | } | |
178 | ||
179 | /* | |
180 | * ms_kick - server message handler | |
181 | * | |
182 | * parv[0] = sender prefix | |
183 | * parv[1] = channel | |
184 | * parv[2] = client to kick | |
185 | * parv[parc-1] = kick comment | |
186 | */ | |
187 | int ms_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[]) | |
188 | { | |
189 | struct Client *who; | |
190 | struct Channel *chptr; | |
191 | struct Membership *member = 0, *sptr_link = 0; | |
192 | char *name, *comment; | |
193 | ||
194 | ClrFlag(sptr, FLAG_TS8); | |
195 | ||
196 | if (parc < 3 || *parv[1] == '\0') | |
197 | return need_more_params(sptr, "KICK"); | |
198 | ||
199 | name = parv[1]; | |
200 | comment = parv[parc - 1]; | |
201 | ||
202 | /* figure out who gets kicked from what */ | |
203 | if (IsLocalChannel(name) || | |
204 | !(chptr = get_channel(sptr, name, CGT_NO_CREATE)) || | |
205 | !(who = findNUser(parv[2]))) | |
206 | return 0; | |
207 | ||
208 | /* We go ahead and pass on the KICK for users not on the channel */ | |
209 | if (!(member = find_member_link(chptr, who)) || IsZombie(member)) | |
210 | member = 0; | |
211 | ||
212 | /* Send HACK notice, but not for servers in BURST */ | |
213 | /* 2002-10-17: Don't send HACK if the users local server is kicking them */ | |
214 | if (IsServer(sptr) && | |
215 | !IsBurstOrBurstAck(sptr) && | |
052b069e | 216 | sptr!=cli_user(who)->server) |
189935b1 | 217 | sendto_opmask_butone(0, SNO_HACK4, "HACK: %C KICK %H %C %s", sptr, chptr, |
218 | who, comment); | |
219 | ||
220 | /* Unless someone accepted it downstream (or the user isn't on the channel | |
221 | * here), if kicker is not on channel, or if kicker is not a channel | |
222 | * operator, bounce the kick | |
223 | */ | |
224 | if (!IsServer(sptr) && member && cli_from(who) != cptr && | |
225 | (!(sptr_link = find_member_link(chptr, sptr)) || !IsChanOp(sptr_link))) { | |
226 | sendto_opmask_butone(0, SNO_HACK2, "HACK: %C KICK %H %C %s", sptr, chptr, | |
227 | who, comment); | |
228 | ||
229 | sendcmdto_one(who, CMD_JOIN, cptr, "%H", chptr); | |
230 | ||
231 | /* Reop/revoice member */ | |
232 | if (IsChanOp(member) || HasVoice(member)) { | |
233 | struct ModeBuf mbuf; | |
234 | ||
235 | modebuf_init(&mbuf, sptr, cptr, chptr, | |
236 | (MODEBUF_DEST_SERVER | /* Send mode to a server */ | |
237 | MODEBUF_DEST_DEOP | /* Deop the source */ | |
238 | MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */ | |
239 | ||
240 | if (IsChanOp(member)) | |
241 | modebuf_mode_client(&mbuf, MODE_DEL | MODE_CHANOP, who, OpLevel(member)); | |
242 | if (HasVoice(member)) | |
243 | modebuf_mode_client(&mbuf, MODE_DEL | MODE_VOICE, who, MAXOPLEVEL + 1); | |
244 | ||
245 | modebuf_flush(&mbuf); | |
246 | } | |
247 | } else { | |
248 | /* Propagate kick... */ | |
249 | sendcmdto_serv_butone(sptr, CMD_KICK, cptr, "%H %C :%s", chptr, who, | |
250 | comment); | |
251 | ||
252 | if (member) { /* and tell the channel about it */ | |
253 | if (IsDelayedJoin(member)) { | |
254 | if (MyUser(who)) | |
255 | sendcmdto_one(IsServer(sptr) ? &his : sptr, CMD_KICK, | |
052b069e | 256 | who, "%H %C :%s", chptr, who, comment); |
189935b1 | 257 | } else { |
258 | sendcmdto_channel_butserv_butone(IsServer(sptr) ? &his : sptr, CMD_KICK, | |
259 | chptr, NULL, 0, "%H %C :%s", chptr, who, | |
260 | comment); | |
261 | } | |
262 | ||
263 | make_zombie(member, who, cptr, sptr, chptr); | |
264 | } | |
265 | } | |
266 | ||
267 | return 0; | |
268 | } |