ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/channel_mode.c
Revision: 8017
Committed: Thu Mar 16 16:41:58 2017 UTC (7 years ago) by michael
Content type: text/x-csrc
File size: 42423 byte(s)
Log Message:
- channel_mode.c:chm_ban, chm_except, chm_invex: add some comments about the max length of 'mask'

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2017 ircd-hybrid development team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
19 * USA
20 */
21
22 /*! \file channel_mode.c
23 * \brief Controls modes on channels.
24 * \version $Id$
25 */
26
27 #include "stdinc.h"
28 #include "list.h"
29 #include "channel.h"
30 #include "channel_mode.h"
31 #include "client.h"
32 #include "conf.h"
33 #include "hostmask.h"
34 #include "irc_string.h"
35 #include "ircd.h"
36 #include "numeric.h"
37 #include "server.h"
38 #include "send.h"
39 #include "memory.h"
40 #include "mempool.h"
41 #include "parse.h"
42
43
44 static char nuh_mask[MAXPARA][IRCD_BUFSIZE];
45 static struct ChModeChange mode_changes[IRCD_BUFSIZE];
46 static unsigned int mode_count;
47 static unsigned int mode_limit; /* number of modes set other than simple */
48 static unsigned int simple_modes_mask; /* bit mask of simple modes already set */
49 extern mp_pool_t *ban_pool;
50
51 const struct mode_letter chan_modes[] =
52 {
53 { MODE_NOCTRL, 'c' },
54 { MODE_INVITEONLY, 'i' },
55 { MODE_MODERATED, 'm' },
56 { MODE_NOPRIVMSGS, 'n' },
57 { MODE_PRIVATE, 'p' },
58 { MODE_REGISTERED, 'r' },
59 { MODE_SECRET, 's' },
60 { MODE_TOPICLIMIT, 't' },
61 { MODE_NOCTCP, 'C' },
62 { MODE_MODREG, 'M' },
63 { MODE_OPERONLY, 'O' },
64 { MODE_REGONLY, 'R' },
65 { MODE_SSLONLY, 'S' },
66 { MODE_NONOTICE, 'T' },
67 { 0, '\0' }
68 };
69
70
71 /* check_string()
72 *
73 * inputs - string to check
74 * output - pointer to modified string
75 * side effects - Fixes a string so that the first white space found
76 * becomes an end of string marker (`\0`).
77 * returns the 'fixed' string or "*" if the string
78 * was NULL length or a NULL pointer.
79 */
80 static char *
81 check_string(char *s)
82 {
83 char *const str = s;
84 static char star[] = "*";
85
86 if (EmptyString(str))
87 return star;
88
89 for (; *s; ++s)
90 {
91 if (IsSpace(*s))
92 {
93 *s = '\0';
94 break;
95 }
96 }
97
98 return EmptyString(str) ? star : str;
99 }
100
101 /*
102 * Ban functions to work with mode +b/e/I
103 */
104 /* add the specified ID to the channel.
105 * -is 8/9/00
106 */
107
108 int
109 add_id(struct Client *client_p, struct Channel *chptr, char *banid, unsigned int type)
110 {
111 dlink_list *list;
112 dlink_node *node;
113 char name[NICKLEN + 1] = "";
114 char user[USERLEN + 1] = "";
115 char host[HOSTLEN + 1] = "";
116 struct split_nuh_item nuh;
117
118 /* Don't let local clients overflow the b/e/I lists */
119 if (MyClient(client_p))
120 {
121 unsigned int num_mask = dlink_list_length(&chptr->banlist) +
122 dlink_list_length(&chptr->exceptlist) +
123 dlink_list_length(&chptr->invexlist);
124
125 if (num_mask >= ConfigChannel.max_bans)
126 {
127 sendto_one_numeric(client_p, &me, ERR_BANLISTFULL, chptr->name, banid);
128 return 0;
129 }
130
131 collapse(banid);
132 }
133
134 nuh.nuhmask = check_string(banid);
135 nuh.nickptr = name;
136 nuh.userptr = user;
137 nuh.hostptr = host;
138
139 nuh.nicksize = sizeof(name);
140 nuh.usersize = sizeof(user);
141 nuh.hostsize = sizeof(host);
142
143 split_nuh(&nuh);
144
145 /*
146 * Re-assemble a new n!u@h and print it back to banid for sending
147 * the mode to the channel.
148 */
149 size_t len = snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
150
151 switch (type)
152 {
153 case CHFL_BAN:
154 list = &chptr->banlist;
155 clear_ban_cache_list(&chptr->locmembers);
156 break;
157 case CHFL_EXCEPTION:
158 list = &chptr->exceptlist;
159 clear_ban_cache_list(&chptr->locmembers);
160 break;
161 case CHFL_INVEX:
162 list = &chptr->invexlist;
163 break;
164 default:
165 list = NULL; /* Let it crash */
166 }
167
168 DLINK_FOREACH(node, list->head)
169 {
170 const struct Ban *ban = node->data;
171
172 if (!irccmp(ban->name, name) &&
173 !irccmp(ban->user, user) &&
174 !irccmp(ban->host, host))
175 return 0;
176 }
177
178 struct Ban *ban = mp_pool_get(ban_pool);
179 ban->when = CurrentTime;
180 ban->len = len - 2; /* -2 for ! + @ */
181 ban->type = parse_netmask(host, &ban->addr, &ban->bits);
182 strlcpy(ban->name, name, sizeof(ban->name));
183 strlcpy(ban->user, user, sizeof(ban->user));
184 strlcpy(ban->host, host, sizeof(ban->host));
185
186 if (IsClient(client_p))
187 snprintf(ban->who, sizeof(ban->who), "%s!%s@%s", client_p->name,
188 client_p->username, client_p->host);
189 else if (IsHidden(client_p) || ConfigServerHide.hide_servers)
190 strlcpy(ban->who, me.name, sizeof(ban->who));
191 else
192 strlcpy(ban->who, client_p->name, sizeof(ban->who));
193
194 dlinkAdd(ban, &ban->node, list);
195
196 return 1;
197 }
198
199 /*
200 * inputs - pointer to channel
201 * - pointer to ban id
202 * - type of ban, i.e. ban, exception, invex
203 * output - 0 for failure, 1 for success
204 * side effects -
205 */
206 static int
207 del_id(struct Channel *chptr, char *banid, unsigned int type)
208 {
209 dlink_list *list;
210 dlink_node *node;
211 char name[NICKLEN + 1] = "";
212 char user[USERLEN + 1] = "";
213 char host[HOSTLEN + 1] = "";
214 struct split_nuh_item nuh;
215
216 assert(banid);
217
218 nuh.nuhmask = check_string(banid);
219 nuh.nickptr = name;
220 nuh.userptr = user;
221 nuh.hostptr = host;
222
223 nuh.nicksize = sizeof(name);
224 nuh.usersize = sizeof(user);
225 nuh.hostsize = sizeof(host);
226
227 split_nuh(&nuh);
228
229 /*
230 * Re-assemble a new n!u@h and print it back to banid for sending
231 * the mode to the channel.
232 */
233 snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
234
235 switch (type)
236 {
237 case CHFL_BAN:
238 list = &chptr->banlist;
239 clear_ban_cache_list(&chptr->locmembers);
240 break;
241 case CHFL_EXCEPTION:
242 list = &chptr->exceptlist;
243 clear_ban_cache_list(&chptr->locmembers);
244 break;
245 case CHFL_INVEX:
246 list = &chptr->invexlist;
247 break;
248 default:
249 list = NULL; /* Let it crash */
250 }
251
252 DLINK_FOREACH(node, list->head)
253 {
254 struct Ban *ban = node->data;
255
256 if (!irccmp(name, ban->name) &&
257 !irccmp(user, ban->user) &&
258 !irccmp(host, ban->host))
259 {
260 remove_ban(ban, list);
261 return 1;
262 }
263 }
264
265 return 0;
266 }
267
268 /* channel_modes()
269 *
270 * inputs - pointer to channel
271 * - pointer to client
272 * - pointer to mode buf
273 * - pointer to parameter buf
274 * output - NONE
275 * side effects - write the "simple" list of channel modes for channel
276 * chptr onto buffer mbuf with the parameters in pbuf.
277 */
278 void
279 channel_modes(struct Channel *chptr, struct Client *client_p, char *mbuf, char *pbuf)
280 {
281 *mbuf++ = '+';
282 *pbuf = '\0';
283
284 for (const struct mode_letter *tab = chan_modes; tab->mode; ++tab)
285 if (chptr->mode.mode & tab->mode)
286 *mbuf++ = tab->letter;
287
288 if (chptr->mode.limit)
289 {
290 *mbuf++ = 'l';
291
292 if (IsServer(client_p) || IsMember(client_p, chptr))
293 pbuf += sprintf(pbuf, "%u ", chptr->mode.limit);
294 }
295
296 if (chptr->mode.key[0])
297 {
298 *mbuf++ = 'k';
299
300 if (IsServer(client_p) || IsMember(client_p, chptr))
301 sprintf(pbuf, "%s ", chptr->mode.key);
302 }
303
304 *mbuf = '\0';
305 }
306
307 /* fix_key()
308 *
309 * inputs - pointer to key to clean up
310 * output - pointer to cleaned up key
311 * side effects - input string is modified
312 *
313 * stolen from Undernet's ircd -orabidoo
314 */
315 static char *
316 fix_key(char *arg)
317 {
318 unsigned char *s, *t, c;
319
320 for (s = t = (unsigned char *)arg; (c = *s); ++s)
321 {
322 c &= 0x7f;
323
324 if (c != ':' && c > ' ' && c != ',')
325 *t++ = c;
326 }
327
328 *t = '\0';
329 return arg;
330 }
331
332 /*
333 * inputs - pointer to channel
334 * output - none
335 * side effects - clear ban cache
336 */
337 void
338 clear_ban_cache_list(dlink_list *list)
339 {
340 dlink_node *node;
341
342 DLINK_FOREACH(node, list->head)
343 {
344 struct Membership *member = node->data;
345 member->flags &= ~(CHFL_BAN_SILENCED | CHFL_BAN_CHECKED);
346 }
347 }
348
349 /*
350 * Bitmasks for various error returns that set_channel_mode should only return
351 * once per call -orabidoo
352 */
353 enum
354 {
355 SM_ERR_NOOPS = 1 << 0, /* No chan ops */
356 SM_ERR_UNKNOWN = 1 << 1,
357 SM_ERR_RPL_B = 1 << 2,
358 SM_ERR_RPL_E = 1 << 3,
359 SM_ERR_RPL_I = 1 << 4,
360 SM_ERR_NOTONCHANNEL = 1 << 5, /* Client is not on channel */
361 SM_ERR_NOTOPER = 1 << 6,
362 SM_ERR_ONLYSERVER = 1 << 7
363 };
364
365 /* Mode functions handle mode changes for a particular mode... */
366 static void
367 chm_nosuch(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
368 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
369 {
370 if (*errors & SM_ERR_UNKNOWN)
371 return;
372
373 *errors |= SM_ERR_UNKNOWN;
374 sendto_one_numeric(source_p, &me, ERR_UNKNOWNMODE, c);
375 }
376
377 static void
378 chm_simple(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
379 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
380 {
381 if (alev < CHACCESS_HALFOP)
382 {
383 if (!(*errors & SM_ERR_NOOPS))
384 sendto_one_numeric(source_p, &me,
385 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
386 ERR_CHANOPRIVSNEEDED, chptr->name);
387
388 *errors |= SM_ERR_NOOPS;
389 return;
390 }
391
392 /* If have already dealt with this simple mode, ignore it */
393 if (simple_modes_mask & d)
394 return;
395
396 simple_modes_mask |= d;
397
398 /* setting + */
399 /* Apparently, (though no one has ever told the hybrid group directly)
400 * admins don't like redundant mode checking. ok. It would have been nice
401 * if you had have told us directly. I've left the original code snippets
402 * in place.
403 *
404 * -Dianora
405 */
406 if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
407 {
408 chptr->mode.mode |= d;
409
410 mode_changes[mode_count].letter = c;
411 mode_changes[mode_count].arg = NULL;
412 mode_changes[mode_count].id = NULL;
413 mode_changes[mode_count++].dir = dir;
414 }
415 else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
416 {
417 /* setting - */
418
419 chptr->mode.mode &= ~d;
420
421 mode_changes[mode_count].letter = c;
422 mode_changes[mode_count].arg = NULL;
423 mode_changes[mode_count].id = NULL;
424 mode_changes[mode_count++].dir = dir;
425 }
426 }
427
428 static void
429 chm_registered(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
430 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
431 {
432 if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
433 {
434 if (!(*errors & SM_ERR_ONLYSERVER))
435 sendto_one_numeric(source_p, &me,
436 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
437 ERR_ONLYSERVERSCANCHANGE, chptr->name);
438
439 *errors |= SM_ERR_ONLYSERVER;
440 return;
441 }
442
443 /* If have already dealt with this simple mode, ignore it */
444 if (simple_modes_mask & d)
445 return;
446
447 simple_modes_mask |= d;
448
449 /* setting + */
450 /* Apparently, (though no one has ever told the hybrid group directly)
451 * admins don't like redundant mode checking. ok. It would have been nice
452 * if you had have told us directly. I've left the original code snippets
453 * in place.
454 *
455 * -Dianora
456 */
457 if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
458 {
459 chptr->mode.mode |= d;
460
461 mode_changes[mode_count].letter = c;
462 mode_changes[mode_count].arg = NULL;
463 mode_changes[mode_count].id = NULL;
464 mode_changes[mode_count++].dir = dir;
465 }
466 else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
467 {
468 /* setting - */
469
470 chptr->mode.mode &= ~d;
471
472 mode_changes[mode_count].letter = c;
473 mode_changes[mode_count].arg = NULL;
474 mode_changes[mode_count].id = NULL;
475 mode_changes[mode_count++].dir = dir;
476 }
477 }
478
479 static void
480 chm_operonly(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
481 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
482 {
483 if (alev < CHACCESS_HALFOP)
484 {
485 if (!(*errors & SM_ERR_NOOPS))
486 sendto_one_numeric(source_p, &me,
487 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
488 ERR_CHANOPRIVSNEEDED, chptr->name);
489
490 *errors |= SM_ERR_NOOPS;
491 return;
492 }
493
494 if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
495 {
496 if (!(*errors & SM_ERR_NOTOPER))
497 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
498
499 *errors |= SM_ERR_NOTOPER;
500 return;
501 }
502
503 /* If have already dealt with this simple mode, ignore it */
504 if (simple_modes_mask & d)
505 return;
506
507 simple_modes_mask |= d;
508
509 if (dir == MODE_ADD) /* && !(chptr->mode.mode & d)) */
510 {
511 chptr->mode.mode |= d;
512
513 mode_changes[mode_count].letter = c;
514 mode_changes[mode_count].arg = NULL;
515 mode_changes[mode_count].id = NULL;
516 mode_changes[mode_count++].dir = dir;
517 }
518 else if (dir == MODE_DEL) /* && (chptr->mode.mode & d)) */
519 {
520 /* setting - */
521
522 chptr->mode.mode &= ~d;
523
524 mode_changes[mode_count].letter = c;
525 mode_changes[mode_count].arg = NULL;
526 mode_changes[mode_count].id = NULL;
527 mode_changes[mode_count++].dir = dir;
528 }
529 }
530
531 static void
532 chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
533 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
534 {
535 if (dir == MODE_QUERY || parc <= *parn)
536 {
537 dlink_node *node;
538
539 if (*errors & SM_ERR_RPL_B)
540 return;
541
542 *errors |= SM_ERR_RPL_B;
543
544 DLINK_FOREACH(node, chptr->banlist.head)
545 {
546 const struct Ban *ban = node->data;
547 sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
548 ban->name, ban->user, ban->host,
549 ban->who, ban->when);
550 }
551
552 sendto_one_numeric(source_p, &me, RPL_ENDOFBANLIST, chptr->name);
553 return;
554 }
555
556 if (alev < CHACCESS_HALFOP)
557 {
558 if (!(*errors & SM_ERR_NOOPS))
559 sendto_one_numeric(source_p, &me,
560 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
561 ERR_CHANOPRIVSNEEDED, chptr->name);
562
563 *errors |= SM_ERR_NOOPS;
564 return;
565 }
566
567 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
568 return;
569
570 char *mask = nuh_mask[*parn];
571 strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
572 ++(*parn);
573
574 if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
575 return;
576
577 switch (dir)
578 {
579 case MODE_ADD:
580 if (!add_id(source_p, chptr, mask, CHFL_BAN))
581 return;
582 break;
583 case MODE_DEL:
584 if (!del_id(chptr, mask, CHFL_BAN))
585 return;
586 break;
587 default:
588 assert(0);
589 }
590
591 mode_changes[mode_count].letter = c;
592 mode_changes[mode_count].arg = mask; /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
593 mode_changes[mode_count].id = NULL;
594 mode_changes[mode_count++].dir = dir;
595 }
596
597 static void
598 chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
599 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
600 {
601 if (dir == MODE_QUERY || parc <= *parn)
602 {
603 dlink_node *node;
604
605 if (*errors & SM_ERR_RPL_E)
606 return;
607
608 *errors |= SM_ERR_RPL_E;
609
610 DLINK_FOREACH(node, chptr->exceptlist.head)
611 {
612 const struct Ban *ban = node->data;
613 sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
614 ban->name, ban->user, ban->host,
615 ban->who, ban->when);
616 }
617
618 sendto_one_numeric(source_p, &me, RPL_ENDOFEXCEPTLIST, chptr->name);
619 return;
620 }
621
622 if (alev < CHACCESS_HALFOP)
623 {
624 if (!(*errors & SM_ERR_NOOPS))
625 sendto_one_numeric(source_p, &me,
626 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
627 ERR_CHANOPRIVSNEEDED, chptr->name);
628
629 *errors |= SM_ERR_NOOPS;
630 return;
631 }
632
633 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
634 return;
635
636 char *mask = nuh_mask[*parn];
637 strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
638 ++(*parn);
639
640 if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
641 return;
642
643 switch (dir)
644 {
645 case MODE_ADD:
646 if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION))
647 return;
648 break;
649 case MODE_DEL:
650 if (!del_id(chptr, mask, CHFL_EXCEPTION))
651 return;
652 break;
653 default:
654 assert(0);
655 }
656
657 mode_changes[mode_count].letter = c;
658 mode_changes[mode_count].arg = mask; /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
659 mode_changes[mode_count].id = NULL;
660 mode_changes[mode_count++].dir = dir;
661 }
662
663 static void
664 chm_invex(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
665 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
666 {
667 if (dir == MODE_QUERY || parc <= *parn)
668 {
669 dlink_node *node;
670
671 if (*errors & SM_ERR_RPL_I)
672 return;
673
674 *errors |= SM_ERR_RPL_I;
675
676 DLINK_FOREACH(node, chptr->invexlist.head)
677 {
678 const struct Ban *ban = node->data;
679 sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
680 ban->name, ban->user, ban->host,
681 ban->who, ban->when);
682 }
683
684 sendto_one_numeric(source_p, &me, RPL_ENDOFINVEXLIST, chptr->name);
685 return;
686 }
687
688 if (alev < CHACCESS_HALFOP)
689 {
690 if (!(*errors & SM_ERR_NOOPS))
691 sendto_one_numeric(source_p, &me,
692 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
693 ERR_CHANOPRIVSNEEDED, chptr->name);
694
695 *errors |= SM_ERR_NOOPS;
696 return;
697 }
698
699 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
700 return;
701
702 char *mask = nuh_mask[*parn];
703 strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
704 ++(*parn);
705
706 if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
707 return;
708
709 switch (dir)
710 {
711 case MODE_ADD:
712 if (!add_id(source_p, chptr, mask, CHFL_INVEX))
713 return;
714 break;
715 case MODE_DEL:
716 if (!del_id(chptr, mask, CHFL_INVEX))
717 return;
718 break;
719 default:
720 assert(0);
721 }
722
723 mode_changes[mode_count].letter = c;
724 mode_changes[mode_count].arg = mask; /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
725 mode_changes[mode_count].id = NULL;
726 mode_changes[mode_count++].dir = dir;
727 }
728
729 static void
730 chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
731 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
732 {
733 struct Client *target_p;
734 struct Membership *member;
735
736 if (alev < CHACCESS_HALFOP)
737 {
738 if (!(*errors & SM_ERR_NOOPS))
739 sendto_one_numeric(source_p, &me,
740 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
741 ERR_CHANOPRIVSNEEDED, chptr->name);
742
743 *errors |= SM_ERR_NOOPS;
744 return;
745 }
746
747 if (dir == MODE_QUERY || parc <= *parn)
748 return;
749
750 if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
751 return; /* find_chasing sends ERR_NOSUCHNICK */
752
753 if ((member = find_channel_link(target_p, chptr)) == NULL)
754 {
755 if (!(*errors & SM_ERR_NOTONCHANNEL))
756 sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
757
758 *errors |= SM_ERR_NOTONCHANNEL;
759 return;
760 }
761
762 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
763 return;
764
765 switch (dir)
766 {
767 case MODE_ADD:
768 if (has_member_flags(member, CHFL_VOICE))
769 return; /* No redundant mode changes */
770
771 AddMemberFlag(member, CHFL_VOICE);
772 break;
773 case MODE_DEL:
774 if (!has_member_flags(member, CHFL_VOICE))
775 return; /* No redundant mode changes */
776
777 DelMemberFlag(member, CHFL_VOICE);
778 break;
779 }
780
781 mode_changes[mode_count].letter = c;
782 mode_changes[mode_count].arg = target_p->name;
783 mode_changes[mode_count].id = target_p->id;
784 mode_changes[mode_count++].dir = dir;
785 }
786
787 static void
788 chm_hop(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
789 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
790 {
791 struct Client *target_p;
792 struct Membership *member;
793
794 if (alev < CHACCESS_CHANOP)
795 {
796 if (!(*errors & SM_ERR_NOOPS))
797 sendto_one_numeric(source_p, &me,
798 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
799 ERR_CHANOPRIVSNEEDED, chptr->name);
800
801 *errors |= SM_ERR_NOOPS;
802 return;
803 }
804
805 if (dir == MODE_QUERY || parc <= *parn)
806 return;
807
808 if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
809 return; /* find_chasing sends ERR_NOSUCHNICK */
810
811 if ((member = find_channel_link(target_p, chptr)) == NULL)
812 {
813 if (!(*errors & SM_ERR_NOTONCHANNEL))
814 sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
815
816 *errors |= SM_ERR_NOTONCHANNEL;
817 return;
818 }
819
820 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
821 return;
822
823 switch (dir)
824 {
825 case MODE_ADD:
826 if (has_member_flags(member, CHFL_HALFOP))
827 return; /* No redundant mode changes */
828
829 AddMemberFlag(member, CHFL_HALFOP);
830 break;
831 case MODE_DEL:
832 if (!has_member_flags(member, CHFL_HALFOP))
833 return; /* No redundant mode changes */
834
835 DelMemberFlag(member, CHFL_HALFOP);
836 break;
837 }
838
839 mode_changes[mode_count].letter = c;
840 mode_changes[mode_count].arg = target_p->name;
841 mode_changes[mode_count].id = target_p->id;
842 mode_changes[mode_count++].dir = dir;
843 }
844
845 static void
846 chm_op(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
847 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
848 {
849 struct Client *target_p;
850 struct Membership *member;
851
852 if (alev < CHACCESS_CHANOP)
853 {
854 if (!(*errors & SM_ERR_NOOPS))
855 sendto_one_numeric(source_p, &me,
856 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
857 ERR_CHANOPRIVSNEEDED, chptr->name);
858
859 *errors |= SM_ERR_NOOPS;
860 return;
861 }
862
863 if (dir == MODE_QUERY || parc <= *parn)
864 return;
865
866 if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
867 return; /* find_chasing sends ERR_NOSUCHNICK */
868
869 if ((member = find_channel_link(target_p, chptr)) == NULL)
870 {
871 if (!(*errors & SM_ERR_NOTONCHANNEL))
872 sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
873
874 *errors |= SM_ERR_NOTONCHANNEL;
875 return;
876 }
877
878 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
879 return;
880
881 switch (dir)
882 {
883 case MODE_ADD:
884 if (has_member_flags(member, CHFL_CHANOP))
885 return; /* No redundant mode changes */
886
887 AddMemberFlag(member, CHFL_CHANOP);
888 break;
889 case MODE_DEL:
890 if (!has_member_flags(member, CHFL_CHANOP))
891 return; /* No redundant mode changes */
892
893 DelMemberFlag(member, CHFL_CHANOP);
894 break;
895 }
896
897 mode_changes[mode_count].letter = c;
898 mode_changes[mode_count].arg = target_p->name;
899 mode_changes[mode_count].id = target_p->id;
900 mode_changes[mode_count++].dir = dir;
901 }
902
903 static void
904 chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
905 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
906 {
907 if (alev < CHACCESS_HALFOP)
908 {
909 if (!(*errors & SM_ERR_NOOPS))
910 sendto_one_numeric(source_p, &me,
911 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
912 ERR_CHANOPRIVSNEEDED, chptr->name);
913 *errors |= SM_ERR_NOOPS;
914 return;
915 }
916
917 if (dir == MODE_QUERY)
918 return;
919
920 if (dir == MODE_ADD && parc > *parn)
921 {
922 char *const lstr = parv[(*parn)++];
923 int limit = 0;
924
925 if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
926 return;
927
928 sprintf(lstr, "%d", limit);
929
930 /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
931 for (unsigned int i = 0; i < mode_count; ++i)
932 if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
933 mode_changes[i].letter = 0;
934
935 mode_changes[mode_count].letter = c;
936 mode_changes[mode_count].arg = lstr;
937 mode_changes[mode_count].id = NULL;
938 mode_changes[mode_count++].dir = dir;
939
940 chptr->mode.limit = limit;
941 }
942 else if (dir == MODE_DEL)
943 {
944 if (!chptr->mode.limit)
945 return;
946
947 chptr->mode.limit = 0;
948
949 mode_changes[mode_count].letter = c;
950 mode_changes[mode_count].arg = NULL;
951 mode_changes[mode_count].id = NULL;
952 mode_changes[mode_count++].dir = dir;
953 }
954 }
955
956 static void
957 chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn,
958 char **parv, int *errors, int alev, int dir, char c, unsigned int d)
959 {
960 if (alev < CHACCESS_HALFOP)
961 {
962 if (!(*errors & SM_ERR_NOOPS))
963 sendto_one_numeric(source_p, &me,
964 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
965 ERR_CHANOPRIVSNEEDED, chptr->name);
966 *errors |= SM_ERR_NOOPS;
967 return;
968 }
969
970 if (dir == MODE_QUERY)
971 return;
972
973 if (dir == MODE_ADD && parc > *parn)
974 {
975 char *const key = fix_key(parv[(*parn)++]);
976
977 if (EmptyString(key))
978 return;
979
980 assert(key[0] != ' ');
981 strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
982
983 /* If somebody does MODE #channel +kk a b, accept latter --fl */
984 for (unsigned int i = 0; i < mode_count; ++i)
985 if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
986 mode_changes[i].letter = 0;
987
988 mode_changes[mode_count].letter = c;
989 mode_changes[mode_count].arg = chptr->mode.key;
990 mode_changes[mode_count].id = NULL;
991 mode_changes[mode_count++].dir = dir;
992 }
993 else if (dir == MODE_DEL)
994 {
995 if (parc > *parn)
996 ++(*parn);
997
998 if (chptr->mode.key[0] == '\0')
999 return;
1000
1001 chptr->mode.key[0] = '\0';
1002
1003 mode_changes[mode_count].letter = c;
1004 mode_changes[mode_count].arg = "*";
1005 mode_changes[mode_count].id = NULL;
1006 mode_changes[mode_count++].dir = dir;
1007 }
1008 }
1009
1010 const struct ChannelMode ModeTable[256] =
1011 {
1012 { chm_nosuch, 0 }, /* 0x00 */
1013 { chm_nosuch, 0 }, /* 0x01 */
1014 { chm_nosuch, 0 }, /* 0x02 */
1015 { chm_nosuch, 0 }, /* 0x03 */
1016 { chm_nosuch, 0 }, /* 0x04 */
1017 { chm_nosuch, 0 }, /* 0x05 */
1018 { chm_nosuch, 0 }, /* 0x06 */
1019 { chm_nosuch, 0 }, /* 0x07 */
1020 { chm_nosuch, 0 }, /* 0x08 */
1021 { chm_nosuch, 0 }, /* 0x09 */
1022 { chm_nosuch, 0 }, /* 0x0a */
1023 { chm_nosuch, 0 }, /* 0x0b */
1024 { chm_nosuch, 0 }, /* 0x0c */
1025 { chm_nosuch, 0 }, /* 0x0d */
1026 { chm_nosuch, 0 }, /* 0x0e */
1027 { chm_nosuch, 0 }, /* 0x0f */
1028 { chm_nosuch, 0 }, /* 0x10 */
1029 { chm_nosuch, 0 }, /* 0x11 */
1030 { chm_nosuch, 0 }, /* 0x12 */
1031 { chm_nosuch, 0 }, /* 0x13 */
1032 { chm_nosuch, 0 }, /* 0x14 */
1033 { chm_nosuch, 0 }, /* 0x15 */
1034 { chm_nosuch, 0 }, /* 0x16 */
1035 { chm_nosuch, 0 }, /* 0x17 */
1036 { chm_nosuch, 0 }, /* 0x18 */
1037 { chm_nosuch, 0 }, /* 0x19 */
1038 { chm_nosuch, 0 }, /* 0x1a */
1039 { chm_nosuch, 0 }, /* 0x1b */
1040 { chm_nosuch, 0 }, /* 0x1c */
1041 { chm_nosuch, 0 }, /* 0x1d */
1042 { chm_nosuch, 0 }, /* 0x1e */
1043 { chm_nosuch, 0 }, /* 0x1f */
1044 { chm_nosuch, 0 }, /* 0x20 */
1045 { chm_nosuch, 0 }, /* 0x21 */
1046 { chm_nosuch, 0 }, /* 0x22 */
1047 { chm_nosuch, 0 }, /* 0x23 */
1048 { chm_nosuch, 0 }, /* 0x24 */
1049 { chm_nosuch, 0 }, /* 0x25 */
1050 { chm_nosuch, 0 }, /* 0x26 */
1051 { chm_nosuch, 0 }, /* 0x27 */
1052 { chm_nosuch, 0 }, /* 0x28 */
1053 { chm_nosuch, 0 }, /* 0x29 */
1054 { chm_nosuch, 0 }, /* 0x2a */
1055 { chm_nosuch, 0 }, /* 0x2b */
1056 { chm_nosuch, 0 }, /* 0x2c */
1057 { chm_nosuch, 0 }, /* 0x2d */
1058 { chm_nosuch, 0 }, /* 0x2e */
1059 { chm_nosuch, 0 }, /* 0x2f */
1060 { chm_nosuch, 0 }, /* 0x30 */
1061 { chm_nosuch, 0 }, /* 0x31 */
1062 { chm_nosuch, 0 }, /* 0x32 */
1063 { chm_nosuch, 0 }, /* 0x33 */
1064 { chm_nosuch, 0 }, /* 0x34 */
1065 { chm_nosuch, 0 }, /* 0x35 */
1066 { chm_nosuch, 0 }, /* 0x36 */
1067 { chm_nosuch, 0 }, /* 0x37 */
1068 { chm_nosuch, 0 }, /* 0x38 */
1069 { chm_nosuch, 0 }, /* 0x39 */
1070 { chm_nosuch, 0 }, /* 0x3a */
1071 { chm_nosuch, 0 }, /* 0x3b */
1072 { chm_nosuch, 0 }, /* 0x3c */
1073 { chm_nosuch, 0 }, /* 0x3d */
1074 { chm_nosuch, 0 }, /* 0x3e */
1075 { chm_nosuch, 0 }, /* 0x3f */
1076 { chm_nosuch, 0 }, /* @ */
1077 { chm_nosuch, 0 }, /* A */
1078 { chm_nosuch, 0 }, /* B */
1079 { chm_simple, MODE_NOCTCP }, /* C */
1080 { chm_nosuch, 0 }, /* D */
1081 { chm_nosuch, 0 }, /* E */
1082 { chm_nosuch, 0 }, /* F */
1083 { chm_nosuch, 0 }, /* G */
1084 { chm_nosuch, 0 }, /* H */
1085 { chm_invex, 0 }, /* I */
1086 { chm_nosuch, 0 }, /* J */
1087 { chm_nosuch, 0 }, /* K */
1088 { chm_nosuch, 0 }, /* L */
1089 { chm_simple, MODE_MODREG}, /* M */
1090 { chm_nosuch, 0 }, /* N */
1091 { chm_operonly, MODE_OPERONLY}, /* O */
1092 { chm_nosuch, 0 }, /* P */
1093 { chm_nosuch, 0 }, /* Q */
1094 { chm_simple, MODE_REGONLY}, /* R */
1095 { chm_simple, MODE_SSLONLY}, /* S */
1096 { chm_simple, MODE_NONOTICE}, /* T */
1097 { chm_nosuch, 0 }, /* U */
1098 { chm_nosuch, 0 }, /* V */
1099 { chm_nosuch, 0 }, /* W */
1100 { chm_nosuch, 0 }, /* X */
1101 { chm_nosuch, 0 }, /* Y */
1102 { chm_nosuch, 0 }, /* Z */
1103 { chm_nosuch, 0 },
1104 { chm_nosuch, 0 },
1105 { chm_nosuch, 0 },
1106 { chm_nosuch, 0 },
1107 { chm_nosuch, 0 },
1108 { chm_nosuch, 0 },
1109 { chm_nosuch, 0 }, /* a */
1110 { chm_ban, 0 }, /* b */
1111 { chm_simple, MODE_NOCTRL}, /* c */
1112 { chm_nosuch, 0 }, /* d */
1113 { chm_except, 0 }, /* e */
1114 { chm_nosuch, 0 }, /* f */
1115 { chm_nosuch, 0 }, /* g */
1116 { chm_hop, 0 }, /* h */
1117 { chm_simple, MODE_INVITEONLY }, /* i */
1118 { chm_nosuch, 0 }, /* j */
1119 { chm_key, 0 }, /* k */
1120 { chm_limit, 0 }, /* l */
1121 { chm_simple, MODE_MODERATED }, /* m */
1122 { chm_simple, MODE_NOPRIVMSGS }, /* n */
1123 { chm_op, 0 }, /* o */
1124 { chm_simple, MODE_PRIVATE }, /* p */
1125 { chm_nosuch, 0 }, /* q */
1126 { chm_registered, MODE_REGISTERED }, /* r */
1127 { chm_simple, MODE_SECRET }, /* s */
1128 { chm_simple, MODE_TOPICLIMIT }, /* t */
1129 { chm_nosuch, 0 }, /* u */
1130 { chm_voice, 0 }, /* v */
1131 { chm_nosuch, 0 }, /* w */
1132 { chm_nosuch, 0 }, /* x */
1133 { chm_nosuch, 0 }, /* y */
1134 { chm_nosuch, 0 }, /* z */
1135 { chm_nosuch, 0 }, /* 0x7b */
1136 { chm_nosuch, 0 }, /* 0x7c */
1137 { chm_nosuch, 0 }, /* 0x7d */
1138 { chm_nosuch, 0 }, /* 0x7e */
1139 { chm_nosuch, 0 }, /* 0x7f */
1140 { chm_nosuch, 0 }, /* 0x80 */
1141 { chm_nosuch, 0 }, /* 0x81 */
1142 { chm_nosuch, 0 }, /* 0x82 */
1143 { chm_nosuch, 0 }, /* 0x83 */
1144 { chm_nosuch, 0 }, /* 0x84 */
1145 { chm_nosuch, 0 }, /* 0x85 */
1146 { chm_nosuch, 0 }, /* 0x86 */
1147 { chm_nosuch, 0 }, /* 0x87 */
1148 { chm_nosuch, 0 }, /* 0x88 */
1149 { chm_nosuch, 0 }, /* 0x89 */
1150 { chm_nosuch, 0 }, /* 0x8a */
1151 { chm_nosuch, 0 }, /* 0x8b */
1152 { chm_nosuch, 0 }, /* 0x8c */
1153 { chm_nosuch, 0 }, /* 0x8d */
1154 { chm_nosuch, 0 }, /* 0x8e */
1155 { chm_nosuch, 0 }, /* 0x8f */
1156 { chm_nosuch, 0 }, /* 0x90 */
1157 { chm_nosuch, 0 }, /* 0x91 */
1158 { chm_nosuch, 0 }, /* 0x92 */
1159 { chm_nosuch, 0 }, /* 0x93 */
1160 { chm_nosuch, 0 }, /* 0x94 */
1161 { chm_nosuch, 0 }, /* 0x95 */
1162 { chm_nosuch, 0 }, /* 0x96 */
1163 { chm_nosuch, 0 }, /* 0x97 */
1164 { chm_nosuch, 0 }, /* 0x98 */
1165 { chm_nosuch, 0 }, /* 0x99 */
1166 { chm_nosuch, 0 }, /* 0x9a */
1167 { chm_nosuch, 0 }, /* 0x9b */
1168 { chm_nosuch, 0 }, /* 0x9c */
1169 { chm_nosuch, 0 }, /* 0x9d */
1170 { chm_nosuch, 0 }, /* 0x9e */
1171 { chm_nosuch, 0 }, /* 0x9f */
1172 { chm_nosuch, 0 }, /* 0xa0 */
1173 { chm_nosuch, 0 }, /* 0xa1 */
1174 { chm_nosuch, 0 }, /* 0xa2 */
1175 { chm_nosuch, 0 }, /* 0xa3 */
1176 { chm_nosuch, 0 }, /* 0xa4 */
1177 { chm_nosuch, 0 }, /* 0xa5 */
1178 { chm_nosuch, 0 }, /* 0xa6 */
1179 { chm_nosuch, 0 }, /* 0xa7 */
1180 { chm_nosuch, 0 }, /* 0xa8 */
1181 { chm_nosuch, 0 }, /* 0xa9 */
1182 { chm_nosuch, 0 }, /* 0xaa */
1183 { chm_nosuch, 0 }, /* 0xab */
1184 { chm_nosuch, 0 }, /* 0xac */
1185 { chm_nosuch, 0 }, /* 0xad */
1186 { chm_nosuch, 0 }, /* 0xae */
1187 { chm_nosuch, 0 }, /* 0xaf */
1188 { chm_nosuch, 0 }, /* 0xb0 */
1189 { chm_nosuch, 0 }, /* 0xb1 */
1190 { chm_nosuch, 0 }, /* 0xb2 */
1191 { chm_nosuch, 0 }, /* 0xb3 */
1192 { chm_nosuch, 0 }, /* 0xb4 */
1193 { chm_nosuch, 0 }, /* 0xb5 */
1194 { chm_nosuch, 0 }, /* 0xb6 */
1195 { chm_nosuch, 0 }, /* 0xb7 */
1196 { chm_nosuch, 0 }, /* 0xb8 */
1197 { chm_nosuch, 0 }, /* 0xb9 */
1198 { chm_nosuch, 0 }, /* 0xba */
1199 { chm_nosuch, 0 }, /* 0xbb */
1200 { chm_nosuch, 0 }, /* 0xbc */
1201 { chm_nosuch, 0 }, /* 0xbd */
1202 { chm_nosuch, 0 }, /* 0xbe */
1203 { chm_nosuch, 0 }, /* 0xbf */
1204 { chm_nosuch, 0 }, /* 0xc0 */
1205 { chm_nosuch, 0 }, /* 0xc1 */
1206 { chm_nosuch, 0 }, /* 0xc2 */
1207 { chm_nosuch, 0 }, /* 0xc3 */
1208 { chm_nosuch, 0 }, /* 0xc4 */
1209 { chm_nosuch, 0 }, /* 0xc5 */
1210 { chm_nosuch, 0 }, /* 0xc6 */
1211 { chm_nosuch, 0 }, /* 0xc7 */
1212 { chm_nosuch, 0 }, /* 0xc8 */
1213 { chm_nosuch, 0 }, /* 0xc9 */
1214 { chm_nosuch, 0 }, /* 0xca */
1215 { chm_nosuch, 0 }, /* 0xcb */
1216 { chm_nosuch, 0 }, /* 0xcc */
1217 { chm_nosuch, 0 }, /* 0xcd */
1218 { chm_nosuch, 0 }, /* 0xce */
1219 { chm_nosuch, 0 }, /* 0xcf */
1220 { chm_nosuch, 0 }, /* 0xd0 */
1221 { chm_nosuch, 0 }, /* 0xd1 */
1222 { chm_nosuch, 0 }, /* 0xd2 */
1223 { chm_nosuch, 0 }, /* 0xd3 */
1224 { chm_nosuch, 0 }, /* 0xd4 */
1225 { chm_nosuch, 0 }, /* 0xd5 */
1226 { chm_nosuch, 0 }, /* 0xd6 */
1227 { chm_nosuch, 0 }, /* 0xd7 */
1228 { chm_nosuch, 0 }, /* 0xd8 */
1229 { chm_nosuch, 0 }, /* 0xd9 */
1230 { chm_nosuch, 0 }, /* 0xda */
1231 { chm_nosuch, 0 }, /* 0xdb */
1232 { chm_nosuch, 0 }, /* 0xdc */
1233 { chm_nosuch, 0 }, /* 0xdd */
1234 { chm_nosuch, 0 }, /* 0xde */
1235 { chm_nosuch, 0 }, /* 0xdf */
1236 { chm_nosuch, 0 }, /* 0xe0 */
1237 { chm_nosuch, 0 }, /* 0xe1 */
1238 { chm_nosuch, 0 }, /* 0xe2 */
1239 { chm_nosuch, 0 }, /* 0xe3 */
1240 { chm_nosuch, 0 }, /* 0xe4 */
1241 { chm_nosuch, 0 }, /* 0xe5 */
1242 { chm_nosuch, 0 }, /* 0xe6 */
1243 { chm_nosuch, 0 }, /* 0xe7 */
1244 { chm_nosuch, 0 }, /* 0xe8 */
1245 { chm_nosuch, 0 }, /* 0xe9 */
1246 { chm_nosuch, 0 }, /* 0xea */
1247 { chm_nosuch, 0 }, /* 0xeb */
1248 { chm_nosuch, 0 }, /* 0xec */
1249 { chm_nosuch, 0 }, /* 0xed */
1250 { chm_nosuch, 0 }, /* 0xee */
1251 { chm_nosuch, 0 }, /* 0xef */
1252 { chm_nosuch, 0 }, /* 0xf0 */
1253 { chm_nosuch, 0 }, /* 0xf1 */
1254 { chm_nosuch, 0 }, /* 0xf2 */
1255 { chm_nosuch, 0 }, /* 0xf3 */
1256 { chm_nosuch, 0 }, /* 0xf4 */
1257 { chm_nosuch, 0 }, /* 0xf5 */
1258 { chm_nosuch, 0 }, /* 0xf6 */
1259 { chm_nosuch, 0 }, /* 0xf7 */
1260 { chm_nosuch, 0 }, /* 0xf8 */
1261 { chm_nosuch, 0 }, /* 0xf9 */
1262 { chm_nosuch, 0 }, /* 0xfa */
1263 { chm_nosuch, 0 }, /* 0xfb */
1264 { chm_nosuch, 0 }, /* 0xfc */
1265 { chm_nosuch, 0 }, /* 0xfd */
1266 { chm_nosuch, 0 }, /* 0xfe */
1267 { chm_nosuch, 0 }, /* 0xff */
1268 };
1269
1270 /* get_channel_access()
1271 *
1272 * inputs - pointer to Client struct
1273 * - pointer to Membership struct
1274 * output - CHACCESS_CHANOP if we should let them have
1275 * chanop level access, 0 for peon level access.
1276 * side effects - NONE
1277 */
1278 static int
1279 get_channel_access(const struct Client *source_p,
1280 const struct Membership *member)
1281 {
1282 /* Let hacked servers in for now... */
1283 if (!MyClient(source_p))
1284 return CHACCESS_REMOTE;
1285
1286 if (!member)
1287 return CHACCESS_NOTONCHAN;
1288
1289 /* Just to be sure.. */
1290 assert(source_p == member->client_p);
1291
1292 if (has_member_flags(member, CHFL_CHANOP))
1293 return CHACCESS_CHANOP;
1294
1295 if (has_member_flags(member, CHFL_HALFOP))
1296 return CHACCESS_HALFOP;
1297
1298 return CHACCESS_PEON;
1299 }
1300
1301 /* send_mode_changes_server()
1302 * Input: the source client(source_p),
1303 * the channel to send mode changes for(chptr)
1304 * Output: None.
1305 * Side-effects: Sends the appropriate mode changes to servers.
1306 *
1307 */
1308 static void
1309 send_mode_changes_server(struct Client *source_p, struct Channel *chptr)
1310 {
1311 char modebuf[IRCD_BUFSIZE] = "";
1312 char parabuf[IRCD_BUFSIZE] = "";
1313 char *parptr = parabuf;
1314 int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
1315 int dir = MODE_QUERY;
1316
1317 mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
1318 source_p->id, chptr->creationtime, chptr->name);
1319
1320 /* Loop the list of modes we have */
1321 for (unsigned int i = 0; i < mode_count; ++i)
1322 {
1323 if (mode_changes[i].letter == 0)
1324 continue;
1325
1326 const char *arg;
1327 if (mode_changes[i].id)
1328 arg = mode_changes[i].id;
1329 else
1330 arg = mode_changes[i].arg;
1331
1332 if (arg)
1333 arglen = strlen(arg);
1334 else
1335 arglen = 0;
1336
1337 /*
1338 * If we're creeping past the buf size, we need to send it and make
1339 * another line for the other modes
1340 */
1341 if ((paracount == MAXMODEPARAMS) ||
1342 ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
1343 {
1344 if (modecount)
1345 sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1346
1347 modecount = 0;
1348 paracount = 0;
1349
1350 mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
1351 source_p->id, chptr->creationtime, chptr->name);
1352
1353 pbl = 0;
1354 parabuf[0] = '\0';
1355 parptr = parabuf;
1356 dir = MODE_QUERY;
1357 }
1358
1359 if (dir != mode_changes[i].dir)
1360 {
1361 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1362 dir = mode_changes[i].dir;
1363 }
1364
1365 modebuf[mbl++] = mode_changes[i].letter;
1366 modebuf[mbl] = '\0';
1367 ++modecount;
1368
1369 if (arg)
1370 {
1371 int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1372 pbl += len;
1373 parptr += len;
1374 ++paracount;
1375 }
1376 }
1377
1378 if (modecount)
1379 sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1380 }
1381
1382 /* void send_mode_changes(struct Client *client_p,
1383 * struct Client *source_p,
1384 * struct Channel *chptr)
1385 * Input: The client sending(client_p), the source client(source_p),
1386 * the channel to send mode changes for(chptr),
1387 * mode change globals.
1388 * Output: None.
1389 * Side-effects: Sends the appropriate mode changes to other clients
1390 * and propagates to servers.
1391 */
1392 static void
1393 send_mode_changes_client(struct Client *source_p, struct Channel *chptr)
1394 {
1395 char modebuf[IRCD_BUFSIZE] = "";
1396 char parabuf[IRCD_BUFSIZE] = "";
1397 char *parptr = parabuf;
1398 int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
1399 int dir = MODE_QUERY;
1400
1401 if (IsServer(source_p))
1402 mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1403 ConfigServerHide.hide_servers) ?
1404 me.name : source_p->name, chptr->name);
1405 else
1406 mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1407 source_p->username, source_p->host, chptr->name);
1408
1409 for (unsigned int i = 0; i < mode_count; ++i)
1410 {
1411 if (mode_changes[i].letter == 0)
1412 continue;
1413
1414 const char *arg = mode_changes[i].arg;
1415 if (arg)
1416 arglen = strlen(arg);
1417 else
1418 arglen = 0;
1419
1420 if ((paracount == MAXMODEPARAMS) ||
1421 ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
1422 {
1423 if (mbl && modebuf[mbl - 1] == '-')
1424 modebuf[mbl - 1] = '\0';
1425
1426 if (modecount)
1427 sendto_channel_local(NULL, chptr, 0, 0, 0, "%s %s", modebuf, parabuf);
1428
1429 modecount = 0;
1430 paracount = 0;
1431
1432 if (IsServer(source_p))
1433 mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1434 ConfigServerHide.hide_servers) ?
1435 me.name : source_p->name, chptr->name);
1436 else
1437 mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1438 source_p->username, source_p->host, chptr->name);
1439
1440 pbl = 0;
1441 parabuf[0] = '\0';
1442 parptr = parabuf;
1443 dir = MODE_QUERY;
1444 }
1445
1446 if (dir != mode_changes[i].dir)
1447 {
1448 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1449 dir = mode_changes[i].dir;
1450 }
1451
1452 modebuf[mbl++] = mode_changes[i].letter;
1453 modebuf[mbl] = '\0';
1454 ++modecount;
1455
1456 if (arg)
1457 {
1458 int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1459 pbl += len;
1460 parptr += len;
1461 ++paracount;
1462 }
1463 }
1464
1465 if (modecount)
1466 sendto_channel_local(NULL, chptr, 0, 0, 0, "%s %s", modebuf, parabuf);
1467 }
1468
1469 /*
1470 * Input: The the client this originated
1471 * from, the channel, the parameter count starting at the modes,
1472 * the parameters, the channel name.
1473 * Output: None.
1474 * Side-effects: Changes the channel membership and modes appropriately,
1475 * sends the appropriate MODE messages to the appropriate
1476 * clients.
1477 */
1478 void
1479 set_channel_mode(struct Client *source_p, struct Channel *chptr,
1480 struct Membership *member, int parc, char *parv[])
1481 {
1482 int dir = MODE_ADD;
1483 int parn = 1;
1484 int alevel = 0, errors = 0;
1485
1486 mode_count = 0;
1487 mode_limit = 0;
1488 simple_modes_mask = 0;
1489
1490 alevel = get_channel_access(source_p, member);
1491
1492 for (const char *ml = parv[0]; *ml; ++ml)
1493 {
1494 switch (*ml)
1495 {
1496 case '+':
1497 dir = MODE_ADD;
1498 break;
1499 case '-':
1500 dir = MODE_DEL;
1501 break;
1502 case '=':
1503 dir = MODE_QUERY;
1504 break;
1505 default:
1506 {
1507 const struct ChannelMode *tptr = &ModeTable[(unsigned char)*ml];
1508
1509 tptr->func(source_p, chptr, parc, &parn, parv,
1510 &errors, alevel, dir, *ml, tptr->d);
1511 break;
1512 }
1513 }
1514 }
1515
1516 /* Bail out if we have nothing to do... */
1517 if (!mode_count)
1518 return;
1519
1520 send_mode_changes_client(source_p, chptr);
1521 send_mode_changes_server(source_p, chptr);
1522 }

Properties

Name Value
svn:eol-style native
svn:keywords Id