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