Author: Perry Lorier <isomer@coders.net>
[ircu2.10.12-pk.git] / ircd / m_mode.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_mode.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 #include "handlers.h"
83 #include "channel.h"
84 #include "client.h"
85 #include "hash.h"
86 #include "ircd.h"
87 #include "ircd_reply.h"
88 #include "ircd_string.h"
89 #include "msg.h"
90 #include "numeric.h"
91 #include "numnicks.h"
92 #include "s_conf.h"
93 #include "s_debug.h"
94 #include "s_user.h"
95 #include "send.h"
96
97 #include <assert.h>
98 #include <stdlib.h>
99 #include <string.h>
100
101 #ifdef CONFIG_NEW_MODE
102 int
103 m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
104 {
105   struct Channel *chptr = 0;
106   struct ModeBuf mbuf;
107   struct Membership *member;
108
109   if (parc < 2)
110     return need_more_params(sptr, "MODE");
111
112   clean_channelname(parv[1]);
113
114   if (('#' != *parv[1] && '&' != *parv[1] && '+' != *parv[1]) || 
115       !(chptr = FindChannel(parv[1])))
116     return set_user_mode(cptr, sptr, parc, parv);
117
118   sptr->flags &= ~FLAGS_TS8;
119
120   if (parc < 3) {
121     char modebuf[MODEBUFLEN];
122     char parabuf[MODEBUFLEN];
123
124     *modebuf = *parabuf = '\0';
125     modebuf[1] = '\0';
126     channel_modes(sptr, modebuf, parabuf, chptr);
127     send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, modebuf, parabuf);
128     send_reply(sptr, RPL_CREATIONTIME, chptr->chname, chptr->creationtime);
129     return 0;
130   }
131
132   if (!(member = find_member_link(chptr, sptr)) || !IsChanOp(member)) {
133 #ifdef OPER_MODE_LCHAN
134     if (IsOperOnLocalChannel(sptr, chptr->chname)) {
135       modebuf_init(&mbuf, sptr, cptr, chptr,
136                    (MODEBUF_DEST_CHANNEL | /* Send mode to channel */
137                     MODEBUF_DEST_HACK4));  /* Send HACK(4) notice */
138       mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
139                  (MODE_PARSE_SET |    /* Set the mode */
140                   MODE_PARSE_FORCE)); /* Force it to take */
141       return modebuf_flush(&mbuf);
142     } else
143 #endif
144       mode_parse(0, cptr, sptr, chptr, parc - 2, parv + 2,
145                  (member ? MODE_PARSE_NOTOPER : MODE_PARSE_NOTMEMBER));
146     return 0;
147   }
148
149   modebuf_init(&mbuf, sptr, cptr, chptr,
150                (MODEBUF_DEST_CHANNEL | /* Send mode to channel */
151                 MODEBUF_DEST_SERVER)); /* Send mode to servers */
152   mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2, MODE_PARSE_SET);
153   return modebuf_flush(&mbuf);
154 }
155
156 int
157 ms_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
158 {
159   struct Channel *chptr = 0;
160   struct ModeBuf mbuf;
161   struct Membership *member;
162
163   if (parc < 3)
164     return need_more_params(sptr, "MODE");
165
166   if (IsLocalChannel(parv[1]))
167     return 0;
168
169   if (('#' != *parv[1] && '+' != *parv[1])|| !(chptr = FindChannel(parv[1])))
170     return set_user_mode(cptr, sptr, parc, parv);
171
172   sptr->flags &= ~FLAGS_TS8;
173
174   if (IsServer(sptr)) {
175     if (find_conf_byhost(cptr->confs, sptr->name, CONF_UWORLD))
176       modebuf_init(&mbuf, sptr, cptr, chptr,
177                    (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
178                     MODEBUF_DEST_SERVER  | /* Send mode to servers */
179                     MODEBUF_DEST_HACK4));  /* Send a HACK(4) message */
180     else
181       modebuf_init(&mbuf, sptr, cptr, chptr,
182                    (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
183                     MODEBUF_DEST_SERVER  | /* Send mode to servers */
184                     MODEBUF_DEST_HACK3));  /* Send a HACK(3) message */
185
186     mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
187                (MODE_PARSE_SET    | /* Set the mode */
188                 MODE_PARSE_STRICT | /* Interpret it strictly */
189                 MODE_PARSE_FORCE)); /* And force it to be accepted */
190   } else {
191     if (!(member = find_member_link(chptr, sptr)) || !IsChanOp(member)) {
192       modebuf_init(&mbuf, sptr, cptr, chptr,
193                    (MODEBUF_DEST_SERVER |  /* Send mode to server */
194                     MODEBUF_DEST_HACK2  |  /* Send a HACK(2) message */
195                     MODEBUF_DEST_DEOP   |  /* Deop the source */
196                     MODEBUF_DEST_BOUNCE)); /* And bounce the MODE */
197       mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
198                  (MODE_PARSE_STRICT |  /* Interpret it strictly */
199                   MODE_PARSE_BOUNCE)); /* And bounce the MODE */
200     } else {
201       modebuf_init(&mbuf, sptr, cptr, chptr,
202                    (MODEBUF_DEST_CHANNEL | /* Send mode to clients */
203                     MODEBUF_DEST_SERVER)); /* Send mode to servers */
204       mode_parse(&mbuf, cptr, sptr, chptr, parc - 2, parv + 2,
205                  (MODE_PARSE_SET    | /* Set the mode */
206                   MODE_PARSE_STRICT | /* Interpret it strictly */
207                   MODE_PARSE_FORCE)); /* And force it to be accepted */
208     }
209   }
210
211   return modebuf_flush(&mbuf);
212 }
213 #else /* CONFIG_NEW_MODE */
214 /*
215  * m_mode - generic message handler
216  */
217 int m_mode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
218 {
219   int             badop;
220   int             sendts;
221   struct Channel* chptr = 0;
222   char modebuf[MODEBUFLEN];
223   char parabuf[MODEBUFLEN];
224   char nparabuf[MODEBUFLEN];
225
226
227   if (parc < 2)
228     return need_more_params(sptr, "MODE");
229
230   /*
231    * if local user, cleanup channel name, don't allow local channel operations
232    * for remote clients
233    */
234   if (MyUser(sptr))
235     clean_channelname(parv[1]);
236   else if (IsLocalChannel(parv[1]))
237     return 0;
238
239   /* 
240    * try to find the channel
241    */
242   if ('#' == *parv[1] || '&' == *parv[1] || '+' == *parv[1])
243     chptr = FindChannel(parv[1]);
244   if (!chptr)
245     return set_user_mode(cptr, sptr, parc, parv);
246
247   sptr->flags &= ~FLAGS_TS8;
248   /*
249    * sending an error wasnt good, lets just send an empty mode reply..  poptix
250    */
251   if (IsModelessChannel(chptr->chname)) {
252     if (IsUser(sptr))
253       send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, "+nt", "");
254     return 0;
255   }
256
257   if (parc < 3) {
258     /*
259      * no parameters, send channel modes
260      */
261     *modebuf = *parabuf = '\0';
262     modebuf[1] = '\0';
263     channel_modes(sptr, modebuf, parabuf, chptr);
264     send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, modebuf, parabuf);
265     send_reply(sptr, RPL_CREATIONTIME, chptr->chname, chptr->creationtime);
266     return 0;
267   }
268
269   LocalChanOperMode = 0;
270
271   if (!(sendts = set_mode(cptr, sptr, chptr, parc - 2, parv + 2,
272                           modebuf, parabuf, nparabuf, &badop))) {
273     send_reply(sptr, (find_channel_member(sptr, chptr) ?
274                       ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL), chptr->chname);
275     return 0;
276   }
277
278   if (badop >= 2)
279     send_hack_notice(cptr, sptr, parc, parv, badop, 1); /* XXX DYING */
280
281   if (strlen(modebuf) > 1 || sendts > 0) {
282     if (badop != 2 && strlen(modebuf) > 1) {
283 #ifdef OPER_MODE_LCHAN
284       if (LocalChanOperMode) {
285         sendcmdto_channel_butserv(&me, CMD_MODE, chptr, "%H %s %s", chptr,
286                                   modebuf, parabuf);
287         sendto_opmask_butone(0, SNO_HACK4, "OPER MODE: %C MODE %H %s %s",
288                              sptr, chptr, modebuf, parabuf);
289       }
290       else
291 #endif
292       sendcmdto_channel_butserv(sptr, CMD_MODE, chptr, "%H %s %s", chptr,
293                                 modebuf, parabuf);
294     }
295     if (IsLocalChannel(chptr->chname))
296       return 0;
297     /* We send a creationtime of 0, to mark it as a hack --Run */
298     if (IsServer(sptr) && (badop == 2 || sendts > 0)) {
299       if (*modebuf == '\0')
300         strcpy(modebuf, "+");
301       if (badop != 2) {
302         sendcmdto_serv_butone(sptr, CMD_MODE, cptr, "%H %s %s %Tu", chptr,
303                               modebuf, nparabuf, (badop == 4) ? (time_t) 0 :
304                               chptr->creationtime);
305       }
306     }
307     else {
308       sendcmdto_serv_butone(sptr, CMD_MODE, cptr, "%H %s %s", chptr, modebuf,
309                             nparabuf);
310     }
311   }
312   return 0;
313 }
314
315 /*
316  * ms_mode - server message handler
317  */
318 int ms_mode(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
319 {
320   int             badop;
321   int             sendts;
322   struct Channel* chptr = 0;
323   char modebuf[MODEBUFLEN];
324   char parabuf[MODEBUFLEN];
325   char nparabuf[MODEBUFLEN];
326
327   if (parc < 2)
328     return need_more_params(sptr, "MODE");
329
330   /*
331    * if local user, cleanup channel name, don't allow local channel operations
332    * for remote clients
333    */
334   if (MyUser(sptr))
335     clean_channelname(parv[1]);
336   else if (IsLocalChannel(parv[1]))
337     return 0;
338
339   /* 
340    * try to find the channel
341    */
342   if ('#' == *parv[1] || '&' == *parv[1] || '+' == *parv[1])
343     chptr = FindChannel(parv[1]);
344   if (!chptr)
345     return set_user_mode(cptr, sptr, parc, parv);
346
347   sptr->flags &= ~FLAGS_TS8;
348   /*
349    * sending an error wasnt good, lets just send an empty mode reply..  poptix
350    */
351   if (IsModelessChannel(chptr->chname)) {
352     if (IsUser(sptr))
353       send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, "+nt", "");
354     return 0;
355   }
356
357   if (parc < 3) {
358     /*
359      * no parameters, send channel modes
360      */
361     *modebuf = *parabuf = '\0';
362     modebuf[1] = '\0';
363     channel_modes(sptr, modebuf, parabuf, chptr);
364     send_reply(sptr, RPL_CHANNELMODEIS, chptr->chname, modebuf, parabuf);
365     send_reply(sptr, RPL_CREATIONTIME, chptr->chname, chptr->creationtime);
366     return 0;
367   }
368
369   LocalChanOperMode = 0;
370
371   if (!(sendts = set_mode(cptr, sptr, chptr, parc - 2, parv + 2,
372                           modebuf, parabuf, nparabuf, &badop))) {
373     send_reply(sptr, (find_channel_member(sptr, chptr) ?
374                       ERR_CHANOPRIVSNEEDED : ERR_NOTONCHANNEL), chptr->chname);
375     return 0;
376   }
377
378   if (badop >= 2)
379     send_hack_notice(cptr, sptr, parc, parv, badop, 1); /* XXX DYING */
380
381   if (strlen(modebuf) > 1 || sendts > 0) {
382     if (badop != 2 && strlen(modebuf) > 1) {
383 #ifdef OPER_MODE_LCHAN
384       if (LocalChanOperMode) {
385         sendcmdto_channel_butserv(&me, CMD_MODE, chptr, "%H %s %s", chptr,
386                                   modebuf, parabuf);
387         sendto_opmask_butone(0, SNO_HACK4, "OPER MODE: %C MODE %H %s %s",
388                              sptr, chptr, modebuf, parabuf);
389       }
390       else
391 #endif
392       sendcmdto_channel_butserv(sptr, CMD_MODE, chptr, "%H %s %s", chptr,
393                                 modebuf, parabuf);
394     }
395     if (IsLocalChannel(chptr->chname))
396       return 0;
397     /* We send a creationtime of 0, to mark it as a hack --Run */
398     if (IsServer(sptr) && (badop == 2 || sendts > 0)) {
399       if (*modebuf == '\0')
400         strcpy(modebuf, "+");
401       if (badop != 2) {
402         sendcmdto_serv_butone(sptr, CMD_MODE, cptr, "%H %s %s %Tu", chptr,
403                               modebuf, nparabuf, (badop == 4) ? (time_t) 0 :
404                               chptr->creationtime);
405       }
406     }
407     else {
408       sendcmdto_serv_butone(sptr, CMD_MODE, cptr, "%H %s %s", chptr, modebuf,
409                             nparabuf);
410     }
411   }
412   return 0;
413 }
414 #endif /* CONFIG_NEW_MODE */
415
416 #if 0
417 /*
418  * m_mode
419  * parv[0] - sender
420  * parv[1] - channel
421  */
422 int m_mode(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
423 {
424   int             badop;
425   int             sendts;
426   struct Channel* chptr = 0;
427
428   if (parc < 2)
429     return need_more_params(sptr, "MODE");
430
431   /*
432    * if local user, cleanup channel name, don't allow local channel operations
433    * for remote clients
434    */
435   if (MyUser(sptr))
436     clean_channelname(parv[1]);
437   else if (IsLocalChannel(parv[1]))
438     return 0;
439
440   /* 
441    * try to find the channel
442    */
443   if ('#' == *parv[1] || '&' == *parv[1] || '+' == *parv[1])
444     chptr = FindChannel(parv[1]);
445   if (!chptr)
446     return set_user_mode(cptr, sptr, parc, parv);
447
448   sptr->flags &= ~FLAGS_TS8;
449   /*
450    * sending an error wasnt good, lets just send an empty mode reply..  poptix
451    */
452   if (IsModelessChannel(chptr->chname)) {
453     if (IsUser(sptr))
454       sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0], /* XXX DEAD */
455                  chptr->chname, "+nt", "");
456     return 0;
457   }
458
459   if (parc < 3) {
460     /*
461      * no parameters, send channel modes
462      */
463     *modebuf = *parabuf = '\0';
464     modebuf[1] = '\0';
465     channel_modes(sptr, modebuf, parabuf, chptr);
466     sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS), me.name, parv[0], /* XXX DEAD */
467                chptr->chname, modebuf, parabuf);
468     sendto_one(sptr, rpl_str(RPL_CREATIONTIME), me.name, parv[0], /* XXX DEAD */
469                chptr->chname, chptr->creationtime);
470     return 0;
471   }
472
473   LocalChanOperMode = 0;
474
475   if (!(sendts = set_mode(cptr, sptr, chptr, parc - 2, parv + 2,
476                           modebuf, parabuf, nparabuf, &badop))) {
477     sendto_one(sptr, err_str(find_channel_member(sptr, chptr) ? ERR_CHANOPRIVSNEEDED : /* XXX DEAD */
478         ERR_NOTONCHANNEL), me.name, parv[0], chptr->chname);
479     return 0;
480   }
481
482   if (badop >= 2)
483     send_hack_notice(cptr, sptr, parc, parv, badop, 1);
484
485   if (strlen(modebuf) > 1 || sendts > 0) {
486     if (badop != 2 && strlen(modebuf) > 1) {
487 #ifdef OPER_MODE_LCHAN
488       if (LocalChanOperMode) {
489         sendto_channel_butserv(chptr, &me, ":%s MODE %s %s %s", /* XXX DEAD */
490                                me.name, chptr->chname, modebuf, parabuf);
491         sendto_op_mask(SNO_HACK4,"OPER MODE: %s MODE %s %s %s", /* XXX DEAD */
492                        me.name, chptr->chname, modebuf, parabuf);
493       }
494       else
495 #endif
496       sendto_channel_butserv(chptr, sptr, ":%s MODE %s %s %s", /* XXX DEAD */
497           parv[0], chptr->chname, modebuf, parabuf);
498     }
499     if (IsLocalChannel(chptr->chname))
500       return 0;
501     /* We send a creationtime of 0, to mark it as a hack --Run */
502     if (IsServer(sptr) && (badop == 2 || sendts > 0)) {
503       if (*modebuf == '\0')
504         strcpy(modebuf, "+");
505       if (badop != 2) {
506         sendto_highprot_butone(cptr, 10, "%s " TOK_MODE " %s %s %s " TIME_T_FMT, /* XXX DEAD */
507             NumServ(sptr), chptr->chname, modebuf, nparabuf,
508             (badop == 4) ? (time_t) 0 : chptr->creationtime);
509       }
510     }
511     else {
512       if (IsServer(sptr))
513          sendto_highprot_butone(cptr, 10, "%s " TOK_MODE " %s %s %s", /* XXX DEAD */
514            NumServ(sptr), chptr->chname, modebuf, nparabuf);
515       else
516          sendto_highprot_butone(cptr, 10, "%s%s " TOK_MODE " %s %s %s", /* XXX DEAD */
517            NumNick(sptr), chptr->chname, modebuf, nparabuf);
518     }
519   }
520   return 0;
521 }
522
523 #endif /* 0 */