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