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: 9083
Committed: Sun Oct 13 10:17:40 2019 UTC (4 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 27502 byte(s)
Log Message:
- channel_mode.c:get_channel_access(): fixed compile error with --enable-assert

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997-2019 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 bool
88 add_id(struct Client *client_p, struct Channel *channel, char *banid, dlink_list *list)
89 {
90 dlink_node *node;
91 char name[NICKLEN + 1] = "";
92 char user[USERLEN + 1] = "";
93 char host[HOSTLEN + 1] = "";
94 struct split_nuh_item nuh;
95
96 if (MyClient(client_p))
97 {
98 unsigned int num_mask = dlink_list_length(&channel->banlist) +
99 dlink_list_length(&channel->exceptlist) +
100 dlink_list_length(&channel->invexlist);
101
102 /* Don't let local clients overflow the b/e/I lists */
103 if (num_mask >= ((HasCMode(channel, MODE_EXTLIMIT)) ? ConfigChannel.max_bans_large :
104 ConfigChannel.max_bans))
105 {
106 sendto_one_numeric(client_p, &me, ERR_BANLISTFULL, channel->name, banid);
107 return false;
108 }
109
110 collapse(banid);
111 }
112
113 nuh.nuhmask = check_string(banid);
114 nuh.nickptr = name;
115 nuh.userptr = user;
116 nuh.hostptr = host;
117
118 nuh.nicksize = sizeof(name);
119 nuh.usersize = sizeof(user);
120 nuh.hostsize = sizeof(host);
121
122 split_nuh(&nuh);
123
124 /*
125 * Re-assemble a new n!u@h and print it back to banid for sending
126 * the mode to the channel.
127 */
128 size_t len = snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
129
130 DLINK_FOREACH(node, list->head)
131 {
132 const struct Ban *ban = node->data;
133
134 if (irccmp(ban->name, name) == 0 &&
135 irccmp(ban->user, user) == 0 &&
136 irccmp(ban->host, host) == 0)
137 return false;
138 }
139
140 clear_ban_cache_list(&channel->members_local);
141
142 struct Ban *ban = xcalloc(sizeof(*ban));
143 ban->when = event_base->time.sec_real;
144 ban->len = len - 2; /* -2 for ! + @ */
145 ban->type = parse_netmask(host, &ban->addr, &ban->bits);
146 strlcpy(ban->name, name, sizeof(ban->name));
147 strlcpy(ban->user, user, sizeof(ban->user));
148 strlcpy(ban->host, host, sizeof(ban->host));
149
150 if (IsClient(client_p))
151 snprintf(ban->who, sizeof(ban->who), "%s!%s@%s", client_p->name,
152 client_p->username, client_p->host);
153 else if (IsHidden(client_p) || ConfigServerHide.hide_servers)
154 strlcpy(ban->who, me.name, sizeof(ban->who));
155 else
156 strlcpy(ban->who, client_p->name, sizeof(ban->who));
157
158 dlinkAdd(ban, &ban->node, list);
159
160 return true;
161 }
162
163 /*
164 * inputs - pointer to channel
165 * - pointer to ban id
166 * - type of ban, i.e. ban, exception, invex
167 * output - 0 for failure, 1 for success
168 * side effects -
169 */
170 static bool
171 del_id(struct Channel *channel, char *banid, dlink_list *list)
172 {
173 dlink_node *node;
174 char name[NICKLEN + 1] = "";
175 char user[USERLEN + 1] = "";
176 char host[HOSTLEN + 1] = "";
177 struct split_nuh_item nuh;
178
179 assert(banid);
180
181 nuh.nuhmask = check_string(banid);
182 nuh.nickptr = name;
183 nuh.userptr = user;
184 nuh.hostptr = host;
185
186 nuh.nicksize = sizeof(name);
187 nuh.usersize = sizeof(user);
188 nuh.hostsize = sizeof(host);
189
190 split_nuh(&nuh);
191
192 /*
193 * Re-assemble a new n!u@h and print it back to banid for sending
194 * the mode to the channel.
195 */
196 snprintf(banid, IRCD_BUFSIZE, "%s!%s@%s", name, user, host);
197
198 DLINK_FOREACH(node, list->head)
199 {
200 struct Ban *ban = node->data;
201
202 if (irccmp(name, ban->name) == 0 &&
203 irccmp(user, ban->user) == 0 &&
204 irccmp(host, ban->host) == 0)
205 {
206 clear_ban_cache_list(&channel->members_local);
207 remove_ban(ban, list);
208 return true;
209 }
210 }
211
212 return false;
213 }
214
215 /* channel_modes()
216 *
217 * inputs - pointer to channel
218 * - pointer to client
219 * - pointer to mode buf
220 * - pointer to parameter buf
221 * output - NONE
222 * side effects - write the "simple" list of channel modes for channel
223 * channel onto buffer mbuf with the parameters in pbuf.
224 */
225 void
226 channel_modes(const struct Channel *channel, const struct Client *client_p, char *mbuf, char *pbuf)
227 {
228 *mbuf++ = '+';
229 *pbuf = '\0';
230
231 for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
232 if (tab->mode && HasCMode(channel, tab->mode))
233 *mbuf++ = tab->letter;
234
235 if (channel->mode.limit)
236 {
237 *mbuf++ = 'l';
238
239 if (IsServer(client_p) || IsMember(client_p, channel))
240 pbuf += sprintf(pbuf, "%u ", channel->mode.limit);
241 }
242
243 if (channel->mode.key[0])
244 {
245 *mbuf++ = 'k';
246
247 if (IsServer(client_p) || IsMember(client_p, channel))
248 sprintf(pbuf, "%s ", channel->mode.key);
249 }
250
251 *mbuf = '\0';
252 }
253
254 /* fix_key()
255 *
256 * inputs - pointer to key to clean up
257 * output - pointer to cleaned up key
258 * side effects - input string is modified
259 *
260 * stolen from Undernet's ircd -orabidoo
261 */
262 static char *
263 fix_key(char *arg)
264 {
265 unsigned char *s, *t, c;
266
267 for (s = t = (unsigned char *)arg; (c = *s) && s - (unsigned char *)arg < KEYLEN; ++s)
268 {
269 c &= 0x7f;
270
271 if (c != ':' && c > ' ' && c != ',')
272 *t++ = c;
273 }
274
275 *t = '\0';
276 return arg;
277 }
278
279 /*
280 * inputs - pointer to channel
281 * output - none
282 * side effects - clear ban cache
283 */
284 void
285 clear_ban_cache_list(dlink_list *list)
286 {
287 dlink_node *node;
288
289 DLINK_FOREACH(node, list->head)
290 {
291 struct ChannelMember *member = node->data;
292 member->flags &= ~(CHFL_BAN_SILENCED | CHFL_BAN_CHECKED);
293 }
294 }
295
296 /*
297 * Bitmasks for various error returns that channel_mode_set should only return
298 * once per call -orabidoo
299 */
300 enum
301 {
302 SM_ERR_NOOPS = 1 << 0, /* No chan ops */
303 SM_ERR_UNKNOWN = 1 << 1,
304 SM_ERR_RPL_B = 1 << 2,
305 SM_ERR_RPL_E = 1 << 3,
306 SM_ERR_RPL_I = 1 << 4,
307 SM_ERR_NOTONCHANNEL = 1 << 5, /* Client is not on channel */
308 SM_ERR_NOTOPER = 1 << 6, /* Only irc-operators can change that mode */
309 SM_ERR_ONLYSERVER = 1 << 7 /* Only servers or services can change that mode */
310 };
311
312 /* Mode functions handle mode changes for a particular mode... */
313 static void
314 chm_nosuch(struct Client *source_p, struct Channel *channel, int parc, int *parn, char **parv,
315 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
316 {
317 if (*errors & SM_ERR_UNKNOWN)
318 return;
319
320 *errors |= SM_ERR_UNKNOWN;
321 sendto_one_numeric(source_p, &me, ERR_UNKNOWNMODE, c);
322 }
323
324 static void
325 chm_simple(struct Client *source_p, struct Channel *channel, int parc, int *parn, char **parv,
326 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
327 {
328 if (mode->only_opers)
329 {
330 if (MyClient(source_p) && !HasUMode(source_p, UMODE_OPER))
331 {
332 if (!(*errors & SM_ERR_NOTOPER))
333 sendto_one_numeric(source_p, &me, ERR_NOPRIVILEGES);
334
335 *errors |= SM_ERR_NOTOPER;
336 return;
337 }
338 }
339
340 if (mode->only_servers)
341 {
342 if (!IsServer(source_p) && !HasFlag(source_p, FLAGS_SERVICE))
343 {
344 if (!(*errors & SM_ERR_ONLYSERVER))
345 sendto_one_numeric(source_p, &me,
346 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
347 ERR_ONLYSERVERSCANCHANGE, channel->name);
348
349 *errors |= SM_ERR_ONLYSERVER;
350 return;
351 }
352 }
353
354 if (alev < mode->required_oplevel)
355 {
356 if (!(*errors & SM_ERR_NOOPS))
357 sendto_one_numeric(source_p, &me,
358 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
359 ERR_CHANOPRIVSNEEDED, channel->name);
360
361 *errors |= SM_ERR_NOOPS;
362 return;
363 }
364
365 /* If have already dealt with this simple mode, ignore it */
366 if (simple_modes_mask & mode->mode)
367 return;
368
369 simple_modes_mask |= mode->mode;
370
371 if (dir == MODE_ADD) /* setting + */
372 {
373 if (MyClient(source_p) && HasCMode(channel, mode->mode))
374 return;
375
376 AddCMode(channel, mode->mode);
377 }
378 else if (dir == MODE_DEL) /* setting - */
379 {
380 if (MyClient(source_p) && !HasCMode(channel, mode->mode))
381 return;
382
383 DelCMode(channel, mode->mode);
384 }
385
386 mode_changes[mode_count].letter = mode->letter;
387 mode_changes[mode_count].arg = NULL;
388 mode_changes[mode_count].id = NULL;
389 mode_changes[mode_count].flags = 0;
390 mode_changes[mode_count++].dir = dir;
391 }
392
393 static void
394 chm_mask(struct Client *source_p, struct Channel *channel, int parc, int *parn, char **parv,
395 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
396 {
397 dlink_list *list;
398 enum irc_numerics rpl_list = 0, rpl_endlist = 0;
399 int errtype = 0;
400
401 switch (mode->flag)
402 {
403 case CHFL_BAN:
404 errtype = SM_ERR_RPL_B;
405 list = &channel->banlist;
406 rpl_list = RPL_BANLIST;
407 rpl_endlist = RPL_ENDOFBANLIST;
408 break;
409 case CHFL_EXCEPTION:
410 errtype = SM_ERR_RPL_E;
411 list = &channel->exceptlist;
412 rpl_list = RPL_EXCEPTLIST;
413 rpl_endlist = RPL_ENDOFEXCEPTLIST;
414 break;
415 case CHFL_INVEX:
416 errtype = SM_ERR_RPL_I;
417 list = &channel->invexlist;
418 rpl_list = RPL_INVEXLIST;
419 rpl_endlist = RPL_ENDOFINVEXLIST;
420 break;
421 default:
422 list = NULL; /* Let it crash */
423 }
424
425 if (dir == MODE_QUERY || parc <= *parn)
426 {
427 dlink_node *node;
428
429 if (*errors & errtype)
430 return;
431
432 *errors |= errtype;
433
434 DLINK_FOREACH(node, list->head)
435 {
436 const struct Ban *ban = node->data;
437
438 if (!HasCMode(channel, MODE_HIDEBMASKS) || alev >= mode->required_oplevel)
439 sendto_one_numeric(source_p, &me, rpl_list, channel->name,
440 ban->name, ban->user, ban->host,
441 ban->who, ban->when);
442 }
443
444 sendto_one_numeric(source_p, &me, rpl_endlist, channel->name);
445 return;
446 }
447
448 if (alev < mode->required_oplevel)
449 {
450 if (!(*errors & SM_ERR_NOOPS))
451 sendto_one_numeric(source_p, &me,
452 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
453 ERR_CHANOPRIVSNEEDED, channel->name);
454
455 *errors |= SM_ERR_NOOPS;
456 return;
457 }
458
459 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
460 return;
461
462 char *const mask = nuh_mask[*parn];
463 strlcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
464 ++(*parn);
465
466 if (*mask == ':' || (!MyConnect(source_p) && strchr(mask, ' ')))
467 return;
468
469 if (dir == MODE_ADD) /* setting + */
470 {
471 if (add_id(source_p, channel, mask, list) == false)
472 return;
473 }
474 else if (dir == MODE_DEL) /* setting - */
475 {
476 if (del_id(channel, mask, list) == false)
477 return;
478 }
479
480 mode_changes[mode_count].letter = mode->letter;
481 mode_changes[mode_count].arg = mask; /* At this point 'mask' is no longer than NICKLEN + USERLEN + HOSTLEN + 3 */
482 mode_changes[mode_count].id = NULL;
483 if (HasCMode(channel, MODE_HIDEBMASKS))
484 mode_changes[mode_count].flags = CHFL_CHANOP | CHFL_HALFOP;
485 else
486 mode_changes[mode_count].flags = 0;
487 mode_changes[mode_count++].dir = dir;
488 }
489
490 static void
491 chm_flag(struct Client *source_p, struct Channel *channel, int parc, int *parn, char **parv,
492 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
493 {
494 struct Client *target_p;
495 struct ChannelMember *member;
496
497 if (alev < mode->required_oplevel)
498 {
499 if (!(*errors & SM_ERR_NOOPS))
500 sendto_one_numeric(source_p, &me,
501 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
502 ERR_CHANOPRIVSNEEDED, channel->name);
503
504 *errors |= SM_ERR_NOOPS;
505 return;
506 }
507
508 if (dir == MODE_QUERY || parc <= *parn)
509 return;
510
511 if ((target_p = find_chasing(source_p, parv[(*parn)++])) == NULL)
512 return; /* find_chasing sends ERR_NOSUCHNICK */
513
514 if ((member = find_channel_link(target_p, channel)) == NULL)
515 {
516 if (!(*errors & SM_ERR_NOTONCHANNEL))
517 sendto_one_numeric(source_p, &me, ERR_USERNOTINCHANNEL, target_p->name, channel->name);
518
519 *errors |= SM_ERR_NOTONCHANNEL;
520 return;
521 }
522
523 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
524 return;
525
526 if (dir == MODE_ADD) /* setting + */
527 {
528 if (has_member_flags(member, mode->flag))
529 return; /* No redundant mode changes */
530
531 AddMemberFlag(member, mode->flag);
532 }
533 else if (dir == MODE_DEL) /* setting - */
534 {
535 if (has_member_flags(member, mode->flag) == 0)
536 return; /* No redundant mode changes */
537
538 DelMemberFlag(member, mode->flag);
539 }
540
541 mode_changes[mode_count].letter = mode->letter;
542 mode_changes[mode_count].arg = target_p->name;
543 mode_changes[mode_count].id = target_p->id;
544 mode_changes[mode_count].flags = 0;
545 mode_changes[mode_count++].dir = dir;
546 }
547
548 static void
549 chm_limit(struct Client *source_p, struct Channel *channel, int parc, int *parn, char **parv,
550 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
551 {
552 if (alev < mode->required_oplevel)
553 {
554 if (!(*errors & SM_ERR_NOOPS))
555 sendto_one_numeric(source_p, &me,
556 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
557 ERR_CHANOPRIVSNEEDED, channel->name);
558 *errors |= SM_ERR_NOOPS;
559 return;
560 }
561
562 if (dir == MODE_QUERY)
563 return;
564
565 if (dir == MODE_ADD && parc > *parn)
566 {
567 char *const lstr = parv[(*parn)++];
568 int limit = 0;
569
570 if (EmptyString(lstr) || (limit = atoi(lstr)) <= 0)
571 return;
572
573 sprintf(lstr, "%d", limit);
574
575 /* If somebody sets MODE #channel +ll 1 2, accept latter --fl */
576 for (unsigned int i = 0; i < mode_count; ++i)
577 if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
578 mode_changes[i].letter = 0;
579
580 mode_changes[mode_count].letter = mode->letter;
581 mode_changes[mode_count].arg = lstr;
582 mode_changes[mode_count].id = NULL;
583 mode_changes[mode_count].flags = 0;
584 mode_changes[mode_count++].dir = dir;
585
586 channel->mode.limit = limit;
587 }
588 else if (dir == MODE_DEL)
589 {
590 if (channel->mode.limit == 0)
591 return;
592
593 channel->mode.limit = 0;
594
595 mode_changes[mode_count].letter = mode->letter;
596 mode_changes[mode_count].arg = NULL;
597 mode_changes[mode_count].id = NULL;
598 mode_changes[mode_count].flags = 0;
599 mode_changes[mode_count++].dir = dir;
600 }
601 }
602
603 static void
604 chm_key(struct Client *source_p, struct Channel *channel, int parc, int *parn, char **parv,
605 int *errors, int alev, int dir, const char c, const struct chan_mode *mode)
606 {
607 if (alev < mode->required_oplevel)
608 {
609 if (!(*errors & SM_ERR_NOOPS))
610 sendto_one_numeric(source_p, &me,
611 alev == CHACCESS_NOTONCHAN ? ERR_NOTONCHANNEL :
612 ERR_CHANOPRIVSNEEDED, channel->name);
613 *errors |= SM_ERR_NOOPS;
614 return;
615 }
616
617 if (dir == MODE_QUERY)
618 return;
619
620 if (dir == MODE_ADD && parc > *parn)
621 {
622 char *const key = fix_key(parv[(*parn)++]);
623
624 if (EmptyString(key))
625 return;
626
627 assert(key[0] != ' ');
628 strlcpy(channel->mode.key, key, sizeof(channel->mode.key));
629
630 /* If somebody does MODE #channel +kk a b, accept latter --fl */
631 for (unsigned int i = 0; i < mode_count; ++i)
632 if (mode_changes[i].letter == mode->letter && mode_changes[i].dir == MODE_ADD)
633 mode_changes[i].letter = 0;
634
635 mode_changes[mode_count].letter = mode->letter;
636 mode_changes[mode_count].arg = key;
637 mode_changes[mode_count].id = NULL;
638 mode_changes[mode_count].flags = 0;
639 mode_changes[mode_count++].dir = dir;
640 }
641 else if (dir == MODE_DEL)
642 {
643 if (parc > *parn)
644 ++(*parn);
645
646 if (channel->mode.key[0] == '\0')
647 return;
648
649 channel->mode.key[0] = '\0';
650
651 mode_changes[mode_count].letter = mode->letter;
652 mode_changes[mode_count].arg = "*";
653 mode_changes[mode_count].id = NULL;
654 mode_changes[mode_count].flags = 0;
655 mode_changes[mode_count++].dir = dir;
656 }
657 }
658
659 /* get_channel_access()
660 *
661 * inputs - pointer to Client struct
662 * - pointer to Membership struct
663 * output - CHACCESS_CHANOP if we should let them have
664 * chanop level access, 0 for peon level access.
665 * side effects - NONE
666 */
667 static int
668 get_channel_access(const struct Client *source_p,
669 const struct ChannelMember *member)
670 {
671 /* Let hacked servers in for now... */
672 if (!MyClient(source_p))
673 return CHACCESS_REMOTE;
674
675 if (member == NULL)
676 return CHACCESS_NOTONCHAN;
677
678 /* Just to be sure.. */
679 assert(source_p == member->client);
680
681 if (has_member_flags(member, CHFL_CHANOP))
682 return CHACCESS_CHANOP;
683
684 if (has_member_flags(member, CHFL_HALFOP))
685 return CHACCESS_HALFOP;
686
687 return CHACCESS_PEON;
688 }
689
690 /* send_mode_changes_server()
691 * Input: the source client(source_p),
692 * the channel to send mode changes for(channel)
693 * Output: None.
694 * Side-effects: Sends the appropriate mode changes to servers.
695 *
696 */
697 static void
698 send_mode_changes_server(struct Client *source_p, struct Channel *channel)
699 {
700 char modebuf[IRCD_BUFSIZE] = "";
701 char parabuf[IRCD_BUFSIZE] = "";
702 char *parptr = parabuf;
703 unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
704 unsigned int dir = MODE_QUERY;
705
706 mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
707 source_p->id, channel->creation_time, channel->name);
708
709 /* Loop the list of modes we have */
710 for (unsigned int i = 0; i < mode_count; ++i)
711 {
712 if (mode_changes[i].letter == 0)
713 continue;
714
715 const char *arg;
716 if (mode_changes[i].id)
717 arg = mode_changes[i].id;
718 else
719 arg = mode_changes[i].arg;
720
721 if (arg)
722 arglen = strlen(arg);
723 else
724 arglen = 0;
725
726 /*
727 * If we're creeping past the buf size, we need to send it and make
728 * another line for the other modes
729 */
730 if ((paracount == MAXMODEPARAMS) ||
731 ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
732 {
733 if (modecount)
734 sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
735
736 modecount = 0;
737 paracount = 0;
738
739 mbl = snprintf(modebuf, sizeof(modebuf), ":%s TMODE %ju %s ",
740 source_p->id, channel->creation_time, channel->name);
741
742 pbl = 0;
743 parabuf[0] = '\0';
744 parptr = parabuf;
745 dir = MODE_QUERY;
746 }
747
748 if (dir != mode_changes[i].dir)
749 {
750 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
751 dir = mode_changes[i].dir;
752 }
753
754 modebuf[mbl++] = mode_changes[i].letter;
755 modebuf[mbl] = '\0';
756 ++modecount;
757
758 if (arg)
759 {
760 int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
761 pbl += len;
762 parptr += len;
763 ++paracount;
764 }
765 }
766
767 if (modecount)
768 sendto_server(source_p, 0, 0, "%s %s", modebuf, parabuf);
769 }
770
771 /* void send_mode_changes(struct Client *client_p,
772 * struct Client *source_p,
773 * struct Channel *channel)
774 * Input: The client sending(client_p), the source client(source_p),
775 * the channel to send mode changes for(channel),
776 * mode change globals.
777 * Output: None.
778 * Side-effects: Sends the appropriate mode changes to other clients
779 * and propagates to servers.
780 */
781 static void
782 send_mode_changes_client(struct Client *source_p, struct Channel *channel)
783 {
784 unsigned int flags = 0;
785
786 for (unsigned int pass = 2; pass--; flags = CHFL_CHANOP | CHFL_HALFOP)
787 {
788 char modebuf[IRCD_BUFSIZE] = "";
789 char parabuf[IRCD_BUFSIZE] = "";
790 char *parptr = parabuf;
791 unsigned int mbl = 0, pbl = 0, arglen = 0, modecount = 0, paracount = 0;
792 unsigned int dir = MODE_QUERY;
793
794 if (IsClient(source_p))
795 mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
796 source_p->username, source_p->host, channel->name);
797 else
798 mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
799 ConfigServerHide.hide_servers) ?
800 me.name : source_p->name, channel->name);
801
802 for (unsigned int i = 0; i < mode_count; ++i)
803 {
804 if (mode_changes[i].letter == 0 || mode_changes[i].flags != flags)
805 continue;
806
807 const char *arg = mode_changes[i].arg;
808 if (arg)
809 arglen = strlen(arg);
810 else
811 arglen = 0;
812
813 if ((paracount == MAXMODEPARAMS) ||
814 ((arglen + mbl + pbl + 2 /* +2 for /r/n */ ) > IRCD_BUFSIZE))
815 {
816 if (modecount)
817 sendto_channel_local(NULL, channel, flags, 0, 0, "%s %s", modebuf, parabuf);
818
819 modecount = 0;
820 paracount = 0;
821
822 if (IsClient(source_p))
823 mbl = snprintf(modebuf, sizeof(modebuf), ":%s!%s@%s MODE %s ", source_p->name,
824 source_p->username, source_p->host, channel->name);
825 else
826 mbl = snprintf(modebuf, sizeof(modebuf), ":%s MODE %s ", (IsHidden(source_p) ||
827 ConfigServerHide.hide_servers) ?
828 me.name : source_p->name, channel->name);
829
830 pbl = 0;
831 parabuf[0] = '\0';
832 parptr = parabuf;
833 dir = MODE_QUERY;
834 }
835
836 if (dir != mode_changes[i].dir)
837 {
838 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
839 dir = mode_changes[i].dir;
840 }
841
842 modebuf[mbl++] = mode_changes[i].letter;
843 modebuf[mbl] = '\0';
844 ++modecount;
845
846 if (arg)
847 {
848 int len = sprintf(parptr, (pbl == 0) ? "%s" : " %s", arg);
849 pbl += len;
850 parptr += len;
851 ++paracount;
852 }
853 }
854
855 if (modecount)
856 sendto_channel_local(NULL, channel, flags, 0, 0, "%s %s", modebuf, parabuf);
857 }
858 }
859
860 const struct chan_mode *cmode_map[256];
861 const struct chan_mode cmode_tab[] =
862 {
863 { .letter = 'b', .flag = CHFL_BAN, .required_oplevel = CHACCESS_HALFOP, .func = chm_mask },
864 { .letter = 'c', .mode = MODE_NOCTRL, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
865 { .letter = 'e', .flag = CHFL_EXCEPTION, .required_oplevel = CHACCESS_HALFOP, .func = chm_mask },
866 { .letter = 'h', .flag = CHFL_HALFOP, .required_oplevel = CHACCESS_CHANOP, .func = chm_flag },
867 { .letter = 'i', .mode = MODE_INVITEONLY, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
868 { .letter = 'k', .func = chm_key, .required_oplevel = CHACCESS_HALFOP },
869 { .letter = 'l', .func = chm_limit, .required_oplevel = CHACCESS_HALFOP },
870 { .letter = 'm', .mode = MODE_MODERATED, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
871 { .letter = 'n', .mode = MODE_NOPRIVMSGS, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
872 { .letter = 'o', .flag = CHFL_CHANOP, .required_oplevel = CHACCESS_CHANOP, .func = chm_flag },
873 { .letter = 'p', .mode = MODE_PRIVATE, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
874 { .letter = 'r', .mode = MODE_REGISTERED, .required_oplevel = CHACCESS_REMOTE, .only_servers = true, .func = chm_simple },
875 { .letter = 's', .mode = MODE_SECRET, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
876 { .letter = 't', .mode = MODE_TOPICLIMIT, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
877 { .letter = 'u', .mode = MODE_HIDEBMASKS, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
878 { .letter = 'v', .flag = CHFL_VOICE, .required_oplevel = CHACCESS_HALFOP, .func = chm_flag },
879 { .letter = 'C', .mode = MODE_NOCTCP, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
880 { .letter = 'I', .flag = CHFL_INVEX, .required_oplevel = CHACCESS_HALFOP, .func = chm_mask },
881 { .letter = 'L', .mode = MODE_EXTLIMIT, .required_oplevel = CHACCESS_HALFOP, .only_opers = true, .func = chm_simple },
882 { .letter = 'M', .mode = MODE_MODREG, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
883 { .letter = 'N', .mode = MODE_NONICKCHANGE, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
884 { .letter = 'O', .mode = MODE_OPERONLY, .required_oplevel = CHACCESS_HALFOP, .only_opers = true, .func = chm_simple },
885 { .letter = 'R', .mode = MODE_REGONLY, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
886 { .letter = 'S', .mode = MODE_SSLONLY, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
887 { .letter = 'T', .mode = MODE_NONOTICE, .required_oplevel = CHACCESS_HALFOP, .func = chm_simple },
888 { .letter = '\0', .mode = 0 }
889 };
890
891 void
892 channel_mode_init(void)
893 {
894 for (const struct chan_mode *tab = cmode_tab; tab->letter; ++tab)
895 cmode_map[tab->letter] = tab;
896 }
897
898 /*
899 * Input: The the client this originated
900 * from, the channel, the parameter count starting at the modes,
901 * the parameters, the channel name.
902 * Output: None.
903 * Side-effects: Changes the channel membership and modes appropriately,
904 * sends the appropriate MODE messages to the appropriate
905 * clients.
906 */
907 void
908 channel_mode_set(struct Client *source_p, struct Channel *channel,
909 struct ChannelMember *member, int parc, char *parv[])
910 {
911 int dir = MODE_ADD;
912 int parn = 1;
913 int alevel = 0, errors = 0;
914
915 mode_count = 0;
916 mode_limit = 0;
917 simple_modes_mask = 0;
918
919 alevel = get_channel_access(source_p, member);
920
921 for (const char *ml = parv[0]; *ml; ++ml)
922 {
923 switch (*ml)
924 {
925 case '+':
926 dir = MODE_ADD;
927 break;
928 case '-':
929 dir = MODE_DEL;
930 break;
931 case '=':
932 dir = MODE_QUERY;
933 break;
934 default:
935 {
936 const struct chan_mode *mode = cmode_map[(unsigned char)*ml];
937
938 if (mode)
939 mode->func(source_p, channel, parc, &parn, parv, &errors, alevel, dir, *ml, mode);
940 else
941 chm_nosuch(source_p, channel, parc, &parn, parv, &errors, alevel, dir, *ml, NULL);
942 break;
943 }
944 }
945 }
946
947 /* Bail out if we have nothing to do... */
948 if (mode_count == 0)
949 return;
950
951 send_mode_changes_client(source_p, channel);
952 send_mode_changes_server(source_p, channel);
953 }

Properties

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