]> jfr.im git - irc/rqf/shadowircd.git/blame - src/chmode.c
Send only one ERR_MLOCKRESTRICTED per MODE command.
[irc/rqf/shadowircd.git] / src / chmode.c
CommitLineData
212380e3 1/*
2 * charybdis: A slightly useful ircd.
3 * chmode.c: channel mode management
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 * Copyright (C) 2005-2006 charybdis development team
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
212380e3 25 */
26
27#include "stdinc.h"
212380e3 28#include "channel.h"
29#include "client.h"
30#include "common.h"
31#include "hash.h"
32#include "hook.h"
13ae2f4b 33#include "match.h"
212380e3 34#include "ircd.h"
35#include "numeric.h"
36#include "s_serv.h" /* captab */
37#include "s_user.h"
38#include "send.h"
39#include "whowas.h"
40#include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
41#include "s_newconf.h"
d3455e2c 42#include "logger.h"
b5482c91 43#include "chmode.h"
a039358e 44#include "irc_dictionary.h"
212380e3 45
46/* bitmasks for error returns, so we send once per call */
47#define SM_ERR_NOTS 0x00000001 /* No TS on channel */
48#define SM_ERR_NOOPS 0x00000002 /* No chan ops */
49#define SM_ERR_UNKNOWN 0x00000004
50#define SM_ERR_RPL_C 0x00000008
51#define SM_ERR_RPL_B 0x00000010
52#define SM_ERR_RPL_E 0x00000020
53#define SM_ERR_NOTONCHANNEL 0x00000040 /* Not on channel */
54#define SM_ERR_RPL_I 0x00000100
55#define SM_ERR_RPL_D 0x00000200
56#define SM_ERR_NOPRIVS 0x00000400
57#define SM_ERR_RPL_Q 0x00000800
58#define SM_ERR_RPL_F 0x00001000
cc2a7258 59#define SM_ERR_MLOCK 0x00002000
212380e3 60
c08f4515
JT
61#define MAXMODES_SIMPLE 46 /* a-zA-Z except bqeIov */
62
212380e3 63static struct ChModeChange mode_changes[BUFSIZE];
64static int mode_count;
65static int mode_limit;
c08f4515 66static int mode_limit_simple;
212380e3 67static int mask_pos;
4ed822ed 68static int no_override_deop;
212380e3 69
2392eb24
VY
70char cflagsbuf[256];
71char cflagsmyinfo[256];
72
75818939 73int chmode_flags[256];
7608ef49 74
1fe75e33
G
75struct module_modes ModuleModes;
76
57d299ac 77/* OPTIMIZE ME! -- dwr */
75818939 78void
6795400d 79construct_cflags_strings(void)
75818939
VY
80{
81 int i;
2392eb24
VY
82 char *ptr = cflagsbuf;
83 char *ptr2 = cflagsmyinfo;
2392eb24
VY
84
85 *ptr = '\0';
86 *ptr2 = '\0';
75818939
VY
87
88 for(i = 0; i < 256; i++)
89 {
6b3b07a8
VY
90 if( !(chmode_table[i].set_func == chm_ban) &&
91 !(chmode_table[i].set_func == chm_forward) &&
92 !(chmode_table[i].set_func == chm_throttle) &&
93 !(chmode_table[i].set_func == chm_key) &&
94 !(chmode_table[i].set_func == chm_limit) &&
c1c91f94 95 !(chmode_table[i].set_func == chm_admin) &&
6b3b07a8 96 !(chmode_table[i].set_func == chm_op) &&
82f8e812 97 !(chmode_table[i].set_func == chm_halfop) &&
6b3b07a8 98 !(chmode_table[i].set_func == chm_voice))
75818939
VY
99 {
100 chmode_flags[i] = chmode_table[i].mode_type;
101 }
102 else
103 {
104 chmode_flags[i] = 0;
105 }
57d299ac 106
1fe75e33 107 if(chmode_flags[i] == ModuleModes.MODE_DISFORWARD)
2392eb24 108 {
1fe75e33 109 if (ModuleModes.MODE_FORWARD)
2392eb24 110 {
1fe75e33 111 *ptr++ = (char) i;
2392eb24 112 }
1fe75e33
G
113 }
114 else if(chmode_flags[i] == ModuleModes.MODE_REGONLY)
115 {
116 if (rb_dlink_list_length(&service_list))
2392eb24 117 {
1fe75e33 118 *ptr++ = (char) i;
2392eb24
VY
119 }
120 }
1fe75e33
G
121 else if(chmode_flags[i] != ModuleModes.MODE_EXLIMIT && chmode_flags[i] != 0)
122 {
123 *ptr++ = (char) i;
124 }
2392eb24
VY
125
126 /* Should we leave orphaned check here? -- dwr */
127 if(!(chmode_table[i].set_func == chm_nosuch) && !(chmode_table[i].set_func == chm_orphaned))
128 {
129 *ptr2++ = (char) i;
130 }
75818939 131 }
2392eb24
VY
132
133 *ptr++ = '\0';
134 *ptr2++ = '\0';
73de5d22
VY
135}
136
137/*
138 * find_umode_slot
139 *
140 * inputs - NONE
141 * outputs - an available cflag bitmask or
142 * 0 if no cflags are available
143 * side effects - NONE
144 */
6795400d 145static unsigned int
73de5d22
VY
146find_cflag_slot(void)
147{
148 unsigned int all_cflags = 0, my_cflag = 0, i;
149
150 for (i = 0; i < 256; i++)
151 all_cflags |= chmode_flags[i];
152
153 for (my_cflag = 1; my_cflag && (all_cflags & my_cflag);
154 my_cflag <<= 1);
155
156 return my_cflag;
75818939
VY
157}
158
6795400d
JT
159unsigned int
160cflag_add(char c_, ChannelModeFunc function)
161{
162 int c = (unsigned char)c_;
163
164 if (chmode_table[c].set_func != chm_nosuch &&
165 chmode_table[c].set_func != chm_orphaned)
166 return 0;
167
168 if (chmode_table[c].set_func == chm_nosuch)
169 chmode_table[c].mode_type = find_cflag_slot();
170 if (chmode_table[c].mode_type == 0)
171 return 0;
172 chmode_table[c].set_func = function;
173 construct_cflags_strings();
174 return chmode_table[c].mode_type;
175}
176
177void
178cflag_orphan(char c_)
179{
180 int c = (unsigned char)c_;
181
182 s_assert(chmode_flags[c] != 0);
183 chmode_table[c].set_func = chm_orphaned;
184 construct_cflags_strings();
185}
186
aa65834c 187static int
212380e3 188get_channel_access(struct Client *source_p, struct membership *msptr)
189{
c1c91f94
G
190 if(!MyClient(source_p) || is_admin(msptr))
191 return CHFL_ADMIN;
82f8e812 192 else if(is_chanop(msptr))
212380e3 193 return CHFL_CHANOP;
82f8e812
G
194 else if(is_halfop(msptr))
195 return CHFL_HALFOP;
212380e3 196
197 return CHFL_PEON;
198}
199
200/* add_id()
201 *
202 * inputs - client, channel, id to add, type
203 * outputs - 0 on failure, 1 on success
204 * side effects - given id is added to the appropriate list
205 */
206int
207add_id(struct Client *source_p, struct Channel *chptr, const char *banid,
af81d5a0 208 rb_dlink_list * list, long mode_type)
212380e3 209{
210 struct Ban *actualBan;
83294285 211 static char who[USERHOST_REPLYLEN];
212380e3 212 char *realban = LOCAL_COPY(banid);
af81d5a0 213 rb_dlink_node *ptr;
212380e3 214
215 /* dont let local clients overflow the banlist, or set redundant
216 * bans
217 */
218 if(MyClient(source_p))
219 {
1fe75e33 220 if((rb_dlink_list_length(&chptr->banlist) + rb_dlink_list_length(&chptr->exceptlist) + rb_dlink_list_length(&chptr->invexlist) + rb_dlink_list_length(&chptr->quietlist)) >= (chptr->mode.mode & ModuleModes.MODE_EXLIMIT ? ConfigChannel.max_bans_large : ConfigChannel.max_bans))
212380e3 221 {
222 sendto_one(source_p, form_str(ERR_BANLISTFULL),
223 me.name, source_p->name, chptr->chname, realban);
224 return 0;
225 }
226
8e69bb4e 227 RB_DLINK_FOREACH(ptr, list->head)
212380e3 228 {
229 actualBan = ptr->data;
fd488ac1 230 if(mask_match(actualBan->banstr, realban))
212380e3 231 return 0;
232 }
233 }
234 /* dont let remotes set duplicates */
235 else
236 {
8e69bb4e 237 RB_DLINK_FOREACH(ptr, list->head)
212380e3 238 {
239 actualBan = ptr->data;
240 if(!irccmp(actualBan->banstr, realban))
241 return 0;
242 }
243 }
244
245
246 if(IsPerson(source_p))
38e6acdd 247 rb_sprintf(who, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
212380e3 248 else
907468c4 249 rb_strlcpy(who, source_p->name, sizeof(who));
212380e3 250
251 actualBan = allocate_ban(realban, who);
9f6bbe3c 252 actualBan->when = rb_current_time();
212380e3 253
af81d5a0 254 rb_dlinkAdd(actualBan, &actualBan->node, list);
212380e3 255
256 /* invalidate the can_send() cache */
1fe75e33 257 if(mode_type == CHFL_BAN || mode_type == ModuleModes.CHFL_QUIET || mode_type == CHFL_EXCEPTION)
212380e3 258 chptr->bants++;
259
260 return 1;
261}
262
263/* del_id()
264 *
265 * inputs - channel, id to remove, type
266 * outputs - 0 on failure, 1 on success
267 * side effects - given id is removed from the appropriate list
268 */
269int
af81d5a0 270del_id(struct Channel *chptr, const char *banid, rb_dlink_list * list, long mode_type)
212380e3 271{
af81d5a0 272 rb_dlink_node *ptr;
212380e3 273 struct Ban *banptr;
274
275 if(EmptyString(banid))
276 return 0;
277
8e69bb4e 278 RB_DLINK_FOREACH(ptr, list->head)
212380e3 279 {
280 banptr = ptr->data;
281
282 if(irccmp(banid, banptr->banstr) == 0)
283 {
af81d5a0 284 rb_dlinkDelete(&banptr->node, list);
212380e3 285 free_ban(banptr);
286
287 /* invalidate the can_send() cache */
1fe75e33 288 if(mode_type == CHFL_BAN || mode_type == ModuleModes.CHFL_QUIET || mode_type == CHFL_EXCEPTION)
212380e3 289 chptr->bants++;
290
291 return 1;
292 }
293 }
294
295 return 0;
296}
297
298/* check_string()
299 *
300 * input - string to check
301 * output - pointer to 'fixed' string, or "*" if empty
302 * side effects - any white space found becomes \0
303 */
304static char *
305check_string(char *s)
306{
307 char *str = s;
308 static char splat[] = "*";
309 if(!(s && *s))
310 return splat;
311
312 for(; *s; ++s)
313 {
314 if(IsSpace(*s))
315 {
316 *s = '\0';
317 break;
318 }
319 }
320 return str;
321}
322
323/* pretty_mask()
324 *
325 * inputs - mask to pretty
326 * outputs - better version of the mask
327 * side effects - mask is chopped to limits, and transformed:
328 * x!y@z => x!y@z
329 * y@z => *!y@z
330 * x!y => x!y@*
331 * x => x!*@*
332 * z.d => *!*@z.d
333 */
334static char *
335pretty_mask(const char *idmask)
336{
337 static char mask_buf[BUFSIZE];
338 int old_mask_pos;
339 char *nick, *user, *host;
340 char splat[] = "*";
341 char *t, *at, *ex;
342 char ne = 0, ue = 0, he = 0; /* save values at nick[NICKLEN], et all */
343 char *mask;
344
345 mask = LOCAL_COPY(idmask);
346 mask = check_string(mask);
347 collapse(mask);
348
349 nick = user = host = splat;
350
351 if((size_t) BUFSIZE - mask_pos < strlen(mask) + 5)
352 return NULL;
353
354 old_mask_pos = mask_pos;
355
356 if (*mask == '$')
357 {
38e6acdd 358 mask_pos += rb_sprintf(mask_buf + mask_pos, "%s", mask) + 1;
212380e3 359 t = mask_buf + old_mask_pos + 1;
360 if (*t == '!')
361 *t = '~';
362 if (*t == '~')
363 t++;
364 *t = ToLower(*t);
365 return mask_buf + old_mask_pos;
366 }
367
368 at = ex = NULL;
369 if((t = strchr(mask, '@')) != NULL)
370 {
371 at = t;
372 *t++ = '\0';
373 if(*t != '\0')
374 host = t;
375
376 if((t = strchr(mask, '!')) != NULL)
377 {
378 ex = t;
379 *t++ = '\0';
380 if(*t != '\0')
381 user = t;
382 if(*mask != '\0')
383 nick = mask;
384 }
385 else
386 {
387 if(*mask != '\0')
388 user = mask;
389 }
390 }
391 else if((t = strchr(mask, '!')) != NULL)
392 {
393 ex = t;
394 *t++ = '\0';
395 if(*mask != '\0')
396 nick = mask;
397 if(*t != '\0')
398 user = t;
399 }
1229514e 400 else if(strchr(mask, '.') != NULL || strchr(mask, ':') != NULL || strchr(mask, '/') != NULL)
212380e3 401 {
402 if(*mask != '\0')
403 host = mask;
404 }
405 else
406 {
407 if(*mask != '\0')
408 nick = mask;
409 }
410
411 /* truncate values to max lengths */
412 if(strlen(nick) > NICKLEN - 1)
413 {
414 ne = nick[NICKLEN - 1];
415 nick[NICKLEN - 1] = '\0';
416 }
417 if(strlen(user) > USERLEN)
418 {
419 ue = user[USERLEN];
420 user[USERLEN] = '\0';
421 }
422 if(strlen(host) > HOSTLEN)
423 {
424 he = host[HOSTLEN];
425 host[HOSTLEN] = '\0';
426 }
427
38e6acdd 428 mask_pos += rb_sprintf(mask_buf + mask_pos, "%s!%s@%s", nick, user, host) + 1;
212380e3 429
430 /* restore mask, since we may need to use it again later */
431 if(at)
432 *at = '@';
433 if(ex)
434 *ex = '!';
435 if(ne)
436 nick[NICKLEN - 1] = ne;
437 if(ue)
438 user[USERLEN] = ue;
439 if(he)
440 host[HOSTLEN] = he;
441
442 return mask_buf + old_mask_pos;
443}
444
445/* fix_key()
446 *
447 * input - key to fix
448 * output - the same key, fixed
449 * side effects - anything below ascii 13 is discarded, ':' discarded,
450 * high ascii is dropped to lower half of ascii table
451 */
452static char *
453fix_key(char *arg)
454{
455 u_char *s, *t, c;
456
457 for(s = t = (u_char *) arg; (c = *s); s++)
458 {
459 c &= 0x7f;
460 if(c != ':' && c != ',' && c > ' ')
461 *t++ = c;
462 }
463
464 *t = '\0';
465 return arg;
466}
467
468/* fix_key_remote()
469 *
470 * input - key to fix
471 * ouput - the same key, fixed
472 * side effects - high ascii dropped to lower half of table,
473 * CR/LF/':' are dropped
474 */
475static char *
476fix_key_remote(char *arg)
477{
478 u_char *s, *t, c;
479
480 for(s = t = (u_char *) arg; (c = *s); s++)
481 {
482 c &= 0x7f;
483 if((c != 0x0a) && (c != ':') && (c != ',') && (c != 0x0d) && (c != ' '))
484 *t++ = c;
485 }
486
487 *t = '\0';
488 return arg;
489}
490
491/* chm_*()
492 *
493 * The handlers for each specific mode.
494 */
495void
496chm_nosuch(struct Client *source_p, struct Channel *chptr,
497 int alevel, int parc, int *parn,
498 const char **parv, int *errors, int dir, char c, long mode_type)
499{
500 if(*errors & SM_ERR_UNKNOWN)
501 return;
502 *errors |= SM_ERR_UNKNOWN;
503 sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
504}
505
506void
507chm_simple(struct Client *source_p, struct Channel *chptr,
508 int alevel, int parc, int *parn,
509 const char **parv, int *errors, int dir, char c, long mode_type)
510{
eccd1c58
JH
511
512 int override = 0;
d3b90aaa
G
513 struct Metadata *md;
514 struct DictionaryIter iter;
eccd1c58 515
c1c91f94 516 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
212380e3 517 {
eccd1c58
JH
518 if (IsOverride(source_p))
519 override = 1;
520 else
521 {
522 if(!(*errors & SM_ERR_NOOPS))
523 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
524 me.name, source_p->name, chptr->chname);
525 *errors |= SM_ERR_NOOPS;
526 return;
527 }
212380e3 528 }
529
c08f4515 530 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
212380e3 531 return;
532
533 /* setting + */
b72bd23a 534 if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
212380e3 535 {
536 /* if +f is disabled, ignore an attempt to set +QF locally */
1fe75e33 537 if(!ModuleModes.MODE_FORWARD && MyClient(source_p) &&
212380e3 538 (c == 'Q' || c == 'F'))
539 return;
540
541 chptr->mode.mode |= mode_type;
542
543 mode_changes[mode_count].letter = c;
544 mode_changes[mode_count].dir = MODE_ADD;
545 mode_changes[mode_count].caps = 0;
546 mode_changes[mode_count].nocaps = 0;
547 mode_changes[mode_count].id = NULL;
548 mode_changes[mode_count].mems = ALL_MEMBERS;
eccd1c58 549 mode_changes[mode_count].override = override;
058aa02c
VY
550 mode_changes[mode_count++].arg = NULL;
551 }
552 else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
553 {
8e3b2b85 554 /* cleanup metadata when the related mode is removed */
f0e0e567
JH
555 if(c == 'J')
556 {
557 DICTIONARY_FOREACH(md, &iter, chptr->metadata)
558 {
559 if(!strcmp(md->value, "KICKNOREJOIN"))
560 channel_metadata_delete(chptr, md->name, 0);
561 }
562 }
8e3b2b85 563 if(c == 'K')
67cecc2b 564 channel_metadata_delete(chptr, "NOREPEAT", 0);
d3b90aaa 565
058aa02c
VY
566 chptr->mode.mode &= ~mode_type;
567
568 mode_changes[mode_count].letter = c;
569 mode_changes[mode_count].dir = MODE_DEL;
570 mode_changes[mode_count].caps = 0;
571 mode_changes[mode_count].nocaps = 0;
572 mode_changes[mode_count].mems = ALL_MEMBERS;
573 mode_changes[mode_count].id = NULL;
eccd1c58 574 mode_changes[mode_count].override = override;
058aa02c
VY
575 mode_changes[mode_count++].arg = NULL;
576 }
577}
578
579void
580chm_orphaned(struct Client *source_p, struct Channel *chptr,
581 int alevel, int parc, int *parn,
582 const char **parv, int *errors, int dir, char c, long mode_type)
583{
584 if(MyClient(source_p))
585 return;
586
587 if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
588 {
589 chptr->mode.mode |= mode_type;
590
591 mode_changes[mode_count].letter = c;
592 mode_changes[mode_count].dir = MODE_ADD;
593 mode_changes[mode_count].caps = 0;
594 mode_changes[mode_count].nocaps = 0;
595 mode_changes[mode_count].id = NULL;
596 mode_changes[mode_count].mems = ALL_MEMBERS;
212380e3 597 mode_changes[mode_count++].arg = NULL;
598 }
b72bd23a 599 else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
212380e3 600 {
601 chptr->mode.mode &= ~mode_type;
602
603 mode_changes[mode_count].letter = c;
604 mode_changes[mode_count].dir = MODE_DEL;
605 mode_changes[mode_count].caps = 0;
606 mode_changes[mode_count].nocaps = 0;
607 mode_changes[mode_count].mems = ALL_MEMBERS;
608 mode_changes[mode_count].id = NULL;
609 mode_changes[mode_count++].arg = NULL;
610 }
611}
612
1cdd8fdf
JH
613void
614chm_hidden(struct Client *source_p, struct Channel *chptr,
615 int alevel, int parc, int *parn,
616 const char **parv, int *errors, int dir, char c, long mode_type)
617{
618 if(!IsOper(source_p) && !IsServer(source_p))
619 {
620 if(!(*errors & SM_ERR_NOPRIVS))
621 sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
622 *errors |= SM_ERR_NOPRIVS;
623 return;
624 }
625 if(MyClient(source_p) && !IsOperAdmin(source_p))
626 {
627 if(!(*errors & SM_ERR_NOPRIVS))
628 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name,
629 source_p->name, "cmodes");
630 *errors |= SM_ERR_NOPRIVS;
631 return;
632 }
633
634 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
635 return;
636
637 /* setting + */
638 if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
639 {
640 chptr->mode.mode |= mode_type;
641
642 mode_changes[mode_count].letter = c;
643 mode_changes[mode_count].dir = MODE_ADD;
644 mode_changes[mode_count].caps = 0;
645 mode_changes[mode_count].nocaps = 0;
646 mode_changes[mode_count].id = NULL;
647 mode_changes[mode_count].mems = ONLY_OPERS;
648 mode_changes[mode_count].override = 0;
649 mode_changes[mode_count++].arg = NULL;
650 }
651 else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
652 {
653 chptr->mode.mode &= ~mode_type;
654
655 mode_changes[mode_count].letter = c;
656 mode_changes[mode_count].dir = MODE_DEL;
657 mode_changes[mode_count].caps = 0;
658 mode_changes[mode_count].nocaps = 0;
659 mode_changes[mode_count].mems = ONLY_OPERS;
660 mode_changes[mode_count].id = NULL;
661 mode_changes[mode_count].override = 0;
662 mode_changes[mode_count++].arg = NULL;
663 }
664}
665
212380e3 666void
667chm_staff(struct Client *source_p, struct Channel *chptr,
668 int alevel, int parc, int *parn,
669 const char **parv, int *errors, int dir, char c, long mode_type)
670{
92b26e74
G
671 int override = 0;
672
212380e3 673 if(!IsOper(source_p) && !IsServer(source_p))
674 {
675 if(!(*errors & SM_ERR_NOPRIVS))
676 sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
677 *errors |= SM_ERR_NOPRIVS;
678 return;
679 }
1ef5b430
JT
680 if(MyClient(source_p) && !IsOperResv(source_p))
681 {
682 if(!(*errors & SM_ERR_NOPRIVS))
683 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name,
684 source_p->name, "resv");
685 *errors |= SM_ERR_NOPRIVS;
686 return;
687 }
212380e3 688
92b26e74
G
689 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
690 {
691 if (IsOverride(source_p))
692 override = 1;
693 else
694 {
695 if(!(*errors & SM_ERR_NOOPS))
696 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
697 me.name, source_p->name, chptr->chname);
698 *errors |= SM_ERR_NOOPS;
699 return;
700 }
701 }
702
c08f4515
JT
703 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
704 return;
705
212380e3 706 /* setting + */
707 if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
708 {
709 chptr->mode.mode |= mode_type;
710
711 mode_changes[mode_count].letter = c;
712 mode_changes[mode_count].dir = MODE_ADD;
713 mode_changes[mode_count].caps = 0;
714 mode_changes[mode_count].nocaps = 0;
715 mode_changes[mode_count].id = NULL;
716 mode_changes[mode_count].mems = ALL_MEMBERS;
92b26e74 717 mode_changes[mode_count].override = override;
212380e3 718 mode_changes[mode_count++].arg = NULL;
719 }
720 else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
721 {
722 chptr->mode.mode &= ~mode_type;
723
724 mode_changes[mode_count].letter = c;
725 mode_changes[mode_count].dir = MODE_DEL;
726 mode_changes[mode_count].caps = 0;
727 mode_changes[mode_count].nocaps = 0;
728 mode_changes[mode_count].mems = ALL_MEMBERS;
92b26e74 729 mode_changes[mode_count].override = override;
212380e3 730 mode_changes[mode_count].id = NULL;
731 mode_changes[mode_count++].arg = NULL;
732 }
733}
734
735void
736chm_ban(struct Client *source_p, struct Channel *chptr,
737 int alevel, int parc, int *parn,
738 const char **parv, int *errors, int dir, char c, long mode_type)
739{
740 const char *mask;
741 const char *raw_mask;
af81d5a0
WP
742 rb_dlink_list *list;
743 rb_dlink_node *ptr;
212380e3 744 struct Ban *banptr;
745 int errorval;
746 int rpl_list;
747 int rpl_endlist;
748 int caps;
749 int mems;
4ed822ed 750 int override = 0;
212380e3 751
1fe75e33 752 if(mode_type == CHFL_BAN)
212380e3 753 {
212380e3 754 list = &chptr->banlist;
755 errorval = SM_ERR_RPL_B;
756 rpl_list = RPL_BANLIST;
757 rpl_endlist = RPL_ENDOFBANLIST;
758 mems = ALL_MEMBERS;
759 caps = 0;
1fe75e33
G
760 }
761 else if(mode_type == CHFL_EXCEPTION)
762 {
212380e3 763 /* if +e is disabled, allow all but +e locally */
764 if(!ConfigChannel.use_except && MyClient(source_p) &&
765 ((dir == MODE_ADD) && (parc > *parn)))
766 return;
767
768 list = &chptr->exceptlist;
769 errorval = SM_ERR_RPL_E;
770 rpl_list = RPL_EXCEPTLIST;
771 rpl_endlist = RPL_ENDOFEXCEPTLIST;
772 caps = CAP_EX;
773
774 if(ConfigChannel.use_except || (dir == MODE_DEL))
775 mems = ONLY_CHANOPS;
776 else
777 mems = ONLY_SERVERS;
1fe75e33
G
778 }
779 else if(mode_type == CHFL_INVEX)
780 {
212380e3 781 /* if +I is disabled, allow all but +I locally */
782 if(!ConfigChannel.use_invex && MyClient(source_p) &&
783 (dir == MODE_ADD) && (parc > *parn))
784 return;
785
786 list = &chptr->invexlist;
787 errorval = SM_ERR_RPL_I;
788 rpl_list = RPL_INVITELIST;
789 rpl_endlist = RPL_ENDOFINVITELIST;
790 caps = CAP_IE;
791
792 if(ConfigChannel.use_invex || (dir == MODE_DEL))
793 mems = ONLY_CHANOPS;
794 else
795 mems = ONLY_SERVERS;
1fe75e33
G
796 }
797 else if(mode_type == ModuleModes.CHFL_QUIET)
798 {
212380e3 799 list = &chptr->quietlist;
800 errorval = SM_ERR_RPL_Q;
360742bd
A
801 rpl_list = RPL_QUIETLIST;
802 rpl_endlist = RPL_ENDOFQUIETLIST;
212380e3 803 mems = ALL_MEMBERS;
804 caps = 0;
1fe75e33
G
805 }
806 else
807 {
212380e3 808 sendto_realops_snomask(SNO_GENERAL, L_ALL, "chm_ban() called with unknown type!");
809 return;
212380e3 810 }
811
812 if(dir == 0 || parc <= *parn)
813 {
814 if((*errors & errorval) != 0)
815 return;
816 *errors |= errorval;
817
818 /* non-ops cant see +eI lists.. */
c1c91f94 819 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP && mode_type != CHFL_BAN &&
1fe75e33 820 mode_type != ModuleModes.CHFL_QUIET)
212380e3 821 {
4ed822ed 822 if(IsOverride(source_p))
cb097b88 823 {
34d8ef4d 824 sendto_wallops_flags(UMODE_WALLOP, &me,
cb097b88 825 "%s is overriding modes on %s: (%s list)",
34d8ef4d
JH
826 get_oper_name(source_p), chptr->chname, mode_type == CHFL_INVEX ? "invex" : "exempt");
827 sendto_server(NULL, chptr, NOCAPS, NOCAPS,
828 ":%s WALLOPS :%s is overriding modes on %s: (%s list)",
71ea6069 829 me.name, get_oper_name(source_p), chptr->chname, mode_type == CHFL_INVEX ? "invex" : "exempt");
cb097b88 830 }
4ed822ed
JH
831 else
832 {
833
834 if(!(*errors & SM_ERR_NOOPS))
835 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
836 me.name, source_p->name, chptr->chname);
837 *errors |= SM_ERR_NOOPS;
838 return;
839 }
212380e3 840 }
841
8e69bb4e 842 RB_DLINK_FOREACH(ptr, list->head)
212380e3 843 {
844 banptr = ptr->data;
845 sendto_one(source_p, form_str(rpl_list),
846 me.name, source_p->name, chptr->chname,
847 banptr->banstr, banptr->who, banptr->when);
848 }
360742bd 849 sendto_one(source_p, form_str(rpl_endlist), me.name, source_p->name, chptr->chname);
212380e3 850 return;
851 }
852
c1c91f94 853 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
212380e3 854 {
4ed822ed
JH
855 if(IsOverride(source_p))
856 override = 1;
857 else
858 {
859
860 if(!(*errors & SM_ERR_NOOPS))
861 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
862 me.name, source_p->name, chptr->chname);
863 *errors |= SM_ERR_NOOPS;
864 return;
865 }
212380e3 866 }
867
868 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
869 return;
870
871 raw_mask = parv[(*parn)];
872 (*parn)++;
873
874 /* empty ban, or starts with ':' which messes up s2s, ignore it */
875 if(EmptyString(raw_mask) || *raw_mask == ':')
876 return;
877
878 if(!MyClient(source_p))
879 {
880 if(strchr(raw_mask, ' '))
881 return;
882
883 mask = raw_mask;
884 }
885 else
886 mask = pretty_mask(raw_mask);
887
83294285 888 /* we'd have problems parsing this, hyb6 does it too
889 * also make sure it will always fit on a line with channel
890 * name etc.
891 */
892 if(strlen(mask) > IRCD_MIN(BANLEN, MODEBUFLEN - 5))
212380e3 893 return;
894
895 /* if we're adding a NEW id */
896 if(dir == MODE_ADD)
897 {
898 if (*mask == '$' && MyClient(source_p))
899 {
900 if (!valid_extban(mask, source_p, chptr, mode_type))
901 /* XXX perhaps return an error message here */
902 return;
903 }
904
905 /* dont allow local clients to overflow the banlist, dont
906 * let remote servers set duplicate bans
907 */
908 if(!add_id(source_p, chptr, mask, list, mode_type))
909 return;
910
911 mode_changes[mode_count].letter = c;
912 mode_changes[mode_count].dir = MODE_ADD;
913 mode_changes[mode_count].caps = caps;
914 mode_changes[mode_count].nocaps = 0;
915 mode_changes[mode_count].mems = mems;
916 mode_changes[mode_count].id = NULL;
4ed822ed 917 mode_changes[mode_count].override = override;
212380e3 918 mode_changes[mode_count++].arg = mask;
919 }
920 else if(dir == MODE_DEL)
921 {
922 if(del_id(chptr, mask, list, mode_type) == 0)
923 {
924 /* mask isn't a valid ban, check raw_mask */
925 if(del_id(chptr, raw_mask, list, mode_type))
926 mask = raw_mask;
927 }
928
929 mode_changes[mode_count].letter = c;
930 mode_changes[mode_count].dir = MODE_DEL;
931 mode_changes[mode_count].caps = caps;
932 mode_changes[mode_count].nocaps = 0;
933 mode_changes[mode_count].mems = mems;
934 mode_changes[mode_count].id = NULL;
4ed822ed 935 mode_changes[mode_count].override = override;
212380e3 936 mode_changes[mode_count++].arg = mask;
937 }
938}
939
82f8e812 940void
c1c91f94 941chm_admin(struct Client *source_p, struct Channel *chptr,
82f8e812
G
942 int alevel, int parc, int *parn,
943 const char **parv, int *errors, int dir, char c, long mode_type)
944{
945 struct membership *mstptr;
c1c91f94 946 const char *adminnick;
82f8e812 947 struct Client *targ_p;
4ed822ed 948 int override = 0;
82f8e812 949
c1c91f94 950 if(!ConfigChannel.use_admin)
82f8e812
G
951 {
952 if(*errors & SM_ERR_UNKNOWN)
953 return;
954 *errors |= SM_ERR_UNKNOWN;
955 sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
956 return;
957 }
958
c1c91f94 959 if(alevel != CHFL_ADMIN)
82f8e812 960 {
4ed822ed
JH
961 if(IsOverride(source_p))
962 override = 1;
963 else
964 {
965
966 if(!(*errors & SM_ERR_NOOPS))
c809010b 967 sendto_one(source_p, ":%s 482 %s %s :You're not a channel administrator", me.name, source_p->name, chptr->chname);
4ed822ed
JH
968 *errors |= SM_ERR_NOOPS;
969 return;
970 }
82f8e812
G
971 }
972
973 if((dir == MODE_QUERY) || (parc <= *parn))
974 return;
975
c1c91f94 976 adminnick = parv[(*parn)];
82f8e812
G
977 (*parn)++;
978
979 /* empty nick */
c1c91f94 980 if(EmptyString(adminnick))
82f8e812
G
981 {
982 sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
983 return;
984 }
985
c1c91f94 986 if((targ_p = find_chasing(source_p, adminnick, NULL)) == NULL)
82f8e812
G
987 {
988 return;
989 }
990
991 mstptr = find_channel_membership(chptr, targ_p);
992
993 if(mstptr == NULL)
994 {
995 if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
996 sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
c1c91f94 997 form_str(ERR_USERNOTINCHANNEL), adminnick, chptr->chname);
82f8e812
G
998 *errors |= SM_ERR_NOTONCHANNEL;
999 return;
1000 }
1001
1002 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1003 return;
1004
1005 if(dir == MODE_ADD)
1006 {
1007 if(targ_p == source_p)
4ed822ed
JH
1008 {
1009 no_override_deop = 1;
cb097b88
JH
1010 /* Don't reject modes from remote. It desyncs, and this is perfectly
1011 * legitimate from a remote override oper.
4ed822ed
JH
1012 if(!override)
1013 return;
cb097b88 1014 */
4ed822ed 1015 }
82f8e812
G
1016
1017 mode_changes[mode_count].letter = c;
1018 mode_changes[mode_count].dir = MODE_ADD;
1019 mode_changes[mode_count].caps = 0;
1020 mode_changes[mode_count].nocaps = 0;
1021 mode_changes[mode_count].mems = ALL_MEMBERS;
1022 mode_changes[mode_count].id = targ_p->id;
1023 mode_changes[mode_count].arg = targ_p->name;
4ed822ed 1024 mode_changes[mode_count].override = override;
82f8e812
G
1025 mode_changes[mode_count++].client = targ_p;
1026
c1c91f94 1027 mstptr->flags |= CHFL_ADMIN;
82f8e812
G
1028 }
1029 else
1030 {
1031 if(MyClient(source_p) && IsService(targ_p))
1032 {
1033 sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
1034 me.name, source_p->name, targ_p->name, chptr->chname);
1035 return;
1036 }
1037
1038 mode_changes[mode_count].letter = c;
1039 mode_changes[mode_count].dir = MODE_DEL;
1040 mode_changes[mode_count].caps = 0;
1041 mode_changes[mode_count].nocaps = 0;
1042 mode_changes[mode_count].mems = ALL_MEMBERS;
1043 mode_changes[mode_count].id = targ_p->id;
1044 mode_changes[mode_count].arg = targ_p->name;
4ed822ed 1045 mode_changes[mode_count].override = override;
82f8e812
G
1046 mode_changes[mode_count++].client = targ_p;
1047
c1c91f94 1048 mstptr->flags &= ~CHFL_ADMIN;
82f8e812
G
1049 }
1050}
1051
212380e3 1052void
1053chm_op(struct Client *source_p, struct Channel *chptr,
1054 int alevel, int parc, int *parn,
1055 const char **parv, int *errors, int dir, char c, long mode_type)
1056{
1057 struct membership *mstptr;
1058 const char *opnick;
1059 struct Client *targ_p;
4ed822ed 1060 int override = 0;
212380e3 1061
c1c91f94 1062 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN)
212380e3 1063 {
4ed822ed
JH
1064 if(IsOverride(source_p))
1065 override = 1;
1066 else
1067 {
1068
1069 if(!(*errors & SM_ERR_NOOPS))
1070 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1071 me.name, source_p->name, chptr->chname);
1072 *errors |= SM_ERR_NOOPS;
1073 return;
1074 }
212380e3 1075 }
1076
1077 if((dir == MODE_QUERY) || (parc <= *parn))
1078 return;
1079
1080 opnick = parv[(*parn)];
1081 (*parn)++;
1082
1083 /* empty nick */
1084 if(EmptyString(opnick))
1085 {
1086 sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
1087 return;
1088 }
1089
1090 if((targ_p = find_chasing(source_p, opnick, NULL)) == NULL)
1091 {
1092 return;
1093 }
1094
1095 mstptr = find_channel_membership(chptr, targ_p);
1096
1097 if(mstptr == NULL)
1098 {
1099 if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
1100 sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
1101 form_str(ERR_USERNOTINCHANNEL), opnick, chptr->chname);
1102 *errors |= SM_ERR_NOTONCHANNEL;
1103 return;
1104 }
1105
1106 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1107 return;
1108
1109 if(dir == MODE_ADD)
1110 {
1111 if(targ_p == source_p)
4ed822ed
JH
1112 {
1113 no_override_deop = 1;
cb097b88
JH
1114 /* Don't reject modes from remote. It desyncs, and this is perfectly
1115 * legitimate from a remote override oper.
4ed822ed
JH
1116 if(!override)
1117 return;
cb097b88 1118 */
4ed822ed 1119 }
212380e3 1120
1121 mode_changes[mode_count].letter = c;
1122 mode_changes[mode_count].dir = MODE_ADD;
1123 mode_changes[mode_count].caps = 0;
1124 mode_changes[mode_count].nocaps = 0;
1125 mode_changes[mode_count].mems = ALL_MEMBERS;
1126 mode_changes[mode_count].id = targ_p->id;
1127 mode_changes[mode_count].arg = targ_p->name;
4ed822ed 1128 mode_changes[mode_count].override = override;
212380e3 1129 mode_changes[mode_count++].client = targ_p;
1130
1131 mstptr->flags |= CHFL_CHANOP;
212380e3 1132 }
1133 else
1134 {
1135 if(MyClient(source_p) && IsService(targ_p))
1136 {
1137 sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
1138 me.name, source_p->name, targ_p->name, chptr->chname);
1139 return;
1140 }
1141
1142 mode_changes[mode_count].letter = c;
1143 mode_changes[mode_count].dir = MODE_DEL;
1144 mode_changes[mode_count].caps = 0;
1145 mode_changes[mode_count].nocaps = 0;
1146 mode_changes[mode_count].mems = ALL_MEMBERS;
1147 mode_changes[mode_count].id = targ_p->id;
1148 mode_changes[mode_count].arg = targ_p->name;
4ed822ed 1149 mode_changes[mode_count].override = override;
212380e3 1150 mode_changes[mode_count++].client = targ_p;
1151
1152 mstptr->flags &= ~CHFL_CHANOP;
1153 }
1154}
1155
82f8e812
G
1156void
1157chm_halfop(struct Client *source_p, struct Channel *chptr,
1158 int alevel, int parc, int *parn,
1159 const char **parv, int *errors, int dir, char c, long mode_type)
1160{
1161 struct membership *mstptr;
1162 const char *halfopnick;
1163 struct Client *targ_p;
4ed822ed 1164 int override = 0;
82f8e812
G
1165
1166 if(!ConfigChannel.use_halfop)
1167 {
1168 if(*errors & SM_ERR_UNKNOWN)
1169 return;
1170 *errors |= SM_ERR_UNKNOWN;
1171 sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
1172 return;
1173 }
1174
c1c91f94 1175 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN)
82f8e812 1176 {
4ed822ed
JH
1177 if(IsOverride(source_p))
1178 override = 1;
1179 else
1180 {
1181
1182 if(!(*errors & SM_ERR_NOOPS))
1183 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1184 me.name, source_p->name, chptr->chname);
1185 *errors |= SM_ERR_NOOPS;
1186 return;
1187 }
82f8e812
G
1188 }
1189
1190 if((dir == MODE_QUERY) || (parc <= *parn))
1191 return;
1192
1193 halfopnick = parv[(*parn)];
1194 (*parn)++;
1195
1196 /* empty nick */
1197 if(EmptyString(halfopnick))
1198 {
1199 sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
1200 return;
1201 }
1202
1203 if((targ_p = find_chasing(source_p, halfopnick, NULL)) == NULL)
1204 {
1205 return;
1206 }
1207
1208 mstptr = find_channel_membership(chptr, targ_p);
1209
1210 if(mstptr == NULL)
1211 {
1212 if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
1213 sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
1214 form_str(ERR_USERNOTINCHANNEL), halfopnick, chptr->chname);
1215 *errors |= SM_ERR_NOTONCHANNEL;
1216 return;
1217 }
1218
1219 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1220 return;
1221
1222 if(dir == MODE_ADD)
1223 {
1224 if(targ_p == source_p)
4ed822ed
JH
1225 {
1226 no_override_deop = 1;
cb097b88
JH
1227 /* Don't reject modes from remote. It desyncs, and this is perfectly
1228 * legitimate from a remote override oper.
4ed822ed
JH
1229 if(!override)
1230 return;
cb097b88 1231 */
4ed822ed 1232 }
82f8e812
G
1233
1234 mode_changes[mode_count].letter = c;
1235 mode_changes[mode_count].dir = MODE_ADD;
1236 mode_changes[mode_count].caps = 0;
1237 mode_changes[mode_count].nocaps = 0;
1238 mode_changes[mode_count].mems = ALL_MEMBERS;
1239 mode_changes[mode_count].id = targ_p->id;
1240 mode_changes[mode_count].arg = targ_p->name;
4ed822ed 1241 mode_changes[mode_count].override = override;
82f8e812
G
1242 mode_changes[mode_count++].client = targ_p;
1243
1244 mstptr->flags |= CHFL_HALFOP;
1245 }
1246 else
1247 {
1248 if(MyClient(source_p) && IsService(targ_p))
1249 {
1250 sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
1251 me.name, source_p->name, targ_p->name, chptr->chname);
1252 return;
1253 }
1254
1255 mode_changes[mode_count].letter = c;
1256 mode_changes[mode_count].dir = MODE_DEL;
1257 mode_changes[mode_count].caps = 0;
1258 mode_changes[mode_count].nocaps = 0;
1259 mode_changes[mode_count].mems = ALL_MEMBERS;
1260 mode_changes[mode_count].id = targ_p->id;
1261 mode_changes[mode_count].arg = targ_p->name;
4ed822ed 1262 mode_changes[mode_count].override = override;
82f8e812
G
1263 mode_changes[mode_count++].client = targ_p;
1264
1265 mstptr->flags &= ~CHFL_HALFOP;
1266 }
1267}
1268
212380e3 1269void
1270chm_voice(struct Client *source_p, struct Channel *chptr,
1271 int alevel, int parc, int *parn,
1272 const char **parv, int *errors, int dir, char c, long mode_type)
1273{
1274 struct membership *mstptr;
1275 const char *opnick;
1276 struct Client *targ_p;
4ed822ed 1277 int override = 0;
212380e3 1278
c1c91f94 1279 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
212380e3 1280 {
4ed822ed
JH
1281 if(IsOverride(source_p))
1282 override = 1;
1283 else
1284 {
1285
1286 if(!(*errors & SM_ERR_NOOPS))
1287 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1288 me.name, source_p->name, chptr->chname);
1289 *errors |= SM_ERR_NOOPS;
1290 return;
1291 }
212380e3 1292 }
1293
1294 if((dir == MODE_QUERY) || parc <= *parn)
1295 return;
1296
1297 opnick = parv[(*parn)];
1298 (*parn)++;
1299
1300 /* empty nick */
1301 if(EmptyString(opnick))
1302 {
1303 sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
1304 return;
1305 }
1306
1307 if((targ_p = find_chasing(source_p, opnick, NULL)) == NULL)
1308 {
1309 return;
1310 }
1311
1312 mstptr = find_channel_membership(chptr, targ_p);
1313
1314 if(mstptr == NULL)
1315 {
1316 if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
1317 sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
1318 form_str(ERR_USERNOTINCHANNEL), opnick, chptr->chname);
1319 *errors |= SM_ERR_NOTONCHANNEL;
1320 return;
1321 }
1322
1323 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1324 return;
1325
1326 if(dir == MODE_ADD)
1327 {
1328 mode_changes[mode_count].letter = c;
1329 mode_changes[mode_count].dir = MODE_ADD;
1330 mode_changes[mode_count].caps = 0;
1331 mode_changes[mode_count].nocaps = 0;
1332 mode_changes[mode_count].mems = ALL_MEMBERS;
1333 mode_changes[mode_count].id = targ_p->id;
1334 mode_changes[mode_count].arg = targ_p->name;
4ed822ed 1335 mode_changes[mode_count].override = override;
212380e3 1336 mode_changes[mode_count++].client = targ_p;
1337
1338 mstptr->flags |= CHFL_VOICE;
1339 }
1340 else
1341 {
1342 mode_changes[mode_count].letter = 'v';
1343 mode_changes[mode_count].dir = MODE_DEL;
1344 mode_changes[mode_count].caps = 0;
1345 mode_changes[mode_count].nocaps = 0;
1346 mode_changes[mode_count].mems = ALL_MEMBERS;
1347 mode_changes[mode_count].id = targ_p->id;
1348 mode_changes[mode_count].arg = targ_p->name;
4ed822ed 1349 mode_changes[mode_count].override = override;
212380e3 1350 mode_changes[mode_count++].client = targ_p;
1351
1352 mstptr->flags &= ~CHFL_VOICE;
1353 }
1354}
1355
1356void
1357chm_limit(struct Client *source_p, struct Channel *chptr,
1358 int alevel, int parc, int *parn,
1359 const char **parv, int *errors, int dir, char c, long mode_type)
1360{
1361 const char *lstr;
1362 static char limitstr[30];
1363 int limit;
b869e117 1364 int override = 0;
212380e3 1365
c1c91f94 1366 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
212380e3 1367 {
b869e117
JH
1368 if(IsOverride(source_p))
1369 override = 1;
1370 else
1371 {
1372 if(!(*errors & SM_ERR_NOOPS))
1373 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1374 me.name, source_p->name, chptr->chname);
1375 *errors |= SM_ERR_NOOPS;
1376 return;
1377 }
212380e3 1378 }
1379
1380 if(dir == MODE_QUERY)
1381 return;
1382
c08f4515
JT
1383 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1384 return;
1385
212380e3 1386 if((dir == MODE_ADD) && parc > *parn)
1387 {
1388 lstr = parv[(*parn)];
1389 (*parn)++;
1390
1391 if(EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
1392 return;
1393
38e6acdd 1394 rb_sprintf(limitstr, "%d", limit);
212380e3 1395
1396 mode_changes[mode_count].letter = c;
1397 mode_changes[mode_count].dir = MODE_ADD;
1398 mode_changes[mode_count].caps = 0;
1399 mode_changes[mode_count].nocaps = 0;
1400 mode_changes[mode_count].mems = ALL_MEMBERS;
1401 mode_changes[mode_count].id = NULL;
b869e117 1402 mode_changes[mode_count].override = override;
212380e3 1403 mode_changes[mode_count++].arg = limitstr;
1404
1405 chptr->mode.limit = limit;
1406 }
1407 else if(dir == MODE_DEL)
1408 {
1409 if(!chptr->mode.limit)
1410 return;
1411
1412 chptr->mode.limit = 0;
1413
1414 mode_changes[mode_count].letter = c;
1415 mode_changes[mode_count].dir = MODE_DEL;
1416 mode_changes[mode_count].caps = 0;
1417 mode_changes[mode_count].nocaps = 0;
1418 mode_changes[mode_count].mems = ALL_MEMBERS;
1419 mode_changes[mode_count].id = NULL;
b869e117 1420 mode_changes[mode_count].override = override;
212380e3 1421 mode_changes[mode_count++].arg = NULL;
1422 }
1423}
1424
1425void
1426chm_throttle(struct Client *source_p, struct Channel *chptr,
1427 int alevel, int parc, int *parn,
1428 const char **parv, int *errors, int dir, char c, long mode_type)
1429{
1430 int joins = 0, timeslice = 0;
b869e117 1431 int override = 0;
212380e3 1432
c1c91f94 1433 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
212380e3 1434 {
b869e117
JH
1435 if(IsOverride(source_p))
1436 override = 1;
1437 else
1438 {
1439
1440 if(!(*errors & SM_ERR_NOOPS))
1441 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1442 me.name, source_p->name, chptr->chname);
1443 *errors |= SM_ERR_NOOPS;
1444 return;
1445 }
212380e3 1446 }
1447
1448 if(dir == MODE_QUERY)
1449 return;
1450
c08f4515
JT
1451 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1452 return;
1453
212380e3 1454 if((dir == MODE_ADD) && parc > *parn)
1455 {
1456 sscanf(parv[(*parn)], "%d:%d", &joins, &timeslice);
1457
1458 if(!joins || !timeslice)
1459 return;
1460
1461 mode_changes[mode_count].letter = c;
1462 mode_changes[mode_count].dir = MODE_ADD;
1463 mode_changes[mode_count].caps = 0;
1464 mode_changes[mode_count].nocaps = 0;
1465 mode_changes[mode_count].mems = ALL_MEMBERS;
1466 mode_changes[mode_count].id = NULL;
b869e117 1467 mode_changes[mode_count].override = override;
212380e3 1468 mode_changes[mode_count++].arg = parv[(*parn)];
1469
1470 (*parn)++;
1471
1472 chptr->mode.join_num = joins;
1473 chptr->mode.join_time = timeslice;
1474 }
1475 else if(dir == MODE_DEL)
1476 {
1477 if(!chptr->mode.join_num)
1478 return;
1479
1480 chptr->mode.join_num = 0;
1481 chptr->mode.join_time = 0;
1482 chptr->join_count = 0;
1483 chptr->join_delta = 0;
1484
1485 mode_changes[mode_count].letter = c;
1486 mode_changes[mode_count].dir = MODE_DEL;
1487 mode_changes[mode_count].caps = 0;
1488 mode_changes[mode_count].nocaps = 0;
1489 mode_changes[mode_count].mems = ALL_MEMBERS;
1490 mode_changes[mode_count].id = NULL;
b869e117 1491 mode_changes[mode_count].override = override;
212380e3 1492 mode_changes[mode_count++].arg = NULL;
1493 }
1494}
1495
1496void
1497chm_forward(struct Client *source_p, struct Channel *chptr,
1498 int alevel, int parc, int *parn,
1499 const char **parv, int *errors, int dir, char c, long mode_type)
1500{
1501 struct Channel *targptr = NULL;
1502 struct membership *msptr;
1503 const char *forward;
b869e117 1504 int override = 0;
212380e3 1505
1506 /* if +f is disabled, ignore local attempts to set it */
1fe75e33 1507 if(!ModuleModes.MODE_FORWARD && MyClient(source_p) &&
212380e3 1508 (dir == MODE_ADD) && (parc > *parn))
1509 return;
1510
1511 if(dir == MODE_QUERY || (dir == MODE_ADD && parc <= *parn))
1512 {
1513 if (!(*errors & SM_ERR_RPL_F))
1514 {
1515 if (*chptr->mode.forward == '\0')
5366977b 1516 sendto_one_notice(source_p, ":%s has no forward channel", chptr->chname);
212380e3 1517 else
5366977b 1518 sendto_one_notice(source_p, ":%s forward channel is %s", chptr->chname, chptr->mode.forward);
212380e3 1519 *errors |= SM_ERR_RPL_F;
1520 }
1521 return;
1522 }
1523
1524#ifndef FORWARD_OPERONLY
c1c91f94 1525 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
212380e3 1526 {
b869e117
JH
1527 if(IsOverride(source_p))
1528 override = 1;
1529 else
1530 {
1531 if(!(*errors & SM_ERR_NOOPS))
1532 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1533 me.name, source_p->name, chptr->chname);
1534 *errors |= SM_ERR_NOOPS;
1535 return;
1536 }
212380e3 1537 }
1538#else
1539 if(!IsOper(source_p) && !IsServer(source_p))
1540 {
1541 if(!(*errors & SM_ERR_NOPRIVS))
1542 sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
1543 *errors |= SM_ERR_NOPRIVS;
1544 return;
1545 }
1546#endif
1547
c08f4515
JT
1548 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1549 return;
1550
212380e3 1551 if(dir == MODE_ADD && parc > *parn)
1552 {
1553 forward = parv[(*parn)];
1554 (*parn)++;
1555
1556 if(EmptyString(forward))
1557 return;
1558 if(!check_channel_name(forward) ||
1559 (MyClient(source_p) && (strlen(forward) > LOC_CHANNELLEN || hash_find_resv(forward))))
1560 {
1561 sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), forward);
1562 return;
1563 }
1564 /* don't forward to inconsistent target -- jilles */
1565 if(chptr->chname[0] == '#' && forward[0] == '&')
1566 {
1567 sendto_one_numeric(source_p, ERR_BADCHANNAME,
1568 form_str(ERR_BADCHANNAME), forward);
1569 return;
1570 }
1571 if(MyClient(source_p) && (targptr = find_channel(forward)) == NULL)
1572 {
1573 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
1574 form_str(ERR_NOSUCHCHANNEL), forward);
1575 return;
1576 }
1fe75e33 1577 if(MyClient(source_p) && !(targptr->mode.mode & ModuleModes.MODE_FREETARGET))
212380e3 1578 {
1579 if((msptr = find_channel_membership(targptr, source_p)) == NULL ||
1fe75e33 1580 !is_any_op(msptr))
212380e3 1581 {
b869e117
JH
1582 if(IsOverride(source_p))
1583 override = 1;
1584 else
1585 {
1586 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1587 me.name, source_p->name, targptr->chname);
1588 return;
1589 }
212380e3 1590 }
1591 }
1592
907468c4 1593 rb_strlcpy(chptr->mode.forward, forward, sizeof(chptr->mode.forward));
212380e3 1594
1595 mode_changes[mode_count].letter = c;
1596 mode_changes[mode_count].dir = MODE_ADD;
1597 mode_changes[mode_count].caps = 0;
1598 mode_changes[mode_count].nocaps = 0;
1fe75e33 1599 mode_changes[mode_count].mems = ModuleModes.MODE_FORWARD ? ALL_MEMBERS : ONLY_SERVERS;
212380e3 1600 mode_changes[mode_count].id = NULL;
b869e117 1601 mode_changes[mode_count].override = override;
212380e3 1602 mode_changes[mode_count++].arg = forward;
1603 }
1604 else if(dir == MODE_DEL)
1605 {
1606 if(!(*chptr->mode.forward))
1607 return;
1608
1609 *chptr->mode.forward = '\0';
1610
1611 mode_changes[mode_count].letter = c;
1612 mode_changes[mode_count].dir = MODE_DEL;
1613 mode_changes[mode_count].caps = 0;
1614 mode_changes[mode_count].nocaps = 0;
1615 mode_changes[mode_count].mems = ALL_MEMBERS;
1616 mode_changes[mode_count].id = NULL;
b869e117 1617 mode_changes[mode_count].override = override;
212380e3 1618 mode_changes[mode_count++].arg = NULL;
1619 }
1620}
1621
1622void
1623chm_key(struct Client *source_p, struct Channel *chptr,
1624 int alevel, int parc, int *parn,
1625 const char **parv, int *errors, int dir, char c, long mode_type)
1626{
1627 char *key;
b869e117 1628 int override = 0;
212380e3 1629
c1c91f94 1630 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
212380e3 1631 {
b869e117
JH
1632 if(IsOverride(source_p))
1633 override = 1;
1634 else
1635 {
1636 if(!(*errors & SM_ERR_NOOPS))
1637 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1638 me.name, source_p->name, chptr->chname);
1639 *errors |= SM_ERR_NOOPS;
1640 return;
1641 }
212380e3 1642 }
1643
1644 if(dir == MODE_QUERY)
1645 return;
1646
c08f4515
JT
1647 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1648 return;
1649
212380e3 1650 if((dir == MODE_ADD) && parc > *parn)
1651 {
1652 key = LOCAL_COPY(parv[(*parn)]);
1653 (*parn)++;
1654
1655 if(MyClient(source_p))
1656 fix_key(key);
1657 else
1658 fix_key_remote(key);
1659
1660 if(EmptyString(key))
1661 return;
1662
1663 s_assert(key[0] != ' ');
907468c4 1664 rb_strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
212380e3 1665
1666 mode_changes[mode_count].letter = c;
1667 mode_changes[mode_count].dir = MODE_ADD;
1668 mode_changes[mode_count].caps = 0;
1669 mode_changes[mode_count].nocaps = 0;
1670 mode_changes[mode_count].mems = ALL_MEMBERS;
1671 mode_changes[mode_count].id = NULL;
b869e117 1672 mode_changes[mode_count].override = override;
212380e3 1673 mode_changes[mode_count++].arg = chptr->mode.key;
1674 }
1675 else if(dir == MODE_DEL)
1676 {
1677 static char splat[] = "*";
1678 int i;
1679
1680 if(parc > *parn)
1681 (*parn)++;
1682
1683 if(!(*chptr->mode.key))
1684 return;
1685
1686 /* hack time. when we get a +k-k mode, the +k arg is
1687 * chptr->mode.key, which the -k sets to \0, so hunt for a
1688 * +k when we get a -k, and set the arg to splat. --anfl
1689 */
1690 for(i = 0; i < mode_count; i++)
1691 {
1692 if(mode_changes[i].letter == 'k' && mode_changes[i].dir == MODE_ADD)
1693 mode_changes[i].arg = splat;
1694 }
1695
1696 *chptr->mode.key = 0;
1697
1698 mode_changes[mode_count].letter = c;
1699 mode_changes[mode_count].dir = MODE_DEL;
1700 mode_changes[mode_count].caps = 0;
1701 mode_changes[mode_count].nocaps = 0;
1702 mode_changes[mode_count].mems = ALL_MEMBERS;
1703 mode_changes[mode_count].id = NULL;
b869e117 1704 mode_changes[mode_count].override = override;
212380e3 1705 mode_changes[mode_count++].arg = "*";
1706 }
1707}
1708
1709void
1710chm_regonly(struct Client *source_p, struct Channel *chptr,
1711 int alevel, int parc, int *parn,
1712 const char **parv, int *errors, int dir, char c, long mode_type)
1713{
b869e117
JH
1714 int override = 0;
1715
c1c91f94 1716 if(alevel != CHFL_CHANOP && alevel != CHFL_ADMIN && alevel != CHFL_HALFOP)
212380e3 1717 {
b869e117
JH
1718 if(IsOverride(source_p))
1719 override = 1;
1720 else
1721 {
1722 if(!(*errors & SM_ERR_NOOPS))
1723 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1724 me.name, source_p->name, chptr->chname);
1725 *errors |= SM_ERR_NOOPS;
1726 return;
1727 }
212380e3 1728 }
1729
1730 if(dir == MODE_QUERY)
1731 return;
1732
040c4408
JT
1733 if(((dir == MODE_ADD) && (chptr->mode.mode & mode_type)) ||
1734 ((dir == MODE_DEL) && !(chptr->mode.mode & mode_type)))
212380e3 1735 return;
1736
c08f4515
JT
1737 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1738 return;
1739
212380e3 1740 if(dir == MODE_ADD)
040c4408 1741 chptr->mode.mode |= mode_type;
212380e3 1742 else
040c4408 1743 chptr->mode.mode &= ~mode_type;
212380e3 1744
1745 mode_changes[mode_count].letter = c;
1746 mode_changes[mode_count].dir = dir;
1747 mode_changes[mode_count].caps = CAP_SERVICE;
1748 mode_changes[mode_count].nocaps = 0;
1749 mode_changes[mode_count].mems = ALL_MEMBERS;
1750 mode_changes[mode_count].id = NULL;
b869e117 1751 mode_changes[mode_count].override = override;
212380e3 1752 mode_changes[mode_count++].arg = NULL;
1753}
1754
1755/* *INDENT-OFF* */
1fe75e33
G
1756/* Only RFC and ircd-ratbox modes are held in this table
1757 * All other modes are added via loading modules in shadowircd/modes
1758 * Such is documented in the comments for each mode, ex: C - NOCTCP. */
212380e3 1759struct ChannelMode chmode_table[256] =
1760{
1761 {chm_nosuch, 0 }, /* 0x00 */
1762 {chm_nosuch, 0 }, /* 0x01 */
1763 {chm_nosuch, 0 }, /* 0x02 */
1764 {chm_nosuch, 0 }, /* 0x03 */
1765 {chm_nosuch, 0 }, /* 0x04 */
1766 {chm_nosuch, 0 }, /* 0x05 */
1767 {chm_nosuch, 0 }, /* 0x06 */
1768 {chm_nosuch, 0 }, /* 0x07 */
1769 {chm_nosuch, 0 }, /* 0x08 */
1770 {chm_nosuch, 0 }, /* 0x09 */
1771 {chm_nosuch, 0 }, /* 0x0a */
1772 {chm_nosuch, 0 }, /* 0x0b */
1773 {chm_nosuch, 0 }, /* 0x0c */
1774 {chm_nosuch, 0 }, /* 0x0d */
1775 {chm_nosuch, 0 }, /* 0x0e */
1776 {chm_nosuch, 0 }, /* 0x0f */
1777 {chm_nosuch, 0 }, /* 0x10 */
1778 {chm_nosuch, 0 }, /* 0x11 */
1779 {chm_nosuch, 0 }, /* 0x12 */
1780 {chm_nosuch, 0 }, /* 0x13 */
1781 {chm_nosuch, 0 }, /* 0x14 */
1782 {chm_nosuch, 0 }, /* 0x15 */
1783 {chm_nosuch, 0 }, /* 0x16 */
1784 {chm_nosuch, 0 }, /* 0x17 */
1785 {chm_nosuch, 0 }, /* 0x18 */
1786 {chm_nosuch, 0 }, /* 0x19 */
1787 {chm_nosuch, 0 }, /* 0x1a */
1788 {chm_nosuch, 0 }, /* 0x1b */
1789 {chm_nosuch, 0 }, /* 0x1c */
1790 {chm_nosuch, 0 }, /* 0x1d */
1791 {chm_nosuch, 0 }, /* 0x1e */
1792 {chm_nosuch, 0 }, /* 0x1f */
1793 {chm_nosuch, 0 }, /* 0x20 */
1794 {chm_nosuch, 0 }, /* 0x21 */
1795 {chm_nosuch, 0 }, /* 0x22 */
1796 {chm_nosuch, 0 }, /* 0x23 */
1797 {chm_nosuch, 0 }, /* 0x24 */
1798 {chm_nosuch, 0 }, /* 0x25 */
1799 {chm_nosuch, 0 }, /* 0x26 */
1800 {chm_nosuch, 0 }, /* 0x27 */
1801 {chm_nosuch, 0 }, /* 0x28 */
1802 {chm_nosuch, 0 }, /* 0x29 */
1803 {chm_nosuch, 0 }, /* 0x2a */
1804 {chm_nosuch, 0 }, /* 0x2b */
1805 {chm_nosuch, 0 }, /* 0x2c */
1806 {chm_nosuch, 0 }, /* 0x2d */
1807 {chm_nosuch, 0 }, /* 0x2e */
1808 {chm_nosuch, 0 }, /* 0x2f */
1809 {chm_nosuch, 0 }, /* 0x30 */
1810 {chm_nosuch, 0 }, /* 0x31 */
1811 {chm_nosuch, 0 }, /* 0x32 */
1812 {chm_nosuch, 0 }, /* 0x33 */
1813 {chm_nosuch, 0 }, /* 0x34 */
1814 {chm_nosuch, 0 }, /* 0x35 */
1815 {chm_nosuch, 0 }, /* 0x36 */
1816 {chm_nosuch, 0 }, /* 0x37 */
1817 {chm_nosuch, 0 }, /* 0x38 */
1818 {chm_nosuch, 0 }, /* 0x39 */
1819 {chm_nosuch, 0 }, /* 0x3a */
1820 {chm_nosuch, 0 }, /* 0x3b */
1821 {chm_nosuch, 0 }, /* 0x3c */
1822 {chm_nosuch, 0 }, /* 0x3d */
1823 {chm_nosuch, 0 }, /* 0x3e */
1824 {chm_nosuch, 0 }, /* 0x3f */
1825
1826 {chm_nosuch, 0 }, /* @ */
1827 {chm_nosuch, 0 }, /* A */
1828 {chm_nosuch, 0 }, /* B */
1fe75e33
G
1829 {chm_nosuch, 0 }, /* C - MODE_NOCTCP */
1830 {chm_nosuch, 0 }, /* D - MODE_NOACTION */
1831 {chm_nosuch, 0 }, /* E - MODE_NOKICK */
1832 {chm_nosuch, 0 }, /* F - MODE_FREETARGET */
1833 {chm_nosuch, 0 }, /* G - MODE_NOCAPS */
212380e3 1834 {chm_nosuch, 0 }, /* H */
1835 {chm_ban, CHFL_INVEX }, /* I */
1fe75e33
G
1836 {chm_nosuch, 0 }, /* J - MODE_NOREJOIN */
1837 {chm_nosuch, 0 }, /* K - MODE_NOREPEAT */
1838 {chm_nosuch, 0 }, /* L - MODE_EXLIMIT */
1839 {chm_nosuch, 0 }, /* M - MODE_NOOPERKICK */
1840 {chm_nosuch, 0 }, /* N - MODE_NONICK */
212380e3 1841 {chm_nosuch, 0 }, /* O */
1fe75e33
G
1842 {chm_nosuch, 0 }, /* P - MODE_PERMANENT */
1843 {chm_nosuch, 0 }, /* Q - MODE_DISFORWARD */
212380e3 1844 {chm_nosuch, 0 }, /* R */
1845 {chm_nosuch, 0 }, /* S */
1fe75e33 1846 {chm_nosuch, 0 }, /* T - MODE_NONOTICE */
212380e3 1847 {chm_nosuch, 0 }, /* U */
1848 {chm_nosuch, 0 }, /* V */
1849 {chm_nosuch, 0 }, /* W */
1850 {chm_nosuch, 0 }, /* X */
1851 {chm_nosuch, 0 }, /* Y */
1852 {chm_nosuch, 0 }, /* Z */
1853 {chm_nosuch, 0 },
1854 {chm_nosuch, 0 },
1855 {chm_nosuch, 0 },
1856 {chm_nosuch, 0 },
1857 {chm_nosuch, 0 },
1858 {chm_nosuch, 0 },
c1c91f94 1859 {chm_admin, 0 }, /* a */
212380e3 1860 {chm_ban, CHFL_BAN }, /* b */
1fe75e33 1861 {chm_nosuch, 0 }, /* c - MODE_NOCOLOR */
212380e3 1862 {chm_nosuch, 0 }, /* d */
1863 {chm_ban, CHFL_EXCEPTION }, /* e */
1fe75e33
G
1864 {chm_nosuch, 0 }, /* f - MODE_FORWARD */
1865 {chm_nosuch, 0 }, /* g - MODE_FREEINVITE */
82f8e812 1866 {chm_halfop, 0 }, /* h */
212380e3 1867 {chm_simple, MODE_INVITEONLY }, /* i */
1fe75e33 1868 {chm_nosuch, 0 }, /* j - MODE_THROTTLE */
212380e3 1869 {chm_key, 0 }, /* k */
1870 {chm_limit, 0 }, /* l */
1871 {chm_simple, MODE_MODERATED }, /* m */
1872 {chm_simple, MODE_NOPRIVMSGS }, /* n */
1873 {chm_op, 0 }, /* o */
1874 {chm_simple, MODE_PRIVATE }, /* p */
1fe75e33
G
1875 {chm_nosuch, 0 }, /* q - CHFL_QUIET */
1876 {chm_nosuch, 0 }, /* r - MODE_REGONLY */
212380e3 1877 {chm_simple, MODE_SECRET }, /* s */
1878 {chm_simple, MODE_TOPICLIMIT }, /* t */
1879 {chm_nosuch, 0 }, /* u */
1880 {chm_voice, 0 }, /* v */
1881 {chm_nosuch, 0 }, /* w */
1882 {chm_nosuch, 0 }, /* x */
1883 {chm_nosuch, 0 }, /* y */
1fe75e33 1884 {chm_nosuch, 0 }, /* z - MODE_OPMODERATE */
212380e3 1885
1886 {chm_nosuch, 0 }, /* 0x7b */
1887 {chm_nosuch, 0 }, /* 0x7c */
1888 {chm_nosuch, 0 }, /* 0x7d */
1889 {chm_nosuch, 0 }, /* 0x7e */
1890 {chm_nosuch, 0 }, /* 0x7f */
1891
1892 {chm_nosuch, 0 }, /* 0x80 */
1893 {chm_nosuch, 0 }, /* 0x81 */
1894 {chm_nosuch, 0 }, /* 0x82 */
1895 {chm_nosuch, 0 }, /* 0x83 */
1896 {chm_nosuch, 0 }, /* 0x84 */
1897 {chm_nosuch, 0 }, /* 0x85 */
1898 {chm_nosuch, 0 }, /* 0x86 */
1899 {chm_nosuch, 0 }, /* 0x87 */
1900 {chm_nosuch, 0 }, /* 0x88 */
1901 {chm_nosuch, 0 }, /* 0x89 */
1902 {chm_nosuch, 0 }, /* 0x8a */
1903 {chm_nosuch, 0 }, /* 0x8b */
1904 {chm_nosuch, 0 }, /* 0x8c */
1905 {chm_nosuch, 0 }, /* 0x8d */
1906 {chm_nosuch, 0 }, /* 0x8e */
1907 {chm_nosuch, 0 }, /* 0x8f */
1908
1909 {chm_nosuch, 0 }, /* 0x90 */
1910 {chm_nosuch, 0 }, /* 0x91 */
1911 {chm_nosuch, 0 }, /* 0x92 */
1912 {chm_nosuch, 0 }, /* 0x93 */
1913 {chm_nosuch, 0 }, /* 0x94 */
1914 {chm_nosuch, 0 }, /* 0x95 */
1915 {chm_nosuch, 0 }, /* 0x96 */
1916 {chm_nosuch, 0 }, /* 0x97 */
1917 {chm_nosuch, 0 }, /* 0x98 */
1918 {chm_nosuch, 0 }, /* 0x99 */
1919 {chm_nosuch, 0 }, /* 0x9a */
1920 {chm_nosuch, 0 }, /* 0x9b */
1921 {chm_nosuch, 0 }, /* 0x9c */
1922 {chm_nosuch, 0 }, /* 0x9d */
1923 {chm_nosuch, 0 }, /* 0x9e */
1924 {chm_nosuch, 0 }, /* 0x9f */
1925
1926 {chm_nosuch, 0 }, /* 0xa0 */
1927 {chm_nosuch, 0 }, /* 0xa1 */
1928 {chm_nosuch, 0 }, /* 0xa2 */
1929 {chm_nosuch, 0 }, /* 0xa3 */
1930 {chm_nosuch, 0 }, /* 0xa4 */
1931 {chm_nosuch, 0 }, /* 0xa5 */
1932 {chm_nosuch, 0 }, /* 0xa6 */
1933 {chm_nosuch, 0 }, /* 0xa7 */
1934 {chm_nosuch, 0 }, /* 0xa8 */
1935 {chm_nosuch, 0 }, /* 0xa9 */
1936 {chm_nosuch, 0 }, /* 0xaa */
1937 {chm_nosuch, 0 }, /* 0xab */
1938 {chm_nosuch, 0 }, /* 0xac */
1939 {chm_nosuch, 0 }, /* 0xad */
1940 {chm_nosuch, 0 }, /* 0xae */
1941 {chm_nosuch, 0 }, /* 0xaf */
1942
1943 {chm_nosuch, 0 }, /* 0xb0 */
1944 {chm_nosuch, 0 }, /* 0xb1 */
1945 {chm_nosuch, 0 }, /* 0xb2 */
1946 {chm_nosuch, 0 }, /* 0xb3 */
1947 {chm_nosuch, 0 }, /* 0xb4 */
1948 {chm_nosuch, 0 }, /* 0xb5 */
1949 {chm_nosuch, 0 }, /* 0xb6 */
1950 {chm_nosuch, 0 }, /* 0xb7 */
1951 {chm_nosuch, 0 }, /* 0xb8 */
1952 {chm_nosuch, 0 }, /* 0xb9 */
1953 {chm_nosuch, 0 }, /* 0xba */
1954 {chm_nosuch, 0 }, /* 0xbb */
1955 {chm_nosuch, 0 }, /* 0xbc */
1956 {chm_nosuch, 0 }, /* 0xbd */
1957 {chm_nosuch, 0 }, /* 0xbe */
1958 {chm_nosuch, 0 }, /* 0xbf */
1959
1960 {chm_nosuch, 0 }, /* 0xc0 */
1961 {chm_nosuch, 0 }, /* 0xc1 */
1962 {chm_nosuch, 0 }, /* 0xc2 */
1963 {chm_nosuch, 0 }, /* 0xc3 */
1964 {chm_nosuch, 0 }, /* 0xc4 */
1965 {chm_nosuch, 0 }, /* 0xc5 */
1966 {chm_nosuch, 0 }, /* 0xc6 */
1967 {chm_nosuch, 0 }, /* 0xc7 */
1968 {chm_nosuch, 0 }, /* 0xc8 */
1969 {chm_nosuch, 0 }, /* 0xc9 */
1970 {chm_nosuch, 0 }, /* 0xca */
1971 {chm_nosuch, 0 }, /* 0xcb */
1972 {chm_nosuch, 0 }, /* 0xcc */
1973 {chm_nosuch, 0 }, /* 0xcd */
1974 {chm_nosuch, 0 }, /* 0xce */
1975 {chm_nosuch, 0 }, /* 0xcf */
1976
1977 {chm_nosuch, 0 }, /* 0xd0 */
1978 {chm_nosuch, 0 }, /* 0xd1 */
1979 {chm_nosuch, 0 }, /* 0xd2 */
1980 {chm_nosuch, 0 }, /* 0xd3 */
1981 {chm_nosuch, 0 }, /* 0xd4 */
1982 {chm_nosuch, 0 }, /* 0xd5 */
1983 {chm_nosuch, 0 }, /* 0xd6 */
1984 {chm_nosuch, 0 }, /* 0xd7 */
1985 {chm_nosuch, 0 }, /* 0xd8 */
1986 {chm_nosuch, 0 }, /* 0xd9 */
1987 {chm_nosuch, 0 }, /* 0xda */
1988 {chm_nosuch, 0 }, /* 0xdb */
1989 {chm_nosuch, 0 }, /* 0xdc */
1990 {chm_nosuch, 0 }, /* 0xdd */
1991 {chm_nosuch, 0 }, /* 0xde */
1992 {chm_nosuch, 0 }, /* 0xdf */
1993
1994 {chm_nosuch, 0 }, /* 0xe0 */
1995 {chm_nosuch, 0 }, /* 0xe1 */
1996 {chm_nosuch, 0 }, /* 0xe2 */
1997 {chm_nosuch, 0 }, /* 0xe3 */
1998 {chm_nosuch, 0 }, /* 0xe4 */
1999 {chm_nosuch, 0 }, /* 0xe5 */
2000 {chm_nosuch, 0 }, /* 0xe6 */
2001 {chm_nosuch, 0 }, /* 0xe7 */
2002 {chm_nosuch, 0 }, /* 0xe8 */
2003 {chm_nosuch, 0 }, /* 0xe9 */
2004 {chm_nosuch, 0 }, /* 0xea */
2005 {chm_nosuch, 0 }, /* 0xeb */
2006 {chm_nosuch, 0 }, /* 0xec */
2007 {chm_nosuch, 0 }, /* 0xed */
2008 {chm_nosuch, 0 }, /* 0xee */
2009 {chm_nosuch, 0 }, /* 0xef */
2010
2011 {chm_nosuch, 0 }, /* 0xf0 */
2012 {chm_nosuch, 0 }, /* 0xf1 */
2013 {chm_nosuch, 0 }, /* 0xf2 */
2014 {chm_nosuch, 0 }, /* 0xf3 */
2015 {chm_nosuch, 0 }, /* 0xf4 */
2016 {chm_nosuch, 0 }, /* 0xf5 */
2017 {chm_nosuch, 0 }, /* 0xf6 */
2018 {chm_nosuch, 0 }, /* 0xf7 */
2019 {chm_nosuch, 0 }, /* 0xf8 */
2020 {chm_nosuch, 0 }, /* 0xf9 */
2021 {chm_nosuch, 0 }, /* 0xfa */
2022 {chm_nosuch, 0 }, /* 0xfb */
2023 {chm_nosuch, 0 }, /* 0xfc */
2024 {chm_nosuch, 0 }, /* 0xfd */
2025 {chm_nosuch, 0 }, /* 0xfe */
2026 {chm_nosuch, 0 }, /* 0xff */
2027};
2028
2029/* *INDENT-ON* */
2030
2031/* set_channel_mode()
2032 *
2033 * inputs - client, source, channel, membership pointer, params
2034 * output -
2035 * side effects - channel modes/memberships are changed, MODE is issued
2036 *
2037 * Extensively modified to be hotpluggable, 03/09/06 -- nenolod
2038 */
2039void
2040set_channel_mode(struct Client *client_p, struct Client *source_p,
2041 struct Channel *chptr, struct membership *msptr, int parc, const char *parv[])
2042{
eccd1c58 2043 static char cmdbuf[BUFSIZE];
212380e3 2044 static char modebuf[BUFSIZE];
2045 static char parabuf[BUFSIZE];
2046 char *mbuf;
2047 char *pbuf;
2048 int cur_len, mlen, paralen, paracount, arglen, len;
eccd1c58 2049 int i, j, flags, override;
212380e3 2050 int dir = MODE_ADD;
2051 int parn = 1;
2052 int errors = 0;
2053 int alevel;
2054 const char *ml = parv[0];
2055 char c;
2056 struct Client *fakesource_p;
1cdd8fdf 2057 int flags_list[3] = { ALL_MEMBERS, ONLY_CHANOPS, ONLY_OPERS };
212380e3 2058
2059 mask_pos = 0;
2060 mode_count = 0;
2061 mode_limit = 0;
c08f4515 2062 mode_limit_simple = 0;
212380e3 2063
2064 alevel = get_channel_access(source_p, msptr);
2065
b869e117
JH
2066 no_override_deop = 0;
2067
212380e3 2068 /* Hide connecting server on netburst -- jilles */
2069 if (ConfigServerHide.flatten_links && IsServer(source_p) && !has_id(source_p) && !HasSentEob(source_p))
2070 fakesource_p = &me;
2071 else
2072 fakesource_p = source_p;
2073
2074 for(; (c = *ml) != 0; ml++)
2075 {
2076 switch (c)
2077 {
2078 case '+':
2079 dir = MODE_ADD;
2080 break;
2081 case '-':
2082 dir = MODE_DEL;
2083 break;
2084 case '=':
2085 dir = MODE_QUERY;
2086 break;
2087 default:
b72bd23a
SB
2088 /* If this mode char is locked, don't allow local users to change it. */
2089 if (MyClient(source_p) && chptr->mode_lock && strchr(chptr->mode_lock, c))
c95fc52d 2090 {
cc2a7258
JT
2091 if (!(errors & SM_ERR_MLOCK))
2092 sendto_one_numeric(source_p,
2093 ERR_MLOCKRESTRICTED,
2094 form_str(ERR_MLOCKRESTRICTED),
2095 chptr->chname,
2096 c,
2097 chptr->mode_lock);
2098 errors |= SM_ERR_MLOCK;
b72bd23a 2099 continue;
c95fc52d 2100 }
212380e3 2101 chmode_table[(unsigned char) c].set_func(fakesource_p, chptr, alevel,
2102 parc, &parn, parv,
2103 &errors, dir, c,
2104 chmode_table[(unsigned char) c].mode_type);
2105 break;
2106 }
2107 }
2108
2109 /* bail out if we have nothing to do... */
2110 if(!mode_count)
2111 return;
2112
2113 if(IsServer(source_p))
eccd1c58 2114 rb_sprintf(cmdbuf, ":%s MODE %s ", fakesource_p->name, chptr->chname);
212380e3 2115 else
eccd1c58 2116 rb_sprintf(cmdbuf, ":%s!%s@%s MODE %s ",
212380e3 2117 source_p->name, source_p->username,
2118 source_p->host, chptr->chname);
2119
e853274c
JH
2120 mlen = 0;
2121
cb097b88 2122 for (override = 0; override < (IsOverride(source_p) && alevel != CHFL_CHANOP ? 2 : 1); ++override)
212380e3 2123 {
eccd1c58 2124 int was_on_chan = 0;
b869e117 2125
eccd1c58 2126 if(override)
212380e3 2127 {
eccd1c58 2128 if(msptr)
b869e117 2129 {
eccd1c58 2130 was_on_chan = 1;
b869e117
JH
2131 msptr->flags |= CHFL_CHANOP;
2132 }
eccd1c58 2133 else
b869e117 2134 add_user_to_channel(chptr, source_p, CHFL_CHANOP);
eccd1c58 2135 }
212380e3 2136
1cdd8fdf 2137 for(j = 0, flags = flags_list[0]; j < 3; j++, flags = flags_list[j])
eccd1c58
JH
2138 {
2139 cur_len = mlen;
2140 mbuf = modebuf + mlen;
2141 pbuf = parabuf;
2142 parabuf[0] = '\0';
2143 paracount = paralen = 0;
2144 dir = MODE_QUERY;
212380e3 2145
eccd1c58 2146 for(i = 0; i < mode_count; i++)
212380e3 2147 {
eccd1c58 2148 if(mode_changes[i].letter == 0 || mode_changes[i].mems != flags)
2f39232f 2149 continue;
212380e3 2150
eccd1c58 2151 if(mode_changes[i].override != override)
212380e3 2152 continue;
2153
eccd1c58
JH
2154 if(mode_changes[i].arg != NULL)
2155 {
2156 arglen = strlen(mode_changes[i].arg);
212380e3 2157
eccd1c58
JH
2158 if(arglen > MODEBUFLEN - 5)
2159 continue;
2160 }
2161 else
2162 arglen = 0;
2163
2164 /* if we're creeping over MAXMODEPARAMSSERV, or over
2165 * bufsize (4 == +/-,modechar,two spaces) send now.
2166 */
2167 if(mode_changes[i].arg != NULL &&
2f39232f
G
2168 ((paracount == MAXMODEPARAMSSERV) ||
2169 ((cur_len + paralen + arglen + 4) > (BUFSIZE - 3))))
eccd1c58
JH
2170 {
2171 *mbuf = '\0';
2172
2173 if(cur_len > mlen)
2174 {
2175 sendto_channel_local(flags, chptr, "%s%s %s",
2f39232f 2176 cmdbuf, modebuf, parabuf);
eccd1c58 2177 if(override)
34d8ef4d
JH
2178 {
2179 sendto_wallops_flags(UMODE_WALLOP, &me,
eccd1c58 2180 "%s is overriding modes on %s: %s %s",
34d8ef4d
JH
2181 get_oper_name(source_p), chptr->chname, modebuf, parabuf);
2182 sendto_server(NULL, chptr, NOCAPS, NOCAPS,
2183 ":%s WALLOPS :%s is overriding modes on %s: %s %s",
71ea6069 2184 me.name, get_oper_name(source_p), chptr->chname, modebuf, parabuf);
34d8ef4d 2185 }
eccd1c58
JH
2186 }
2187 else
2188 continue;
2189
2190 paracount = paralen = 0;
2191 cur_len = mlen;
2192 mbuf = modebuf + mlen;
2193 pbuf = parabuf;
2194 parabuf[0] = '\0';
2195 dir = MODE_QUERY;
2196 }
2197
2198 if(dir != mode_changes[i].dir)
2199 {
2200 *mbuf++ = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
2201 cur_len++;
2202 dir = mode_changes[i].dir;
2203 }
2204
2205 *mbuf++ = mode_changes[i].letter;
212380e3 2206 cur_len++;
212380e3 2207
eccd1c58
JH
2208 if(mode_changes[i].arg != NULL)
2209 {
2210 paracount++;
2211 len = rb_sprintf(pbuf, "%s ", mode_changes[i].arg);
2212 pbuf += len;
2213 paralen += len;
2214 }
212380e3 2215 }
212380e3 2216
3da167f2
JH
2217 if(paralen && parabuf[paralen - 1] == ' ')
2218 parabuf[paralen - 1] = '\0';
2219
2220 *mbuf = '\0';
2221 if(cur_len > mlen)
b869e117 2222 {
3da167f2
JH
2223 sendto_channel_local(flags, chptr, "%s%s %s", cmdbuf, modebuf, parabuf);
2224 if(override)
34d8ef4d
JH
2225 {
2226 sendto_wallops_flags(UMODE_WALLOP, &me,
3da167f2 2227 "%s is overriding modes on %s: %s %s",
34d8ef4d
JH
2228 get_oper_name(source_p), chptr->chname, modebuf, parabuf);
2229 sendto_server(NULL, chptr, NOCAPS, NOCAPS,
2230 ":%s WALLOPS :%s is overriding modes on %s: %s %s",
71ea6069 2231 me.name, get_oper_name(source_p), chptr->chname, modebuf, parabuf);
34d8ef4d 2232 }
b869e117 2233 }
3da167f2
JH
2234 }
2235 if(override)
2236 {
2237 if(!was_on_chan)
2238 remove_user_from_channel(find_channel_membership(chptr, source_p));
2239 else if (!no_override_deop)
2240 msptr->flags &= ~CHFL_CHANOP;
2241 }
212380e3 2242 }
2f39232f 2243
212380e3 2244 /* only propagate modes originating locally, or if we're hubbing */
af81d5a0 2245 if(MyClient(source_p) || rb_dlink_list_length(&serv_list) > 1)
212380e3 2246 send_cap_mode_changes(client_p, source_p, chptr, mode_changes, mode_count);
2247}
28805dc5
WP
2248
2249/* set_channel_mlock()
2250 *
2251 * inputs - client, source, channel, params
2252 * output -
2253 * side effects - channel mlock is changed / MLOCK is propagated
2254 */
2255void
2256set_channel_mlock(struct Client *client_p, struct Client *source_p,
fc579e36 2257 struct Channel *chptr, const char *newmlock, int propagate)
28805dc5 2258{
b72bd23a 2259 rb_free(chptr->mode_lock);
c554add2 2260 chptr->mode_lock = newmlock ? rb_strdup(newmlock) : NULL;
28805dc5 2261
fc579e36
WP
2262 if (propagate)
2263 {
2264 sendto_server(client_p, NULL, CAP_TS6 | CAP_MLOCK, NOCAPS, ":%s MLOCK %ld %s :%s",
2265 source_p->id, (long) chptr->channelts, chptr->chname,
2266 chptr->mode_lock ? chptr->mode_lock : "");
2267 }
28805dc5 2268}