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