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