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