Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / m_kick.c
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  *
23  * $Id$
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 #if 0
83 /*
84  * No need to include handlers.h here the signatures must match
85  * and we don't need to force a rebuild of all the handlers everytime
86  * we add a new one to the list. --Bleep
87  */
88 #include "handlers.h"
89 #endif /* 0 */
90 #include "channel.h"
91 #include "client.h"
92 #include "hash.h"
93 #include "ircd.h"
94 #include "ircd_reply.h"
95 #include "ircd_string.h"
96 #include "msg.h"
97 #include "numeric.h"
98 #include "numnicks.h"
99 #include "send.h"
100
101 #include <assert.h>
102
103 /*
104  * m_kick - generic message handler
105  *
106  * parv[0] = sender prefix
107  * parv[1] = channel
108  * parv[2] = client to kick
109  * parv[parc-1] = kick comment
110  */
111 int m_kick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
112 {
113   struct Client*  who;
114   struct Channel* chptr;
115   struct Membership* member = 0;
116   char*           channel_name;
117
118   sptr->flags &= ~FLAGS_TS8;
119
120   if (parc < 3 || *parv[1] == '\0')
121     return need_more_params(sptr, "KICK");
122
123   channel_name = parv[1];
124
125   if (IsLocalChannel(channel_name) && !MyUser(sptr))
126     return 0;
127
128   if (IsModelessChannel(channel_name)) {
129     sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
130                channel_name);
131     return 0;
132   }
133
134   chptr = get_channel(sptr, channel_name, CGT_NO_CREATE);
135   if (!chptr) {
136     sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], channel_name);
137     return 0;
138   }
139
140   if (!IsServer(cptr) && !is_chan_op(sptr, chptr)) {
141     sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
142                me.name, parv[0], chptr->chname);
143     return 0;
144   }
145
146   if (MyUser(sptr)) {
147     if (!(who = find_chasing(sptr, parv[2], 0)))
148       return 0;                 /* No such user left! */
149   }
150   else if (!(who = findNUser(parv[2])))
151     return 0;                   /* No such user left! */
152
153   /*
154    * if the user is +k, prevent a kick from local user
155    */
156   if (IsChannelService(who) && MyUser(sptr)) {
157     sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
158         parv[0], who->name, chptr->chname);
159     return 0;
160   }
161
162 #ifdef NO_OPER_DEOP_LCHAN
163   /*
164    * Prevent kicking opers from local channels -DM-
165    */
166   if (IsOperOnLocalChannel(who, chptr->chname)) {
167     sendto_one(sptr, err_str(ERR_ISOPERLCHAN), me.name,
168                parv[0], who->name, chptr->chname);
169     return 0;
170   }
171 #endif
172
173   /* 
174    * Servers can now send kicks without hacks during a netburst - they
175    * are kicking users from a +i channel.
176    *  - Isomer 25-11-1999
177    */
178   if (IsServer(sptr)
179 #if defined(NO_INVITE_NETRIDE)
180       && !IsBurstOrBurstAck(sptr)
181 #endif
182      ) {
183     send_hack_notice(cptr, sptr, parc, parv, 1, 3);
184   }
185
186   if (IsServer(sptr) ||
187       ((member = find_member_link(chptr, who)) && !IsZombie(member)))
188   {
189     struct Membership* sptr_link = find_member_link(chptr, sptr);
190     if (who->from != cptr &&
191         ((sptr_link && IsDeopped(sptr_link)) || (!sptr_link && IsUser(sptr))))
192     {
193       /*
194        * Bounce here:
195        * cptr must be a server (or cptr == sptr and
196        * sptr->flags can't have DEOPPED set
197        * when CHANOP is set).
198        */
199       sendto_one(cptr, "%s%s " TOK_JOIN " %s", NumNick(who), chptr->chname);
200       if (IsChanOp(member))
201       {
202          sendto_one(cptr, "%s " TOK_MODE " %s +o %s%s " TIME_T_FMT,
203               NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
204       }
205       if (HasVoice(member))
206       {
207          sendto_one(cptr, "%s " TOK_MODE " %s +v %s%s " TIME_T_FMT,
208               NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
209       }
210     }
211     else
212     {
213       char* comment = (EmptyString(parv[parc - 1])) ? parv[0] : parv[parc - 1];
214       if (strlen(comment) > TOPICLEN)
215         comment[TOPICLEN] = '\0';
216
217       if (!IsLocalChannel(channel_name))
218       {
219         sendto_highprot_butone(cptr, 10, "%s%s " TOK_KICK " %s %s%s :%s",
220             NumNick(sptr), chptr->chname, NumNick(who), comment);
221       }
222       if (member) {
223         sendto_channel_butserv(chptr, sptr,
224             ":%s KICK %s %s :%s", parv[0], chptr->chname, who->name, comment);
225         make_zombie(member, who, cptr, sptr, chptr);
226       }
227     }
228   }
229   else if (MyUser(sptr))
230     sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
231         me.name, parv[0], who->name, chptr->chname);
232
233   return 0;
234 }
235
236 /*
237  * ms_kick - server message handler
238  *
239  * parv[0] = sender prefix
240  * parv[1] = channel
241  * parv[2] = client to kick
242  * parv[parc-1] = kick comment
243  */
244 int ms_kick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
245 {
246   struct Client*  who;
247   struct Channel* chptr;
248   struct Membership* member = 0;
249   char*           channel_name;
250
251   sptr->flags &= ~FLAGS_TS8;
252
253   if (parc < 3 || *parv[1] == '\0')
254     return need_more_params(sptr, "KICK");
255
256   channel_name = parv[1];
257
258   if (IsLocalChannel(channel_name) && !MyUser(sptr))
259     return 0;
260
261   if (IsModelessChannel(channel_name)) {
262     sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
263                channel_name);
264     return 0;
265   }
266
267   chptr = get_channel(sptr, channel_name, CGT_NO_CREATE);
268   if (!chptr) {
269     sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], channel_name);
270     return 0;
271   }
272
273   if (!IsServer(cptr) && !is_chan_op(sptr, chptr)) {
274     sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
275                me.name, parv[0], chptr->chname);
276     return 0;
277   }
278
279   if (MyUser(sptr)) {
280     if (!(who = find_chasing(sptr, parv[2], 0)))
281       return 0;                 /* No such user left! */
282   }
283   else if (!(who = findNUser(parv[2])))
284     return 0;                   /* No such user left! */
285
286   /*
287    * if the user is +k, prevent a kick from local user
288    */
289   if (IsChannelService(who) && MyUser(sptr)) {
290     sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
291         parv[0], who->name, chptr->chname);
292     return 0;
293   }
294
295 #ifdef NO_OPER_DEOP_LCHAN
296   /*
297    * Prevent kicking opers from local channels -DM-
298    */
299   if (IsOperOnLocalChannel(who, chptr->chname)) {
300     sendto_one(sptr, err_str(ERR_ISOPERLCHAN), me.name,
301                parv[0], who->name, chptr->chname);
302     return 0;
303   }
304 #endif
305
306 #if defined(NO_INVITE_NETRIDE)
307   /* 
308    * Servers can now send kicks without hacks during a netburst - they
309    * are kicking users from a +i channel.
310    *  - Isomer 25-11-1999
311    */
312   if (IsServer(sptr) && !IsBurstOrBurstAck(sptr)) {
313 #else
314   if (IsServer(sptr)) {
315 #endif
316     send_hack_notice(cptr, sptr, parc, parv, 1, 3);
317   }
318
319   if (IsServer(sptr) ||
320       ((member = find_member_link(chptr, who)) && !IsZombie(member)))
321   {
322     struct Membership* sptr_link = find_member_link(chptr, sptr);
323     if (who->from != cptr &&
324         ((sptr_link && IsDeopped(sptr_link)) || (!sptr_link && IsUser(sptr))))
325     {
326       /*
327        * Bounce here:
328        * cptr must be a server (or cptr == sptr and
329        * sptr->flags can't have DEOPPED set
330        * when CHANOP is set).
331        */
332       sendto_one(cptr, "%s%s " TOK_JOIN " %s", NumNick(who), chptr->chname);
333       if (IsChanOp(member))
334       {
335          sendto_one(cptr, "%s " TOK_MODE " %s +o %s%s " TIME_T_FMT,
336               NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
337       }
338       if (HasVoice(member))
339       {
340          sendto_one(cptr, "%s " TOK_MODE " %s +v %s%s " TIME_T_FMT,
341               NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
342       }
343     }
344     else
345     {
346       char* comment = (EmptyString(parv[parc - 1])) ? parv[0] : parv[parc - 1];
347       if (strlen(comment) > TOPICLEN)
348         comment[TOPICLEN] = '\0';
349
350       if (!IsLocalChannel(channel_name)) {
351         if (IsServer(sptr)) {
352           sendto_highprot_butone(cptr, 10, "%s " TOK_KICK " %s %s%s :%s",
353                                  NumServ(sptr), chptr->chname, NumNick(who),
354                                  comment);
355         }
356         else {
357           sendto_highprot_butone(cptr, 10, "%s%s " TOK_KICK " %s %s%s :%s",
358                                  NumNick(sptr), chptr->chname, NumNick(who),
359                                  comment);
360         }
361       }
362       if (member) {
363         sendto_channel_butserv(chptr, sptr,
364             ":%s KICK %s %s :%s", parv[0], chptr->chname, who->name, comment);
365         make_zombie(member, who, cptr, sptr, chptr);
366       }
367     }
368   }
369   else if (MyUser(sptr))
370     sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
371         me.name, parv[0], who->name, chptr->chname);
372
373   return 0;
374 }
375
376
377 #if 0
378 /*
379  * m_kick
380  *
381  * parv[0] = sender prefix
382  * parv[1] = channel
383  * parv[2] = client to kick
384  * parv[parc-1] = kick comment
385  */
386 int m_kick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
387 {
388   struct Client*  who;
389   struct Channel* chptr;
390   struct Membership* member = 0;
391   char*           channel_name;
392
393   sptr->flags &= ~FLAGS_TS8;
394
395   if (parc < 3 || *parv[1] == '\0')
396     return need_more_params(sptr, "KICK");
397
398   channel_name = parv[1];
399
400   if (IsLocalChannel(channel_name) && !MyUser(sptr))
401     return 0;
402
403   if (IsModelessChannel(channel_name)) {
404     sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED), me.name, parv[0],
405                channel_name);
406     return 0;
407   }
408
409   chptr = get_channel(sptr, channel_name, CGT_NO_CREATE);
410   if (!chptr) {
411     sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL), me.name, parv[0], channel_name);
412     return 0;
413   }
414
415   if (!IsServer(cptr) && !is_chan_op(sptr, chptr)) {
416     sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED),
417                me.name, parv[0], chptr->chname);
418     return 0;
419   }
420
421   if (MyUser(sptr)) {
422     if (!(who = find_chasing(sptr, parv[2], 0)))
423       return 0;                 /* No such user left! */
424   }
425   else if (!(who = findNUser(parv[2])))
426     return 0;                   /* No such user left! */
427
428   /*
429    * if the user is +k, prevent a kick from local user
430    */
431   if (IsChannelService(who) && MyUser(sptr)) {
432     sendto_one(sptr, err_str(ERR_ISCHANSERVICE), me.name,
433         parv[0], who->name, chptr->chname);
434     return 0;
435   }
436
437 #ifdef NO_OPER_DEOP_LCHAN
438   /*
439    * Prevent kicking opers from local channels -DM-
440    */
441   if (IsOperOnLocalChannel(who, chptr->chname)) {
442     sendto_one(sptr, err_str(ERR_ISOPERLCHAN), me.name,
443                parv[0], who->name, chptr->chname);
444     return 0;
445   }
446 #endif
447
448   /* 
449    * Servers can now send kicks without hacks during a netburst - they
450    * are kicking users from a +i channel.
451    *  - Isomer 25-11-1999
452    */
453   if (IsServer(sptr)
454 #if defined(NO_INVITE_NETRIDE)
455       && !IsBurstOrBurstAck(sptr)
456 #endif
457      ) {
458     send_hack_notice(cptr, sptr, parc, parv, 1, 3);
459   }
460
461   if (IsServer(sptr) ||
462       ((member = find_member_link(chptr, who)) && !IsZombie(member)))
463   {
464     struct Membership* sptr_link = find_member_link(chptr, sptr);
465     if (who->from != cptr &&
466         ((sptr_link && IsDeopped(sptr_link)) || (!sptr_link && IsUser(sptr))))
467     {
468       /*
469        * Bounce here:
470        * cptr must be a server (or cptr == sptr and
471        * sptr->flags can't have DEOPPED set
472        * when CHANOP is set).
473        */
474       sendto_one(cptr, "%s%s " TOK_JOIN " %s", NumNick(who), chptr->chname);
475       if (IsChanOp(member))
476       {
477          sendto_one(cptr, "%s " TOK_MODE " %s +o %s%s " TIME_T_FMT,
478               NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
479       }
480       if (HasVoice(member))
481       {
482          sendto_one(cptr, "%s " TOK_MODE " %s +v %s%s " TIME_T_FMT,
483               NumServ(&me), chptr->chname, NumNick(who), chptr->creationtime);
484       }
485     }
486     else
487     {
488       char* comment = (EmptyString(parv[parc - 1])) ? parv[0] : parv[parc - 1];
489       if (strlen(comment) > TOPICLEN)
490         comment[TOPICLEN] = '\0';
491
492       if (!IsLocalChannel(channel_name))
493       {
494         sendto_highprot_butone(cptr, 10, "%s%s " TOK_KICK " %s %s%s :%s",
495             NumNick(sptr), chptr->chname, NumNick(who), comment);
496       }
497       if (member) {
498         sendto_channel_butserv(chptr, sptr,
499             ":%s KICK %s %s :%s", parv[0], chptr->chname, who->name, comment);
500         make_zombie(member, who, cptr, sptr, chptr);
501       }
502     }
503   }
504   else if (MyUser(sptr))
505     sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL),
506         me.name, parv[0], who->name, chptr->chname);
507
508   return 0;
509 }
510 #endif /* 0 */
511