/[svn]/ircd-hybrid/src/channel_mode.c
ViewVC logotype

Contents of /ircd-hybrid/src/channel_mode.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 602 - (show annotations)
Sun May 14 09:36:11 2006 UTC (16 years, 3 months ago) by michael
File MIME type: text/x-chdr
File size: 45881 byte(s)
- channel_mode.c: removed a bunch of prototypes we don't need

1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * channel_mode.c: Controls modes on channels.
4 *
5 * Copyright (C) 2005 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "channel.h"
27 #include "channel_mode.h"
28 #include "client.h"
29 #include "common.h"
30 #include "hash.h"
31 #include "hostmask.h"
32 #include "ircd.h"
33 #include "numeric.h"
34 #include "s_serv.h" /* captab */
35 #include "s_user.h"
36 #include "send.h"
37 #include "whowas.h"
38 #include "s_conf.h" /* ConfigFileEntry, ConfigChannel */
39 #include "msg.h"
40
41 /* 10 is a magic number in hybrid 6 NFI where it comes from -db */
42 #define BAN_FUDGE 10
43 #define NCHCAPS (sizeof(channel_capabs)/sizeof(int))
44 #define NCHCAP_COMBOS (1 << NCHCAPS)
45
46 static char nuh_mask[IRCD_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 int mode_count;
52 static int mode_limit; /* number of modes set other than simple */
53 static int simple_modes_mask; /* bit mask of simple modes already set */
54 #ifdef HALFOPS
55 static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6, CAP_HOPS };
56 #else
57 static int channel_capabs[] = { CAP_EX, CAP_IE, CAP_TS6 };
58 #endif
59 static struct ChCapCombo chcap_combos[NCHCAP_COMBOS];
60 extern BlockHeap *ban_heap;
61 struct Callback *channel_access_cb = NULL;
62
63
64 /* check_string()
65 *
66 * inputs - string to check
67 * output - pointer to modified string
68 * side effects - Fixes a string so that the first white space found
69 * becomes an end of string marker (`\0`).
70 * returns the 'fixed' string or "*" if the string
71 * was NULL length or a NULL pointer.
72 */
73 static char *
74 check_string(char *s)
75 {
76 char *str = s;
77 static char star[] = "*";
78
79 if (EmptyString(s))
80 return star;
81
82 for (; *s; ++s)
83 {
84 if (IsSpace(*s))
85 {
86 *s = '\0';
87 break;
88 }
89 }
90
91 return str;
92 }
93
94 /*
95 * Ban functions to work with mode +b/e/d/I
96 */
97 /* add the specified ID to the channel..
98 * -is 8/9/00
99 */
100
101 int
102 add_id(struct Client *client_p, struct Channel *chptr, char *banid, int type)
103 {
104 dlink_list *list = NULL;
105 dlink_node *ban = NULL;
106 size_t len = 0;
107 struct Ban *ban_p = NULL;
108 unsigned int num_mask = 0;
109 char name[NICKLEN];
110 char user[USERLEN + 1];
111 char host[HOSTLEN + 1];
112 struct split_nuh_item nuh;
113
114 /* dont let local clients overflow the b/e/I lists */
115 if (MyClient(client_p))
116 {
117 num_mask = dlink_list_length(&chptr->banlist) +
118 dlink_list_length(&chptr->exceptlist) +
119 dlink_list_length(&chptr->invexlist);
120
121 if (num_mask >= ConfigChannel.max_bans)
122 {
123 sendto_one(client_p, form_str(ERR_BANLISTFULL),
124 me.name, client_p->name, chptr->chname, banid);
125 return 0;
126 }
127
128 collapse(banid);
129 }
130
131 nuh.nuhmask = check_string(banid);
132 nuh.nickptr = name;
133 nuh.userptr = user;
134 nuh.hostptr = host;
135
136 nuh.nicksize = sizeof(name);
137 nuh.usersize = sizeof(user);
138 nuh.hostsize = sizeof(host);
139
140 split_nuh(&nuh);
141
142 /*
143 * Re-assemble a new n!u@h and print it back to banid for sending
144 * the mode to the channel.
145 */
146 len = ircsprintf(banid, "%s!%s@%s", name, user, host);
147
148 switch (type)
149 {
150 case CHFL_BAN:
151 list = &chptr->banlist;
152 clear_ban_cache(chptr);
153 break;
154 case CHFL_EXCEPTION:
155 list = &chptr->exceptlist;
156 clear_ban_cache(chptr);
157 break;
158 case CHFL_INVEX:
159 list = &chptr->invexlist;
160 break;
161 default:
162 assert(0);
163 return 0;
164 }
165
166 DLINK_FOREACH(ban, list->head)
167 {
168 ban_p = ban->data;
169 if (!irccmp(ban_p->name, name) &&
170 !irccmp(ban_p->username, user) &&
171 !irccmp(ban_p->host, host))
172 {
173 return 0;
174 }
175 }
176
177 ban_p = BlockHeapAlloc(ban_heap);
178
179 DupString(ban_p->name, name);
180 DupString(ban_p->username, user);
181 DupString(ban_p->host, host);
182
183 ban_p->when = CurrentTime;
184 ban_p->len = len - 2; /* -2 for @ and ! */
185 ban_p->type = parse_netmask(host, &ban_p->addr, &ban_p->bits);
186
187 if (IsClient(client_p))
188 {
189 ban_p->who = MyMalloc(strlen(client_p->name) +
190 strlen(client_p->username) +
191 strlen(client_p->host) + 3);
192 ircsprintf(ban_p->who, "%s!%s@%s", client_p->name,
193 client_p->username, client_p->host);
194 }
195 else
196 DupString(ban_p->who, client_p->name);
197
198 dlinkAdd(ban_p, &ban_p->node, list);
199
200 return 1;
201 }
202
203 /*
204 * inputs - pointer to channel
205 * - pointer to ban id
206 * - type of ban, i.e. ban, exception, invex
207 * output - 0 for failure, 1 for success
208 * side effects -
209 */
210 static int
211 del_id(struct Channel *chptr, char *banid, int type)
212 {
213 dlink_list *list = NULL;
214 dlink_node *ban = NULL;
215 char name[NICKLEN];
216 char user[USERLEN + 1];
217 char host[HOSTLEN + 1];
218 struct split_nuh_item nuh;
219
220 assert(banid != NULL);
221
222 nuh.nuhmask = check_string(banid);
223 nuh.nickptr = name;
224 nuh.userptr = user;
225 nuh.hostptr = host;
226
227 nuh.nicksize = sizeof(name);
228 nuh.usersize = sizeof(user);
229 nuh.hostsize = sizeof(host);
230
231 split_nuh(&nuh);
232
233 /*
234 * Re-assemble a new n!u@h and print it back to banid for sending
235 * the mode to the channel.
236 */
237 ircsprintf(banid, "%s!%s@%s", name, user, host);
238
239 switch (type)
240 {
241 case CHFL_BAN:
242 list = &chptr->banlist;
243 clear_ban_cache(chptr);
244 break;
245 case CHFL_EXCEPTION:
246 list = &chptr->exceptlist;
247 clear_ban_cache(chptr);
248 break;
249 case CHFL_INVEX:
250 list = &chptr->invexlist;
251 break;
252 default:
253 assert(0);
254 return 0;
255 }
256
257 DLINK_FOREACH(ban, list->head)
258 {
259 struct Ban *banptr = ban->data;
260
261 if (!irccmp(name, banptr->name) &&
262 !irccmp(user, banptr->username) &&
263 !irccmp(host, banptr->host))
264 {
265 remove_ban(banptr, list);
266 return 1;
267 }
268 }
269
270 return 0;
271 }
272
273 static const struct mode_letter
274 {
275 const unsigned int mode;
276 const unsigned char letter;
277 } flags[] = {
278 { MODE_INVITEONLY, 'i' },
279 { MODE_MODERATED, 'm' },
280 { MODE_NOPRIVMSGS, 'n' },
281 { MODE_PARANOID, 'p' },
282 { MODE_SECRET, 's' },
283 { MODE_TOPICLIMIT, 't' },
284 { 0, '\0' }
285 };
286
287 /* channel_modes()
288 *
289 * inputs - pointer to channel
290 * - pointer to client
291 * - pointer to mode buf
292 * - pointer to parameter buf
293 * output - NONE
294 * side effects - write the "simple" list of channel modes for channel
295 * chptr onto buffer mbuf with the parameters in pbuf.
296 */
297 void
298 channel_modes(struct Channel *chptr, struct Client *client_p,
299 char *mbuf, char *pbuf)
300 {
301 int i;
302
303 *mbuf++ = '+';
304 *pbuf = '\0';
305
306 for (i = 0; flags[i].mode; ++i)
307 if (chptr->mode.mode & flags[i].mode)
308 *mbuf++ = flags[i].letter;
309
310 if (chptr->mode.limit)
311 {
312 *mbuf++ = 'l';
313
314 if (IsMember(client_p, chptr) || IsServer(client_p))
315 pbuf += ircsprintf(pbuf, "%d ", chptr->mode.limit);
316 }
317
318 if (chptr->mode.key[0])
319 {
320 *mbuf++ = 'k';
321
322 if (*pbuf || IsMember(client_p, chptr) || IsServer(client_p))
323 ircsprintf(pbuf, "%s ", chptr->mode.key);
324 }
325
326 *mbuf = '\0';
327 }
328
329 /* fix_key()
330 *
331 * inputs - pointer to key to clean up
332 * output - pointer to cleaned up key
333 * side effects - input string is modified
334 *
335 * stolen from Undernet's ircd -orabidoo
336 */
337 static char *
338 fix_key(char *arg)
339 {
340 unsigned char *s, *t, c;
341
342 for (s = t = (unsigned char *)arg; (c = *s); s++)
343 {
344 c &= 0x7f;
345 if (c != ':' && c > ' ' && c != ',')
346 *t++ = c;
347 }
348
349 *t = '\0';
350 return arg;
351 }
352
353 /* fix_key_old()
354 *
355 * inputs - pointer to key to clean up
356 * output - pointer to cleaned up key
357 * side effects - input string is modifed
358 *
359 * Here we attempt to be compatible with older non-hybrid servers.
360 * We can't back down from the ':' issue however. --Rodder
361 */
362 static char *
363 fix_key_old(char *arg)
364 {
365 unsigned char *s, *t, c;
366
367 for (s = t = (unsigned char *)arg; (c = *s); s++)
368 {
369 c &= 0x7f;
370 if ((c != 0x0a) && (c != ':') && (c != 0x0d) && (c != ','))
371 *t++ = c;
372 }
373
374 *t = '\0';
375 return arg;
376 }
377
378 /* bitmasks for various error returns that set_channel_mode should only return
379 * once per call -orabidoo
380 */
381
382 #define SM_ERR_NOTS 0x00000001 /* No TS on channel */
383 #define SM_ERR_NOOPS 0x00000002 /* No chan ops */
384 #define SM_ERR_UNKNOWN 0x00000004
385 #define SM_ERR_RPL_B 0x00000008
386 #define SM_ERR_RPL_E 0x00000010
387 #define SM_ERR_NOTONCHANNEL 0x00000020 /* Not on channel */
388 #define SM_ERR_RPL_I 0x00000040
389
390 /* Now lets do some stuff to keep track of what combinations of
391 * servers exist...
392 * Note that the number of combinations doubles each time you add
393 * something to this list. Each one is only quick if no servers use that
394 * combination, but if the numbers get too high here MODE will get too
395 * slow. I suggest if you get more than 7 here, you consider getting rid
396 * of some and merging or something. If it wasn't for irc+cs we would
397 * probably not even need to bother about most of these, but unfortunately
398 * we do. -A1kmm
399 */
400
401 /* static void init_chcap_usage_counts(void)
402 *
403 * Inputs - none
404 * Output - none
405 * Side-effects - Initialises the usage counts to zero. Fills in the
406 * chcap_yes and chcap_no combination tables.
407 */
408 static void
409 init_chcap_usage_counts(void)
410 {
411 unsigned long m, c, y, n;
412
413 memset(chcap_combos, 0, sizeof(chcap_combos));
414
415 /* For every possible combination */
416 for (m = 0; m < NCHCAP_COMBOS; m++)
417 {
418 /* Check each capab */
419 for (c = y = n = 0; c < NCHCAPS; c++)
420 {
421 if ((m & (1 << c)) == 0)
422 n |= channel_capabs[c];
423 else
424 y |= channel_capabs[c];
425 }
426
427 chcap_combos[m].cap_yes = y;
428 chcap_combos[m].cap_no = n;
429 }
430 }
431
432 /* void set_chcap_usage_counts(struct Client *serv_p)
433 * Input: serv_p; The client whose capabs to register.
434 * Output: none
435 * Side-effects: Increments the usage counts for the correct capab
436 * combination.
437 */
438 void
439 set_chcap_usage_counts(struct Client *serv_p)
440 {
441 int n;
442
443 for (n = 0; n < NCHCAP_COMBOS; n++)
444 {
445 if (((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
446 chcap_combos[n].cap_yes) &&
447 ((serv_p->localClient->caps & chcap_combos[n].cap_no) == 0))
448 {
449 chcap_combos[n].count++;
450 return;
451 }
452 }
453
454 /* This should be impossible -A1kmm. */
455 assert(0);
456 }
457
458 /* void set_chcap_usage_counts(struct Client *serv_p)
459 *
460 * Inputs - serv_p; The client whose capabs to register.
461 * Output - none
462 * Side-effects - Decrements the usage counts for the correct capab
463 * combination.
464 */
465 void
466 unset_chcap_usage_counts(struct Client *serv_p)
467 {
468 int n;
469
470 for (n = 0; n < NCHCAP_COMBOS; n++)
471 {
472 if ((serv_p->localClient->caps & chcap_combos[n].cap_yes) ==
473 chcap_combos[n].cap_yes &&
474 (serv_p->localClient->caps & chcap_combos[n].cap_no) == 0)
475 {
476 /* Hopefully capabs can't change dynamically or anything... */
477 assert(chcap_combos[n].count > 0);
478 chcap_combos[n].count--;
479 return;
480 }
481 }
482
483 /* This should be impossible -A1kmm. */
484 assert(0);
485 }
486
487 /* Mode functions handle mode changes for a particular mode... */
488 static void
489 chm_nosuch(struct Client *client_p, struct Client *source_p,
490 struct Channel *chptr, int parc, int *parn,
491 char **parv, int *errors, int alev, int dir, char c, void *d,
492 const char *chname)
493 {
494 if (*errors & SM_ERR_UNKNOWN)
495 return;
496
497 *errors |= SM_ERR_UNKNOWN;
498 sendto_one(source_p, form_str(ERR_UNKNOWNMODE), me.name,
499 source_p->name, c);
500 }
501
502 static void
503 chm_simple(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
504 int parc, int *parn, char **parv, int *errors, int alev, int dir,
505 char c, void *d, const char *chname)
506 {
507 long mode_type;
508
509 mode_type = (long)d;
510
511 if ((alev < CHACCESS_HALFOP) ||
512 ((mode_type == MODE_PARANOID) && (alev < CHACCESS_CHANOP)))
513 {
514 if (!(*errors & SM_ERR_NOOPS))
515 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
516 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
517 me.name, source_p->name, chname);
518 *errors |= SM_ERR_NOOPS;
519 return;
520 }
521
522 /* If have already dealt with this simple mode, ignore it */
523 if (simple_modes_mask & mode_type)
524 return;
525
526 simple_modes_mask |= mode_type;
527
528 /* setting + */
529 /* Apparently, (though no one has ever told the hybrid group directly)
530 * admins don't like redundant mode checking. ok. It would have been nice
531 * if you had have told us directly. I've left the original code snippets
532 * in place.
533 *
534 * -Dianora
535 */
536 if ((dir == MODE_ADD)) /* && !(chptr->mode.mode & mode_type)) */
537 {
538 chptr->mode.mode |= mode_type;
539
540 mode_changes[mode_count].letter = c;
541 mode_changes[mode_count].dir = MODE_ADD;
542 mode_changes[mode_count].caps = 0;
543 mode_changes[mode_count].nocaps = 0;
544 mode_changes[mode_count].id = NULL;
545 mode_changes[mode_count].mems = ALL_MEMBERS;
546 mode_changes[mode_count++].arg = NULL;
547 }
548 else if ((dir == MODE_DEL)) /* && (chptr->mode.mode & mode_type)) */
549 {
550 /* setting - */
551
552 chptr->mode.mode &= ~mode_type;
553
554 mode_changes[mode_count].letter = c;
555 mode_changes[mode_count].dir = MODE_DEL;
556 mode_changes[mode_count].caps = 0;
557 mode_changes[mode_count].nocaps = 0;
558 mode_changes[mode_count].mems = ALL_MEMBERS;
559 mode_changes[mode_count].id = NULL;
560 mode_changes[mode_count++].arg = NULL;
561 }
562 }
563
564 static void
565 chm_ban(struct Client *client_p, struct Client *source_p,
566 struct Channel *chptr, int parc, int *parn,
567 char **parv, int *errors, int alev, int dir, char c, void *d,
568 const char *chname)
569 {
570 char *mask = NULL;
571 if (dir == MODE_QUERY || parc <= *parn)
572 {
573 dlink_node *ptr = NULL;
574
575 if (*errors & SM_ERR_RPL_B)
576 return;
577
578 *errors |= SM_ERR_RPL_B;
579
580 DLINK_FOREACH(ptr, chptr->banlist.head)
581 {
582 const struct Ban *banptr = ptr->data;
583 sendto_one(client_p, form_str(RPL_BANLIST),
584 me.name, client_p->name, chname,
585 banptr->name, banptr->username, banptr->host,
586 banptr->who, banptr->when);
587 }
588
589 sendto_one(source_p, form_str(RPL_ENDOFBANLIST), me.name,
590 source_p->name, chname);
591 return;
592 }
593
594 if (alev < CHACCESS_HALFOP)
595 {
596 if (!(*errors & SM_ERR_NOOPS))
597 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
598 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
599 me.name, source_p->name, chname);
600 *errors |= SM_ERR_NOOPS;
601 return;
602 }
603
604 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
605 return;
606
607 mask = nuh_mask[*parn];
608 memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
609 ++*parn;
610
611 if (IsServer(client_p))
612 if (strchr(mask, ' '))
613 return;
614
615 switch (dir)
616 {
617 case MODE_ADD:
618 if (!add_id(source_p, chptr, mask, CHFL_BAN))
619 return;
620 break;
621 case MODE_DEL:
622 /* XXX grrrrrrr */
623 #ifdef NO_BAN_COOKIE
624 if (!del_id(chptr, mask, CHFL_BAN))
625 return;
626 #else
627 /* XXX this hack allows /mode * +o-b nick ban.cookie
628 * I'd like to see this hack go away in the future.
629 */
630 del_id(chptr, mask, CHFL_BAN);
631 #endif
632 break;
633 default:
634 assert(0);
635 }
636
637 mode_changes[mode_count].letter = c;
638 mode_changes[mode_count].dir = dir;
639 mode_changes[mode_count].caps = 0;
640 mode_changes[mode_count].nocaps = 0;
641 mode_changes[mode_count].mems = ALL_MEMBERS;
642 mode_changes[mode_count].id = NULL;
643 mode_changes[mode_count++].arg = mask;
644 }
645
646 static void
647 chm_except(struct Client *client_p, struct Client *source_p,
648 struct Channel *chptr, int parc, int *parn,
649 char **parv, int *errors, int alev, int dir, char c, void *d,
650 const char *chname)
651 {
652 char *mask = NULL;
653
654 /* if we have +e disabled, allow local clients to do anything but
655 * set the mode. This prevents the abuse of +e when just a few
656 * servers support it. --fl
657 */
658 if (!ConfigChannel.use_except && MyClient(source_p) &&
659 ((dir == MODE_ADD) && (parc > *parn)))
660 {
661 if (*errors & SM_ERR_RPL_E)
662 return;
663
664 *errors |= SM_ERR_RPL_E;
665 return;
666 }
667
668 if (alev < CHACCESS_HALFOP)
669 {
670 if (!(*errors & SM_ERR_NOOPS))
671 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
672 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
673 me.name, source_p->name, chname);
674 *errors |= SM_ERR_NOOPS;
675 return;
676 }
677
678 if (dir == MODE_QUERY || parc <= *parn)
679 {
680 dlink_node *ptr = NULL;
681
682 if (*errors & SM_ERR_RPL_E)
683 return;
684
685 *errors |= SM_ERR_RPL_E;
686
687 DLINK_FOREACH(ptr, chptr->exceptlist.head)
688 {
689 const struct Ban *banptr = ptr->data;
690 sendto_one(client_p, form_str(RPL_EXCEPTLIST),
691 me.name, client_p->name, chname,
692 banptr->name, banptr->username, banptr->host,
693 banptr->who, banptr->when);
694 }
695
696 sendto_one(source_p, form_str(RPL_ENDOFEXCEPTLIST), me.name,
697 source_p->name, chname);
698 return;
699 }
700
701 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
702 return;
703
704 mask = nuh_mask[*parn];
705 memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
706 ++*parn;
707
708 if (IsServer(client_p))
709 if (strchr(mask, ' '))
710 return;
711
712 switch (dir)
713 {
714 case MODE_ADD:
715 if (!add_id(source_p, chptr, mask, CHFL_EXCEPTION))
716 return;
717 break;
718 case MODE_DEL:
719 if (!del_id(chptr, mask, CHFL_EXCEPTION))
720 return;
721 break;
722 default:
723 assert(0);
724 }
725
726 mode_changes[mode_count].letter = c;
727 mode_changes[mode_count].dir = dir;
728 mode_changes[mode_count].caps = CAP_EX;
729 mode_changes[mode_count].nocaps = 0;
730
731 if (ConfigChannel.use_except)
732 mode_changes[mode_count].mems = ONLY_CHANOPS;
733 else
734 mode_changes[mode_count].mems = ONLY_SERVERS;
735
736 mode_changes[mode_count].id = NULL;
737 mode_changes[mode_count++].arg = mask;
738 }
739
740 static void
741 chm_invex(struct Client *client_p, struct Client *source_p,
742 struct Channel *chptr, int parc, int *parn,
743 char **parv, int *errors, int alev, int dir, char c, void *d,
744 const char *chname)
745 {
746 char *mask = NULL;
747
748 /* if we have +I disabled, allow local clients to do anything but
749 * set the mode. This prevents the abuse of +I when just a few
750 * servers support it --fl
751 */
752 if (!ConfigChannel.use_invex && MyClient(source_p) &&
753 (dir == MODE_ADD) && (parc > *parn))
754 {
755 if (*errors & SM_ERR_RPL_I)
756 return;
757
758 *errors |= SM_ERR_RPL_I;
759 return;
760 }
761
762 if (alev < CHACCESS_HALFOP)
763 {
764 if (!(*errors & SM_ERR_NOOPS))
765 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
766 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
767 me.name, source_p->name, chname);
768 *errors |= SM_ERR_NOOPS;
769 return;
770 }
771
772 if (dir == MODE_QUERY || parc <= *parn)
773 {
774 dlink_node *ptr = NULL;
775
776 if (*errors & SM_ERR_RPL_I)
777 return;
778
779 *errors |= SM_ERR_RPL_I;
780
781 DLINK_FOREACH(ptr, chptr->invexlist.head)
782 {
783 const struct Ban *banptr = ptr->data;
784 sendto_one(client_p, form_str(RPL_INVITELIST), me.name,
785 client_p->name, chname,
786 banptr->name, banptr->username, banptr->host,
787 banptr->who, banptr->when);
788 }
789
790 sendto_one(source_p, form_str(RPL_ENDOFINVITELIST), me.name,
791 source_p->name, chname);
792 return;
793 }
794
795 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
796 return;
797
798 mask = nuh_mask[*parn];
799 memcpy(mask, parv[*parn], sizeof(nuh_mask[*parn]));
800 ++*parn;
801
802 if (IsServer(client_p))
803 if (strchr(mask, ' '))
804 return;
805
806 switch (dir)
807 {
808 case MODE_ADD:
809 if (!add_id(source_p, chptr, mask, CHFL_INVEX))
810 return;
811 break;
812 case MODE_DEL:
813 if (!del_id(chptr, mask, CHFL_INVEX))
814 return;
815 break;
816 default:
817 assert(0);
818 }
819
820 mode_changes[mode_count].letter = c;
821 mode_changes[mode_count].dir = dir;
822 mode_changes[mode_count].caps = CAP_IE;
823 mode_changes[mode_count].nocaps = 0;
824
825 if (ConfigChannel.use_invex)
826 mode_changes[mode_count].mems = ONLY_CHANOPS;
827 else
828 mode_changes[mode_count].mems = ONLY_SERVERS;
829
830 mode_changes[mode_count].id = NULL;
831 mode_changes[mode_count++].arg = mask;
832 }
833
834 /*
835 * inputs - pointer to channel
836 * output - none
837 * side effects - clear ban cache
838 */
839 void
840 clear_ban_cache(struct Channel *chptr)
841 {
842 dlink_node *ptr = NULL;
843
844 DLINK_FOREACH(ptr, chptr->members.head)
845 {
846 struct Membership *ms = ptr->data;
847 if (MyConnect(ms->client_p))
848 ms->flags &= ~(CHFL_BAN_SILENCED|CHFL_BAN_CHECKED);
849 }
850 }
851
852 static void
853 chm_op(struct Client *client_p, struct Client *source_p,
854 struct Channel *chptr, int parc, int *parn,
855 char **parv, int *errors, int alev, int dir, char c, void *d,
856 const char *chname)
857 {
858 char *opnick;
859 struct Client *targ_p;
860 struct Membership *member;
861 int caps = 0;
862
863 if (alev < CHACCESS_CHANOP)
864 {
865 if (!(*errors & SM_ERR_NOOPS))
866 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
867 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
868 me.name, source_p->name, chname);
869 *errors |= SM_ERR_NOOPS;
870 return;
871 }
872
873 if ((dir == MODE_QUERY) || (parc <= *parn))
874 return;
875
876 opnick = parv[(*parn)++];
877
878 if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
879 return;
880 if (!IsClient(targ_p))
881 return;
882
883 if ((member = find_channel_link(targ_p, chptr)) == NULL)
884 {
885 if (!(*errors & SM_ERR_NOTONCHANNEL))
886 sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
887 me.name, source_p->name, opnick, chname);
888 *errors |= SM_ERR_NOTONCHANNEL;
889 return;
890 }
891
892 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
893 return;
894
895 /* no redundant mode changes */
896 if (dir == MODE_ADD && has_member_flags(member, CHFL_CHANOP))
897 return;
898 if (dir == MODE_DEL && !has_member_flags(member, CHFL_CHANOP))
899 {
900 #ifdef HALFOPS
901 if (has_member_flags(member, CHFL_HALFOP))
902 chm_hop(client_p, source_p, chptr, parc, parn, parv, errors, alev,
903 dir, c, d, chname);
904 #endif
905 return;
906 }
907
908 #ifdef HALFOPS
909 if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP))
910 {
911 /* promoting from % to @ is visible only to CAP_HOPS servers */
912 mode_changes[mode_count].letter = 'h';
913 mode_changes[mode_count].dir = MODE_DEL;
914 mode_changes[mode_count].caps = caps = CAP_HOPS;
915 mode_changes[mode_count].nocaps = 0;
916 mode_changes[mode_count].mems = ALL_MEMBERS;
917 mode_changes[mode_count].id = NULL;
918 mode_changes[mode_count].arg = targ_p->name;
919 mode_changes[mode_count++].client = targ_p;
920 }
921 #endif
922
923 mode_changes[mode_count].letter = 'o';
924 mode_changes[mode_count].dir = dir;
925 mode_changes[mode_count].caps = caps;
926 mode_changes[mode_count].nocaps = 0;
927 mode_changes[mode_count].mems = ALL_MEMBERS;
928 mode_changes[mode_count].id = targ_p->id;
929 mode_changes[mode_count].arg = targ_p->name;
930 mode_changes[mode_count++].client = targ_p;
931
932 if (dir == MODE_ADD)
933 {
934 AddMemberFlag(member, CHFL_CHANOP);
935 DelMemberFlag(member, CHFL_DEOPPED | CHFL_HALFOP);
936 }
937 else
938 DelMemberFlag(member, CHFL_CHANOP);
939 }
940
941 #ifdef HALFOPS
942 static void
943 chm_hop(struct Client *client_p, struct Client *source_p,
944 struct Channel *chptr, int parc, int *parn,
945 char **parv, int *errors, int alev, int dir, char c, void *d,
946 const char *chname)
947 {
948 char *opnick;
949 struct Client *targ_p;
950 struct Membership *member;
951
952 /* *sigh* - dont allow halfops to set +/-h, they could fully control a
953 * channel if there were no ops - it doesnt solve anything.. MODE_PARANOID
954 * when used with MODE_SECRET is paranoid - cant use +p
955 *
956 * it needs to be optional per channel - but not via +p, that or remove
957 * paranoid.. -- fl_
958 *
959 * +p means paranoid, it is useless for anything else on modern IRC, as
960 * list isn't really usable. If you want to have a private channel these
961 * days, you set it +s. Halfops can no longer remove simple modes when
962 * +p is set (although they can set +p) so it is safe to use this to
963 * control whether they can (de)halfop...
964 */
965 if (alev <
966 ((chptr->mode.mode & MODE_PARANOID) ? CHACCESS_CHANOP : CHACCESS_HALFOP))
967 {
968 if (!(*errors & SM_ERR_NOOPS))
969 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
970 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
971 me.name, source_p->name, chname);
972 *errors |= SM_ERR_NOOPS;
973 return;
974 }
975
976 if ((dir == MODE_QUERY) || (parc <= *parn))
977 return;
978
979 opnick = parv[(*parn)++];
980
981 if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
982 return;
983 if (!IsClient(targ_p))
984 return;
985
986 if ((member = find_channel_link(targ_p, chptr)) == NULL)
987 {
988 if (!(*errors & SM_ERR_NOTONCHANNEL))
989 sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
990 me.name, source_p->name, opnick, chname);
991 *errors |= SM_ERR_NOTONCHANNEL;
992 return;
993 }
994
995 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
996 return;
997
998 /* no redundant mode changes */
999 if (dir == MODE_ADD && has_member_flags(member, CHFL_HALFOP | CHFL_CHANOP))
1000 return;
1001 if (dir == MODE_DEL && !has_member_flags(member, CHFL_HALFOP))
1002 return;
1003
1004 mode_changes[mode_count].letter = 'h';
1005 mode_changes[mode_count].dir = dir;
1006 mode_changes[mode_count].caps = CAP_HOPS;
1007 mode_changes[mode_count].nocaps = 0;
1008 mode_changes[mode_count].mems = ALL_MEMBERS;
1009 mode_changes[mode_count].id = targ_p->id;
1010 mode_changes[mode_count].arg = targ_p->name;
1011 mode_changes[mode_count++].client = targ_p;
1012
1013 mode_changes[mode_count].letter = 'o';
1014 mode_changes[mode_count].dir = dir;
1015 mode_changes[mode_count].caps = 0;
1016 mode_changes[mode_count].nocaps = CAP_HOPS;
1017 mode_changes[mode_count].mems = ONLY_SERVERS;
1018 mode_changes[mode_count].id = targ_p->id;
1019 mode_changes[mode_count].arg = targ_p->name;
1020 mode_changes[mode_count++].client = targ_p;
1021
1022 if (dir == MODE_ADD)
1023 {
1024 AddMemberFlag(member, CHFL_HALFOP);
1025 DelMemberFlag(member, CHFL_DEOPPED);
1026 }
1027 else
1028 DelMemberFlag(member, CHFL_HALFOP);
1029 }
1030 #endif
1031
1032 static void
1033 chm_voice(struct Client *client_p, struct Client *source_p,
1034 struct Channel *chptr, int parc, int *parn,
1035 char **parv, int *errors, int alev, int dir, char c, void *d,
1036 const char *chname)
1037 {
1038 char *opnick;
1039 struct Client *targ_p;
1040 struct Membership *member;
1041
1042 if (alev < CHACCESS_HALFOP)
1043 {
1044 if (!(*errors & SM_ERR_NOOPS))
1045 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1046 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1047 me.name, source_p->name, chname);
1048 *errors |= SM_ERR_NOOPS;
1049 return;
1050 }
1051
1052 if ((dir == MODE_QUERY) || parc <= *parn)
1053 return;
1054
1055 opnick = parv[(*parn)++];
1056
1057 if ((targ_p = find_chasing(client_p, source_p, opnick, NULL)) == NULL)
1058 return;
1059 if (!IsClient(targ_p))
1060 return;
1061
1062 if ((member = find_channel_link(targ_p, chptr)) == NULL)
1063 {
1064 if (!(*errors & SM_ERR_NOTONCHANNEL))
1065 sendto_one(source_p, form_str(ERR_USERNOTINCHANNEL),
1066 me.name, source_p->name, opnick, chname);
1067 *errors |= SM_ERR_NOTONCHANNEL;
1068 return;
1069 }
1070
1071 if (MyClient(source_p) && (++mode_limit > MAXMODEPARAMS))
1072 return;
1073
1074 /* no redundant mode changes */
1075 if (dir == MODE_ADD && has_member_flags(member, CHFL_VOICE))
1076 return;
1077 if (dir == MODE_DEL && !has_member_flags(member, CHFL_VOICE))
1078 return;
1079
1080 mode_changes[mode_count].letter = 'v';
1081 mode_changes[mode_count].dir = dir;
1082 mode_changes[mode_count].caps = 0;
1083 mode_changes[mode_count].nocaps = 0;
1084 mode_changes[mode_count].mems = ALL_MEMBERS;
1085 mode_changes[mode_count].id = targ_p->id;
1086 mode_changes[mode_count].arg = targ_p->name;
1087 mode_changes[mode_count++].client = targ_p;
1088
1089 if (dir == MODE_ADD)
1090 AddMemberFlag(member, CHFL_VOICE);
1091 else
1092 DelMemberFlag(member, CHFL_VOICE);
1093 }
1094
1095 static void
1096 chm_limit(struct Client *client_p, struct Client *source_p,
1097 struct Channel *chptr, int parc, int *parn,
1098 char **parv, int *errors, int alev, int dir, char c, void *d,
1099 const char *chname)
1100 {
1101 int i, limit;
1102 char *lstr;
1103
1104 if (alev < CHACCESS_HALFOP)
1105 {
1106 if (!(*errors & SM_ERR_NOOPS))
1107 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1108 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1109 me.name, source_p->name, chname);
1110 *errors |= SM_ERR_NOOPS;
1111 return;
1112 }
1113
1114 if (dir == MODE_QUERY)
1115 return;
1116
1117 if ((dir == MODE_ADD) && parc > *parn)
1118 {
1119 lstr = parv[(*parn)++];
1120
1121 if ((limit = atoi(lstr)) <= 0)
1122 return;
1123
1124 ircsprintf(lstr, "%d", limit);
1125
1126 /* if somebody sets MODE #channel +ll 1 2, accept latter --fl */
1127 for (i = 0; i < mode_count; i++)
1128 {
1129 if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1130 mode_changes[i].letter = 0;
1131 }
1132
1133 mode_changes[mode_count].letter = c;
1134 mode_changes[mode_count].dir = MODE_ADD;
1135 mode_changes[mode_count].caps = 0;
1136 mode_changes[mode_count].nocaps = 0;
1137 mode_changes[mode_count].mems = ALL_MEMBERS;
1138 mode_changes[mode_count].id = NULL;
1139 mode_changes[mode_count++].arg = lstr;
1140
1141 chptr->mode.limit = limit;
1142 }
1143 else if (dir == MODE_DEL)
1144 {
1145 if (!chptr->mode.limit)
1146 return;
1147
1148 chptr->mode.limit = 0;
1149
1150 mode_changes[mode_count].letter = c;
1151 mode_changes[mode_count].dir = MODE_DEL;
1152 mode_changes[mode_count].caps = 0;
1153 mode_changes[mode_count].nocaps = 0;
1154 mode_changes[mode_count].mems = ALL_MEMBERS;
1155 mode_changes[mode_count].id = NULL;
1156 mode_changes[mode_count++].arg = NULL;
1157 }
1158 }
1159
1160 static void
1161 chm_key(struct Client *client_p, struct Client *source_p,
1162 struct Channel *chptr, int parc, int *parn,
1163 char **parv, int *errors, int alev, int dir, char c, void *d,
1164 const char *chname)
1165 {
1166 int i;
1167 char *key;
1168
1169 if (alev < CHACCESS_HALFOP)
1170 {
1171 if (!(*errors & SM_ERR_NOOPS))
1172 sendto_one(source_p, form_str(alev == CHACCESS_NOTONCHAN ?
1173 ERR_NOTONCHANNEL : ERR_CHANOPRIVSNEEDED),
1174 me.name, source_p->name, chname);
1175 *errors |= SM_ERR_NOOPS;
1176 return;
1177 }
1178
1179 if (dir == MODE_QUERY)
1180 return;
1181
1182 if ((dir == MODE_ADD) && parc > *parn)
1183 {
1184 key = parv[(*parn)++];
1185
1186 if (MyClient(source_p))
1187 fix_key(key);
1188 else
1189 fix_key_old(key);
1190
1191 if (*key == '\0')
1192 return;
1193
1194 assert(key[0] != ' ');
1195 strlcpy(chptr->mode.key, key, sizeof(chptr->mode.key));
1196
1197 /* if somebody does MODE #channel +kk a b, accept latter --fl */
1198 for (i = 0; i < mode_count; i++)
1199 {
1200 if (mode_changes[i].letter == c && mode_changes[i].dir == MODE_ADD)
1201 mode_changes[i].letter = 0;
1202 }
1203
1204 mode_changes[mode_count].letter = c;
1205 mode_changes[mode_count].dir = MODE_ADD;
1206 mode_changes[mode_count].caps = 0;
1207 mode_changes[mode_count].nocaps = 0;
1208 mode_changes[mode_count].mems = ALL_MEMBERS;
1209 mode_changes[mode_count].id = NULL;
1210 mode_changes[mode_count++].arg = chptr->mode.key;
1211 }
1212 else if (dir == MODE_DEL)
1213 {
1214 if (parc > *parn)
1215 (*parn)++;
1216
1217 if (chptr->mode.key[0] == '\0')
1218 return;
1219
1220 chptr->mode.key[0] = '\0';
1221
1222 mode_changes[mode_count].letter = c;
1223 mode_changes[mode_count].dir = MODE_DEL;
1224 mode_changes[mode_count].caps = 0;
1225 mode_changes[mode_count].nocaps = 0;
1226 mode_changes[mode_count].mems = ALL_MEMBERS;
1227 mode_changes[mode_count].id = NULL;
1228 mode_changes[mode_count++].arg = "*";
1229 }
1230 }
1231
1232 struct ChannelMode
1233 {
1234 void (*func) (struct Client *client_p, struct Client *source_p,
1235 struct Channel *chptr, int parc, int *parn, char **parv,
1236 int *errors, int alev, int dir, char c, void *d,
1237 const char *chname);
1238 void *d;
1239 };
1240
1241 static struct ChannelMode ModeTable[255] =
1242 {
1243 {chm_nosuch, NULL},
1244 {chm_nosuch, NULL}, /* A */
1245 {chm_nosuch, NULL}, /* B */
1246 {chm_nosuch, NULL}, /* C */
1247 {chm_nosuch, NULL}, /* D */
1248 {chm_nosuch, NULL}, /* E */
1249 {chm_nosuch, NULL}, /* F */
1250 {chm_nosuch, NULL}, /* G */
1251 {chm_nosuch, NULL}, /* H */
1252 {chm_invex, NULL}, /* I */
1253 {chm_nosuch, NULL}, /* J */
1254 {chm_nosuch, NULL}, /* K */
1255 {chm_nosuch, NULL}, /* L */
1256 {chm_nosuch, NULL}, /* M */
1257 {chm_nosuch, NULL}, /* N */
1258 {chm_nosuch, NULL}, /* O */
1259 {chm_nosuch, NULL}, /* P */
1260 {chm_nosuch, NULL}, /* Q */
1261 {chm_nosuch, NULL}, /* R */
1262 {chm_nosuch, NULL}, /* S */
1263 {chm_nosuch, NULL}, /* T */
1264 {chm_nosuch, NULL}, /* U */
1265 {chm_nosuch, NULL}, /* V */
1266 {chm_nosuch, NULL}, /* W */
1267 {chm_nosuch, NULL}, /* X */
1268 {chm_nosuch, NULL}, /* Y */
1269 {chm_nosuch, NULL}, /* Z */
1270 {chm_nosuch, NULL},
1271 {chm_nosuch, NULL},
1272 {chm_nosuch, NULL},
1273 {chm_nosuch, NULL},
1274 {chm_nosuch, NULL},
1275 {chm_nosuch, NULL},
1276 {chm_nosuch, NULL}, /* a */
1277 {chm_ban, NULL}, /* b */
1278 {chm_nosuch, NULL}, /* c */
1279 {chm_nosuch, NULL}, /* d */
1280 {chm_except, NULL}, /* e */
1281 {chm_nosuch, NULL}, /* f */
1282 {chm_nosuch, NULL}, /* g */
1283 #ifdef HALFOPS
1284 {chm_hop, NULL}, /* h */
1285 #else
1286 {chm_nosuch, NULL}, /* h */
1287 #endif
1288 {chm_simple, (void *) MODE_INVITEONLY}, /* i */
1289 {chm_nosuch, NULL}, /* j */
1290 {chm_key, NULL}, /* k */
1291 {chm_limit, NULL}, /* l */
1292 {chm_simple, (void *) MODE_MODERATED}, /* m */
1293 {chm_simple, (void *) MODE_NOPRIVMSGS}, /* n */
1294 {chm_op, NULL}, /* o */
1295 {chm_simple, (void *) MODE_PARANOID}, /* p */
1296 {chm_nosuch, NULL}, /* q */
1297 {chm_nosuch, NULL}, /* r */
1298 {chm_simple, (void *) MODE_SECRET}, /* s */
1299 {chm_simple, (void *) MODE_TOPICLIMIT}, /* t */
1300 {chm_nosuch, NULL}, /* u */
1301 {chm_voice, NULL}, /* v */
1302 {chm_nosuch, NULL}, /* w */
1303 {chm_nosuch, NULL}, /* x */
1304 {chm_nosuch, NULL}, /* y */
1305 {chm_nosuch, NULL}, /* z */
1306 };
1307
1308 /* get_channel_access()
1309 *
1310 * inputs - pointer to Client struct
1311 * - pointer to Membership struct
1312 * output - CHACCESS_CHANOP if we should let them have
1313 * chanop level access, 0 for peon level access.
1314 * side effects - NONE
1315 */
1316 static void *
1317 get_channel_access(va_list args)
1318 {
1319 struct Client *source_p = va_arg(args, struct Client *);
1320 struct Membership *member = va_arg(args, struct Membership *);
1321 int *level = va_arg(args, int *);
1322
1323 /* Let hacked servers in for now... */
1324 if (!MyClient(source_p))
1325 {
1326 *level = CHACCESS_CHANOP;
1327 return NULL;
1328 }
1329
1330 if (member == NULL)
1331 {
1332 *level = CHACCESS_NOTONCHAN;
1333 return NULL;
1334 }
1335
1336 /* just to be sure.. */
1337 assert(source_p == member->client_p);
1338
1339 if (has_member_flags(member, CHFL_CHANOP))
1340 *level = CHACCESS_CHANOP;
1341 #ifdef HALFOPS
1342 else if (has_member_flags(member, CHFL_HALFOP))
1343 *level = CHACCESS_HALFOP;
1344 #endif
1345 else
1346 *level = CHACCESS_PEON;
1347
1348 return NULL;
1349 }
1350
1351 void
1352 init_channel_modes(void)
1353 {
1354 init_chcap_usage_counts();
1355 channel_access_cb = register_callback("get_channel_access",
1356 get_channel_access);
1357 }
1358
1359 /* void send_cap_mode_changes(struct Client *client_p,
1360 * struct Client *source_p,
1361 * struct Channel *chptr, int cap, int nocap)
1362 * Input: The client sending(client_p), the source client(source_p),
1363 * the channel to send mode changes for(chptr)
1364 * Output: None.
1365 * Side-effects: Sends the appropriate mode changes to capable servers.
1366 *
1367 * send_cap_mode_changes() will loop the server list itself, because
1368 * at this point in time we have 4 capabs for channels, CAP_IE, CAP_EX,
1369 * and a server could support any number of these..
1370 * so we make the modebufs per server, tailoring them to each servers
1371 * specific demand. Its not very pretty, but its one of the few realistic
1372 * ways to handle having this many capabs for channel modes.. --fl_
1373 *
1374 * Reverted back to my original design, except that we now keep a count
1375 * of the number of servers which each combination as an optimisation, so
1376 * the capabs combinations which are not needed are not worked out. -A1kmm
1377 */
1378 /* rewritten to ensure parabuf < MODEBUFLEN -db */
1379
1380 static void
1381 send_cap_mode_changes(struct Client *client_p, struct Client *source_p,
1382 struct Channel *chptr, int cap, int nocap)
1383 {
1384 int i, mbl, pbl, arglen, nc, mc;
1385 int len;
1386 const char *arg = NULL;
1387 char *parptr;
1388 int dir = MODE_QUERY;
1389
1390 mc = 0;
1391 nc = 0;
1392 pbl = 0;
1393
1394 parabuf[0] = '\0';
1395 parptr = parabuf;
1396
1397 if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1398 mbl = ircsprintf(modebuf, ":%s TMODE %lu %s ", source_p->id,
1399 (unsigned long)chptr->channelts, chptr->chname);
1400 else
1401 mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1402 chptr->chname);
1403
1404 /* loop the list of - modes we have */
1405 for (i = 0; i < mode_count; i++)
1406 {
1407 /* if they dont support the cap we need, or they do support a cap they
1408 * cant have, then dont add it to the modebuf.. that way they wont see
1409 * the mode
1410 */
1411 if ((mode_changes[i].letter == 0) ||
1412 ((cap & mode_changes[i].caps) != mode_changes[i].caps)
1413 || ((nocap & mode_changes[i].nocaps) != mode_changes[i].nocaps))
1414 continue;
1415
1416 arg = "";
1417
1418 if ((cap & CAP_TS6) && mode_changes[i].id)
1419 arg = mode_changes[i].id;
1420 if (*arg == '\0')
1421 arg = mode_changes[i].arg;
1422
1423 /* if we're creeping past the buf size, we need to send it and make
1424 * another line for the other modes
1425 * XXX - this could give away server topology with uids being
1426 * different lengths, but not much we can do, except possibly break
1427 * them as if they were the longest of the nick or uid at all times,
1428 * which even then won't work as we don't always know the uid -A1kmm.
1429 */
1430 if (arg != NULL)
1431 arglen = strlen(arg);
1432 else
1433 arglen = 0;
1434
1435 if ((mc == MAXMODEPARAMS) ||
1436 ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1437 (pbl + arglen + BAN_FUDGE) >= MODEBUFLEN)
1438 {
1439 if (nc != 0)
1440 sendto_server(client_p, source_p, chptr, cap, nocap,
1441 "%s %s",
1442 modebuf, parabuf);
1443 nc = 0;
1444 mc = 0;
1445
1446 if ((cap & CAP_TS6) && source_p->id[0] != '\0')
1447 mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->id,
1448 chptr->chname);
1449 else
1450 mbl = ircsprintf(modebuf, ":%s MODE %s ", source_p->name,
1451 chptr->chname);
1452
1453 pbl = 0;
1454 parabuf[0] = '\0';
1455 parptr = parabuf;
1456 dir = MODE_QUERY;
1457 }
1458
1459 if (dir != mode_changes[i].dir)
1460 {
1461 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1462 dir = mode_changes[i].dir;
1463 }
1464
1465 modebuf[mbl++] = mode_changes[i].letter;
1466 modebuf[mbl] = '\0';
1467 nc++;
1468
1469 if (arg != NULL)
1470 {
1471 len = ircsprintf(parptr, "%s ", arg);
1472 pbl += len;
1473 parptr += len;
1474 mc++;
1475 }
1476 }
1477
1478 if (pbl && parabuf[pbl - 1] == ' ')
1479 parabuf[pbl - 1] = 0;
1480
1481 if (nc != 0)
1482 sendto_server(client_p, source_p, chptr, cap, nocap,
1483 "%s %s", modebuf, parabuf);
1484 }
1485
1486 /* void send_mode_changes(struct Client *client_p,
1487 * struct Client *source_p,
1488 * struct Channel *chptr)
1489 * Input: The client sending(client_p), the source client(source_p),
1490 * the channel to send mode changes for(chptr),
1491 * mode change globals.
1492 * Output: None.
1493 * Side-effects: Sends the appropriate mode changes to other clients
1494 * and propagates to servers.
1495 */
1496 /* ensure parabuf < MODEBUFLEN -db */
1497 static void
1498 send_mode_changes(struct Client *client_p, struct Client *source_p,
1499 struct Channel *chptr, char *chname)
1500 {
1501 int i, mbl, pbl, arglen, nc, mc;
1502 int len;
1503 const char *arg = NULL;
1504 char *parptr;
1505 int dir = MODE_QUERY;
1506
1507 /* bail out if we have nothing to do... */
1508 if (!mode_count)
1509 return;
1510
1511 if (IsServer(source_p))
1512 mbl = ircsprintf(modebuf, ":%s MODE %s ", (IsHidden(source_p) ||
1513 ConfigServerHide.hide_servers) ?
1514 me.name : source_p->name, chname);
1515 else
1516 mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1517 source_p->username, source_p->host, chname);
1518
1519 mc = 0;
1520 nc = 0;
1521 pbl = 0;
1522
1523 parabuf[0] = '\0';
1524 parptr = parabuf;
1525
1526 for (i = 0; i < mode_count; i++)
1527 {
1528 if (mode_changes[i].letter == 0 ||
1529 mode_changes[i].mems == NON_CHANOPS ||
1530 mode_changes[i].mems == ONLY_SERVERS)
1531 continue;
1532
1533 arg = mode_changes[i].arg;
1534 if (arg != NULL)
1535 arglen = strlen(arg);
1536 else
1537 arglen = 0;
1538
1539 if ((mc == MAXMODEPARAMS) ||
1540 ((arglen + mbl + pbl + 2) > IRCD_BUFSIZE) ||
1541 ((arglen + pbl + BAN_FUDGE) >= MODEBUFLEN))
1542 {
1543 if (mbl && modebuf[mbl - 1] == '-')
1544 modebuf[mbl - 1] = '\0';
1545
1546 if (nc != 0)
1547 sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1548
1549 nc = 0;
1550 mc = 0;
1551
1552 if (IsServer(source_p))
1553 mbl = ircsprintf(modebuf, ":%s MODE %s ", me.name, chname);
1554 else
1555 mbl = ircsprintf(modebuf, ":%s!%s@%s MODE %s ", source_p->name,
1556 source_p->username, source_p->host, chname);
1557
1558 pbl = 0;
1559 parabuf[0] = '\0';
1560 parptr = parabuf;
1561 dir = MODE_QUERY;
1562 }
1563
1564 if (dir != mode_changes[i].dir)
1565 {
1566 modebuf[mbl++] = (mode_changes[i].dir == MODE_ADD) ? '+' : '-';
1567 dir = mode_changes[i].dir;
1568 }
1569
1570 modebuf[mbl++] = mode_changes[i].letter;
1571 modebuf[mbl] = '\0';
1572 nc++;
1573
1574 if (arg != NULL)
1575 {
1576 len = ircsprintf(parptr, "%s ", arg);
1577 pbl += len;
1578 parptr += len;
1579 mc++;
1580 }
1581 }
1582
1583 if (pbl && parabuf[pbl - 1] == ' ')
1584 parabuf[pbl - 1] = 0;
1585
1586 if (nc != 0)
1587 sendto_channel_local(ALL_MEMBERS, NO, chptr, "%s %s", modebuf, parabuf);
1588
1589 nc = 0;
1590 mc = 0;
1591
1592 /* Now send to servers... */
1593 for (i = 0; i < NCHCAP_COMBOS; i++)
1594 if (chcap_combos[i].count != 0)
1595 send_cap_mode_changes(client_p, source_p, chptr,
1596 chcap_combos[i].cap_yes,
1597 chcap_combos[i].cap_no);
1598 }
1599
1600 /* void set_channel_mode(struct Client *client_p, struct Client *source_p,
1601 * struct Channel *chptr, int parc, char **parv,
1602 * char *chname)
1603 * Input: The client we received this from, the client this originated
1604 * from, the channel, the parameter count starting at the modes,
1605 * the parameters, the channel name.
1606 * Output: None.
1607 * Side-effects: Changes the channel membership and modes appropriately,
1608 * sends the appropriate MODE messages to the appropriate
1609 * clients.
1610 */
1611 void
1612 set_channel_mode(struct Client *client_p, struct Client *source_p, struct Channel *chptr,
1613 struct Membership *member, int parc, char *parv[], char *chname)
1614 {
1615 int dir = MODE_ADD;
1616 int parn = 1;
1617 int alevel, errors = 0;
1618 char *ml = parv[0], c;
1619 int table_position;
1620
1621 mode_count = 0;
1622 mode_limit = 0;
1623 simple_modes_mask = 0;
1624
1625 execute_callback(channel_access_cb, source_p, member, &alevel);
1626
1627 for (; (c = *ml) != '\0'; ml++)
1628 {
1629 switch (c)
1630 {
1631 case '+':
1632 dir = MODE_ADD;
1633 break;
1634 case '-':
1635 dir = MODE_DEL;
1636 break;
1637 case '=':
1638 dir = MODE_QUERY;
1639 break;
1640 default:
1641 if (c < 'A' || c > 'z')
1642 table_position = 0;
1643 else
1644 table_position = c - 'A' + 1;
1645 ModeTable[table_position].func(client_p, source_p, chptr,
1646 parc, &parn,
1647 parv, &errors, alevel, dir, c,
1648 ModeTable[table_position].d,
1649 chname);
1650 break;
1651 }
1652 }
1653
1654 send_mode_changes(client_p, source_p, chptr, chname);
1655 }

Properties

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

svnadmin@ircd-hybrid.org
ViewVC Help
Powered by ViewVC 1.1.28