]> jfr.im git - irc/rqf/shadowircd.git/blob - src/chmode.c
Add user metadata.
[irc/rqf/shadowircd.git] / src / chmode.c
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 *
25 * $Id: chmode.c 3580 2007-11-07 23:45:14Z jilles $
26 */
27
28 #include "stdinc.h"
29 #include "channel.h"
30 #include "client.h"
31 #include "common.h"
32 #include "hash.h"
33 #include "hook.h"
34 #include "match.h"
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"
43 #include "logger.h"
44 #include "chmode.h"
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
60 #define MAXMODES_SIMPLE 46 /* a-zA-Z except bqeIov */
61
62 static struct ChModeChange mode_changes[BUFSIZE];
63 static int mode_count;
64 static int mode_limit;
65 static int mode_limit_simple;
66 static int mask_pos;
67
68 char cflagsbuf[256];
69 char cflagsmyinfo[256];
70
71 int chmode_flags[256];
72
73 /* OPTIMIZE ME! -- dwr */
74 void
75 construct_noparam_modes(void)
76 {
77 int i;
78 char *ptr = cflagsbuf;
79 char *ptr2 = cflagsmyinfo;
80 static int prev_chmode_flags[256];
81
82 *ptr = '\0';
83 *ptr2 = '\0';
84
85 for(i = 0; i < 256; i++)
86 {
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) &&
92 !(chmode_table[i].set_func == chm_owner) &&
93 !(chmode_table[i].set_func == chm_op) &&
94 !(chmode_table[i].set_func == chm_halfop) &&
95 !(chmode_table[i].set_func == chm_voice))
96 {
97 chmode_flags[i] = chmode_table[i].mode_type;
98 }
99 else
100 {
101 chmode_flags[i] = 0;
102 }
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];
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 }
149 }
150
151 *ptr++ = '\0';
152 *ptr2++ = '\0';
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 */
163 unsigned int
164 find_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;
175 }
176
177 static int
178 get_channel_access(struct Client *source_p, struct membership *msptr)
179 {
180 if(!MyClient(source_p) || is_owner(msptr))
181 return CHFL_OWNER;
182 else if(is_chanop(msptr))
183 return CHFL_CHANOP;
184 else if(is_halfop(msptr))
185 return CHFL_HALFOP;
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 */
196 int
197 add_id(struct Client *source_p, struct Channel *chptr, const char *banid,
198 rb_dlink_list * list, long mode_type)
199 {
200 struct Ban *actualBan;
201 static char who[USERHOST_REPLYLEN];
202 char *realban = LOCAL_COPY(banid);
203 rb_dlink_node *ptr;
204
205 /* dont let local clients overflow the banlist, or set redundant
206 * bans
207 */
208 if(MyClient(source_p))
209 {
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))
211 {
212 sendto_one(source_p, form_str(ERR_BANLISTFULL),
213 me.name, source_p->name, chptr->chname, realban);
214 return 0;
215 }
216
217 RB_DLINK_FOREACH(ptr, list->head)
218 {
219 actualBan = ptr->data;
220 if(mask_match(actualBan->banstr, realban))
221 return 0;
222 }
223 }
224 /* dont let remotes set duplicates */
225 else
226 {
227 RB_DLINK_FOREACH(ptr, list->head)
228 {
229 actualBan = ptr->data;
230 if(!irccmp(actualBan->banstr, realban))
231 return 0;
232 }
233 }
234
235
236 if(IsPerson(source_p))
237 rb_sprintf(who, "%s!%s@%s", source_p->name, source_p->username, source_p->host);
238 else
239 rb_strlcpy(who, source_p->name, sizeof(who));
240
241 actualBan = allocate_ban(realban, who);
242 actualBan->when = rb_current_time();
243
244 rb_dlinkAdd(actualBan, &actualBan->node, list);
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 */
259 int
260 del_id(struct Channel *chptr, const char *banid, rb_dlink_list * list, long mode_type)
261 {
262 rb_dlink_node *ptr;
263 struct Ban *banptr;
264
265 if(EmptyString(banid))
266 return 0;
267
268 RB_DLINK_FOREACH(ptr, list->head)
269 {
270 banptr = ptr->data;
271
272 if(irccmp(banid, banptr->banstr) == 0)
273 {
274 rb_dlinkDelete(&banptr->node, list);
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 */
294 static char *
295 check_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 */
324 static char *
325 pretty_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 {
348 mask_pos += rb_sprintf(mask_buf + mask_pos, "%s", mask) + 1;
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 }
390 else if(strchr(mask, '.') != NULL || strchr(mask, ':') != NULL || strchr(mask, '/') != NULL)
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
418 mask_pos += rb_sprintf(mask_buf + mask_pos, "%s!%s@%s", nick, user, host) + 1;
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 */
442 static char *
443 fix_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 */
465 static char *
466 fix_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 */
485 void
486 chm_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
496 void
497 chm_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 {
501
502 int override = 0;
503
504 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
505 {
506 if (IsOverride(source_p))
507 override = 1;
508 else
509 {
510 if(!(*errors & SM_ERR_NOOPS))
511 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
512 me.name, source_p->name, chptr->chname);
513 *errors |= SM_ERR_NOOPS;
514 return;
515 }
516 }
517
518 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
519 return;
520
521 /* setting + */
522 if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
523 {
524 /* if +f is disabled, ignore an attempt to set +QF locally */
525 if(!ConfigChannel.use_forward && MyClient(source_p) &&
526 (c == 'Q' || c == 'F'))
527 return;
528
529 chptr->mode.mode |= mode_type;
530
531 mode_changes[mode_count].letter = c;
532 mode_changes[mode_count].dir = MODE_ADD;
533 mode_changes[mode_count].caps = 0;
534 mode_changes[mode_count].nocaps = 0;
535 mode_changes[mode_count].id = NULL;
536 mode_changes[mode_count].mems = ALL_MEMBERS;
537 mode_changes[mode_count].override = override;
538 mode_changes[mode_count++].arg = NULL;
539 }
540 else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
541 {
542 chptr->mode.mode &= ~mode_type;
543
544 mode_changes[mode_count].letter = c;
545 mode_changes[mode_count].dir = MODE_DEL;
546 mode_changes[mode_count].caps = 0;
547 mode_changes[mode_count].nocaps = 0;
548 mode_changes[mode_count].mems = ALL_MEMBERS;
549 mode_changes[mode_count].id = NULL;
550 mode_changes[mode_count].override = override;
551 mode_changes[mode_count++].arg = NULL;
552 }
553 }
554
555 void
556 chm_orphaned(struct Client *source_p, struct Channel *chptr,
557 int alevel, int parc, int *parn,
558 const char **parv, int *errors, int dir, char c, long mode_type)
559 {
560 if(MyClient(source_p))
561 return;
562
563 if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
564 {
565 chptr->mode.mode |= mode_type;
566
567 mode_changes[mode_count].letter = c;
568 mode_changes[mode_count].dir = MODE_ADD;
569 mode_changes[mode_count].caps = 0;
570 mode_changes[mode_count].nocaps = 0;
571 mode_changes[mode_count].id = NULL;
572 mode_changes[mode_count].mems = ALL_MEMBERS;
573 mode_changes[mode_count++].arg = NULL;
574 }
575 else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
576 {
577 chptr->mode.mode &= ~mode_type;
578
579 mode_changes[mode_count].letter = c;
580 mode_changes[mode_count].dir = MODE_DEL;
581 mode_changes[mode_count].caps = 0;
582 mode_changes[mode_count].nocaps = 0;
583 mode_changes[mode_count].mems = ALL_MEMBERS;
584 mode_changes[mode_count].id = NULL;
585 mode_changes[mode_count++].arg = NULL;
586 }
587 }
588
589 void
590 chm_staff(struct Client *source_p, struct Channel *chptr,
591 int alevel, int parc, int *parn,
592 const char **parv, int *errors, int dir, char c, long mode_type)
593 {
594 if(!IsOper(source_p) && !IsServer(source_p))
595 {
596 if(!(*errors & SM_ERR_NOPRIVS))
597 sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
598 *errors |= SM_ERR_NOPRIVS;
599 return;
600 }
601 if(MyClient(source_p) && !IsOperResv(source_p))
602 {
603 if(!(*errors & SM_ERR_NOPRIVS))
604 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name,
605 source_p->name, "resv");
606 *errors |= SM_ERR_NOPRIVS;
607 return;
608 }
609
610 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
611 return;
612
613 /* setting + */
614 if((dir == MODE_ADD) && !(chptr->mode.mode & mode_type))
615 {
616 chptr->mode.mode |= mode_type;
617
618 mode_changes[mode_count].letter = c;
619 mode_changes[mode_count].dir = MODE_ADD;
620 mode_changes[mode_count].caps = 0;
621 mode_changes[mode_count].nocaps = 0;
622 mode_changes[mode_count].id = NULL;
623 mode_changes[mode_count].mems = ALL_MEMBERS;
624 mode_changes[mode_count++].arg = NULL;
625 }
626 else if((dir == MODE_DEL) && (chptr->mode.mode & mode_type))
627 {
628 chptr->mode.mode &= ~mode_type;
629
630 mode_changes[mode_count].letter = c;
631 mode_changes[mode_count].dir = MODE_DEL;
632 mode_changes[mode_count].caps = 0;
633 mode_changes[mode_count].nocaps = 0;
634 mode_changes[mode_count].mems = ALL_MEMBERS;
635 mode_changes[mode_count].id = NULL;
636 mode_changes[mode_count++].arg = NULL;
637 }
638 }
639
640 void
641 chm_ban(struct Client *source_p, struct Channel *chptr,
642 int alevel, int parc, int *parn,
643 const char **parv, int *errors, int dir, char c, long mode_type)
644 {
645 const char *mask;
646 const char *raw_mask;
647 rb_dlink_list *list;
648 rb_dlink_node *ptr;
649 struct Ban *banptr;
650 int errorval;
651 int rpl_list;
652 int rpl_endlist;
653 int caps;
654 int mems;
655
656 switch (mode_type)
657 {
658 case CHFL_BAN:
659 list = &chptr->banlist;
660 errorval = SM_ERR_RPL_B;
661 rpl_list = RPL_BANLIST;
662 rpl_endlist = RPL_ENDOFBANLIST;
663 mems = ALL_MEMBERS;
664 caps = 0;
665 break;
666
667 case CHFL_EXCEPTION:
668 /* if +e is disabled, allow all but +e locally */
669 if(!ConfigChannel.use_except && MyClient(source_p) &&
670 ((dir == MODE_ADD) && (parc > *parn)))
671 return;
672
673 list = &chptr->exceptlist;
674 errorval = SM_ERR_RPL_E;
675 rpl_list = RPL_EXCEPTLIST;
676 rpl_endlist = RPL_ENDOFEXCEPTLIST;
677 caps = CAP_EX;
678
679 if(ConfigChannel.use_except || (dir == MODE_DEL))
680 mems = ONLY_CHANOPS;
681 else
682 mems = ONLY_SERVERS;
683 break;
684
685 case CHFL_INVEX:
686 /* if +I is disabled, allow all but +I locally */
687 if(!ConfigChannel.use_invex && MyClient(source_p) &&
688 (dir == MODE_ADD) && (parc > *parn))
689 return;
690
691 list = &chptr->invexlist;
692 errorval = SM_ERR_RPL_I;
693 rpl_list = RPL_INVITELIST;
694 rpl_endlist = RPL_ENDOFINVITELIST;
695 caps = CAP_IE;
696
697 if(ConfigChannel.use_invex || (dir == MODE_DEL))
698 mems = ONLY_CHANOPS;
699 else
700 mems = ONLY_SERVERS;
701 break;
702
703 case CHFL_QUIET:
704 list = &chptr->quietlist;
705 errorval = SM_ERR_RPL_Q;
706 rpl_list = RPL_BANLIST;
707 rpl_endlist = RPL_ENDOFBANLIST;
708 mems = ALL_MEMBERS;
709 caps = 0;
710 break;
711
712 default:
713 sendto_realops_snomask(SNO_GENERAL, L_ALL, "chm_ban() called with unknown type!");
714 return;
715 break;
716 }
717
718 if(dir == 0 || parc <= *parn)
719 {
720 if((*errors & errorval) != 0)
721 return;
722 *errors |= errorval;
723
724 /* non-ops cant see +eI lists.. */
725 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP && mode_type != CHFL_BAN &&
726 mode_type != CHFL_QUIET)
727 {
728 if(!(*errors & SM_ERR_NOOPS))
729 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
730 me.name, source_p->name, chptr->chname);
731 *errors |= SM_ERR_NOOPS;
732 return;
733 }
734
735 RB_DLINK_FOREACH(ptr, list->head)
736 {
737 banptr = ptr->data;
738 sendto_one(source_p, form_str(rpl_list),
739 me.name, source_p->name, chptr->chname,
740 banptr->banstr, banptr->who, banptr->when);
741 }
742 if (mode_type == CHFL_QUIET)
743 sendto_one(source_p, ":%s %d %s %s :End of Channel Quiet List", me.name, rpl_endlist, source_p->name, chptr->chname);
744 else
745 sendto_one(source_p, form_str(rpl_endlist), me.name, source_p->name, chptr->chname);
746 return;
747 }
748
749 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
750 {
751 if(!(*errors & SM_ERR_NOOPS))
752 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
753 me.name, source_p->name, chptr->chname);
754 *errors |= SM_ERR_NOOPS;
755 return;
756 }
757
758 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
759 return;
760
761 raw_mask = parv[(*parn)];
762 (*parn)++;
763
764 /* empty ban, or starts with ':' which messes up s2s, ignore it */
765 if(EmptyString(raw_mask) || *raw_mask == ':')
766 return;
767
768 if(!MyClient(source_p))
769 {
770 if(strchr(raw_mask, ' '))
771 return;
772
773 mask = raw_mask;
774 }
775 else
776 mask = pretty_mask(raw_mask);
777
778 /* we'd have problems parsing this, hyb6 does it too
779 * also make sure it will always fit on a line with channel
780 * name etc.
781 */
782 if(strlen(mask) > IRCD_MIN(BANLEN, MODEBUFLEN - 5))
783 return;
784
785 /* if we're adding a NEW id */
786 if(dir == MODE_ADD)
787 {
788 if (*mask == '$' && MyClient(source_p))
789 {
790 if (!valid_extban(mask, source_p, chptr, mode_type))
791 /* XXX perhaps return an error message here */
792 return;
793 }
794
795 /* dont allow local clients to overflow the banlist, dont
796 * let remote servers set duplicate bans
797 */
798 if(!add_id(source_p, chptr, mask, list, mode_type))
799 return;
800
801 mode_changes[mode_count].letter = c;
802 mode_changes[mode_count].dir = MODE_ADD;
803 mode_changes[mode_count].caps = caps;
804 mode_changes[mode_count].nocaps = 0;
805 mode_changes[mode_count].mems = mems;
806 mode_changes[mode_count].id = NULL;
807 mode_changes[mode_count++].arg = mask;
808 }
809 else if(dir == MODE_DEL)
810 {
811 if(del_id(chptr, mask, list, mode_type) == 0)
812 {
813 /* mask isn't a valid ban, check raw_mask */
814 if(del_id(chptr, raw_mask, list, mode_type))
815 mask = raw_mask;
816 }
817
818 mode_changes[mode_count].letter = c;
819 mode_changes[mode_count].dir = MODE_DEL;
820 mode_changes[mode_count].caps = caps;
821 mode_changes[mode_count].nocaps = 0;
822 mode_changes[mode_count].mems = mems;
823 mode_changes[mode_count].id = NULL;
824 mode_changes[mode_count++].arg = mask;
825 }
826 }
827
828 void
829 chm_owner(struct Client *source_p, struct Channel *chptr,
830 int alevel, int parc, int *parn,
831 const char **parv, int *errors, int dir, char c, long mode_type)
832 {
833 struct membership *mstptr;
834 const char *ownernick;
835 struct Client *targ_p;
836
837 if(!ConfigChannel.use_owner)
838 {
839 if(*errors & SM_ERR_UNKNOWN)
840 return;
841 *errors |= SM_ERR_UNKNOWN;
842 sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
843 return;
844 }
845
846 if(alevel != CHFL_OWNER)
847 {
848 if(!(*errors & SM_ERR_NOOPS))
849 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
850 me.name, source_p->name, chptr->chname);
851 *errors |= SM_ERR_NOOPS;
852 return;
853 }
854
855 if((dir == MODE_QUERY) || (parc <= *parn))
856 return;
857
858 ownernick = parv[(*parn)];
859 (*parn)++;
860
861 /* empty nick */
862 if(EmptyString(ownernick))
863 {
864 sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
865 return;
866 }
867
868 if((targ_p = find_chasing(source_p, ownernick, NULL)) == NULL)
869 {
870 return;
871 }
872
873 mstptr = find_channel_membership(chptr, targ_p);
874
875 if(mstptr == NULL)
876 {
877 if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
878 sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
879 form_str(ERR_USERNOTINCHANNEL), ownernick, chptr->chname);
880 *errors |= SM_ERR_NOTONCHANNEL;
881 return;
882 }
883
884 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
885 return;
886
887 if(dir == MODE_ADD)
888 {
889 if(targ_p == source_p)
890 return;
891
892 mode_changes[mode_count].letter = c;
893 mode_changes[mode_count].dir = MODE_ADD;
894 mode_changes[mode_count].caps = 0;
895 mode_changes[mode_count].nocaps = 0;
896 mode_changes[mode_count].mems = ALL_MEMBERS;
897 mode_changes[mode_count].id = targ_p->id;
898 mode_changes[mode_count].arg = targ_p->name;
899 mode_changes[mode_count++].client = targ_p;
900
901 mstptr->flags |= CHFL_OWNER;
902 }
903 else
904 {
905 if(MyClient(source_p) && IsService(targ_p))
906 {
907 sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
908 me.name, source_p->name, targ_p->name, chptr->chname);
909 return;
910 }
911
912 mode_changes[mode_count].letter = c;
913 mode_changes[mode_count].dir = MODE_DEL;
914 mode_changes[mode_count].caps = 0;
915 mode_changes[mode_count].nocaps = 0;
916 mode_changes[mode_count].mems = ALL_MEMBERS;
917 mode_changes[mode_count].id = targ_p->id;
918 mode_changes[mode_count].arg = targ_p->name;
919 mode_changes[mode_count++].client = targ_p;
920
921 mstptr->flags &= ~CHFL_OWNER;
922 }
923 }
924
925 void
926 chm_op(struct Client *source_p, struct Channel *chptr,
927 int alevel, int parc, int *parn,
928 const char **parv, int *errors, int dir, char c, long mode_type)
929 {
930 struct membership *mstptr;
931 const char *opnick;
932 struct Client *targ_p;
933
934 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER)
935 {
936 if(!(*errors & SM_ERR_NOOPS))
937 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
938 me.name, source_p->name, chptr->chname);
939 *errors |= SM_ERR_NOOPS;
940 return;
941 }
942
943 if((dir == MODE_QUERY) || (parc <= *parn))
944 return;
945
946 opnick = parv[(*parn)];
947 (*parn)++;
948
949 /* empty nick */
950 if(EmptyString(opnick))
951 {
952 sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
953 return;
954 }
955
956 if((targ_p = find_chasing(source_p, opnick, NULL)) == NULL)
957 {
958 return;
959 }
960
961 mstptr = find_channel_membership(chptr, targ_p);
962
963 if(mstptr == NULL)
964 {
965 if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
966 sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
967 form_str(ERR_USERNOTINCHANNEL), opnick, chptr->chname);
968 *errors |= SM_ERR_NOTONCHANNEL;
969 return;
970 }
971
972 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
973 return;
974
975 if(dir == MODE_ADD)
976 {
977 if(targ_p == source_p)
978 return;
979
980 mode_changes[mode_count].letter = c;
981 mode_changes[mode_count].dir = MODE_ADD;
982 mode_changes[mode_count].caps = 0;
983 mode_changes[mode_count].nocaps = 0;
984 mode_changes[mode_count].mems = ALL_MEMBERS;
985 mode_changes[mode_count].id = targ_p->id;
986 mode_changes[mode_count].arg = targ_p->name;
987 mode_changes[mode_count++].client = targ_p;
988
989 mstptr->flags |= CHFL_CHANOP;
990 }
991 else
992 {
993 if(MyClient(source_p) && IsService(targ_p))
994 {
995 sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
996 me.name, source_p->name, targ_p->name, chptr->chname);
997 return;
998 }
999
1000 mode_changes[mode_count].letter = c;
1001 mode_changes[mode_count].dir = MODE_DEL;
1002 mode_changes[mode_count].caps = 0;
1003 mode_changes[mode_count].nocaps = 0;
1004 mode_changes[mode_count].mems = ALL_MEMBERS;
1005 mode_changes[mode_count].id = targ_p->id;
1006 mode_changes[mode_count].arg = targ_p->name;
1007 mode_changes[mode_count++].client = targ_p;
1008
1009 mstptr->flags &= ~CHFL_CHANOP;
1010 }
1011 }
1012
1013 void
1014 chm_halfop(struct Client *source_p, struct Channel *chptr,
1015 int alevel, int parc, int *parn,
1016 const char **parv, int *errors, int dir, char c, long mode_type)
1017 {
1018 struct membership *mstptr;
1019 const char *halfopnick;
1020 struct Client *targ_p;
1021
1022 if(!ConfigChannel.use_halfop)
1023 {
1024 if(*errors & SM_ERR_UNKNOWN)
1025 return;
1026 *errors |= SM_ERR_UNKNOWN;
1027 sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name, source_p->name, c);
1028 return;
1029 }
1030
1031 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER)
1032 {
1033 if(!(*errors & SM_ERR_NOOPS))
1034 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1035 me.name, source_p->name, chptr->chname);
1036 *errors |= SM_ERR_NOOPS;
1037 return;
1038 }
1039
1040 if((dir == MODE_QUERY) || (parc <= *parn))
1041 return;
1042
1043 halfopnick = parv[(*parn)];
1044 (*parn)++;
1045
1046 /* empty nick */
1047 if(EmptyString(halfopnick))
1048 {
1049 sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
1050 return;
1051 }
1052
1053 if((targ_p = find_chasing(source_p, halfopnick, NULL)) == NULL)
1054 {
1055 return;
1056 }
1057
1058 mstptr = find_channel_membership(chptr, targ_p);
1059
1060 if(mstptr == NULL)
1061 {
1062 if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
1063 sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
1064 form_str(ERR_USERNOTINCHANNEL), halfopnick, chptr->chname);
1065 *errors |= SM_ERR_NOTONCHANNEL;
1066 return;
1067 }
1068
1069 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1070 return;
1071
1072 if(dir == MODE_ADD)
1073 {
1074 if(targ_p == source_p)
1075 return;
1076
1077 mode_changes[mode_count].letter = c;
1078 mode_changes[mode_count].dir = MODE_ADD;
1079 mode_changes[mode_count].caps = 0;
1080 mode_changes[mode_count].nocaps = 0;
1081 mode_changes[mode_count].mems = ALL_MEMBERS;
1082 mode_changes[mode_count].id = targ_p->id;
1083 mode_changes[mode_count].arg = targ_p->name;
1084 mode_changes[mode_count++].client = targ_p;
1085
1086 mstptr->flags |= CHFL_HALFOP;
1087 }
1088 else
1089 {
1090 if(MyClient(source_p) && IsService(targ_p))
1091 {
1092 sendto_one(source_p, form_str(ERR_ISCHANSERVICE),
1093 me.name, source_p->name, targ_p->name, chptr->chname);
1094 return;
1095 }
1096
1097 mode_changes[mode_count].letter = c;
1098 mode_changes[mode_count].dir = MODE_DEL;
1099 mode_changes[mode_count].caps = 0;
1100 mode_changes[mode_count].nocaps = 0;
1101 mode_changes[mode_count].mems = ALL_MEMBERS;
1102 mode_changes[mode_count].id = targ_p->id;
1103 mode_changes[mode_count].arg = targ_p->name;
1104 mode_changes[mode_count++].client = targ_p;
1105
1106 mstptr->flags &= ~CHFL_HALFOP;
1107 }
1108 }
1109
1110 void
1111 chm_voice(struct Client *source_p, struct Channel *chptr,
1112 int alevel, int parc, int *parn,
1113 const char **parv, int *errors, int dir, char c, long mode_type)
1114 {
1115 struct membership *mstptr;
1116 const char *opnick;
1117 struct Client *targ_p;
1118
1119 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
1120 {
1121 if(!(*errors & SM_ERR_NOOPS))
1122 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1123 me.name, source_p->name, chptr->chname);
1124 *errors |= SM_ERR_NOOPS;
1125 return;
1126 }
1127
1128 if((dir == MODE_QUERY) || parc <= *parn)
1129 return;
1130
1131 opnick = parv[(*parn)];
1132 (*parn)++;
1133
1134 /* empty nick */
1135 if(EmptyString(opnick))
1136 {
1137 sendto_one_numeric(source_p, ERR_NOSUCHNICK, form_str(ERR_NOSUCHNICK), "*");
1138 return;
1139 }
1140
1141 if((targ_p = find_chasing(source_p, opnick, NULL)) == NULL)
1142 {
1143 return;
1144 }
1145
1146 mstptr = find_channel_membership(chptr, targ_p);
1147
1148 if(mstptr == NULL)
1149 {
1150 if(!(*errors & SM_ERR_NOTONCHANNEL) && MyClient(source_p))
1151 sendto_one_numeric(source_p, ERR_USERNOTINCHANNEL,
1152 form_str(ERR_USERNOTINCHANNEL), opnick, chptr->chname);
1153 *errors |= SM_ERR_NOTONCHANNEL;
1154 return;
1155 }
1156
1157 if(MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1158 return;
1159
1160 if(dir == MODE_ADD)
1161 {
1162 mode_changes[mode_count].letter = c;
1163 mode_changes[mode_count].dir = MODE_ADD;
1164 mode_changes[mode_count].caps = 0;
1165 mode_changes[mode_count].nocaps = 0;
1166 mode_changes[mode_count].mems = ALL_MEMBERS;
1167 mode_changes[mode_count].id = targ_p->id;
1168 mode_changes[mode_count].arg = targ_p->name;
1169 mode_changes[mode_count++].client = targ_p;
1170
1171 mstptr->flags |= CHFL_VOICE;
1172 }
1173 else
1174 {
1175 mode_changes[mode_count].letter = 'v';
1176 mode_changes[mode_count].dir = MODE_DEL;
1177 mode_changes[mode_count].caps = 0;
1178 mode_changes[mode_count].nocaps = 0;
1179 mode_changes[mode_count].mems = ALL_MEMBERS;
1180 mode_changes[mode_count].id = targ_p->id;
1181 mode_changes[mode_count].arg = targ_p->name;
1182 mode_changes[mode_count++].client = targ_p;
1183
1184 mstptr->flags &= ~CHFL_VOICE;
1185 }
1186 }
1187
1188 void
1189 chm_limit(struct Client *source_p, struct Channel *chptr,
1190 int alevel, int parc, int *parn,
1191 const char **parv, int *errors, int dir, char c, long mode_type)
1192 {
1193 const char *lstr;
1194 static char limitstr[30];
1195 int limit;
1196
1197 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
1198 {
1199 if(!(*errors & SM_ERR_NOOPS))
1200 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1201 me.name, source_p->name, chptr->chname);
1202 *errors |= SM_ERR_NOOPS;
1203 return;
1204 }
1205
1206 if(dir == MODE_QUERY)
1207 return;
1208
1209 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1210 return;
1211
1212 if((dir == MODE_ADD) && parc > *parn)
1213 {
1214 lstr = parv[(*parn)];
1215 (*parn)++;
1216
1217 if(EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
1218 return;
1219
1220 rb_sprintf(limitstr, "%d", limit);
1221
1222 mode_changes[mode_count].letter = c;
1223 mode_changes[mode_count].dir = MODE_ADD;
1224 mode_changes[mode_count].caps = 0;
1225 mode_changes[mode_count].nocaps = 0;
1226 mode_changes[mode_count].mems = ALL_MEMBERS;
1227 mode_changes[mode_count].id = NULL;
1228 mode_changes[mode_count++].arg = limitstr;
1229
1230 chptr->mode.limit = limit;
1231 }
1232 else if(dir == MODE_DEL)
1233 {
1234 if(!chptr->mode.limit)
1235 return;
1236
1237 chptr->mode.limit = 0;
1238
1239 mode_changes[mode_count].letter = c;
1240 mode_changes[mode_count].dir = MODE_DEL;
1241 mode_changes[mode_count].caps = 0;
1242 mode_changes[mode_count].nocaps = 0;
1243 mode_changes[mode_count].mems = ALL_MEMBERS;
1244 mode_changes[mode_count].id = NULL;
1245 mode_changes[mode_count++].arg = NULL;
1246 }
1247 }
1248
1249 void
1250 chm_throttle(struct Client *source_p, struct Channel *chptr,
1251 int alevel, int parc, int *parn,
1252 const char **parv, int *errors, int dir, char c, long mode_type)
1253 {
1254 int joins = 0, timeslice = 0;
1255
1256 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
1257 {
1258 if(!(*errors & SM_ERR_NOOPS))
1259 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1260 me.name, source_p->name, chptr->chname);
1261 *errors |= SM_ERR_NOOPS;
1262 return;
1263 }
1264
1265 if(dir == MODE_QUERY)
1266 return;
1267
1268 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1269 return;
1270
1271 if((dir == MODE_ADD) && parc > *parn)
1272 {
1273 sscanf(parv[(*parn)], "%d:%d", &joins, &timeslice);
1274
1275 if(!joins || !timeslice)
1276 return;
1277
1278 mode_changes[mode_count].letter = c;
1279 mode_changes[mode_count].dir = MODE_ADD;
1280 mode_changes[mode_count].caps = 0;
1281 mode_changes[mode_count].nocaps = 0;
1282 mode_changes[mode_count].mems = ALL_MEMBERS;
1283 mode_changes[mode_count].id = NULL;
1284 mode_changes[mode_count++].arg = parv[(*parn)];
1285
1286 (*parn)++;
1287
1288 chptr->mode.join_num = joins;
1289 chptr->mode.join_time = timeslice;
1290 }
1291 else if(dir == MODE_DEL)
1292 {
1293 if(!chptr->mode.join_num)
1294 return;
1295
1296 chptr->mode.join_num = 0;
1297 chptr->mode.join_time = 0;
1298 chptr->join_count = 0;
1299 chptr->join_delta = 0;
1300
1301 mode_changes[mode_count].letter = c;
1302 mode_changes[mode_count].dir = MODE_DEL;
1303 mode_changes[mode_count].caps = 0;
1304 mode_changes[mode_count].nocaps = 0;
1305 mode_changes[mode_count].mems = ALL_MEMBERS;
1306 mode_changes[mode_count].id = NULL;
1307 mode_changes[mode_count++].arg = NULL;
1308 }
1309 }
1310
1311 void
1312 chm_forward(struct Client *source_p, struct Channel *chptr,
1313 int alevel, int parc, int *parn,
1314 const char **parv, int *errors, int dir, char c, long mode_type)
1315 {
1316 struct Channel *targptr = NULL;
1317 struct membership *msptr;
1318 const char *forward;
1319
1320 /* if +f is disabled, ignore local attempts to set it */
1321 if(!ConfigChannel.use_forward && MyClient(source_p) &&
1322 (dir == MODE_ADD) && (parc > *parn))
1323 return;
1324
1325 if(dir == MODE_QUERY || (dir == MODE_ADD && parc <= *parn))
1326 {
1327 if (!(*errors & SM_ERR_RPL_F))
1328 {
1329 if (*chptr->mode.forward == '\0')
1330 sendto_one_notice(source_p, ":%s has no forward channel", chptr->chname);
1331 else
1332 sendto_one_notice(source_p, ":%s forward channel is %s", chptr->chname, chptr->mode.forward);
1333 *errors |= SM_ERR_RPL_F;
1334 }
1335 return;
1336 }
1337
1338 #ifndef FORWARD_OPERONLY
1339 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
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 }
1347 #else
1348 if(!IsOper(source_p) && !IsServer(source_p))
1349 {
1350 if(!(*errors & SM_ERR_NOPRIVS))
1351 sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
1352 *errors |= SM_ERR_NOPRIVS;
1353 return;
1354 }
1355 #endif
1356
1357 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1358 return;
1359
1360 if(dir == MODE_ADD && parc > *parn)
1361 {
1362 forward = parv[(*parn)];
1363 (*parn)++;
1364
1365 if(EmptyString(forward))
1366 return;
1367 if(!check_channel_name(forward) ||
1368 (MyClient(source_p) && (strlen(forward) > LOC_CHANNELLEN || hash_find_resv(forward))))
1369 {
1370 sendto_one_numeric(source_p, ERR_BADCHANNAME, form_str(ERR_BADCHANNAME), forward);
1371 return;
1372 }
1373 /* don't forward to inconsistent target -- jilles */
1374 if(chptr->chname[0] == '#' && forward[0] == '&')
1375 {
1376 sendto_one_numeric(source_p, ERR_BADCHANNAME,
1377 form_str(ERR_BADCHANNAME), forward);
1378 return;
1379 }
1380 if(MyClient(source_p) && (targptr = find_channel(forward)) == NULL)
1381 {
1382 sendto_one_numeric(source_p, ERR_NOSUCHCHANNEL,
1383 form_str(ERR_NOSUCHCHANNEL), forward);
1384 return;
1385 }
1386 if(MyClient(source_p) && !(targptr->mode.mode & MODE_FREETARGET))
1387 {
1388 if((msptr = find_channel_membership(targptr, source_p)) == NULL ||
1389 is_any_op(msptr))
1390 {
1391 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1392 me.name, source_p->name, targptr->chname);
1393 return;
1394 }
1395 }
1396
1397 rb_strlcpy(chptr->mode.forward, forward, sizeof(chptr->mode.forward));
1398
1399 mode_changes[mode_count].letter = c;
1400 mode_changes[mode_count].dir = MODE_ADD;
1401 mode_changes[mode_count].caps = 0;
1402 mode_changes[mode_count].nocaps = 0;
1403 mode_changes[mode_count].mems = ConfigChannel.use_forward ? ALL_MEMBERS : ONLY_SERVERS;
1404 mode_changes[mode_count].id = NULL;
1405 mode_changes[mode_count++].arg = forward;
1406 }
1407 else if(dir == MODE_DEL)
1408 {
1409 if(!(*chptr->mode.forward))
1410 return;
1411
1412 *chptr->mode.forward = '\0';
1413
1414 mode_changes[mode_count].letter = c;
1415 mode_changes[mode_count].dir = MODE_DEL;
1416 mode_changes[mode_count].caps = 0;
1417 mode_changes[mode_count].nocaps = 0;
1418 mode_changes[mode_count].mems = ALL_MEMBERS;
1419 mode_changes[mode_count].id = NULL;
1420 mode_changes[mode_count++].arg = NULL;
1421 }
1422 }
1423
1424 void
1425 chm_key(struct Client *source_p, struct Channel *chptr,
1426 int alevel, int parc, int *parn,
1427 const char **parv, int *errors, int dir, char c, long mode_type)
1428 {
1429 char *key;
1430
1431 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
1432 {
1433 if(!(*errors & SM_ERR_NOOPS))
1434 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1435 me.name, source_p->name, chptr->chname);
1436 *errors |= SM_ERR_NOOPS;
1437 return;
1438 }
1439
1440 if(dir == MODE_QUERY)
1441 return;
1442
1443 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1444 return;
1445
1446 if((dir == MODE_ADD) && parc > *parn)
1447 {
1448 key = LOCAL_COPY(parv[(*parn)]);
1449 (*parn)++;
1450
1451 if(MyClient(source_p))
1452 fix_key(key);
1453 else
1454 fix_key_remote(key);
1455
1456 if(EmptyString(key))
1457 return;
1458
1459 s_assert(key[0] != ' ');
1460 rb_strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1461
1462 mode_changes[mode_count].letter = c;
1463 mode_changes[mode_count].dir = MODE_ADD;
1464 mode_changes[mode_count].caps = 0;
1465 mode_changes[mode_count].nocaps = 0;
1466 mode_changes[mode_count].mems = ALL_MEMBERS;
1467 mode_changes[mode_count].id = NULL;
1468 mode_changes[mode_count++].arg = chptr->mode.key;
1469 }
1470 else if(dir == MODE_DEL)
1471 {
1472 static char splat[] = "*";
1473 int i;
1474
1475 if(parc > *parn)
1476 (*parn)++;
1477
1478 if(!(*chptr->mode.key))
1479 return;
1480
1481 /* hack time. when we get a +k-k mode, the +k arg is
1482 * chptr->mode.key, which the -k sets to \0, so hunt for a
1483 * +k when we get a -k, and set the arg to splat. --anfl
1484 */
1485 for(i = 0; i < mode_count; i++)
1486 {
1487 if(mode_changes[i].letter == 'k' && mode_changes[i].dir == MODE_ADD)
1488 mode_changes[i].arg = splat;
1489 }
1490
1491 *chptr->mode.key = 0;
1492
1493 mode_changes[mode_count].letter = c;
1494 mode_changes[mode_count].dir = MODE_DEL;
1495 mode_changes[mode_count].caps = 0;
1496 mode_changes[mode_count].nocaps = 0;
1497 mode_changes[mode_count].mems = ALL_MEMBERS;
1498 mode_changes[mode_count].id = NULL;
1499 mode_changes[mode_count++].arg = "*";
1500 }
1501 }
1502
1503 void
1504 chm_regonly(struct Client *source_p, struct Channel *chptr,
1505 int alevel, int parc, int *parn,
1506 const char **parv, int *errors, int dir, char c, long mode_type)
1507 {
1508 if(alevel != CHFL_CHANOP && alevel != CHFL_OWNER && alevel != CHFL_HALFOP)
1509 {
1510 if(!(*errors & SM_ERR_NOOPS))
1511 sendto_one(source_p, form_str(ERR_CHANOPRIVSNEEDED),
1512 me.name, source_p->name, chptr->chname);
1513 *errors |= SM_ERR_NOOPS;
1514 return;
1515 }
1516
1517 if(dir == MODE_QUERY)
1518 return;
1519
1520 if(((dir == MODE_ADD) && (chptr->mode.mode & mode_type)) ||
1521 ((dir == MODE_DEL) && !(chptr->mode.mode & mode_type)))
1522 return;
1523
1524 if(MyClient(source_p) && (++mode_limit_simple > MAXMODES_SIMPLE))
1525 return;
1526
1527 if(dir == MODE_ADD)
1528 chptr->mode.mode |= mode_type;
1529 else
1530 chptr->mode.mode &= ~mode_type;
1531
1532 mode_changes[mode_count].letter = c;
1533 mode_changes[mode_count].dir = dir;
1534 mode_changes[mode_count].caps = CAP_SERVICE;
1535 mode_changes[mode_count].nocaps = 0;
1536 mode_changes[mode_count].mems = ALL_MEMBERS;
1537 mode_changes[mode_count].id = NULL;
1538 mode_changes[mode_count++].arg = NULL;
1539 }
1540
1541 /* *INDENT-OFF* */
1542 struct ChannelMode chmode_table[256] =
1543 {
1544 {chm_nosuch, 0 }, /* 0x00 */
1545 {chm_nosuch, 0 }, /* 0x01 */
1546 {chm_nosuch, 0 }, /* 0x02 */
1547 {chm_nosuch, 0 }, /* 0x03 */
1548 {chm_nosuch, 0 }, /* 0x04 */
1549 {chm_nosuch, 0 }, /* 0x05 */
1550 {chm_nosuch, 0 }, /* 0x06 */
1551 {chm_nosuch, 0 }, /* 0x07 */
1552 {chm_nosuch, 0 }, /* 0x08 */
1553 {chm_nosuch, 0 }, /* 0x09 */
1554 {chm_nosuch, 0 }, /* 0x0a */
1555 {chm_nosuch, 0 }, /* 0x0b */
1556 {chm_nosuch, 0 }, /* 0x0c */
1557 {chm_nosuch, 0 }, /* 0x0d */
1558 {chm_nosuch, 0 }, /* 0x0e */
1559 {chm_nosuch, 0 }, /* 0x0f */
1560 {chm_nosuch, 0 }, /* 0x10 */
1561 {chm_nosuch, 0 }, /* 0x11 */
1562 {chm_nosuch, 0 }, /* 0x12 */
1563 {chm_nosuch, 0 }, /* 0x13 */
1564 {chm_nosuch, 0 }, /* 0x14 */
1565 {chm_nosuch, 0 }, /* 0x15 */
1566 {chm_nosuch, 0 }, /* 0x16 */
1567 {chm_nosuch, 0 }, /* 0x17 */
1568 {chm_nosuch, 0 }, /* 0x18 */
1569 {chm_nosuch, 0 }, /* 0x19 */
1570 {chm_nosuch, 0 }, /* 0x1a */
1571 {chm_nosuch, 0 }, /* 0x1b */
1572 {chm_nosuch, 0 }, /* 0x1c */
1573 {chm_nosuch, 0 }, /* 0x1d */
1574 {chm_nosuch, 0 }, /* 0x1e */
1575 {chm_nosuch, 0 }, /* 0x1f */
1576 {chm_nosuch, 0 }, /* 0x20 */
1577 {chm_nosuch, 0 }, /* 0x21 */
1578 {chm_nosuch, 0 }, /* 0x22 */
1579 {chm_nosuch, 0 }, /* 0x23 */
1580 {chm_nosuch, 0 }, /* 0x24 */
1581 {chm_nosuch, 0 }, /* 0x25 */
1582 {chm_nosuch, 0 }, /* 0x26 */
1583 {chm_nosuch, 0 }, /* 0x27 */
1584 {chm_nosuch, 0 }, /* 0x28 */
1585 {chm_nosuch, 0 }, /* 0x29 */
1586 {chm_nosuch, 0 }, /* 0x2a */
1587 {chm_nosuch, 0 }, /* 0x2b */
1588 {chm_nosuch, 0 }, /* 0x2c */
1589 {chm_nosuch, 0 }, /* 0x2d */
1590 {chm_nosuch, 0 }, /* 0x2e */
1591 {chm_nosuch, 0 }, /* 0x2f */
1592 {chm_nosuch, 0 }, /* 0x30 */
1593 {chm_nosuch, 0 }, /* 0x31 */
1594 {chm_nosuch, 0 }, /* 0x32 */
1595 {chm_nosuch, 0 }, /* 0x33 */
1596 {chm_nosuch, 0 }, /* 0x34 */
1597 {chm_nosuch, 0 }, /* 0x35 */
1598 {chm_nosuch, 0 }, /* 0x36 */
1599 {chm_nosuch, 0 }, /* 0x37 */
1600 {chm_nosuch, 0 }, /* 0x38 */
1601 {chm_nosuch, 0 }, /* 0x39 */
1602 {chm_nosuch, 0 }, /* 0x3a */
1603 {chm_nosuch, 0 }, /* 0x3b */
1604 {chm_nosuch, 0 }, /* 0x3c */
1605 {chm_nosuch, 0 }, /* 0x3d */
1606 {chm_nosuch, 0 }, /* 0x3e */
1607 {chm_nosuch, 0 }, /* 0x3f */
1608
1609 {chm_nosuch, 0 }, /* @ */
1610 {chm_nosuch, 0 }, /* A */
1611 {chm_nosuch, 0 }, /* B */
1612 {chm_simple, MODE_NOCTCP }, /* C */
1613 {chm_simple, MODE_NOACTION }, /* D */
1614 {chm_simple, MODE_NOKICK }, /* E */
1615 {chm_simple, MODE_FREETARGET }, /* F */
1616 {chm_simple, MODE_NOCAPS }, /* G */
1617 {chm_nosuch, 0 }, /* H */
1618 {chm_ban, CHFL_INVEX }, /* I */
1619 {chm_simple, MODE_NOREJOIN }, /* J */
1620 {chm_simple, MODE_NOREPEAT }, /* K */
1621 {chm_staff, MODE_EXLIMIT }, /* L */
1622 {chm_nosuch, 0 }, /* M */
1623 {chm_simple, MODE_NONICK }, /* N */
1624 {chm_nosuch, 0 }, /* O */
1625 {chm_staff, MODE_PERMANENT }, /* P */
1626 {chm_simple, MODE_DISFORWARD }, /* Q */
1627 {chm_nosuch, 0 }, /* R */
1628 {chm_nosuch, 0 }, /* S */
1629 {chm_simple, MODE_NONOTICE }, /* T */
1630 {chm_nosuch, 0 }, /* U */
1631 {chm_nosuch, 0 }, /* V */
1632 {chm_nosuch, 0 }, /* W */
1633 {chm_nosuch, 0 }, /* X */
1634 {chm_nosuch, 0 }, /* Y */
1635 {chm_nosuch, 0 }, /* Z */
1636 {chm_nosuch, 0 },
1637 {chm_nosuch, 0 },
1638 {chm_nosuch, 0 },
1639 {chm_nosuch, 0 },
1640 {chm_nosuch, 0 },
1641 {chm_nosuch, 0 },
1642 {chm_owner, 0 }, /* a */
1643 {chm_ban, CHFL_BAN }, /* b */
1644 {chm_simple, MODE_NOCOLOR }, /* c */
1645 {chm_nosuch, 0 }, /* d */
1646 {chm_ban, CHFL_EXCEPTION }, /* e */
1647 {chm_forward, 0 }, /* f */
1648 {chm_simple, MODE_FREEINVITE }, /* g */
1649 {chm_halfop, 0 }, /* h */
1650 {chm_simple, MODE_INVITEONLY }, /* i */
1651 {chm_throttle, 0 }, /* j */
1652 {chm_key, 0 }, /* k */
1653 {chm_limit, 0 }, /* l */
1654 {chm_simple, MODE_MODERATED }, /* m */
1655 {chm_simple, MODE_NOPRIVMSGS }, /* n */
1656 {chm_op, 0 }, /* o */
1657 {chm_simple, MODE_PRIVATE }, /* p */
1658 {chm_ban, CHFL_QUIET }, /* q */
1659 {chm_regonly, MODE_REGONLY }, /* r */
1660 {chm_simple, MODE_SECRET }, /* s */
1661 {chm_simple, MODE_TOPICLIMIT }, /* t */
1662 {chm_nosuch, 0 }, /* u */
1663 {chm_voice, 0 }, /* v */
1664 {chm_nosuch, 0 }, /* w */
1665 {chm_nosuch, 0 }, /* x */
1666 {chm_nosuch, 0 }, /* y */
1667 {chm_simple, MODE_OPMODERATE }, /* z */
1668
1669 {chm_nosuch, 0 }, /* 0x7b */
1670 {chm_nosuch, 0 }, /* 0x7c */
1671 {chm_nosuch, 0 }, /* 0x7d */
1672 {chm_nosuch, 0 }, /* 0x7e */
1673 {chm_nosuch, 0 }, /* 0x7f */
1674
1675 {chm_nosuch, 0 }, /* 0x80 */
1676 {chm_nosuch, 0 }, /* 0x81 */
1677 {chm_nosuch, 0 }, /* 0x82 */
1678 {chm_nosuch, 0 }, /* 0x83 */
1679 {chm_nosuch, 0 }, /* 0x84 */
1680 {chm_nosuch, 0 }, /* 0x85 */
1681 {chm_nosuch, 0 }, /* 0x86 */
1682 {chm_nosuch, 0 }, /* 0x87 */
1683 {chm_nosuch, 0 }, /* 0x88 */
1684 {chm_nosuch, 0 }, /* 0x89 */
1685 {chm_nosuch, 0 }, /* 0x8a */
1686 {chm_nosuch, 0 }, /* 0x8b */
1687 {chm_nosuch, 0 }, /* 0x8c */
1688 {chm_nosuch, 0 }, /* 0x8d */
1689 {chm_nosuch, 0 }, /* 0x8e */
1690 {chm_nosuch, 0 }, /* 0x8f */
1691
1692 {chm_nosuch, 0 }, /* 0x90 */
1693 {chm_nosuch, 0 }, /* 0x91 */
1694 {chm_nosuch, 0 }, /* 0x92 */
1695 {chm_nosuch, 0 }, /* 0x93 */
1696 {chm_nosuch, 0 }, /* 0x94 */
1697 {chm_nosuch, 0 }, /* 0x95 */
1698 {chm_nosuch, 0 }, /* 0x96 */
1699 {chm_nosuch, 0 }, /* 0x97 */
1700 {chm_nosuch, 0 }, /* 0x98 */
1701 {chm_nosuch, 0 }, /* 0x99 */
1702 {chm_nosuch, 0 }, /* 0x9a */
1703 {chm_nosuch, 0 }, /* 0x9b */
1704 {chm_nosuch, 0 }, /* 0x9c */
1705 {chm_nosuch, 0 }, /* 0x9d */
1706 {chm_nosuch, 0 }, /* 0x9e */
1707 {chm_nosuch, 0 }, /* 0x9f */
1708
1709 {chm_nosuch, 0 }, /* 0xa0 */
1710 {chm_nosuch, 0 }, /* 0xa1 */
1711 {chm_nosuch, 0 }, /* 0xa2 */
1712 {chm_nosuch, 0 }, /* 0xa3 */
1713 {chm_nosuch, 0 }, /* 0xa4 */
1714 {chm_nosuch, 0 }, /* 0xa5 */
1715 {chm_nosuch, 0 }, /* 0xa6 */
1716 {chm_nosuch, 0 }, /* 0xa7 */
1717 {chm_nosuch, 0 }, /* 0xa8 */
1718 {chm_nosuch, 0 }, /* 0xa9 */
1719 {chm_nosuch, 0 }, /* 0xaa */
1720 {chm_nosuch, 0 }, /* 0xab */
1721 {chm_nosuch, 0 }, /* 0xac */
1722 {chm_nosuch, 0 }, /* 0xad */
1723 {chm_nosuch, 0 }, /* 0xae */
1724 {chm_nosuch, 0 }, /* 0xaf */
1725
1726 {chm_nosuch, 0 }, /* 0xb0 */
1727 {chm_nosuch, 0 }, /* 0xb1 */
1728 {chm_nosuch, 0 }, /* 0xb2 */
1729 {chm_nosuch, 0 }, /* 0xb3 */
1730 {chm_nosuch, 0 }, /* 0xb4 */
1731 {chm_nosuch, 0 }, /* 0xb5 */
1732 {chm_nosuch, 0 }, /* 0xb6 */
1733 {chm_nosuch, 0 }, /* 0xb7 */
1734 {chm_nosuch, 0 }, /* 0xb8 */
1735 {chm_nosuch, 0 }, /* 0xb9 */
1736 {chm_nosuch, 0 }, /* 0xba */
1737 {chm_nosuch, 0 }, /* 0xbb */
1738 {chm_nosuch, 0 }, /* 0xbc */
1739 {chm_nosuch, 0 }, /* 0xbd */
1740 {chm_nosuch, 0 }, /* 0xbe */
1741 {chm_nosuch, 0 }, /* 0xbf */
1742
1743 {chm_nosuch, 0 }, /* 0xc0 */
1744 {chm_nosuch, 0 }, /* 0xc1 */
1745 {chm_nosuch, 0 }, /* 0xc2 */
1746 {chm_nosuch, 0 }, /* 0xc3 */
1747 {chm_nosuch, 0 }, /* 0xc4 */
1748 {chm_nosuch, 0 }, /* 0xc5 */
1749 {chm_nosuch, 0 }, /* 0xc6 */
1750 {chm_nosuch, 0 }, /* 0xc7 */
1751 {chm_nosuch, 0 }, /* 0xc8 */
1752 {chm_nosuch, 0 }, /* 0xc9 */
1753 {chm_nosuch, 0 }, /* 0xca */
1754 {chm_nosuch, 0 }, /* 0xcb */
1755 {chm_nosuch, 0 }, /* 0xcc */
1756 {chm_nosuch, 0 }, /* 0xcd */
1757 {chm_nosuch, 0 }, /* 0xce */
1758 {chm_nosuch, 0 }, /* 0xcf */
1759
1760 {chm_nosuch, 0 }, /* 0xd0 */
1761 {chm_nosuch, 0 }, /* 0xd1 */
1762 {chm_nosuch, 0 }, /* 0xd2 */
1763 {chm_nosuch, 0 }, /* 0xd3 */
1764 {chm_nosuch, 0 }, /* 0xd4 */
1765 {chm_nosuch, 0 }, /* 0xd5 */
1766 {chm_nosuch, 0 }, /* 0xd6 */
1767 {chm_nosuch, 0 }, /* 0xd7 */
1768 {chm_nosuch, 0 }, /* 0xd8 */
1769 {chm_nosuch, 0 }, /* 0xd9 */
1770 {chm_nosuch, 0 }, /* 0xda */
1771 {chm_nosuch, 0 }, /* 0xdb */
1772 {chm_nosuch, 0 }, /* 0xdc */
1773 {chm_nosuch, 0 }, /* 0xdd */
1774 {chm_nosuch, 0 }, /* 0xde */
1775 {chm_nosuch, 0 }, /* 0xdf */
1776
1777 {chm_nosuch, 0 }, /* 0xe0 */
1778 {chm_nosuch, 0 }, /* 0xe1 */
1779 {chm_nosuch, 0 }, /* 0xe2 */
1780 {chm_nosuch, 0 }, /* 0xe3 */
1781 {chm_nosuch, 0 }, /* 0xe4 */
1782 {chm_nosuch, 0 }, /* 0xe5 */
1783 {chm_nosuch, 0 }, /* 0xe6 */
1784 {chm_nosuch, 0 }, /* 0xe7 */
1785 {chm_nosuch, 0 }, /* 0xe8 */
1786 {chm_nosuch, 0 }, /* 0xe9 */
1787 {chm_nosuch, 0 }, /* 0xea */
1788 {chm_nosuch, 0 }, /* 0xeb */
1789 {chm_nosuch, 0 }, /* 0xec */
1790 {chm_nosuch, 0 }, /* 0xed */
1791 {chm_nosuch, 0 }, /* 0xee */
1792 {chm_nosuch, 0 }, /* 0xef */
1793
1794 {chm_nosuch, 0 }, /* 0xf0 */
1795 {chm_nosuch, 0 }, /* 0xf1 */
1796 {chm_nosuch, 0 }, /* 0xf2 */
1797 {chm_nosuch, 0 }, /* 0xf3 */
1798 {chm_nosuch, 0 }, /* 0xf4 */
1799 {chm_nosuch, 0 }, /* 0xf5 */
1800 {chm_nosuch, 0 }, /* 0xf6 */
1801 {chm_nosuch, 0 }, /* 0xf7 */
1802 {chm_nosuch, 0 }, /* 0xf8 */
1803 {chm_nosuch, 0 }, /* 0xf9 */
1804 {chm_nosuch, 0 }, /* 0xfa */
1805 {chm_nosuch, 0 }, /* 0xfb */
1806 {chm_nosuch, 0 }, /* 0xfc */
1807 {chm_nosuch, 0 }, /* 0xfd */
1808 {chm_nosuch, 0 }, /* 0xfe */
1809 {chm_nosuch, 0 }, /* 0xff */
1810 };
1811
1812 /* *INDENT-ON* */
1813
1814 /* set_channel_mode()
1815 *
1816 * inputs - client, source, channel, membership pointer, params
1817 * output -
1818 * side effects - channel modes/memberships are changed, MODE is issued
1819 *
1820 * Extensively modified to be hotpluggable, 03/09/06 -- nenolod
1821 */
1822 void
1823 set_channel_mode(struct Client *client_p, struct Client *source_p,
1824 struct Channel *chptr, struct membership *msptr, int parc, const char *parv[])
1825 {
1826 static char cmdbuf[BUFSIZE];
1827 static char modebuf[BUFSIZE];
1828 static char parabuf[BUFSIZE];
1829 char *mbuf;
1830 char *pbuf;
1831 int cur_len, mlen, paralen, paracount, arglen, len;
1832 int i, j, flags, override;
1833 int dir = MODE_ADD;
1834 int parn = 1;
1835 int errors = 0;
1836 int alevel;
1837 const char *ml = parv[0];
1838 char c;
1839 struct Client *fakesource_p;
1840
1841 mask_pos = 0;
1842 mode_count = 0;
1843 mode_limit = 0;
1844 mode_limit_simple = 0;
1845
1846 alevel = get_channel_access(source_p, msptr);
1847
1848 /* Hide connecting server on netburst -- jilles */
1849 if (ConfigServerHide.flatten_links && IsServer(source_p) && !has_id(source_p) && !HasSentEob(source_p))
1850 fakesource_p = &me;
1851 else
1852 fakesource_p = source_p;
1853
1854 for(; (c = *ml) != 0; ml++)
1855 {
1856 switch (c)
1857 {
1858 case '+':
1859 dir = MODE_ADD;
1860 break;
1861 case '-':
1862 dir = MODE_DEL;
1863 break;
1864 case '=':
1865 dir = MODE_QUERY;
1866 break;
1867 default:
1868 chmode_table[(unsigned char) c].set_func(fakesource_p, chptr, alevel,
1869 parc, &parn, parv,
1870 &errors, dir, c,
1871 chmode_table[(unsigned char) c].mode_type);
1872 break;
1873 }
1874 }
1875
1876 /* bail out if we have nothing to do... */
1877 if(!mode_count)
1878 return;
1879
1880 if(IsServer(source_p))
1881 rb_sprintf(cmdbuf, ":%s MODE %s ", fakesource_p->name, chptr->chname);
1882 else
1883 rb_sprintf(cmdbuf, ":%s!%s@%s MODE %s ",
1884 source_p->name, source_p->username,
1885 source_p->host, chptr->chname);
1886
1887 for (override = 0; override < (IsOverride(source_p) ? 2 : 1); ++override)
1888 {
1889 int was_on_chan = 0;
1890 if(override)
1891 {
1892 if(msptr)
1893 was_on_chan = 1;
1894 else
1895 add_user_to_channel(chptr, source_p, 0);
1896 }
1897
1898 for(j = 0, flags = ALL_MEMBERS; j < 2; j++, flags = ONLY_CHANOPS)
1899 {
1900 cur_len = mlen;
1901 mbuf = modebuf + mlen;
1902 pbuf = parabuf;
1903 parabuf[0] = '\0';
1904 paracount = paralen = 0;
1905 dir = MODE_QUERY;
1906
1907 for(i = 0; i < mode_count; i++)
1908 {
1909 if(mode_changes[i].letter == 0 || mode_changes[i].mems != flags)
1910
1911 if(mode_changes[i].override != override)
1912 continue;
1913
1914 if(mode_changes[i].arg != NULL)
1915 {
1916 arglen = strlen(mode_changes[i].arg);
1917
1918 if(arglen > MODEBUFLEN - 5)
1919 continue;
1920 }
1921 else
1922 arglen = 0;
1923
1924 /* if we're creeping over MAXMODEPARAMSSERV, or over
1925 * bufsize (4 == +/-,modechar,two spaces) send now.
1926 */
1927 if(mode_changes[i].arg != NULL &&
1928 ((paracount == MAXMODEPARAMSSERV) ||
1929 ((cur_len + paralen + arglen + 4) > (BUFSIZE - 3))))
1930 {
1931 *mbuf = '\0';
1932
1933 if(cur_len > mlen)
1934 {
1935 sendto_channel_local(flags, chptr, "%s%s %s",
1936 cmdbuf, modebuf, parabuf);
1937 if(override)
1938 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
1939 "%s is overriding modes on %s: %s %s",
1940 get_oper_name(source_p), chptr->chname,
1941 modebuf, parabuf);
1942 }
1943 else
1944 continue;
1945
1946 paracount = paralen = 0;
1947 cur_len = mlen;
1948 mbuf = modebuf + mlen;
1949 pbuf = parabuf;
1950 parabuf[0] = '\0';
1951 dir = MODE_QUERY;
1952 }
1953
1954 if(dir != mode_changes[i].dir)
1955 {
1956 *mbuf++ = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1957 cur_len++;
1958 dir = mode_changes[i].dir;
1959 }
1960
1961 *mbuf++ = mode_changes[i].letter;
1962 cur_len++;
1963
1964 if(mode_changes[i].arg != NULL)
1965 {
1966 paracount++;
1967 len = rb_sprintf(pbuf, "%s ", mode_changes[i].arg);
1968 pbuf += len;
1969 paralen += len;
1970 }
1971 }
1972
1973 if(override && !was_on_chan)
1974 remove_user_from_channel(find_channel_membership(chptr, source_p));
1975 }
1976 /* only propagate modes originating locally, or if we're hubbing */
1977 if(MyClient(source_p) || rb_dlink_list_length(&serv_list) > 1)
1978 send_cap_mode_changes(client_p, source_p, chptr, mode_changes, mode_count);
1979 }
1980 }