ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/ircd-hybrid-newconf/src/channel_mode.c
Revision: 1027
Committed: Sun Nov 8 13:01:13 2009 UTC (14 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 45973 byte(s)
Log Message:
- Move old 7.3 sources to branches/ircd-hybrid-newconf

File Contents

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

Properties

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