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: 8600
Committed: Sun Oct 28 18:12:12 2018 UTC (5 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 33447 byte(s)
Log Message:
- Rename Channel:locmembers to Channel::members_local

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2018 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 "parse.h"
41
42
43 static char nuh_mask[MAXPARA][IRCD_BUFSIZE];
44 static struct ChModeChange mode_changes[IRCD_BUFSIZE];
45 static unsigned int mode_count;
46 static unsigned int mode_limit; /* number of modes set other than simple */
47 static unsigned int simple_modes_mask; /* bit mask of simple modes already set */
48
49
50 /* check_string()
51 *
52 * inputs - string to check
53 * output - pointer to modified string
54 * side effects - Fixes a string so that the first white space found
55 * becomes an end of string marker (`\0`).
56 * returns the 'fixed' string or "*" if the string
57 * was NULL length or a NULL pointer.
58 */
59 static char *
60 check_string(char *s)
61 {
62 char *const str = s;
63 static char star[] = "*";
64
65 if (EmptyString(str))
66 return star;
67
68 for (; *s; ++s)
69 {
70 if (IsSpace(*s))
71 {
72 *s = '\0';
73 break;
74 }
75 }
76
77 return EmptyString(str) ? star : str;
78 }
79
80 /*
81 * Ban functions to work with mode +b/e/I
82 */
83 /* add the specified ID to the channel.
84 * -is 8/9/00
85 */
86
87 int
88 add_id(struct Client *client_p, struct Channel *chptr, char *banid, unsigned int type)
89 {
90 dlink_list *list;
91 dlink_node *node;
92 char name[NICKLEN + 1] = "";
93 char user[USERLEN + 1] = "";
94 char host[HOSTLEN + 1] = "";
95 struct split_nuh_item nuh;
96
97 if (MyClient(client_p))
98 {
99 unsigned int num_mask = dlink_list_length(&chptr->banlist) +
100 dlink_list_length(&chptr->exceptlist) +
101 dlink_list_length(&chptr->invexlist);
102
103 /* Don't let local clients overflow the b/e/I lists */
104 if (num_mask >= ((HasCMode(chptr, MODE_EXTLIMIT)) ? ConfigChannel.max_bans_large :
105 ConfigChannel.max_bans))
106 {
107 sendto_one_numeric(client_p, &me, ERR_BANLISTFULL, chptr->name, banid);
108 return 0;
109 }
110
111 collapse(banid);
112 }
113
114 nuh.nuhmask = check_string(banid);
115 nuh.nickptr = name;
116 nuh.userptr = user;
117 nuh.hostptr = host;
118
119 nuh.nicksize = sizeof(name);
120 nuh.usersize = sizeof(user);
121 nuh.hostsize = sizeof(host);
122
123 split_nuh(&nuh);
124
125 /*
126 * Re-assemble a new n!u@h and print it back to banid for sending
127 * the mode to the channel.
128 */
129 size_t len = snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
130
131 switch (type)
132 {
133 case CHFL_BAN:
134 list = &chptr->banlist;
135 clear_ban_cache_list(&chptr->members_local);
136 break;
137 case CHFL_EXCEPTION:
138 list = &chptr->exceptlist;
139 clear_ban_cache_list(&chptr->members_local);
140 break;
141 case CHFL_INVEX:
142 list = &chptr->invexlist;
143 break;
144 default:
145 list = NULL; /* Let it crash */
146 }
147
148 DLINK_FOREACH(node, list->head)
149 {
150 const struct Ban *ban = node->data;
151
152 if (!irccmp(ban->name, name) &&
153 !irccmp(ban->user, user) &&
154 !irccmp(ban->host, host))
155 return 0;
156 }
157
158 struct Ban *ban = xcalloc(sizeof(*ban));
159 ban->when = CurrentTime;
160 ban->len = len - 2; /* -2 for ! + @ */
161 ban->type = parse_netmask(host, &ban->addr, &ban->bits);
162 strlcpy(ban->name, name, sizeof(ban->name));
163 strlcpy(ban->user, user, sizeof(ban->user));
164 strlcpy(ban->host, host, sizeof(ban->host));
165
166 if (IsClient(client_p))
167 snprintf(ban->who, sizeof(ban->who), "%s!%s@%s", client_p->name,
168 client_p->username, client_p->host);
169 else if (IsHidden(client_p) || ConfigServerHide.hide_servers)
170 strlcpy(ban->who, me.name, sizeof(ban->who));
171 else
172 strlcpy(ban->who, client_p->name, sizeof(ban->who));
173
174 dlinkAdd(ban, &ban->node, list);
175
176 return 1;
177 }
178
179 /*
180 * inputs - pointer to channel
181 * - pointer to ban id
182 * - type of ban, i.e. ban, exception, invex
183 * output - 0 for failure, 1 for success
184 * side effects -
185 */
186 static int
187 del_id(struct Channel *chptr, char *banid, unsigned int type)
188 {
189 dlink_list *list;
190 dlink_node *node;
191 char name[NICKLEN + 1] = "";
192 char user[USERLEN + 1] = "";
193 char host[HOSTLEN + 1] = "";
194 struct split_nuh_item nuh;
195
196 assert(banid);
197
198 nuh.nuhmask = check_string(banid);
199 nuh.nickptr = name;
200 nuh.userptr = user;
201 nuh.hostptr = host;
202
203 nuh.nicksize = sizeof(name);
204 nuh.usersize = sizeof(user);
205 nuh.hostsize = sizeof(host);
206
207 split_nuh(&nuh);
208
209 /*
210 * Re-assemble a new n!u@h and print it back to banid for sending
211 * the mode to the channel.
212 */
213 snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
214
215 switch (type)
216 {
217 case CHFL_BAN:
218 list = &chptr->banlist;
219 clear_ban_cache_list(&chptr->members_local);
220 break;
221 case CHFL_EXCEPTION:
222 list = &chptr->exceptlist;
223 clear_ban_cache_list(&chptr->members_local);
224 break;
225 case CHFL_INVEX:
226 list = &chptr->invexlist;
227 break;
228 default:
229 list = NULL; /* Let it crash */
230 }
231
232 DLINK_FOREACH(node, list->head)
233 {
234 struct Ban *ban = node->data;
235
236 if (!irccmp(name, ban->name) &&
237 !irccmp(user, ban->user) &&
238 !irccmp(host, ban->host))
239 {
240 remove_ban(ban, list);
241 return 1;
242 }
243 }
244
245 return 0;
246 }
247
248 /* channel_modes()
249 *
250 * inputs - pointer to channel
251 * - pointer to client
252 * - pointer to mode buf
253 * - pointer to parameter buf
254 * output - NONE
255 * side effects - write the "simple" list of channel modes for channel
256 * chptr onto buffer mbuf with the parameters in pbuf.
257 */
258 void
259 channel_modes(const struct Channel *chptr, const struct Client *client_p, char *mbuf, char *pbuf)
260 {
261 *mbuf++ = '+';
262 *pbuf = '\0';
263
264 for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
265 if (tab->mode && HasCMode(chptr, tab->mode))
266 *mbuf++ = tab->letter;
267
268 if (chptr->mode.limit)
269 {
270 *mbuf++ = 'l';
271
272 if (IsServer(client_p) || IsMember(client_p, chptr))
273 pbuf += sprintf(pbuf, "%u ", chptr->mode.limit);
274 }
275
276 if (chptr->mode.key[0])
277 {
278 *mbuf++ = 'k';
279
280 if (IsServer(client_p) || IsMember(client_p, chptr))
281 sprintf(pbuf, "%s ", chptr->mode.key);
282 }
283
284 *mbuf = '\0';
285 }
286
287 /* fix_key()
288 *
289 * inputs - pointer to key to clean up
290 * output - pointer to cleaned up key
291 * side effects - input string is modified
292 *
293 * stolen from Undernet's ircd -orabidoo
294 */
295 static char *
296 fix_key(char *arg)
297 {
298 unsigned char *s, *t, c;
299
300 for (s = t = (unsigned char *)arg; (c = *s) && s - (unsigned char *)arg < KEYLEN; ++s)
301 {
302 c &= 0x7f;
303
304 if (c != ':' && c > ' ' && c != ',')
305 *t++ = c;
306 }
307
308 *t = '\0';
309 return arg;
310 }
311
312 /*
313 * inputs - pointer to channel
314 * output - none
315 * side effects - clear ban cache
316 */
317 void
318 clear_ban_cache_list(dlink_list *list)
319 {
320 dlink_node *node;
321
322 DLINK_FOREACH(node, list->head)
323 {
324 struct Membership *member = node->data;
325 member->flags &= ~(CHFL_BAN_SILENCED | CHFL_BAN_CHECKED);
326 }
327 }
328
329 /*
330 * Bitmasks for various error returns that channel_mode_set should only return
331 * once per call -orabidoo
332 */
333 enum
334 {
335 SM_ERR_NOOPS = 1 << 0, /* No chan ops */
336 SM_ERR_UNKNOWN = 1 << 1,
337 SM_ERR_RPL_B = 1 << 2,
338 SM_ERR_RPL_E = 1 << 3,
339 SM_ERR_RPL_I = 1 << 4,
340 SM_ERR_NOTONCHANNEL = 1 << 5, /* Client is not on channel */
341 SM_ERR_NOTOPER = 1 << 6, /* Only irc-operators can change that mode */
342 SM_ERR_ONLYSERVER = 1 << 7 /* Only servers or services can change that mode */
343 };
344
345 /* Mode functions handle mode changes for a particular mode... */
346 static void
347 chm_nosuch(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
348 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
349 {
350 if (*errors & SM_ERR_UNKNOWN)
351 return;
352
353 *errors |= SM_ERR_UNKNOWN;
354 sendto_one_numeric(source_p, &me, ERR_UNKNOWNMODE, c);
355 }
356
357 static void
358 chm_simple(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
359 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
360 {
361 if (mode->only_opers)
362 {
363 if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
364 {
365 if (!(*errors & SM_ERR_NOTOPER))
366 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
367
368 *errors |= SM_ERR_NOTOPER;
369 return;
370 }
371 }
372
373 if (mode->only_servers)
374 {
375 if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
376 {
377 if (!(*errors & SM_ERR_ONLYSERVER))
378 sendto_one_numeric(source_p, &me,
379 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
380 ERR_ONLYSERVERSCANCHANGE, chptr->name);
381
382 *errors |= SM_ERR_ONLYSERVER;
383 return;
384 }
385 }
386
387 if (alev < CHACCESS_HALFOP)
388 {
389 if (!(*errors & SM_ERR_NOOPS))
390 sendto_one_numeric(source_p, &me,
391 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
392 ERR_CHANOPRIVSNEEDED, chptr->name);
393
394 *errors |= SM_ERR_NOOPS;
395 return;
396 }
397
398 /* If have already dealt with this simple mode, ignore it */
399 if (simple_modes_mask & mode->mode)
400 return;
401
402 simple_modes_mask |= mode->mode;
403
404 if (dir == MODE_ADD) /* setting + */
405 {
406 if (MyClient(source_p) && HasCMode(chptr, mode->mode))
407 return;
408
409 AddCMode(chptr, mode->mode);
410 }
411 else if (dir == MODE_DEL) /* setting - */
412 {
413 if (MyClient(source_p) && !HasCMode(chptr, mode->mode))
414 return;
415
416 DelCMode(chptr, mode->mode);
417 }
418
419 mode_changes[mode_count].letter = mode->letter;
420 mode_changes[mode_count].arg = NULL;
421 mode_changes[mode_count].id = NULL;
422 mode_changes[mode_count].flags = 0;
423 mode_changes[mode_count++].dir = dir;
424 }
425
426 static void
427 chm_ban(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
428 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
429 {
430 if (dir == MODE_QUERY || parc <= *parn)
431 {
432 dlink_node *node;
433
434 if (*errors & SM_ERR_RPL_B)
435 return;
436
437 *errors |= SM_ERR_RPL_B;
438
439 DLINK_FOREACH(node, chptr->banlist.head)
440 {
441 const struct Ban *ban = node->data;
442
443 if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
444 sendto_one_numeric(source_p, &me, RPL_BANLIST, chptr->name,
445 ban->name, ban->user, ban->host,
446 ban->who, ban->when);
447 }
448
449 sendto_one_numeric(source_p, &me, RPL_ENDOFBANLIST, chptr->name);
450 return;
451 }
452
453 if (alev < CHACCESS_HALFOP)
454 {
455 if (!(*errors & SM_ERR_NOOPS))
456 sendto_one_numeric(source_p, &me,
457 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
458 ERR_CHANOPRIVSNEEDED, chptr->name);
459
460 *errors |= SM_ERR_NOOPS;
461 return;
462 }
463
464 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
465 return;
466
467 char *const mask = nuh_mask[*parn];
468 strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
469 ++(*parn);
470
471 if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
472 return;
473
474 if (dir == MODE_ADD) /* setting + */
475 {
476 if (add_id(source_p, chptr, mask, CHFL_BAN) == 0)
477 return;
478 }
479 else if (dir == MODE_DEL) /* setting - */
480 {
481 if (del_id(chptr, mask, CHFL_BAN) == 0)
482 return;
483 }
484
485 mode_changes[mode_count].letter = mode->letter;
486 mode_changes[mode_count].arg = mask; /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
487 mode_changes[mode_count].id = NULL;
488 if (HasCMode(chptr, MODE_HIDEBMASKS))
489 mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
490 else
491 mode_changes[mode_count].flags = 0;
492 mode_changes[mode_count++].dir = dir;
493 }
494
495 static void
496 chm_except(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
497 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
498 {
499 if (dir == MODE_QUERY || parc <= *parn)
500 {
501 dlink_node *node;
502
503 if (*errors & SM_ERR_RPL_E)
504 return;
505
506 *errors |= SM_ERR_RPL_E;
507
508 DLINK_FOREACH(node, chptr->exceptlist.head)
509 {
510 const struct Ban *ban = node->data;
511
512 if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
513 sendto_one_numeric(source_p, &me, RPL_EXCEPTLIST, chptr->name,
514 ban->name, ban->user, ban->host,
515 ban->who, ban->when);
516 }
517
518 sendto_one_numeric(source_p, &me, RPL_ENDOFEXCEPTLIST, chptr->name);
519 return;
520 }
521
522 if (alev < CHACCESS_HALFOP)
523 {
524 if (!(*errors & SM_ERR_NOOPS))
525 sendto_one_numeric(source_p, &me,
526 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
527 ERR_CHANOPRIVSNEEDED, chptr->name);
528
529 *errors |= SM_ERR_NOOPS;
530 return;
531 }
532
533 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
534 return;
535
536 char *const mask = nuh_mask[*parn];
537 strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
538 ++(*parn);
539
540 if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
541 return;
542
543 if (dir == MODE_ADD) /* setting + */
544 {
545 if (add_id(source_p, chptr, mask, CHFL_EXCEPTION) == 0)
546 return;
547 }
548 else if (dir == MODE_DEL) /* setting - */
549 {
550 if (del_id(chptr, mask, CHFL_EXCEPTION) == 0)
551 return;
552 }
553
554 mode_changes[mode_count].letter = mode->letter;
555 mode_changes[mode_count].arg = mask; /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
556 mode_changes[mode_count].id = NULL;
557 if (HasCMode(chptr, MODE_HIDEBMASKS))
558 mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
559 else
560 mode_changes[mode_count].flags = 0;
561 mode_changes[mode_count++].dir = dir;
562 }
563
564 static void
565 chm_invex(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
566 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
567 {
568 if (dir == MODE_QUERY || parc <= *parn)
569 {
570 dlink_node *node;
571
572 if (*errors & SM_ERR_RPL_I)
573 return;
574
575 *errors |= SM_ERR_RPL_I;
576
577 DLINK_FOREACH(node, chptr->invexlist.head)
578 {
579 const struct Ban *ban = node->data;
580
581 if (!HasCMode(chptr, MODE_HIDEBMASKS) || alev >= CHACCESS_HALFOP)
582 sendto_one_numeric(source_p, &me, RPL_INVEXLIST, chptr->name,
583 ban->name, ban->user, ban->host,
584 ban->who, ban->when);
585 }
586
587 sendto_one_numeric(source_p, &me, RPL_ENDOFINVEXLIST, chptr->name);
588 return;
589 }
590
591 if (alev < CHACCESS_HALFOP)
592 {
593 if (!(*errors & SM_ERR_NOOPS))
594 sendto_one_numeric(source_p, &me,
595 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
596 ERR_CHANOPRIVSNEEDED, chptr->name);
597
598 *errors |= SM_ERR_NOOPS;
599 return;
600 }
601
602 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
603 return;
604
605 char *const mask = nuh_mask[*parn];
606 strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
607 ++(*parn);
608
609 if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
610 return;
611
612 if (dir == MODE_ADD) /* setting + */
613 {
614 if (add_id(source_p, chptr, mask, CHFL_INVEX) == 0)
615 return;
616 }
617 else if (dir == MODE_DEL) /* setting - */
618 {
619 if (del_id(chptr, mask, CHFL_INVEX) == 0)
620 return;
621 }
622
623 mode_changes[mode_count].letter = mode->letter;
624 mode_changes[mode_count].arg = mask; /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
625 mode_changes[mode_count].id = NULL;
626 if (HasCMode(chptr, MODE_HIDEBMASKS))
627 mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
628 else
629 mode_changes[mode_count].flags = 0;
630 mode_changes[mode_count++].dir = dir;
631 }
632
633 static void
634 chm_voice(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
635 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
636 {
637 struct Client *target_p;
638 struct Membership *member;
639
640 if (alev < CHACCESS_HALFOP)
641 {
642 if (!(*errors & SM_ERR_NOOPS))
643 sendto_one_numeric(source_p, &me,
644 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
645 ERR_CHANOPRIVSNEEDED, chptr->name);
646
647 *errors |= SM_ERR_NOOPS;
648 return;
649 }
650
651 if (dir == MODE_QUERY || parc <= *parn)
652 return;
653
654 if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
655 return; /* find_chasing sends ERR_NOSUCHNICK */
656
657 if ((member = find_channel_link(target_p, chptr)) == NULL)
658 {
659 if (!(*errors & SM_ERR_NOTONCHANNEL))
660 sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
661
662 *errors |= SM_ERR_NOTONCHANNEL;
663 return;
664 }
665
666 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
667 return;
668
669 if (dir == MODE_ADD) /* setting + */
670 {
671 if (has_member_flags(member, CHFL_VOICE))
672 return; /* No redundant mode changes */
673
674 AddMemberFlag(member, CHFL_VOICE);
675 }
676 else if (dir == MODE_DEL) /* setting - */
677 {
678 if (has_member_flags(member, CHFL_VOICE) == 0)
679 return; /* No redundant mode changes */
680
681 DelMemberFlag(member, CHFL_VOICE);
682 }
683
684 mode_changes[mode_count].letter = mode->letter;
685 mode_changes[mode_count].arg = target_p->name;
686 mode_changes[mode_count].id = target_p->id;
687 mode_changes[mode_count].flags = 0;
688 mode_changes[mode_count++].dir = dir;
689 }
690
691 static void
692 chm_hop(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
693 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
694 {
695 struct Client *target_p;
696 struct Membership *member;
697
698 if (alev < CHACCESS_CHANOP)
699 {
700 if (!(*errors & SM_ERR_NOOPS))
701 sendto_one_numeric(source_p, &me,
702 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
703 ERR_CHANOPRIVSNEEDED, chptr->name);
704
705 *errors |= SM_ERR_NOOPS;
706 return;
707 }
708
709 if (dir == MODE_QUERY || parc <= *parn)
710 return;
711
712 if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
713 return; /* find_chasing sends ERR_NOSUCHNICK */
714
715 if ((member = find_channel_link(target_p, chptr)) == NULL)
716 {
717 if (!(*errors & SM_ERR_NOTONCHANNEL))
718 sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
719
720 *errors |= SM_ERR_NOTONCHANNEL;
721 return;
722 }
723
724 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
725 return;
726
727 if (dir == MODE_ADD) /* setting + */
728 {
729 if (has_member_flags(member, CHFL_HALFOP))
730 return; /* No redundant mode changes */
731
732 AddMemberFlag(member, CHFL_HALFOP);
733 }
734 else if (dir == MODE_DEL) /* setting - */
735 {
736 if (has_member_flags(member, CHFL_HALFOP) == 0)
737 return; /* No redundant mode changes */
738
739 DelMemberFlag(member, CHFL_HALFOP);
740 }
741
742 mode_changes[mode_count].letter = mode->letter;
743 mode_changes[mode_count].arg = target_p->name;
744 mode_changes[mode_count].id = target_p->id;
745 mode_changes[mode_count].flags = 0;
746 mode_changes[mode_count++].dir = dir;
747 }
748
749 static void
750 chm_op(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
751 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
752 {
753 struct Client *target_p;
754 struct Membership *member;
755
756 if (alev < CHACCESS_CHANOP)
757 {
758 if (!(*errors & SM_ERR_NOOPS))
759 sendto_one_numeric(source_p, &me,
760 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
761 ERR_CHANOPRIVSNEEDED, chptr->name);
762
763 *errors |= SM_ERR_NOOPS;
764 return;
765 }
766
767 if (dir == MODE_QUERY || parc <= *parn)
768 return;
769
770 if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
771 return; /* find_chasing sends ERR_NOSUCHNICK */
772
773 if ((member = find_channel_link(target_p, chptr)) == NULL)
774 {
775 if (!(*errors & SM_ERR_NOTONCHANNEL))
776 sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, chptr->name);
777
778 *errors |= SM_ERR_NOTONCHANNEL;
779 return;
780 }
781
782 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
783 return;
784
785 if (dir == MODE_ADD) /* setting + */
786 {
787 if (has_member_flags(member, CHFL_CHANOP))
788 return; /* No redundant mode changes */
789
790 AddMemberFlag(member, CHFL_CHANOP);
791 }
792 else if (dir == MODE_DEL) /* setting - */
793 {
794 if (has_member_flags(member, CHFL_CHANOP) == 0)
795 return; /* No redundant mode changes */
796
797 DelMemberFlag(member, CHFL_CHANOP);
798 }
799
800 mode_changes[mode_count].letter = mode->letter;
801 mode_changes[mode_count].arg = target_p->name;
802 mode_changes[mode_count].id = target_p->id;
803 mode_changes[mode_count].flags = 0;
804 mode_changes[mode_count++].dir = dir;
805 }
806
807 static void
808 chm_limit(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
809 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
810 {
811 if (alev < CHACCESS_HALFOP)
812 {
813 if (!(*errors & SM_ERR_NOOPS))
814 sendto_one_numeric(source_p, &me,
815 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
816 ERR_CHANOPRIVSNEEDED, chptr->name);
817 *errors |= SM_ERR_NOOPS;
818 return;
819 }
820
821 if (dir == MODE_QUERY)
822 return;
823
824 if (dir == MODE_ADD && parc > *parn)
825 {
826 char *const lstr = parv[(*parn)++];
827 int limit = 0;
828
829 if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
830 return;
831
832 sprintf(lstr, "%d", limit);
833
834 /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
835 for (unsigned int i = 0; i < mode_count; ++i)
836 if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
837 mode_changes[i].letter = 0;
838
839 mode_changes[mode_count].letter = mode->letter;
840 mode_changes[mode_count].arg = lstr;
841 mode_changes[mode_count].id = NULL;
842 mode_changes[mode_count].flags = 0;
843 mode_changes[mode_count++].dir = dir;
844
845 chptr->mode.limit = limit;
846 }
847 else if (dir == MODE_DEL)
848 {
849 if (chptr->mode.limit == 0)
850 return;
851
852 chptr->mode.limit = 0;
853
854 mode_changes[mode_count].letter = mode->letter;
855 mode_changes[mode_count].arg = NULL;
856 mode_changes[mode_count].id = NULL;
857 mode_changes[mode_count].flags = 0;
858 mode_changes[mode_count++].dir = dir;
859 }
860 }
861
862 static void
863 chm_key(struct Client *source_p, struct Channel *chptr, int parc, int *parn, char **parv,
864 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
865 {
866 if (alev < CHACCESS_HALFOP)
867 {
868 if (!(*errors & SM_ERR_NOOPS))
869 sendto_one_numeric(source_p, &me,
870 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
871 ERR_CHANOPRIVSNEEDED, chptr->name);
872 *errors |= SM_ERR_NOOPS;
873 return;
874 }
875
876 if (dir == MODE_QUERY)
877 return;
878
879 if (dir == MODE_ADD && parc > *parn)
880 {
881 char *const key = fix_key(parv[(*parn)++]);
882
883 if (EmptyString(key))
884 return;
885
886 assert(key[0] != ' ');
887 strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
888
889 /* If somebody does MODE #channel +kk a b, accept latter --fl */
890 for (unsigned int i = 0; i < mode_count; ++i)
891 if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
892 mode_changes[i].letter = 0;
893
894 mode_changes[mode_count].letter = mode->letter;
895 mode_changes[mode_count].arg = key;
896 mode_changes[mode_count].id = NULL;
897 mode_changes[mode_count].flags = 0;
898 mode_changes[mode_count++].dir = dir;
899 }
900 else if (dir == MODE_DEL)
901 {
902 if (parc > *parn)
903 ++(*parn);
904
905 if (chptr->mode.key[0] == '\0')
906 return;
907
908 chptr->mode.key[0] = '\0';
909
910 mode_changes[mode_count].letter = mode->letter;
911 mode_changes[mode_count].arg = "*";
912 mode_changes[mode_count].id = NULL;
913 mode_changes[mode_count].flags = 0;
914 mode_changes[mode_count++].dir = dir;
915 }
916 }
917
918 /* get_channel_access()
919 *
920 * inputs - pointer to Client struct
921 * - pointer to Membership struct
922 * output - CHACCESS_CHANOP if we should let them have
923 * chanop level access, 0 for peon level access.
924 * side effects - NONE
925 */
926 static int
927 get_channel_access(const struct Client *source_p,
928 const struct Membership *member)
929 {
930 /* Let hacked servers in for now... */
931 if (!MyClient(source_p))
932 return CHACCESS_REMOTE;
933
934 if (!member)
935 return CHACCESS_NOTONCHAN;
936
937 /* Just to be sure.. */
938 assert(source_p == member->client_p);
939
940 if (has_member_flags(member, CHFL_CHANOP))
941 return CHACCESS_CHANOP;
942
943 if (has_member_flags(member, CHFL_HALFOP))
944 return CHACCESS_HALFOP;
945
946 return CHACCESS_PEON;
947 }
948
949 /* send_mode_changes_server()
950 * Input: the source client(source_p),
951 * the channel to send mode changes for(chptr)
952 * Output: None.
953 * Side-effects: Sends the appropriate mode changes to servers.
954 *
955 */
956 static void
957 send_mode_changes_server(struct Client *source_p, struct Channel *chptr)
958 {
959 char modebuf[IRCD_BUFSIZE] = "";
960 char parabuf[IRCD_BUFSIZE] = "";
961 char *parptr = parabuf;
962 unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
963 unsigned int dir = MODE_QUERY;
964
965 mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
966 source_p->id, chptr->creationtime, chptr->name);
967
968 /* Loop the list of modes we have */
969 for (unsigned int i = 0; i < mode_count; ++i)
970 {
971 if (mode_changes[i].letter == 0)
972 continue;
973
974 const char *arg;
975 if (mode_changes[i].id)
976 arg = mode_changes[i].id;
977 else
978 arg = mode_changes[i].arg;
979
980 if (arg)
981 arglen = strlen(arg);
982 else
983 arglen = 0;
984
985 /*
986 * If we're creeping past the buf size, we need to send it and make
987 * another line for the other modes
988 */
989 if ((paracount == MAXMODEPARAMS) ||
990 ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
991 {
992 if (modecount)
993 sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
994
995 modecount = 0;
996 paracount = 0;
997
998 mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
999 source_p->id, chptr->creationtime, chptr->name);
1000
1001 pbl = 0;
1002 parabuf[0] = '\0';
1003 parptr = parabuf;
1004 dir = MODE_QUERY;
1005 }
1006
1007 if (dir != mode_changes[i].dir)
1008 {
1009 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1010 dir = mode_changes[i].dir;
1011 }
1012
1013 modebuf[mbl++] = mode_changes[i].letter;
1014 modebuf[mbl] = '\0';
1015 ++modecount;
1016
1017 if (arg)
1018 {
1019 int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1020 pbl += len;
1021 parptr += len;
1022 ++paracount;
1023 }
1024 }
1025
1026 if (modecount)
1027 sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
1028 }
1029
1030 /* void send_mode_changes(struct Client *client_p,
1031 * struct Client *source_p,
1032 * struct Channel *chptr)
1033 * Input: The client sending(client_p), the source client(source_p),
1034 * the channel to send mode changes for(chptr),
1035 * mode change globals.
1036 * Output: None.
1037 * Side-effects: Sends the appropriate mode changes to other clients
1038 * and propagates to servers.
1039 */
1040 static void
1041 send_mode_changes_client(struct Client *source_p, struct Channel *chptr)
1042 {
1043 unsigned int flags = 0;
1044
1045 for (unsigned int pass = 2; pass--; flags = CHFL_CHANOP | CHFL_HALFOP)
1046 {
1047 char modebuf[IRCD_BUFSIZE] = "";
1048 char parabuf[IRCD_BUFSIZE] = "";
1049 char *parptr = parabuf;
1050 unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
1051 unsigned int dir = MODE_QUERY;
1052
1053 if (IsClient(source_p))
1054 mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1055 source_p->username, source_p->host, chptr->name);
1056 else
1057 mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1058 ConfigServerHide.hide_servers) ?
1059 me.name : source_p->name, chptr->name);
1060
1061 for (unsigned int i = 0; i < mode_count; ++i)
1062 {
1063 if (mode_changes[i].letter == 0 || mode_changes[i].flags != flags)
1064 continue;
1065
1066 const char *arg = mode_changes[i].arg;
1067 if (arg)
1068 arglen = strlen(arg);
1069 else
1070 arglen = 0;
1071
1072 if ((paracount == MAXMODEPARAMS) ||
1073 ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
1074 {
1075 if (modecount)
1076 sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
1077
1078 modecount = 0;
1079 paracount = 0;
1080
1081 if (IsClient(source_p))
1082 mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
1083 source_p->username, source_p->host, chptr->name);
1084 else
1085 mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
1086 ConfigServerHide.hide_servers) ?
1087 me.name : source_p->name, chptr->name);
1088
1089 pbl = 0;
1090 parabuf[0] = '\0';
1091 parptr = parabuf;
1092 dir = MODE_QUERY;
1093 }
1094
1095 if (dir != mode_changes[i].dir)
1096 {
1097 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1098 dir = mode_changes[i].dir;
1099 }
1100
1101 modebuf[mbl++] = mode_changes[i].letter;
1102 modebuf[mbl] = '\0';
1103 ++modecount;
1104
1105 if (arg)
1106 {
1107 int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
1108 pbl += len;
1109 parptr += len;
1110 ++paracount;
1111 }
1112 }
1113
1114 if (modecount)
1115 sendto_channel_local(NULL, chptr, flags, 0, 0, "%s %s", modebuf, parabuf);
1116 }
1117 }
1118
1119 const struct chan_mode *cmode_map[256];
1120 const struct chan_mode cmode_tab[] =
1121 {
1122 { .letter = 'b', .func = chm_ban },
1123 { .letter = 'c', .mode = MODE_NOCTRL, .func = chm_simple },
1124 { .letter = 'e', .func = chm_except },
1125 { .letter = 'h', .func = chm_hop },
1126 { .letter = 'i', .mode = MODE_INVITEONLY, .func = chm_simple },
1127 { .letter = 'k', .func = chm_key },
1128 { .letter = 'l', .func = chm_limit },
1129 { .letter = 'm', .mode = MODE_MODERATED, .func = chm_simple },
1130 { .letter = 'n', .mode = MODE_NOPRIVMSGS, .func = chm_simple },
1131 { .letter = 'o', .func = chm_op },
1132 { .letter = 'p', .mode = MODE_PRIVATE, .func = chm_simple },
1133 { .letter = 'r', .mode = MODE_REGISTERED, .only_servers = 1, .func = chm_simple },
1134 { .letter = 's', .mode = MODE_SECRET, .func = chm_simple },
1135 { .letter = 't', .mode = MODE_TOPICLIMIT, .func = chm_simple },
1136 { .letter = 'u', .mode = MODE_HIDEBMASKS, .func = chm_simple },
1137 { .letter = 'v', .func = chm_voice },
1138 { .letter = 'C', .mode = MODE_NOCTCP, .func = chm_simple },
1139 { .letter = 'I', .func = chm_invex },
1140 { .letter = 'L', .mode = MODE_EXTLIMIT, .only_opers = 1, .func = chm_simple },
1141 { .letter = 'M', .mode = MODE_MODREG, .func = chm_simple },
1142 { .letter = 'N', .mode = MODE_NONICKCHANGE, .func = chm_simple },
1143 { .letter = 'O', .mode = MODE_OPERONLY, .only_opers = 1, .func = chm_simple },
1144 { .letter = 'R', .mode = MODE_REGONLY, .func = chm_simple },
1145 { .letter = 'S', .mode = MODE_SSLONLY, .func = chm_simple },
1146 { .letter = 'T', .mode = MODE_NONOTICE, .func = chm_simple },
1147 { .letter = '\0', .mode = 0 }
1148 };
1149
1150 void
1151 channel_mode_init(void)
1152 {
1153 for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
1154 cmode_map[tab->letter] = tab;
1155 }
1156
1157 /*
1158 * Input: The the client this originated
1159 * from, the channel, the parameter count starting at the modes,
1160 * the parameters, the channel name.
1161 * Output: None.
1162 * Side-effects: Changes the channel membership and modes appropriately,
1163 * sends the appropriate MODE messages to the appropriate
1164 * clients.
1165 */
1166 void
1167 channel_mode_set(struct Client *source_p, struct Channel *chptr,
1168 struct Membership *member, int parc, char *parv[])
1169 {
1170 int dir = MODE_ADD;
1171 int parn = 1;
1172 int alevel = 0, errors = 0;
1173
1174 mode_count = 0;
1175 mode_limit = 0;
1176 simple_modes_mask = 0;
1177
1178 alevel = get_channel_access(source_p, member);
1179
1180 for (const char *ml = parv[0]; *ml; ++ml)
1181 {
1182 switch (*ml)
1183 {
1184 case '+':
1185 dir = MODE_ADD;
1186 break;
1187 case '-':
1188 dir = MODE_DEL;
1189 break;
1190 case '=':
1191 dir = MODE_QUERY;
1192 break;
1193 default:
1194 {
1195 const struct chan_mode *mode = cmode_map[(unsigned char)*ml];
1196
1197 if (mode)
1198 mode->func(source_p, chptr, parc, &parn, parv, &errors, alevel, dir, *ml, mode);
1199 else
1200 chm_nosuch(source_p, chptr, parc, &parn, parv, &errors, alevel, dir, *ml, NULL);
1201 break;
1202 }
1203 }
1204 }
1205
1206 /* Bail out if we have nothing to do... */
1207 if (mode_count == 0)
1208 return;
1209
1210 send_mode_changes_client(source_p, chptr);
1211 send_mode_changes_server(source_p, chptr);
1212 }

Properties

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