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