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