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