ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/channel_mode.c
Revision: 5749
Committed: Tue Mar 31 11:55:44 2015 UTC (10 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 42709 byte(s)
Log Message:
- channel_mode.c: moved 'if (!mode_count)' test from send_mode_changes_client() to
  set_channel_mode()

File Contents

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

Properties

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